src/suunto_eonsteel.c | 124 ++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 104 insertions(+), 20 deletions(-) diff --git a/src/suunto_eonsteel.c b/src/suunto_eonsteel.c index c381668..4b49751 100644 --- a/src/suunto_eonsteel.c +++ b/src/suunto_eonsteel.c @@ -23,6 +23,8 @@ #include #include #include /* For crc32() */ +#include +#include #include "suunto_eonsteel.h" #include "context-private.h" @@ -54,20 +56,25 @@ struct directory_entry { }; // EON Steel command numbers and other magic field values -#define INIT_CMD 0x00 -#define INIT_MAGIC 0x0001 -#define INIT_SEQ 0 +#define CMD_INIT 0x0000 +#define INIT_MAGIC 0x0001 +#define INIT_SEQ 0 -#define READ_STRING_CMD 0x0411 +#define CMD_READ_STRING 0x0411 -#define FILE_LOOKUP_CMD 0x0010 -#define FILE_READ_CMD 0x0110 -#define FILE_STAT_CMD 0x0710 -#define FILE_CLOSE_CMD 0x0510 +#define CMD_FILE_OPEN 0x0010 +#define CMD_FILE_READ 0x0110 +#define CMD_FILE_STAT 0x0710 +#define CMD_FILE_CLOSE 0x0510 -#define DIR_LOOKUP_CMD 0x0810 -#define READDIR_CMD 0x0910 -#define DIR_CLOSE_CMD 0x0a10 +#define CMD_DIR_OPEN 0x0810 +#define CMD_DIR_READDIR 0x0910 +#define CMD_DIR_CLOSE 0x0a10 + +#define CMD_SET_TIME 0x0003 +#define CMD_GET_TIME 0x0103 +#define CMD_SET_DATE 0x0203 +#define CMD_GET_DATE 0x0303 static dc_status_t suunto_eonsteel_device_set_fingerprint (dc_device_t *abstract, const unsigned char data[], unsigned int size); static dc_status_t suunto_eonsteel_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata); @@ -527,7 +534,7 @@ static int read_file(suunto_eonsteel_device_t *eon, const char *filename, dc_buf return -1; } memcpy(cmdbuf+4, filename, len); - rc = send_receive(eon, FILE_LOOKUP_CMD, + rc = send_receive(eon, CMD_FILE_OPEN, len+4, cmdbuf, sizeof(result), result); if (rc < 0) { @@ -536,7 +543,7 @@ static int read_file(suunto_eonsteel_device_t *eon, const char *filename, dc_buf } HEXDUMP (eon->base.context, DC_LOGLEVEL_DEBUG, "lookup", result, rc); - rc = send_receive(eon, FILE_STAT_CMD, + rc = send_receive(eon, CMD_FILE_STAT, 0, NULL, sizeof(result), result); if (rc < 0) { @@ -556,7 +563,7 @@ static int read_file(suunto_eonsteel_device_t *eon, const char *filename, dc_buf ask = 1024; put_le32(1234, cmdbuf+0); // Not file offset, after all put_le32(ask, cmdbuf+4); // Size of read - rc = send_receive(eon, FILE_READ_CMD, + rc = send_receive(eon, CMD_FILE_READ, 8, cmdbuf, sizeof(result), result); if (rc < 0) { @@ -591,11 +598,11 @@ static int read_file(suunto_eonsteel_device_t *eon, const char *filename, dc_buf size -= got; } - rc = send_receive(eon, FILE_CLOSE_CMD, + rc = send_receive(eon, CMD_FILE_CLOSE, 0, NULL, sizeof(result), result); if (rc < 0) { - ERROR(eon->base.context, "cmd FILE_CLOSE_CMD failed"); + ERROR(eon->base.context, "cmd CMD_FILE_CLOSE failed"); return -1; } HEXDUMP(eon->base.context, DC_LOGLEVEL_DEBUG, "close", result, rc); @@ -646,7 +653,7 @@ static int get_file_list(suunto_eonsteel_device_t *eon, struct directory_entry * put_le32(0, cmd); memcpy(cmd + 4, dive_directory, sizeof(dive_directory)); cmdlen = 4 + sizeof(dive_directory); - rc = send_receive(eon, DIR_LOOKUP_CMD, + rc = send_receive(eon, CMD_DIR_OPEN, cmdlen, cmd, sizeof(result), result); if (rc < 0) { @@ -657,7 +664,7 @@ static int get_file_list(suunto_eonsteel_device_t *eon, struct directory_entry * for (;;) { unsigned int nr, last; - rc = send_receive(eon, READDIR_CMD, + rc = send_receive(eon, CMD_DIR_READDIR, 0, NULL, sizeof(result), result); if (rc < 0) { @@ -677,7 +684,7 @@ static int get_file_list(suunto_eonsteel_device_t *eon, struct directory_entry * break; } - rc = send_receive(eon, DIR_CLOSE_CMD, + rc = send_receive(eon, CMD_DIR_CLOSE, 0, NULL, sizeof(result), result); if (rc < 0) { @@ -693,7 +700,7 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon) const unsigned char init[] = {0x02, 0x00, 0x2a, 0x00}; struct eon_hdr hdr; - if (send_cmd(eon, INIT_CMD, sizeof(init), init)) { + if (send_cmd(eon, CMD_INIT, sizeof(init), init)) { ERROR(eon->base.context, "Failed to send initialization command"); return -1; } @@ -709,6 +716,81 @@ static int initialize_eonsteel(suunto_eonsteel_device_t *eon) return 0; } +/* + * We should have some way to say whether we want to + * synchronize time or not.. + */ +static void verify_date_time(suunto_eonsteel_device_t *eon) +{ + unsigned char result[64], cmd[64]; + int year, month, day; + int hour, min, sec, msec; + struct timeval tv; + struct tm *tm; + int rc; + + rc = send_receive(eon, CMD_GET_DATE, + 0, NULL, + sizeof(result), result); + if (rc < 4) + return; + + year = array_uint16_le(result); + month = result[2]; + day = result[3]; + INFO(eon->base.context, "GET_DATE: %d/%d/%d", year, month, day); + + rc = send_receive(eon, CMD_GET_TIME, + 0, NULL, + sizeof(result), result); + if (rc < 8) + return; + + year = array_uint16_le(result); + month = result[2]; + day = result[3]; + hour = result[4]; + min = result[5]; + msec = array_uint16_le(result+6); + sec = msec / 1000; + msec %= 1000; + + INFO(eon->base.context, "GET_TIME: %d/%d/%d %d:%02d:%02d.%03d", + year, month, day, hour, min, sec, msec); + + /* Make this conditional somehow */ + if (gettimeofday(&tv, NULL)) + return; + tm = localtime(&tv.tv_sec); + year = tm->tm_year + 1900; + month = tm->tm_mon + 1; + day = tm->tm_mday; + hour = tm->tm_hour; + min = tm->tm_min; + sec = tm->tm_sec; + msec = tv.tv_usec / 1000; + + INFO(eon->base.context, "SET_TIME: %d/%d/%d %d:%02d:%02d.%03d", + year, month, day, hour, min, sec, msec); + + msec += sec * 1000; + + cmd[0] = year & 255; + cmd[1] = year >> 8; + cmd[2] = month; + cmd[3] = day; + cmd[4] = hour; + cmd[5] = min; + cmd[6] = msec & 255; + cmd[7] = msec >> 8; + + rc = send_receive(eon, CMD_SET_TIME, + 8, cmd, + sizeof(result), result); + if (rc < 0) + INFO(eon->base.context, "SET_TIME failed"); +} + dc_status_t suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char *name) { @@ -745,6 +827,8 @@ suunto_eonsteel_device_open(dc_device_t **out, dc_context_t *context, const char goto error_close; } + verify_date_time(eon); + *out = (dc_device_t *) eon; return DC_STATUS_SUCCESS;