Add support for time synchronization

Add time synchronisation for the Shearwater dive computers. All models
support setting the local time. Only the Teric has basic support for
time zones, and can set UTC time with a timezone offset.

Co-authored-by: Michael Keller <github@ike.ch>
This commit is contained in:
Jef Driesen 2023-06-22 21:23:28 +02:00
parent c16530b8ab
commit 25bd1f9853
4 changed files with 131 additions and 2 deletions

View File

@ -599,6 +599,91 @@ shearwater_common_wdbi (shearwater_common_device_t *device, unsigned int id, con
return status;
}
dc_status_t
shearwater_common_timesync_local (shearwater_common_device_t *device, const dc_datetime_t *datetime)
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
// Convert to local time.
dc_datetime_t local = *datetime;
local.timezone = DC_TIMEZONE_NONE;
dc_ticks_t ticks = dc_datetime_mktime (&local);
if (ticks == -1) {
ERROR (abstract->context, "Invalid date/time value specified.");
return DC_STATUS_INVALIDARGS;
}
const unsigned char timestamp[] = {
(ticks >> 24) & 0xFF,
(ticks >> 16) & 0xFF,
(ticks >> 8) & 0xFF,
(ticks ) & 0xFF,
};
status = shearwater_common_wdbi (device, ID_TIME_LOCAL, timestamp, sizeof(timestamp));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to write the dive computer local time.");
return status;
}
return status;
}
dc_status_t
shearwater_common_timesync_utc (shearwater_common_device_t *device, const dc_datetime_t *datetime)
{
dc_status_t status = DC_STATUS_SUCCESS;
dc_device_t *abstract = (dc_device_t *) device;
// Convert to UTC time.
dc_ticks_t ticks = dc_datetime_mktime (datetime);
if (ticks == -1) {
ERROR (abstract->context, "Invalid date/time value specified.");
return DC_STATUS_INVALIDARGS;
}
const unsigned char timestamp[] = {
(ticks >> 24) & 0xFF,
(ticks >> 16) & 0xFF,
(ticks >> 8) & 0xFF,
(ticks ) & 0xFF,
};
status = shearwater_common_wdbi (device, ID_TIME_UTC, timestamp, sizeof(timestamp));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to write the dive computer UTC time.");
return status;
}
int timezone = datetime->timezone / 60;
const unsigned char offset[] = {
(timezone >> 24) & 0xFF,
(timezone >> 16) & 0xFF,
(timezone >> 8) & 0xFF,
(timezone ) & 0xFF,
};
status = shearwater_common_wdbi (device, ID_TIME_OFFSET, offset, sizeof (offset));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to write the dive computer timezone offset.");
return status;
}
// We don't have a way to determine the daylight savings time setting,
// but the required offset is already factored into the timezone offset.
const unsigned char dst[] = {0, 0, 0, 0};
status = shearwater_common_wdbi (device, ID_TIME_DST, dst, sizeof (dst));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to write the dive computer DST setting.");
return status;
}
return status;
}
unsigned int
shearwater_common_get_model (shearwater_common_device_t *device, unsigned int hardware)
{

View File

@ -35,6 +35,11 @@ extern "C" {
#define ID_LOGUPLOAD 0x8021
#define ID_HARDWARE 0x8050
#define ID_TIME_LOCAL 0x9030
#define ID_TIME_UTC 0x9031
#define ID_TIME_OFFSET 0x9032
#define ID_TIME_DST 0x9033
#define PREDATOR 2
#define PETREL 3
#define PETREL2 PETREL
@ -70,6 +75,12 @@ shearwater_common_rdbi (shearwater_common_device_t *device, unsigned int id, uns
dc_status_t
shearwater_common_wdbi (shearwater_common_device_t *device, unsigned int id, const unsigned char data[], unsigned int size);
dc_status_t
shearwater_common_timesync_local (shearwater_common_device_t *device, const dc_datetime_t *datetime);
dc_status_t
shearwater_common_timesync_utc (shearwater_common_device_t *device, const dc_datetime_t *datetime);
unsigned int
shearwater_common_get_model (shearwater_common_device_t *device, unsigned int hardware);

View File

@ -46,6 +46,7 @@ typedef struct shearwater_petrel_device_t {
static dc_status_t shearwater_petrel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
static dc_status_t shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
static dc_status_t shearwater_petrel_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
static dc_status_t shearwater_petrel_device_close (dc_device_t *abstract);
static const dc_device_vtable_t shearwater_petrel_device_vtable = {
@ -56,7 +57,7 @@ static const dc_device_vtable_t shearwater_petrel_device_vtable = {
NULL, /* write */
NULL, /* dump */
shearwater_petrel_device_foreach, /* foreach */
NULL, /* timesync */
shearwater_petrel_device_timesync,
shearwater_petrel_device_close /* close */
};
@ -350,3 +351,28 @@ shearwater_petrel_device_foreach (dc_device_t *abstract, dc_dive_callback_t call
return rc;
}
static dc_status_t
shearwater_petrel_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
{
dc_status_t status = DC_STATUS_SUCCESS;
shearwater_common_device_t *device = (shearwater_common_device_t *) abstract;
// Read the hardware type.
unsigned char rsp_hardware[2] = {0};
status = shearwater_common_rdbi (device, ID_HARDWARE, rsp_hardware, sizeof(rsp_hardware));
if (status != DC_STATUS_SUCCESS) {
ERROR (abstract->context, "Failed to read the hardware type.");
return status;
}
// Convert and map to the model number.
unsigned int hardware = array_uint16_be (rsp_hardware);
unsigned int model = shearwater_common_get_model (device, hardware);
if (model == TERIC) {
return shearwater_common_timesync_utc (device, datetime);
} else {
return shearwater_common_timesync_local (device, datetime);
}
}

View File

@ -44,6 +44,7 @@ typedef struct shearwater_predator_device_t {
static dc_status_t shearwater_predator_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size);
static dc_status_t shearwater_predator_device_dump (dc_device_t *abstract, dc_buffer_t *buffer);
static dc_status_t shearwater_predator_device_foreach (dc_device_t *abstract, dc_dive_callback_t callback, void *userdata);
static dc_status_t shearwater_predator_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime);
static const dc_device_vtable_t shearwater_predator_device_vtable = {
sizeof(shearwater_predator_device_t),
@ -53,7 +54,7 @@ static const dc_device_vtable_t shearwater_predator_device_vtable = {
NULL, /* write */
shearwater_predator_device_dump, /* dump */
shearwater_predator_device_foreach, /* foreach */
NULL, /* timesync */
shearwater_predator_device_timesync,
NULL /* close */
};
@ -357,3 +358,9 @@ shearwater_predator_extract_dives (dc_device_t *abstract, const unsigned char da
return shearwater_predator_extract_predator (abstract, data, size, callback, userdata);
}
}
static dc_status_t
shearwater_predator_device_timesync (dc_device_t *abstract, const dc_datetime_t *datetime)
{
return shearwater_common_timesync_local ((shearwater_common_device_t *) abstract, datetime);
}