Merge branch 'eonsteel'
This commit is contained in:
commit
5bc52bc5a2
@ -22,6 +22,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <libdivecomputer/suunto_eonsteel.h>
|
||||
|
||||
@ -34,27 +35,30 @@
|
||||
|
||||
enum eon_sample {
|
||||
ES_none = 0,
|
||||
ES_dtime, // duint16,precision=3 (time delta in ms)
|
||||
ES_depth, // uint16,precision=2,nillable=65535 (depth in cm)
|
||||
ES_temp, // int16,precision=2,nillable=-3000 (temp in deci-Celsius)
|
||||
ES_ndl, // int16,nillable=-1 (ndl in minutes)
|
||||
ES_ceiling, // uint16,precision=2,nillable=65535 (ceiling in cm)
|
||||
ES_tts, // uint16,nillable=65535 (time to surface)
|
||||
ES_heading, // uint16,precision=4,nillable=65535 (heading in degrees)
|
||||
ES_abspressure, // uint16,precision=0,nillable=65535 (abs presure in centibar)
|
||||
ES_gastime, // int16,nillable=-1 (remaining gas time in minutes)
|
||||
ES_ventilation, // uint16,precision=6,nillable=65535 ("x/6000000,x"? No idea)
|
||||
ES_gasnr, // uint8
|
||||
ES_pressure, // uint16,nillable=65535 (cylinder pressure in centibar)
|
||||
ES_state,
|
||||
ES_state_active,
|
||||
ES_notify,
|
||||
ES_notify_active,
|
||||
ES_warning,
|
||||
ES_warning_active,
|
||||
ES_dtime, // duint16,precision=3 (time delta in ms)
|
||||
ES_depth, // uint16,precision=2,nillable=65535 (depth in cm)
|
||||
ES_temp, // int16,precision=2,nillable=-3000 (temp in deci-Celsius)
|
||||
ES_ndl, // int16,nillable=-1 (ndl in minutes)
|
||||
ES_ceiling, // uint16,precision=2,nillable=65535 (ceiling in cm)
|
||||
ES_tts, // uint16,nillable=65535 (time to surface)
|
||||
ES_heading, // uint16,precision=4,nillable=65535 (heading in degrees)
|
||||
ES_abspressure, // uint16,precision=0,nillable=65535 (abs presure in centibar)
|
||||
ES_gastime, // int16,nillable=-1 (remaining gas time in minutes)
|
||||
ES_ventilation, // uint16,precision=6,nillable=65535 ("x/6000000,x"? No idea)
|
||||
ES_gasnr, // uint8
|
||||
ES_pressure, // uint16,nillable=65535 (cylinder pressure in centibar)
|
||||
ES_state, // enum:0=Wet Outside,1=Below Wet Activation Depth,2=Below Surface,3=Dive Active,4=Surface Calculation,5=Tank pressure available,6=Closed Circuit Mode
|
||||
ES_state_active, // bool
|
||||
ES_notify, // enum:0=NoFly Time,1=Depth,2=Surface Time,3=Tissue Level,4=Deco,5=Deco Window,6=Safety Stop Ahead,7=Safety Stop,8=Safety Stop Broken,9=Deep Stop Ahead,10=Deep Stop,11=Dive Time,12=Gas Available,13=SetPoint Switch,14=Diluent Hypoxia,15=Air Time,16=Tank Pressure
|
||||
ES_notify_active, // bool
|
||||
ES_warning, // enum:0=ICD Penalty,1=Deep Stop Penalty,2=Mandatory Safety Stop,3=OTU250,4=OTU300,5=CNS80%,6=CNS100%,7=Max.Depth,8=Air Time,9=Tank Pressure,10=Safety Stop Broken,11=Deep Stop Broken,12=Ceiling Broken,13=PO2 High
|
||||
ES_warning_active, // bool
|
||||
ES_alarm,
|
||||
ES_alarm_active,
|
||||
ES_gasswitch, // uint16
|
||||
ES_gasswitch, // uint16
|
||||
ES_setpoint_type, // enum:0=Low,1=High,2=Custom
|
||||
ES_setpoint_po2, // uint32
|
||||
ES_setpoint_automatic, // bool
|
||||
ES_bookmark,
|
||||
};
|
||||
|
||||
@ -82,15 +86,28 @@ typedef struct suunto_eonsteel_parser_t {
|
||||
dc_gasmix_t gasmix[MAXGASES];
|
||||
dc_salinity_t salinity;
|
||||
double surface_pressure;
|
||||
dc_divemode_t divemode;
|
||||
double lowsetpoint;
|
||||
double highsetpoint;
|
||||
double customsetpoint;
|
||||
dc_tankvolume_t tankinfo[MAXGASES];
|
||||
double tanksize[MAXGASES];
|
||||
double tankworkingpressure[MAXGASES];
|
||||
} 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;
|
||||
} type_translation[] = {
|
||||
{ "+Time", ES_dtime },
|
||||
{ "Depth", ES_depth },
|
||||
{ "Temperature", ES_temp },
|
||||
{ "NoDecTime", ES_ndl },
|
||||
@ -112,6 +129,9 @@ static const struct {
|
||||
{ "Events.Alarm.Active", ES_alarm_active },
|
||||
{ "Events.Bookmark.Name", ES_bookmark },
|
||||
{ "Events.GasSwitch.GasNumber", ES_gasswitch },
|
||||
{ "Events.SetPoint.Type", ES_setpoint_type },
|
||||
{ "Events.Events.SetPoint.PO2", ES_setpoint_po2 },
|
||||
{ "Events.SetPoint.Automatic", ES_setpoint_automatic },
|
||||
{ "Events.DiveTimer.Active", ES_none },
|
||||
{ "Events.DiveTimer.Time", ES_none },
|
||||
};
|
||||
@ -148,6 +168,26 @@ 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;
|
||||
for (i = 0; i < C_ARRAY_SIZE(type_translation); i++) {
|
||||
if (type == type_translation[i].type)
|
||||
return type_translation[i].name;
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static int lookup_descriptor_size(suunto_eonsteel_parser_t *eon, struct type_desc *desc)
|
||||
{
|
||||
const char *format = desc->format;
|
||||
@ -424,8 +464,8 @@ struct sample_data {
|
||||
dc_sample_callback_t callback;
|
||||
void *userdata;
|
||||
unsigned int time;
|
||||
unsigned char state_type, notify_type;
|
||||
unsigned char warning_type, alarm_type;
|
||||
const char *state_type, *notify_type;
|
||||
const char *warning_type, *alarm_type;
|
||||
|
||||
/* We gather up deco and cylinder pressure information */
|
||||
int gasnr;
|
||||
@ -575,154 +615,256 @@ static void sample_gas_switch_event(struct sample_data *info, unsigned short idx
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the string from an enumeration.
|
||||
*
|
||||
* Enumerations have the enum values in the "format" string,
|
||||
* and all start with "enum:" followed by a comma-separated list
|
||||
* of enumeration values and strings. Example:
|
||||
*
|
||||
* "enum:0=NoFly Time,1=Depth,2=Surface Time,3=..."
|
||||
*/
|
||||
static const char *lookup_enum(const struct type_desc *desc, unsigned char value)
|
||||
{
|
||||
const char *str = desc->format;
|
||||
unsigned char c;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
if (strncmp(str, "enum:", 5))
|
||||
return NULL;
|
||||
str += 5;
|
||||
|
||||
while ((c = *str) != 0) {
|
||||
unsigned char n;
|
||||
const char *begin, *end;
|
||||
char *ret;
|
||||
|
||||
str++;
|
||||
if (!isdigit(c))
|
||||
continue;
|
||||
n = c - '0';
|
||||
|
||||
// We only handle one or two digits
|
||||
if (isdigit(*str)) {
|
||||
n = n*10 + *str - '0';
|
||||
str++;
|
||||
}
|
||||
|
||||
begin = end = str;
|
||||
while ((c = *str) != 0) {
|
||||
str++;
|
||||
if (c == ',')
|
||||
break;
|
||||
end = str;
|
||||
}
|
||||
|
||||
// Verify that it has the 'n=string' format and skip the equals sign
|
||||
if (*begin != '=')
|
||||
continue;
|
||||
begin++;
|
||||
|
||||
// Is it the value we're looking for?
|
||||
if (n != value)
|
||||
continue;
|
||||
|
||||
ret = malloc(end - begin + 1);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
memcpy(ret, begin, end-begin);
|
||||
ret[end-begin] = 0;
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* FIXME! This needs to parse the actual type descriptor enum
|
||||
*/
|
||||
static void sample_event_state_type(struct sample_data *info, unsigned char type)
|
||||
static void sample_event_state_type(const struct type_desc *desc, struct sample_data *info, unsigned char type)
|
||||
{
|
||||
info->state_type = type;
|
||||
info->state_type = lookup_enum(desc, 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;
|
||||
}
|
||||
|
||||
|
||||
// FIXME! This needs to parse the actual type descriptor enum
|
||||
static void sample_event_notify_value(struct sample_data *info, unsigned char value)
|
||||
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 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_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
|
||||
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
|
||||
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;
|
||||
|
||||
if (info->notify_type > 15)
|
||||
name = info->state_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = translate_notification[info->notify_type];
|
||||
sample.event.type = lookup_event(name, states, C_ARRAY_SIZE(states));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
static void sample_event_notify_type(const struct type_desc *desc, struct sample_data *info, unsigned char type)
|
||||
{
|
||||
info->notify_type = lookup_enum(desc, type);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
name = info->notify_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = lookup_event(name, notifications, C_ARRAY_SIZE(notifications));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
|
||||
static void sample_event_warning_type(struct sample_data *info, unsigned char type)
|
||||
static void sample_event_warning_type(const struct type_desc *desc, struct sample_data *info, unsigned char type)
|
||||
{
|
||||
info->warning_type = type;
|
||||
info->warning_type = lookup_enum(desc, type);
|
||||
}
|
||||
|
||||
|
||||
static void sample_event_warning_value(struct sample_data *info, unsigned char value)
|
||||
static void sample_event_warning_value(const struct type_desc *desc, 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
|
||||
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;
|
||||
|
||||
if (info->warning_type > 13)
|
||||
name = info->warning_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = translate_warning[info->warning_type];
|
||||
sample.event.type = lookup_event(name, warnings, C_ARRAY_SIZE(warnings));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags = 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)
|
||||
static void sample_event_alarm_type(const struct type_desc *desc, struct sample_data *info, unsigned char type)
|
||||
{
|
||||
info->alarm_type = type;
|
||||
info->alarm_type = lookup_enum(desc, type);
|
||||
}
|
||||
|
||||
|
||||
// FIXME! This needs to parse the actual type descriptor enum
|
||||
static void sample_event_alarm_value(struct sample_data *info, unsigned char value)
|
||||
static void sample_event_alarm_value(const struct type_desc *desc, 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
|
||||
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;
|
||||
|
||||
if (info->alarm_type > 6)
|
||||
name = info->alarm_type;
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
sample.event.type = translate_alarm[info->alarm_type];
|
||||
sample.event.type = lookup_event(name, alarms, C_ARRAY_SIZE(alarms));
|
||||
if (sample.event.type == SAMPLE_EVENT_NONE)
|
||||
return;
|
||||
|
||||
sample.event.value = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
sample.event.flags = value ? SAMPLE_FLAGS_BEGIN : SAMPLE_FLAGS_END;
|
||||
if (info->callback) info->callback(DC_SAMPLE_EVENT, sample, info->userdata);
|
||||
}
|
||||
|
||||
static int handle_sample_type(struct sample_data *info, enum eon_sample type, const unsigned char *data)
|
||||
// enum:0=Low,1=High,2=Custom
|
||||
static void sample_setpoint_type(const struct type_desc *desc, struct sample_data *info, unsigned char value)
|
||||
{
|
||||
dc_sample_value_t sample = {0};
|
||||
const char *type = lookup_enum(desc, value);
|
||||
|
||||
if (!type) {
|
||||
DEBUG(info->eon->base.context, "sample_setpoint_type(%u) did not match anything in %s", value, desc->format);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!strcasecmp(type, "Low"))
|
||||
sample.ppo2 = info->eon->cache.lowsetpoint;
|
||||
else if (!strcasecmp(type, "High"))
|
||||
sample.ppo2 = info->eon->cache.highsetpoint;
|
||||
else if (!strcasecmp(type, "Custom"))
|
||||
sample.ppo2 = info->eon->cache.customsetpoint;
|
||||
else {
|
||||
DEBUG(info->eon->base.context, "sample_setpoint_type(%u) unknown type '%s'", value, type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->callback) info->callback(DC_SAMPLE_SETPOINT, sample, info->userdata);
|
||||
}
|
||||
|
||||
// uint32
|
||||
static void sample_setpoint_po2(struct sample_data *info, unsigned int pressure)
|
||||
{
|
||||
// I *think* this just sets the custom SP, and then
|
||||
// we'll get a setpoint_type(2) later.
|
||||
info->eon->cache.customsetpoint = pressure / 100000.0; // Pascal to bar
|
||||
}
|
||||
|
||||
static void sample_setpoint_automatic(struct sample_data *info, unsigned char value)
|
||||
{
|
||||
DEBUG(info->eon->base.context, "sample_setpoint_automatic(%u)", value);
|
||||
}
|
||||
|
||||
static int handle_sample_type(const struct type_desc *desc, struct sample_data *info, enum eon_sample type, const unsigned char *data)
|
||||
{
|
||||
switch (type) {
|
||||
case ES_dtime:
|
||||
@ -774,35 +916,35 @@ static int handle_sample_type(struct sample_data *info, enum eon_sample type, co
|
||||
return 2;
|
||||
|
||||
case ES_state:
|
||||
sample_event_state_type(info, data[0]);
|
||||
sample_event_state_type(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_state_active:
|
||||
sample_event_state_value(info, data[0]);
|
||||
sample_event_state_value(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_notify:
|
||||
sample_event_notify_type(info, data[0]);
|
||||
sample_event_notify_type(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_notify_active:
|
||||
sample_event_notify_value(info, data[0]);
|
||||
sample_event_notify_value(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_warning:
|
||||
sample_event_warning_type(info, data[0]);
|
||||
sample_event_warning_type(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_warning_active:
|
||||
sample_event_warning_value(info, data[0]);
|
||||
sample_event_warning_value(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_alarm:
|
||||
sample_event_alarm_type(info, data[0]);
|
||||
sample_event_alarm_type(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_alarm_active:
|
||||
sample_event_alarm_value(info, data[0]);
|
||||
sample_event_alarm_value(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_bookmark:
|
||||
@ -813,6 +955,18 @@ static int handle_sample_type(struct sample_data *info, enum eon_sample type, co
|
||||
sample_gas_switch_event(info, array_uint16_le(data));
|
||||
return 2;
|
||||
|
||||
case ES_setpoint_type:
|
||||
sample_setpoint_type(desc, info, data[0]);
|
||||
return 1;
|
||||
|
||||
case ES_setpoint_po2:
|
||||
sample_setpoint_po2(info, array_uint32_le(data));
|
||||
return 4;
|
||||
|
||||
case ES_setpoint_automatic: // bool
|
||||
sample_setpoint_automatic(info, data[0]);
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@ -833,7 +987,7 @@ static int traverse_samples(unsigned short type, const struct type_desc *desc, c
|
||||
|
||||
for (i = 0; i < EON_MAX_GROUP; i++) {
|
||||
enum eon_sample type = desc->type[i];
|
||||
int bytes = handle_sample_type(info, type, data);
|
||||
int bytes = handle_sample_type(desc, info, type, data);
|
||||
|
||||
if (!bytes)
|
||||
break;
|
||||
@ -879,9 +1033,11 @@ suunto_eonsteel_parser_samples_foreach(dc_parser_t *abstract, dc_sample_callback
|
||||
static dc_status_t
|
||||
suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsigned int flags, void *value)
|
||||
{
|
||||
dc_tank_t *tank = (dc_tank_t *) value;
|
||||
|
||||
suunto_eonsteel_parser_t *eon = (suunto_eonsteel_parser_t *)parser;
|
||||
|
||||
if (!(eon->cache.initialized >> type))
|
||||
if (!(eon->cache.initialized & (1 << type)))
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
|
||||
switch (type) {
|
||||
@ -895,6 +1051,7 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi
|
||||
field_value(value, eon->cache.avgdepth);
|
||||
break;
|
||||
case DC_FIELD_GASMIX_COUNT:
|
||||
case DC_FIELD_TANK_COUNT:
|
||||
field_value(value, eon->cache.ngases);
|
||||
break;
|
||||
case DC_FIELD_GASMIX:
|
||||
@ -908,6 +1065,39 @@ suunto_eonsteel_parser_get_field(dc_parser_t *parser, dc_field_type_t type, unsi
|
||||
case DC_FIELD_ATMOSPHERIC:
|
||||
field_value(value, eon->cache.surface_pressure);
|
||||
break;
|
||||
case DC_FIELD_DIVEMODE:
|
||||
field_value(value, eon->cache.divemode);
|
||||
break;
|
||||
case DC_FIELD_TANK:
|
||||
/*
|
||||
* Sadly it seems that the EON Steel doesn't tell us whether
|
||||
* we get imperial or metric data - the only indication is
|
||||
* that metric is (at least so far) always whole liters
|
||||
*/
|
||||
tank->volume = eon->cache.tanksize[flags];
|
||||
tank->gasmix = flags;
|
||||
|
||||
/*
|
||||
* The pressure reported is NOT the pressure the user enters.
|
||||
*
|
||||
* So 3000psi turns into 206.700 bar instead of 206.843 bar;
|
||||
* We report it as we get it and let the application figure out
|
||||
* what to do with that
|
||||
*/
|
||||
tank->workpressure = eon->cache.tankworkingpressure[flags];
|
||||
tank->type = eon->cache.tankinfo[flags];
|
||||
|
||||
/*
|
||||
* See if we should call this imperial instead.
|
||||
*
|
||||
* 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 (fabs(tank->volume - rint(tank->volume)) > 0.001)
|
||||
tank->type = DC_TANKVOLUME_IMPERIAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DC_STATUS_UNSUPPORTED;
|
||||
}
|
||||
@ -953,11 +1143,38 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
|
||||
// Two versions so far:
|
||||
// "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
|
||||
// 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)
|
||||
{
|
||||
if (eon->cache.ngases < MAXGASES)
|
||||
eon->cache.ngases++;
|
||||
int idx = eon->cache.ngases;
|
||||
dc_tankvolume_t tankinfo = DC_TANKVOLUME_METRIC;
|
||||
const char *name;
|
||||
|
||||
if (idx >= MAXGASES)
|
||||
return 0;
|
||||
|
||||
eon->cache.ngases = 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"))
|
||||
;
|
||||
else if (!strcasecmp(name, "Oxygen"))
|
||||
;
|
||||
else if (!strcasecmp(name, "None"))
|
||||
tankinfo = 0;
|
||||
else if (strcasecmp(name, "Primary"))
|
||||
DEBUG(eon->base.context, "Unknown gas type %u (%s)", type, name);
|
||||
|
||||
eon->cache.tankinfo[idx] = tankinfo;
|
||||
|
||||
eon->cache.initialized |= 1 << DC_FIELD_GASMIX_COUNT;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_TANK_COUNT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -983,6 +1200,23 @@ static int add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_gas_size(suunto_eonsteel_parser_t *eon, float l)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.tanksize[idx] = l;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_TANK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_gas_workpressure(suunto_eonsteel_parser_t *eon, float wp)
|
||||
{
|
||||
int idx = eon->cache.ngases-1;
|
||||
if (idx >= 0)
|
||||
eon->cache.tankworkingpressure[idx] = wp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float get_le32_float(const unsigned char *src)
|
||||
{
|
||||
union {
|
||||
@ -1010,19 +1244,45 @@ static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
// "sml.DeviceLog.Header.Diving.Gases"
|
||||
//
|
||||
// +Gas.State (enum:0=Off,1=Primary,3=Diluent,4=Oxygen)
|
||||
// .Gas.Oxygen (uint8,precision=2)
|
||||
// .Gas.Helium (uint8,precision=2)
|
||||
// .Gas.PO2 (uint32)
|
||||
// .Gas.TransmitterID (utf8)
|
||||
// .Gas.TankSize (float32,precision=5)
|
||||
// .Gas.TankFillPressure (float32,precision=0)
|
||||
// .Gas.StartPressure (float32,precision=0)
|
||||
// .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)
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Header.Diving.Gases");
|
||||
|
||||
if (!strcmp(name, "+Gas.State"))
|
||||
return add_gas_type(eon, desc, data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.Oxygen"))
|
||||
return add_gas_o2(eon, data[0]);
|
||||
|
||||
if (!strcmp(name, ".Gas.Helium"))
|
||||
return add_gas_he(eon, data[0]);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// "sml.DeviceLog.Header.Diving."
|
||||
//
|
||||
// Gases+Gas.State (enum:0=Off,1=Primary,3=Diluent,4=Oxygen)
|
||||
// Gases.Gas.Oxygen (uint8,precision=2)
|
||||
// Gases.Gas.Helium (uint8,precision=2)
|
||||
// Gases.Gas.PO2 (uint32)
|
||||
// Gases.Gas.TransmitterID (utf8)
|
||||
// Gases.Gas.TankSize (float32,precision=5)
|
||||
// Gases.Gas.TankFillPressure (float32,precision=0)
|
||||
// Gases.Gas.StartPressure (float32,precision=0)
|
||||
// Gases.Gas.EndPressure (float32,precision=0)
|
||||
// Gases.Gas.TransmitterStartBatteryCharge (int8,precision=2)
|
||||
// Gases.Gas.TransmitterEndBatteryCharge (int8,precision=2)
|
||||
// SurfaceTime (uint32)
|
||||
// NumberInSeries (uint32)
|
||||
// Algorithm (utf8)
|
||||
@ -1032,6 +1292,12 @@ static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
// AlgorithmTransitionDepth (uint8)
|
||||
// DaysInSeries (uint32)
|
||||
// PreviousDiveDepth (float32,precision=2)
|
||||
// LowSetPoint (uint32)
|
||||
// HighSetPoint (uint32)
|
||||
// SwitchHighSetPoint.Enabled (bool)
|
||||
// SwitchHighSetPoint.Depth (float32,precision=1)
|
||||
// SwitchLowSetPoint.Enabled (bool)
|
||||
// SwitchLowSetPoint.Depth (float32,precision=1)
|
||||
// StartTissue.CNS (float32,precision=3)
|
||||
// StartTissue.OTU (float32)
|
||||
// StartTissue.OLF (float32,precision=3)
|
||||
@ -1057,14 +1323,8 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
{
|
||||
const char *name = desc->desc + strlen("sml.DeviceLog.Header.Diving.");
|
||||
|
||||
if (!strcmp(name, "Gases+Gas.State"))
|
||||
return add_gas_type(eon, desc, data[0]);
|
||||
|
||||
if (!strcmp(name, "Gases.Gas.Oxygen"))
|
||||
return add_gas_o2(eon, data[0]);
|
||||
|
||||
if (!strcmp(name, "Gases.Gas.Helium"))
|
||||
return add_gas_he(eon, data[0]);
|
||||
if (!strncmp(name, "Gases", 5))
|
||||
return traverse_gas_fields(eon, desc, data, len);
|
||||
|
||||
if (!strcmp(name, "SurfacePressure")) {
|
||||
unsigned int pressure = array_uint32_le(data); // in SI units - Pascal
|
||||
@ -1073,6 +1333,26 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "DiveMode")) {
|
||||
if (!strncmp(data, "CCR", 3)) {
|
||||
eon->cache.divemode = DC_DIVEMODE_CC;
|
||||
eon->cache.initialized |= 1 << DC_FIELD_DIVEMODE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "LowSetPoint")) {
|
||||
unsigned int pressure = array_uint32_le(data); // in SI units - Pascal
|
||||
eon->cache.lowsetpoint = pressure / 100000.0; // bar
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(name, "HighSetPoint")) {
|
||||
unsigned int pressure = array_uint32_le(data); // in SI units - Pascal
|
||||
eon->cache.highsetpoint = pressure / 100000.0; // bar
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1174,6 +1454,31 @@ static void initialize_field_caches(suunto_eonsteel_parser_t *eon)
|
||||
eon->cache.divetime /= 1000;
|
||||
}
|
||||
|
||||
static void show_descriptor(suunto_eonsteel_parser_t *eon, int nr, struct type_desc *desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!desc->desc)
|
||||
return;
|
||||
DEBUG(eon->base.context, "Descriptor %d: '%s', size %d bytes", nr, desc->desc, desc->size);
|
||||
if (desc->format)
|
||||
DEBUG(eon->base.context, " format '%s'", desc->format);
|
||||
if (desc->mod)
|
||||
DEBUG(eon->base.context, " mod '%s'", desc->mod);
|
||||
for (i = 0; i < EON_MAX_GROUP; i++) {
|
||||
enum eon_sample type = desc->type[i];
|
||||
if (!type)
|
||||
continue;
|
||||
DEBUG(eon->base.context, " %d: %d (%s)", i, type, desc_type_name(type));
|
||||
}
|
||||
}
|
||||
|
||||
static void show_all_descriptors(suunto_eonsteel_parser_t *eon)
|
||||
{
|
||||
for (unsigned int i = 0; i < MAXTYPE; ++i)
|
||||
show_descriptor(eon, i, eon->type_desc+i);
|
||||
}
|
||||
|
||||
static dc_status_t
|
||||
suunto_eonsteel_parser_set_data(dc_parser_t *parser, const unsigned char *data, unsigned int size)
|
||||
{
|
||||
@ -1182,6 +1487,7 @@ suunto_eonsteel_parser_set_data(dc_parser_t *parser, const unsigned char *data,
|
||||
desc_free(eon->type_desc, MAXTYPE);
|
||||
memset(eon->type_desc, 0, sizeof(eon->type_desc));
|
||||
initialize_field_caches(eon);
|
||||
show_all_descriptors(eon);
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user