diff --git a/src/shearwater_common.c b/src/shearwater_common.c index 1e2a65b..ca3f237 100644 --- a/src/shearwater_common.c +++ b/src/shearwater_common.c @@ -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) { diff --git a/src/shearwater_common.h b/src/shearwater_common.h index 1c25b75..4c7f186 100644 --- a/src/shearwater_common.h +++ b/src/shearwater_common.h @@ -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); diff --git a/src/shearwater_petrel.c b/src/shearwater_petrel.c index 0d91c03..7ec18ff 100644 --- a/src/shearwater_petrel.c +++ b/src/shearwater_petrel.c @@ -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); + } +} diff --git a/src/shearwater_predator.c b/src/shearwater_predator.c index d4c97b4..fffd511 100644 --- a/src/shearwater_predator.c +++ b/src/shearwater_predator.c @@ -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); +}