summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2014-08-17 12:26:21 -0600
committerGravatar Dirk Hohndel <dirk@hohndel.org>2014-10-12 07:45:37 -0400
commitdf4e26c8757a81bb40ba2fd60431d5d1ecd64b11 (patch)
treea7f46fb0a25a5131a42727ab0ca770f2fc0c8f30
parentb47e0658cf5e60e18d4c9405e3b28f196ac3e2d8 (diff)
downloadsubsurface-df4e26c8757a81bb40ba2fd60431d5d1ecd64b11.tar.gz
Start sanitizing gaschange event information
Decode the gasmix data into a sane format when creating the event, and add the (currently unused) ability to specify a gas change to a particular cylinder rather than (or in addition to) the gasmix. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--dive.c68
-rw-r--r--dive.h22
-rw-r--r--load-git.c21
-rw-r--r--parse-xml.c136
-rw-r--r--profile.c22
-rw-r--r--qt-ui/profile/diveeventitem.cpp8
-rw-r--r--save-git.c27
-rw-r--r--save-xml.c27
8 files changed, 234 insertions, 97 deletions
diff --git a/dive.c b/dive.c
index 9972212aa..e7bf685e6 100644
--- a/dive.c
+++ b/dive.c
@@ -26,7 +26,31 @@ static const char *default_tags[] = {
QT_TRANSLATE_NOOP("gettextFromC", "deco")
};
-void add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name)
+int event_is_gaschange(struct event *ev)
+{
+ return ev->type == SAMPLE_EVENT_GASCHANGE ||
+ ev->type == SAMPLE_EVENT_GASCHANGE2;
+}
+
+/*
+ * Does the gas mix data match the legacy
+ * libdivecomputer event format? If so,
+ * we can skip saving it, in order to maintain
+ * the old save formats. We'll re-generate the
+ * gas mix when loading.
+ */
+int event_gasmix_redundant(struct event *ev)
+{
+ int value = ev->value;
+ int o2, he;
+
+ o2 = (value & 0xffff) * 10;
+ he = (value >> 16) * 10;
+ return o2 == ev->gas.mix.o2.permille &&
+ he == ev->gas.mix.he.permille;
+}
+
+struct event *add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name)
{
struct event *ev, **p;
unsigned int size, len = strlen(name);
@@ -34,7 +58,7 @@ void add_event(struct divecomputer *dc, int time, int type, int flags, int value
size = sizeof(*ev) + len + 1;
ev = malloc(size);
if (!ev)
- return;
+ return NULL;
memset(ev, 0, size);
memcpy(ev->name, name, len);
ev->time.seconds = time;
@@ -42,6 +66,22 @@ void add_event(struct divecomputer *dc, int time, int type, int flags, int value
ev->flags = flags;
ev->value = value;
+ /*
+ * Expand the events into a sane format. Currently
+ * just gas switches
+ */
+ switch (type) {
+ case SAMPLE_EVENT_GASCHANGE2:
+ /* High 16 bits are He percentage */
+ ev->gas.mix.he.permille = (value >> 16) * 10;
+ /* Fallthrough */
+ case SAMPLE_EVENT_GASCHANGE:
+ /* Low 16 bits are O2 percentage */
+ ev->gas.mix.o2.permille = (value & 0xffff) * 10;
+ ev->gas.index = -1;
+ break;
+ }
+
p = &dc->events;
/* insert in the sorted list of events */
@@ -50,6 +90,7 @@ void add_event(struct divecomputer *dc, int time, int type, int flags, int value
ev->next = *p;
*p = ev;
remember_event(name);
+ return ev;
}
static int same_event(struct event *a, struct event *b)
@@ -107,14 +148,11 @@ void update_event_name(struct dive *d, struct event *event, char *name)
/* this returns a pointer to static variable - so use it right away after calling */
struct gasmix *get_gasmix_from_event(struct event *ev)
{
- static struct gasmix g;
- g.o2.permille = g.he.permille = 0;
- if (ev && (ev->type == SAMPLE_EVENT_GASCHANGE || ev->type == SAMPLE_EVENT_GASCHANGE2)) {
- g.o2.permille = 10 * ev->value & 0xffff;
- if (ev->type == SAMPLE_EVENT_GASCHANGE2)
- g.he.permille = 10 * (ev->value >> 16);
- }
- return &g;
+ static struct gasmix dummy;
+ if (ev && event_is_gaschange(ev))
+ return &ev->gas.mix;
+
+ return &dummy;
}
int get_pressure_units(int mb, const char **units)
@@ -1543,6 +1581,7 @@ static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc)
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, int mapping[])
{
int i;
+ struct event *ev;
/* Did the first gas get remapped? Add gas switch event */
if (mapping[0] > 0)
@@ -1559,6 +1598,15 @@ static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, int
if (sensor >= 0)
s->sensor = sensor;
}
+
+ /* Remap the gas change indexes */
+ for (ev = dc->events; ev; ev = ev->next) {
+ if (!event_is_gaschange(ev))
+ continue;
+ if (ev->gas.index < 0)
+ continue;
+ ev->gas.index = mapping[ev->gas.index];
+ }
}
/*
diff --git a/dive.h b/dive.h
index eb8909118..55396d8fe 100644
--- a/dive.h
+++ b/dive.h
@@ -85,11 +85,29 @@ typedef struct
struct event {
struct event *next;
duration_t time;
- int type, flags, value;
+ int type;
+ /* This is the annoying libdivecomputer format. */
+ int flags, value;
+ /* .. and this is our "extended" data for some event types */
+ union {
+ /*
+ * Currently only for gas switch events.
+ *
+ * NOTE! The index may be -1, which means "unknown". In that
+ * case, the get_cylinder_index() function will give the best
+ * match with the cylinders in the dive based on gasmix.
+ */
+ struct {
+ int index;
+ struct gasmix mix;
+ } gas;
+ };
bool deleted;
char name[];
};
+extern int event_is_gaschange(struct event *ev);
+extern int event_gasmix_redundant(struct event *ev);
extern int get_pressure_units(int mb, const char **units);
extern double get_depth_units(int mm, int *frac, const char **units);
@@ -651,7 +669,7 @@ extern void copy_samples(struct divecomputer *s, struct divecomputer *d);
extern bool is_cylinder_used(struct dive *dive, int idx);
extern void fill_default_cylinder(cylinder_t *cyl);
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);
+extern struct event *add_event(struct divecomputer *dc, int time, int type, int flags, int value, const char *name);
extern void remove_event(struct event *event);
extern void update_event_name(struct dive *d, struct event* event, char *name);
extern void per_cylinder_mean_depth(struct dive *dive, struct divecomputer *dc, int *mean, int *duration);
diff --git a/load-git.c b/load-git.c
index e61a0ca13..16aa1958f 100644
--- a/load-git.c
+++ b/load-git.c
@@ -529,6 +529,13 @@ static void parse_event_keyvalue(void *_event, const char *key, const char *valu
event->value = val;
} else if (!strcmp(key, "name")) {
/* We get the name from the string handling */
+ } else if (!strcmp(key, "cylinder")) {
+ /* NOTE! We add one here as a marker that "yes, we got a cylinder index" */
+ event->gas.index = 1+get_index(value);
+ } else if (!strcmp(key, "o2")) {
+ event->gas.mix.o2 = get_fraction(value);
+ } else if (!strcmp(key, "he")) {
+ event->gas.mix.he = get_fraction(value);
} else
report_error("Unexpected event key/value pair (%s/%s)", key, value);
}
@@ -538,7 +545,7 @@ static void parse_dc_event(char *line, struct membuffer *str, void *_dc)
int m, s = 0;
const char *name;
struct divecomputer *dc = _dc;
- struct event event = { 0 };
+ struct event event = { 0 }, *ev;
m = strtol(line, &line, 10);
if (*line == ':')
@@ -557,7 +564,17 @@ static void parse_dc_event(char *line, struct membuffer *str, void *_dc)
name = "";
if (str->len)
name = mb_cstring(str);
- add_event(dc, event.time.seconds, event.type, event.flags, event.value, name);
+ ev = add_event(dc, event.time.seconds, event.type, event.flags, event.value, name);
+ if (ev && event_is_gaschange(ev)) {
+ /*
+ * We subtract one here because "0" is "no index",
+ * and the parsing will add one for actual cylinder
+ * index data (see parse_event_keyvalue)
+ */
+ ev->gas.index = event.gas.index-1;
+ if (event.gas.mix.o2.permille || event.gas.mix.he.permille)
+ ev->gas.mix = event.gas.mix;
+ }
}
static void parse_trip_date(char *line, struct membuffer *str, void *_trip)
diff --git a/parse-xml.c b/parse-xml.c
index 6e74e8aaf..e88c9b944 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -95,17 +95,17 @@ const struct units IMPERIAL_units = IMPERIAL_UNITS;
/*
* Dive info as it is being built up..
*/
+#define MAX_EVENT_NAME 128
static struct divecomputer *cur_dc;
static struct dive *cur_dive;
static dive_trip_t *cur_trip = NULL;
static struct sample *cur_sample;
static struct picture *cur_picture;
-static struct {
- int active;
- duration_t time;
- int type, flags, value;
- const char *name;
-} cur_event;
+static union {
+ struct event event;
+ char allocation[sizeof(struct event)+MAX_EVENT_NAME];
+} event_allocation = { .event.deleted = 1 };
+#define cur_event event_allocation.event
static struct {
struct {
const char *model;
@@ -527,6 +527,15 @@ static void utf8_string(char *buffer, void *_res)
*res = strdup(buffer);
}
+static void event_name(char *buffer, char *name)
+{
+ int size = trimspace(buffer);
+ if (size >= MAX_EVENT_NAME)
+ size = MAX_EVENT_NAME-1;
+ memcpy(name, buffer, size);
+ name[size] = 0;
+}
+
/* Extract the dive computer type from the xml text buffer */
static void get_dc_type(char *buffer, enum dive_comp_type *i)
{
@@ -704,16 +713,22 @@ static void try_to_match_autogroup(const char *name, char *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 = get_o2(&dive->cylinder[idx].gasmix);
- int he = get_he(&dive->cylinder[idx].gasmix);
+ /* The gas switch event format is insane for historical reasons */
+ struct gasmix *mix = &dive->cylinder[idx].gasmix;
+ int o2 = get_o2(mix);
+ int he = get_he(mix);
+ struct event *ev;
int value;
o2 = (o2 + 5) / 10;
he = (he + 5) / 10;
value = o2 + (he << 16);
- add_event(dc, seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
+ ev = add_event(dc, seconds, he ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE, 0, value, "gaschange");
+ if (ev) {
+ ev->gas.index = idx;
+ ev->gas.mix = *mix;
+ }
}
static void get_cylinderindex(char *buffer, uint8_t *i)
@@ -751,9 +766,9 @@ static void try_to_fill_dc_settings(const char *name, char *buf)
static void try_to_fill_event(const char *name, char *buf)
{
start_match("event", name, buf);
- if (MATCH("event", utf8_string, &cur_event.name))
+ if (MATCH("event", event_name, cur_event.name))
return;
- if (MATCH("name", utf8_string, &cur_event.name))
+ if (MATCH("name", event_name, cur_event.name))
return;
if (MATCH("time", eventtime, &cur_event.time))
return;
@@ -763,6 +778,15 @@ static void try_to_fill_event(const char *name, char *buf)
return;
if (MATCH("value", get_index, &cur_event.value))
return;
+ if (MATCH("cylinder", get_index, &cur_event.gas.index)) {
+ /* We add one to indicate that we got an actual cylinder index value */
+ cur_event.gas.index++;
+ return;
+ }
+ if (MATCH("o2", percent, &cur_event.gas.mix.o2))
+ return;
+ if (MATCH("he", percent, &cur_event.gas.mix.he))
+ return;
nonmatch("event", name, buf);
}
@@ -1332,36 +1356,38 @@ static void trip_end(void)
static void event_start(void)
{
memset(&cur_event, 0, sizeof(cur_event));
- cur_event.active = 1;
+ cur_event.deleted = 0; /* Active */
}
static void event_end(void)
{
struct divecomputer *dc = get_dc();
- if (cur_event.name) {
- if (strcmp(cur_event.name, "surface") != 0) {
- /* 123 is a magic event that we used for a while to encode images in dives */
- if (cur_event.type == 123) {
- struct picture *pic = alloc_picture();
- pic->filename = strdup(cur_event.name);
- /* theoretically this could fail - but we didn't support multi year offsets */
- pic->offset.seconds = cur_event.time.seconds;
- dive_add_picture(cur_dive, pic);
- } else {
- /* At some point gas change events did not have any type. Thus we need to add
- * one on import, if we encounter the type one missing.
- */
- if (cur_event.type == 0 && strcmp(cur_event.name, "gaschange") == 0)
- cur_event.type = cur_event.value >> 16 > 0 ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE;
-
- add_event(dc, cur_event.time.seconds,
- cur_event.type, cur_event.flags,
- cur_event.value, cur_event.name);
+ if (strcmp(cur_event.name, "surface") != 0) { /* 123 is a magic event that we used for a while to encode images in dives */
+ if (cur_event.type == 123) {
+ struct picture *pic = alloc_picture();
+ pic->filename = strdup(cur_event.name);
+ /* theoretically this could fail - but we didn't support multi year offsets */
+ pic->offset.seconds = cur_event.time.seconds;
+ dive_add_picture(cur_dive, pic);
+ } else {
+ struct event *ev;
+ /* At some point gas change events did not have any type. Thus we need to add
+ * one on import, if we encounter the type one missing.
+ */
+ if (cur_event.type == 0 && strcmp(cur_event.name, "gaschange") == 0)
+ cur_event.type = cur_event.value >> 16 > 0 ? SAMPLE_EVENT_GASCHANGE2 : SAMPLE_EVENT_GASCHANGE;
+ ev = add_event(dc, cur_event.time.seconds,
+ cur_event.type, cur_event.flags,
+ cur_event.value, cur_event.name);
+ if (ev && event_is_gaschange(ev)) {
+ /* See try_to_fill_event() on why the filled-in index is one too big */
+ ev->gas.index = cur_event.gas.index-1;
+ if (cur_event.gas.mix.o2.permille || cur_event.gas.mix.he.permille)
+ ev->gas.mix = cur_event.gas.mix;
}
}
- free((void *)cur_event.name);
}
- cur_event.active = 0;
+ cur_event.deleted = 1; /* No longer active */
}
static void picture_start(void)
@@ -1472,7 +1498,7 @@ static void entry(const char *name, char *buf)
try_to_match_autogroup(name, buf);
return;
}
- if (cur_event.active) {
+ if (!cur_event.deleted) {
try_to_fill_event(name, buf);
return;
}
@@ -1722,71 +1748,71 @@ extern int dm4_events(void *handle, int columns, char **data, char **column)
switch (atoi(data[2])) {
case 1:
/* 1 Mandatory Safety Stop */
- cur_event.name = strdup("safety stop (mandatory)");
+ strcpy(cur_event.name, "safety stop (mandatory)");
break;
case 3:
/* 3 Deco */
/* What is Subsurface's term for going to
* deco? */
- cur_event.name = strdup("deco");
+ strcpy(cur_event.name, "deco");
break;
case 4:
/* 4 Ascent warning */
- cur_event.name = strdup("ascent");
+ strcpy(cur_event.name, "ascent");
break;
case 5:
/* 5 Ceiling broken */
- cur_event.name = strdup("violation");
+ strcpy(cur_event.name, "violation");
break;
case 6:
/* 6 Mandatory safety stop ceiling error */
- cur_event.name = strdup("violation");
+ strcpy(cur_event.name, "violation");
break;
case 7:
/* 7 Below deco floor */
- cur_event.name = strdup("below floor");
+ strcpy(cur_event.name, "below floor");
break;
case 8:
/* 8 Dive time alarm */
- cur_event.name = strdup("divetime");
+ strcpy(cur_event.name, "divetime");
break;
case 9:
/* 9 Depth alarm */
- cur_event.name = strdup("maxdepth");
+ strcpy(cur_event.name, "maxdepth");
break;
case 10:
/* 10 OLF 80% */
case 11:
/* 11 OLF 100% */
- cur_event.name = strdup("OLF");
+ strcpy(cur_event.name, "OLF");
break;
case 12:
/* 12 High pO₂ */
- cur_event.name = strdup("PO2");
+ strcpy(cur_event.name, "PO2");
break;
case 13:
/* 13 Air time */
- cur_event.name = strdup("airtime");
+ strcpy(cur_event.name, "airtime");
break;
case 17:
/* 17 Ascent warning */
- cur_event.name = strdup("ascent");
+ strcpy(cur_event.name, "ascent");
break;
case 18:
/* 18 Ceiling error */
- cur_event.name = strdup("ceiling");
+ strcpy(cur_event.name, "ceiling");
break;
case 19:
/* 19 Surfaced */
- cur_event.name = strdup("surface");
+ strcpy(cur_event.name, "surface");
break;
case 20:
/* 20 Deco */
- cur_event.name = strdup("deco");
+ strcpy(cur_event.name, "deco");
break;
case 22:
/* 22 Mandatory safety stop violation */
- cur_event.name = strdup("violation");
+ strcpy(cur_event.name, "violation");
break;
case 257:
/* 257 Dive active */
@@ -1796,14 +1822,14 @@ extern int dm4_events(void *handle, int columns, char **data, char **column)
case 258:
/* 258 Bookmark */
if (data[3]) {
- cur_event.name = strdup("heading");
+ strcpy(cur_event.name, "heading");
cur_event.value = atoi(data[3]);
} else {
- cur_event.name = strdup("bookmark");
+ strcpy(cur_event.name, "bookmark");
}
break;
default:
- cur_event.name = strdup("unknown");
+ strcpy(cur_event.name, "unknown");
cur_event.value = atoi(data[2]);
break;
}
@@ -1986,7 +2012,7 @@ extern int shearwater_changes(void *handle, int columns, char **data, char **col
if (data[0])
cur_event.time.seconds = atoi(data[0]);
if (data[1]) {
- cur_event.name = strdup("gaschange");
+ strcpy(cur_event.name, "gaschange");
cur_event.value = atof(data[1]) * 100;
}
event_end();
diff --git a/profile.c b/profile.c
index 71a9164e6..79917d6e6 100644
--- a/profile.c
+++ b/profile.c
@@ -289,6 +289,14 @@ struct plot_info *analyze_plot_info(struct plot_info *pi)
return pi;
}
+/*
+ * If the event has an explicit cylinder index,
+ * we return that. If it doesn't, we return the best
+ * match based on the gasmix.
+ *
+ * Some dive computers give cylinder indexes, some
+ * give just the gas mix.
+ */
int get_cylinder_index(struct dive *dive, struct event *ev)
{
int i;
@@ -296,10 +304,9 @@ int get_cylinder_index(struct dive *dive, struct event *ev)
int target_o2, target_he;
struct gasmix *g;
- /*
- * Crazy gas change events give us odd encoded o2/he in percent.
- * Decode into our internal permille format.
- */
+ if (ev->gas.index >= 0)
+ return ev->gas.index;
+
g = get_gasmix_from_event(ev);
target_o2 = get_o2(g);
target_he = get_he(g);
@@ -318,13 +325,8 @@ int get_cylinder_index(struct dive *dive, struct event *ev)
delta_o2 = get_o2(&cyl->gasmix) - target_o2;
delta_he = get_he(&cyl->gasmix) - target_he;
distance = delta_o2 * delta_o2;
+ distance += delta_he * delta_he;
- /* Check the event type to figure out if we should care about the he part.
- * SAMPLE_EVENT_GASCHANGE, aka without he
- * SAMPLE_EVENT_GASCHANGE2, aka with he
- */
- if (ev->type == SAMPLE_EVENT_GASCHANGE2)
- distance += delta_he * delta_he;
if (distance >= score)
continue;
score = distance;
diff --git a/qt-ui/profile/diveeventitem.cpp b/qt-ui/profile/diveeventitem.cpp
index b9bb4482b..c1ea48544 100644
--- a/qt-ui/profile/diveeventitem.cpp
+++ b/qt-ui/profile/diveeventitem.cpp
@@ -66,10 +66,10 @@ void DiveEventItem::setupPixmap()
setPixmap(EVENT_PIXMAP(":flag"));
} else if (strcmp(internalEvent->name, "heading") == 0) {
setPixmap(EVENT_PIXMAP(":flag"));
- } else if (internalEvent->type == SAMPLE_EVENT_GASCHANGE || internalEvent->type == SAMPLE_EVENT_GASCHANGE2) {
- if (internalEvent->value >> 16)
+ } else if (event_is_gaschange(internalEvent)) {
+ if (internalEvent->gas.mix.he.permille)
setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeTrimix"));
- else if (internalEvent->value == 0)
+ else if (gasmix_is_air(&internalEvent->gas.mix))
setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeAir"));
else
setPixmap(EVENT_PIXMAP_BIGGER(":gaschangeNitrox"));
@@ -86,7 +86,7 @@ void DiveEventItem::setupToolTipString()
int value = internalEvent->value;
int type = internalEvent->type;
if (value) {
- if (type == SAMPLE_EVENT_GASCHANGE || type == SAMPLE_EVENT_GASCHANGE2) {
+ if (event_is_gaschange(internalEvent)) {
QModelIndexList result = dataModel->match(dataModel->index(0, DivePlotDataModel::TIME), Qt::DisplayRole, internalEvent->time.seconds);
if (result.isEmpty()) {
Q_ASSERT("can't find a spot in the dataModel");
diff --git a/save-git.c b/save-git.c
index a1ef022fb..308a02c83 100644
--- a/save-git.c
+++ b/save-git.c
@@ -119,6 +119,18 @@ static void save_tags(struct membuffer *b, struct tag_entry *tags)
put_string(b, "\n");
}
+static void put_gasmix(struct membuffer *b, struct gasmix *mix)
+{
+ int o2 = mix->o2.permille;
+ int he = mix->he.permille;
+
+ if (o2) {
+ put_format(b, " o2=%u.%u%%", FRACTION(o2, 10));
+ if (he)
+ put_format(b, " he=%u.%u%%", FRACTION(he, 10));
+ }
+}
+
static void save_cylinder_info(struct membuffer *b, struct dive *dive)
{
int i, nr;
@@ -128,8 +140,6 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
cylinder_t *cylinder = dive->cylinder + i;
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
- int o2 = cylinder->gasmix.o2.permille;
- int he = cylinder->gasmix.he.permille;
put_string(b, "cylinder");
if (volume)
@@ -137,11 +147,7 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
put_pressure(b, cylinder->type.workingpressure, " workpressure=", "bar");
show_utf8(b, " description=", description, "");
strip_mb(b);
- if (o2) {
- put_format(b, " o2=%u.%u%%", FRACTION(o2, 10));
- if (he)
- put_format(b, " he=%u.%u%%", FRACTION(he, 10));
- }
+ put_gasmix(b, &cylinder->gasmix);
put_pressure(b, cylinder->start, " start=", "bar");
put_pressure(b, cylinder->end, " end=", "bar");
put_string(b, "\n");
@@ -292,6 +298,13 @@ static void save_one_event(struct membuffer *b, struct event *ev)
show_index(b, ev->flags, "flags=", "");
show_index(b, ev->value, "value=", "");
show_utf8(b, " name=", ev->name, "");
+ if (event_is_gaschange(ev)) {
+ if (ev->gas.index >= 0) {
+ show_index(b, ev->gas.index, "cylinder=", "");
+ put_gasmix(b, &ev->gas.mix);
+ } else if (!event_gasmix_redundant(ev))
+ put_gasmix(b, &ev->gas.mix);
+ }
put_string(b, "\n");
}
diff --git a/save-xml.c b/save-xml.c
index fe804cb6d..e9f769d3f 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -148,6 +148,18 @@ static void save_overview(struct membuffer *b, struct dive *dive)
show_utf8(b, dive->suit, " <suit>", "</suit>\n", 0);
}
+static void put_gasmix(struct membuffer *b, struct gasmix *mix)
+{
+ int o2 = mix->o2.permille;
+ int he = mix->he.permille;
+
+ if (o2) {
+ put_format(b, " o2='%u.%u%%'", FRACTION(o2, 10));
+ if (he)
+ put_format(b, " he='%u.%u%%'", FRACTION(he, 10));
+ }
+}
+
static void save_cylinder_info(struct membuffer *b, struct dive *dive)
{
int i, nr;
@@ -158,19 +170,13 @@ static void save_cylinder_info(struct membuffer *b, struct dive *dive)
cylinder_t *cylinder = dive->cylinder + i;
int volume = cylinder->type.size.mliter;
const char *description = cylinder->type.description;
- int o2 = cylinder->gasmix.o2.permille;
- int he = cylinder->gasmix.he.permille;
put_format(b, " <cylinder");
if (volume)
put_milli(b, " size='", volume, " l'");
put_pressure(b, cylinder->type.workingpressure, " workpressure='", " bar'");
show_utf8(b, description, " description='", "'", 1);
- if (o2) {
- put_format(b, " o2='%u.%u%%'", FRACTION(o2, 10));
- if (he)
- put_format(b, " he='%u.%u%%'", FRACTION(he, 10));
- }
+ put_gasmix(b, &cylinder->gasmix);
put_pressure(b, cylinder->start, " start='", " bar'");
put_pressure(b, cylinder->end, " end='", " bar'");
put_format(b, " />\n");
@@ -261,6 +267,13 @@ static void save_one_event(struct membuffer *b, struct event *ev)
show_index(b, ev->flags, "flags='", "'");
show_index(b, ev->value, "value='", "'");
show_utf8(b, ev->name, " name='", "'", 1);
+ if (event_is_gaschange(ev)) {
+ if (ev->gas.index >= 0) {
+ show_index(b, ev->gas.index, "cylinder='", "'");
+ put_gasmix(b, &ev->gas.mix);
+ } else if (!event_gasmix_redundant(ev))
+ put_gasmix(b, &ev->gas.mix);
+ }
put_format(b, " />\n");
}