First step in cleaning up cylinder pressure sensor logic

This clarifies/changes the meaning of our "cylinderindex" entry in our
samples. It has been rather confused, because different dive computers
have done things differently, and the naming really hasn't helped.

There are two totally different - and independent - cylinder "indexes":

 - the pressure sensor index, which indicates which cylinder the sensor
   data is from.

 - the "active cylinder" index, which indicates which cylinder we actually
   breathe from.

These two values really are totally independent, and have nothing
what-so-ever to do with each other. The sensor index may well be fixed:
many dive computers only support a single pressure sensor (whether
wireless or wired), and the sensor index is thus always zero.

Other dive computers may support multiple pressure sensors, and the gas
switch event may - or may not - indicate that the sensor changed too. A
dive computer might give the sensor data for *all* cylinders it can read,
regardless of which one is the one we're actively breathing. In fact, some
dive computers might give sensor data for not just *your* cylinder, but
your buddies.

This patch renames "cylinderindex" in the samples as "sensor", making it
quite clear that it's about which sensor index the pressure data in the
sample is about.

The way we figure out which is the currently active gas is with an
explicit has change event. If a computer (like the Uemis Zurich) joins the
two concepts together, then a sensor change should also create a gas
switch event. This patch also changes the Uemis importer to do that.

Finally, it should be noted that the plot info works totally separately
from the sample data, and is about what we actually *display*, not about
the sample pressures etc. In the plot info, the "cylinderindex" does in
fact mean the currently active cylinder, and while it is initially set to
match the sensor information from the samples, we then walk the gas change
events and fix it up - and if the active cylinder differs from the sensor
cylinder, we clear the sensor data.

[Dirk Hohndel:  this conflicted with some of my recent changes - I think
		I merged things correctly...]

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Linus Torvalds 2012-12-30 20:00:51 -08:00 committed by Dirk Hohndel
parent df0ea07292
commit d720e133d8
8 changed files with 111 additions and 27 deletions

14
dive.c
View file

@ -237,7 +237,9 @@ static void fixup_pressure(struct dive *dive, struct sample *sample)
pressure = sample->cylinderpressure.mbar;
if (!pressure)
return;
index = sample->cylinderindex;
index = sample->sensor;
/* FIXME! sensor -> cylinder mapping? */
if (index >= MAX_CYLINDERS)
return;
cyl = dive->cylinder + index;
@ -427,7 +429,7 @@ struct dive *fixup_dive(struct dive *dive)
int depth = sample->depth.mm;
int temp = sample->temperature.mkelvin;
int pressure = sample->cylinderpressure.mbar;
int index = sample->cylinderindex;
int index = sample->sensor;
if (index == lastindex) {
/* Remove duplicate redundant pressure information */
@ -502,7 +504,7 @@ struct dive *fixup_dive(struct dive *dive)
if (abs(pressure_delta[j]) != INT_MAX) {
cylinder_t *cyl = dive->cylinder + j;
for (i = 0; i < dc->samples; i++)
if (dc->sample[i].cylinderindex == j)
if (dc->sample[i].sensor == j)
dc->sample[i].cylinderpressure.mbar = 0;
if (! cyl->start.mbar)
cyl->start.mbar = cyl->sample_start.mbar;
@ -709,8 +711,8 @@ add_sample_b:
sample.temperature = as->temperature;
if (as->cylinderpressure.mbar)
sample.cylinderpressure = as->cylinderpressure;
if (as->cylinderindex)
sample.cylinderindex = as->cylinderindex;
if (as->sensor)
sample.sensor = as->sensor;
if (as->cns)
sample.cns = as->cns;
if (as->po2)
@ -1291,7 +1293,7 @@ static int same_sample(struct sample *a, struct sample *b)
return 0;
if (a->cylinderpressure.mbar != b->cylinderpressure.mbar)
return 0;
return a->cylinderindex == b->cylinderindex;
return a->sensor == b->sensor;
}
static int same_dc(struct divecomputer *a, struct divecomputer *b)

3
dive.h
View file

@ -226,7 +226,7 @@ struct sample {
depth_t depth;
temperature_t temperature;
pressure_t cylinderpressure;
int cylinderindex;
int sensor; /* Cylinder pressure sensor index */
duration_t ndl;
duration_t stoptime;
depth_t stopdepth;
@ -503,6 +503,7 @@ extern struct dive *try_to_merge(struct dive *a, struct dive *b, gboolean prefer
extern void renumber_dives(int nr);
extern void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int time, int idx);
extern void add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name);
/* UI related protopypes */

View file

@ -715,6 +715,24 @@ static void cns_data_func(GtkTreeViewColumn *col,
g_object_set(renderer, "text", buffer, NULL);
}
static int active_o2(struct dive *dive, struct divecomputer *dc, duration_t time)
{
int o2permille = dive->cylinder[0].gasmix.o2.permille;
struct event *event = dc->events;
if (!o2permille)
o2permille = AIR_PERMILLE;
for (event = dc->events; event; event = event->next) {
if (event->time.seconds > time.seconds)
break;
if (strcmp(event->name, "gaschange"))
continue;
o2permille = 10*(event->value & 0xffff);
}
return o2permille;
}
/* calculate OTU for a dive */
static int calculate_otu(struct dive *dive, struct divecomputer *dc)
{
@ -730,9 +748,7 @@ static int calculate_otu(struct dive *dive, struct divecomputer *dc)
if (sample->po2) {
po2 = sample->po2;
} else {
int o2 = dive->cylinder[sample->cylinderindex].gasmix.o2.permille;
if (!o2)
o2 = AIR_PERMILLE;
int o2 = active_o2(dive, dc, sample->time);
po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive) / 1000.0;
}
if (po2 >= 0.5)

View file

@ -209,7 +209,7 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
sample->depth.mm = value.depth * 1000 + 0.5;
break;
case DC_SAMPLE_PRESSURE:
sample->cylinderindex = value.pressure.tank;
sample->sensor = value.pressure.tank;
sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
break;
case DC_SAMPLE_TEMPERATURE:

View file

@ -155,6 +155,7 @@ static gboolean in_settings = FALSE;
static struct tm cur_tm;
static int cur_cylinder_index, cur_ws_index;
static int lastndl, laststoptime, laststopdepth, lastcns, lastpo2, lastindeco;
static int lastcylinderindex, lastsensor;
static enum import_source {
UNKNOWN,
@ -650,6 +651,39 @@ static void try_to_fill_dc(struct divecomputer *dc, const char *name, char *buf)
nonmatch("divecomputer", name, buf);
}
void add_gas_switch_event(struct dive *dive, struct divecomputer *dc, int seconds, int idx)
{
/* The gas switch event format is insane. It will be fixed, I think */
int o2 = dive->cylinder[idx].gasmix.o2.permille;
int he = dive->cylinder[idx].gasmix.he.permille;
int value;
if (!o2)
o2 = AIR_PERMILLE;
o2 = (o2+5) / 10;
he = (he+5) / 10;
value = o2 + (he << 16);
add_event(dc, seconds, 11, 0, value, "gaschange");
}
static void get_cylinderindex(char *buffer, void *_i)
{
int *i = _i;
*i = atoi(buffer);
if (lastcylinderindex != *i) {
add_gas_switch_event(cur_dive, cur_dc, cur_sample->time.seconds, *i);
lastcylinderindex = *i;
}
}
static void get_sensor(char *buffer, void *_i)
{
int *i = _i;
*i = atoi(buffer);
lastsensor = *i;
}
/* We're in samples - try to convert the random xml value to something useful */
static void try_to_fill_sample(struct sample *sample, const char *name, char *buf)
{
@ -661,7 +695,9 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
return;
if (MATCH(".sample.cylpress", pressure, &sample->cylinderpressure))
return;
if (MATCH(".sample.cylinderindex", get_index, &sample->cylinderindex))
if (MATCH(".sample.cylinderindex", get_cylinderindex, &sample->sensor))
return;
if (MATCH(".sample.sensor", get_sensor, &sample->sensor))
return;
if (MATCH(".sample.depth", depth, &sample->depth))
return;
@ -1005,6 +1041,7 @@ static gboolean is_dive(void)
static void reset_dc_info(struct divecomputer *dc)
{
lastcns = lastpo2 = lastndl = laststoptime = laststopdepth = lastindeco = 0;
lastsensor = lastcylinderindex = 0;
}
static void reset_dc_settings(void)
@ -1129,6 +1166,7 @@ static void sample_start(void)
cur_sample->stopdepth.mm = laststopdepth;
cur_sample->cns = lastcns;
cur_sample->po2 = lastpo2;
cur_sample->sensor = lastsensor;
}
static void sample_end(void)

View file

@ -1644,7 +1644,8 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
entry->in_deco = in_deco;
entry->cns = cns;
entry->po2 = po2;
entry->cylinderindex = sample->cylinderindex;
/* FIXME! sensor index -> cylinder index translation! */
entry->cylinderindex = sample->sensor;
SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar;
entry->temperature = sample->temperature.mkelvin;

View file

@ -319,27 +319,50 @@ static void show_index(FILE *f, int value, const char *pre, const char *post)
fprintf(f, " %s%d%s", pre, value, post);
}
static void save_sample(FILE *f, struct sample *sample, const struct sample *prev)
static void save_sample(FILE *f, struct sample *sample, struct sample *old)
{
fprintf(f, " <sample time='%u:%02u min'", FRACTION(sample->time.seconds,60));
show_milli(f, " depth='", sample->depth.mm, " m", "'");
show_temperature(f, sample->temperature, " temp='", "'");
show_pressure(f, sample->cylinderpressure, " pressure='", "'");
if (sample->cylinderindex)
fprintf(f, " cylinderindex='%d'", sample->cylinderindex);
/*
* We only show sensor information for samples with pressure, and only if it
* changed from the previous sensor we showed.
*/
if (sample->cylinderpressure.mbar && sample->sensor != old->sensor) {
fprintf(f, " sensor='%d'", sample->sensor);
old->sensor = sample->sensor;
}
/* the deco/ndl values are stored whenever they change */
if (sample->ndl.seconds != prev->ndl.seconds)
if (sample->ndl.seconds != old->ndl.seconds) {
fprintf(f, " ndl='%u:%02u min'", FRACTION(sample->ndl.seconds, 60));
if (sample->in_deco != prev->in_deco)
old->ndl = sample->ndl;
}
if (sample->in_deco != old->in_deco) {
fprintf(f, " in_deco='%d'", sample->in_deco ? 1 : 0);
if (sample->stoptime.seconds != prev->stoptime.seconds)
old->in_deco = sample->in_deco;
}
if (sample->stoptime.seconds != old->stoptime.seconds) {
fprintf(f, " stoptime='%u:%02u min'", FRACTION(sample->stoptime.seconds, 60));
if (sample->stopdepth.mm != prev->stopdepth.mm)
old->stoptime = sample->stoptime;
}
if (sample->stopdepth.mm != old->stopdepth.mm) {
show_milli(f, " stopdepth='", sample->stopdepth.mm, " m", "'");
if (sample->cns != prev->cns)
old->stopdepth = sample->stopdepth;
}
if (sample->cns != old->cns) {
fprintf(f, " cns='%u%%'", sample->cns);
if (sample->po2 != prev->po2)
old->cns = sample->cns;
}
if (sample->po2 != old->po2) {
fprintf(f, " po2='%u.%2u bar'", FRACTION(sample->po2, 1000));
old->po2 = sample->po2;
}
fprintf(f, " />\n");
}
@ -376,12 +399,10 @@ static void show_date(FILE *f, timestamp_t when)
static void save_samples(FILE *f, int nr, struct sample *s)
{
static const struct sample empty_sample;
const struct sample *prev = &empty_sample;
struct sample dummy = { };
while (--nr >= 0) {
save_sample(f, s, prev);
prev = s;
save_sample(f, s, &dummy);
s++;
}
}

View file

@ -291,6 +291,7 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
struct dive *dive = datap;
struct divecomputer *dc = &dive->dc;
int template, gasoffset;
int active = 0;
datalen = uemis_convert_base64(base64, &data);
@ -345,11 +346,15 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
* duration in the header is a) in minutes and b) up to 3 minutes short */
if (u_sample->dive_time > dive->duration.seconds + 180)
break;
if (u_sample->active_tank != active) {
active = u_sample->active_tank;
add_gas_switch_event(dive, dc, u_sample->dive_time, active);
}
sample = prepare_sample(dc);
sample->time.seconds = u_sample->dive_time;
sample->depth.mm = rel_mbar_to_depth(u_sample->water_pressure, dive);
sample->temperature.mkelvin = (u_sample->dive_temperature * 100) + 273150;
sample->cylinderindex = u_sample->active_tank;
sample->sensor = active;
sample->cylinderpressure.mbar =
(u_sample->tank_pressure_high * 256 + u_sample->tank_pressure_low) * 10;
sample->cns = u_sample->cns;