diff --git a/src/oceans_s1.c b/src/oceans_s1.c index 3cd7496..7e126a2 100644 --- a/src/oceans_s1.c +++ b/src/oceans_s1.c @@ -167,7 +167,7 @@ static dc_status_t oceans_s1_get_sequence(oceans_s1_device_t *s1, unsigned char return DC_STATUS_SUCCESS; } -static dc_status_t oceans_s1_get_blob(oceans_s1_device_t *s1, unsigned char **result) +static dc_status_t oceans_s1_get_blob(oceans_s1_device_t *s1, const unsigned char **result) { dc_status_t status; dc_buffer_t *res; @@ -441,7 +441,7 @@ oceans_s1_device_set_fingerprint(dc_device_t *abstract, const unsigned char data } static dc_status_t -get_dive_list(oceans_s1_device_t *s1, unsigned char **list) +get_dive_list(oceans_s1_device_t *s1, const unsigned char **list) { dc_status_t status; @@ -457,7 +457,7 @@ get_dive_list(oceans_s1_device_t *s1, unsigned char **list) } static dc_status_t -get_one_dive(oceans_s1_device_t *s1, int nr, unsigned char **dive) +get_one_dive(oceans_s1_device_t *s1, int nr, const unsigned char **dive) { dc_status_t status; @@ -472,10 +472,52 @@ get_one_dive(oceans_s1_device_t *s1, int nr, unsigned char **dive) return oceans_s1_get_blob(s1, dive); } +static const unsigned char *get_string_line(const unsigned char *in, const unsigned char **next) +{ + const unsigned char *line; + unsigned char c; + + if (!in) { + *next = NULL; + return NULL; + } + + while (isspace(*in)) + in++; + + if (!*in) { + *next = NULL; + return NULL; + } + + line = in; + while ((c = *in) != 0) { + if (c == '\r' || c == '\n') + break; + in++; + } + *next = in; + return line; +} + +static int count_dives(const unsigned char *divelist) +{ + int dives = 0; + const unsigned char *line; + + while ((line = get_string_line(divelist, &divelist)) != NULL) { + if (strncmp(line, "dive ", 5)) + continue; + dives++; + } + return dives; +} + static dc_status_t oceans_s1_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, void *userdata) { - unsigned char *divelist, *dive; + int nr; + const unsigned char *divelist, *line; dc_status_t status = DC_STATUS_SUCCESS; oceans_s1_device_t *s1 = (oceans_s1_device_t*)abstract; @@ -485,19 +527,60 @@ oceans_s1_device_foreach(dc_device_t *abstract, dc_dive_callback_t callback, voi status = get_dive_list(s1, &divelist); if (status != DC_STATUS_SUCCESS) return status; - fprintf(stderr, "divelist = %s\n", divelist); + + nr = count_dives(divelist); + if (!nr) + return DC_STATUS_SUCCESS; progress.current = 0; - progress.maximum = 100; + progress.maximum = nr; device_event_emit(abstract, DC_EVENT_PROGRESS, &progress); - // Just force dive 4 for now - status = get_one_dive(s1, 4, &dive); - if (status != DC_STATUS_SUCCESS) - return status; - fprintf(stderr, "dive 4 = %s\n", dive); + int dive_nr = 0, dive_unknown = 0, dive_o2 = 0; + int dive_depth, dive_time; + long long dive_date = -1; + char fingerprint[32]; - // Fill in + while ((line = get_string_line(divelist, &divelist)) != NULL) { + int linelen = divelist - line; + const unsigned char *dive; + + /* We only care about 'dive' and 'enddive' lines */ + if (linelen < 8 || linelen >= 32) + continue; + + if (!memcmp(line, "dive ", 5)) { + int nr, unknown, o2; + long long date; + + if (sscanf(line, "dive %d,%d,%d,%lld", &nr, &unknown, &o2, &date) != 4) + continue; + dive_nr = nr; + dive_unknown = unknown; + dive_o2 = o2; + dive_date = date; + + memset(fingerprint, 0, sizeof(fingerprint)); + memcpy(fingerprint, line, linelen); + continue; + } + + if (memcmp(line, "enddive ", 8)) + continue; + + if (sscanf(line, "enddive %d,%d", &dive_depth, &dive_time) != 2) + continue; + + status = get_one_dive(s1, dive_nr, &dive); + if (status != DC_STATUS_SUCCESS) + return status; + + progress.current++; + device_event_emit(abstract, DC_EVENT_PROGRESS, &progress); + + if (callback && !callback(dive, strlen(dive), fingerprint, sizeof(fingerprint), userdata)) + break; + } return status; } diff --git a/src/oceans_s1_parser.c b/src/oceans_s1_parser.c index f545c15..dd30f06 100644 --- a/src/oceans_s1_parser.c +++ b/src/oceans_s1_parser.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include "oceans_s1.h" #include "context-private.h" @@ -16,6 +18,9 @@ typedef struct oceans_s1_parser_t oceans_s1_parser_t; struct oceans_s1_parser_t { dc_parser_t base; + int divenr; + unsigned int maxdepth, duration; + long long date; struct dc_field_cache cache; }; @@ -37,7 +42,7 @@ static const dc_parser_vtable_t oceans_s1_parser_vtable = { dc_status_t oceans_s1_parser_create(dc_parser_t **out, dc_context_t *context) { - oceans_s1_parser_t* parser = NULL; + oceans_s1_parser_t *parser = NULL; if (out == NULL) return DC_STATUS_INVALIDARGS; @@ -54,23 +59,139 @@ oceans_s1_parser_create(dc_parser_t **out, dc_context_t *context) return DC_STATUS_SUCCESS; } +static const unsigned char *get_string_line(const unsigned char *in, const unsigned char **next) +{ + const unsigned char *line; + unsigned char c; + + if (!in) { + *next = NULL; + return NULL; + } + + while (isspace(*in)) + in++; + + if (!*in) { + *next = NULL; + return NULL; + } + + line = in; + while ((c = *in) != 0) { + if (c == '\r' || c == '\n') + break; + in++; + } + *next = in; + return line; +} + +static dc_status_t +oceans_s1_parse_dive(struct oceans_s1_parser_t *s1, const unsigned char *data, dc_sample_callback_t callback, void *userdata) +{ + const unsigned char *line; + unsigned int sample_interval = 10; + unsigned int sample_time = 0; + + memset(&s1->cache, 0, sizeof(s1->cache)); + + while ((line = get_string_line(data, &data)) != NULL) { + dc_sample_value_t sample = {0}; + int depth = 0, temp = 0, flags = 0; + + if (!strncmp(line, "divelog ", 8)) { + sscanf(line, "divelog v1,%us/sample", &sample_interval); + continue; + } + if (!strncmp(line, "dive ", 5)) { + int nr, unknown, o2; + long long date; + + sscanf(line, "dive %d,%d,%d,%lld", &nr, &unknown, &o2, &date); + s1->divenr = nr; + s1->date = date; + // I think "unknown" is dive mode + if (o2) { + dc_gasmix_t mix = { 0 }; + mix.oxygen = o2 / 100.0; + DC_ASSIGN_FIELD(s1->cache, GASMIX_COUNT, 1); + DC_ASSIGN_IDX(s1->cache, GASMIX, 0, mix); + } + continue; + } + if (!strncmp(line, "continue ", 9)) { + int depth = 0, seconds = 0; + sscanf(line, "continue %d,%d", &depth, &seconds); + + // Create surface samples for the surface time, + // and then a depth sample at the stated depth + if (callback) { + if (seconds >= sample_interval*2) { + dc_sample_value_t sample = {0}; + sample.time = sample_time + sample_interval; + callback(DC_SAMPLE_TIME, sample, userdata); + sample.depth = 0; + callback(DC_SAMPLE_DEPTH, sample, userdata); + + sample.time = sample_time + seconds - sample_interval; + callback(DC_SAMPLE_TIME, sample, userdata); + sample.depth = 0; + callback(DC_SAMPLE_DEPTH, sample, userdata); + } + sample.time = sample_time + seconds; + callback(DC_SAMPLE_TIME, sample, userdata); + sample.depth = depth / 100.0; + callback(DC_SAMPLE_DEPTH, sample, userdata); + } + sample_time += seconds; + continue; + } + if (!strncmp(line, "enddive ", 8)) { + int maxdepth = 0, duration = 0; + sscanf(line, "enddive %d,%d", &maxdepth, &duration); + DC_ASSIGN_FIELD(s1->cache, MAXDEPTH, maxdepth / 100.0); + DC_ASSIGN_FIELD(s1->cache, DIVETIME, duration); + s1->maxdepth = maxdepth; + s1->duration = duration; + continue; + } + if (sscanf(line, "%d,%d,%d", &depth, &temp, &flags) != 3) + continue; + + sample_time += sample_interval; + if (callback) { + dc_sample_value_t sample = {0}; + sample.time = sample_time; + callback(DC_SAMPLE_TIME, sample, userdata); + sample.depth = depth / 100.0; + callback(DC_SAMPLE_DEPTH, sample, userdata); + sample.temperature = temp; + callback (DC_SAMPLE_TEMPERATURE, sample, userdata); + } + } + return DC_STATUS_SUCCESS; +} + static dc_status_t oceans_s1_parser_set_data(dc_parser_t *abstract, const unsigned char *data, unsigned int size) { - dc_status_t status = DC_STATUS_SUCCESS; - // Fill me - return DC_STATUS_SUCCESS; + struct oceans_s1_parser_t *s1 = (struct oceans_s1_parser_t *)abstract; + + return oceans_s1_parse_dive(s1, data, NULL, NULL); } static dc_status_t -oceans_s1_parser_get_datetime(dc_parser_t* abstract, dc_datetime_t* datetime) +oceans_s1_parser_get_datetime(dc_parser_t *abstract, dc_datetime_t *datetime) { - // Fill me + oceans_s1_parser_t *s1 = (oceans_s1_parser_t *)abstract; + + dc_datetime_gmtime(datetime, s1->date); return DC_STATUS_SUCCESS; } static dc_status_t -oceans_s1_parser_get_field(dc_parser_t* abstract, dc_field_type_t type, unsigned int flags, void* value) +oceans_s1_parser_get_field(dc_parser_t *abstract, dc_field_type_t type, unsigned int flags, void *value) { oceans_s1_parser_t *s1 = (oceans_s1_parser_t *)abstract; @@ -78,8 +199,9 @@ oceans_s1_parser_get_field(dc_parser_t* abstract, dc_field_type_t type, unsigned } static dc_status_t -oceans_s1_parser_samples_foreach(dc_parser_t* abstract, dc_sample_callback_t callback, void* userdata) +oceans_s1_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback_t callback, void *userdata) { - // Fill me - return DC_STATUS_SUCCESS; + struct oceans_s1_parser_t *s1 = (struct oceans_s1_parser_t *)abstract; + + return oceans_s1_parse_dive(s1, s1->base.data, callback, userdata); }