Revert "Add support for the Aqualung i330R and Apeks DSX"

This reverts commit d1106cb8babb993d97b816f8274e22ae4fa6a08d.
This commit is contained in:
Jack 2024-06-14 14:04:43 -04:00
parent d1106cb8ba
commit 27a37fc95a
7 changed files with 260 additions and 1113 deletions

View File

@ -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

View File

@ -20,6 +20,8 @@
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libdivecomputer/units.h>
@ -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 ||

View File

@ -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;

View File

@ -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);

View File

@ -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 *

View File

@ -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 <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;
}

View File

@ -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 <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 */