Add tank size reporting for Suunto EON Steel

Sadly the data we get from the EON Steel is a bit of a mess.
It doesn't really tell us if the data is metric or imperial (it always sends
both wet volume and working pressure). And in imperial mode the Suunto
engineers seem a bit confused. The pressure given (entered on the dive computer
in psi) is sent to us not in bar, not in atm... it's "something". As far as I
can tell it's a constant factor of 1.00069182389937 different from bar.
And the wet sizes are a bit to small to get the cuft size the user entered.
But instead of trying to guess and fix the mess, we just pass it through...

So this is somewhat useful, but not really what most users will want.

Linus started this commit with a few lines that parsed the right values out of
the data stream from the Suunto EON Steel. I then added the implementation of
the infrastructure to convert the raw data and report it back to the caller.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2015-10-13 19:21:56 -07:00 committed by Jef Driesen
parent decfa24f92
commit eb61dc4c75

View File

@ -22,6 +22,7 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <libdivecomputer/suunto_eonsteel.h>
@ -82,6 +83,9 @@ typedef struct suunto_eonsteel_parser_t {
dc_gasmix_t gasmix[MAXGASES];
dc_salinity_t salinity;
double surface_pressure;
dc_tankvolume_t tankinfo[MAXGASES];
double tanksize[MAXGASES];
double tankworkingpressure[MAXGASES];
} cache;
} suunto_eonsteel_parser_t;
@ -879,6 +883,8 @@ 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))
@ -895,6 +901,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 +915,35 @@ 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_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];
/*
* 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,10 +989,30 @@ 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;
if (idx >= MAXGASES)
return 0;
eon->cache.ngases = idx+1;
switch (type) {
case 0:
tankinfo = 0;
break;
default:
break;
}
eon->cache.tankinfo[idx] = tankinfo;
eon->cache.initialized |= 1 << DC_FIELD_GASMIX_COUNT;
return 0;
}
@ -983,6 +1039,22 @@ 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;
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 {
@ -1066,6 +1138,12 @@ static int traverse_diving_fields(suunto_eonsteel_parser_t *eon, const struct ty
if (!strcmp(name, "Gases.Gas.Helium"))
return add_gas_he(eon, data[0]);
if (!strcmp(name, "Gases.Gas.TankSize"))
return add_gas_size(eon, get_le32_float(data));
if (!strcmp(name, "Gases.Gas.TankFillPressure"))
return add_gas_workpressure(eon, get_le32_float(data));
if (!strcmp(name, "SurfacePressure")) {
unsigned int pressure = array_uint32_le(data); // in SI units - Pascal
eon->cache.surface_pressure = pressure / 100000.0; // bar