Compare commits
No commits in common. "Subsurface-DS9" and "jma-test-20240614-01" have entirely different histories.
Subsurface
...
jma-test-2
@ -71,7 +71,6 @@ LOCAL_SRC_FILES := \
|
||||
src/oceans_s1_parser.c \
|
||||
src/packet.c \
|
||||
src/parser.c \
|
||||
src/pelagic_i330r.c \
|
||||
src/platform.c \
|
||||
src/rbstream.c \
|
||||
src/reefnet_sensus.c \
|
||||
|
||||
@ -239,7 +239,6 @@
|
||||
<ClCompile Include="..\..\src\oceans_s1_parser.c" />
|
||||
<ClCompile Include="..\..\src\packet.c" />
|
||||
<ClCompile Include="..\..\src\parser.c" />
|
||||
<ClCompile Include="..\..\src\pelagic_i330r.c" />
|
||||
<ClCompile Include="..\..\src\platform.c" />
|
||||
<ClCompile Include="..\..\src\rbstream.c" />
|
||||
<ClCompile Include="..\..\src\reefnet_sensus.c" />
|
||||
@ -358,7 +357,6 @@
|
||||
<ClInclude Include="..\..\src\oceans_s1_common.h" />
|
||||
<ClInclude Include="..\..\src\packet.h" />
|
||||
<ClInclude Include="..\..\src\parser-private.h" />
|
||||
<ClInclude Include="..\..\src\pelagic_i330r.h" />
|
||||
<ClInclude Include="..\..\src\platform.h" />
|
||||
<ClInclude Include="..\..\src\rbstream.h" />
|
||||
<ClInclude Include="..\..\src\reefnet_sensus.h" />
|
||||
|
||||
@ -72,7 +72,6 @@ static const backend_table_t g_backends[] = {
|
||||
{"vtpro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
||||
{"veo250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
||||
{"atom2", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
||||
{"i330r", DC_FAMILY_PELAGIC_I330R, 0x4744},
|
||||
{"nemo", DC_FAMILY_MARES_NEMO, 0},
|
||||
{"puck", DC_FAMILY_MARES_PUCK, 7},
|
||||
{"darwin", DC_FAMILY_MARES_DARWIN, 0},
|
||||
|
||||
@ -33,21 +33,6 @@ extern "C" {
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_NAME DC_IOCTL_IOR('b', 0, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get the bluetooth authentication PIN code.
|
||||
*
|
||||
* The data format is a NULL terminated string.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_PINCODE DC_IOCTL_IOR('b', 1, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
/**
|
||||
* Get/set the bluetooth authentication access code.
|
||||
*
|
||||
* The data format is a variable sized byte array.
|
||||
*/
|
||||
#define DC_IOCTL_BLE_GET_ACCESSCODE DC_IOCTL_IOR('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
#define DC_IOCTL_BLE_SET_ACCESSCODE DC_IOCTL_IOW('b', 2, DC_IOCTL_SIZE_VARIABLE)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
@ -78,7 +78,6 @@ typedef enum dc_family_t {
|
||||
DC_FAMILY_OCEANIC_VTPRO = (4 << 16),
|
||||
DC_FAMILY_OCEANIC_VEO250,
|
||||
DC_FAMILY_OCEANIC_ATOM2,
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
/* Mares */
|
||||
DC_FAMILY_MARES_NEMO = (5 << 16),
|
||||
DC_FAMILY_MARES_PUCK,
|
||||
|
||||
@ -43,7 +43,6 @@ libdivecomputer_la_SOURCES = \
|
||||
oceanic_atom2.h oceanic_atom2.c oceanic_atom2_parser.c \
|
||||
oceanic_veo250.h oceanic_veo250.c oceanic_veo250_parser.c \
|
||||
oceanic_vtpro.h oceanic_vtpro.c oceanic_vtpro_parser.c \
|
||||
pelagic_i330r.h pelagic_i330r.c \
|
||||
mares_common.h mares_common.c \
|
||||
mares_nemo.h mares_nemo.c mares_nemo_parser.c \
|
||||
mares_puck.h mares_puck.c \
|
||||
|
||||
@ -275,9 +275,6 @@ static const dc_descriptor_t g_descriptors[] = {
|
||||
{"Aqualung", "i470TC", DC_FAMILY_OCEANIC_ATOM2, 0x4743, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i200Cv2", DC_FAMILY_OCEANIC_ATOM2, 0x4749, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Oceanic", "Geo Air", DC_FAMILY_OCEANIC_ATOM2, 0x474B, DC_TRANSPORT_SERIAL | DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Pelagic I330R */
|
||||
{"Apeks", "DSX", DC_FAMILY_PELAGIC_I330R, 0x4741, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
{"Aqualung", "i330R", DC_FAMILY_PELAGIC_I330R, 0x4744, DC_TRANSPORT_BLE, dc_filter_oceanic},
|
||||
/* Mares Nemo */
|
||||
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0, DC_TRANSPORT_SERIAL, NULL},
|
||||
@ -758,10 +755,8 @@ dc_filter_oceanic (dc_descriptor_t *descriptor, dc_transport_t transport, const
|
||||
0x4654, // Oceanic Veo 4.0
|
||||
0x4655, // Sherwood Wisdom 4
|
||||
0x4656, // Oceanic Pro Plus 4
|
||||
0x4741, // Apeks DSX
|
||||
0x4742, // Sherwood Beacon
|
||||
0x4743, // Aqualung i470TC
|
||||
0x4744, // Aqualung i330R
|
||||
0x4749, // Aqualung i200C (newer model)
|
||||
0x474B, // Oceanic Geo Air
|
||||
};
|
||||
|
||||
@ -38,7 +38,6 @@
|
||||
#include "oceanic_atom2.h"
|
||||
#include "oceanic_veo250.h"
|
||||
#include "oceanic_vtpro.h"
|
||||
#include "pelagic_i330r.h"
|
||||
#include "mares_darwin.h"
|
||||
#include "mares_iconhd.h"
|
||||
#include "mares_nemo.h"
|
||||
@ -166,9 +165,6 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
rc = oceanic_atom2_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
rc = pelagic_i330r_device_open (&device, context, iostream, dc_descriptor_get_model (descriptor));
|
||||
break;
|
||||
case DC_FAMILY_MARES_NEMO:
|
||||
rc = mares_nemo_device_open (&device, context, iostream);
|
||||
break;
|
||||
|
||||
@ -37,12 +37,6 @@
|
||||
#define GAUGE 1
|
||||
#define FREEDIVE 2
|
||||
|
||||
#define DSX_CC 0
|
||||
#define DSX_OC 1
|
||||
#define DSX_SIDEMOUNT 2
|
||||
#define DSX_SIDEGAUGE 3
|
||||
#define DSX_GAUGE 4
|
||||
|
||||
#define NGASMIXES 6
|
||||
|
||||
#define HEADER 1
|
||||
@ -53,7 +47,6 @@ typedef struct oceanic_atom2_parser_t oceanic_atom2_parser_t;
|
||||
struct oceanic_atom2_parser_t {
|
||||
dc_parser_t base;
|
||||
unsigned int model;
|
||||
unsigned int logbooksize;
|
||||
unsigned int headersize;
|
||||
unsigned int footersize;
|
||||
unsigned int serial;
|
||||
@ -103,7 +96,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
|
||||
|
||||
// Set the default values.
|
||||
parser->model = model;
|
||||
parser->logbooksize = 0;
|
||||
parser->headersize = 9 * PAGESIZE / 2;
|
||||
parser->footersize = 2 * PAGESIZE / 2;
|
||||
if (model == DATAMASK || model == COMPUMASK ||
|
||||
@ -142,14 +134,6 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const uns
|
||||
} else if (model == I550C || model == WISDOM4 ||
|
||||
model == I200CV2) {
|
||||
parser->headersize = 5 * PAGESIZE / 2;
|
||||
} else if (model == I330R) {
|
||||
parser->logbooksize = 64;
|
||||
parser->headersize = parser->logbooksize + 80;
|
||||
parser->footersize = 48;
|
||||
} else if (model == DSX) {
|
||||
parser->logbooksize = 512;
|
||||
parser->headersize = parser->logbooksize + 256;
|
||||
parser->footersize = 64;
|
||||
}
|
||||
|
||||
parser->serial = serial;
|
||||
@ -190,18 +174,8 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
if (datetime) {
|
||||
// AM/PM bit of the 12-hour clock.
|
||||
unsigned int pm = p[1] & 0x80;
|
||||
unsigned int have_ampm = 1;
|
||||
|
||||
switch (parser->model) {
|
||||
case I330R:
|
||||
case DSX:
|
||||
datetime->year = p[7] + 2000;
|
||||
datetime->month = p[6];
|
||||
datetime->day = p[5];
|
||||
datetime->hour = p[3];
|
||||
datetime->minute = p[4];
|
||||
have_ampm = 0;
|
||||
break;
|
||||
case OC1A:
|
||||
case OC1B:
|
||||
case OC1C:
|
||||
@ -310,11 +284,9 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim
|
||||
datetime->timezone = DC_TIMEZONE_NONE;
|
||||
|
||||
// Convert to a 24-hour clock.
|
||||
if (have_ampm) {
|
||||
datetime->hour %= 12;
|
||||
if (pm)
|
||||
datetime->hour += 12;
|
||||
}
|
||||
datetime->hour %= 12;
|
||||
if (pm)
|
||||
datetime->hour += 12;
|
||||
|
||||
/*
|
||||
* Workaround for the year 2010 problem.
|
||||
@ -390,10 +362,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
} else if (parser->model == VEO20 || parser->model == VEO30 ||
|
||||
parser->model == OCS) {
|
||||
mode = (data[1] & 0x60) >> 5;
|
||||
} else if (parser->model == I330R) {
|
||||
mode = data[2];
|
||||
} else if (parser->model == DSX) {
|
||||
mode = data[45];
|
||||
}
|
||||
|
||||
// Get the gas mixes.
|
||||
@ -451,17 +419,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
} else if (parser->model == WISDOM4) {
|
||||
o2_offset = header + 4;
|
||||
ngasmixes = 1;
|
||||
} else if (parser->model == I330R) {
|
||||
ngasmixes = 3;
|
||||
o2_offset = parser->logbooksize + 16;
|
||||
} else if (parser->model == DSX) {
|
||||
if (mode < DSX_SIDEGAUGE) {
|
||||
o2_offset = parser->logbooksize + 0x89 + mode * 16;
|
||||
he_offset = parser->logbooksize + 0xB9 + mode * 16;
|
||||
ngasmixes = 6;
|
||||
} else {
|
||||
ngasmixes = 0;
|
||||
}
|
||||
} else {
|
||||
o2_offset = header + 4;
|
||||
ngasmixes = 3;
|
||||
@ -475,10 +432,6 @@ oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser)
|
||||
for (unsigned int i = 0; i < ngasmixes; ++i) {
|
||||
if (data[o2_offset + i * o2_step]) {
|
||||
parser->oxygen[i] = data[o2_offset + i * o2_step];
|
||||
// The i330R uses 20 as "Air" and 21 as 21% Nitrox
|
||||
if (parser->model == I330R && parser->oxygen[i] == 20) {
|
||||
parser->oxygen[i] = 21;
|
||||
}
|
||||
} else {
|
||||
parser->oxygen[i] = 21;
|
||||
}
|
||||
@ -540,18 +493,9 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
parser->model == F11A || parser->model == F11B ||
|
||||
parser->model == MUNDIAL2 || parser->model == MUNDIAL3)
|
||||
*((double *) value) = array_uint16_le (data + 4) / 16.0 * FEET;
|
||||
else if (parser->model == I330R || parser->model == DSX)
|
||||
*((double *) value) = array_uint16_le (data + parser->footer + 10) / 10.0 * FEET;
|
||||
else
|
||||
*((double *) value) = (array_uint16_le (data + parser->footer + 4) & 0x0FFF) / 16.0 * FEET;
|
||||
break;
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
*((double *) value) = array_uint16_le (data + parser->footer + 12) / 10.0 * FEET;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
*((unsigned int *) value) = parser->ngasmixes;
|
||||
break;
|
||||
@ -570,49 +514,23 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns
|
||||
water->type = DC_WATER_SALT;
|
||||
}
|
||||
water->density = 0.0;
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
unsigned int settings = array_uint32_le (data + parser->logbooksize + 12);
|
||||
if (settings & 0x10000) {
|
||||
water->type = DC_WATER_FRESH;
|
||||
} else {
|
||||
water->type = DC_WATER_SALT;
|
||||
}
|
||||
water->density = 0.0;
|
||||
} else {
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
if (parser->model == DSX) {
|
||||
switch (parser->mode) {
|
||||
case DSX_OC:
|
||||
case DSX_SIDEMOUNT:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case DSX_SIDEGAUGE:
|
||||
case DSX_GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case DSX_CC:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_CCR;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
} else {
|
||||
switch (parser->mode) {
|
||||
case NORMAL:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
switch (parser->mode) {
|
||||
case NORMAL:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_OC;
|
||||
break;
|
||||
case GAUGE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_GAUGE;
|
||||
break;
|
||||
case FREEDIVE:
|
||||
*((unsigned int *) value) = DC_DIVEMODE_FREEDIVE;
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
@ -688,19 +606,15 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
unsigned int time = 0;
|
||||
unsigned int interval = 1000;
|
||||
if (parser->mode != FREEDIVE) {
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
interval = data[parser->logbooksize + 36] * 1000;
|
||||
} else {
|
||||
unsigned int offset = 0x17;
|
||||
if (parser->model == A300CS || parser->model == VTX ||
|
||||
parser->model == I450T || parser->model == I750TC ||
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
offset = 0x1f;
|
||||
const unsigned int intervals[] = {2000, 15000, 30000, 60000};
|
||||
unsigned int idx = data[offset] & 0x03;
|
||||
interval = intervals[idx];
|
||||
}
|
||||
unsigned int offset = 0x17;
|
||||
if (parser->model == A300CS || parser->model == VTX ||
|
||||
parser->model == I450T || parser->model == I750TC ||
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
offset = 0x1f;
|
||||
const unsigned int intervals[] = {2000, 15000, 30000, 60000};
|
||||
unsigned int idx = data[offset] & 0x03;
|
||||
interval = intervals[idx];
|
||||
} else if (parser->model == F11A || parser->model == F11B) {
|
||||
const unsigned int intervals[] = {250, 500, 1000, 2000};
|
||||
unsigned int idx = data[0x29] & 0x03;
|
||||
@ -723,10 +637,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I750TC || parser->model == PROPLUSX ||
|
||||
parser->model == I770R || parser->model == I470TC ||
|
||||
parser->model == SAGE || parser->model == BEACON ||
|
||||
parser->model == GEOAIR || parser->model == I330R) {
|
||||
parser->model == GEOAIR) {
|
||||
samplesize = PAGESIZE;
|
||||
} else if (parser->model == DSX) {
|
||||
samplesize = 32;
|
||||
}
|
||||
|
||||
unsigned int have_temperature = 1, have_pressure = 1;
|
||||
@ -741,8 +653,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I200 || parser->model == I100 ||
|
||||
parser->model == I300C || parser->model == TALIS ||
|
||||
parser->model == I200C || parser->model == I200CV2 ||
|
||||
parser->model == GEO40 || parser->model == VEO40 ||
|
||||
parser->model == I330R) {
|
||||
parser->model == GEO40 || parser->model == VEO40) {
|
||||
have_pressure = 0;
|
||||
}
|
||||
|
||||
@ -911,8 +822,6 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I770R|| parser->model == SAGE ||
|
||||
parser->model == BEACON) {
|
||||
temperature = data[offset + 11];
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
temperature = array_uint16_le(data + offset + 10);
|
||||
} else {
|
||||
unsigned int sign;
|
||||
if (parser->model == DG03 || parser->model == PROPLUS3 ||
|
||||
@ -935,11 +844,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
else
|
||||
temperature += (data[offset + 7] & 0x0C) >> 2;
|
||||
}
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.temperature = ((temperature / 10.0) - 32.0) * (5.0 / 9.0);
|
||||
} else {
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
}
|
||||
sample.temperature = (temperature - 32.0) * (5.0 / 9.0);
|
||||
if (callback) callback (DC_SAMPLE_TEMPERATURE, &sample, userdata);
|
||||
}
|
||||
|
||||
@ -964,12 +869,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == PROPLUSX || parser->model == I770R ||
|
||||
parser->model == SAGE || parser->model == BEACON)
|
||||
pressure = array_uint16_le (data + offset + 4);
|
||||
else if (parser->model == DSX) {
|
||||
pressure = array_uint16_le (data + offset + 14);
|
||||
tank = ((data[offset] & 0xF0) >> 4) - 1;
|
||||
} else {
|
||||
else
|
||||
pressure -= data[offset + 1];
|
||||
}
|
||||
sample.pressure.tank = tank;
|
||||
sample.pressure.value = pressure * PSI / BAR;
|
||||
if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata);
|
||||
@ -990,17 +891,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
parser->model == I470TC || parser->model == I200CV2 ||
|
||||
parser->model == GEOAIR)
|
||||
depth = (data[offset + 4] + (data[offset + 5] << 8)) & 0x0FFF;
|
||||
else if (parser->model == I330R || parser->model == DSX)
|
||||
depth = array_uint16_le (data + offset + 2);
|
||||
else if (parser->model == ATOM1)
|
||||
depth = data[offset + 3] * 16;
|
||||
else
|
||||
depth = (data[offset + 2] + (data[offset + 3] << 8)) & 0x0FFF;
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.depth = depth / 10.0 * FEET;
|
||||
} else {
|
||||
sample.depth = depth / 16.0 * FEET;
|
||||
}
|
||||
sample.depth = depth / 16.0 * FEET;
|
||||
if (callback) callback (DC_SAMPLE_DEPTH, &sample, userdata);
|
||||
|
||||
// Gas mix
|
||||
@ -1009,11 +904,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
if (parser->model == TX1) {
|
||||
gasmix = data[offset] & 0x07;
|
||||
have_gasmix = 1;
|
||||
} else if (parser->model == DSX) {
|
||||
gasmix = (data[offset] & 0xF0) >> 4;
|
||||
have_gasmix = 1;
|
||||
}
|
||||
if (have_gasmix && gasmix != gasmix_previous && parser->ngasmixes > 0) {
|
||||
if (have_gasmix && gasmix != gasmix_previous) {
|
||||
if (gasmix < 1 || gasmix > parser->ngasmixes) {
|
||||
ERROR (abstract->context, "Invalid gas mix index (%u).", gasmix);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
@ -1058,25 +950,11 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
decostop = (data[offset + 7] & 0xF0) >> 4;
|
||||
decotime = array_uint16_le(data + offset + 6) & 0x0FFF;
|
||||
have_deco = 1;
|
||||
} else if (parser->model == I330R || parser->model == DSX) {
|
||||
decostop = data[offset + 8];
|
||||
if (decostop) {
|
||||
// Deco time
|
||||
decotime = array_uint16_le(data + offset + 6);
|
||||
} else {
|
||||
// NDL
|
||||
decotime = array_uint16_le(data + offset + 4);
|
||||
}
|
||||
have_deco = 1;
|
||||
}
|
||||
if (have_deco) {
|
||||
if (decostop) {
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
if (parser->model == I330R || parser->model == DSX) {
|
||||
sample.deco.depth = decostop * FEET;
|
||||
} else {
|
||||
sample.deco.depth = decostop * 10 * FEET;
|
||||
}
|
||||
sample.deco.depth = decostop * 10 * FEET;
|
||||
} else {
|
||||
sample.deco.type = DC_DECO_NDL;
|
||||
sample.deco.depth = 0.0;
|
||||
@ -1109,13 +987,6 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_
|
||||
if (callback) callback (DC_SAMPLE_RBT, &sample, userdata);
|
||||
}
|
||||
|
||||
// PPO2
|
||||
if (parser->model == I330R) {
|
||||
sample.ppo2.sensor = DC_SENSOR_NONE;
|
||||
sample.ppo2.value = data[offset + 9] / 100.0;
|
||||
if (callback) callback (DC_SAMPLE_PPO2, &sample, userdata);
|
||||
}
|
||||
|
||||
// Bookmarks
|
||||
unsigned int have_bookmark = 0;
|
||||
if (parser->model == OC1A || parser->model == OC1B ||
|
||||
|
||||
@ -125,12 +125,8 @@ extern "C" {
|
||||
#define I200CV2 0x4749
|
||||
#define GEOAIR 0x474B
|
||||
|
||||
// i330r
|
||||
#define DSX 0x4741
|
||||
#define I330R 0x4744
|
||||
|
||||
#define PAGESIZE 0x10
|
||||
#define FPMAXSIZE 0x200
|
||||
#define FPMAXSIZE 0x20
|
||||
|
||||
#define OCEANIC_COMMON_MATCH(version,patterns,firmware) \
|
||||
oceanic_common_match ((version), (patterns), \
|
||||
|
||||
@ -127,7 +127,6 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned
|
||||
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
|
||||
break;
|
||||
case DC_FAMILY_OCEANIC_ATOM2:
|
||||
case DC_FAMILY_PELAGIC_I330R:
|
||||
if (model == REACTPROWHITE)
|
||||
rc = oceanic_veo250_parser_create (&parser, context, data, size, model);
|
||||
else
|
||||
|
||||
@ -1,647 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Janice McLaughlin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
// test 01
|
||||
|
||||
#include <string.h> // memcpy
|
||||
#include <stdlib.h> // malloc, free
|
||||
#include <assert.h>
|
||||
|
||||
#include <libdivecomputer/ble.h>
|
||||
|
||||
#include "pelagic_i330r.h"
|
||||
#include "oceanic_common.h"
|
||||
|
||||
#include "context-private.h"
|
||||
#include "device-private.h"
|
||||
#include "ringbuffer.h"
|
||||
#include "rbstream.h"
|
||||
#include "checksum.h"
|
||||
#include "array.h"
|
||||
|
||||
#define UNDEFINED 0
|
||||
|
||||
#define STARTBYTE 0xCD
|
||||
|
||||
#define FLAG_NONE 0x00
|
||||
#define FLAG_REQUEST 0x40
|
||||
#define FLAG_DATA 0x80
|
||||
#define FLAG_LAST 0xC0
|
||||
|
||||
#define CMD_ACCESS_REQUEST 0xFA
|
||||
#define CMD_ACCESS_CODE 0xFB
|
||||
#define CMD_AUTHENTICATION 0x97
|
||||
#define CMD_WAKEUP_RDONLY 0x21
|
||||
#define CMD_WAKEUP_RDWR 0x22
|
||||
#define CMD_READ_HW_CAL 0x27
|
||||
#define CMD_READ_A2D 0x25
|
||||
#define CMD_READ_DEVICE_REC 0x31
|
||||
#define CMD_READ_GEN_SET 0x29
|
||||
#define CMD_READ_EXFLASHMAP 0x2F
|
||||
#define CMD_READ_FLASH 0x0D
|
||||
|
||||
#define RSP_READY 1
|
||||
#define RSP_DONE 2
|
||||
|
||||
#define MAXPACKET 255
|
||||
|
||||
#define MAXPASSCODE 6
|
||||
|
||||
typedef struct pelagic_i330r_device_t {
|
||||
oceanic_common_device_t base;
|
||||
dc_iostream_t *iostream;
|
||||
unsigned char accesscode[16];
|
||||
unsigned char id[16];
|
||||
unsigned char hwcal[256];
|
||||
unsigned char flashmap[256];
|
||||
unsigned int model;
|
||||
} pelagic_i330r_device_t;
|
||||
|
||||
static dc_status_t pelagic_i330r_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size);
|
||||
static dc_status_t pelagic_i330r_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress);
|
||||
static dc_status_t pelagic_i330r_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end);
|
||||
|
||||
static const oceanic_common_device_vtable_t pelagic_i330r_device_vtable = {
|
||||
{
|
||||
sizeof(pelagic_i330r_device_t),
|
||||
DC_FAMILY_PELAGIC_I330R,
|
||||
oceanic_common_device_set_fingerprint, /* set_fingerprint */
|
||||
pelagic_i330r_device_read, /* read */
|
||||
NULL, /* write */
|
||||
oceanic_common_device_dump, /* dump */
|
||||
oceanic_common_device_foreach, /* foreach */
|
||||
NULL, /* timesync */
|
||||
NULL /* close */
|
||||
},
|
||||
pelagic_i330r_device_devinfo,
|
||||
pelagic_i330r_device_pointers,
|
||||
oceanic_common_device_logbook,
|
||||
oceanic_common_device_profile,
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t pelagic_i330r = {
|
||||
0x00400000, /* memsize */
|
||||
0, /* highmem */
|
||||
UNDEFINED, /* cf_devinfo */
|
||||
UNDEFINED, /* cf_pointers */
|
||||
0x00102000, /* rb_logbook_begin */
|
||||
0x00106000, /* rb_logbook_end */
|
||||
64, /* rb_logbook_entry_size */
|
||||
0, /* rb_logbook_direction */
|
||||
0x0010A000, /* rb_profile_begin */
|
||||
0x00400000, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
4, /* pt_mode_logbook */
|
||||
UNDEFINED, /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static const oceanic_common_layout_t pelagic_dsx = {
|
||||
0x02000000, /* memsize */
|
||||
0, /* highmem */
|
||||
UNDEFINED, /* cf_devinfo */
|
||||
UNDEFINED, /* cf_pointers */
|
||||
0x00800000, /* rb_logbook_begin */
|
||||
0x00880000, /* rb_logbook_end */
|
||||
512, /* rb_logbook_entry_size */
|
||||
1, /* rb_logbook_direction */
|
||||
0x01000000, /* rb_profile_begin */
|
||||
0x02000000, /* rb_profile_end */
|
||||
1, /* pt_mode_global */
|
||||
4, /* pt_mode_logbook */
|
||||
UNDEFINED /* pt_mode_serial */
|
||||
};
|
||||
|
||||
static unsigned char
|
||||
checksum (const unsigned char data[], unsigned int size)
|
||||
{
|
||||
unsigned int csum = 0;
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
unsigned int a = csum ^ data[i];
|
||||
unsigned int b = (a >> 7) ^ ((a >> 4) ^ a);
|
||||
csum = ((b << 4) & 0xFF) ^ ((b << 1) & 0xFF);
|
||||
}
|
||||
return csum & 0xFF;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_send (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char flag, const unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
if (size > MAXPACKET) {
|
||||
ERROR (abstract->context, "Packet payload is too large (%u).", size);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
unsigned char packet[MAXPACKET + 5] = {
|
||||
STARTBYTE,
|
||||
flag,
|
||||
cmd,
|
||||
0,
|
||||
size
|
||||
};
|
||||
if (size) {
|
||||
memcpy(packet + 5, data, size);
|
||||
}
|
||||
packet[3] = checksum (packet, size + 5);
|
||||
|
||||
// Send the data packet.
|
||||
status = dc_iostream_write (device->iostream, packet, size + 5, NULL);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_recv (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char data[], unsigned int size, unsigned int *errorcode)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char packet[MAXPACKET + 5] = {0};
|
||||
unsigned int errcode = 0;
|
||||
|
||||
unsigned int nbytes = 0;
|
||||
while (1) {
|
||||
// Read the data packet.
|
||||
size_t transferred = 0;
|
||||
status = dc_iostream_read (device->iostream, packet, sizeof(packet), &transferred);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to receive the data packet.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Verify the minimum packet size.
|
||||
if (transferred < 5) {
|
||||
ERROR (abstract->context, "Invalid packet length (" DC_PRINTF_SIZE ").", transferred);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the start byte.
|
||||
if (packet[0] != STARTBYTE) {
|
||||
ERROR (abstract->context, "Unexpected packet start byte (%02x).", packet[0]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the command byte.
|
||||
if (packet[2] != cmd) {
|
||||
ERROR (abstract->context, "Unexpected packet command byte (%02x).", packet[2]);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the length byte.
|
||||
unsigned int length = packet[4];
|
||||
if (length + 5 > transferred) {
|
||||
ERROR (abstract->context, "Invalid packet length (%u).", length);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Verify the checksum.
|
||||
unsigned char crc = packet[3]; packet[3] = 0;
|
||||
unsigned char ccrc = checksum (packet, length + 5);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected packet checksum (%02x %02x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
// Check the flag byte for the last packet.
|
||||
unsigned char flag = packet[1];
|
||||
if ((flag & FLAG_LAST) == FLAG_LAST) {
|
||||
// The last packet (typically 2 bytes) does not get appended!
|
||||
if (length) {
|
||||
errcode = packet[5];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the payload data to the output buffer. If the output
|
||||
// buffer is too small, the error is not reported immediately
|
||||
// but delayed until all packets have been received.
|
||||
if (nbytes < size) {
|
||||
unsigned int n = length;
|
||||
if (nbytes + n > size) {
|
||||
n = size - nbytes;
|
||||
}
|
||||
memcpy (data + nbytes, packet + 5, n);
|
||||
}
|
||||
nbytes += length;
|
||||
}
|
||||
|
||||
// Verify the expected number of bytes.
|
||||
if (nbytes != size) {
|
||||
ERROR (abstract->context, "Unexpected number of bytes received (%u %u).", nbytes, size);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
if (errorcode) {
|
||||
*errorcode = errcode;
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_transfer (pelagic_i330r_device_t *device, unsigned char cmd, unsigned char flag, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize, unsigned int response)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned int errorcode = 0;
|
||||
|
||||
status = pelagic_i330r_send (device, cmd, flag, data, size);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_recv (device, cmd, answer, asize, &errorcode);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (errorcode != response) {
|
||||
ERROR (abstract->context, "Unexpected response code (%u)", errorcode);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_accesscode (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_REQUEST, FLAG_REQUEST, zero, sizeof(zero), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_REQUEST, FLAG_DATA, device->accesscode, sizeof(device->accesscode), NULL, 0, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_passcode (pelagic_i330r_device_t *device, const char *pincode)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
unsigned char passcode[MAXPASSCODE] = {0};
|
||||
|
||||
// Check the maximum length.
|
||||
size_t len = pincode ? strlen (pincode) : 0;
|
||||
if (len > sizeof(passcode)) {
|
||||
ERROR (abstract->context, "Invalid pincode length (" DC_PRINTF_SIZE ").", len);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
|
||||
// Convert to binary number.
|
||||
unsigned int offset = sizeof(passcode) - len;
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
unsigned char c = pincode[i];
|
||||
if (c < '0' || c > '9') {
|
||||
ERROR (abstract->context, "Invalid pincode character (%c).", c);
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
}
|
||||
passcode[offset + i] = c - '0';
|
||||
}
|
||||
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_CODE, FLAG_REQUEST, zero, sizeof(zero), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_ACCESS_CODE, FLAG_DATA, passcode, sizeof(passcode), device->accesscode, sizeof(device->accesscode), RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "Access code", device->accesscode, sizeof(device->accesscode));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_handshake (pelagic_i330r_device_t *device, unsigned int readwrite)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
const unsigned char cmd = readwrite ? CMD_WAKEUP_RDWR : CMD_WAKEUP_RDONLY;
|
||||
|
||||
const unsigned char args[9] = {0, 0, 0, 0, 0x0C, 0, 0, 0, 0};
|
||||
status = pelagic_i330r_transfer (device, cmd, FLAG_REQUEST, args, sizeof(args), device->id, sizeof(device->id), RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "ID", device->id, sizeof(device->id));
|
||||
|
||||
device->model = array_uint16_be (device->id + 12);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init_auth (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
|
||||
const unsigned char args[2][9] = {
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // DSX
|
||||
{0x37, 0x30, 0x31, 0x55}, // I330R
|
||||
};
|
||||
unsigned int args_idx = device->model == DSX ? 0 : 1;
|
||||
status = pelagic_i330r_transfer (device, CMD_AUTHENTICATION, FLAG_REQUEST, args[args_idx], sizeof(args[args_idx]), NULL, 0, RSP_READY);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_init (pelagic_i330r_device_t *device)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
// Get the bluetooth access code.
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_GET_ACCESSCODE, device->accesscode, sizeof(device->accesscode));
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to get the access code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
if (array_isequal (device->accesscode, sizeof(device->accesscode), 0)) {
|
||||
// Request to display the PIN code.
|
||||
status = pelagic_i330r_init_accesscode (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to display the PIN code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Get the bluetooth PIN code.
|
||||
char pincode[6 + 1] = {0};
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_GET_PINCODE, pincode, sizeof(pincode));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to get the PIN code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Force a null terminated string.
|
||||
pincode[sizeof(pincode) - 1] = 0;
|
||||
|
||||
// Request the access code.
|
||||
status = pelagic_i330r_init_passcode (device, pincode);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to request the access code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Store the bluetooth access code.
|
||||
status = dc_iostream_ioctl (device->iostream, DC_IOCTL_BLE_SET_ACCESSCODE, device->accesscode, sizeof(device->accesscode));
|
||||
if (status != DC_STATUS_SUCCESS && status != DC_STATUS_UNSUPPORTED) {
|
||||
ERROR (abstract->context, "Failed to store the access code.");
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// Request access.
|
||||
status = pelagic_i330r_init_accesscode (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to request access.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the wakeup command.
|
||||
status = pelagic_i330r_init_handshake (device, 1);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the wakeup command.");
|
||||
return status;
|
||||
}
|
||||
|
||||
// Send the authentication code.
|
||||
status = pelagic_i330r_init_auth (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (abstract->context, "Failed to send the authentication code.");
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_download (pelagic_i330r_device_t *device, unsigned char cmd, const unsigned char data[], unsigned int size, unsigned char answer[], unsigned int asize)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
dc_device_t *abstract = (dc_device_t *) device;
|
||||
|
||||
status = pelagic_i330r_transfer (device, cmd, FLAG_REQUEST, data, size, answer, asize, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
// Verify the checksum
|
||||
unsigned short crc = array_uint16_be (answer + asize - 2);
|
||||
unsigned short ccrc = checksum_crc16_ccitt (answer, asize - 2, 0xffff, 0x0000);
|
||||
if (crc != ccrc) {
|
||||
ERROR (abstract->context, "Unexpected data checksum (%04x %04x).", crc, ccrc);
|
||||
return DC_STATUS_PROTOCOL;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
dc_status_t
|
||||
pelagic_i330r_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
pelagic_i330r_device_t *device = NULL;
|
||||
|
||||
if (out == NULL)
|
||||
return DC_STATUS_INVALIDARGS;
|
||||
|
||||
// Allocate memory.
|
||||
device = (pelagic_i330r_device_t *) dc_device_allocate (context, &pelagic_i330r_device_vtable.base);
|
||||
if (device == NULL) {
|
||||
ERROR (context, "Failed to allocate memory.");
|
||||
return DC_STATUS_NOMEMORY;
|
||||
}
|
||||
|
||||
// Initialize the base class.
|
||||
oceanic_common_device_init (&device->base);
|
||||
|
||||
// Override the base class values.
|
||||
device->base.multipage = 256;
|
||||
|
||||
// Set the default values.
|
||||
device->iostream = iostream;
|
||||
memset (device->accesscode, 0, sizeof(device->accesscode));
|
||||
memset (device->id, 0, sizeof(device->id));
|
||||
memset (device->hwcal, 0, sizeof(device->hwcal));
|
||||
memset (device->flashmap, 0, sizeof(device->flashmap));
|
||||
device->model = 0;
|
||||
|
||||
// Set the timeout for receiving data (3000 ms).
|
||||
status = dc_iostream_set_timeout (device->iostream, 3000);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to set the timeout.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Perform the bluetooth authentication.
|
||||
status = pelagic_i330r_init (device);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to perform the bluetooth authentication.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
// Download the calibration data.
|
||||
const unsigned char args[9] = {0, 0, 0, 0, 0, 0x01, 0, 0, 0};
|
||||
status = pelagic_i330r_download (device, CMD_READ_HW_CAL, args, sizeof(args), device->hwcal, sizeof(device->hwcal));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to download the calibration data.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Hwcal", device->hwcal, sizeof(device->hwcal));
|
||||
|
||||
// Download the flash map.
|
||||
const unsigned char zero[9] = {0};
|
||||
status = pelagic_i330r_download (device, CMD_READ_EXFLASHMAP, zero, sizeof(zero), device->flashmap, sizeof(device->flashmap));
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
ERROR (context, "Failed to download the flash map.");
|
||||
goto error_free;
|
||||
}
|
||||
|
||||
HEXDUMP (context, DC_LOGLEVEL_DEBUG, "Flashmap", device->flashmap, sizeof(device->flashmap));
|
||||
|
||||
// Detect the memory layout.
|
||||
if (device->model == DSX) {
|
||||
device->base.layout = &pelagic_dsx;
|
||||
} else {
|
||||
device->base.layout = &pelagic_i330r;
|
||||
}
|
||||
|
||||
*out = (dc_device_t *) device;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
error_free:
|
||||
dc_device_deallocate ((dc_device_t *) device);
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size)
|
||||
{
|
||||
dc_status_t status = DC_STATUS_SUCCESS;
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t*) abstract;
|
||||
|
||||
unsigned char command[9] = {0};
|
||||
array_uint32_le_set(command + 0, address);
|
||||
array_uint32_le_set(command + 4, size);
|
||||
|
||||
status = pelagic_i330r_transfer (device, CMD_READ_FLASH, FLAG_NONE, command, sizeof(command), data, size, RSP_DONE);
|
||||
if (status != DC_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress)
|
||||
{
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
|
||||
// Emit a device info event.
|
||||
dc_event_devinfo_t devinfo;
|
||||
devinfo.model = device->model;
|
||||
devinfo.firmware = 0;
|
||||
devinfo.serial =
|
||||
bcd2dec (device->hwcal[12]) +
|
||||
bcd2dec (device->hwcal[13]) * 100 +
|
||||
bcd2dec (device->hwcal[14]) * 10000;
|
||||
device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
pelagic_i330r_device_pointers (dc_device_t *abstract, dc_event_progress_t *progress, unsigned int *rb_logbook_begin, unsigned int *rb_logbook_end, unsigned int *rb_profile_begin, unsigned int *rb_profile_end)
|
||||
{
|
||||
pelagic_i330r_device_t *device = (pelagic_i330r_device_t *) abstract;
|
||||
|
||||
assert (device != NULL);
|
||||
assert (device->base.layout != NULL);
|
||||
assert (rb_logbook_begin != NULL && rb_logbook_end != NULL);
|
||||
assert (rb_profile_begin != NULL && rb_profile_end != NULL);
|
||||
|
||||
const oceanic_common_layout_t *layout = device->base.layout;
|
||||
|
||||
// Get the logbook pointers.
|
||||
unsigned int rb_logbook_min = array_uint32_le (device->flashmap + 0x50);
|
||||
unsigned int rb_logbook_max = array_uint32_le (device->flashmap + 0x54);
|
||||
unsigned int rb_logbook_first = array_uint32_le (device->flashmap + 0x58);
|
||||
unsigned int rb_logbook_last = array_uint32_le (device->flashmap + 0x5C);
|
||||
if (rb_logbook_min != 0 && rb_logbook_max != 0) {
|
||||
rb_logbook_max += 1;
|
||||
}
|
||||
|
||||
// Get the profile pointers.
|
||||
unsigned int rb_profile_min = array_uint32_le (device->flashmap + 0x70);
|
||||
unsigned int rb_profile_max = array_uint32_le (device->flashmap + 0x74);
|
||||
unsigned int rb_profile_first = array_uint32_le (device->flashmap + 0x78);
|
||||
unsigned int rb_profile_last = array_uint32_le (device->flashmap + 0x7C);
|
||||
if (rb_profile_min != 0 && rb_profile_max != 0) {
|
||||
rb_profile_max += 1;
|
||||
}
|
||||
|
||||
// Check the logbook ringbuffer area.
|
||||
if (rb_logbook_min != layout->rb_logbook_begin ||
|
||||
rb_logbook_max != layout->rb_logbook_end) {
|
||||
ERROR (abstract->context, "Unexpected logbook ringbuffer area (%08x %08x)",
|
||||
rb_logbook_min, rb_logbook_max);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Check the profile ringbuffer area.
|
||||
if (rb_profile_min != layout->rb_profile_begin ||
|
||||
rb_profile_max != layout->rb_profile_end) {
|
||||
ERROR (abstract->context, "Unexpected profile ringbuffer area (%08x %08x)",
|
||||
rb_profile_min, rb_profile_max);
|
||||
return DC_STATUS_DATAFORMAT;
|
||||
}
|
||||
|
||||
// Get the begin/end pointers.
|
||||
if (device->model == DSX) {
|
||||
*rb_logbook_begin = rb_logbook_first;
|
||||
*rb_logbook_end = rb_logbook_last;
|
||||
} else {
|
||||
*rb_logbook_begin = rb_logbook_min;
|
||||
*rb_logbook_end = rb_logbook_last + 1;
|
||||
}
|
||||
*rb_profile_begin = rb_profile_first;
|
||||
*rb_profile_end = rb_profile_last;
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
/*
|
||||
* libdivecomputer
|
||||
*
|
||||
* Copyright (C) 2023 Janice McLaughlin
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301 USA
|
||||
*/
|
||||
// test 01
|
||||
|
||||
#ifndef PELAGIC_I330R_H
|
||||
#define PELAGIC_I330R_H
|
||||
|
||||
#include <libdivecomputer/context.h>
|
||||
#include <libdivecomputer/iostream.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
dc_status_t
|
||||
pelagic_i330r_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int model);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* PELAGIC_I330R_H */
|
||||
Loading…
x
Reference in New Issue
Block a user