From efe7e52bbe5e1b68940aa130e9af9079cc3d4075 Mon Sep 17 00:00:00 2001 From: Jef Driesen Date: Thu, 9 Jul 2015 20:13:25 +0200 Subject: [PATCH] Add support for parsing the event bytes. Right now only gas switch and bookmark events are supported, because none of the other uwatec events can easily be mapped onto the existing libdivecomputer events. But the basic infrastructure for supporting more events is in place now. --- src/uwatec_smart_parser.c | 136 +++++++++++++++++++++++++++++++++++--- 1 file changed, 128 insertions(+), 8 deletions(-) diff --git a/src/uwatec_smart_parser.c b/src/uwatec_smart_parser.c index 622a4f7..d9e18de 100644 --- a/src/uwatec_smart_parser.c +++ b/src/uwatec_smart_parser.c @@ -49,6 +49,7 @@ #define UNSUPPORTED 0xFFFFFFFF +#define NEVENTS 3 #define NGASMIXES 10 #define HEADER 1 @@ -71,6 +72,16 @@ typedef enum { UNKNOWN2, } uwatec_smart_sample_t; +typedef enum { + EV_WARNING, /* Warning (yellow buzzer) */ + EV_ALARM, /* Alarm (red buzzer) */ + EV_WORKLOAD, /* Workload */ + EV_WORKLOAD_WARNING, /* Increased workload (lung symbol) */ + EV_BOOKMARK, /* Bookmark / safety stop timer started */ + EV_GASMIX, /* Active gasmix */ + EV_UNKNOWN, +} uwatec_smart_event_t; + typedef struct uwatec_smart_header_info_t { unsigned int maxdepth; unsigned int divetime; @@ -93,6 +104,12 @@ typedef struct uwatec_smart_sample_info_t { unsigned int extrabytes; } uwatec_smart_sample_info_t; +typedef struct uwatec_smart_event_info_t { + uwatec_smart_event_t type; + unsigned int mask; + unsigned int shift; +} uwatec_smart_event_info_t; + typedef struct uwatec_smart_gasmix_t { unsigned int id; unsigned int oxygen; @@ -117,6 +134,8 @@ struct uwatec_smart_parser_t { const uwatec_smart_header_info_t *header; unsigned int headersize; unsigned int nsamples; + const uwatec_smart_event_info_t *events[NEVENTS]; + unsigned int nevents[NEVENTS]; // Cached fields. unsigned int cached; unsigned int trimix; @@ -303,6 +322,57 @@ uwatec_smart_sample_info_t uwatec_smart_tec_samples[] = { {RBT, 1, 0, 14, 1, 1}, // 11111111 111110dd dddddddd }; +static const +uwatec_smart_event_info_t uwatec_smart_tec_events_0[] = { + {EV_WARNING, 0x01, 0}, + {EV_ALARM, 0x02, 1}, + {EV_WORKLOAD_WARNING, 0x04, 2}, + {EV_WORKLOAD, 0x38, 3}, + {EV_UNKNOWN, 0xC0, 6}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_aladintec_events_0[] = { + {EV_WARNING, 0x01, 0}, + {EV_ALARM, 0x02, 1}, + {EV_BOOKMARK, 0x04, 2}, + {EV_UNKNOWN, 0x08, 3}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_aladintec2g_events_0[] = { + {EV_WARNING, 0x01, 0}, + {EV_ALARM, 0x02, 1}, + {EV_BOOKMARK, 0x04, 2}, + {EV_UNKNOWN, 0x08, 3}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_aladintec2g_events_1[] = { + {EV_UNKNOWN, 0x07, 0}, + {EV_GASMIX, 0x18, 3}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_galileo_events_0[] = { + {EV_WARNING, 0x01, 0}, + {EV_ALARM, 0x02, 1}, + {EV_WORKLOAD_WARNING, 0x04, 2}, + {EV_BOOKMARK, 0x08, 3}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_galileo_events_1[] = { + {EV_WORKLOAD, 0x07, 0}, + {EV_UNKNOWN, 0x18, 3}, + {EV_GASMIX, 0x60, 5}, + {EV_UNKNOWN, 0x80, 7}, +}; + +static const +uwatec_smart_event_info_t uwatec_smart_galileo_events_2[] = { + {EV_UNKNOWN, 0xFF, 0}, +}; static unsigned int uwatec_smart_find_gasmix (uwatec_smart_parser_t *parser, unsigned int id) @@ -444,12 +514,18 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->model = model; parser->devtime = devtime; parser->systime = systime; + for (unsigned int i = 0; i < NEVENTS; ++i) { + parser->events[i] = NULL; + parser->nevents[i] = 0; + } switch (model) { case SMARTPRO: parser->headersize = 92; parser->header = &uwatec_smart_pro_header; parser->samples = uwatec_smart_pro_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_pro_samples); + parser->events[0] = uwatec_smart_tec_events_0; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_tec_events_0); break; case GALILEO: case GALILEOTRIMIX: @@ -460,24 +536,38 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->header = &uwatec_smart_galileo_header; parser->samples = uwatec_smart_galileo_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_galileo_samples); + parser->events[0] = uwatec_smart_galileo_events_0; + parser->events[1] = uwatec_smart_galileo_events_1; + parser->events[2] = uwatec_smart_galileo_events_2; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_galileo_events_0); + parser->nevents[1] = C_ARRAY_SIZE (uwatec_smart_galileo_events_1); + parser->nevents[2] = C_ARRAY_SIZE (uwatec_smart_galileo_events_2); break; case ALADINTEC: parser->headersize = 108; parser->header = &uwatec_smart_aladin_tec_header; parser->samples = uwatec_smart_aladin_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_aladin_samples); + parser->events[0] = uwatec_smart_aladintec_events_0; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_aladintec_events_0); break; case ALADINTEC2G: parser->headersize = 116; parser->header = &uwatec_smart_aladin_tec2g_header; parser->samples = uwatec_smart_aladin_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_aladin_samples); + parser->events[0] = uwatec_smart_aladintec2g_events_0; + parser->events[1] = uwatec_smart_aladintec2g_events_1; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_aladintec2g_events_0); + parser->nevents[1] = C_ARRAY_SIZE (uwatec_smart_aladintec2g_events_1); break; case SMARTCOM: parser->headersize = 100; parser->header = &uwatec_smart_com_header; parser->samples = uwatec_smart_com_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_com_samples); + parser->events[0] = uwatec_smart_tec_events_0; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_tec_events_0); break; case SMARTTEC: case SMARTZ: @@ -485,6 +575,8 @@ uwatec_smart_parser_create (dc_parser_t **out, dc_context_t *context, unsigned i parser->header = &uwatec_smart_tec_header; parser->samples = uwatec_smart_tec_samples; parser->nsamples = C_ARRAY_SIZE (uwatec_smart_tec_samples); + parser->events[0] = uwatec_smart_tec_events_0; + parser->nevents[0] = C_ARRAY_SIZE (uwatec_smart_tec_events_0); break; default: free (parser); @@ -775,6 +867,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t unsigned int heartrate = 0; unsigned int bearing = 0; unsigned char alarms[3] = {0, 0, 0}; + unsigned int bookmark = 0; // Previous gas mix - initialize with impossible value unsigned int gasmix_previous = 0xFFFFFFFF; @@ -841,7 +934,10 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t signed int svalue = uwatec_smart_fixsignbit (value, nbits); // Parse the value. + unsigned int idx = 0; unsigned int subtype = 0; + unsigned int nevents = 0; + const uwatec_smart_event_info_t *events = NULL; switch (table[id].type) { case PRESSURE_DEPTH: pressure += ((signed char) ((svalue >> NBITS) & 0xFF)) / 4.0; @@ -907,11 +1003,27 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t case ALARMS: alarms[table[id].index] = value; have_alarms = 1; - if (table[id].index == 1) { - if (parser->model == ALADINTEC || parser->model == ALADINTEC2G) { - gasmix = (value & 0x18) >> 3; - } else { - gasmix = (value & 0x60) >> 5; + idx = table[id].index; + if (idx >= NEVENTS || parser->events[idx] == NULL) { + ERROR (abstract->context, "Unexpected event index."); + return DC_STATUS_DATAFORMAT; + } + + events = parser->events[idx]; + nevents = parser->nevents[idx]; + + for (unsigned int i = 0; i < nevents; ++i) { + uwatec_smart_event_t ev_type = events[i].type; + unsigned int ev_value = (value & events[i].mask) >> events[i].shift; + switch (ev_type) { + case EV_BOOKMARK: + bookmark = ev_value; + break; + case EV_GASMIX: + gasmix = ev_value; + break; + default: + break; } } break; @@ -945,7 +1057,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t unsigned int endpressure = array_uint16_le (data + offset + 7); if (o2 != 0 || he != 0) { - unsigned int idx = uwatec_smart_find_gasmix (parser, mixid); + idx = uwatec_smart_find_gasmix (parser, mixid); if (idx >= parser->ngasmixes) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of gas mixes reached."); @@ -960,7 +1072,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t } if (beginpressure != 0 || endpressure != 0) { - unsigned int idx = uwatec_smart_find_tank (parser, mixid); + idx = uwatec_smart_find_tank (parser, mixid); if (idx >= parser->ntanks) { if (idx >= NGASMIXES) { ERROR (abstract->context, "Maximum number of tanks reached."); @@ -987,7 +1099,7 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_TIME, sample, userdata); if (parser->ngasmixes && gasmix != gasmix_previous) { - unsigned int idx = uwatec_smart_find_gasmix (parser, gasmix); + idx = uwatec_smart_find_gasmix (parser, gasmix); if (idx >= parser->ngasmixes) { ERROR (abstract->context, "Invalid gas mix index."); return DC_STATUS_DATAFORMAT; @@ -1007,6 +1119,14 @@ uwatec_smart_parser_samples_foreach (dc_parser_t *abstract, dc_sample_callback_t if (callback) callback (DC_SAMPLE_TEMPERATURE, sample, userdata); } + if (bookmark) { + sample.event.type = SAMPLE_EVENT_BOOKMARK; + sample.event.time = 0; + sample.event.flags = 0; + sample.event.value = 0; + if (callback) callback (DC_SAMPLE_EVENT, sample, userdata); + } + if (have_alarms) { sample.vendor.type = SAMPLE_VENDOR_UWATEC_SMART; sample.vendor.size = nalarms;