EON Steel: start moving away from "fixed" fields

I was initially fooled into thinking that the field type numbers have
some meaning: the types didn't change if the upper byte of the type
number was zero.  So I assumed that meant "fixed".

But the most recent firmware update made clear that no, they aren't
fixed, and the upper byte of the type must be some other thing.

This moves some more of the parsing over to comparing the strings,
rather than looking at the type index.  It still leaves the sample data
alone, and I really want to do something more efficient than comparing
the type descriptor string for that, but at least the dive header fields
are now just comparing strings.

The actual marshalling that Suunto uses also describes the encoding, and
it's all ignoring that for now.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2015-06-08 09:30:57 -07:00 committed by Jef Driesen
parent a701cc9309
commit af3e099c55

View File

@ -605,30 +605,41 @@ static void set_depth_field(suunto_eonsteel_parser_t *eon, unsigned short d)
}
}
// gas type: 0=Off,1=Primary,2=?,3=Diluent
static void add_gas_type(suunto_eonsteel_parser_t *eon, unsigned char type)
// new gas:
// "sml.DeviceLog.Header.Diving.Gases+Gas.State"
//
// We eventually need to parse the descriptor for that 'enum type'.
// Two versions so far:
// "enum:0=Off,1=Primary,2=?,3=Diluent"
// "enum:0=Off,1=Primary,3=Diluent,4=Oxygen"
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++;
eon->cache.initialized |= 1 << DC_FIELD_GASMIX_COUNT;
return 0;
}
// "sml.DeviceLog.Header.Diving.Gases.Gas.Oxygen"
// O2 percentage as a byte
static void add_gas_o2(suunto_eonsteel_parser_t *eon, unsigned char o2)
static int add_gas_o2(suunto_eonsteel_parser_t *eon, unsigned char o2)
{
int idx = eon->cache.ngases-1;
if (idx >= 0)
eon->cache.gasmix[idx].oxygen = o2 / 100.0;
eon->cache.initialized |= 1 << DC_FIELD_GASMIX;
return 0;
}
// "sml.DeviceLog.Header.Diving.Gases.Gas.Helium"
// He percentage as a byte
static void add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he)
static int add_gas_he(suunto_eonsteel_parser_t *eon, unsigned char he)
{
int idx = eon->cache.ngases-1;
if (idx >= 0)
eon->cache.gasmix[idx].helium = he / 100.0;
eon->cache.initialized |= 1 << DC_FIELD_GASMIX;
return 0;
}
static float get_le32_float(const unsigned char *src)
@ -650,57 +661,71 @@ static float get_le32_float(const unsigned char *src)
// Info.SW
// Name
// SerialNumber
static int traverse_device_fields(suunto_eonsteel_parser_t *eon, const char *name, const void *data, int len)
static int 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;
}
// "Header" fields are:
// Activity (utf8)
// DateTime (utf8)
// Depth.Avg (float32,precision=2)
// Depth.Max (float32,precision=2)
// Diving.AlgorithmAscentTime (uint32)
// Diving.AlgorithmBottomMixture.Helium (uint8,precision=2) (0.01*x,100*x)
// Diving.AlgorithmBottomMixture.Oxygen (uint8,precision=2) (0.01*x,100*x)
// Diving.AlgorithmBottomTime (uint32)
// Diving.AlgorithmTransitionDepth (uint8)
// Diving.Algorithm (utf8)
// Diving.Altitude (uint16)
// Diving.Conservatism (int8)
// Diving.DaysInSeries (uint32)
// Diving.DesaturationTime (uint32)
// Diving.DiveMode (utf8)
// Diving.EndTissue.CNS (float32,precision=3)
// Diving.EndTissue.Helium+Pressure (uint32)
// Diving.EndTissue.Nitrogen+Pressure (uint32)
// Diving.EndTissue.OLF (float32,precision=3)
// Diving.EndTissue.OTU (float32)
// Diving.EndTissue.RgbmHelium (float32,precision=3)
// Diving.EndTissue.RgbmNitrogen (float32,precision=3)
// Diving.NumberInSeries (uint32)
// Diving.PreviousDiveDepth (float32,precision=2)
// Diving.StartTissue.CNS (float32,precision=3)
// Diving.StartTissue.Helium+Pressure (uint32)
// Diving.StartTissue.Nitrogen+Pressure (uint32)
// Diving.StartTissue.OLF (float32,precision=3)
// Diving.StartTissue.OTU (float32)
// Diving.StartTissue.RgbmHelium (float32,precision=3)
// Diving.StartTissue.RgbmNitrogen (float32,precision=3)
// Diving.SurfacePressure (uint32)
// Diving.SurfaceTime (uint32)
// Duration (uint32)
// PauseDuration (uint32)
// SampleInterval (uint8)
static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const char *name, const void *data, int len)
// "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)
// SurfacePressure (uint32)
// Conservatism (int8)
// Altitude (uint16)
// AlgorithmTransitionDepth (uint8)
// DaysInSeries (uint32)
// PreviousDiveDepth (float32,precision=2)
// StartTissue.CNS (float32,precision=3)
// StartTissue.OTU (float32)
// StartTissue.OLF (float32,precision=3)
// StartTissue.Nitrogen+Pressure (uint32)
// StartTissue.Helium+Pressure (uint32)
// StartTissue.RgbmNitrogen (float32,precision=3)
// StartTissue.RgbmHelium (float32,precision=3)
// DiveMode (utf8)
// AlgorithmBottomTime (uint32)
// AlgorithmAscentTime (uint32)
// AlgorithmBottomMixture.Oxygen (uint8,precision=2)
// AlgorithmBottomMixture.Helium (uint8,precision=2)
// DesaturationTime (uint32)
// EndTissue.CNS (float32,precision=3)
// EndTissue.OTU (float32)
// EndTissue.OLF (float32,precision=3)
// EndTissue.Nitrogen+Pressure (uint32)
// 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)
{
if (!strcmp(name, "Depth.Max")) {
double d = get_le32_float(data);
if (d > eon->cache.maxdepth)
eon->cache.maxdepth = d;
return 0;
}
if (!strcmp(name, "Diving.SurfacePressure")) {
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 (!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;
@ -710,7 +735,34 @@ static int traverse_header_fields(suunto_eonsteel_parser_t *eon, const char *nam
return 0;
}
static int traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, const void *data, int len)
// "Header" fields are:
// Activity (utf8)
// DateTime (utf8)
// Depth.Avg (float32,precision=2)
// Depth.Max (float32,precision=2)
// Diving.*
// 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)
{
const char *name = desc->desc + strlen("sml.DeviceLog.Header.");
if (!strncmp(name, "Diving.", 7))
return traverse_diving_fields(eon, desc, data, len);
if (!strcmp(name, "Depth.Max")) {
double d = get_le32_float(data);
if (d > eon->cache.maxdepth)
eon->cache.maxdepth = d;
return 0;
}
return 0;
}
static int traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct type_desc *desc, const unsigned char *data, int len)
{
const char *name = desc->desc;
@ -719,9 +771,9 @@ static int traverse_dynamic_fields(suunto_eonsteel_parser_t *eon, const struct t
if (!strncmp(name, "DeviceLog.", 10)) {
name += 10;
if (!strncmp(name, "Device.", 7))
return traverse_device_fields(eon, name+7, data, len);
return traverse_device_fields(eon, desc, data, len);
if (!strncmp(name, "Header.", 7)) {
return traverse_header_fields(eon, name+7, data, len);
return traverse_header_fields(eon, desc, data, len);
}
}
}
@ -743,21 +795,8 @@ static int traverse_fields(unsigned short type, const struct type_desc *desc, co
case 0x0003: // depth in first word
set_depth_field(eon, array_uint16_le(data));
break;
case 0x000d: // gas state in first byte
add_gas_type(eon, data[0]);
break;
case 0x000e: // Oxygen percentage in first byte
add_gas_o2(eon, data[0]);
break;
case 0x000f: // Helium percentage in first byte
add_gas_he(eon, data[0]);
break;
default:
// The types with the high byte set seem to be dynamic
// although not all of them seem to change. But let's
// just check the descriptor name for them.
if (type > 255)
traverse_dynamic_fields(eon, desc, data, len);
traverse_dynamic_fields(eon, desc, data, len);
break;
}
return 0;