From 7a7418421c1a3fc482dcf97d9533aa3dcb8d09a1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 2 Jan 2015 22:23:40 -0800 Subject: [PATCH 1/3] Add EON Steel gas change event parsing The really sad part is that the EON Steel handles gas change events correctly, by actually saying which cylinder it switches to. But the libdivecomputer interfaces are broken, and only contain the gas *mix* you switch to, which is ambiguous since you could have the same mix in multiple cylinders. Maybe we could put the one-based cylinder index into the "flags" field? With zero meaning "unknown". That would be a straightforward extension. Signed-off-by: Linus Torvalds --- src/suunto_eonsteel_parser.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index e5736a5..47fbc50 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -289,6 +289,25 @@ static void sample_cylinder_pressure(struct sample_data *info, unsigned char idx if (info->callback) info->callback(DC_SAMPLE_PRESSURE, sample, info->userdata); } +static void sample_gas_switch_event(struct sample_data *info, unsigned short idx) +{ + suunto_eonsteel_parser_t *eon = info->eon; + dc_sample_value_t sample = {0}; + int o2, he; + + if (idx < 1 || idx > eon->cache.ngases) + return; + + // Horrible, broken, gas change events + o2 = 100 * eon->cache.gasmix[idx-1].oxygen; + he = 100 * eon->cache.gasmix[idx-1].helium; + + sample.event.type = SAMPLE_EVENT_GASCHANGE2; + sample.event.value = o2 | (he << 16); + + if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +} + static int traverse_samples(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user) { struct sample_data *info = (struct sample_data *) user; @@ -309,6 +328,9 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c case 0x000a: // cylinder idx in first byte, pressure in next word sample_cylinder_pressure(info, data[0], array_uint16_le(data+1)); break; + case 0x001d: + sample_gas_switch_event(info, array_uint16_le(data)); + break; } return 0; } From 92371935fc50182ffa741db261807f8a865e9d52 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Jan 2015 15:23:35 -0800 Subject: [PATCH 2/3] Parse EON Steel notification and state changes The EON Steel notifications and states match the libdivecomputer ones very badly, but this tries to make sense of the ones that match. And puts the infrastructure in to do others in the future. Signed-off-by: Linus Torvalds --- src/suunto_eonsteel_parser.c | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 47fbc50..90df30a 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -226,6 +226,7 @@ struct sample_data { dc_sample_callback_t callback; void *userdata; unsigned int time; + unsigned char state_type, notify_type; }; static void sample_time(struct sample_data *info, unsigned short time_delta) @@ -308,6 +309,82 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); } +/* + * The EON Steel has two different sample events: "state" and "notification". + * Both end up having two fields: type and a boolean value. + * + * The type enumerations are available as part of the type descriptor, and we + * *should* probably parse them dynamically, but this hardcodes the different + * type values. + * + * For event states, the types are: + * + * 0=Wet Outside + * 1=Below Wet Activation Depth + * 2=Below Surface + * 3=Dive Active + * 4=Surface Calculation + * 5=Tank pressure available + */ +static void sample_event_state_type(struct sample_data *info, unsigned char type) +{ + info->state_type = type; +} + +static void sample_event_state_value(struct sample_data *info, unsigned char value) +{ + /* + * We could turn these into sample events, but they don't actually + * match any libdivecomputer events. + * + * unsigned int state = info->state_type; + * dc_sample_value_t sample = {0}; + * sample.event.type = ... + * sample.event.value = value; + * if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); + */ +} + +static void sample_event_notify_type(struct sample_data *info, unsigned char type) +{ + info->notify_type = type; +} + + +static void sample_event_notify_value(struct sample_data *info, unsigned char value) +{ + dc_sample_value_t sample = {0}; + static const enum parser_sample_event_t translate_notification[] = { + SAMPLE_EVENT_NONE, // 0=NoFly Time + SAMPLE_EVENT_NONE, // 1=Depth + SAMPLE_EVENT_NONE, // 2=Surface Time + SAMPLE_EVENT_TISSUELEVEL, // 3=Tissue Level + SAMPLE_EVENT_NONE, // 4=Deco + SAMPLE_EVENT_NONE, // 5=Deco Window + SAMPLE_EVENT_SAFETYSTOP_MANDATORY, // 6=Safety Stop Ahead + SAMPLE_EVENT_SAFETYSTOP, // 7=Safety Stop + SAMPLE_EVENT_CEILING_SAFETYSTOP, // 8=Safety Stop Broken + SAMPLE_EVENT_NONE, // 9=Deep Stop Ahead + SAMPLE_EVENT_DEEPSTOP, // 10=Deep Stop + SAMPLE_EVENT_DIVETIME, // 11=Dive Time + SAMPLE_EVENT_NONE, // 12=Gas Available + SAMPLE_EVENT_NONE, // 13=SetPoint Switch + SAMPLE_EVENT_NONE, // 14=Diluent Hypoxia + SAMPLE_EVENT_NONE, // 15=Tank Pressure + }; + + if (info->notify_type > 15) + return; + + sample.event.type = translate_notification[info->notify_type]; + if (sample.event.type == SAMPLE_EVENT_NONE) + return; + + sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END; + if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +} + + static int traverse_samples(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user) { struct sample_data *info = (struct sample_data *) user; @@ -328,6 +405,18 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c case 0x000a: // cylinder idx in first byte, pressure in next word sample_cylinder_pressure(info, data[0], array_uint16_le(data+1)); break; + case 0x0013: + sample_event_state_type(info, data[0]); + break; + case 0x0014: + sample_event_state_value(info, data[0]); + break; + case 0x0015: + sample_event_notify_type(info, data[0]); + break; + case 0x0016: + sample_event_notify_value(info, data[0]); + break; case 0x001d: sample_gas_switch_event(info, array_uint16_le(data)); break; From 97a8d41089a0c613cb8f62d8c3d4013bc97585ca Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Jan 2015 16:25:19 -0800 Subject: [PATCH 3/3] Add EON Steel bookmarks, warnings and alarm events I'd missed these because I'm blind. But mostly because they aren't as common. Signed-off-by: Linus Torvalds --- src/suunto_eonsteel_parser.c | 100 +++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/src/suunto_eonsteel_parser.c b/src/suunto_eonsteel_parser.c index 90df30a..b19315b 100644 --- a/src/suunto_eonsteel_parser.c +++ b/src/suunto_eonsteel_parser.c @@ -227,6 +227,7 @@ struct sample_data { void *userdata; unsigned int time; unsigned char state_type, notify_type; + unsigned char warning_type, alarm_type; }; static void sample_time(struct sample_data *info, unsigned short time_delta) @@ -290,6 +291,16 @@ static void sample_cylinder_pressure(struct sample_data *info, unsigned char idx if (info->callback) info->callback(DC_SAMPLE_PRESSURE, sample, info->userdata); } +static void sample_bookmark_event(struct sample_data *info, unsigned short idx) +{ + dc_sample_value_t sample = {0}; + + sample.event.type = SAMPLE_EVENT_BOOKMARK; + sample.event.value = idx; + + if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +} + static void sample_gas_switch_event(struct sample_data *info, unsigned short idx) { suunto_eonsteel_parser_t *eon = info->eon; @@ -310,8 +321,8 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx } /* - * The EON Steel has two different sample events: "state" and "notification". - * Both end up having two fields: type and a boolean value. + * The EON Steel has four different sample events: "state", "notification", + * "warning" and "alarm". All end up having two fields: type and a boolean value. * * The type enumerations are available as part of the type descriptor, and we * *should* probably parse them dynamically, but this hardcodes the different @@ -361,7 +372,7 @@ static void sample_event_notify_value(struct sample_data *info, unsigned char va SAMPLE_EVENT_TISSUELEVEL, // 3=Tissue Level SAMPLE_EVENT_NONE, // 4=Deco SAMPLE_EVENT_NONE, // 5=Deco Window - SAMPLE_EVENT_SAFETYSTOP_MANDATORY, // 6=Safety Stop Ahead + SAMPLE_EVENT_SAFETYSTOP_VOLUNTARY, // 6=Safety Stop Ahead SAMPLE_EVENT_SAFETYSTOP, // 7=Safety Stop SAMPLE_EVENT_CEILING_SAFETYSTOP, // 8=Safety Stop Broken SAMPLE_EVENT_NONE, // 9=Deep Stop Ahead @@ -385,6 +396,74 @@ static void sample_event_notify_value(struct sample_data *info, unsigned char va } +static void sample_event_warning_type(struct sample_data *info, unsigned char type) +{ + info->warning_type = type; +} + + +static void sample_event_warning_value(struct sample_data *info, unsigned char value) +{ + dc_sample_value_t sample = {0}; + static const enum parser_sample_event_t translate_warning[] = { + SAMPLE_EVENT_NONE, // 0=ICD Penalty ("Isobaric counterdiffusion") + SAMPLE_EVENT_VIOLATION, // 1=Deep Stop Penalty + SAMPLE_EVENT_SAFETYSTOP_MANDATORY, // 2=Mandatory Safety Stop + SAMPLE_EVENT_NONE, // 3=OTU250 + SAMPLE_EVENT_NONE, // 4=OTU300 + SAMPLE_EVENT_NONE, // 5=CNS80% + SAMPLE_EVENT_NONE, // 6=CNS100% + SAMPLE_EVENT_AIRTIME, // 7=Air Time + SAMPLE_EVENT_MAXDEPTH, // 8=Max.Depth + SAMPLE_EVENT_AIRTIME, // 9=Tank Pressure + SAMPLE_EVENT_CEILING_SAFETYSTOP, // 10=Safety Stop Broken + SAMPLE_EVENT_CEILING_SAFETYSTOP, // 11=Deep Stop Broken + SAMPLE_EVENT_CEILING, // 12=Ceiling Broken + SAMPLE_EVENT_PO2, // 13=PO2 High + }; + + if (info->warning_type > 13) + return; + + sample.event.type = translate_warning[info->warning_type]; + if (sample.event.type == SAMPLE_EVENT_NONE) + return; + + sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END; + if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +} + +static void sample_event_alarm_type(struct sample_data *info, unsigned char type) +{ + info->alarm_type = type; +} + + +static void sample_event_alarm_value(struct sample_data *info, unsigned char value) +{ + dc_sample_value_t sample = {0}; + static const enum parser_sample_event_t translate_alarm[] = { + SAMPLE_EVENT_CEILING_SAFETYSTOP, // 0=Mandatory Safety Stop Broken + SAMPLE_EVENT_ASCENT, // 1=Ascent Speed + SAMPLE_EVENT_NONE, // 2=Diluent Hyperoxia + SAMPLE_EVENT_VIOLATION, // 3=Violated Deep Stop + SAMPLE_EVENT_CEILING, // 4=Ceiling Broken + SAMPLE_EVENT_PO2, // 5=PO2 High + SAMPLE_EVENT_PO2, // 6=PO2 Low + }; + + if (info->alarm_type > 6) + return; + + sample.event.type = translate_alarm[info->alarm_type]; + if (sample.event.type == SAMPLE_EVENT_NONE) + return; + + sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END; + if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata); +} + + static int traverse_samples(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user) { struct sample_data *info = (struct sample_data *) user; @@ -417,6 +496,21 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c case 0x0016: sample_event_notify_value(info, data[0]); break; + case 0x0017: + sample_event_warning_type(info, data[0]); + break; + case 0x0018: + sample_event_warning_value(info, data[0]); + break; + case 0x0019: + sample_event_alarm_type(info, data[0]); + break; + case 0x001a: + sample_event_alarm_value(info, data[0]); + break; + case 0x001c: + sample_bookmark_event(info, array_uint16_le(data)); + break; case 0x001d: sample_gas_switch_event(info, array_uint16_le(data)); break;