diff --git a/configure.ac b/configure.ac index 57e2d678..38d68dd4 100644 --- a/configure.ac +++ b/configure.ac @@ -62,7 +62,7 @@ AM_CONDITIONAL([ENABLE_DOC], [test "x$enable_doc" = "xyes"]) # Checks for programs. AC_PROG_CC -AC_PROG_CC_C99 +m4_version_prereq([2.70], [], [AC_PROG_CC_C99]) AC_CHECK_PROGS([DOXYGEN], [doxygen]) AC_CHECK_PROGS([MANDOC], [mandoc]) diff --git a/contrib/android/Android.mk b/contrib/android/Android.mk index 2f74444b..fc49add4 100644 --- a/contrib/android/Android.mk +++ b/contrib/android/Android.mk @@ -42,7 +42,6 @@ LOCAL_SRC_FILES := \ src/halcyon_symbios.c \ src/halcyon_symbios_parser.c \ src/hdlc.c \ - src/hw_frog.c \ src/hw_ostc3.c \ src/hw_ostc.c \ src/hw_ostc_parser.c \ diff --git a/contrib/msvc/libdivecomputer.vcxproj b/contrib/msvc/libdivecomputer.vcxproj index 25b1aa4b..118b9d49 100644 --- a/contrib/msvc/libdivecomputer.vcxproj +++ b/contrib/msvc/libdivecomputer.vcxproj @@ -213,7 +213,6 @@ - @@ -305,7 +304,6 @@ - @@ -348,7 +346,6 @@ - diff --git a/examples/output_xml.c b/examples/output_xml.c index 0f1621d1..fae8b2ec 100644 --- a/examples/output_xml.c +++ b/examples/output_xml.c @@ -179,6 +179,17 @@ sample_cb (dc_sample_type_t type, const dc_sample_value_t *value, void *userdata case DC_SAMPLE_GASMIX: fprintf (sampledata->ostream, " %u\n", value->gasmix); break; + case DC_SAMPLE_LOCATION: + fprintf (sampledata->ostream, + " \n" + " %.6f\n" + " %.6f\n" + " %.3f\n" + " \n", + value->location.latitude, + value->location.longitude, + value->location.altitude); + break; default: break; } @@ -503,9 +514,9 @@ dctool_xml_output_write (dctool_output_t *abstract, dc_parser_t *parser, const u if (status != DC_STATUS_UNSUPPORTED) { fprintf (output->ostream, "\n" - " %.6f\n" + " %.6f\n" " %.6f\n" - " %.2f\n" + " %.2f\n" "\n", location.latitude, location.longitude, diff --git a/include/libdivecomputer/Makefile.am b/include/libdivecomputer/Makefile.am index 6f679c77..401f839a 100644 --- a/include/libdivecomputer/Makefile.am +++ b/include/libdivecomputer/Makefile.am @@ -29,7 +29,6 @@ libdivecomputer_HEADERS = \ oceanic_veo250.h \ oceanic_vtpro.h \ hw_ostc.h \ - hw_frog.h \ hw_ostc3.h \ atomics_cobalt.h \ divesystem_idive.h diff --git a/include/libdivecomputer/hw_frog.h b/include/libdivecomputer/hw_frog.h deleted file mode 100644 index 0af10cac..00000000 --- a/include/libdivecomputer/hw_frog.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2012 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_HW_FROG_H -#define DC_HW_FROG_H - -#include "common.h" -#include "device.h" -#include "datetime.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#define HW_FROG_DISPLAY_SIZE 15 -#define HW_FROG_CUSTOMTEXT_SIZE 13 - -dc_status_t -hw_frog_device_version (dc_device_t *device, unsigned char data[], unsigned int size); - -dc_status_t -hw_frog_device_display (dc_device_t *device, const char *text); - -dc_status_t -hw_frog_device_customtext (dc_device_t *device, const char *text); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* DC_HW_FROG_H */ diff --git a/include/libdivecomputer/hw_ostc3.h b/include/libdivecomputer/hw_ostc3.h index 4e0a98ac..69e035b1 100644 --- a/include/libdivecomputer/hw_ostc3.h +++ b/include/libdivecomputer/hw_ostc3.h @@ -35,6 +35,9 @@ extern "C" { #define HW_OSTC3_DISPLAY_SIZE 16 #define HW_OSTC3_CUSTOMTEXT_SIZE 60 +#define HW_FROG_DISPLAY_SIZE 15 +#define HW_FROG_CUSTOMTEXT_SIZE 13 + dc_status_t hw_ostc3_device_version (dc_device_t *device, unsigned char data[], unsigned int size); diff --git a/include/libdivecomputer/parser.h b/include/libdivecomputer/parser.h index 8c3e075a..d3608e1d 100644 --- a/include/libdivecomputer/parser.h +++ b/include/libdivecomputer/parser.h @@ -48,10 +48,13 @@ typedef enum dc_sample_type_t { DC_SAMPLE_DECO, DC_SAMPLE_GASMIX, DC_SAMPLE_TTS, // time to surface in seconds + DC_SAMPLE_LOCATION, } dc_sample_type_t; // Make it easy to test support compile-time with "#ifdef DC_SAMPLE_TTS" #define DC_SAMPLE_TTS DC_SAMPLE_TTS +// Make it easy to test support compile-time with "#ifdef DC_SAMPLE_LOCATION" +#define DC_SAMPLE_LOCATION DC_SAMPLE_LOCATION typedef enum dc_field_type_t { DC_FIELD_DIVETIME, @@ -331,6 +334,7 @@ typedef union dc_sample_value_t { unsigned int tts; } deco; unsigned int gasmix; /* Gas mix index */ + dc_location_t location; } dc_sample_value_t; typedef struct dc_parser_t dc_parser_t; diff --git a/src/Makefile.am b/src/Makefile.am index 87cd8ab0..27201495 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,7 +51,6 @@ libdivecomputer_la_SOURCES = \ mares_iconhd.h mares_iconhd.c mares_iconhd_parser.c \ ihex.h ihex.c \ hw_ostc.h hw_ostc.c hw_ostc_parser.c \ - hw_frog.h hw_frog.c \ hw_ostc3.h hw_ostc3.c \ aes.h aes.c \ cressi_edy.h cressi_edy.c cressi_edy_parser.c \ diff --git a/src/descriptor.c b/src/descriptor.c index ad612019..fd6a1509 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -325,6 +325,7 @@ static const dc_descriptor_t g_descriptors[] = { {"Mares", "Sirius", DC_FAMILY_MARES_ICONHD , 0x2F, DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad Ci", DC_FAMILY_MARES_ICONHD , 0x31, DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Quad 2", DC_FAMILY_MARES_ICONHD , 0x32, DC_TRANSPORT_BLE, dc_filter_mares}, + {"Mares", "Sirius L", DC_FAMILY_MARES_ICONHD , 0x33, DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Puck 4", DC_FAMILY_MARES_ICONHD , 0x35, DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Puck Lite", DC_FAMILY_MARES_ICONHD , 0x35, DC_TRANSPORT_BLE, dc_filter_mares}, {"Mares", "Puck Pro EZ", DC_FAMILY_MARES_ICONHD , 0x35, DC_TRANSPORT_BLE, dc_filter_mares}, @@ -800,6 +801,7 @@ dc_filter_mares (const dc_descriptor_t *descriptor, dc_transport_t transport, co "Mares bluelink pro", "Mares Genius", "Sirius", + "Sirius L", "Quad Ci", "Quad2", "Puck4", diff --git a/src/device.c b/src/device.c index e4378e5f..4950b42c 100644 --- a/src/device.c +++ b/src/device.c @@ -43,7 +43,6 @@ #include "mares_iconhd.h" #include "mares_nemo.h" #include "mares_puck.h" -#include "hw_frog.h" #include "hw_ostc.h" #include "hw_ostc3.h" #include "cressi_edy.h" @@ -186,10 +185,10 @@ dc_device_open (dc_device_t **out, dc_context_t *context, dc_descriptor_t *descr rc = hw_ostc_device_open (&device, context, iostream); break; case DC_FAMILY_HW_FROG: - rc = hw_frog_device_open (&device, context, iostream); + rc = hw_ostc3_device_open (&device, context, iostream, 1); break; case DC_FAMILY_HW_OSTC3: - rc = hw_ostc3_device_open (&device, context, iostream); + rc = hw_ostc3_device_open (&device, context, iostream, 0); break; case DC_FAMILY_CRESSI_EDY: rc = cressi_edy_device_open (&device, context, iostream); diff --git a/src/divesoft_freedom_parser.c b/src/divesoft_freedom_parser.c index 5bb2e54f..3e37ea9e 100644 --- a/src/divesoft_freedom_parser.c +++ b/src/divesoft_freedom_parser.c @@ -252,9 +252,6 @@ typedef struct divesoft_freedom_parser_t { unsigned int seawater; unsigned int calibration[NSENSORS]; unsigned int calibrated; - unsigned int have_location; - int latitude; - int longitude; } divesoft_freedom_parser_t; static dc_status_t divesoft_freedom_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); @@ -397,10 +394,6 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser) unsigned int gasmixid_previous = UNDEFINED; - unsigned int have_location = 0; - int latitude = 0; - int longitude = 0; - // Parse the dive profile. unsigned int offset = headersize; while (offset + RECORD_SIZE <= size) { @@ -550,14 +543,6 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser) } tank[idx].endpressure = pressure; } - } else if (id == MEASURE_ID_GPS) { - if (!have_location) { - latitude = (signed int) array_uint32_le (data + offset + 4); - longitude = (signed int) array_uint32_le (data + offset + 8); - have_location = 1; - } else { - WARNING (abstract->context, "Multiple GPS locations present."); - } } } @@ -650,9 +635,6 @@ divesoft_freedom_cache (divesoft_freedom_parser_t *parser) parser->calibration[i] = calibration[i]; } parser->calibrated = calibrated; - parser->have_location = have_location; - parser->latitude = latitude; - parser->longitude = longitude; return DC_STATUS_SUCCESS; } @@ -707,9 +689,6 @@ divesoft_freedom_parser_create (dc_parser_t **out, dc_context_t *context, const parser->calibration[i] = 0; } parser->calibrated = 0; - parser->have_location = 0; - parser->latitude = 0; - parser->longitude = 0; *out = (dc_parser_t *) parser; @@ -766,7 +745,6 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; dc_decomodel_t *decomodel = (dc_decomodel_t *) value; - dc_location_t *location = (dc_location_t *) value; if (value) { switch (type) { @@ -862,13 +840,6 @@ divesoft_freedom_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, decomodel->params.gf.high = parser->gf_hi; } break; - case DC_FIELD_LOCATION: - if (!parser->have_location) - return DC_STATUS_UNSUPPORTED; - location->latitude = parser->latitude / 1000000.0; - location->longitude = parser->longitude / 1000000.0; - location->altitude = 0.0; - break; default: return DC_STATUS_UNSUPPORTED; } @@ -1061,6 +1032,13 @@ divesoft_freedom_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba sample.ppo2.value = value / 100.0 * parser->calibration[i] / BAR; if (callback) callback(DC_SAMPLE_PPO2, &sample, userdata); } + } else if (id == MEASURE_ID_GPS) { + int latitude = (signed int) array_uint32_le (data + offset + 4); + int longitude = (signed int) array_uint32_le (data + offset + 8); + sample.location.latitude = latitude / 1000000.0; + sample.location.longitude = longitude / 1000000.0; + sample.location.altitude = 0.0; + if (callback) callback (DC_SAMPLE_LOCATION, &sample, userdata); } } else if (type == LREC_STATE) { // Tissue saturation record. diff --git a/src/divesystem_idive.c b/src/divesystem_idive.c index ece18e1d..51904b52 100644 --- a/src/divesystem_idive.c +++ b/src/divesystem_idive.c @@ -649,6 +649,10 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da // Adjust the epoch. timestamp -= EPOCH; + // UTC offset. + int tz_offset = datetime->timezone != DC_TIMEZONE_NONE ? + datetime->timezone : 0; + // Find the timezone index. size_t tz_idx = C_ARRAY_SIZE(tz_array); for (size_t i = 0; i < C_ARRAY_SIZE(tz_array); i += 2) { @@ -659,7 +663,7 @@ divesystem_idive_device_timesync (dc_device_t *abstract, const dc_datetime_t *da timezone += tz_array[i + 1] * 60; } - if (timezone == datetime->timezone) { + if (timezone == tz_offset) { tz_idx = i; break; } diff --git a/src/divesystem_idive_parser.c b/src/divesystem_idive_parser.c index 073f4987..e913968d 100644 --- a/src/divesystem_idive_parser.c +++ b/src/divesystem_idive_parser.c @@ -91,10 +91,6 @@ struct divesystem_idive_parser_t { unsigned int algorithm; unsigned int gf_low; unsigned int gf_high; - unsigned int have_location; - int latitude; - int longitude; - int altitude; }; static dc_status_t divesystem_idive_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); @@ -154,10 +150,6 @@ divesystem_idive_parser_create (dc_parser_t **out, dc_context_t *context, const parser->algorithm = INVALID; parser->gf_low = INVALID; parser->gf_high = INVALID; - parser->have_location = 0; - parser->latitude = 0; - parser->longitude = 0; - parser->altitude = 0; *out = (dc_parser_t*) parser; @@ -284,7 +276,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, dc_tank_t *tank = (dc_tank_t *) value; dc_salinity_t *water = (dc_salinity_t *) value; dc_decomodel_t *decomodel = (dc_decomodel_t *) value; - dc_location_t *location = (dc_location_t *) value; if (value) { switch (type) { @@ -390,13 +381,6 @@ divesystem_idive_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, } } break; - case DC_FIELD_LOCATION: - if (!parser->have_location) - return DC_STATUS_UNSUPPORTED; - location->latitude = parser->latitude / 10000000.0; - location->longitude = parser->longitude / 10000000.0; - location->altitude = parser->altitude / 1000.0; - break; default: return DC_STATUS_UNSUPPORTED; } @@ -474,14 +458,10 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba type = REC_SAMPLE; if (type != REC_SAMPLE) { if (type == REC_INFO) { - if (!have_location) { - altitude = (signed int) array_uint32_le (data + offset + 40); - longitude = (signed int) array_uint32_le (data + offset + 44); - latitude = (signed int) array_uint32_le (data + offset + 48); - have_location = 1; - } else { - WARNING (abstract->context, "Multiple GPS locations present."); - } + altitude = (signed int) array_uint32_le (data + offset + 40); + longitude = (signed int) array_uint32_le (data + offset + 44); + latitude = (signed int) array_uint32_le (data + offset + 48); + have_location = 1; } // Skip non-sample records. @@ -668,6 +648,15 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba } } + // GPS location + if (have_location) { + sample.location.latitude = latitude / 10000000.0; + sample.location.longitude = longitude / 10000000.0; + sample.location.altitude = altitude / 1000.0; + if (callback) callback (DC_SAMPLE_LOCATION, &sample, userdata); + have_location = 0; + } + offset += samplesize; } @@ -686,10 +675,6 @@ divesystem_idive_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callba parser->algorithm = algorithm; parser->gf_low = gf_low; parser->gf_high = gf_high; - parser->have_location = have_location; - parser->latitude = latitude; - parser->longitude = longitude; - parser->altitude = altitude; parser->cached = 1; return DC_STATUS_SUCCESS; diff --git a/src/halcyon_symbios_parser.c b/src/halcyon_symbios_parser.c index b7e51307..320e8134 100644 --- a/src/halcyon_symbios_parser.c +++ b/src/halcyon_symbios_parser.c @@ -107,8 +107,6 @@ typedef struct halcyon_symbios_parser_t { halcyon_symbios_tank_t tank[NTANKS]; unsigned int gf_lo; unsigned int gf_hi; - unsigned int have_location; - int latitude, longitude; } halcyon_symbios_parser_t; static dc_status_t halcyon_symbios_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime); @@ -153,9 +151,6 @@ halcyon_symbios_parser_create (dc_parser_t **out, dc_context_t *context, const u parser->atmospheric = UNDEFINED; parser->gf_lo = UNDEFINED; parser->gf_hi = UNDEFINED; - parser->have_location = 0; - parser->latitude = 0; - parser->longitude = 0; parser->ngasmixes = 0; parser->ntanks = 0; for (unsigned int i = 0; i < NGASMIXES; ++i) { @@ -230,7 +225,6 @@ halcyon_symbios_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; dc_decomodel_t *decomodel = (dc_decomodel_t *) value; - dc_location_t *location = (dc_location_t *) value; if (value) { switch (type) { @@ -293,13 +287,6 @@ halcyon_symbios_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, u decomodel->params.gf.low = parser->gf_lo; decomodel->params.gf.high = parser->gf_hi; break; - case DC_FIELD_LOCATION: - if (!parser->have_location) - return DC_STATUS_UNSUPPORTED; - location->latitude = parser->latitude / 1000000.0; - location->longitude = parser->longitude / 1000000.0; - location->altitude = 0.0; - break; default: return DC_STATUS_UNSUPPORTED; } @@ -348,8 +335,6 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac unsigned int atmospheric = UNDEFINED; unsigned int gf_lo = UNDEFINED; unsigned int gf_hi = UNDEFINED; - unsigned int have_location = 0; - int latitude = 0, longitude = 0; unsigned int ngasmixes = 0; unsigned int ntanks = 0; halcyon_symbios_gasmix_t gasmix[NGASMIXES] = {0}; @@ -539,13 +524,12 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac unsigned int DC_ATTR_UNUSED he = array_uint16_le (data + offset + 36 + i * 2); } } else if (type == ID_GPS) { - if (!have_location) { - longitude = (signed int) array_uint32_le (data + offset + 4); - latitude = (signed int) array_uint32_le (data + offset + 8); - have_location = 1; - } else { - WARNING (abstract->context, "Multiple GPS locations present."); - } + int longitude = (signed int) array_uint32_le (data + offset + 4); + int latitude = (signed int) array_uint32_le (data + offset + 8); + sample.location.latitude = latitude / 1000000.0; + sample.location.longitude = longitude / 1000000.0; + sample.location.altitude = 0.0; + if (callback) callback (DC_SAMPLE_LOCATION, &sample, userdata); } else if (type == ID_PO2_BOARD) { unsigned int DC_ATTR_UNUSED serial = array_uint16_le (data + offset + 6); for (unsigned int i = 0; i < 3; ++i) { @@ -748,9 +732,6 @@ halcyon_symbios_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callbac parser->atmospheric = atmospheric; parser->gf_lo = gf_lo; parser->gf_hi = gf_hi; - parser->have_location = have_location; - parser->latitude = latitude; - parser->longitude = longitude; parser->ngasmixes = ngasmixes; parser->ntanks = ntanks; for (unsigned int i = 0; i < NGASMIXES; ++i) { diff --git a/src/hw_frog.c b/src/hw_frog.c deleted file mode 100644 index dcd9dec3..00000000 --- a/src/hw_frog.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2012 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 - */ - -#include // memcmp, memcpy -#include // malloc, free - -#include "hw_frog.h" -#include "context-private.h" -#include "device-private.h" -#include "checksum.h" -#include "ringbuffer.h" -#include "array.h" - -#define ISINSTANCE(device) dc_device_isinstance((device), &hw_frog_device_vtable) - -#define SZ_DISPLAY 15 -#define SZ_CUSTOMTEXT 13 -#define SZ_VERSION (SZ_CUSTOMTEXT + 4) - -#define RB_LOGBOOK_SIZE 256 -#define RB_LOGBOOK_COUNT 256 - -#define RB_PROFILE_BEGIN 0x000000 -#define RB_PROFILE_END 0x200000 -#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END) - -#define READY 0x4D -#define HEADER 0x61 -#define CLOCK 0x62 -#define CUSTOMTEXT 0x63 -#define DIVE 0x66 -#define IDENTITY 0x69 -#define DISPLAY 0x6E -#define INIT 0xBB -#define EXIT 0xFF - -typedef struct hw_frog_device_t { - dc_device_t base; - dc_iostream_t *iostream; - unsigned char fingerprint[5]; -} hw_frog_device_t; - -static dc_status_t hw_frog_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); -static dc_status_t hw_frog_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); -static dc_status_t hw_frog_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime); -static dc_status_t hw_frog_device_close (dc_device_t *abstract); - -static const dc_device_vtable_t hw_frog_device_vtable = { - sizeof(hw_frog_device_t), - DC_FAMILY_HW_FROG, - hw_frog_device_set_fingerprint, /* set_fingerprint */ - NULL, /* read */ - NULL, /* write */ - NULL, /* dump */ - hw_frog_device_foreach, /* foreach */ - hw_frog_device_timesync, /* timesync */ - hw_frog_device_close /* close */ -}; - - -static int -hw_frog_strncpy (unsigned char *data, unsigned int size, const char *text) -{ - // Check the maximum length. - size_t length = (text ? strlen (text) : 0); - if (length > size) { - return -1; - } - - // Copy the text. - if (length) - memcpy (data, text, length); - - // Pad with spaces. - memset (data + length, 0x20, size - length); - - return 0; -} - - -static dc_status_t -hw_frog_transfer (hw_frog_device_t *device, - dc_event_progress_t *progress, - unsigned char cmd, - const unsigned char input[], - unsigned int isize, - unsigned char output[], - unsigned int osize) -{ - dc_status_t status = DC_STATUS_SUCCESS; - dc_device_t *abstract = (dc_device_t *) device; - - if (device_is_cancelled (abstract)) - return DC_STATUS_CANCELLED; - - // Send the command. - unsigned char command[1] = {cmd}; - status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to send the command."); - return status; - } - - if (cmd != INIT && cmd != HEADER) { - // Read the echo. - unsigned char answer[1] = {0}; - status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to receive the echo."); - return status; - } - - // Verify the echo. - if (memcmp (answer, command, sizeof (command)) != 0) { - ERROR (abstract->context, "Unexpected echo."); - return DC_STATUS_PROTOCOL; - } - } - - if (input) { - // Send the input data packet. - status = dc_iostream_write (device->iostream, input, isize, NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to send the data packet."); - return status; - } - } - - if (output) { - unsigned int nbytes = 0; - while (nbytes < osize) { - // Set the minimum packet size. - unsigned int len = 1024; - - // Increase the packet size if more data is immediately available. - size_t available = 0; - status = dc_iostream_get_available (device->iostream, &available); - if (status == DC_STATUS_SUCCESS && available > len) - len = available; - - // Limit the packet size to the total size. - if (nbytes + len > osize) - len = osize - nbytes; - - // Read the packet. - status = dc_iostream_read (device->iostream, output + nbytes, len, NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to receive the answer."); - return status; - } - - // Update and emit a progress event. - if (progress) { - progress->current += len; - device_event_emit ((dc_device_t *) device, DC_EVENT_PROGRESS, progress); - } - - nbytes += len; - } - } - - if (cmd != EXIT) { - // Read the ready byte. - unsigned char answer[1] = {0}; - status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to receive the ready byte."); - return status; - } - - // Verify the ready byte. - if (answer[0] != READY) { - ERROR (abstract->context, "Unexpected ready byte."); - return DC_STATUS_PROTOCOL; - } - } - - return DC_STATUS_SUCCESS; -} - - -dc_status_t -hw_frog_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream) -{ - dc_status_t status = DC_STATUS_SUCCESS; - hw_frog_device_t *device = NULL; - - if (out == NULL) - return DC_STATUS_INVALIDARGS; - - // Allocate memory. - device = (hw_frog_device_t *) dc_device_allocate (context, &hw_frog_device_vtable); - if (device == NULL) { - ERROR (context, "Failed to allocate memory."); - return DC_STATUS_NOMEMORY; - } - - // Set the default values. - device->iostream = iostream; - memset (device->fingerprint, 0, sizeof (device->fingerprint)); - - // Set the serial communication protocol (115200 8N1). - status = dc_iostream_configure (device->iostream, 115200, 8, DC_PARITY_NONE, DC_STOPBITS_ONE, DC_FLOWCONTROL_NONE); - if (status != DC_STATUS_SUCCESS) { - ERROR (context, "Failed to set the terminal attributes."); - goto error_free; - } - - // Set the timeout for receiving data (3000ms). - status = dc_iostream_set_timeout (device->iostream, 3000); - if (status != DC_STATUS_SUCCESS) { - ERROR (context, "Failed to set the timeout."); - goto error_free; - } - - // Make sure everything is in a sane state. - dc_iostream_sleep (device->iostream, 300); - dc_iostream_purge (device->iostream, DC_DIRECTION_ALL); - - // Send the init command. - status = hw_frog_transfer (device, NULL, INIT, NULL, 0, NULL, 0); - if (status != DC_STATUS_SUCCESS) { - ERROR (context, "Failed to send the command."); - goto error_free; - } - - *out = (dc_device_t *) device; - - return DC_STATUS_SUCCESS; - -error_free: - dc_device_deallocate ((dc_device_t *) device); - return status; -} - - -static dc_status_t -hw_frog_device_close (dc_device_t *abstract) -{ - dc_status_t status = DC_STATUS_SUCCESS; - hw_frog_device_t *device = (hw_frog_device_t*) abstract; - dc_status_t rc = DC_STATUS_SUCCESS; - - // Send the exit command. - rc = hw_frog_transfer (device, NULL, EXIT, NULL, 0, NULL, 0); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to send the command."); - dc_status_set_error(&status, rc); - } - - return status; -} - - -static dc_status_t -hw_frog_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - if (size && size != sizeof (device->fingerprint)) - return DC_STATUS_INVALIDARGS; - - if (size) - memcpy (device->fingerprint, data, sizeof (device->fingerprint)); - else - memset (device->fingerprint, 0, sizeof (device->fingerprint)); - - return DC_STATUS_SUCCESS; -} - - -dc_status_t -hw_frog_device_version (dc_device_t *abstract, unsigned char data[], unsigned int size) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - if (!ISINSTANCE (abstract)) - return DC_STATUS_INVALIDARGS; - - if (size != SZ_VERSION) - return DC_STATUS_INVALIDARGS; - - // Send the command. - dc_status_t rc = hw_frog_transfer (device, NULL, IDENTITY, NULL, 0, data, size); - if (rc != DC_STATUS_SUCCESS) - return rc; - - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -hw_frog_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - // Enable progress notifications. - dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - progress.maximum = (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT) + - (RB_PROFILE_END - RB_PROFILE_BEGIN); - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - - // Download the version data. - unsigned char id[SZ_VERSION] = {0}; - dc_status_t rc = hw_frog_device_version (abstract, id, sizeof (id)); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the version."); - return rc; - } - - HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "Version", id, sizeof (id)); - - // Emit a device info event. - dc_event_devinfo_t devinfo; - devinfo.model = 0; - devinfo.firmware = array_uint16_be (id + 2); - devinfo.serial = array_uint16_le (id + 0); - device_event_emit (abstract, DC_EVENT_DEVINFO, &devinfo); - - // Allocate memory. - unsigned char *header = (unsigned char *) malloc (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT); - if (header == NULL) { - ERROR (abstract->context, "Failed to allocate memory."); - return DC_STATUS_NOMEMORY; - } - - // Download the logbook headers. - rc = hw_frog_transfer (device, &progress, HEADER, - NULL, 0, header, RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the header."); - free (header); - return rc; - } - - // Locate the most recent dive. - // 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) { - unsigned int offset = i * RB_LOGBOOK_SIZE; - - // Ignore uninitialized header entries. - if (array_isequal (header + offset, RB_LOGBOOK_SIZE, 0xFF)) - break; - - // Get the internal dive number. - unsigned int current = array_uint16_le (header + offset + 52); - if (current > maximum) { - 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 int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT; - unsigned int offset = idx * RB_LOGBOOK_SIZE; - - // Get the ringbuffer pointers. - unsigned int begin = array_uint24_le (header + offset + 2); - unsigned int end = array_uint24_le (header + offset + 5); - if (begin < RB_PROFILE_BEGIN || - begin >= RB_PROFILE_END || - end < RB_PROFILE_BEGIN || - end >= RB_PROFILE_END) - { - ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", begin, end); - free (header); - return DC_STATUS_DATAFORMAT; - } - - // Calculate the profile length. - unsigned int length = RB_LOGBOOK_SIZE + RB_PROFILE_DISTANCE (begin, end) - 6; - - // Check the fingerprint data. - if (memcmp (header + offset + 9, device->fingerprint, sizeof (device->fingerprint)) == 0) - break; - - if (length > maxsize) - maxsize = length; - size += length; - ndives++; - } - - // Update and emit a progress event. - progress.maximum = (RB_LOGBOOK_SIZE * RB_LOGBOOK_COUNT) + size; - device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); - - // Finish immediately if there are no dives available. - if (ndives == 0) { - free (header); - return DC_STATUS_SUCCESS; - } - - // Allocate enough memory for the largest dive. - unsigned char *profile = (unsigned char *) malloc (maxsize); - if (profile == NULL) { - ERROR (abstract->context, "Failed to allocate memory."); - free (header); - return DC_STATUS_NOMEMORY; - } - - // Download the dives. - for (unsigned int i = 0; i < ndives; ++i) { - unsigned int idx = (latest + RB_LOGBOOK_COUNT - i) % RB_LOGBOOK_COUNT; - unsigned int offset = idx * RB_LOGBOOK_SIZE; - - // Get the ringbuffer pointers. - unsigned int begin = array_uint24_le (header + offset + 2); - unsigned int end = array_uint24_le (header + offset + 5); - - // Calculate the profile length. - unsigned int length = RB_LOGBOOK_SIZE + RB_PROFILE_DISTANCE (begin, end) - 6; - - // Download the dive. - unsigned char number[1] = {idx}; - rc = hw_frog_transfer (device, &progress, DIVE, - number, sizeof (number), profile, length); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the dive."); - free (profile); - free (header); - return rc; - } - - // Verify the header in the logbook and profile are identical. - if (memcmp (profile, header + offset, RB_LOGBOOK_SIZE) != 0) { - ERROR (abstract->context, "Unexpected profile header."); - free (profile); - free (header); - return rc; - - } - - if (callback && !callback (profile, length, profile + 9, sizeof (device->fingerprint), userdata)) - break; - } - - free (profile); - free (header); - - return DC_STATUS_SUCCESS; -} - - -static dc_status_t -hw_frog_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - // Send the command. - unsigned char packet[6] = { - datetime->hour, datetime->minute, datetime->second, - datetime->month, datetime->day, datetime->year - 2000}; - dc_status_t rc = hw_frog_transfer (device, NULL, CLOCK, packet, sizeof (packet), NULL, 0); - if (rc != DC_STATUS_SUCCESS) - return rc; - - return DC_STATUS_SUCCESS; -} - - -dc_status_t -hw_frog_device_display (dc_device_t *abstract, const char *text) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - if (!ISINSTANCE (abstract)) - return DC_STATUS_INVALIDARGS; - - // Pad the data packet with spaces. - unsigned char packet[SZ_DISPLAY] = {0}; - if (hw_frog_strncpy (packet, sizeof (packet), text) != 0) { - ERROR (abstract->context, "Invalid parameter specified."); - return DC_STATUS_INVALIDARGS; - } - - // Send the command. - dc_status_t rc = hw_frog_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0); - if (rc != DC_STATUS_SUCCESS) - return rc; - - return DC_STATUS_SUCCESS; -} - - -dc_status_t -hw_frog_device_customtext (dc_device_t *abstract, const char *text) -{ - hw_frog_device_t *device = (hw_frog_device_t *) abstract; - - if (!ISINSTANCE (abstract)) - return DC_STATUS_INVALIDARGS; - - // Pad the data packet with spaces. - unsigned char packet[SZ_CUSTOMTEXT] = {0}; - if (hw_frog_strncpy (packet, sizeof (packet), text) != 0) { - ERROR (abstract->context, "Invalid parameter specified."); - return DC_STATUS_INVALIDARGS; - } - - // Send the command. - dc_status_t rc = hw_frog_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0); - if (rc != DC_STATUS_SUCCESS) - return rc; - - return DC_STATUS_SUCCESS; -} diff --git a/src/hw_frog.h b/src/hw_frog.h deleted file mode 100644 index 74cf5afb..00000000 --- a/src/hw_frog.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * libdivecomputer - * - * Copyright (C) 2012 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 HW_FROG_H -#define HW_FROG_H - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -dc_status_t -hw_frog_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* HW_FROG_H */ diff --git a/src/hw_ostc3.c b/src/hw_ostc3.c index cc77b098..0e48b799 100644 --- a/src/hw_ostc3.c +++ b/src/hw_ostc3.c @@ -31,6 +31,7 @@ #include "aes.h" #include "platform.h" #include "packet.h" +#include "ringbuffer.h" #define ISINSTANCE(device) dc_device_isinstance((device), &hw_ostc3_device_vtable) @@ -38,15 +39,23 @@ (((major) & 0xFF) << 8) | \ ((minor) & 0xFF)) -#define SZ_DISPLAY 16 -#define SZ_CUSTOMTEXT 60 -#define SZ_VERSION (SZ_CUSTOMTEXT + 4) +#define SZ_DISPLAY_FROG 15 +#define SZ_DISPLAY_OSTC3 16 +#define SZ_DISPLAY_MAX SZ_DISPLAY_OSTC3 +#define SZ_CUSTOMTEXT_FROG 13 +#define SZ_CUSTOMTEXT_OSTC3 60 +#define SZ_CUSTOMTEXT_MAX SZ_CUSTOMTEXT_OSTC3 +#define SZ_VERSION_FROG (SZ_CUSTOMTEXT_FROG + 4) +#define SZ_VERSION_OSTC3 (SZ_CUSTOMTEXT_OSTC3 + 4) +#define SZ_VERSION_MAX SZ_VERSION_OSTC3 + #define SZ_HARDWARE 1 #define SZ_HARDWARE2 5 #define SZ_MEMORY 0x400000 #define SZ_CONFIG 4 #define SZ_FWINFO 4 -#define SZ_FIRMWARE 0x01E000 // 120KB +#define SZ_FIRMWARE_OSTC3 0x01E000 // 120KB +#define SZ_FIRMWARE_FROG 0x01D000 // 116KB #define SZ_FIRMWARE_BLOCK 0x1000 // 4KB #define SZ_FIRMWARE_BLOCK2 0x0100 // 256B #define FIRMWARE_AREA 0x3E0000 @@ -55,10 +64,15 @@ #define RB_LOGBOOK_SIZE_FULL 256 #define RB_LOGBOOK_COUNT 256 +#define RB_PROFILE_BEGIN 0x000000 +#define RB_PROFILE_END 0x200000 +#define RB_PROFILE_DISTANCE(a,b) ringbuffer_distance (a, b, DC_RINGBUFFER_EMPTY, RB_PROFILE_BEGIN, RB_PROFILE_END) + #define S_BLOCK_READ 0x20 #define S_BLOCK_WRITE 0x30 #define S_BLOCK_WRITE2 0x31 #define S_ERASE 0x42 +#define S_KEY 0x4B #define S_READY 0x4C #define READY 0x4D #define S_UPGRADE 0x50 @@ -88,6 +102,8 @@ #define MODEL_OSTC4 0x43 #define MODEL_OSTC5 0x44 +#define UNDEFINED 0xFFFFFFFF + #define NODELAY 0 #define TIMEOUT 400 @@ -104,7 +120,6 @@ #define HDR_FULL_POINTERS 2 // 6 bytes #define HDR_FULL_FIRMWARE 48 // 2 bytes - typedef enum hw_ostc3_state_t { OPEN, DOWNLOAD, @@ -115,6 +130,7 @@ typedef enum hw_ostc3_state_t { typedef struct hw_ostc3_device_t { dc_device_t base; dc_iostream_t *iostream; + unsigned int frog; unsigned int hardware; unsigned int feature; unsigned int model; @@ -130,23 +146,16 @@ typedef struct hw_ostc3_logbook_t { unsigned int fingerprint; unsigned int number; unsigned int version; + unsigned int pointers; + unsigned int firmware; } hw_ostc3_logbook_t; typedef struct hw_ostc3_firmware_t { - unsigned char data[SZ_FIRMWARE]; + unsigned int size; unsigned int checksum; + unsigned char data[]; } hw_ostc3_firmware_t; -// This key is used both for the OSTC3 and its cousin, -// the OSTC Sport. -// The Frog uses a similar protocol, and with another key. -static const unsigned char ostc3_key[16] = { - 0xF1, 0xE9, 0xB0, 0x30, - 0x45, 0x6F, 0xBE, 0x55, - 0xFF, 0xE7, 0xF8, 0x31, - 0x13, 0x6C, 0xF2, 0xFE -}; - static dc_status_t hw_ostc3_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); static dc_status_t hw_ostc3_device_read (dc_device_t *abstract, unsigned int address, unsigned char data[], unsigned int size); static dc_status_t hw_ostc3_device_write (dc_device_t *abstract, unsigned int address, const unsigned char data[], unsigned int size); @@ -169,20 +178,53 @@ static const dc_device_vtable_t hw_ostc3_device_vtable = { static const hw_ostc3_logbook_t hw_ostc3_logbook_compact = { RB_LOGBOOK_SIZE_COMPACT, /* size */ - HDR_COMPACT_LENGTH, /* profile */ - HDR_COMPACT_SUMMARY, /* fingerprint */ - HDR_COMPACT_NUMBER, /* number */ - HDR_COMPACT_VERSION, /* version */ + 0, /* profile */ + 3, /* fingerprint */ + 13, /* number */ + 15, /* version */ + UNDEFINED, /* pointers */ + UNDEFINED, /* firmware */ }; -static const hw_ostc3_logbook_t hw_ostc3_logbook_full = { - RB_LOGBOOK_SIZE_FULL, /* size */ - HDR_FULL_LENGTH, /* profile */ - HDR_FULL_SUMMARY, /* fingerprint */ - HDR_FULL_NUMBER, /* number */ - HDR_FULL_VERSION, /* version */ +static const hw_ostc3_logbook_t hw_ostc3_logbook_full[2] = { + /* OSTC3 */ + { + RB_LOGBOOK_SIZE_FULL, /* size */ + 9, /* profile */ + 12, /* fingerprint */ + 80, /* number */ + 8, /* version */ + 2, /* pointers */ + 48, /* firmware */ + }, + /* Frog */ + { + RB_LOGBOOK_SIZE_FULL, /* size */ + UNDEFINED, /* profile */ + 9, /* fingerprint */ + 52, /* number */ + 8, /* version */ + 2, /* pointers */ + 32, /* firmware */ + } }; +static const unsigned char hw_ostc3_key[2][16] = { + /* OSTC3 */ + { + 0xF1, 0xE9, 0xB0, 0x30, + 0x45, 0x6F, 0xBE, 0x55, + 0xFF, 0xE7, 0xF8, 0x31, + 0x13, 0x6C, 0xF2, 0xFE + }, + /* Frog */ + { + 0x6F, 0x55, 0xBE, 0x45, + 0x6C, 0xFE, 0xF2, 0x13, + 0xE7, 0x31, 0xF8, 0xFF, + 0xE9, 0x30, 0xB0, 0xF1 + } +}; static int hw_ostc3_strncpy (unsigned char *data, unsigned int size, const char *text) @@ -278,6 +320,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, { dc_device_t *abstract = (dc_device_t *) device; dc_status_t status = DC_STATUS_SUCCESS; + const hw_ostc3_logbook_t *layout = &hw_ostc3_logbook_full[device->frog]; unsigned int length = osize; if (cmd == DIVE && length < RB_LOGBOOK_SIZE_FULL) @@ -297,22 +340,24 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, return status; } - // Read the echo. - unsigned char echo[1] = {0}; - status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to receive the echo."); - return status; - } + if (!device->frog || (cmd != INIT && cmd != HEADER)) { + // Read the echo. + unsigned char echo[1] = {0}; + status = dc_iostream_read (device->iostream, echo, sizeof (echo), NULL); + if (status != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to receive the echo."); + return status; + } - // Verify the echo. - if (memcmp (echo, command, sizeof (command)) != 0) { - if (echo[0] == ready) { - ERROR (abstract->context, "Unsupported command."); - return DC_STATUS_UNSUPPORTED; - } else { - ERROR (abstract->context, "Unexpected echo."); - return DC_STATUS_PROTOCOL; + // Verify the echo. + if (memcmp (echo, command, sizeof (command)) != 0) { + if (echo[0] == ready) { + ERROR (abstract->context, "Unsupported command."); + return DC_STATUS_UNSUPPORTED; + } else { + ERROR (abstract->context, "Unexpected echo."); + return DC_STATUS_PROTOCOL; + } } } @@ -327,7 +372,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, dc_iostream_sleep (device->iostream, 10); - // Send the reamainder of the input data packet. + // Send the remainder of the input data packet. status = hw_ostc3_write (device, progress, input + 1, isize - 1); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the data packet."); @@ -357,8 +402,9 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, // pointer fields reset to zero, and the length field reduced to 8 // bytes), along with an empty dive profile. Detect this condition // and adjust the expected length. - if (array_isequal (output + HDR_FULL_POINTERS, 6, 0x00) && - array_uint24_le (output + HDR_FULL_LENGTH) == 8 && + if (!device->frog && + array_isequal (output + layout->pointers, 6, 0x00) && + array_uint24_le (output + layout->profile) == 8 && length > RB_LOGBOOK_SIZE_FULL + 5) { length = RB_LOGBOOK_SIZE_FULL + 5; } @@ -413,7 +459,7 @@ hw_ostc3_transfer (hw_ostc3_device_t *device, dc_status_t -hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream) +hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *iostream, unsigned int frog) { dc_status_t status = DC_STATUS_SUCCESS; hw_ostc3_device_t *device = NULL; @@ -430,6 +476,7 @@ hw_ostc3_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_t *i } // Set the default values. + device->frog = frog; device->hardware = INVALID; device->feature = 0; device->model = 0; @@ -537,27 +584,31 @@ hw_ostc3_device_init_service (hw_ostc3_device_t *device) dc_status_t status = DC_STATUS_SUCCESS; dc_device_t *abstract = (dc_device_t *) device; - const unsigned char command[] = {S_INIT, 0xAB, 0xCD, 0xEF}; + const unsigned char command[2][4] = { + {S_INIT, 0xAB, 0xCD, 0xEF}, // OSTC3 + {S_INIT, 0xAA, 0xAB, 0xAC}, // Frog + }; + const unsigned int echolen = device->frog ? 0 : sizeof(command[device->frog]) - 1; unsigned char answer[5] = {0}; // Send the command and service key. - status = dc_iostream_write (device->iostream, command, sizeof (command), NULL); + status = dc_iostream_write (device->iostream, command[device->frog], sizeof (command[device->frog]), NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to send the command."); return status; } // Read the response. - status = dc_iostream_read (device->iostream, answer, sizeof (answer), NULL); + status = dc_iostream_read (device->iostream, answer, 1 + echolen + 1, NULL); if (status != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to receive the answer."); return status; } // Verify the response to service mode. - if (answer[0] != 0x4B || answer[1] != 0xAB || - answer[2] != 0xCD || answer[3] != 0xEF || - answer[4] != S_READY) { + if (answer[0] != S_KEY || + memcmp (answer + 1, command[device->frog] + 1, echolen) != 0 || + answer[1 + echolen] != S_READY) { ERROR (abstract->context, "Failed to verify the answer."); return DC_STATUS_PROTOCOL; } @@ -633,14 +684,16 @@ hw_ostc3_device_init (hw_ostc3_device_t *device, hw_ostc3_state_t state) } // Read the version information. - unsigned char version[SZ_VERSION] = {0}; - rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, version, sizeof(version), NULL, NODELAY); + unsigned char version[SZ_VERSION_MAX] = {0}; + const unsigned int versionsize = device->frog ? + SZ_VERSION_FROG : SZ_VERSION_OSTC3; + rc = hw_ostc3_transfer (device, NULL, IDENTITY, NULL, 0, version, versionsize, NULL, NODELAY); if (rc != DC_STATUS_SUCCESS) { ERROR (abstract->context, "Failed to read the version information."); return rc; } - HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "Version", version, sizeof(version)); + HEXDUMP (abstract->context, DC_LOGLEVEL_DEBUG, "Version", version, versionsize); // Cache the descriptor. if (hardware_prefix != OSTC4_5_PREFIX) { @@ -731,7 +784,10 @@ hw_ostc3_device_version (dc_device_t *abstract, unsigned char data[], unsigned i if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; - if (size != SZ_VERSION) + const unsigned int versionsize = device->frog ? + SZ_VERSION_FROG : SZ_VERSION_OSTC3; + + if (size != versionsize) return DC_STATUS_INVALIDARGS; dc_status_t rc = hw_ostc3_device_init (device, DOWNLOAD); @@ -810,26 +866,38 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi // Download the compact logbook headers. If the firmware doesn't support // compact headers yet, fallback to downloading the full logbook headers. // This is slower, but also works for older firmware versions. - unsigned int compact = 1; - rc = hw_ostc3_transfer (device, &progress, COMPACT, - NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT, NULL, NODELAY); - if (rc == DC_STATUS_UNSUPPORTED) { - compact = 0; + // The Frog always uses the full header format. + unsigned int compact = !device->frog; + if (compact) { + rc = hw_ostc3_transfer (device, &progress, COMPACT, + NULL, 0, header, RB_LOGBOOK_SIZE_COMPACT * RB_LOGBOOK_COUNT, NULL, NODELAY); + if (rc == DC_STATUS_UNSUPPORTED) { + compact = 0; + } else if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the header."); + free (header); + return rc; + } + } + if (!compact) { rc = hw_ostc3_transfer (device, &progress, HEADER, NULL, 0, header, RB_LOGBOOK_SIZE_FULL * RB_LOGBOOK_COUNT, NULL, NODELAY); + if (rc != DC_STATUS_SUCCESS) { + ERROR (abstract->context, "Failed to read the header."); + free (header); + return rc; + } } - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the header."); - free (header); - return rc; - } + + // Get the correct header layout. + const hw_ostc3_logbook_t *layout = &hw_ostc3_logbook_full[device->frog]; // Get the correct logbook layout. const hw_ostc3_logbook_t *logbook = NULL; if (compact) { logbook = &hw_ostc3_logbook_compact; } else { - logbook = &hw_ostc3_logbook_full; + logbook = layout; } // Locate the most recent dive. @@ -868,13 +936,32 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi continue; } + // Calculate the profile length. - unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3; - if (!compact) { - // Workaround for a bug in older firmware versions. - unsigned int firmware = array_uint16_be (header + offset + HDR_FULL_FIRMWARE); - if (firmware < OSTC3FW(0,93)) - length -= 3; + unsigned int length = 0; + if (device->frog) { + // Get the ringbuffer pointers. + unsigned int begin = array_uint24_le (header + offset + logbook->pointers); + unsigned int end = array_uint24_le (header + offset + logbook->pointers + 3); + if (begin < RB_PROFILE_BEGIN || + begin >= RB_PROFILE_END || + end < RB_PROFILE_BEGIN || + end >= RB_PROFILE_END) + { + ERROR (abstract->context, "Invalid ringbuffer pointer detected (0x%06x 0x%06x).", begin, end); + free (header); + return DC_STATUS_DATAFORMAT; + } + + length = RB_LOGBOOK_SIZE_FULL + RB_PROFILE_DISTANCE (begin, end) - 6; + } else { + length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3; + if (!compact) { + // Workaround for a bug in older firmware versions. + unsigned int firmware = array_uint16_be (header + offset + logbook->firmware); + if (firmware < OSTC3FW(0,93)) + length -= 3; + } } if (length < RB_LOGBOOK_SIZE_FULL) { ERROR (abstract->context, "Invalid profile length (%u bytes).", length); @@ -917,12 +1004,21 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi unsigned int offset = idx * logbook->size; // Calculate the profile length. - unsigned int length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3; - if (!compact) { - // Workaround for a bug in older firmware versions. - unsigned int firmware = array_uint16_be (header + offset + HDR_FULL_FIRMWARE); - if (firmware < OSTC3FW(0,93)) - length -= 3; + unsigned int length = 0; + if (device->frog) { + // Get the ringbuffer pointers. + unsigned int begin = array_uint24_le (header + offset + logbook->pointers); + unsigned int end = array_uint24_le (header + offset + logbook->pointers + 3); + + length = RB_LOGBOOK_SIZE_FULL + RB_PROFILE_DISTANCE (begin, end) - 6; + } else { + length = RB_LOGBOOK_SIZE_FULL + array_uint24_le (header + offset + logbook->profile) - 3; + if (!compact) { + // Workaround for a bug in older firmware versions. + unsigned int firmware = array_uint16_be (header + offset + logbook->firmware); + if (firmware < OSTC3FW(0,93)) + length -= 3; + } } // Download the dive. @@ -937,11 +1033,11 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi } // Verify the header in the logbook and profile are identical. - if (memcmp (profile + HDR_FULL_VERSION, header + offset + logbook->version, 1) != 0 || - compact ? - memcmp (profile + HDR_FULL_SUMMARY, header + offset + HDR_COMPACT_SUMMARY, 10) != 0 || - memcmp (profile + HDR_FULL_NUMBER, header + offset + HDR_COMPACT_NUMBER, 2) != 0 : - memcmp (profile + HDR_FULL_SUMMARY, header + offset + HDR_FULL_SUMMARY, RB_LOGBOOK_SIZE_FULL - HDR_FULL_SUMMARY) != 0) { + if (memcmp (profile + layout->version, header + offset + logbook->version, 1) != 0 || + (compact ? + (memcmp (profile + layout->fingerprint, header + offset + logbook->fingerprint, 10) != 0 || + memcmp (profile + layout->number, header + offset + logbook->number, 2) != 0) : + memcmp (profile + layout->fingerprint, header + offset + layout->fingerprint, RB_LOGBOOK_SIZE_FULL - layout->fingerprint) != 0)) { ERROR (abstract->context, "Unexpected profile header."); free (profile); free (header); @@ -959,8 +1055,8 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi } else if (length == RB_LOGBOOK_SIZE_FULL + 2) { // A profile containing only the 2 byte end-of-profile // marker is considered a valid empty profile. - } else if (length < RB_LOGBOOK_SIZE_FULL + 5 || - array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + HDR_FULL_LENGTH)) { + } else if (!device->frog && (length < RB_LOGBOOK_SIZE_FULL + 5 || + array_uint24_le (profile + RB_LOGBOOK_SIZE_FULL) + delta != array_uint24_le (profile + layout->profile))) { // If there is more data available, then there should be a // valid profile header containing a length matching the // length in the dive header. @@ -968,7 +1064,7 @@ hw_ostc3_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, voi length = RB_LOGBOOK_SIZE_FULL; } - if (callback && !callback (profile, length, profile + HDR_FULL_SUMMARY, sizeof (device->fingerprint), userdata)) + if (callback && !callback (profile, length, profile + layout->fingerprint, sizeof (device->fingerprint), userdata)) break; } @@ -1008,9 +1104,12 @@ hw_ostc3_device_display (dc_device_t *abstract, const char *text) if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; + const unsigned int packetsize = device->frog ? + SZ_DISPLAY_FROG : SZ_DISPLAY_OSTC3; + // Pad the data packet with spaces. - unsigned char packet[SZ_DISPLAY] = {0}; - if (hw_ostc3_strncpy (packet, sizeof (packet), text) != 0) { + unsigned char packet[SZ_DISPLAY_MAX] = {0}; + if (hw_ostc3_strncpy (packet, packetsize, text) != 0) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } @@ -1020,7 +1119,7 @@ hw_ostc3_device_display (dc_device_t *abstract, const char *text) return rc; // Send the command. - rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, sizeof (packet), NULL, 0, NULL, NODELAY); + rc = hw_ostc3_transfer (device, NULL, DISPLAY, packet, packetsize, NULL, 0, NULL, NODELAY); if (rc != DC_STATUS_SUCCESS) return rc; @@ -1036,9 +1135,12 @@ hw_ostc3_device_customtext (dc_device_t *abstract, const char *text) if (!ISINSTANCE (abstract)) return DC_STATUS_INVALIDARGS; + const unsigned int packetsize = device->frog ? + SZ_CUSTOMTEXT_FROG : SZ_CUSTOMTEXT_OSTC3; + // Pad the data packet with spaces. - unsigned char packet[SZ_CUSTOMTEXT] = {0}; - if (hw_ostc3_strncpy (packet, sizeof (packet), text) != 0) { + unsigned char packet[SZ_CUSTOMTEXT_MAX] = {0}; + if (hw_ostc3_strncpy (packet, packetsize, text) != 0) { ERROR (abstract->context, "Invalid parameter specified."); return DC_STATUS_INVALIDARGS; } @@ -1048,7 +1150,7 @@ hw_ostc3_device_customtext (dc_device_t *abstract, const char *text) return rc; // Send the command. - rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, sizeof (packet), NULL, 0, NULL, NODELAY); + rc = hw_ostc3_transfer (device, NULL, CUSTOMTEXT, packet, packetsize, NULL, 0, NULL, NODELAY); if (rc != DC_STATUS_SUCCESS) return rc; @@ -1204,7 +1306,7 @@ hw_ostc3_firmware_readline (FILE *fp, dc_context_t *context, unsigned int addr, static dc_status_t -hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *context, const char *filename) +hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *context, const char *filename, const unsigned char key[]) { dc_status_t rc = DC_STATUS_SUCCESS; FILE *fp = NULL; @@ -1220,7 +1322,7 @@ hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *contex } // Initialize the buffers. - memset (firmware->data, 0xFF, sizeof (firmware->data)); + memset (firmware->data, 0xFF, firmware->size); firmware->checksum = 0; fp = fopen (filename, "rb"); @@ -1238,9 +1340,9 @@ hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *contex bytes += 16; // Load the iv for AES-FCB-mode - AES128_ECB_encrypt (iv, ostc3_key, tmpbuf); + AES128_ECB_encrypt (iv, key, tmpbuf); - for (addr = 0; addr < SZ_FIRMWARE; addr += 16, bytes += 16) { + for (addr = 0; addr < firmware->size; addr += 16, bytes += 16) { rc = hw_ostc3_firmware_readline (fp, context, bytes, encrypted, sizeof(encrypted)); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to parse file data."); @@ -1253,7 +1355,7 @@ hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *contex firmware->data[addr + i] = encrypted[i] ^ tmpbuf[i]; // Run the next round of encryption - AES128_ECB_encrypt (encrypted, ostc3_key, tmpbuf); + AES128_ECB_encrypt (encrypted, key, tmpbuf); } // This file format contains a tail with the checksum in @@ -1267,7 +1369,7 @@ hw_ostc3_firmware_readfile3 (hw_ostc3_firmware_t *firmware, dc_context_t *contex fclose (fp); unsigned int csum1 = array_uint32_le (checksum); - unsigned int csum2 = hw_ostc3_firmware_checksum (firmware->data, sizeof(firmware->data)); + unsigned int csum2 = hw_ostc3_firmware_checksum (firmware->data, firmware->size); if (csum1 != csum2) { ERROR (context, "Failed to verify file checksum."); return DC_STATUS_DATAFORMAT; @@ -1452,21 +1554,28 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename) hw_ostc3_device_t *device = (hw_ostc3_device_t *) abstract; dc_context_t *context = (abstract ? abstract->context : NULL); + // Firmware size. + const unsigned int firmwaresize = device->frog ? + SZ_FIRMWARE_FROG : SZ_FIRMWARE_OSTC3; + // Enable progress notifications. // load, erase, upload FZ, verify FZ, reprogram dc_event_progress_t progress = EVENT_PROGRESS_INITIALIZER; - progress.maximum = 3 + SZ_FIRMWARE * 2 / SZ_FIRMWARE_BLOCK; + progress.maximum = 3 + firmwaresize * 2 / SZ_FIRMWARE_BLOCK; device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); // Allocate memory for the firmware data. - hw_ostc3_firmware_t *firmware = (hw_ostc3_firmware_t *) malloc (sizeof (hw_ostc3_firmware_t)); + hw_ostc3_firmware_t *firmware = (hw_ostc3_firmware_t *) malloc (sizeof (hw_ostc3_firmware_t) + firmwaresize); if (firmware == NULL) { ERROR (context, "Failed to allocate memory."); return DC_STATUS_NOMEMORY; } + // Initialize the size. + firmware->size = firmwaresize; + // Read the hex file. - rc = hw_ostc3_firmware_readfile3 (firmware, context, filename); + rc = hw_ostc3_firmware_readfile3 (firmware, context, filename, hw_ostc3_key[device->frog]); if (rc != DC_STATUS_SUCCESS) { free (firmware); return rc; @@ -1478,7 +1587,7 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename) hw_ostc3_device_display (abstract, " Erasing FW..."); - rc = hw_ostc3_firmware_erase (device, FIRMWARE_AREA, SZ_FIRMWARE); + rc = hw_ostc3_firmware_erase (device, FIRMWARE_AREA, firmware->size); if (rc != DC_STATUS_SUCCESS) { ERROR (context, "Failed to erase old firmware"); free (firmware); @@ -1491,10 +1600,10 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename) hw_ostc3_device_display (abstract, " Uploading..."); - for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) { - char status[SZ_DISPLAY + 1]; // Status message on the display - dc_platform_snprintf (status, sizeof(status), " Uploading %2d%%", (100 * len) / SZ_FIRMWARE); - hw_ostc3_device_display (abstract, status); + for (unsigned int len = 0; len < firmware->size; len += SZ_FIRMWARE_BLOCK) { + char msg[SZ_DISPLAY_MAX + 1]; // Status message on the display + dc_platform_snprintf (msg, sizeof(msg), " Uploading %2d%%", (100 * len) / firmware->size); + hw_ostc3_device_display (abstract, msg); rc = hw_ostc3_firmware_block_write (device, FIRMWARE_AREA + len, firmware->data + len, SZ_FIRMWARE_BLOCK); if (rc != DC_STATUS_SUCCESS) { @@ -1509,11 +1618,11 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename) hw_ostc3_device_display (abstract, " Verifying..."); - for (unsigned int len = 0; len < SZ_FIRMWARE; len += SZ_FIRMWARE_BLOCK) { + for (unsigned int len = 0; len < firmware->size; len += SZ_FIRMWARE_BLOCK) { unsigned char block[SZ_FIRMWARE_BLOCK]; - char status[SZ_DISPLAY + 1]; // Status message on the display - dc_platform_snprintf (status, sizeof(status), " Verifying %2d%%", (100 * len) / SZ_FIRMWARE); - hw_ostc3_device_display (abstract, status); + char msg[SZ_DISPLAY_MAX + 1]; // Status message on the display + dc_platform_snprintf (msg, sizeof(msg), " Verifying %2d%%", (100 * len) / firmware->size); + hw_ostc3_device_display (abstract, msg); rc = hw_ostc3_firmware_block_read (device, FIRMWARE_AREA + len, block, sizeof (block)); if (rc != DC_STATUS_SUCCESS) { @@ -1536,7 +1645,7 @@ hw_ostc3_device_fwupdate3 (dc_device_t *abstract, const char *filename) rc = hw_ostc3_firmware_upgrade (abstract, firmware->checksum); if (rc != DC_STATUS_SUCCESS) { - ERROR (context, "Failed to start programing"); + ERROR (context, "Failed to start programming"); free (firmware); return rc; } diff --git a/src/hw_ostc3.h b/src/hw_ostc3.h index 7de52715..e0cd5b28 100644 --- a/src/hw_ostc3.h +++ b/src/hw_ostc3.h @@ -36,7 +36,7 @@ extern "C" { #define ISHWOS4(hardware) (((hardware) >> 8) == OSTC4_5_PREFIX) dc_status_t -hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream); +hw_ostc3_device_open (dc_device_t **device, dc_context_t *context, dc_iostream_t *iostream, unsigned int frog); dc_status_t hw_ostc3_parser_create (dc_parser_t **out, dc_context_t *context, const unsigned char data[], size_t size, unsigned int model, unsigned int serial); diff --git a/src/libdivecomputer.symbols b/src/libdivecomputer.symbols index 859dbe11..48bdabef 100644 --- a/src/libdivecomputer.symbols +++ b/src/libdivecomputer.symbols @@ -141,9 +141,6 @@ hw_ostc_device_eeprom_write hw_ostc_device_reset hw_ostc_device_screenshot hw_ostc_device_fwupdate -hw_frog_device_version -hw_frog_device_display -hw_frog_device_customtext hw_ostc3_device_version hw_ostc3_device_hardware hw_ostc3_device_display diff --git a/src/mares_iconhd.c b/src/mares_iconhd.c index 05e2021a..9a55769f 100644 --- a/src/mares_iconhd.c +++ b/src/mares_iconhd.c @@ -52,6 +52,7 @@ #define SIRIUS 0x2F #define QUADCI 0x31 #define QUAD2 0x32 +#define SIRIUS_L 0x33 #define PUCK4 0x35 #define ISSMART(model) ( \ @@ -66,6 +67,7 @@ (model) == SIRIUS || \ (model) == QUADCI || \ (model) == QUAD2 || \ + (model) == SIRIUS_L || \ (model) == PUCK4) #define ISSIRIUS(model) ( \ @@ -73,6 +75,7 @@ (model) == SIRIUS || \ (model) == QUADCI || \ (model) == QUAD2 || \ + (model) == SIRIUS_L || \ (model) == PUCK4) #define MAXRETRIES 4 @@ -199,6 +202,7 @@ mares_iconhd_get_model (mares_iconhd_device_t *device) {"Horizon", HORIZON}, {"Puck Air 2", PUCKAIR2}, {"Sirius", SIRIUS}, + {"Sirius L", SIRIUS_L}, {"Quad Ci", QUADCI}, {"Quad2", QUAD2}, {"Puck4", PUCK4}, @@ -675,6 +679,7 @@ mares_iconhd_device_open (dc_device_t **out, dc_context_t *context, dc_iostream_ case SIRIUS: case QUADCI: case QUAD2: + case SIRIUS_L: case PUCK4: device->layout = &mares_genius_layout; device->packetsize = 4096; @@ -882,7 +887,7 @@ mares_iconhd_device_foreach_raw (dc_device_t *abstract, dc_dive_callback_t callb device_event_emit (abstract, DC_EVENT_PROGRESS, &progress); eop = array_uint32_le (pointer); - if (eop != 0xFFFFFFFF) + if (eop >= layout->rb_profile_begin && eop < layout->rb_profile_end) break; } if (eop < layout->rb_profile_begin || eop >= layout->rb_profile_end) { diff --git a/src/mares_iconhd_parser.c b/src/mares_iconhd_parser.c index 73f28fae..ba489d44 100644 --- a/src/mares_iconhd_parser.c +++ b/src/mares_iconhd_parser.c @@ -52,6 +52,7 @@ #define SIRIUS 0x2F #define QUADCI 0x31 #define QUAD2 0x32 +#define SIRIUS_L 0x33 #define PUCK4 0x35 #define ISSMART(model) ( \ @@ -66,6 +67,7 @@ (model) == SIRIUS || \ (model) == QUADCI || \ (model) == QUAD2 || \ + (model) == SIRIUS_L || \ (model) == PUCK4) #define NGASMIXES_ICONHD 3 diff --git a/src/parser.c b/src/parser.c index 36236979..fd4a263b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -42,7 +42,6 @@ #include "mares_iconhd.h" #include "mares_nemo.h" #include "mares_puck.h" -#include "hw_frog.h" #include "hw_ostc.h" #include "hw_ostc3.h" #include "cressi_edy.h" diff --git a/src/seac_screen.c b/src/seac_screen.c index 9632f097..be33a794 100644 --- a/src/seac_screen.c +++ b/src/seac_screen.c @@ -135,7 +135,7 @@ static const seac_screen_layout_t layout_screen = { static const seac_screen_layout_t layout_tablet = { 0x0A0000, /* rb_profile_begin */ - 0x200000, /* rb_profile_end */ + 0x400000, /* rb_profile_end */ }; static dc_status_t diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 2d75fb6e..0777ea75 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -846,8 +846,21 @@ dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsi *model = TERN; break; default: - WARNING (device->base.context, "Unknown hardware type 0x%04x.", hardware); + // Unknown hardware type: fall back to reading the model number directly from the device. + WARNING (device->base.context, "Unknown hardware type 0x%04x, falling back to ID_MODEL.", hardware); + { + unsigned char rsp_model = 0; + dc_status_t rc = shearwater_common_rdbi (device, ID_MODEL, &rsp_model, sizeof(rsp_model), NULL); + if (rc != DC_STATUS_SUCCESS) { + ERROR (device->base.context, "Failed to read the model number."); + return rc; + } + *model = rsp_model; + } + break; } return status; } + + diff --git a/src/shearwater_common.h b/src/shearwater_common.h index d9da0082..9808875b 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -30,16 +30,14 @@ extern "C" { #endif /* __cplusplus */ +#define WDBI_TIME_PACKET_SIZE 7 + #define ID_SERIAL 0x8010 #define ID_FIRMWARE 0x8011 #define ID_LOGUPLOAD 0x8021 #define ID_HARDWARE 0x8050 -#define ID_LOCAL_TIME 0x9030 -#define ID_UTC_TIME 0x9031 -#define ID_LOCAL_TIME_OFFSET 0x9032 -#define ID_LOCAL_TIME_DST 0x9033 -#define WDBI_TIME_PACKET_SIZE 7 +#define ID_MODEL 0x8060 #define ID_TIME_LOCAL 0x9030 #define ID_TIME_UTC 0x9031 @@ -91,13 +89,11 @@ shearwater_common_timesync_local (shearwater_common_device_t *device, const dc_d dc_status_t shearwater_common_timesync_utc (shearwater_common_device_t *device, const dc_datetime_t *datetime); -dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsigned int *model); - dc_status_t shearwater_common_can_wdbi (shearwater_common_device_t *device, dc_buffer_t *buffer, unsigned int id); dc_status_t shearwater_common_device_timesync(dc_device_t *abstract, const dc_datetime_t *datetime); -dc_status_t shearwater_common_read_model(shearwater_common_device_t *device, unsigned int *model); +dc_status_t shearwater_common_get_model(shearwater_common_device_t *device, unsigned int *model); #ifdef __cplusplus } diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 1079bb13..3a9af132 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -192,10 +192,8 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call unsigned int model = 0; rc = shearwater_common_get_model (&device->base, &model); - if (rc != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the hardware type."); + if (rc != DC_STATUS_SUCCESS) return rc; - } // Emit a device info event. dc_event_devinfo_t devinfo; @@ -363,10 +361,8 @@ shearwater_petrel_device_timesync (dc_device_t *abstract, const dc_datetime_t *d unsigned int model = 0; status = shearwater_common_get_model (device, &model); - if (status != DC_STATUS_SUCCESS) { - ERROR (abstract->context, "Failed to read the hardware type."); + if (status != DC_STATUS_SUCCESS) return status; - } if (model == TERIC) { return shearwater_common_timesync_utc (device, datetime); diff --git a/src/shearwater_predator_parser.c b/src/shearwater_predator_parser.c index 03e56eeb..10b2f13a 100644 --- a/src/shearwater_predator_parser.c +++ b/src/shearwater_predator_parser.c @@ -117,10 +117,14 @@ #define SENSOR_CALIBRATION_DEFAULT 2100 -#define UNDEFINED 0xFFFFFFFF +#define GNSS_NOSAT 0 +#define GNSS_NOFIX 1 +#define GNSS_FIX_2D 2 +#define GNSS_FIX_3D 3 +#define GNSS_UNKNOWN 0xFF +#define GNSS_DISABLED 0x10 -#define GNSS_FIX_2D 2 -#define GNSS_FIX_3D 3 +#define UNDEFINED 0xFFFFFFFF typedef struct shearwater_predator_parser_t shearwater_predator_parser_t; @@ -159,6 +163,7 @@ struct shearwater_predator_parser_t { unsigned int opening[NRECORDS]; unsigned int closing[NRECORDS]; unsigned int final; + unsigned int nsamples; unsigned int ngasmixes; unsigned int ntanks; shearwater_predator_gasmix_t gasmix[NGASMIXES]; @@ -541,6 +546,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) } } + unsigned int nsamples = 0; unsigned int offset = headersize; unsigned int length = size - footersize; unsigned int sub_mode = SM_OC_REC; @@ -558,6 +564,9 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) if (type == LOG_RECORD_DIVE_SAMPLE || type == LOG_RECORD_AVELO_SAMPLE) { + // Number of samples. + nsamples++; + // Status flags. unsigned int status = 0; unsigned int ccr = 0; @@ -895,6 +904,7 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser) parser->tankidx[i] = UNDEFINED; } } + parser->nsamples = nsamples; parser->aimode = aimode; parser->hpccr = hpccr; parser->divemode = divemode; @@ -1002,7 +1012,6 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ unsigned int decomodel_idx = parser->pnf ? parser->opening[2] + 18 : 67; unsigned int gf_idx = parser->pnf ? parser->opening[0] + 4 : 4; - int latitude = 0, longitude = 0; dc_gasmix_t *gasmix = (dc_gasmix_t *) value; dc_tank_t *tank = (dc_tank_t *) value; @@ -1108,15 +1117,17 @@ shearwater_predator_parser_get_field (dc_parser_t *abstract, dc_field_type_t typ if (parser->opening[9] == UNDEFINED || parser->aimode != AI_ON_GPS) return DC_STATUS_UNSUPPORTED; - unsigned int gnss_status = data[parser->opening[9] + 16]; - if (!(gnss_status == GNSS_FIX_2D || gnss_status == GNSS_FIX_3D)) - return DC_STATUS_UNSUPPORTED; + { + unsigned int gnss_status = data[parser->opening[9] + 16]; + if (!(gnss_status == GNSS_FIX_2D || gnss_status == GNSS_FIX_3D)) + return DC_STATUS_UNSUPPORTED; - latitude = (signed int) array_uint32_be (data + parser->opening[9] + 21); - longitude = (signed int) array_uint32_be (data + parser->opening[9] + 25); - location->latitude = latitude / 100000.0; - location->longitude = longitude / 100000.0; - location->altitude = 0.0; + signed int latitude = (signed int) array_uint32_be (data + parser->opening[9] + 21); + signed int longitude = (signed int) array_uint32_be (data + parser->opening[9] + 25); + location->latitude = latitude / 100000.0; + location->longitude = longitude / 100000.0; + location->altitude = 0.0; + } break; case DC_FIELD_STRING: return dc_field_get_string(&parser->cache, flags, string); @@ -1152,6 +1163,7 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal interval = array_uint16_be (data + parser->opening[5] + 23); } + unsigned int nsamples = 0; unsigned int pnf = parser->pnf; unsigned int offset = parser->headersize; unsigned int length = size - parser->footersize; @@ -1169,6 +1181,9 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal if (type == LOG_RECORD_DIVE_SAMPLE || type == LOG_RECORD_AVELO_SAMPLE) { + // Number of samples. + nsamples++; + // Time (seconds). time += interval; sample.time = time; @@ -1358,6 +1373,21 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal if (callback) callback (DC_SAMPLE_RBT, &sample, userdata); } } + + if (nsamples == 1 || nsamples == parser->nsamples) { + unsigned int record = nsamples == 1 ? parser->opening[9] : parser->closing[9]; + if (record != UNDEFINED && parser->logversion >= 17) { + unsigned int gnss = data[record + 16]; + int latitude = (signed int) array_uint32_be (data + record + 21); + int longitude = (signed int) array_uint32_be (data + record + 25); + if (gnss == GNSS_FIX_2D || gnss == GNSS_FIX_3D) { + sample.location.latitude = latitude / 100000.0; + sample.location.longitude = longitude / 100000.0; + sample.location.altitude = 0.0; + if (callback) callback (DC_SAMPLE_LOCATION, &sample, userdata); + } + } + } } else if (type == LOG_RECORD_DIVE_SAMPLE_EXT) { // Tank pressure if (parser->logversion >= 13) {