diff --git a/src/Makefile.am b/src/Makefile.am index 16680d2..2139959 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,9 +1,9 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include -AM_CFLAGS = $(LIBUSB_CFLAGS) $(HIDAPI_CFLAGS) $(BLUEZ_CFLAGS) +AM_CFLAGS = $(LIBUSB_CFLAGS) $(LIBMTP_CFLAGS) $(HIDAPI_CFLAGS) $(BLUEZ_CFLAGS) lib_LTLIBRARIES = libdivecomputer.la -libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(HIDAPI_LIBS) $(BLUEZ_LIBS) -lm +libdivecomputer_la_LIBADD = $(LIBUSB_LIBS) $(LIBMTP_LIBS) $(HIDAPI_LIBS) $(BLUEZ_LIBS) -lm libdivecomputer_la_LDFLAGS = \ -version-info $(DC_VERSION_LIBTOOL) \ -no-undefined \ @@ -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 \ @@ -91,6 +90,12 @@ libdivecomputer_la_SOURCES = \ bluetooth.c \ custom.c +# Not merged upstream yet +libdivecomputer_la_SOURCES += \ + usb_storage.c \ + field-cache.h field-cache.c \ + garmin.h garmin.c garmin_parser.c + if OS_WIN32 libdivecomputer_la_SOURCES += serial_win32.c else diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 19b7a91..fe50796 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -20,6 +20,8 @@ */ #include +#include +#include #include @@ -35,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 @@ -51,9 +47,9 @@ 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; // Cached fields. unsigned int cached; unsigned int header; @@ -84,7 +80,7 @@ static const dc_parser_vtable_t oceanic_atom2_parser_vtable = { dc_status_t -oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model) +oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial) { oceanic_atom2_parser_t *parser = NULL; @@ -100,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 || @@ -139,16 +134,9 @@ 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; parser->cached = 0; parser->header = 0; parser->footer = 0; @@ -186,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: @@ -306,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. @@ -347,6 +323,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim return DC_STATUS_SUCCESS; } +#define BUF_LEN 16 static dc_status_t oceanic_atom2_parser_cache (oceanic_atom2_parser_t *parser) @@ -385,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. @@ -446,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; @@ -470,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; } @@ -516,6 +474,9 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; + dc_field_string_t *string = (dc_field_string_t *) value; + + char buf[BUF_LEN]; if (value) { switch (type) { @@ -532,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; @@ -555,58 +507,43 @@ oceanic_atom2_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, uns break; case DC_FIELD_SALINITY: if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC) { + parser->model == I750TC || parser->model == I770R) { if (data[0x18] & 0x80) { water->type = DC_WATER_FRESH; } else { 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: + switch(flags) { + case 0: /* Serial */ + string->desc = "Serial"; + snprintf(buf, BUF_LEN, "%06u", parser->serial); + break; + default: + return DC_STATUS_UNSUPPORTED; + } + string->value = strdup(buf); + break; default: return DC_STATUS_UNSUPPORTED; } @@ -669,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; @@ -704,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; @@ -722,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; } @@ -734,12 +664,12 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ } // Initial tank pressure. - unsigned int tank = 1; + unsigned int tank = 0; unsigned int pressure = 0; if (have_pressure) { unsigned int idx = 2; if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC) + parser->model == I750TC || parser->model == I770R) idx = 16; pressure = array_uint16_le(data + parser->header + idx); if (pressure == 10000) @@ -789,17 +719,17 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (sampletype == 0xAA) { if (parser->model == DATAMASK || parser->model == COMPUMASK) { // Tank pressure (1 psi) and number - tank = 1; + tank = 0; pressure = (((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF); } else if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC || parser->model == SAGE || - parser->model == BEACON) { + parser->model == I750TC || parser->model == I770R || + parser->model == SAGE || parser->model == BEACON) { // Tank pressure (1 psi) and number (one based index) - tank = data[offset + 1] & 0x03; + tank = (data[offset + 1] & 0x03) - 1; pressure = ((data[offset + 7] << 8) + data[offset + 6]) & 0x0FFF; } else { // Tank pressure (2 psi) and number (one based index) - tank = data[offset + 1] & 0x03; + tank = (data[offset + 1] & 0x03) - 1; if (parser->model == ATOM2 || parser->model == EPICA || parser->model == EPICB) pressure = (((data[offset + 3] << 8) + data[offset + 4]) & 0x0FFF) * 2; else @@ -892,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 || @@ -916,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); } @@ -945,17 +869,11 @@ 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; - } else { + else pressure -= data[offset + 1]; - } - if (tank) { - sample.pressure.tank = tank - 1; - sample.pressure.value = pressure * PSI / BAR; - if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); - } + sample.pressure.tank = tank; + sample.pressure.value = pressure * PSI / BAR; + if (callback) callback (DC_SAMPLE_PRESSURE, &sample, userdata); } // Depth (1/16 ft) @@ -973,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 @@ -992,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; @@ -1026,8 +935,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ have_deco = 1; } else if (parser->model == ATOM31 || parser->model == VISION || parser->model == XPAIR || parser->model == I550 || - parser->model == I550C || parser->model == WISDOM4 || - parser->model == PROPLUS4 || parser->model == ATMOSAI2) { + parser->model == I550C || parser->model == WISDOM4) { decostop = (data[offset + 5] & 0xF0) >> 4; decotime = array_uint16_le(data + offset + 4) & 0x03FF; have_deco = 1; @@ -1042,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; @@ -1084,8 +978,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ have_rbt = 1; } else if (parser->model == VISION || parser->model == XPAIR || parser->model == I550 || parser->model == I550C || - parser->model == WISDOM4 || parser->model == PROPLUS4 || - parser->model == ATMOSAI2) { + parser->model == WISDOM4) { rbt = array_uint16_le(data + offset + 6) & 0x03FF; have_rbt = 1; } @@ -1094,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 || diff --git a/src/oceanic_common.c b/src/oceanic_common.c index fc80bc1..62f5f74 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -32,62 +32,72 @@ #define VTABLE(abstract) ((const oceanic_common_device_vtable_t *) abstract->vtable) -#define RB_LOGBOOK_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_logbook_begin, l->rb_logbook_end) +#define RB_LOGBOOK_DISTANCE(a,b,l) ringbuffer_distance (a, b, 1, l->rb_logbook_begin, l->rb_logbook_end) +#define RB_LOGBOOK_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_logbook_begin, l->rb_logbook_end) -#define RB_PROFILE_DISTANCE(a,b,l,m) ringbuffer_distance (a, b, m, l->rb_profile_begin, l->rb_profile_end) +#define RB_PROFILE_DISTANCE(a,b,l) ringbuffer_distance (a, b, 0, l->rb_profile_begin, l->rb_profile_end) +#define RB_PROFILE_INCR(a,b,l) ringbuffer_increment (a, b, l->rb_profile_begin, l->rb_profile_end) #define INVALID 0 -static dc_status_t -oceanic_common_device_get_profile (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int *begin, unsigned int *end) +static unsigned int +get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) { - assert (layout != NULL); - assert (begin != NULL && end != NULL); + unsigned int value; - // Get the pagesize - unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE; - - // Get the profile pointers. - unsigned int first = 0, last = 0; if (layout->pt_mode_logbook == 0) { - first = array_uint16_le (data + 5); - last = array_uint16_le (data + 6) >> 4; + value = array_uint16_le (data + 5); } else if (layout->pt_mode_logbook == 1) { - first = array_uint16_le (data + 4); - last = array_uint16_le (data + 6); - } else if (layout->pt_mode_logbook == 2 || layout->pt_mode_logbook == 3) { - first = array_uint16_le (data + 16); - last = array_uint16_le (data + 18); - } else if (layout->pt_mode_logbook == 4) { - first = array_uint32_le (data + 8); - last = array_uint32_le (data + 12); + value = array_uint16_le (data + 4); + } else if (layout->pt_mode_logbook == 3) { + value = array_uint16_le (data + 16); + } else { + return array_uint16_le (data + 16); } - // Convert pages to bytes. - if (layout->pt_mode_logbook < 3) { - unsigned int npages = (layout->memsize - layout->highmem) / pagesize; - if (npages > 0x4000) { - first &= 0x7FFF; - last &= 0x7FFF; - } else if (npages > 0x2000) { - first &= 0x3FFF; - last &= 0x3FFF; - } else if (npages > 0x1000) { - first &= 0x1FFF; - last &= 0x1FFF; - } else { - first &= 0x0FFF; - last &= 0x0FFF; - } - - first *= pagesize; - last *= pagesize; + unsigned int npages = (layout->memsize - layout->highmem) / pagesize; + if (npages > 0x4000) { + value &= 0x7FFF; + } else if (npages > 0x2000) { + value &= 0x3FFF; + } else if (npages > 0x1000) { + value &= 0x1FFF; + } else { + value &= 0x0FFF; } - *begin = layout->highmem + first; - *end = layout->highmem + last + (layout->pt_mode_logbook < 4 ? pagesize : 0); + return layout->highmem + value * pagesize; +} - return DC_STATUS_SUCCESS; + +static unsigned int +get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) +{ + unsigned int value; + + if (layout->pt_mode_logbook == 0) { + value = array_uint16_le (data + 6) >> 4; + } else if (layout->pt_mode_logbook == 1) { + value = array_uint16_le (data + 6); + } else if (layout->pt_mode_logbook == 3) { + value = array_uint16_le (data + 18); + } else { + return array_uint16_le(data + 18); + } + + unsigned int npages = (layout->memsize - layout->highmem) / pagesize; + + if (npages > 0x4000) { + value &= 0x7FFF; + } else if (npages > 0x2000) { + value &= 0x3FFF; + } else if (npages > 0x1000) { + value &= 0x1FFF; + } else { + value &= 0x0FFF; + } + + return layout->highmem + value * pagesize; } @@ -196,11 +206,11 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return DC_STATUS_NOMEMORY; } - // Read the device info. - status = VTABLE(abstract)->devinfo (abstract, NULL); - if (status != DC_STATUS_SUCCESS) { - return status; - } + // Emit a vendor event. + dc_event_vendor_t vendor; + vendor.data = device->version; + vendor.size = sizeof (device->version); + device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); // Download the memory dump. status = device_dump_read (abstract, 0, dc_buffer_get_data (buffer), @@ -209,43 +219,8 @@ oceanic_common_device_dump (dc_device_t *abstract, dc_buffer_t *buffer) return status; } - return status; -} - - -dc_status_t -oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progress) -{ - dc_status_t status = DC_STATUS_SUCCESS; - oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; - - assert (device != NULL); - assert (device->layout != NULL); - - const oceanic_common_layout_t *layout = device->layout; - - // Read the device id. - unsigned char id[PAGESIZE] = {0}; - status = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); - return status; - } - - // Update and emit a progress event. - if (progress) { - progress->current += PAGESIZE; - progress->maximum += PAGESIZE; - device_event_emit (abstract, DC_EVENT_PROGRESS, progress); - } - - // Emit a vendor event. - dc_event_vendor_t vendor; - vendor.data = device->version; - vendor.size = sizeof (device->version); - device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); - // Emit a device info event. + unsigned char *id = dc_buffer_get_data (buffer) + layout->cf_devinfo; dc_event_devinfo_t devinfo; devinfo.model = array_uint16_be (id + 8); devinfo.firmware = device->firmware; @@ -265,51 +240,7 @@ oceanic_common_device_devinfo (dc_device_t *abstract, dc_event_progress_t *progr dc_status_t -oceanic_common_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) -{ - dc_status_t status = DC_STATUS_SUCCESS; - oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; - - assert (device != NULL); - assert (device->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->layout; - - // Read the pointer data. - unsigned char pointers[PAGESIZE] = {0}; - status = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the memory page."); - return status; - } - - // Update and emit a progress event. - if (progress) { - progress->current += PAGESIZE; - progress->maximum += PAGESIZE; - device_event_emit (abstract, DC_EVENT_PROGRESS, progress); - } - - // Get the pointers. - unsigned int rb_logbook_first = array_uint16_le (pointers + 4); - unsigned int rb_logbook_last = array_uint16_le (pointers + 6); - unsigned int rb_profile_first = array_uint16_le (pointers + 8); - unsigned int rb_profile_last = array_uint16_le (pointers + 10); - - *rb_logbook_begin = rb_logbook_first; - *rb_logbook_end = rb_logbook_last + (layout->pt_mode_global == 0 ? layout->rb_logbook_entry_size : 0); - *rb_profile_begin = rb_profile_first; - *rb_profile_end = rb_profile_last; - - return status; -} - -dc_status_t -oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end) +oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progress, dc_buffer_t *logbook) { oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; dc_status_t rc = DC_STATUS_SUCCESS; @@ -325,30 +256,37 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr if (!dc_buffer_clear (logbook)) return DC_STATUS_NOMEMORY; - // Validate the logbook pointers. - unsigned int rb_logbook_begin = begin; - unsigned int rb_logbook_end = end; - if (rb_logbook_begin < layout->rb_logbook_begin || - rb_logbook_begin > layout->rb_logbook_end) - { - ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_begin); - if (layout->rb_logbook_direction == 0) { - return DC_STATUS_DATAFORMAT; - } - // Fall back to downloading the entire logbook ringbuffer as - // workaround for an invalid logbook begin pointer! - rb_logbook_begin = rb_logbook_end; + // For devices without a logbook ringbuffer, downloading dives isn't + // possible. This is not considered a fatal error, but handled as if there + // are no dives present. + if (layout->rb_logbook_begin == layout->rb_logbook_end) { + return DC_STATUS_SUCCESS; } - if (rb_logbook_end < layout->rb_logbook_begin || - rb_logbook_end > layout->rb_logbook_end) + + // Read the pointer data. + unsigned char pointers[PAGESIZE] = {0}; + rc = dc_device_read (abstract, layout->cf_pointers, pointers, sizeof (pointers)); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); + return rc; + } + + // Get the logbook pointers. + unsigned int rb_logbook_first = array_uint16_le (pointers + 4); + unsigned int rb_logbook_last = array_uint16_le (pointers + 6); + if (rb_logbook_last < layout->rb_logbook_begin || + rb_logbook_last >= layout->rb_logbook_end) { - ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_end); - if (layout->rb_logbook_direction != 0) { - return DC_STATUS_DATAFORMAT; - } - // Fall back to downloading the entire logbook ringbuffer as - // workaround for an invalid logbook end pointer! - rb_logbook_end = rb_logbook_begin; + ERROR (abstract->context, "Invalid logbook end pointer detected (0x%04x).", rb_logbook_last); + return DC_STATUS_DATAFORMAT; + } + + // Calculate the end pointer. + unsigned int rb_logbook_end = 0; + if (layout->pt_mode_global == 0) { + rb_logbook_end = RB_LOGBOOK_INCR (rb_logbook_last, layout->rb_logbook_entry_size, layout); + } else { + rb_logbook_end = rb_logbook_last; } // Calculate the number of bytes. @@ -357,9 +295,21 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr // full ringbuffer. We always consider the ringbuffer full in that // case, because an empty ringbuffer can be detected by inspecting // the logbook entries once they are downloaded. - unsigned int rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_begin, rb_logbook_end, layout, DC_RINGBUFFER_FULL); + unsigned int rb_logbook_size = 0; + if (rb_logbook_first < layout->rb_logbook_begin || + rb_logbook_first >= layout->rb_logbook_end) + { + // Fall back to downloading the entire logbook ringbuffer as + // workaround for an invalid logbook begin pointer! + ERROR (abstract->context, "Invalid logbook begin pointer detected (0x%04x).", rb_logbook_first); + rb_logbook_size = layout->rb_logbook_end - layout->rb_logbook_begin; + } else { + rb_logbook_size = RB_LOGBOOK_DISTANCE (rb_logbook_first, rb_logbook_end, layout); + } // Update and emit a progress event. + progress->current += PAGESIZE; + progress->maximum += PAGESIZE; progress->maximum -= (layout->rb_logbook_end - layout->rb_logbook_begin) - rb_logbook_size; device_event_emit (abstract, DC_EVENT_PROGRESS, progress); @@ -377,11 +327,7 @@ oceanic_common_device_logbook (dc_device_t *abstract, dc_event_progress_t *progr // Create the ringbuffer stream. dc_rbstream_t *rbstream = NULL; - rc = dc_rbstream_new (&rbstream, abstract, - PAGESIZE, PAGESIZE * device->multipage, - layout->rb_logbook_begin, layout->rb_logbook_end, - layout->rb_logbook_direction ? rb_logbook_end : rb_logbook_begin, - layout->rb_logbook_direction ? DC_RBSTREAM_BACKWARD : DC_RBSTREAM_FORWARD); + rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_logbook_begin, layout->rb_logbook_end, rb_logbook_end); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to create the ringbuffer stream."); return rc; @@ -457,6 +403,9 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr const oceanic_common_layout_t *layout = device->layout; + // Get the pagesize + unsigned int pagesize = layout->highmem ? 16 * PAGESIZE : PAGESIZE; + // Cache the logbook pointer and size. const unsigned char *logbooks = dc_buffer_get_data (logbook); unsigned int rb_logbook_size = dc_buffer_get_size (logbook); @@ -464,7 +413,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr // Go through the logbook entries a first time, to get the end of // profile pointer and calculate the total amount of bytes in the // profile ringbuffer. - unsigned int rb_profile_begin = INVALID; unsigned int rb_profile_end = INVALID; unsigned int rb_profile_size = 0; @@ -486,20 +434,22 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // Get the profile pointers. - unsigned int rb_entry_begin = 0, rb_entry_end = 0; - oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); - if (rb_entry_begin < layout->rb_profile_begin || - rb_entry_begin > layout->rb_profile_end || - rb_entry_end < layout->rb_profile_begin || - rb_entry_end > layout->rb_profile_end) + unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize); + unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize); + if (rb_entry_first < layout->rb_profile_begin || + rb_entry_first >= layout->rb_profile_end || + rb_entry_last < layout->rb_profile_begin || + rb_entry_last >= layout->rb_profile_end) { ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", - rb_entry_begin, rb_entry_end); + rb_entry_first, rb_entry_last); status = DC_STATUS_DATAFORMAT; continue; } - DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); + // Calculate the end pointer and the number of bytes. + unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout); + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize; // Take the end pointer of the most recent logbook entry as the // end of profile pointer. @@ -507,13 +457,11 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr rb_profile_end = previous = rb_entry_end; } - // Calculate the number of bytes. - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL); - // Skip gaps between the profiles. - unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); - if (gap) { - WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); + unsigned int gap = 0; + if (rb_entry_end != previous) { + WARNING (abstract->context, "Profiles are not continuous."); + gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); } // Make sure the profile size is valid. @@ -522,18 +470,13 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr break; } - // Update the profile begin pointer. - rb_profile_begin = rb_entry_begin; - // Update the total profile size. rb_profile_size += rb_entry_size + gap; remaining -= rb_entry_size + gap; - previous = rb_entry_begin; + previous = rb_entry_first; } - DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end); - // At this point, we know the exact amount of data // that needs to be transfered for the profiles. progress->maximum -= (layout->rb_profile_end - layout->rb_profile_begin) - rb_profile_size; @@ -546,7 +489,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr // Create the ringbuffer stream. dc_rbstream_t *rbstream = NULL; - rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end, DC_RBSTREAM_BACKWARD); + rc = dc_rbstream_new (&rbstream, abstract, PAGESIZE, PAGESIZE * device->multipage, layout->rb_profile_begin, layout->rb_profile_end, rb_profile_end); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to create the ringbuffer stream."); return rc; @@ -581,28 +524,28 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // Get the profile pointers. - unsigned int rb_entry_begin = 0, rb_entry_end = 0; - oceanic_common_device_get_profile (logbooks + entry, layout, &rb_entry_begin, &rb_entry_end); - if (rb_entry_begin < layout->rb_profile_begin || - rb_entry_begin > layout->rb_profile_end || - rb_entry_end < layout->rb_profile_begin || - rb_entry_end > layout->rb_profile_end) + unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout, pagesize); + unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout, pagesize); + if (rb_entry_first < layout->rb_profile_begin || + rb_entry_first >= layout->rb_profile_end || + rb_entry_last < layout->rb_profile_begin || + rb_entry_last >= layout->rb_profile_end) { ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", - rb_entry_begin, rb_entry_end); + rb_entry_first, rb_entry_last); status = DC_STATUS_DATAFORMAT; continue; } - DEBUG (abstract->context, "Entry: %08x %08x", rb_entry_begin, rb_entry_end); - - // Calculate the number of bytes. - unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_begin, rb_entry_end, layout, DC_RINGBUFFER_FULL); + // Calculate the end pointer and the number of bytes. + unsigned int rb_entry_end = RB_PROFILE_INCR (rb_entry_last, pagesize, layout); + unsigned int rb_entry_size = RB_PROFILE_DISTANCE (rb_entry_first, rb_entry_last, layout) + pagesize; // Skip gaps between the profiles. - unsigned int gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout, DC_RINGBUFFER_EMPTY); - if (gap) { - WARNING (abstract->context, "Profiles are not continuous (%u bytes).", gap); + unsigned int gap = 0; + if (rb_entry_end != previous) { + WARNING (abstract->context, "Profiles are not continuous."); + gap = RB_PROFILE_DISTANCE (rb_entry_end, previous, layout); } // Make sure the profile size is valid. @@ -623,7 +566,7 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } remaining -= rb_entry_size + gap; - previous = rb_entry_begin; + previous = rb_entry_first; // Prepend the logbook entry to the profile data. The memory buffer is // large enough to store this entry. @@ -661,7 +604,6 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr dc_status_t oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) { - dc_status_t rc = DC_STATUS_SUCCESS; oceanic_common_device_t *device = (oceanic_common_device_t *) abstract; assert (device != NULL); @@ -669,37 +611,45 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac const oceanic_common_layout_t *layout = device->layout; - // For devices without a logbook and profile ringbuffer, downloading dives - // isn't possible. This is not considered a fatal error, but handled as if - // there are no dives present. - if (layout->rb_logbook_begin == layout->rb_logbook_end && - layout->rb_profile_begin == layout->rb_profile_end) { - return DC_STATUS_SUCCESS; - } - // Enable progress notifications. dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - progress.maximum = + progress.maximum = PAGESIZE + (layout->rb_logbook_end - layout->rb_logbook_begin) + (layout->rb_profile_end - layout->rb_profile_begin); device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - // Read the device info. - rc = VTABLE(abstract)->devinfo (abstract, &progress); + // Emit a vendor event. + dc_event_vendor_t vendor; + vendor.data = device->version; + vendor.size = sizeof (device->version); + device_event_emit (abstract, DC_EVENT_VENDOR, &vendor); + + // Read the device id. + unsigned char id[PAGESIZE] = {0}; + dc_status_t rc = dc_device_read (abstract, layout->cf_devinfo, id, sizeof (id)); if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the memory page."); return rc; } - // Read the ringbuffer pointers. - unsigned int rb_logbook_begin = 0, rb_logbook_end = 0; - unsigned int rb_profile_begin = 0, rb_profile_end = 0; - rc = VTABLE(abstract)->pointers (abstract, &progress, &rb_logbook_begin, &rb_logbook_end, &rb_profile_begin, &rb_profile_end); - if (rc != DC_STATUS_SUCCESS) { - return rc; - } + // Update and emit a progress event. + progress.current += PAGESIZE; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - DEBUG (abstract->context, "Logbook: %08x %08x", rb_logbook_begin, rb_logbook_end); - DEBUG (abstract->context, "Profile: %08x %08x", rb_profile_begin, rb_profile_end); + // Emit a device info event. + dc_event_devinfo_t devinfo; + devinfo.model = array_uint16_be (id + 8); + devinfo.firmware = device->firmware; + if (layout->pt_mode_serial == 0) + devinfo.serial = array_convert_bcd2dec (id + 10, 3); + else if (layout->pt_mode_serial == 1) + devinfo.serial = array_convert_bin2dec (id + 11, 3); + else + devinfo.serial = + (id[11] & 0x0F) * 100000 + ((id[11] & 0xF0) >> 4) * 10000 + + (id[12] & 0x0F) * 1000 + ((id[12] & 0xF0) >> 4) * 100 + + (id[13] & 0x0F) * 10 + ((id[13] & 0xF0) >> 4) * 1; + device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); // Memory buffer for the logbook data. dc_buffer_t *logbook = dc_buffer_new (0); @@ -708,7 +658,7 @@ oceanic_common_device_foreach (dc_device_t *abstract, dc_dive_callback_t callbac } // Download the logbook ringbuffer. - rc = VTABLE(abstract)->logbook (abstract, &progress, logbook, rb_logbook_begin, rb_logbook_end); + rc = VTABLE(abstract)->logbook (abstract, &progress, logbook); if (rc != DC_STATUS_SUCCESS) { dc_buffer_free (logbook); return rc; diff --git a/src/oceanic_common.h b/src/oceanic_common.h index 43254a9..045dca4 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -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), \ @@ -148,7 +144,6 @@ typedef struct oceanic_common_layout_t { unsigned int rb_logbook_begin; unsigned int rb_logbook_end; unsigned int rb_logbook_entry_size; - unsigned int rb_logbook_direction; // Profile ringbuffer unsigned int rb_profile_begin; unsigned int rb_profile_end; @@ -173,9 +168,7 @@ typedef struct oceanic_common_device_t { typedef struct oceanic_common_device_vtable_t { dc_device_vtable_t base; - dc_status_t (*devinfo) (dc_device_t *device, dc_event_progress_t *progress); - dc_status_t (*pointers) (dc_device_t *device, 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); - dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end); + dc_status_t (*logbook) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); dc_status_t (*profile) (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); } oceanic_common_device_vtable_t; @@ -193,15 +186,7 @@ void oceanic_common_device_init (oceanic_common_device_t *device); dc_status_t -oceanic_common_device_devinfo (dc_device_t *device, dc_event_progress_t *progress); - -dc_status_t -oceanic_common_device_pointers (dc_device_t *device, 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); - -dc_status_t -oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, unsigned int begin, unsigned int end); +oceanic_common_device_logbook (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook); dc_status_t oceanic_common_device_profile (dc_device_t *device, dc_event_progress_t *progress, dc_buffer_t *logbook, dc_dive_callback_t callback, void *userdata); diff --git a/src/parser.c b/src/parser.c index bc143f4..d63c5c6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -66,6 +66,9 @@ #include "oceans_s1.h" #include "divesoft_freedom.h" +// Not merged upstream yet +#include "garmin.h" + #include "context-private.h" #include "parser-private.h" #include "device-private.h" @@ -73,7 +76,7 @@ #define REACTPROWHITE 0x4354 static dc_status_t -dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, dc_family_t family, unsigned int model) +dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, dc_family_t family, unsigned int model, unsigned int serial) { dc_status_t rc = DC_STATUS_SUCCESS; dc_parser_t *parser = NULL; @@ -92,11 +95,11 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned if (model == 0x01) rc = suunto_eon_parser_create (&parser, context, data, size, 1); else - rc = suunto_vyper_parser_create (&parser, context, data, size); + rc = suunto_vyper_parser_create (&parser, context, data, size, serial); break; case DC_FAMILY_SUUNTO_VYPER2: case DC_FAMILY_SUUNTO_D9: - rc = suunto_d9_parser_create (&parser, context, data, size, model); + rc = suunto_d9_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_SUUNTO_EONSTEEL: rc = suunto_eonsteel_parser_create(&parser, context, data, size, model); @@ -124,11 +127,10 @@ 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 - rc = oceanic_atom2_parser_create (&parser, context, data, size, model); + rc = oceanic_atom2_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_MARES_NEMO: case DC_FAMILY_MARES_PUCK: @@ -138,14 +140,14 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned rc = mares_darwin_parser_create (&parser, context, data, size, model); break; case DC_FAMILY_MARES_ICONHD: - rc = mares_iconhd_parser_create (&parser, context, data, size, model); + rc = mares_iconhd_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, data, size); + rc = hw_ostc_parser_create (&parser, context, data, size, serial); break; case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_OSTC3: - rc = hw_ostc3_parser_create (&parser, context, data, size, model); + rc = hw_ostc3_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_CRESSI_EDY: case DC_FAMILY_ZEAGLE_N2ITION3: @@ -161,10 +163,10 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned rc = atomics_cobalt_parser_create (&parser, context, data, size); break; case DC_FAMILY_SHEARWATER_PREDATOR: - rc = shearwater_predator_parser_create (&parser, context, data, size, model); + rc = shearwater_predator_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_SHEARWATER_PETREL: - rc = shearwater_petrel_parser_create (&parser, context, data, size, model); + rc = shearwater_petrel_parser_create (&parser, context, data, size, model, serial); break; case DC_FAMILY_DIVERITE_NITEKQ: rc = diverite_nitekq_parser_create (&parser, context, data, size); @@ -207,6 +209,11 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, const unsigned break; default: return DC_STATUS_INVALIDARGS; + + // Not merged upstream yet + case DC_FAMILY_GARMIN: + rc = garmin_parser_create (&parser, context, data, size); + break; } *out = parser; @@ -224,7 +231,7 @@ dc_parser_new (dc_parser_t **out, dc_device_t *device, const unsigned char data[ return DC_STATUS_INVALIDARGS; status = dc_parser_new_internal (&parser, device->context, data, size, - dc_device_get_type (device), device->devinfo.model); + dc_device_get_type (device), device->devinfo.model, device->devinfo.serial); if (status != DC_STATUS_SUCCESS) goto error_exit; @@ -246,7 +253,7 @@ dc_status_t dc_parser_new2 (dc_parser_t **out, dc_context_t *context, dc_descriptor_t *descriptor, const unsigned char data[], size_t size) { return dc_parser_new_internal (out, context, data, size, - dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor)); + dc_descriptor_get_type (descriptor), dc_descriptor_get_model (descriptor), 0); } dc_parser_t * diff --git a/src/pelagic_i330r.c b/src/pelagic_i330r.c deleted file mode 100644 index 17aad3b..0000000 --- a/src/pelagic_i330r.c +++ /dev/null @@ -1,646 +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 - */ - -#include // memcpy -#include // malloc, free -#include - -#include - -#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; -} diff --git a/src/pelagic_i330r.h b/src/pelagic_i330r.h deleted file mode 100644 index 23045cd..0000000 --- a/src/pelagic_i330r.h +++ /dev/null @@ -1,40 +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 - */ - -#ifndef PELAGIC_I330R_H -#define PELAGIC_I330R_H - -#include -#include -#include -#include - -#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 */