Use the extended parsing facilities for the Suunto EON Steel backend
This takes advantage of the field cache and string interfaces, and reports TTS with the new TTS sample. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
41f89f415e
commit
62057c90bd
@ -29,6 +29,7 @@
|
||||
#include "parser-private.h"
|
||||
#include "array.h"
|
||||
#include "platform.h"
|
||||
#include "field-cache.h"
|
||||
|
||||
#define C_ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
|
||||
|
||||
@ -70,38 +71,15 @@ struct type_desc {
|
||||
};
|
||||
|
||||
#define MAXTYPE 512
|
||||
#define MAXGASES 16
|
||||
|
||||
typedef struct suunto_eonsteel_parser_t {
|
||||
dc_parser_t base;
|
||||
struct type_desc type_desc[MAXTYPE];
|
||||
// field cache
|
||||
struct {
|
||||
unsigned int initialized;
|
||||
unsigned int divetime;
|
||||
double maxdepth;
|
||||
double avgdepth;
|
||||
unsigned int ngases;
|
||||
dc_gasmix_t gasmix[MAXGASES];
|
||||
dc_salinity_t salinity;
|
||||
double surface_pressure;
|
||||
dc_divemode_t divemode;
|
||||
double lowsetpoint;
|
||||
double highsetpoint;
|
||||
double customsetpoint;
|
||||
dc_tankinfo_t tankinfo[MAXGASES];
|
||||
double tanksize[MAXGASES];
|
||||
double tankworkingpressure[MAXGASES];
|
||||
} cache;
|
||||
struct dc_field_cache cache;
|
||||
} suunto_eonsteel_parser_t;
|
||||
|
||||
typedef int (*eon_data_cb_t)(unsigned short type, const struct type_desc *desc, const unsigned char *data, int len, void *user);
|
||||
|
||||
typedef struct eon_event_t {
|
||||
const char *name;
|
||||
parser_sample_event_t type;
|
||||
} eon_event_t;
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
enum eon_sample type;
|
||||
@ -167,16 +145,6 @@ static enum eon_sample lookup_descriptor_type(suunto_eonsteel_parser_t *eon, str
|
||||
return ES_none;
|
||||
}
|
||||
|
||||
static parser_sample_event_t lookup_event(const char *name, const eon_event_t events[], size_t n)
|
||||
{
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
if (!strcasecmp(name, events[i].name))
|
||||
return events[i].type;
|
||||
}
|
||||
|
||||
return SAMPLE_EVENT_NONE;
|
||||
}
|
||||
|
||||
static const char *desc_type_name(enum eon_sample type)
|
||||
{
|
||||
int i;
|
||||
@ -468,8 +436,6 @@ struct sample_data {
|
||||
|
||||
/* We gather up deco and cylinder pressure information */
|
||||
int gasnr;
|
||||
int tts, ndl;
|
||||
double ceiling;
|
||||
};
|
||||
|
||||
static void sample_time(struct sample_data *info, unsigned short time_delta)
|
||||
@ -507,7 +473,6 @@ static void sample_ndl(struct sample_data *info, short ndl)
|
||||
{
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
info->ndl = ndl;
|
||||
if (ndl < 0)
|
||||
return;
|
||||
|
||||
@ -518,14 +483,27 @@ static void sample_ndl(struct sample_data *info, short ndl)
|
||||
|
||||
static void sample_tts(struct sample_data *info, unsigned short tts)
|
||||
{
|
||||
if (tts != 0xffff)
|
||||
info->tts = tts;
|
||||
if (tts != 0xffff) {
|
||||
dc_sample_value_t sample = {0};
|
||||
sample.time = tts;
|
||||
if (info->callback) info->callback(DC_SAMPLE_TTS, sample, info->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_ceiling(struct sample_data *info, unsigned short ceiling)
|
||||
{
|
||||
if (ceiling != 0xffff)
|
||||
info->ceiling = ceiling / 100.0;
|
||||
if (ceiling != 0xffff) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
// We don't actually have a time for the
|
||||
// deco stop, we just have a ceiling.
|
||||
//
|
||||
// We'll just say it's one minute.
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = ceiling ? 60 : 0;
|
||||
sample.deco.depth = ceiling / 100.0;
|
||||
if (info->callback) info->callback(DC_SAMPLE_DECO, sample, info->userdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void sample_heading(struct sample_data *info, unsigned short heading)
|
||||
@ -597,7 +575,7 @@ 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};
|
||||
|
||||
if (idx < 1 || idx > eon->cache.ngases)
|
||||
if (idx < 1 || idx > eon->cache.GASMIX_COUNT)
|
||||
return;
|
||||
|
||||
sample.gasmix = idx - 1;
|
||||
@ -681,26 +659,17 @@ static void sample_event_state_type(const struct type_desc *desc, struct sample_
|
||||
static void sample_event_state_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
dc_sample_value_t sample = {0};
|
||||
static const eon_event_t states[] = {
|
||||
{"Wet Outside", SAMPLE_EVENT_NONE},
|
||||
{"Below Wet Activation Depth", SAMPLE_EVENT_NONE},
|
||||
{"Below Surface", SAMPLE_EVENT_NONE},
|
||||
{"Dive Active", SAMPLE_EVENT_NONE},
|
||||
{"Surface Calculation", SAMPLE_EVENT_NONE},
|
||||
{"Tank pressure available", SAMPLE_EVENT_NONE},
|
||||
{"Closed Circuit Mode", SAMPLE_EVENT_NONE},
|
||||
};
|
||||
const char *name;
|
||||
|
||||
name = info->state_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, states, C_ARRAY_SIZE(states));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 1 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -712,25 +681,6 @@ static void sample_event_notify_type(const struct type_desc *desc, struct sample
|
||||
|
||||
static void sample_event_notify_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t notifications[] = {
|
||||
{"NoFly Time", SAMPLE_EVENT_NONE},
|
||||
{"Depth", SAMPLE_EVENT_NONE},
|
||||
{"Surface Time", SAMPLE_EVENT_NONE},
|
||||
{"Tissue Level", SAMPLE_EVENT_TISSUELEVEL},
|
||||
{"Deco", SAMPLE_EVENT_NONE},
|
||||
{"Deco Window", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop Ahead", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop", SAMPLE_EVENT_SAFETYSTOP},
|
||||
{"Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Deep Stop Ahead", SAMPLE_EVENT_NONE},
|
||||
{"Deep Stop", SAMPLE_EVENT_DEEPSTOP},
|
||||
{"Dive Time", SAMPLE_EVENT_DIVETIME},
|
||||
{"Gas Available", SAMPLE_EVENT_NONE},
|
||||
{"SetPoint Switch", SAMPLE_EVENT_NONE},
|
||||
{"Diluent Hypoxia", SAMPLE_EVENT_NONE},
|
||||
{"Air Time", SAMPLE_EVENT_NONE},
|
||||
{"Tank Pressure", SAMPLE_EVENT_NONE},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
|
||||
@ -738,11 +688,11 @@ static void sample_event_notify_value(const struct type_desc *desc, struct sampl
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, notifications, C_ARRAY_SIZE(notifications));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 2 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -755,22 +705,6 @@ static void sample_event_warning_type(const struct type_desc *desc, struct sampl
|
||||
|
||||
static void sample_event_warning_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t warnings[] = {
|
||||
{"ICD Penalty", SAMPLE_EVENT_NONE},
|
||||
{"Deep Stop Penalty", SAMPLE_EVENT_VIOLATION},
|
||||
{"Mandatory Safety Stop", SAMPLE_EVENT_SAFETYSTOP_MANDATORY},
|
||||
{"OTU250", SAMPLE_EVENT_NONE},
|
||||
{"OTU300", SAMPLE_EVENT_NONE},
|
||||
{"CNS80%", SAMPLE_EVENT_NONE},
|
||||
{"CNS100%", SAMPLE_EVENT_NONE},
|
||||
{"Max.Depth", SAMPLE_EVENT_MAXDEPTH},
|
||||
{"Air Time", SAMPLE_EVENT_AIRTIME},
|
||||
{"Tank Pressure", SAMPLE_EVENT_NONE},
|
||||
{"Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Deep Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Ceiling Broken", SAMPLE_EVENT_CEILING},
|
||||
{"PO2 High", SAMPLE_EVENT_PO2},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
|
||||
@ -778,11 +712,11 @@ static void sample_event_warning_value(const struct type_desc *desc, struct samp
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, warnings, C_ARRAY_SIZE(warnings));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 3 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -795,27 +729,18 @@ static void sample_event_alarm_type(const struct type_desc *desc, struct sample_
|
||||
|
||||
static void sample_event_alarm_value(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
static const eon_event_t alarms[] = {
|
||||
{"Mandatory Safety Stop Broken", SAMPLE_EVENT_CEILING_SAFETYSTOP},
|
||||
{"Ascent Speed", SAMPLE_EVENT_ASCENT},
|
||||
{"Diluent Hyperoxia", SAMPLE_EVENT_NONE},
|
||||
{"Violated Deep Stop", SAMPLE_EVENT_VIOLATION},
|
||||
{"Ceiling Broken", SAMPLE_EVENT_CEILING},
|
||||
{"PO2 High", SAMPLE_EVENT_PO2},
|
||||
{"PO2 Low", SAMPLE_EVENT_PO2},
|
||||
};
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *name;
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
name = info->alarm_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, alarms, C_ARRAY_SIZE(alarms));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.type = SAMPLE_EVENT_STRING;
|
||||
sample.event.name = name;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags |= 4 << SAMPLE_FLAGS_SEVERITY_SHIFT;
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
@ -976,10 +901,6 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c
|
||||
if (desc->size > len)
|
||||
ERROR(eon->base.context, "Got %d bytes of data for '%s' that wants %d bytes", len, desc->desc, desc->size);
|
||||
|
||||
info->ndl = -1;
|
||||
info->tts = 0;
|
||||
info->ceiling = 0.0;
|
||||
|
||||
for (i = 0; i < EON_MAX_GROUP; i++) {
|
||||
enum eon_sample type = desc->type[i];
|
||||
int bytes = handle_sample_type(desc, info, type, data);
|
||||
@ -995,15 +916,6 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c
|
||||
used += bytes;
|
||||
}
|
||||
|
||||
if (info->ndl < 0 && (info->tts || info->ceiling)) {
|
||||
dc_sample_value_t sample = {0};
|
||||
|
||||
sample.deco.type = DC_DECO_DECOSTOP;
|
||||
sample.deco.time = info->tts;
|
||||
sample.deco.depth = info->ceiling;
|
||||
if (info->callback) info->callback(DC_SAMPLE_DECO, sample, info->userdata);
|
||||
}
|
||||
|
||||
// Warn if there are left-over bytes for something we did use part of
|
||||
if (used && len)
|
||||
ERROR(eon->base.context, "Entry for '%s' had %d bytes, only used %d", desc->desc, len+used, used);
|
||||
@ -1026,11 +938,6 @@ suunto_eonsteel_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Ugly define thing makes the code much easier to read
|
||||
// I'd love to use __typeof__, but that's a gcc'ism
|
||||
#define field_value(p, set) \
|
||||
memcpy((p), &(set), sizeof(set))
|
||||
|
||||
static dc_status_t
|
||||
suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
@ -1043,33 +950,27 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi
|
||||
|
||||
switch (type) {
|
||||
case DC_FIELD_DIVETIME:
|
||||
field_value(value, eon->cache.divetime);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, DIVETIME);
|
||||
case DC_FIELD_MAXDEPTH:
|
||||
field_value(value, eon->cache.maxdepth);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, MAXDEPTH);
|
||||
case DC_FIELD_AVGDEPTH:
|
||||
field_value(value, eon->cache.avgdepth);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, AVGDEPTH);
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
field_value(value, eon->cache.ngases);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, GASMIX_COUNT);
|
||||
case DC_FIELD_GASMIX:
|
||||
if (flags >= MAXGASES)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
field_value(value, eon->cache.gasmix[flags]);
|
||||
break;
|
||||
return DC_FIELD_INDEX(eon->cache, value, GASMIX, flags);
|
||||
case DC_FIELD_SALINITY:
|
||||
field_value(value, eon->cache.salinity);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, SALINITY);
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
field_value(value, eon->cache.surface_pressure);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, ATMOSPHERIC);
|
||||
case DC_FIELD_DIVEMODE:
|
||||
field_value(value, eon->cache.divemode);
|
||||
break;
|
||||
return DC_FIELD_VALUE(eon->cache, value, DIVEMODE);
|
||||
case DC_FIELD_TANK:
|
||||
if (flags >= MAXGASES)
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
/*
|
||||
* Sadly it seems that the EON Steel doesn't tell us whether
|
||||
* we get imperial or metric data - the only indication is
|
||||
@ -1094,11 +995,13 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi
|
||||
* We need to have workpressure and a valid tank. In that case,
|
||||
* a fractional tank size implies imperial.
|
||||
*/
|
||||
if (tank->workpressure && (tank->type == DC_TANKVOLUME_METRIC)) {
|
||||
if (tank->workpressure && (tank->type & DC_TANKINFO_METRIC)) {
|
||||
if (fabs(tank->volume - rint(tank->volume)) > 0.001)
|
||||
tank->type = DC_TANKVOLUME_IMPERIAL;
|
||||
tank->type += DC_TANKINFO_IMPERIAL - DC_TANKINFO_METRIC;
|
||||
}
|
||||
break;
|
||||
case DC_FIELD_STRING:
|
||||
return dc_field_get_string(&eon->cache, flags, (dc_field_string_t *)value);
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -1127,7 +1030,7 @@ suunto_eonsteel_parser_get_datetime(dc_parser_t *parser, dc_datetime_t *datetime
|
||||
// time in ms
|
||||
static void add_time_field(suunto_eonsteel_parser_t *eon, unsigned short time_delta_ms)
|
||||
{
|
||||
eon->cache.divetime += time_delta_ms;
|
||||
eon->cache.DIVETIME += time_delta_ms;
|
||||
}
|
||||
|
||||
// depth in cm
|
||||
@ -1135,8 +1038,8 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
|
||||
{
|
||||
if (d != 0xffff) {
|
||||
double depth = d / 100.0;
|
||||
if (depth > eon->cache.maxdepth)
|
||||
eon->cache.maxdepth = depth;
|
||||
if (depth > eon->cache.MAXDEPTH)
|
||||
eon->cache.MAXDEPTH = depth;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_MAXDEPTH;
|
||||
}
|
||||
}
|
||||
@ -1149,28 +1052,28 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
|
||||
// "enum:0=Off,1=Primary,2=?,3=Diluent"
|
||||
// "enum:0=Off,1=Primary,3=Diluent,4=Oxygen"
|
||||
//
|
||||
// We turn that into the DC_TANKVOLUME data here, but
|
||||
// We turn that into the DC_TANKINFO data here, but
|
||||
// initially consider all non-off tanks to me METRIC.
|
||||
//
|
||||
// We may later turn the METRIC tank size into IMPERIAL if we
|
||||
// get a working pressure and non-integral size
|
||||
static int add_gas_type(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, unsigned char type)
|
||||
static dc_status_t add_gas_type(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, unsigned char type)
|
||||
{
|
||||
int idx = eon->cache.ngases;
|
||||
int idx = eon->cache.GASMIX_COUNT;
|
||||
dc_tankinfo_t tankinfo = DC_TANKINFO_METRIC;
|
||||
char *name;
|
||||
|
||||
if (idx >= MAXGASES)
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
|
||||
eon->cache.ngases = idx+1;
|
||||
eon->cache.GASMIX_COUNT = idx+1;
|
||||
name = lookup_enum(desc, type);
|
||||
if (!name)
|
||||
DEBUG(eon->base.context, "Unable to look up gas type %u in %s", type, desc->format);
|
||||
else if (!strcasecmp(name, "Diluent"))
|
||||
;
|
||||
tankinfo |= DC_TANKINFO_CC_DILUENT;
|
||||
else if (!strcasecmp(name, "Oxygen"))
|
||||
;
|
||||
tankinfo |= DC_TANKINFO_CC_O2;
|
||||
else if (!strcasecmp(name, "None"))
|
||||
tankinfo = DC_TANKVOLUME_NONE;
|
||||
else if (strcasecmp(name, "Primary"))
|
||||
@ -1181,46 +1084,46 @@ static int add_gas_type(suunto_eonsteel_parser_t *eon, const struct type_desc *d
|
||||
eon->cache.initialized |= 1 << DC_FIELD_GASMIX_COUNT;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_TANK_COUNT;
|
||||
free(name);
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// "sml.DeviceLog.Header.Diving.Gases.Gas.Oxygen"
|
||||
// O2 percentage as a byte
|
||||
static int add_gas_o2(suunto_eonsteel_parser_t *eon, unsigned char o2)
|
||||
static dc_status_t add_gas_o2(suunto_eonsteel_parser_t *eon, unsigned char o2)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
int idx = eon->cache.GASMIX_COUNT-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.gasmix[idx].oxygen = o2 / 100.0;
|
||||
eon->cache.GASMIX[idx].oxygen = o2 / 100.0;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_GASMIX;
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// "sml.DeviceLog.Header.Diving.Gases.Gas.Helium"
|
||||
// He percentage as a byte
|
||||
static int add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he)
|
||||
static dc_status_t add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
int idx = eon->cache.GASMIX_COUNT-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.gasmix[idx].helium = he / 100.0;
|
||||
eon->cache.GASMIX[idx].helium = he / 100.0;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_GASMIX;
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int add_gas_size(suunto_eonsteel_parser_t *eon, float l)
|
||||
static dc_status_t add_gas_size(suunto_eonsteel_parser_t *eon, float l)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
int idx = eon->cache.GASMIX_COUNT-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.tanksize[idx] = l;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_TANK;
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int add_gas_workpressure(suunto_eonsteel_parser_t *eon, float wp)
|
||||
static dc_status_t add_gas_workpressure(suunto_eonsteel_parser_t *eon, float wp)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
int idx = eon->cache.GASMIX_COUNT-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.tankworkingpressure[idx] = wp;
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static float get_le32_float(const unsigned char *src)
|
||||
@ -1242,12 +1145,22 @@ static float get_le32_float(const unsigned char *src)
|
||||
// Info.SW
|
||||
// Name
|
||||
// SerialNumber
|
||||
static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
static dc_status_t traverse_device_fields(suunto_eonsteel_parser_t *eon,
|
||||
const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Device.");
|
||||
|
||||
return 0;
|
||||
if (!strcmp(name, "SerialNumber"))
|
||||
return dc_field_add_string(&eon->cache, "Serial", data);
|
||||
if (!strcmp(name, "Info.HW"))
|
||||
return dc_field_add_string(&eon->cache, "HW Version", data);
|
||||
if (!strcmp(name, "Info.SW"))
|
||||
return dc_field_add_string(&eon->cache, "FW Version", data);
|
||||
if (!strcmp(name, "Info.BatteryAtStart"))
|
||||
return dc_field_add_string(&eon->cache, "Battery at start", data);
|
||||
if (!strcmp(name, "Info.BatteryAtEnd"))
|
||||
return dc_field_add_string(&eon->cache, "Battery at end", data);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// "sml.DeviceLog.Header.Diving.Gases"
|
||||
@ -1263,8 +1176,9 @@ static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
// .Gas.EndPressure (float32,precision=0)
|
||||
// .Gas.TransmitterStartBatteryCharge (int8,precision=2)
|
||||
// .Gas.TransmitterEndBatteryCharge (int8,precision=2)
|
||||
static int traverse_gas_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
static dc_status_t traverse_gas_fields(suunto_eonsteel_parser_t *eon,
|
||||
const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Header.Diving.Gases");
|
||||
|
||||
@ -1277,13 +1191,31 @@ static int traverse_gas_fields(suunto_eonsteel_parser_t *eon, const struct type_
|
||||
if (!strcmp(name, ".Gas.Helium"))
|
||||
return add_gas_he(eon, data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterID"))
|
||||
return dc_field_add_string(&eon->cache, "Transmitter ID", data);
|
||||
|
||||
if (!strcmp(name, ".Gas.TankSize"))
|
||||
return add_gas_size(eon, get_le32_float(data));
|
||||
|
||||
if (!strcmp(name, ".Gas.TankFillPressure"))
|
||||
return add_gas_workpressure(eon, get_le32_float(data));
|
||||
|
||||
return 0;
|
||||
// There is a bug with older transmitters, where the transmitter
|
||||
// battery charge returns zero. Rather than returning that bogus
|
||||
// data, just don't return any battery charge information at all.
|
||||
//
|
||||
// Make sure to add all non-battery-charge field checks above this
|
||||
// test, so that it doesn't trigger for anything else.
|
||||
if (!data[0])
|
||||
return 0;
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterStartBatteryCharge"))
|
||||
return dc_field_add_string_fmt(&eon->cache, "Transmitter Battery at start", "%d %%", data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.TransmitterEndBatteryCharge"))
|
||||
return dc_field_add_string_fmt(&eon->cache, "Transmitter Battery at end", "%d %%", data[0]);
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@ -1324,8 +1256,9 @@ static int traverse_gas_fields(suunto_eonsteel_parser_t *eon, const struct type_
|
||||
// EndTissue.Helium+Pressure (uint32)
|
||||
// EndTissue.RgbmNitrogen (float32,precision=3)
|
||||
// EndTissue.RgbmHelium (float32,precision=3)
|
||||
static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
static dc_status_t traverse_diving_fields(suunto_eonsteel_parser_t *eon,
|
||||
const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Header.Diving.");
|
||||
|
||||
@ -1334,17 +1267,25 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
|
||||
if (!strcmp(name, "SurfacePressure")) {
|
||||
unsigned int pressure = array_uint32_le(data); // in SI units - Pascal
|
||||
eon->cache.surface_pressure = pressure / 100000.0; // bar
|
||||
eon->cache.initialized |= 1 << DC_FIELD_ATMOSPHERIC;
|
||||
return 0;
|
||||
DC_ASSIGN_FIELD(eon->cache, ATMOSPHERIC, pressure / 100000.0); // bar
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "Algorithm"))
|
||||
return dc_field_add_string(&eon->cache, "Deco algorithm", data);
|
||||
|
||||
if (!strcmp(name, "DiveMode")) {
|
||||
if (!strncmp((const char *)data, "CCR", 3)) {
|
||||
eon->cache.divemode = DC_DIVEMODE_CCR;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_DIVEMODE;
|
||||
DC_ASSIGN_FIELD(eon->cache, DIVEMODE, DC_DIVEMODE_CCR);
|
||||
}
|
||||
return 0;
|
||||
return dc_field_add_string(&eon->cache, "Dive Mode", data);
|
||||
}
|
||||
|
||||
/* Signed byte of conservatism (-2 .. +2) */
|
||||
if (!strcmp(name, "Conservatism")) {
|
||||
int val = *(signed char *)data;
|
||||
|
||||
return dc_field_add_string_fmt(&eon->cache, "Personal Adjustment", "P%d", val);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "LowSetPoint")) {
|
||||
@ -1359,7 +1300,19 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
// Time recoded in seconds.
|
||||
// Let's just agree to ignore seconds
|
||||
if (!strcmp(name, "DesaturationTime")) {
|
||||
unsigned int time = array_uint32_le(data) / 60;
|
||||
return dc_field_add_string_fmt(&eon->cache, "Desaturation Time", "%d:%02d", time / 60, time % 60);
|
||||
}
|
||||
|
||||
if (!strcmp(name, "SurfaceTime")) {
|
||||
unsigned int time = array_uint32_le(data) / 60;
|
||||
return dc_field_add_string_fmt(&eon->cache, "Surface Time", "%d:%02d", time / 60, time % 60);
|
||||
}
|
||||
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// "Header" fields are:
|
||||
@ -1371,8 +1324,9 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
// Duration (uint32)
|
||||
// PauseDuration (uint32)
|
||||
// SampleInterval (uint8)
|
||||
static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
static dc_status_t traverse_header_fields(suunto_eonsteel_parser_t *eon,
|
||||
const struct type_desc *desc,
|
||||
const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Header.");
|
||||
|
||||
@ -1381,15 +1335,17 @@ static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
|
||||
if (!strcmp(name, "Depth.Max")) {
|
||||
double d = get_le32_float(data);
|
||||
if (d > eon->cache.maxdepth)
|
||||
eon->cache.maxdepth = d;
|
||||
return 0;
|
||||
if (d > eon->cache.MAXDEPTH)
|
||||
DC_ASSIGN_FIELD(eon->cache, MAXDEPTH, d);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
if (!strcmp(name, "DateTime"))
|
||||
return dc_field_add_string(&eon->cache, "Dive ID", data);
|
||||
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static int traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, const unsigned char *data, int len)
|
||||
static dc_status_t traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, const unsigned char *data, int len)
|
||||
{
|
||||
const char *name = desc->desc;
|
||||
|
||||
@ -1404,7 +1360,7 @@ static int traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct t
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1428,6 +1384,8 @@ static int traverse_sample_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
set_depth_field(eon, array_uint16_le(data));
|
||||
data += 2;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1457,7 +1415,7 @@ static void initialize_field_caches(suunto_eonsteel_parser_t *eon)
|
||||
|
||||
// The internal time fields are in ms and have to be added up
|
||||
// like that. At the end, we translate it back to seconds.
|
||||
eon->cache.divetime /= 1000;
|
||||
eon->cache.DIVETIME /= 1000;
|
||||
}
|
||||
|
||||
static void show_descriptor(suunto_eonsteel_parser_t *eon, int nr, struct type_desc *desc)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user