summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--color.h1
-rw-r--r--dive.c61
-rw-r--r--dive.h2
-rw-r--r--gtk-gui.c2
-rw-r--r--parse-xml.c2
-rw-r--r--profile.c105
-rw-r--r--uemis-downloader.c10
-rw-r--r--uemis.c23
9 files changed, 179 insertions, 29 deletions
diff --git a/Makefile b/Makefile
index 448cff807..90403c4f1 100644
--- a/Makefile
+++ b/Makefile
@@ -252,7 +252,7 @@ gtk-gui.o: gtk-gui.c dive.h display.h divelist.h display-gtk.h libdivecomputer.h
-c gtk-gui.c
uemis.o: uemis.c dive.h uemis.h
- $(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(XML2CFLAGS) -c uemis.c
+ $(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(XML2CFLAGS) $(LIBDIVECOMPUTERCFLAGS) -c uemis.c
uemis-downloader.o: uemis-downloader.c dive.h uemis.h
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(XML2CFLAGS) -c uemis-downloader.c
diff --git a/color.h b/color.h
index eb740fbd6..38839ae7f 100644
--- a/color.h
+++ b/color.h
@@ -26,6 +26,7 @@
#define REDORANGE1 { 1.0, 0.2, 0.2, 1 }
#define REDORANGE1_HIGH_TRANS { 1.0, 0.2, 0.2, 0.25 }
#define REDORANGE1_MED_TRANS { 1.0, 0.2, 0.2, 0.5 }
+#define RED1_MED_TRANS { 1.0, 0.0, 0.0, 0.5 }
#define RED1 { 1.0, 0.0, 0.0, 1 }
// Monochromes
diff --git a/dive.c b/dive.c
index ca6fda649..caf1eedfe 100644
--- a/dive.c
+++ b/dive.c
@@ -373,6 +373,30 @@ static void sanitize_cylinder_info(struct dive *dive)
}
}
+/* some events should never be thrown away */
+static gboolean is_potentially_redundant(struct event *event)
+{
+ if (!strcmp(event->name, "gaschange"))
+ return FALSE;
+ return TRUE;
+}
+
+/* match just by name - we compare the details in the code that uses this helper */
+static struct event *find_previous_event(struct dive *dive, struct event *event)
+{
+ struct event *ev = dive->events;
+ struct event *previous = NULL;
+
+ if (!event->name)
+ return NULL;
+ while (ev && ev != event) {
+ if(ev->name && !strcmp(ev->name, event->name))
+ previous = ev;
+ ev = ev->next;
+ }
+ return previous;
+}
+
struct dive *fixup_dive(struct dive *dive)
{
int i,j;
@@ -384,6 +408,7 @@ struct dive *fixup_dive(struct dive *dive)
int lastdepth = 0;
int lasttemp = 0, lastpressure = 0;
int pressure_delta[MAX_CYLINDERS] = {INT_MAX, };
+ struct event *event;
add_people(dive->buddy);
add_people(dive->divemaster);
@@ -514,6 +539,42 @@ struct dive *fixup_dive(struct dive *dive)
add_weightsystem_description(ws);
}
+ /* events are stored as a linked list, so the concept of
+ * "consecutive, identical events" is somewhat hard to
+ * implement correctly (especially given that on some dive
+ * computers events are asynchronous, so they can come in
+ * between what would be the non-constant sample rate).
+ *
+ * So what we do is that we throw away clearly redundant
+ * events that are fewer than 61 seconds apart (assuming there
+ * is no dive computer with a sample rate of more than 60
+ * seconds... that would be pretty pointless to plot the
+ * profile with)
+ * We first only mark the events for deletion so that we
+ * still know when the previous event happened. */
+ event = dive->events;
+ while (event) {
+ struct event *prev;
+ if (is_potentially_redundant(event)) {
+ prev = find_previous_event(dive, event);
+ if (prev && prev->value == event->value &&
+ prev->flags == event->flags &&
+ event->time.seconds - prev->time.seconds < 61)
+ event->deleted = TRUE;
+ }
+ event = event->next;
+ }
+ event = dive->events;
+ while (event) {
+ if (event->next && event->next->deleted) {
+ struct event *nextnext = event->next->next;
+ free(event->next);
+ event->next = nextnext;
+ } else {
+ event = event->next;
+ }
+ }
+
return dive;
}
diff --git a/dive.h b/dive.h
index a1520a1a6..949be20d3 100644
--- a/dive.h
+++ b/dive.h
@@ -233,6 +233,7 @@ struct event {
struct event *next;
duration_t time;
int type, flags, value;
+ gboolean deleted;
char name[];
};
@@ -269,6 +270,7 @@ struct dive {
duration_t duration, surfacetime;
int visibility; /* 0 - 5 star rating */
temperature_t airtemp, watertemp;
+ pressure_t surface_pressure;
cylinder_t cylinder[MAX_CYLINDERS];
weightsystem_t weightsystem[MAX_WEIGHTSYSTEMS];
char *suit;
diff --git a/gtk-gui.c b/gtk-gui.c
index 665a4abef..690b2a488 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -1231,7 +1231,7 @@ void attach_tooltip(int x, int y, int w, int h, const char *text)
rect->y = y;
rect->width = w;
rect->height = h;
- tooltip_rects[tooltips].text = text;
+ tooltip_rects[tooltips].text = strdup(text);
tooltips++;
}
diff --git a/parse-xml.c b/parse-xml.c
index 9429580e6..272b82c0f 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -545,7 +545,7 @@ static void decicelsius(char *buffer, void *_temp)
temp->mkelvin = (val.fp/10 + 273.15) * 1000 + 0.5;
break;
default:
- fprintf(stderr, "Strange julian date: %s", buffer);
+ fprintf(stderr, "Strange temperature: %s", buffer);
}
free(buffer);
}
diff --git a/profile.c b/profile.c
index 9b0dcb600..7902560f3 100644
--- a/profile.c
+++ b/profile.c
@@ -15,6 +15,7 @@
#include "display-gtk.h"
#include "divelist.h"
#include "color.h"
+#include "libdivecomputer/parser.h"
int selected_dive = 0;
char zoomed_plot = 0;
@@ -44,6 +45,7 @@ struct plot_info {
int temperature;
/* Depth info */
int depth;
+ int ceiling;
int smoothed;
double po2, pn2, phe;
velocity_t velocity;
@@ -77,7 +79,8 @@ typedef enum {
/* Other colors */
TEXT_BACKGROUND, ALERT_BG, ALERT_FG, EVENTS, SAMPLE_DEEP, SAMPLE_SHALLOW,
SMOOTHED, MINUTE, TIME_GRID, TIME_TEXT, DEPTH_GRID, MEAN_DEPTH, DEPTH_TOP,
- DEPTH_BOTTOM, TEMP_TEXT, TEMP_PLOT, SAC_DEFAULT, BOUNDING_BOX, PRESSURE_TEXT, BACKGROUND
+ DEPTH_BOTTOM, TEMP_TEXT, TEMP_PLOT, SAC_DEFAULT, BOUNDING_BOX, PRESSURE_TEXT, BACKGROUND,
+ CEILING_SHALLOW, CEILING_DEEP
} color_indice_t;
typedef struct {
@@ -129,6 +132,9 @@ static const color_t profile_color[] = {
[BOUNDING_BOX] = {{WHITE1, BLACK1_LOW_TRANS}},
[PRESSURE_TEXT] = {{KILLARNEY1, BLACK1_LOW_TRANS}},
[BACKGROUND] = {{SPRINGWOOD1, BLACK1_LOW_TRANS}},
+ [CEILING_SHALLOW] = {{REDORANGE1_HIGH_TRANS, REDORANGE1_HIGH_TRANS}},
+ [CEILING_DEEP] = {{RED1_MED_TRANS, RED1_MED_TRANS}},
+
};
#define plot_info_size(nr) (sizeof(struct plot_info) + (nr)*sizeof(struct plot_data))
@@ -185,11 +191,11 @@ static void dump_pi (struct plot_info *pi)
pi->maxpressure, pi->mintemp, pi->maxtemp);
for (i = 0; i < pi->nr; i++)
printf(" entry[%d]:{same_cylinder:%d cylinderindex:%d sec:%d pressure:{%d,%d}\n"
- " time:%d:%02d temperature:%d depth:%d smoothed:%d po2:%lf phe:%lf pn2:%lf sum-pp %lf}\n",
+ " time:%d:%02d temperature:%d depth:%d ceiling:%d smoothed:%d po2:%lf phe:%lf pn2:%lf sum-pp %lf}\n",
i, pi->entry[i].same_cylinder, pi->entry[i].cylinderindex, pi->entry[i].sec,
pi->entry[i].pressure[0], pi->entry[i].pressure[1],
pi->entry[i].sec / 60, pi->entry[i].sec % 60,
- pi->entry[i].temperature, pi->entry[i].depth, pi->entry[i].smoothed,
+ pi->entry[i].temperature, pi->entry[i].depth, pi->entry[i].ceiling, pi->entry[i].smoothed,
pi->entry[i].po2, pi->entry[i].phe, pi->entry[i].pn2,
pi->entry[i].po2 + pi->entry[i].phe + pi->entry[i].pn2);
printf(" }\n");
@@ -294,6 +300,7 @@ static void plot_text(struct graphics_context *gc, const text_render_options_t *
cairo_show_text(cr, buffer);
}
+/* collect all event names and whether we display them */
struct ev_select {
char *ev_name;
gboolean plot_ev;
@@ -314,12 +321,12 @@ void evn_foreach(void (*callback)(const char *, int *, void *), void *data)
void remember_event(const char *eventname)
{
- int i=0, len;
+ int i = 0, len;
if (!eventname || (len = strlen(eventname)) == 0)
return;
while (i < evn_used) {
- if (!strncmp(eventname,ev_namelist[i].ev_name,len))
+ if (!strncmp(eventname, ev_namelist[i].ev_name, len))
return;
i++;
}
@@ -339,6 +346,7 @@ static void plot_one_event(struct graphics_context *gc, struct plot_info *pi, st
{
int i, depth = 0;
int x,y;
+ char buffer[80];
/* is plotting this event disabled? */
if (event->name) {
@@ -374,7 +382,11 @@ static void plot_one_event(struct graphics_context *gc, struct plot_info *pi, st
cairo_line_to(gc->cr, x-9, y+4);
cairo_stroke(gc->cr);
/* we display the event on screen - so translate */
- attach_tooltip(x-15, y-6, 12, 12, _(event->name));
+ if (event->value)
+ snprintf(buffer, sizeof(buffer), "%s: %d", _(event->name), event->value);
+ else
+ snprintf(buffer, sizeof(buffer), "%s", _(event->name));
+ attach_tooltip(x-15, y-6, 12, 12, buffer);
}
static void plot_events(struct graphics_context *gc, struct plot_info *pi, struct dive *dive)
@@ -386,7 +398,8 @@ static void plot_events(struct graphics_context *gc, struct plot_info *pi, struc
return;
while (event) {
- plot_one_event(gc, pi, event, &tro);
+ if (event->flags != SAMPLE_FLAGS_BEGIN && event->flags != SAMPLE_FLAGS_END)
+ plot_one_event(gc, pi, event, &tro);
event = event->next;
}
}
@@ -928,8 +941,37 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi
move_to(gc, 0, 0);
for (i = 0; i < pi->nr; i++, entry++)
line_to(gc, entry->sec, entry->depth);
+
+ /* Show any ceiling we may have encountered */
+ for (i = pi->nr - 1; i >= 0; i--, entry--) {
+ if (entry->ceiling < entry->depth) {
+ line_to(gc, entry->sec, entry->ceiling);
+ } else {
+ line_to(gc, entry->sec, entry->depth);
+ }
+ }
cairo_close_path(gc->cr);
+ cairo_fill(gc->cr);
+
+ /* next show where we have been bad and crossed the ceiling */
+ pat = cairo_pattern_create_linear (0.0, 0.0, 0.0, 256.0 * plot_scale);
+ pattern_add_color_stop_rgba (gc, pat, 0, CEILING_SHALLOW);
+ pattern_add_color_stop_rgba (gc, pat, 1, CEILING_DEEP);
+ cairo_set_source(gc->cr, pat);
+ cairo_pattern_destroy(pat);
+ entry = pi->entry;
+ move_to(gc, 0, 0);
+ for (i = 0; i < pi->nr; i++, entry++)
+ line_to(gc, entry->sec, entry->depth);
+ for (i = pi->nr - 1; i >= 0; i--, entry--) {
+ if (entry->ceiling > entry->depth) {
+ line_to(gc, entry->sec, entry->ceiling);
+ } else {
+ line_to(gc, entry->sec, entry->depth);
+ }
+ }
+ cairo_close_path(gc->cr);
cairo_fill(gc->cr);
/* Now do it again for the velocity colors */
@@ -1509,10 +1551,12 @@ static int get_cylinder_index(struct dive *dive, struct event *ev)
return 0;
}
-static struct event *get_next_gaschange(struct event *event)
+static struct event *get_next_event(struct event *event, char *name)
{
+ if (!name || !*name)
+ return NULL;
while (event) {
- if (!strcmp(event->name, "gaschange"))
+ if (!strcmp(event->name, name))
return event;
event = event->next;
}
@@ -1537,7 +1581,7 @@ static int set_cylinder_index(struct plot_info *pi, int i, int cylinderindex, un
static void check_gas_change_events(struct dive *dive, struct plot_info *pi)
{
int i = 0, cylinderindex = 0;
- struct event *ev = get_next_gaschange(dive->events);
+ struct event *ev = get_next_event(dive->events, "gaschange");
if (!ev)
return;
@@ -1545,7 +1589,7 @@ static void check_gas_change_events(struct dive *dive, struct plot_info *pi)
do {
i = set_cylinder_index(pi, i, cylinderindex, ev->time.seconds);
cylinderindex = get_cylinder_index(dive, ev);
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
} while (ev);
set_cylinder_index(pi, i, cylinderindex, ~0u);
}
@@ -1554,11 +1598,11 @@ static void check_gas_change_events(struct dive *dive, struct plot_info *pi)
static int count_gas_change_events(struct dive *dive)
{
int count = 0;
- struct event *ev = get_next_gaschange(dive->events);
+ struct event *ev = get_next_event(dive->events, "gaschange");
while (ev) {
count++;
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
}
return count;
}
@@ -1574,14 +1618,14 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
{
int cylinderindex = -1;
int lastdepth, lastindex;
- int i, pi_idx, nr, sec, cyl;
+ int i, pi_idx, nr, sec, cyl, ceiling = 0;
size_t alloc_size;
struct plot_info *pi;
pr_track_t *track_pr[MAX_CYLINDERS] = {NULL, };
pr_track_t *pr_track, *current;
gboolean missing_pr = FALSE;
struct plot_data *entry = NULL;
- struct event *ev;
+ struct event *ev, *ceil_ev;
/* we want to potentially add synthetic plot_info elements for the gas changes */
nr = nr_samples + 4 + 2 * count_gas_change_events(dive);
@@ -1593,18 +1637,20 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
pi->nr = nr;
pi_idx = 2; /* the two extra events at the start */
/* check for gas changes before the samples start */
- ev = get_next_gaschange(dive->events);
+ ev = get_next_event(dive->events, "gaschange");
while (ev && ev->time.seconds < dive_sample->time.seconds) {
entry = pi->entry + pi_idx;
entry->sec = ev->time.seconds;
entry->depth = 0; /* is that always correct ? */
pi_idx++;
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
}
if (ev && ev->time.seconds == dive_sample->time.seconds) {
/* we already have a sample at the time of the event */
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
}
+ /* find the first deco/ceiling event (if any) */
+ ceil_ev = get_next_event(dive->events, "ceiling");
sec = 0;
lastindex = 0;
lastdepth = -1;
@@ -1614,13 +1660,22 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
struct sample *sample = dive_sample+i;
entry = pi->entry + i + pi_idx;
+ while (ceil_ev && ceil_ev->time.seconds <= sample->time.seconds) {
+ struct event *next_ceil_ev = get_next_event(ceil_ev->next, "ceiling");
+ if (!next_ceil_ev || next_ceil_ev->time.seconds > sample->time.seconds)
+ break;
+ ceil_ev = next_ceil_ev;
+ }
+ if (ceil_ev && ceil_ev->time.seconds <= sample->time.seconds) {
+ ceiling = ceil_ev->value;
+ ceil_ev = get_next_event(ceil_ev->next, "ceiling");
+ }
while (ev && ev->time.seconds < sample->time.seconds) {
/* insert two fake plot info structures for the end of
* the old tank and the start of the new tank */
if (ev->time.seconds == sample->time.seconds - 1) {
entry->sec = ev->time.seconds - 1;
(entry+1)->sec = ev->time.seconds;
- } else {
entry->sec = ev->time.seconds;
(entry+1)->sec = ev->time.seconds + 1;
}
@@ -1630,10 +1685,12 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
(sample->depth.mm - (sample-1)->depth.mm) / 2;
} else
entry->depth = sample->depth.mm;
- (entry+1)->depth = entry->depth;
+ (entry + 1)->depth = entry->depth;
+ entry->ceiling = ceiling;
+ (entry + 1)->ceiling = ceiling;
pi_idx += 2;
entry = pi->entry + i + pi_idx;
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
}
if (ev && ev->time.seconds == sample->time.seconds) {
/* we already have a sample at the time of the event
@@ -1641,13 +1698,15 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
* real even by one second (to keep time monotonous) */
entry->sec = ev->time.seconds;
entry->depth = sample->depth.mm;
+ entry->ceiling = ceiling;
pi_idx++;
entry = pi->entry + i + pi_idx;
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
delay = 1;
}
sec = entry->sec = sample->time.seconds + delay;
depth = entry->depth = sample->depth.mm;
+ entry->ceiling = ceiling;
entry->cylinderindex = sample->cylinderindex;
SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar;
entry->temperature = sample->temperature.mkelvin;
@@ -1666,7 +1725,7 @@ static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, str
entry->depth = 0; /* why are there gas changes after the dive is over? */
pi_idx++;
entry = pi->entry + i + pi_idx;
- ev = get_next_gaschange(ev->next);
+ ev = get_next_event(ev->next, "gaschange");
}
nr = nr_samples + pi_idx - 2;
check_gas_change_events(dive, pi);
diff --git a/uemis-downloader.c b/uemis-downloader.c
index 5267a0b00..6f85eca59 100644
--- a/uemis-downloader.c
+++ b/uemis-downloader.c
@@ -792,7 +792,15 @@ static char *do_uemis_download(struct argument_block *args)
if (! uemis_get_answer(mountpath, "processSync", 0, 2, &result))
goto bail;
param_buff[1] = "notempty";
- newmax = get_divenr(*max_dive_data, deviceid);
+ /* if we have an empty divelist then the user will almost
+ * certainly want to start downloading from the first dive on
+ * the Uemis; otherwise check which was the last dive
+ * downloaded */
+ if (dive_table.nr > 0)
+ newmax = get_divenr(*max_dive_data, deviceid);
+ else
+ newmax = strdup("0");
+
if (sscanf(newmax, "%d", &start) != 1)
start = 0;
for (;;) {
diff --git a/uemis.c b/uemis.c
index 25ff9bf49..72d20e360 100644
--- a/uemis.c
+++ b/uemis.c
@@ -18,6 +18,7 @@
#include "dive.h"
#include "uemis.h"
+#include <libdivecomputer/parser.h>
/*
* following code is based on code found in at base64.sourceforge.net/b64.c
@@ -119,7 +120,9 @@ bail:
return datalen;
}
-/* Create events from the flag bits;
+static gboolean in_deco;
+
+/* Create events from the flag bits and other data in the sample;
* These bits basically represent what is displayed on screen at sample time.
* Many of these 'warnings' are way hyper-active and seriously clutter the
* profile plot - so these are disabled by default
@@ -175,6 +178,21 @@ void uemis_event(struct dive *dive, struct sample *sample, uemis_sample_t *u_sam
add_event(dive, sample->time.seconds, 0, 0, 0, N_("Low Battery Alert"));
/* flags[7] reflects the little on screen icons that remind of previous
* warnings / alerts - not useful for events */
+
+ /* now add deco / ceiling events */
+ if (u_sample->p_amb_tol > dive->surface_pressure.mbar &&
+ u_sample->hold_time &&
+ u_sample->hold_time < 99) {
+ add_event(dive, sample->time.seconds, SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_BEGIN,
+ u_sample->hold_depth * 10, N_("ceiling"));
+ add_event(dive, sample->time.seconds, SAMPLE_EVENT_DECOSTOP, 0,
+ u_sample->hold_time * 60, N_("deco"));
+ in_deco = TRUE;
+ } else if (in_deco) {
+ in_deco = FALSE;
+ add_event(dive, sample->time.seconds, SAMPLE_EVENT_CEILING, SAMPLE_FLAGS_END,
+ 0, N_("ceiling"));
+ }
}
/*
@@ -190,10 +208,11 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
struct dive *dive = *divep;
int template, gasoffset;
+ in_deco = FALSE;
datalen = uemis_convert_base64(base64, &data);
dive->airtemp.mkelvin = *(uint16_t *)(data + 45) * 100 + 273150;
-
+ dive->surface_pressure.mbar = *(uint16_t *)(data +43);
/* dive template in use:
0 = air
1 = nitrox (B)