From aee70d1ec7a016334dab766d25c7f7bb637d6082 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Wed, 13 Dec 2017 23:18:47 +0100 Subject: [PATCH 1/7] Add support for the Oceanic Pro Plus X The Oceanic Pro Plus X is quite different from the previous models. The profile data is now stored in a dedicated memory area, and hence there are a few important differences: Reading data from the new profile memory area is done with a new F6 command. This new command is very similar to the existing B8 command, but accesses a completely different memory area. In order to integrate those two memory areas as transparantly as possible into the existing infrastructure, a virtual memory space is introduced. The lower part of the virtual memory is mapped onto the main memory area, while the upper part is mapped onto the new profile memory area. The page size of the new profile memory area also increased from 16 to 256 bytes. If the profile size is not an exact multiple of 256 bytes, the dive computer pads the profile data with 0xFF bytes. The other changes are the usual Oceanic device specific changes. --- src/descriptor.c | 1 + src/oceanic_atom2.c | 78 ++++++++++++++++++++++++++++++++++---- src/oceanic_atom2_parser.c | 19 +++++++--- src/oceanic_common.c | 65 ++++++++++++++++++++----------- src/oceanic_common.h | 1 + src/oceanic_veo250.c | 1 + src/oceanic_vtpro.c | 3 ++ 7 files changed, 132 insertions(+), 36 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index c4e86ca..72db49a 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -208,6 +208,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B, DC_TRANSPORT_SERIAL, NULL}, {"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C, DC_TRANSPORT_SERIAL, NULL}, {"Beuchat", "Mundial 3", DC_FAMILY_OCEANIC_ATOM2, 0x4550, DC_TRANSPORT_SERIAL, NULL}, + {"Oceanic", "Pro Plus X", DC_FAMILY_OCEANIC_ATOM2, 0x4552, DC_TRANSPORT_SERIAL, NULL}, {"Oceanic", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x4553, DC_TRANSPORT_SERIAL, NULL}, {"Oceanic", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4554, DC_TRANSPORT_SERIAL, NULL}, {"Subgear", "XP-Air", DC_FAMILY_OCEANIC_ATOM2, 0x4555, DC_TRANSPORT_SERIAL, NULL}, diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index f7a9b7a..c33c880 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -32,6 +32,7 @@ #define ISINSTANCE(device) dc_device_isinstance((device), &oceanic_atom2_device_vtable.base) +#define PROPLUSX 0x4552 #define VTX 0x4557 #define I750TC 0x455A @@ -44,6 +45,7 @@ #define CMD_READ1 0xB1 #define CMD_READ8 0xB4 #define CMD_READ16 0xB8 +#define CMD_READ16HI 0xF6 #define CMD_WRITE 0xB2 #define CMD_KEEPALIVE 0x91 #define CMD_QUIT 0x6A @@ -57,7 +59,8 @@ typedef struct oceanic_atom2_device_t { unsigned int delay; unsigned int bigpage; unsigned char cache[256]; - unsigned int cached; + unsigned int cached_page; + unsigned int cached_highmem; } oceanic_atom2_device_t; static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); @@ -184,6 +187,10 @@ static const oceanic_common_version_t oceanic_reactpro_version[] = { {"REACPRO2 \0\0 512K"}, }; +static const oceanic_common_version_t oceanic_proplusx_version[] = { + {"OCEANOCX \0\0 2048"}, +}; + static const oceanic_common_version_t aeris_a300cs_version[] = { {"AER300CS \0\0 2048"}, {"OCEANVTX \0\0 2048"}, @@ -196,6 +203,7 @@ static const oceanic_common_version_t aqualung_i450t_version[] = { static const oceanic_common_layout_t aeris_f10_layout = { 0x10000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0100, /* rb_logbook_begin */ @@ -210,6 +218,7 @@ static const oceanic_common_layout_t aeris_f10_layout = { static const oceanic_common_layout_t aeris_f11_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0100, /* rb_logbook_begin */ @@ -224,6 +233,7 @@ static const oceanic_common_layout_t aeris_f11_layout = { static const oceanic_common_layout_t oceanic_default_layout = { 0x10000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -238,6 +248,7 @@ static const oceanic_common_layout_t oceanic_default_layout = { static const oceanic_common_layout_t oceanic_atom1_layout = { 0x8000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -252,6 +263,7 @@ static const oceanic_common_layout_t oceanic_atom1_layout = { static const oceanic_common_layout_t oceanic_atom2a_layout = { 0xFFF0, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -266,6 +278,7 @@ static const oceanic_common_layout_t oceanic_atom2a_layout = { static const oceanic_common_layout_t oceanic_atom2b_layout = { 0x10000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -280,6 +293,7 @@ static const oceanic_common_layout_t oceanic_atom2b_layout = { static const oceanic_common_layout_t oceanic_atom2c_layout = { 0xFFF0, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -294,6 +308,7 @@ static const oceanic_common_layout_t oceanic_atom2c_layout = { static const oceanic_common_layout_t sherwood_wisdom_layout = { 0xFFF0, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x03D0, /* rb_logbook_begin */ @@ -308,6 +323,7 @@ static const oceanic_common_layout_t sherwood_wisdom_layout = { static const oceanic_common_layout_t oceanic_proplus3_layout = { 0x10000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x03E0, /* rb_logbook_begin */ @@ -322,6 +338,7 @@ static const oceanic_common_layout_t oceanic_proplus3_layout = { static const oceanic_common_layout_t tusa_zenair_layout = { 0xFFF0, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -336,6 +353,7 @@ static const oceanic_common_layout_t tusa_zenair_layout = { static const oceanic_common_layout_t oceanic_oc1_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -350,6 +368,7 @@ static const oceanic_common_layout_t oceanic_oc1_layout = { static const oceanic_common_layout_t oceanic_oci_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x10C0, /* rb_logbook_begin */ @@ -364,6 +383,7 @@ static const oceanic_common_layout_t oceanic_oci_layout = { static const oceanic_common_layout_t oceanic_atom3_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0400, /* rb_logbook_begin */ @@ -378,6 +398,7 @@ static const oceanic_common_layout_t oceanic_atom3_layout = { static const oceanic_common_layout_t oceanic_vt4_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0420, /* rb_logbook_begin */ @@ -392,6 +413,7 @@ static const oceanic_common_layout_t oceanic_vt4_layout = { static const oceanic_common_layout_t hollis_tx1_layout = { 0x40000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0780, /* rb_logbook_begin */ @@ -406,6 +428,7 @@ static const oceanic_common_layout_t hollis_tx1_layout = { static const oceanic_common_layout_t oceanic_veo1_layout = { 0x0400, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0400, /* rb_logbook_begin */ @@ -420,6 +443,7 @@ static const oceanic_common_layout_t oceanic_veo1_layout = { static const oceanic_common_layout_t oceanic_reactpro_layout = { 0xFFF0, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0400, /* rb_logbook_begin */ @@ -432,8 +456,24 @@ static const oceanic_common_layout_t oceanic_reactpro_layout = { 1, /* pt_mode_serial */ }; +static const oceanic_common_layout_t oceanic_proplusx_layout = { + 0x440000, /* memsize */ + 0x40000, /* highmem */ + 0x0000, /* cf_devinfo */ + 0x0040, /* cf_pointers */ + 0x1000, /* rb_logbook_begin */ + 0x10000, /* rb_logbook_end */ + 16, /* rb_logbook_entry_size */ + 0x40000, /* rb_profile_begin */ + 0x440000, /* rb_profile_end */ + 0, /* pt_mode_global */ + 1, /* pt_mode_logbook */ + 0, /* pt_mode_serial */ +}; + static const oceanic_common_layout_t aeris_a300cs_layout = { 0x40000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0900, /* rb_logbook_begin */ @@ -448,6 +488,7 @@ static const oceanic_common_layout_t aeris_a300cs_layout = { static const oceanic_common_layout_t aqualung_i450t_layout = { 0x40000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x10C0, /* rb_logbook_begin */ @@ -595,12 +636,13 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream device->iostream = iostream; device->delay = 0; device->bigpage = 1; // no big pages - device->cached = INVALID; + device->cached_page = INVALID; + device->cached_highmem = INVALID; memset(device->cache, 0, sizeof(device->cache)); // Get the correct baudrate. unsigned int baudrate = 38400; - if (model == VTX || model == I750TC) { + if (model == VTX || model == I750TC || model == PROPLUSX) { baudrate = 115200; } @@ -684,6 +726,9 @@ oceanic_atom2_device_open (dc_device_t **out, dc_context_t *context, dc_iostream device->base.layout = &oceanic_veo1_layout; } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_reactpro_version)) { device->base.layout = &oceanic_reactpro_layout; + } else if (OCEANIC_COMMON_MATCH (device->base.version, oceanic_proplusx_version)) { + device->base.layout = &oceanic_proplusx_layout; + device->bigpage = 16; } else if (OCEANIC_COMMON_MATCH (device->base.version, aeris_a300cs_version)) { device->base.layout = &aeris_a300cs_layout; device->bigpage = 16; @@ -779,6 +824,7 @@ static dc_status_t oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size) { oceanic_atom2_device_t *device = (oceanic_atom2_device_t*) abstract; + const oceanic_common_layout_t *layout = device->base.layout; if ((address % PAGESIZE != 0) || (size % PAGESIZE != 0)) @@ -807,12 +853,26 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned // Pick the best pagesize to use. unsigned int pagesize = device->bigpage * PAGESIZE; + // High memory state. + unsigned int highmem = 0; + unsigned int nbytes = 0; while (nbytes < size) { - unsigned int page = address / pagesize; - if (page != device->cached) { + // Switch to the correct read command when entering the high memory area. + if (layout->highmem && address >= layout->highmem && !highmem) { + highmem = layout->highmem; + read_cmd = CMD_READ16HI; + crc_size = 2; + pagesize = 16 * PAGESIZE; + } + + // Calculate the page number after mapping the virtual high memory + // addresses back to their physical address. + unsigned int page = (address - highmem) / pagesize; + + if (page != device->cached_page || highmem != device->cached_highmem) { // Read the package. - unsigned int number = page * device->bigpage; // This is always PAGESIZE, even in big page mode. + unsigned int number = highmem ? page : page * device->bigpage; // This is always PAGESIZE, even in big page mode. unsigned char answer[256 + 2] = {0}; // Maximum we support for the known commands. unsigned char command[4] = {read_cmd, (number >> 8) & 0xFF, // high @@ -824,7 +884,8 @@ oceanic_atom2_device_read (dc_device_t *abstract, unsigned int address, unsigned // Cache the page. memcpy (device->cache, answer, pagesize); - device->cached = page; + device->cached_page = page; + device->cached_highmem = highmem; } unsigned int offset = address % pagesize; @@ -853,7 +914,8 @@ oceanic_atom2_device_write (dc_device_t *abstract, unsigned int address, const u return DC_STATUS_INVALIDARGS; // Invalidate the cache. - device->cached = INVALID; + device->cached_page = INVALID; + device->cached_highmem = INVALID; unsigned int nbytes = 0; while (nbytes < size) { diff --git a/src/oceanic_atom2_parser.c b/src/oceanic_atom2_parser.c index 0550983..227eae6 100644 --- a/src/oceanic_atom2_parser.c +++ b/src/oceanic_atom2_parser.c @@ -75,6 +75,7 @@ #define OCI 0x454B #define A300CS 0x454C #define MUNDIAL3 0x4550 +#define PROPLUSX 0x4552 #define F10B 0x4553 #define F11B 0x4554 #define XPAIR 0x4555 @@ -174,6 +175,8 @@ oceanic_atom2_parser_create (dc_parser_t **out, dc_context_t *context, unsigned } else if (model == A300CS || model == VTX || model == I450T || model == I750TC) { parser->headersize = 5 * PAGESIZE; + } else if (model == PROPLUSX) { + parser->headersize = 3 * PAGESIZE; } parser->cached = 0; @@ -309,6 +312,7 @@ oceanic_atom2_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetim case VTX: case I450T: case I750TC: + case PROPLUSX: datetime->year = (p[10]) + 2000; datetime->month = (p[8]); datetime->day = (p[9]); @@ -622,7 +626,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ if (parser->mode != FREEDIVE) { unsigned int idx = 0x17; if (parser->model == A300CS || parser->model == VTX || - parser->model == I450T || parser->model == I750TC) + parser->model == I450T || parser->model == I750TC || + parser->model == PROPLUSX) idx = 0x1f; switch (data[idx] & 0x03) { case 0: @@ -677,7 +682,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == OC1C || parser->model == OCI || parser->model == TX1 || parser->model == A300CS || parser->model == VTX || parser->model == I450T || - parser->model == I750TC) { + parser->model == I750TC || parser->model == PROPLUSX) { samplesize = PAGESIZE; } @@ -855,7 +860,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == XPAIR) { temperature = ((data[offset + 7] & 0xF0) >> 4) | ((data[offset + 7] & 0x0C) << 2) | ((data[offset + 5] & 0x0C) << 4); } else if (parser->model == A300CS || parser->model == VTX || - parser->model == I750TC) { + parser->model == I750TC || parser->model == PROPLUSX) { temperature = data[offset + 11]; } else { unsigned int sign; @@ -895,7 +900,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ parser->model == VISION || parser->model == XPAIR) pressure = (((data[offset + 0] & 0x03) << 8) + data[offset + 1]) * 5; else if (parser->model == TX1 || parser->model == A300CS || - parser->model == VTX || parser->model == I750TC) + parser->model == VTX || parser->model == I750TC || + parser->model == PROPLUSX) pressure = array_uint16_le (data + offset + 4); else pressure -= data[offset + 1]; @@ -943,7 +949,8 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ unsigned int have_deco = 0; unsigned int decostop = 0, decotime = 0; if (parser->model == A300CS || parser->model == VTX || - parser->model == I450T || parser->model == I750TC) { + parser->model == I450T || parser->model == I750TC || + parser->model == PROPLUSX) { decostop = (data[offset + 15] & 0x70) >> 4; decotime = array_uint16_le(data + offset + 6) & 0x03FF; have_deco = 1; @@ -986,7 +993,7 @@ oceanic_atom2_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_ have_rbt = 1; } else if (parser->model == I450T || parser->model == OC1A || parser->model == OC1B || parser->model == OC1C || - parser->model == OCI) { + parser->model == OCI || parser->model == PROPLUSX) { rbt = array_uint16_le(data + offset + 8) & 0x01FF; have_rbt = 1; } else if (parser->model == VISION || parser->model == XPAIR || diff --git a/src/oceanic_common.c b/src/oceanic_common.c index 9f7341a..908896c 100644 --- a/src/oceanic_common.c +++ b/src/oceanic_common.c @@ -41,7 +41,7 @@ #define INVALID 0 static unsigned int -get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout) +get_profile_first (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) { unsigned int value; @@ -55,17 +55,22 @@ get_profile_first (const unsigned char data[], const oceanic_common_layout_t *la return array_uint16_le (data + 16); } - if (layout->memsize > 0x20000) - return (value & 0x3FFF) * PAGESIZE; - else if (layout->memsize > 0x10000) - return (value & 0x1FFF) * PAGESIZE; - else - return (value & 0x0FFF) * PAGESIZE; + unsigned int npages = (layout->memsize - layout->highmem) / pagesize; + + if (npages > 0x2000) { + value &= 0x3FFF; + } else if (npages > 0x1000) { + value &= 0x1FFF; + } else { + value &= 0x0FFF; + } + + return layout->highmem + value * pagesize; } static unsigned int -get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout) +get_profile_last (const unsigned char data[], const oceanic_common_layout_t *layout, unsigned int pagesize) { unsigned int value; @@ -79,12 +84,17 @@ get_profile_last (const unsigned char data[], const oceanic_common_layout_t *lay return array_uint16_le(data + 18); } - if (layout->memsize > 0x20000) - return (value & 0x3FFF) * PAGESIZE; - else if (layout->memsize > 0x10000) - return (value & 0x1FFF) * PAGESIZE; - else - return (value & 0x0FFF) * PAGESIZE; + unsigned int npages = (layout->memsize - layout->highmem) / pagesize; + + if (npages > 0x2000) { + value &= 0x3FFF; + } else if (npages > 0x1000) { + value &= 0x1FFF; + } else { + value &= 0x0FFF; + } + + return layout->highmem + value * pagesize; } @@ -330,6 +340,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); @@ -352,8 +365,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr entry -= layout->rb_logbook_entry_size; // Get the profile pointers. - unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout); - unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout); + 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 || @@ -365,8 +378,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // 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; + 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. @@ -430,8 +443,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr entry -= layout->rb_logbook_entry_size; // Get the profile pointers. - unsigned int rb_entry_first = get_profile_first (logbooks + entry, layout); - unsigned int rb_entry_last = get_profile_last (logbooks + entry, layout); + 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 || @@ -445,8 +458,8 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr } // 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; + 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 = 0; @@ -481,6 +494,14 @@ oceanic_common_device_profile (dc_device_t *abstract, dc_event_progress_t *progr offset -= layout->rb_logbook_entry_size; memcpy (profiles + offset, logbooks + entry, layout->rb_logbook_entry_size); + // Remove padding from the profile. + if (layout->highmem) { + unsigned char *profile = profiles + offset + layout->rb_logbook_entry_size; + while (rb_entry_size >= PAGESIZE && array_isequal (profile + rb_entry_size - PAGESIZE, PAGESIZE, 0xFF)) { + rb_entry_size -= PAGESIZE; + } + } + unsigned char *p = profiles + offset; if (callback && !callback (p, rb_entry_size + layout->rb_logbook_entry_size, p, layout->rb_logbook_entry_size, userdata)) { break; diff --git a/src/oceanic_common.h b/src/oceanic_common.h index 1b8ed08..a5c55b8 100644 --- a/src/oceanic_common.h +++ b/src/oceanic_common.h @@ -38,6 +38,7 @@ extern "C" { typedef struct oceanic_common_layout_t { // Memory size. unsigned int memsize; + unsigned int highmem; // Device info. unsigned int cf_devinfo; // Ringbuffer pointers. diff --git a/src/oceanic_veo250.c b/src/oceanic_veo250.c index 42cb676..de70c7b 100644 --- a/src/oceanic_veo250.c +++ b/src/oceanic_veo250.c @@ -75,6 +75,7 @@ static const oceanic_common_version_t oceanic_veo250_version[] = { static const oceanic_common_layout_t oceanic_veo250_layout = { 0x8000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0400, /* rb_logbook_begin */ diff --git a/src/oceanic_vtpro.c b/src/oceanic_vtpro.c index 2c9298b..d3387f2 100644 --- a/src/oceanic_vtpro.c +++ b/src/oceanic_vtpro.c @@ -89,6 +89,7 @@ static const oceanic_common_version_t oceanic_wisdom_version[] = { static const oceanic_common_layout_t oceanic_vtpro_layout = { 0x8000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x0240, /* rb_logbook_begin */ @@ -103,6 +104,7 @@ static const oceanic_common_layout_t oceanic_vtpro_layout = { static const oceanic_common_layout_t oceanic_wisdom_layout = { 0x8000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0040, /* cf_pointers */ 0x03D0, /* rb_logbook_begin */ @@ -117,6 +119,7 @@ static const oceanic_common_layout_t oceanic_wisdom_layout = { static const oceanic_common_layout_t aeris_500ai_layout = { 0x20000, /* memsize */ + 0, /* highmem */ 0x0000, /* cf_devinfo */ 0x0110, /* cf_pointers */ 0x0200, /* rb_logbook_begin */ From 17b3e0739877bb44c78af7a30a3e414d55826a7e Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 9 Aug 2018 23:49:25 +0200 Subject: [PATCH 2/7] Fix the average depth for older OSTC dives For older OSTC dives, using logbook format version 0x20, the average depth is not available in the dive header. It's only available since version 0x21, which increased the header size from 47 to 57 bytes. --- src/hw_ostc_parser.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index bf28be9..f377684 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -465,6 +465,8 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned *((double *) value) = array_uint16_le (data + layout->maxdepth) / 100.0; break; case DC_FIELD_AVGDEPTH: + if (parser->version < 0x21) + return DC_STATUS_UNSUPPORTED; *((double *) value) = array_uint16_le (data + layout->avgdepth) / 100.0; break; case DC_FIELD_GASMIX_COUNT: From ff1ee12770a6c63bb7217a965bdf02f14d49c8a6 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 12 Aug 2018 19:42:27 +0200 Subject: [PATCH 3/7] Add support for the Mares Smart Air The Smart Air uses almost the same data format as the Quad Air. Only the 4 bytes containing the dive mode and number of samples moved from the beginning of the header to the end. This is a change adopted from the regular Smart. --- src/descriptor.c | 1 + src/mares_iconhd.c | 13 ++++++++++--- src/mares_iconhd_parser.c | 20 ++++++++++++-------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/descriptor.c b/src/descriptor.c index 72db49a..0fad0e2 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -246,6 +246,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Quad Air", DC_FAMILY_MARES_ICONHD , 0x23, DC_TRANSPORT_SERIAL, NULL}, + {"Mares", "Smart Air", DC_FAMILY_MARES_ICONHD , 0x24, DC_TRANSPORT_SERIAL, NULL}, {"Mares", "Quad", DC_FAMILY_MARES_ICONHD , 0x29, DC_TRANSPORT_SERIAL, NULL}, /* Heinrichs Weikamp */ {"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0, DC_TRANSPORT_SERIAL, NULL}, diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 450245e..d5f0ede 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -42,6 +42,7 @@ #define NEMOWIDE2 0x19 #define PUCK2 0x1F #define QUADAIR 0x23 +#define SMARTAIR 0x24 #define QUAD 0x29 #define ACK 0xAA @@ -127,6 +128,7 @@ mares_iconhd_get_model (mares_iconhd_device_t *device) {"Nemo Wide 2", NEMOWIDE2}, {"Puck 2", PUCK2}, {"Quad Air", QUADAIR}, + {"Smart Air", SMARTAIR}, {"Quad", QUAD}, }; @@ -293,6 +295,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_ device->packetsize = 256; break; case QUADAIR: + case SMARTAIR: device->layout = &mares_iconhdnet_layout; device->packetsize = 256; break; @@ -442,7 +445,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, header = 0x80; else if (model == QUADAIR) header = 0x84; - else if (model == SMART) + else if (model == SMART || model == SMARTAIR) header = 4; // Type and number of samples only! else if (model == SMARTAPNEA) header = 6; // Type and number of samples only! @@ -504,7 +507,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, // Get the number of samples in the profile data. unsigned int type = 0, nsamples = 0; - if (model == SMART || model == SMARTAPNEA) { + if (model == SMART || model == SMARTAPNEA || model == SMARTAIR) { type = array_uint16_le (buffer + offset - header + 2); nsamples = array_uint16_le (buffer + offset - header + 0); } else { @@ -541,6 +544,10 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, headersize = 0x50; samplesize = 14; fingerprint = 0x40; + } else if (model == SMARTAIR) { + headersize = 0x84; + samplesize = 12; + fingerprint = 2; } if (offset < headersize) break; @@ -559,7 +566,7 @@ mares_iconhd_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, // end of the ringbuffer. The current dive is incomplete (partially // overwritten with newer data), and processing should stop. unsigned int nbytes = 4 + headersize + nsamples * samplesize; - if (model == ICONHDNET || model == QUADAIR) { + if (model == ICONHDNET || model == QUADAIR || model == SMARTAIR) { nbytes += (nsamples / 4) * 8; } else if (model == SMARTAPNEA) { unsigned int settings = array_uint16_le (buffer + offset - headersize + 0x1C); diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 0c48a22..aa44ace 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -35,6 +35,7 @@ #define ICONHD 0x14 #define ICONHDNET 0x15 #define QUADAIR 0x23 +#define SMARTAIR 0x24 #define NGASMIXES 3 #define NTANKS NGASMIXES @@ -94,7 +95,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) header = 0x80; else if (parser->model == QUADAIR) header = 0x84; - else if (parser->model == SMART) + else if (parser->model == SMART || parser->model == SMARTAIR) header = 4; // Type and number of samples only! else if (parser->model == SMARTAPNEA) header = 6; // Type and number of samples only! @@ -112,7 +113,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) // Get the number of samples in the profile data. unsigned int type = 0, nsamples = 0; - if (parser->model == SMART || parser->model == SMARTAPNEA) { + if (parser->model == SMART || parser->model == SMARTAPNEA || parser->model == SMARTAIR) { type = array_uint16_le (data + length - header + 2); nsamples = array_uint16_le (data + length - header + 0); } else { @@ -129,7 +130,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) if (parser->model == ICONHDNET) { headersize = 0x80; samplesize = 12; - } else if (parser->model == QUADAIR) { + } else if (parser->model == QUADAIR || parser->model == SMARTAIR) { headersize = 0x84; samplesize = 12; } else if (parser->model == SMART) { @@ -151,7 +152,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) } const unsigned char *p = data + length - headersize; - if (parser->model != SMART && parser->model != SMARTAPNEA) { + if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { p += 4; } @@ -181,7 +182,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) // Calculate the total number of bytes for this dive. unsigned int nbytes = 4 + headersize + nsamples * samplesize; - if (parser->model == ICONHDNET || parser->model == QUADAIR) { + if (parser->model == ICONHDNET || parser->model == QUADAIR || parser->model == SMARTAIR) { nbytes += (nsamples / 4) * 8; } else if (parser->model == SMARTAPNEA) { unsigned int divetime = array_uint32_le (p + 0x24); @@ -215,7 +216,7 @@ mares_iconhd_parser_cache (mares_iconhd_parser_t *parser) // Tanks unsigned int ntanks = 0; - if (parser->model == ICONHDNET || parser->model == QUADAIR) { + if (parser->model == ICONHDNET || parser->model == QUADAIR || parser->model == SMARTAIR) { unsigned int tankoffset = (parser->model == ICONHDNET) ? 0x58 : 0x5C; while (ntanks < NTANKS) { unsigned int beginpressure = array_uint16_le (p + tankoffset + ntanks * 4 + 0); @@ -325,6 +326,8 @@ mares_iconhd_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime } } else if (parser->model == SMARTAPNEA) { p += 0x40; + } else if (parser->model == SMARTAIR) { + p += 2; } else { p += 6; } @@ -354,7 +357,7 @@ mares_iconhd_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsi return rc; const unsigned char *p = abstract->data + parser->footer; - if (parser->model != SMART && parser->model != SMARTAPNEA) { + if (parser->model != SMART && parser->model != SMARTAPNEA && parser->model != SMARTAIR) { p += 4; } @@ -611,7 +614,8 @@ mares_iconhd_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t nsamples++; // Some extra data. - if ((parser->model == ICONHDNET || parser->model == QUADAIR) && (nsamples % 4) == 0) { + if ((parser->model == ICONHDNET || parser->model == QUADAIR || parser->model == SMARTAIR) && + (nsamples % 4) == 0) { // Pressure (1/100 bar). unsigned int pressure = array_uint16_le(data + offset); if (gasmix < parser->ntanks) { From 4da94a72856403c864091d0972fb0ce80a08b36f Mon Sep 17 00:00:00 2001 From: Calle Gunnarsson Date: Fri, 15 Jun 2018 23:35:56 +0200 Subject: [PATCH 4/7] Include stddef.h in iostream.h This header need to be included to successfully generate Go-bindings. --- include/libdivecomputer/iostream.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/libdivecomputer/iostream.h b/include/libdivecomputer/iostream.h index e2cb439..d7d2621 100644 --- a/include/libdivecomputer/iostream.h +++ b/include/libdivecomputer/iostream.h @@ -22,6 +22,7 @@ #ifndef DC_IOSTREAM_H #define DC_IOSTREAM_H +#include #include #include From e4f04128beeeb63c13f58c9a01de844765de1ba6 Mon Sep 17 00:00:00 2001 From: Kristaps Dz Date: Sun, 19 Aug 2018 17:43:18 +0200 Subject: [PATCH 5/7] Document dc_descriptor_get_model --- doc/man/Makefile.am | 1 + doc/man/dc_descriptor_get_model.3 | 52 +++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 doc/man/dc_descriptor_get_model.3 diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am index fbaa991..7108446 100644 --- a/doc/man/Makefile.am +++ b/doc/man/Makefile.am @@ -14,6 +14,7 @@ MANPAGES = \ dc_datetime_mktime.3 \ dc_datetime_now.3 \ dc_descriptor_free.3 \ + dc_descriptor_get_model.3 \ dc_descriptor_get_product.3 \ dc_descriptor_get_vendor.3 \ dc_descriptor_iterator.3 \ diff --git a/doc/man/dc_descriptor_get_model.3 b/doc/man/dc_descriptor_get_model.3 new file mode 100644 index 0000000..24ee991 --- /dev/null +++ b/doc/man/dc_descriptor_get_model.3 @@ -0,0 +1,52 @@ + +.\" +.\" libdivecomputer +.\" +.\" Copyright (C) 2018 Kristaps Dzonsons +.\" +.\" 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 +.\" +.Dd August 19, 2018 +.Dt DC_DESCRIPTOR_GET_MODEL 3 +.Os +.Sh NAME +.Nm dc_descriptor_get_model +.Nd get the model of a dive computer descriptor +.Sh LIBRARY +.Lb libdivecomputer +.Sh SYNOPSIS +.In libdivecomputer/descriptor.h +.Ft "unsigned int" +.Fo dc_descriptor_get_model +.Fa "dc_descriptor_t *descriptor" +.Fc +.Sh DESCRIPTION +Gets the model number of a dive computer descriptor or 0 if none was +defined for the computer. +0 is also a valid model number. +.Sh RETURN VALUES +This returns the model number or 0 if none exists. +.Sh SEE ALSO +.Xr dc_descriptor_iterator 3 +.Sh AUTHORS +The +.Lb libdivecomputer +library was written by +.An Jef Driesen , +.Mt jef@libdivecomputer.org . +The manpages were written by +.An Kristaps Dzonsons , +.Mt kristaps@bsd.lv . From a4d9f72cf051a714dea7cf320221b344edf132a0 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Sun, 26 Aug 2018 10:37:36 +0200 Subject: [PATCH 6/7] Fix the transport command-line parameter --- examples/dctool_timesync.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/dctool_timesync.c b/examples/dctool_timesync.c index e0aff1f..35647b1 100644 --- a/examples/dctool_timesync.c +++ b/examples/dctool_timesync.c @@ -123,6 +123,9 @@ dctool_timesync_run (int argc, char *argv[], dc_context_t *context, dc_descripto case 'h': help = 1; break; + case 't': + transport = dctool_transport_type (optarg); + break; default: return EXIT_FAILURE; } From 631cfd8c45ce90d88a30d9f3fa42a10bad8f025b Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 16 Aug 2018 21:16:43 +0200 Subject: [PATCH 7/7] Add Travis CI integration --- .travis.yml | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..10e3edd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,56 @@ +language: c + +matrix: + include: + - os: linux + compiler: gcc + + - os: linux + compiler: clang + + - os: osx + compiler: gcc + + - os: osx + compiler: clang + + - os: linux + compiler: i686-w64-mingw32-gcc + addons: + apt: + packages: + - gcc-mingw-w64 + - binutils-mingw-w64 + - mingw-w64-tools + + - os: linux + compiler: x86_64-w64-mingw32-gcc + addons: + apt: + packages: + - gcc-mingw-w64 + - binutils-mingw-w64 + - mingw-w64-tools + +addons: + apt: + packages: + - libbluetooth-dev + - libusb-1.0-0-dev + +install: + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then + brew install hidapi libusb; + fi + +script: + - case $CC in + *-gcc) TARGET="${CC%-gcc}" ;; + esac + - if [ -n "$TARGET" ]; then + TARGETOPTS="--host=${TARGET}"; + unset CC; + fi + - autoreconf --install --force + - ./configure $TARGETOPTS --disable-doc + - make