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) {