2011-09-01 23:27:52 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "dive.h"
|
2013-01-09 20:07:09 +00:00
|
|
|
#include "device.h"
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2011-09-04 21:56:21 +00:00
|
|
|
static void show_milli(FILE *f, const char *pre, int value, const char *unit, const char *post)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
2011-09-04 22:08:31 +00:00
|
|
|
int i;
|
|
|
|
char buf[4];
|
|
|
|
unsigned v;
|
|
|
|
|
2011-09-04 21:56:21 +00:00
|
|
|
fputs(pre, f);
|
2011-09-04 22:08:31 +00:00
|
|
|
v = value;
|
2011-09-04 21:56:21 +00:00
|
|
|
if (value < 0) {
|
|
|
|
putc('-', f);
|
2011-09-04 22:08:31 +00:00
|
|
|
v = -value;
|
|
|
|
}
|
|
|
|
for (i = 2; i >= 0; i--) {
|
|
|
|
buf[i] = (v % 10) + '0';
|
|
|
|
v /= 10;
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
2011-09-04 22:08:31 +00:00
|
|
|
buf[3] = 0;
|
|
|
|
if (buf[2] == '0') {
|
|
|
|
buf[2] = 0;
|
|
|
|
if (buf[1] == '0')
|
|
|
|
buf[1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(f, "%u.%s%s%s", v, buf, unit, post);
|
2011-09-04 21:56:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void show_temperature(FILE *f, temperature_t temp, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (temp.mkelvin)
|
2013-01-24 22:09:53 +00:00
|
|
|
show_milli(f, pre, temp.mkelvin - ZERO_C_IN_MKELVIN, " C", post);
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
2011-09-01 23:59:10 +00:00
|
|
|
static void show_depth(FILE *f, depth_t depth, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (depth.mm)
|
2011-09-04 21:56:21 +00:00
|
|
|
show_milli(f, pre, depth.mm, " m", post);
|
2011-09-01 23:59:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void show_duration(FILE *f, duration_t duration, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (duration.seconds)
|
2011-09-02 00:37:41 +00:00
|
|
|
fprintf(f, "%s%u:%02u min%s", pre, FRACTION(duration.seconds, 60), post);
|
2011-09-01 23:59:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void show_pressure(FILE *f, pressure_t pressure, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (pressure.mbar)
|
2011-09-04 21:56:21 +00:00
|
|
|
show_milli(f, pre, pressure.mbar, " bar", post);
|
2011-09-01 23:59:10 +00:00
|
|
|
}
|
|
|
|
|
2012-11-12 19:57:49 +00:00
|
|
|
static void show_salinity(FILE *f, int salinity, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (salinity)
|
2012-12-05 19:57:40 +00:00
|
|
|
fprintf(f, "%s%d g/l%s", pre, salinity / 10, post);
|
2012-11-12 19:57:49 +00:00
|
|
|
}
|
2011-09-02 02:56:04 +00:00
|
|
|
/*
|
|
|
|
* We're outputting utf8 in xml.
|
|
|
|
* We need to quote the characters <, >, &.
|
|
|
|
*
|
2011-09-02 03:28:17 +00:00
|
|
|
* Technically I don't think we'd necessarily need to quote the control
|
|
|
|
* characters, but at least libxml2 doesn't like them. It doesn't even
|
|
|
|
* allow them quoted. So we just skip them and replace them with '?'.
|
|
|
|
*
|
2012-08-27 20:19:06 +00:00
|
|
|
* If we do this for attributes, we need to quote the quotes we use too.
|
2011-09-02 02:56:04 +00:00
|
|
|
*/
|
2012-08-27 20:19:06 +00:00
|
|
|
static void quote(FILE *f, const char *text, int is_attribute)
|
2011-09-02 02:56:04 +00:00
|
|
|
{
|
|
|
|
const char *p = text;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
const char *escape;
|
|
|
|
|
|
|
|
switch (*p++) {
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
case 0:
|
|
|
|
escape = NULL;
|
|
|
|
break;
|
2011-09-02 03:28:17 +00:00
|
|
|
case 1 ... 8:
|
|
|
|
case 11: case 12:
|
|
|
|
case 14 ... 31:
|
|
|
|
escape = "?";
|
|
|
|
break;
|
2011-09-02 02:56:04 +00:00
|
|
|
case '<':
|
|
|
|
escape = "<";
|
|
|
|
break;
|
|
|
|
case '>':
|
|
|
|
escape = ">";
|
|
|
|
break;
|
|
|
|
case '&':
|
|
|
|
escape = "&";
|
|
|
|
break;
|
2012-08-27 16:38:23 +00:00
|
|
|
case '\'':
|
2012-08-27 20:19:06 +00:00
|
|
|
if (!is_attribute)
|
|
|
|
continue;
|
2012-08-27 16:38:23 +00:00
|
|
|
escape = "'";
|
|
|
|
break;
|
|
|
|
case '\"':
|
2012-08-27 20:19:06 +00:00
|
|
|
if (!is_attribute)
|
|
|
|
continue;
|
2012-08-27 16:38:23 +00:00
|
|
|
escape = """;
|
|
|
|
break;
|
2011-09-02 02:56:04 +00:00
|
|
|
}
|
|
|
|
fwrite(text, (p - text - 1), 1, f);
|
|
|
|
if (!escape)
|
|
|
|
break;
|
|
|
|
fputs(escape, f);
|
|
|
|
text = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-27 20:19:06 +00:00
|
|
|
static void show_utf8(FILE *f, const char *text, const char *pre, const char *post, int is_attribute)
|
2011-09-02 02:56:04 +00:00
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (!text)
|
|
|
|
return;
|
|
|
|
while (isspace(*text))
|
|
|
|
text++;
|
|
|
|
len = strlen(text);
|
|
|
|
if (!len)
|
|
|
|
return;
|
|
|
|
while (len && isspace(text[len-1]))
|
|
|
|
len--;
|
|
|
|
/* FIXME! Quoting! */
|
|
|
|
fputs(pre, f);
|
2012-08-27 20:19:06 +00:00
|
|
|
quote(f, text, is_attribute);
|
2011-09-02 02:56:04 +00:00
|
|
|
fputs(post, f);
|
|
|
|
}
|
|
|
|
|
2013-01-23 18:25:31 +00:00
|
|
|
static void save_depths(FILE *f, struct divecomputer *dc)
|
2011-09-05 16:39:55 +00:00
|
|
|
{
|
|
|
|
/* What's the point of this dive entry again? */
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->maxdepth.mm && !dc->meandepth.mm)
|
2011-09-05 16:39:55 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
fputs(" <depth", f);
|
2013-01-23 18:25:31 +00:00
|
|
|
show_depth(f, dc->maxdepth, " max='", "'");
|
|
|
|
show_depth(f, dc->meandepth, " mean='", "'");
|
2011-09-05 16:39:55 +00:00
|
|
|
fputs(" />\n", f);
|
|
|
|
}
|
|
|
|
|
2013-02-14 17:44:18 +00:00
|
|
|
static void save_dive_temperature(FILE *f, struct dive *dive)
|
|
|
|
{
|
2013-02-14 23:18:48 +00:00
|
|
|
if (!dive->airtemp.mkelvin)
|
|
|
|
return;
|
|
|
|
if (dive->airtemp.mkelvin == dc_airtemp(&dive->dc))
|
|
|
|
return;
|
2013-02-14 17:44:18 +00:00
|
|
|
|
2013-02-14 23:18:48 +00:00
|
|
|
fputs(" <divetemperature", f);
|
|
|
|
show_temperature(f, dive->airtemp, " air='", "'");
|
|
|
|
fputs("/>\n", f);
|
2013-02-14 17:44:18 +00:00
|
|
|
}
|
|
|
|
|
2013-01-23 18:25:31 +00:00
|
|
|
static void save_temperatures(FILE *f, struct divecomputer *dc)
|
2011-09-05 16:39:55 +00:00
|
|
|
{
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->airtemp.mkelvin && !dc->watertemp.mkelvin)
|
2011-09-05 16:39:55 +00:00
|
|
|
return;
|
|
|
|
fputs(" <temperature", f);
|
2013-01-23 18:25:31 +00:00
|
|
|
show_temperature(f, dc->airtemp, " air='", "'");
|
|
|
|
show_temperature(f, dc->watertemp, " water='", "'");
|
2011-09-05 16:39:55 +00:00
|
|
|
fputs(" />\n", f);
|
|
|
|
}
|
|
|
|
|
2013-01-23 18:25:31 +00:00
|
|
|
static void save_airpressure(FILE *f, struct divecomputer *dc)
|
2012-11-12 19:57:49 +00:00
|
|
|
{
|
2013-01-23 18:25:31 +00:00
|
|
|
if (!dc->surface_pressure.mbar)
|
2012-11-12 19:57:49 +00:00
|
|
|
return;
|
|
|
|
fputs(" <surface", f);
|
2013-01-23 18:25:31 +00:00
|
|
|
show_pressure(f, dc->surface_pressure, " pressure='", "'");
|
2012-11-12 19:57:49 +00:00
|
|
|
fputs(" />\n", f);
|
|
|
|
}
|
|
|
|
|
2013-01-23 18:25:31 +00:00
|
|
|
static void save_salinity(FILE *f, struct divecomputer *dc)
|
2012-11-12 19:57:49 +00:00
|
|
|
{
|
2012-12-05 19:57:40 +00:00
|
|
|
/* only save if we have a value that isn't the default of sea water */
|
2013-02-09 00:15:18 +00:00
|
|
|
if (!dc->salinity || dc->salinity == SEAWATER_SALINITY)
|
2012-11-12 19:57:49 +00:00
|
|
|
return;
|
2012-12-05 19:57:40 +00:00
|
|
|
fputs(" <water", f);
|
2013-01-23 18:25:31 +00:00
|
|
|
show_salinity(f, dc->salinity, " salinity='", "'");
|
2012-11-12 19:57:49 +00:00
|
|
|
fputs(" />\n", f);
|
|
|
|
}
|
|
|
|
|
2012-12-05 16:25:33 +00:00
|
|
|
/*
|
|
|
|
* Format degrees to within 6 decimal places. That's about 0.1m
|
|
|
|
* on a great circle (ie longitude at equator). And micro-degrees
|
|
|
|
* is also enough to fit in a fixed-point 32-bit integer.
|
|
|
|
*/
|
2012-12-05 17:59:52 +00:00
|
|
|
static int format_degrees(char *buffer, degrees_t value)
|
2012-12-05 16:25:33 +00:00
|
|
|
{
|
2012-12-05 17:59:52 +00:00
|
|
|
int udeg = value.udeg;
|
2012-12-05 16:25:33 +00:00
|
|
|
const char *sign = "";
|
|
|
|
|
|
|
|
if (udeg < 0) {
|
|
|
|
sign = "-";
|
|
|
|
udeg = -udeg;
|
|
|
|
}
|
|
|
|
return sprintf(buffer, "%s%u.%06u",
|
|
|
|
sign, udeg / 1000000, udeg % 1000000);
|
|
|
|
}
|
|
|
|
|
2012-12-05 17:59:52 +00:00
|
|
|
static int format_location(char *buffer, degrees_t latitude, degrees_t longitude)
|
2012-12-05 16:25:33 +00:00
|
|
|
{
|
|
|
|
int len = sprintf(buffer, "gps='");
|
|
|
|
|
|
|
|
len += format_degrees(buffer+len, latitude);
|
|
|
|
buffer[len++] = ' ';
|
|
|
|
len += format_degrees(buffer+len, longitude);
|
|
|
|
buffer[len++] = '\'';
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
2012-11-12 19:57:49 +00:00
|
|
|
|
2011-09-16 01:16:07 +00:00
|
|
|
static void show_location(FILE *f, struct dive *dive)
|
|
|
|
{
|
|
|
|
char buffer[80];
|
|
|
|
const char *prefix = " <location>";
|
2012-12-05 17:59:52 +00:00
|
|
|
degrees_t latitude = dive->latitude;
|
|
|
|
degrees_t longitude = dive->longitude;
|
2011-09-16 01:16:07 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ok, theoretically I guess you could dive at
|
|
|
|
* exactly 0,0. But we don't support that. So
|
|
|
|
* if you do, just fudge it a bit, and say that
|
|
|
|
* you dove a few meters away.
|
|
|
|
*/
|
2012-12-05 17:59:52 +00:00
|
|
|
if (latitude.udeg || longitude.udeg) {
|
2012-12-05 16:25:33 +00:00
|
|
|
int len = sprintf(buffer, " <location ");
|
|
|
|
|
|
|
|
len += format_location(buffer+len, latitude, longitude);
|
2011-09-16 01:16:07 +00:00
|
|
|
if (!dive->location) {
|
2012-12-05 16:25:33 +00:00
|
|
|
memcpy(buffer+len, "/>\n", 4);
|
2011-09-16 01:16:07 +00:00
|
|
|
fputs(buffer, f);
|
|
|
|
return;
|
|
|
|
}
|
2012-12-05 16:25:33 +00:00
|
|
|
buffer[len++] = '>';
|
|
|
|
buffer[len] = 0;
|
2011-09-16 01:16:07 +00:00
|
|
|
prefix = buffer;
|
|
|
|
}
|
2012-08-27 20:19:06 +00:00
|
|
|
show_utf8(f, dive->location, prefix,"</location>\n", 0);
|
2011-09-16 01:16:07 +00:00
|
|
|
}
|
|
|
|
|
2011-09-01 23:27:52 +00:00
|
|
|
static void save_overview(FILE *f, struct dive *dive)
|
|
|
|
{
|
2011-09-16 01:16:07 +00:00
|
|
|
show_location(f, dive);
|
2012-08-27 20:19:06 +00:00
|
|
|
show_utf8(f, dive->divemaster, " <divemaster>","</divemaster>\n", 0);
|
|
|
|
show_utf8(f, dive->buddy, " <buddy>","</buddy>\n", 0);
|
|
|
|
show_utf8(f, dive->notes, " <notes>","</notes>\n", 0);
|
|
|
|
show_utf8(f, dive->suit, " <suit>","</suit>\n", 0);
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
static int nr_cylinders(struct dive *dive)
|
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
|
|
|
|
for (nr = MAX_CYLINDERS; nr; --nr) {
|
|
|
|
cylinder_t *cylinder = dive->cylinder+nr-1;
|
|
|
|
if (!cylinder_nodata(cylinder))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
|
2011-09-04 03:31:18 +00:00
|
|
|
static void save_cylinder_info(FILE *f, struct dive *dive)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
int i, nr;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
Fix missing save of (almost empty) cylinder information
If we have no explicit cylinder info at all (it's normal air, no size or
working pressure information, and no beginning/end pressure information),
we don't save the cylinders in question because that would be redundant.
Such non-saved cylinders may still show up in the equipment list because
there may be implicit mention of them elsewhere, notably due to sample
data, so not saving them is the right thing to do - there is nothing to
save.
However, we missed one case: if there were other cylinders that *did* have
explicit information in it following such an uninteresting cylinder, we do
need to save the cylinder information for the useless case - if only in
order to be able to save the non-useless information for subsequent
cylinders.
This patch does that. Now, if you had an air-filled cylinder with no
information as your first cylinder, and a 51% nitrox as your second one,
it will save that information as
<cylinder />
<cylinder o2='51.0%' />
rather than dropping the cylinder information entirely.
This bug has been there for a long time, and was hidden by the fact that
normally you'd fill in cylinder descriptions etc after importing new
dives. It also used to be that we saved the cylinder beginning/end
pressure even if that was generated from the sample data, so if you
imported from a air-integrated computer and had samples for that cylinder,
we used to save it even though it was technically redundant.
We stopped saving redundant air sample information in commit 0089dd8819b7
("Don't save cylinder start/end pressures unless set by hand").
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Removed start and end in save_cylinder_info(). These two variables are no
longer used.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-21 21:06:57 +00:00
|
|
|
nr = nr_cylinders(dive);
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++) {
|
2011-09-04 03:31:18 +00:00
|
|
|
cylinder_t *cylinder = dive->cylinder+i;
|
|
|
|
int volume = cylinder->type.size.mliter;
|
2011-09-04 20:34:22 +00:00
|
|
|
const char *description = cylinder->type.description;
|
2011-09-04 03:31:18 +00:00
|
|
|
int o2 = cylinder->gasmix.o2.permille;
|
|
|
|
int he = cylinder->gasmix.he.permille;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2011-09-04 03:31:18 +00:00
|
|
|
fprintf(f, " <cylinder");
|
Don't save cylinder working pressure
It was a mistake to save it - and I did it just because other dive
managers did. It's a totally nonsensical measure, and nobody cares.
The only thing that matters is the size of the cylinder, and the
*actual* pressures. Those give actual air consumption numbers, and are
meaningful and unambiguous.
So the "working pressure" for a cylinder is pointless except for two
things:
- if you don't know the actual physical size, you need the "working
pressure" along with the air size (eg "85 cuft") in order to compute
the physical size. So we do use the working pressure on *input* from
systems that report cylinder sizes that way.
- People may well want to know what kind of cylinder they were diving,
and again, you can make a good guess about this from the working
pressure. So saving information like "HP100+" for the cylinder would
be a good thing.
But notice how in neither case do we actually want to save the working
pressure itself. And in fact saving it actually makes the output format
ambiguous: if we give both size and working pressure, what does 'size'
mean? Is it physical size in liters, or air size in cu ft?
So saving working pressure is just wrong. Get rid of it.
I'm going to add some kind of "cylinder description" thing, which we can
save instead (and perhaps guess standard cylinders from input like the
working pressure from dive logs that don't do this sanely - which is all
of them, as far as I can tell).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2011-09-04 18:23:41 +00:00
|
|
|
if (volume)
|
2011-09-04 21:56:21 +00:00
|
|
|
show_milli(f, " size='", volume, " l", "'");
|
2011-09-10 22:17:33 +00:00
|
|
|
show_pressure(f, cylinder->type.workingpressure, " workpressure='", "'");
|
2011-09-12 20:41:37 +00:00
|
|
|
if (description && *description)
|
2011-09-04 22:07:47 +00:00
|
|
|
fprintf(f, " description='%s'", description);
|
2011-11-10 23:42:37 +00:00
|
|
|
if (o2) {
|
|
|
|
fprintf(f, " o2='%u.%u%%'", FRACTION(o2, 10));
|
|
|
|
if (he)
|
|
|
|
fprintf(f, " he='%u.%u%%'", FRACTION(he, 10));
|
|
|
|
}
|
2011-09-05 16:12:54 +00:00
|
|
|
show_pressure(f, cylinder->start, " start='", "'");
|
|
|
|
show_pressure(f, cylinder->end, " end='", "'");
|
2011-09-04 03:31:18 +00:00
|
|
|
fprintf(f, " />\n");
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-24 03:41:16 +00:00
|
|
|
static void save_weightsystem_info(FILE *f, struct dive *dive)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++) {
|
|
|
|
weightsystem_t *ws = dive->weightsystem+i;
|
|
|
|
int grams = ws->weight.grams;
|
|
|
|
const char *description = ws->description;
|
|
|
|
|
|
|
|
/* No weight information at all? */
|
|
|
|
if (grams == 0)
|
|
|
|
return;
|
|
|
|
fprintf(f, " <weightsystem");
|
|
|
|
show_milli(f, " weight='", grams, " kg", "'");
|
|
|
|
if (description && *description)
|
|
|
|
fprintf(f, " description='%s'", description);
|
|
|
|
fprintf(f, " />\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-09-23 01:02:54 +00:00
|
|
|
static void show_index(FILE *f, int value, const char *pre, const char *post)
|
|
|
|
{
|
|
|
|
if (value)
|
|
|
|
fprintf(f, " %s%d%s", pre, value, post);
|
|
|
|
}
|
|
|
|
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
static void save_sample(FILE *f, struct sample *sample, struct sample *old)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
2011-09-04 21:56:21 +00:00
|
|
|
fprintf(f, " <sample time='%u:%02u min'", FRACTION(sample->time.seconds,60));
|
|
|
|
show_milli(f, " depth='", sample->depth.mm, " m", "'");
|
2011-09-02 00:37:41 +00:00
|
|
|
show_temperature(f, sample->temperature, " temp='", "'");
|
2011-09-04 03:31:18 +00:00
|
|
|
show_pressure(f, sample->cylinderpressure, " pressure='", "'");
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2012-12-01 21:02:30 +00:00
|
|
|
/* the deco/ndl values are stored whenever they change */
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
if (sample->ndl.seconds != old->ndl.seconds) {
|
2012-12-01 21:02:30 +00:00
|
|
|
fprintf(f, " ndl='%u:%02u min'", FRACTION(sample->ndl.seconds, 60));
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->ndl = sample->ndl;
|
|
|
|
}
|
|
|
|
if (sample->in_deco != old->in_deco) {
|
2012-12-31 02:11:01 +00:00
|
|
|
fprintf(f, " in_deco='%d'", sample->in_deco ? 1 : 0);
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->in_deco = sample->in_deco;
|
|
|
|
}
|
|
|
|
if (sample->stoptime.seconds != old->stoptime.seconds) {
|
2012-12-01 21:02:30 +00:00
|
|
|
fprintf(f, " stoptime='%u:%02u min'", FRACTION(sample->stoptime.seconds, 60));
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->stoptime = sample->stoptime;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sample->stopdepth.mm != old->stopdepth.mm) {
|
2012-12-01 21:02:30 +00:00
|
|
|
show_milli(f, " stopdepth='", sample->stopdepth.mm, " m", "'");
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->stopdepth = sample->stopdepth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sample->cns != old->cns) {
|
2012-12-08 04:08:29 +00:00
|
|
|
fprintf(f, " cns='%u%%'", sample->cns);
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->cns = sample->cns;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sample->po2 != old->po2) {
|
2012-12-08 04:08:29 +00:00
|
|
|
fprintf(f, " po2='%u.%2u bar'", FRACTION(sample->po2, 1000));
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
old->po2 = sample->po2;
|
|
|
|
}
|
2011-09-02 00:37:41 +00:00
|
|
|
fprintf(f, " />\n");
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|
|
|
|
|
2011-09-23 01:02:54 +00:00
|
|
|
static void save_one_event(FILE *f, struct event *ev)
|
|
|
|
{
|
|
|
|
fprintf(f, " <event time='%d:%02d min'", FRACTION(ev->time.seconds,60));
|
|
|
|
show_index(f, ev->type, "type='", "'");
|
|
|
|
show_index(f, ev->flags, "flags='", "'");
|
|
|
|
show_index(f, ev->value, "value='", "'");
|
2012-08-27 20:19:06 +00:00
|
|
|
show_utf8(f, ev->name, " name='", "'", 1);
|
2011-09-23 01:02:54 +00:00
|
|
|
fprintf(f, " />\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void save_events(FILE *f, struct event *ev)
|
|
|
|
{
|
|
|
|
while (ev) {
|
|
|
|
save_one_event(f, ev);
|
|
|
|
ev = ev->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-25 02:50:21 +00:00
|
|
|
static void show_date(FILE *f, timestamp_t when)
|
2012-08-22 05:04:24 +00:00
|
|
|
{
|
2012-09-20 00:35:52 +00:00
|
|
|
struct tm tm;
|
|
|
|
|
2012-11-25 02:50:21 +00:00
|
|
|
utc_mkdate(when, &tm);
|
2012-08-22 05:04:24 +00:00
|
|
|
|
|
|
|
fprintf(f, " date='%04u-%02u-%02u'",
|
2012-09-20 00:35:52 +00:00
|
|
|
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday);
|
2012-08-30 00:24:15 +00:00
|
|
|
fprintf(f, " time='%02u:%02u:%02u'",
|
2012-09-20 00:35:52 +00:00
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
2012-11-25 02:50:21 +00:00
|
|
|
}
|
|
|
|
|
2012-12-01 21:02:30 +00:00
|
|
|
static void save_samples(FILE *f, int nr, struct sample *s)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
struct sample dummy = { };
|
2012-12-01 21:02:30 +00:00
|
|
|
|
|
|
|
while (--nr >= 0) {
|
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>
2012-12-31 04:00:51 +00:00
|
|
|
save_sample(f, s, &dummy);
|
2012-12-01 21:02:30 +00:00
|
|
|
s++;
|
|
|
|
}
|
|
|
|
}
|
2012-11-25 04:29:14 +00:00
|
|
|
|
2012-12-01 21:02:30 +00:00
|
|
|
static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc)
|
|
|
|
{
|
2012-11-25 04:29:14 +00:00
|
|
|
fprintf(f, " <divecomputer");
|
2012-11-25 19:44:27 +00:00
|
|
|
if (dc->model)
|
|
|
|
show_utf8(f, dc->model, " model='", "'", 1);
|
|
|
|
if (dc->deviceid)
|
|
|
|
fprintf(f, " deviceid='%08x'", dc->deviceid);
|
|
|
|
if (dc->diveid)
|
|
|
|
fprintf(f, " diveid='%08x'", dc->diveid);
|
2012-11-25 04:29:14 +00:00
|
|
|
if (dc->when && dc->when != dive->when)
|
|
|
|
show_date(f, dc->when);
|
2013-01-23 18:25:31 +00:00
|
|
|
if (dc->duration.seconds && dc->duration.seconds != dive->dc.duration.seconds)
|
|
|
|
show_duration(f, dc->duration, " duration='", "'");
|
2012-11-25 04:29:14 +00:00
|
|
|
fprintf(f, ">\n");
|
2013-01-23 18:25:31 +00:00
|
|
|
save_depths(f, dc);
|
|
|
|
save_temperatures(f, dc);
|
|
|
|
save_airpressure(f, dc);
|
|
|
|
save_salinity(f, dc);
|
|
|
|
show_duration(f, dc->surfacetime, " <surfacetime>", "</surfacetime>\n");
|
|
|
|
|
2012-11-25 02:50:21 +00:00
|
|
|
save_events(f, dc->events);
|
2012-12-01 21:02:30 +00:00
|
|
|
save_samples(f, dc->samples, dc->sample);
|
|
|
|
|
2012-11-25 04:29:14 +00:00
|
|
|
fprintf(f, " </divecomputer>\n");
|
2012-11-25 02:50:21 +00:00
|
|
|
}
|
2012-09-20 00:35:52 +00:00
|
|
|
|
2013-01-10 00:01:15 +00:00
|
|
|
void save_dive(FILE *f, struct dive *dive)
|
2012-11-25 02:50:21 +00:00
|
|
|
{
|
|
|
|
struct divecomputer *dc;
|
2011-09-01 23:27:52 +00:00
|
|
|
|
2011-09-11 18:36:33 +00:00
|
|
|
fputs("<dive", f);
|
2011-09-11 18:36:33 +00:00
|
|
|
if (dive->number)
|
|
|
|
fprintf(f, " number='%d'", dive->number);
|
2012-11-26 22:52:07 +00:00
|
|
|
if (dive->tripflag == NO_TRIP)
|
|
|
|
fprintf(f, " tripflag='NOTRIP'");
|
2011-12-08 04:49:22 +00:00
|
|
|
if (dive->rating)
|
|
|
|
fprintf(f, " rating='%d'", dive->rating);
|
2012-10-28 22:49:02 +00:00
|
|
|
if (dive->visibility)
|
|
|
|
fprintf(f, " visibility='%d'", dive->visibility);
|
2012-11-25 02:50:21 +00:00
|
|
|
show_date(f, dive->when);
|
2011-09-11 18:36:33 +00:00
|
|
|
fprintf(f, " duration='%u:%02u min'>\n",
|
2013-01-23 18:25:31 +00:00
|
|
|
FRACTION(dive->dc.duration.seconds, 60));
|
2011-09-01 23:27:52 +00:00
|
|
|
save_overview(f, dive);
|
2011-09-04 03:31:18 +00:00
|
|
|
save_cylinder_info(f, dive);
|
2011-12-24 03:41:16 +00:00
|
|
|
save_weightsystem_info(f, dive);
|
2013-02-14 17:44:18 +00:00
|
|
|
save_dive_temperature(f, dive);
|
2012-11-25 02:50:21 +00:00
|
|
|
/* Save the dive computer data */
|
|
|
|
dc = &dive->dc;
|
|
|
|
do {
|
|
|
|
save_dc(f, dive, dc);
|
|
|
|
dc = dc->next;
|
|
|
|
} while (dc);
|
|
|
|
|
2011-09-01 23:27:52 +00:00
|
|
|
fprintf(f, "</dive>\n");
|
|
|
|
}
|
|
|
|
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
static void save_trip(FILE *f, dive_trip_t *trip)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct dive *dive;
|
|
|
|
|
|
|
|
fprintf(f, "<trip");
|
|
|
|
show_date(f, trip->when);
|
|
|
|
if (trip->location)
|
|
|
|
show_utf8(f, trip->location, " location=\'","\'", 1);
|
|
|
|
fprintf(f, ">\n");
|
|
|
|
if (trip->notes)
|
|
|
|
show_utf8(f, trip->notes, "<notes>","</notes>\n", 0);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Incredibly cheesy: we want to save the dives sorted, and they
|
|
|
|
* are sorted in the dive array.. So instead of using the dive
|
|
|
|
* list in the trip, we just traverse the global dive array and
|
|
|
|
* check the divetrip pointer..
|
|
|
|
*/
|
|
|
|
for_each_dive(i, dive) {
|
|
|
|
if (dive->divetrip == trip)
|
|
|
|
save_dive(f, dive);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(f, "</trip>\n");
|
|
|
|
}
|
|
|
|
|
2013-01-24 19:42:20 +00:00
|
|
|
static void save_one_device(FILE *f, struct device_info *info)
|
2012-12-28 16:38:47 +00:00
|
|
|
{
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
const char *nickname, *serial_nr, *firmware;
|
2012-12-28 16:38:47 +00:00
|
|
|
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
/* Nicknames that are empty or the same as the device model are not interesting */
|
|
|
|
nickname = info->nickname;
|
|
|
|
if (nickname) {
|
2013-01-24 19:42:20 +00:00
|
|
|
if (!*nickname || !strcmp(info->model, nickname))
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
nickname = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Serial numbers that are empty are not interesting */
|
|
|
|
serial_nr = info->serial_nr;
|
|
|
|
if (serial_nr && !*serial_nr)
|
|
|
|
serial_nr = NULL;
|
|
|
|
|
|
|
|
/* Firmware strings that are empty are not interesting */
|
|
|
|
firmware = info->firmware;
|
|
|
|
if (firmware && !*firmware)
|
|
|
|
firmware = NULL;
|
2012-12-28 16:38:47 +00:00
|
|
|
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
/* Do we have anything interesting about this dive computer to save? */
|
|
|
|
if (!serial_nr && !nickname && !firmware)
|
2012-12-31 04:27:01 +00:00
|
|
|
return;
|
2012-12-28 16:38:47 +00:00
|
|
|
|
2013-01-24 19:42:20 +00:00
|
|
|
fprintf(f, "<divecomputerid model='%s' deviceid='%08x'", info->model, info->deviceid);
|
Assemble the actual Suunto serial number
It turns out that the serial number returned by libdivecomputer isn't
really the serial number as interpreted by the vendor. Those tend to be
strings, but libdivecomputer gives us a 32bit number.
Some experimenting showed that for the Suunto devies tested the serial
number is encoded in that 32bit number:
It so happens that the Suunto serial number strings are strings that have
all numbers, but they aren't *one* number. They are four bytes
representing two numbers each, and the "23500027" string is actually the
four bytes 23 50 00 27 (0x17 0x32 0x00 0x1b). And libdivecomputer has
incorrectly parsed those four bytes as one number, not as the encoded
serial number string it is. So the value 389152795 is actually hex
0x1732001b, which is 0x17 0x32 0x00 0x1b, which is - 23 50 00 27.
This should be done by libdivecomputer, but hey, in the meantime this at
least shows the concept. And helps test the XML save/restore code.
It depends on the two patches that create the whole "device.c"
infrastructure, of course. With this, my dive file ends up having the
settings section look like this:
<divecomputerid model='Suunto Vyper Air' deviceid='d4629110'
serial='01201094' firmware='1.1.22'/>
<divecomputerid model='Suunto HelO2' deviceid='995dd566'
serial='23500027' firmware='1.0.4'/>
where the format of the firmware version is something I guessed at,
but it was the obvious choice (again, it's byte-based, I'm ignoring
the high byte that is zero for both of my Suuntos).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2013-01-10 00:14:21 +00:00
|
|
|
if (serial_nr)
|
|
|
|
show_utf8(f, serial_nr, " serial='", "'", 1);
|
|
|
|
if (firmware)
|
|
|
|
show_utf8(f, firmware, " firmware='", "'", 1);
|
|
|
|
if (nickname)
|
|
|
|
show_utf8(f, nickname, " nickname='", "'", 1);
|
2012-12-31 04:27:01 +00:00
|
|
|
fprintf(f, "/>\n");
|
2013-01-24 19:42:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void save_device_info(FILE *f)
|
|
|
|
{
|
|
|
|
struct device_info *info;
|
|
|
|
|
|
|
|
info = head_of_device_info_list();
|
|
|
|
while (info) {
|
|
|
|
save_one_device(f, info);
|
|
|
|
info = info->next;
|
|
|
|
}
|
2012-12-28 16:38:47 +00:00
|
|
|
}
|
|
|
|
|
2012-12-26 21:47:54 +00:00
|
|
|
#define VERSION 2
|
2011-09-01 23:27:52 +00:00
|
|
|
|
|
|
|
void save_dives(const char *filename)
|
2013-02-01 08:28:33 +00:00
|
|
|
{
|
|
|
|
save_dives_logic(filename, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void save_dives_logic(const char *filename, const gboolean select_only)
|
2011-09-01 23:27:52 +00:00
|
|
|
{
|
|
|
|
int i;
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
struct dive *dive;
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
dive_trip_t *trip;
|
2012-08-22 05:04:24 +00:00
|
|
|
|
2012-10-03 14:29:01 +00:00
|
|
|
FILE *f = g_fopen(filename, "w");
|
2011-09-01 23:27:52 +00:00
|
|
|
|
|
|
|
if (!f)
|
|
|
|
return;
|
2011-09-02 02:56:04 +00:00
|
|
|
|
|
|
|
/* Flush any edits of current dives back to the dives! */
|
2011-09-11 19:53:59 +00:00
|
|
|
update_dive(current_dive);
|
2011-09-02 02:56:04 +00:00
|
|
|
|
2012-12-26 21:47:54 +00:00
|
|
|
fprintf(f, "<divelog program='subsurface' version='%d'>\n<settings>\n", VERSION);
|
2013-01-01 16:29:43 +00:00
|
|
|
|
|
|
|
/* save the dive computer nicknames, if any */
|
2013-01-24 19:42:20 +00:00
|
|
|
save_device_info(f);
|
2013-01-02 01:29:38 +00:00
|
|
|
if (autogroup)
|
|
|
|
fprintf(f, "<autogroup state='1' />\n");
|
2012-12-26 21:47:54 +00:00
|
|
|
fprintf(f, "</settings>\n<dives>\n");
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
|
|
|
for (trip = dive_trip_list; trip != NULL; trip = trip->next)
|
|
|
|
trip->index = 0;
|
|
|
|
|
2012-08-22 05:04:24 +00:00
|
|
|
/* save the dives */
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
for_each_dive(i, dive) {
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
2013-02-01 08:28:33 +00:00
|
|
|
if (select_only) {
|
|
|
|
|
|
|
|
if(!dive->selected)
|
|
|
|
continue;
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
save_dive(f, dive);
|
|
|
|
|
2013-02-01 08:28:33 +00:00
|
|
|
} else {
|
|
|
|
trip = dive->divetrip;
|
|
|
|
|
|
|
|
/* Bare dive without a trip? */
|
|
|
|
if (!trip) {
|
|
|
|
save_dive(f, dive);
|
|
|
|
continue;
|
|
|
|
}
|
Allow overlapping (and disjoint) dive trips
We used to have the rule that a dive trip has to have all dives in it in
sequential order, even though our XML file really is much more flexible,
and allows arbitrary nesting of dives within a dive trip.
Put another way, the old model had fairly inflexible rules:
- the dive array is sorted by time
- a dive trip is always a contiguous slice of this sorted array
which makes perfect sense when you think of the dive and trip list as a
physical activity by one person, but leads to various very subtle issues
in the general case when there are no guarantees that the user then uses
subsurface that way.
In particular, if you load the XML files of two divers that have
overlapping dive trips, the end result is incredibly messy, and does not
conform to the above model at all.
There's two ways to enforce such conformance:
- disallow that kind of behavior entirely.
This is actually hard. Our XML files aren't date-based, they are
based on XML nesting rules, and even a single XML file can have
nesting that violates the date ordering. With multiple XML files,
it's trivial to do in practice, and while we could just fail at
loading, the failure would have to be a hard failure that leaves the
user no way to use the data at all.
- try to "fix it up" by sorting, splitting, and combining dive trips
automatically.
Dirk had a patch to do this, but it really does destroy the actual
dive data: if you load both mine and Dirk's dive trips, you ended up
with a result that followed the above two technical rules, but that
didn't actually make any *sense*.
So this patch doesn't try to enforce the rules, and instead just changes
them to be more generic:
- the dive array is still sorted by dive time
- a dive trip is just an arbitrary collection of dives.
The relaxed rules means that mixing dives and dive trips for two people
is trivial, and we can easily handle any XML file. The dive trip is
defined by the XML nesting level, and is totally independent of any
date-based sorting.
It does require a few things:
- when we save our dive data, we have to do it hierarchically by dive
trip, not just by walking the dive array linearly.
- similarly, when we create the dive tree model, we can't just blindly
walk the array of dives one by one, we have to look up the correct
trip (parent)
- when we try to merge two dives that are adjacent (by date sorting),
we can't do it if they are in different trips.
but apart from that, nothing else really changes.
NOTE! Despite the new relaxed model, creating totally disjoing dive
trips is not all that easy (nor is there any *reason* for it to be
easty). Our GUI interfaces still are "add dive to trip above" etc, and
the automatic adding of dives to dive trips is obviously still based on
date.
So this does not really change the expected normal usage, the relaxed
data structure rules just mean that we don't need to worry about the odd
cases as much, because we can just let them be.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-12-30 19:00:37 +00:00
|
|
|
|
2013-02-01 08:28:33 +00:00
|
|
|
/* Have we already seen this trip (and thus saved this dive?) */
|
|
|
|
if (trip->index)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* We haven't seen this trip before - save it and all dives */
|
|
|
|
trip->index = 1;
|
|
|
|
save_trip(f, trip);
|
|
|
|
}
|
New XML format for saving dives
This patch makes the trips nest, and it also fixes the fact that you never
saved the trip notes (you could edit it, but saving would throw it away).
I did *not* change the indentation of the dives, so the trip stuff shows
up the the beginning of the line, at the same level as the <dive> and
<dives> thing. I think it's fairly readable xml, though, and we haven't
really had proper "indentation shows nesting" anyway, since the top-level
"<dives>" thing also didn't indent stuff inside of it.
Anyway, the way I wrote it, it still parses your old "INTRIP" stuff etc,
so as far as I know, it should happily read the old-style XML too. At
least it seemed to work with your xml file that already had the old-style
one (I haven't committed my divetrips, exactly because I didn't like the
new format).
It always saves in the new style, though.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2012-09-30 19:36:18 +00:00
|
|
|
}
|
2012-12-26 21:47:54 +00:00
|
|
|
fprintf(f, "</dives>\n</divelog>\n");
|
2011-09-04 16:50:31 +00:00
|
|
|
fclose(f);
|
2011-09-01 23:27:52 +00:00
|
|
|
}
|