diff --git a/contrib/udev/libdivecomputer.rules b/contrib/udev/libdivecomputer.rules index 14d0ce6..e4e6fdc 100644 --- a/contrib/udev/libdivecomputer.rules +++ b/contrib/udev/libdivecomputer.rules @@ -17,7 +17,7 @@ SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3201", GROUP="plugde SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="3211", GROUP="plugdev" # Scubapro G2 HUD -SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="0x4201", GROUP="plugdev" +SUBSYSTEM=="usb", ATTR{idVendor}=="2e6c", ATTR{idProduct}=="4201", GROUP="plugdev" # Scubapro Aladin Square SUBSYSTEM=="usb", ATTR{idVendor}=="c251", ATTR{idProduct}=="2006", GROUP="plugdev" diff --git a/examples/dctool_fwupdate.c b/examples/dctool_fwupdate.c index e5daf35..596ccb1 100644 --- a/examples/dctool_fwupdate.c +++ b/examples/dctool_fwupdate.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "dctool.h" #include "common.h" @@ -93,6 +94,9 @@ fwupdate (dc_context_t *context, dc_descriptor_t *descriptor, dc_transport_t tra case DC_FAMILY_HW_OSTC3: rc = hw_ostc3_device_fwupdate (device, hexfile); break; + case DC_FAMILY_DIVESYSTEM_IDIVE: + rc = divesystem_idive_device_fwupdate (device, hexfile); + break; default: rc = DC_STATUS_UNSUPPORTED; break; diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am index 8e12f2d..e972153 100644 --- a/include/libdivecomputer/Makefile.am +++ b/include/libdivecomputer/Makefile.am @@ -28,4 +28,5 @@ libdivecomputer_HEADERS = \ hw_ostc.h \ hw_frog.h \ hw_ostc3.h \ - atomics_cobalt.h + atomics_cobalt.h \ + divesystem_idive.h diff --git a/include/libdivecomputer/divesystem_idive.h b/include/libdivecomputer/divesystem_idive.h new file mode 100644 index 0000000..07065d1 --- /dev/null +++ b/include/libdivecomputer/divesystem_idive.h @@ -0,0 +1,38 @@ +/* + * libdivecomputer + * + * Copyright (C) 2019 Jef Driesen + * + * 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 DC_DIVESYSTEM_IDIVE_H +#define DC_DIVESYSTEM_IDIVE_H + +#include "common.h" +#include "device.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +dc_status_t +divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* DC_DIVESYSTEM_IDIVE_H */ diff --git a/src/descriptor.c b/src/descriptor.c index f7731b7..4db368d 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -584,10 +584,11 @@ static int dc_filter_mares (dc_transport_t transport, const void *userdata) { static const char * const bluetooth[] = { "Mares bluelink pro", + "Mares Genius", }; if (transport == DC_TRANSPORT_BLE) { - return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_name); + return DC_FILTER_INTERNAL (userdata, bluetooth, 0, dc_match_prefix); } return 1; diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index 1c71de9..0659d06 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -21,10 +21,12 @@ #include // memcmp, memcpy #include // malloc, free +#include #include "divesystem_idive.h" #include "context-private.h" #include "device-private.h" +#include "platform.h" #include "checksum.h" #include "array.h" @@ -39,6 +41,7 @@ #define MAXPACKET 0xFF #define START 0x55 #define ACK 0x06 +#define WAIT 0x13 #define NAK 0x15 #define CMD_IDIVE_ID 0x10 @@ -51,6 +54,12 @@ #define CMD_IX3M_HEADER 0x79 #define CMD_IX3M_SAMPLE 0x7A #define CMD_IX3M_TIMESYNC 0x13 +#define CMD_IX3M_BOOTLOADER 0x0A + +#define BOOTLOADER_PROBE 0x78 +#define BOOTLOADER_UPLOAD_A 0x40 +#define BOOTLOADER_UPLOAD_B 0x23 +#define BOOTLOADER_ACK 0x46 #define ERR_INVALID_CMD 0x10 #define ERR_INVALID_LENGTH 0x20 @@ -80,6 +89,11 @@ typedef struct divesystem_idive_commands_t { unsigned int nsamples; } divesystem_idive_commands_t; +typedef struct divesystem_idive_signature_t { + const char *name; + unsigned int delay; +} divesystem_idive_signature_t; + typedef struct divesystem_idive_device_t { dc_device_t base; dc_iostream_t *iostream; @@ -127,6 +141,14 @@ static const divesystem_idive_commands_t ix3m_apos4 = { 3, }; +static const divesystem_idive_signature_t signatures[] = { + {"dsh01", 50}, // IX3M GPS + {"dsh30", 50}, // IX3M Pro + {"dsh20", 5}, // iDive Sport + {"dsh23", 5}, // iDive Color + {"acx", 5}, // WPT +}; + dc_status_t divesystem_idive_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int model) { @@ -652,3 +674,262 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da return DC_STATUS_SUCCESS; } + +static dc_status_t +divesystem_idive_firmware_readfile (dc_buffer_t *buffer, dc_context_t *context, const char *filename) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_buffer_t *tmp = NULL; + FILE *fp = NULL; + + if (!dc_buffer_clear (buffer)) { + ERROR (context, "Invalid arguments."); + return DC_STATUS_INVALIDARGS; + } + + // Allocate a temporary buffer. + tmp = dc_buffer_new (0x20000); + if (tmp == NULL) { + ERROR (context, "Failed to allocate memory."); + status = DC_STATUS_NOMEMORY; + goto error_exit; + } + + // Open the file. + fp = fopen (filename, "rb"); + if (fp == NULL) { + ERROR (context, "Failed to open the file."); + status = DC_STATUS_IO; + goto error_free; + } + + // Read the entire file into the buffer. + size_t n = 0; + unsigned char block[4096] = {0}; + while ((n = fread (block, 1, sizeof (block), fp)) > 0) { + if (!dc_buffer_append (tmp, block, n)) { + ERROR (context, "Insufficient buffer space available."); + status = DC_STATUS_NOMEMORY; + goto error_close; + } + } + + // Resize the output buffer. + size_t nbytes = dc_buffer_get_size (tmp); + if (!dc_buffer_resize (buffer, nbytes / 2)) { + ERROR (context, "Insufficient buffer space available."); + status = DC_STATUS_NOMEMORY; + goto error_close; + } + + // Convert to binary data. + int rc = array_convert_hex2bin ( + dc_buffer_get_data (tmp), dc_buffer_get_size (tmp), + dc_buffer_get_data (buffer), dc_buffer_get_size (buffer)); + if (rc != 0) { + ERROR (context, "Unexpected data format."); + status = DC_STATUS_DATAFORMAT; + goto error_close; + } + +error_close: + fclose (fp); +error_free: + dc_buffer_free (tmp); +error_exit: + return status; +} + +static dc_status_t +divesystem_idive_firmware_send (divesystem_idive_device_t *device, const divesystem_idive_signature_t *signature, const unsigned char data[], size_t size) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_device_t *abstract = (dc_device_t *) device; + + unsigned int nretries = 0; + while (1) { + // Send the frame. + status = dc_iostream_write (device->iostream, data, size, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the frame."); + return status; + } + + // Read the response until an ACK or NAK byte is received. + unsigned int state = 0; + while (state == 0) { + // Receive the response. + unsigned char response = 0; + status = dc_iostream_read (device->iostream, &response, 1, NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the response."); + return status; + } + + // Process the response. + switch (response) { + case ACK: + case NAK: + state = response; + break; + case WAIT: + dc_iostream_sleep (device->iostream, signature->delay); + break; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'K': + case 'X': + break; + default: + WARNING (abstract->context, "Unexpected response byte received (%02x)", response); + break; + } + } + + // Exit if ACK received. + if (state == ACK) + break; + + // Abort if the maximum number of retries is reached. + if (nretries++ >= MAXRETRIES) { + ERROR (abstract->context, "Maximum number of retries reached."); + return DC_STATUS_PROTOCOL; + } + } + + return DC_STATUS_SUCCESS; +} + +dc_status_t +divesystem_idive_device_fwupdate (dc_device_t *abstract, const char *filename) +{ + dc_status_t status = DC_STATUS_SUCCESS; + divesystem_idive_device_t *device = (divesystem_idive_device_t *) abstract; + unsigned int errcode = 0; + + // Allocate memory for the firmware data. + dc_buffer_t *buffer = dc_buffer_new (0); + if (buffer == NULL) { + ERROR (abstract->context, "Failed to allocate memory for the firmware data."); + status = DC_STATUS_NOMEMORY; + goto error_exit; + } + + // Read the firmware file. + status = divesystem_idive_firmware_readfile (buffer, abstract->context, filename); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the firmware file."); + goto error_free; + } + + // Cache the data and size. + const unsigned char *data = dc_buffer_get_data (buffer); + size_t size = dc_buffer_get_size (buffer); + + // Enable progress notifications. + dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; + progress.maximum = size; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + // Activate the bootloader. + const unsigned char bootloader[] = {CMD_IX3M_BOOTLOADER, 0xC9, 0x4B}; + status = divesystem_idive_transfer (device, bootloader, sizeof (bootloader), NULL, 0, &errcode); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to activate the bootloader."); + goto error_free; + } + + // Give the device some time to enter the bootloader. + dc_iostream_sleep (device->iostream, 2000); + + // Wait for the bootloader. + const divesystem_idive_signature_t *signature = NULL; + while (signature == NULL) { + // Discard garbage data. + dc_iostream_purge (device->iostream, DC_DIRECTION_INPUT); + + // Probe for the bootloader. + const unsigned char probe[] = {BOOTLOADER_PROBE}; + status = dc_iostream_write (device->iostream, probe, sizeof (probe), NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to activate the bootloader."); + goto error_free; + } + + // Read the signature string. + size_t n = 0; + unsigned char name[5] = {0}; + status = dc_iostream_read (device->iostream, name, sizeof (name), &n); + if (status != DC_STATUS_SUCCESS && status != DC_STATUS_TIMEOUT) { + ERROR (abstract->context, "Failed to read the signature string."); + goto error_free; + } + + // Verify the signature string. + for (size_t i = 0; i < C_ARRAY_SIZE (signatures); ++i) { + if (n == strlen (signatures[i].name) && memcmp (name, signatures[i].name, n) == 0) { + signature = signatures + i; + break; + } + } + } + + // Send the start upload command. + const unsigned char upload[] = {BOOTLOADER_UPLOAD_A, BOOTLOADER_UPLOAD_B}; + status = dc_iostream_write (device->iostream, upload, sizeof(upload), NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the start upload command."); + goto error_free; + } + + // Receive the ack. + unsigned char ack[1] = {0}; + status = dc_iostream_read (device->iostream, ack, sizeof(ack), NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the ack byte."); + goto error_free; + } + + // Verify the ack. + if (ack[0] != BOOTLOADER_ACK) { + ERROR (abstract->context, "Invalid ack byte (%02x).", ack[0]); + status = DC_STATUS_PROTOCOL; + goto error_free; + } + + // Upload the firmware. + unsigned int offset = 0; + while (offset + 2 <= size) { + // Get the number of bytes in the current frame. + unsigned int len = array_uint16_be (data + offset) + 2; + if (offset + len > size) { + ERROR (abstract->context, "Invalid frame size (%u %u " DC_PRINTF_SIZE ")", offset, len, size); + status = DC_STATUS_DATAFORMAT; + goto error_free; + } + + // Send the frame. + status = divesystem_idive_firmware_send (device, signature, data + offset, len); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to send the frame."); + goto error_free; + } + + // Update and emit a progress event. + progress.current += len; + device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); + + offset += len; + } + +error_free: + dc_buffer_free (buffer); +error_exit: + return status; +} diff --git a/src/divesystem_idive.h b/src/divesystem_idive.h index 8c79866..1da80a0 100644 --- a/src/divesystem_idive.h +++ b/src/divesystem_idive.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/src/hw_ostc.h b/src/hw_ostc.h index 8232e5d..5635e6d 100644 --- a/src/hw_ostc.h +++ b/src/hw_ostc.h @@ -36,7 +36,7 @@ dc_status_t hw_ostc_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); dc_status_t -hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial, unsigned int hwos); +hw_ostc_parser_create (dc_parser_t **parser, dc_context_t *context, unsigned int serial); #ifdef __cplusplus } diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index 187a9e4..0521e2e 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -713,7 +713,6 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi // The device maintains an internal counter which is incremented for every // dive, and the current value at the time of the dive is stored in the // dive header. Thus the most recent dive will have the highest value. - unsigned int count = 0; unsigned int latest = 0; unsigned int maximum = 0; for (unsigned int i = 0; i < RB_LOGBOOK_COUNT; ++i) { @@ -729,24 +728,21 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi maximum = current; latest = i; } - - count++; } // Calculate the total and maximum size. unsigned int ndives = 0; unsigned int size = 0; unsigned int maxsize = 0; - for (unsigned int i = 0; i < count; ++i) { + unsigned char dive[RB_LOGBOOK_COUNT] = {0}; + for (unsigned int i = 0; i < RB_LOGBOOK_COUNT; ++i) { unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT; unsigned int offset = idx * logbook->size; - // Uninitialized header entries should no longer be present at this - // stage, unless the dives are interleaved with empty entries. But - // that's something we don't support at all. + // Ignore uninitialized header entries. if (array_isequal (header + offset, logbook->size, 0xFF)) { WARNING (abstract->context, "Unexpected empty header found."); - break; + continue; } // Calculate the profile length. @@ -770,6 +766,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi if (length > maxsize) maxsize = length; size += length; + dive[ndives] = idx; ndives++; } @@ -793,7 +790,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi // Download the dives. for (unsigned int i = 0; i < ndives; ++i) { - unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT; + unsigned int idx = dive[i]; unsigned int offset = idx * logbook->size; // Calculate the profile length. diff --git a/src/hw_ostc_parser.c b/src/hw_ostc_parser.c index 1f82b07..7a7817e 100644 --- a/src/hw_ostc_parser.c +++ b/src/hw_ostc_parser.c @@ -49,6 +49,14 @@ #define HEADER 1 #define PROFILE 2 +#define TEMPERATURE 0 +#define DECO 1 +#define GF 2 +#define PPO2 3 +#define DECOPLAN 4 +#define CNS 5 +#define TANK 6 + #define OSTC_ZHL16_OC 0 #define OSTC_GAUGE 1 #define OSTC_ZHL16_CC 2 @@ -75,6 +83,16 @@ #define UNSUPPORTED 0xFFFFFFFF +#define OSTC3FW(major,minor) ( \ + (((major) & 0xFF) << 8) | \ + ((minor) & 0xFF)) + +#define OSTC4FW(major,minor,micro,beta) ( \ + (((major) & 0x1F) << 11) | \ + (((minor) & 0x1F) >> 6) | \ + (((micro) & 0x1F) << 1) | \ + ((beta) & 0x01)) + typedef struct hw_ostc_sample_info_t { unsigned int type; unsigned int divisor; @@ -370,9 +388,9 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, unsign dc_status_t -hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial, unsigned int hwos) +hw_ostc_parser_create (dc_parser_t **out, dc_context_t *context, unsigned int serial) { - return hw_ostc_parser_create_internal (out, context, serial, hwos, 0); + return hw_ostc_parser_create_internal (out, context, serial, 0, 0); } dc_status_t @@ -757,21 +775,21 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call if (info[i].divisor) { switch (info[i].type) { - case 0: // Temperature - case 1: // Deco / NDL - case 6: // Tank pressure + case TEMPERATURE: + case DECO: + case TANK: if (info[i].size != 2) { ERROR(abstract->context, "Unexpected sample size."); return DC_STATUS_DATAFORMAT; } break; - case 3: // ppO2 + case PPO2: if (info[i].size != 3 && info[i].size != 9) { ERROR(abstract->context, "Unexpected sample size."); return DC_STATUS_DATAFORMAT; } break; - case 5: // CNS + case CNS: if (info[i].size != 1 && info[i].size != 2) { ERROR(abstract->context, "Unexpected sample size."); return DC_STATUS_DATAFORMAT; @@ -978,6 +996,17 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call for (unsigned int i = 0; i < nconfig; ++i) { if (info[i].divisor && (nsamples % info[i].divisor) == 0) { if (length < info[i].size) { + // Due to a bug in the hwOS Tech firmware v3.03 to v3.07, and + // the hwOS Sport firmware v10.57 to v10.63, the ppO2 divisor + // is sometimes not correctly reset to zero when no ppO2 + // samples are being recorded. + if (info[i].type == PPO2 && parser->hwos && parser->model != OSTC4 && + ((firmware >= OSTC3FW(3,3) && firmware <= OSTC3FW(3,7)) || + (firmware >= OSTC3FW(10,57) && firmware <= OSTC3FW(10,63)))) { + WARNING (abstract->context, "Reset invalid ppO2 divisor to zero."); + info[i].divisor = 0; + continue; + } ERROR (abstract->context, "Buffer overflow detected!"); return DC_STATUS_DATAFORMAT; } @@ -986,15 +1015,15 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call unsigned int count = 0; unsigned int value = 0; switch (info[i].type) { - case 0: // Temperature (0.1 °C). + case TEMPERATURE: value = array_uint16_le (data + offset); sample.temperature = value / 10.0; if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); break; - case 1: // Deco / NDL + case DECO: // Due to a firmware bug, the deco/ndl info is incorrect for // all OSTC4 dives with a firmware older than version 1.0.8. - if (parser->model == OSTC4 && firmware < 0x0810) + if (parser->model == OSTC4 && firmware < OSTC4FW(1,0,8,0)) break; if (data[offset]) { sample.deco.type = DC_DECO_DECOSTOP; @@ -1006,7 +1035,7 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call sample.deco.time = data[offset + 1] * 60; if (callback) callback (DC_SAMPLE_DECO, sample, userdata); break; - case 3: // ppO2 (0.01 bar). + case PPO2: for (unsigned int j = 0; j < 3; ++j) { if (info[i].size == 3) { ppo2[j] = data[offset + j]; @@ -1023,18 +1052,24 @@ hw_ostc_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t call } } break; - case 5: // CNS + case CNS: if (info[i].size == 2) sample.cns = array_uint16_le (data + offset) / 100.0; else sample.cns = data[offset] / 100.0; if (callback) callback (DC_SAMPLE_CNS, sample, userdata); break; - case 6: // Tank pressure + case TANK: value = array_uint16_le (data + offset); if (value != 0) { sample.pressure.tank = tank; - sample.pressure.value = value / 10.0; + sample.pressure.value = value; + // The hwOS Sport firmware used a resolution of + // 0.1 bar between versions 10.40 and 10.50. + if (parser->hwos && parser->model != OSTC4 && + (firmware >= OSTC3FW(10,40) && firmware <= OSTC3FW(10,50))) { + sample.pressure.value /= 10.0; + } if (callback) callback (DC_SAMPLE_PRESSURE, sample, userdata); } break; diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index eeb7240..bb553a0 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -144,3 +144,4 @@ hw_ostc3_device_config_reset hw_ostc3_device_fwupdate atomics_cobalt_device_version atomics_cobalt_device_set_simulation +divesystem_idive_device_fwupdate diff --git a/src/oceanic_atom2.c b/src/oceanic_atom2.c index c3fe75a..42152f0 100644 --- a/src/oceanic_atom2.c +++ b/src/oceanic_atom2.c @@ -124,7 +124,8 @@ static const oceanic_common_version_t oceanic_atom2b_version[] = { {"AQUAI300 \0\0 512K"}, {"HOLLDG03 \0\0 512K"}, {"AQUAI100 \0\0 512K"}, - {"AQUA300C \0\0 \0\0\0\0"}, + {"AQUA300C \0\0 512K"}, + {"OCEGEO40 \0\0 512K"}, }; static const oceanic_common_version_t oceanic_atom2c_version[] = { @@ -139,7 +140,6 @@ static const oceanic_common_version_t oceanic_default_version[] = { {"ELITET31 \0\0 512K"}, {"DATAMASK \0\0 512K"}, {"COMPMASK \0\0 512K"}, - {"OCEGEO40 \0\0 512K"}, }; static const oceanic_common_version_t sherwood_wisdom_version[] = { diff --git a/src/parser.c b/src/parser.c index 5e347bd..8fd16ee 100644 --- a/src/parser.c +++ b/src/parser.c @@ -134,7 +134,7 @@ dc_parser_new_internal (dc_parser_t **out, dc_context_t *context, dc_family_t fa rc = mares_iconhd_parser_create (&parser, context, model); break; case DC_FAMILY_HW_OSTC: - rc = hw_ostc_parser_create (&parser, context, serial, 0); + rc = hw_ostc_parser_create (&parser, context, serial); break; case DC_FAMILY_HW_FROG: case DC_FAMILY_HW_OSTC3: