diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | color.h | 1 | ||||
-rw-r--r-- | dive.c | 61 | ||||
-rw-r--r-- | dive.h | 2 | ||||
-rw-r--r-- | gtk-gui.c | 2 | ||||
-rw-r--r-- | parse-xml.c | 2 | ||||
-rw-r--r-- | profile.c | 105 | ||||
-rw-r--r-- | uemis-downloader.c | 10 | ||||
-rw-r--r-- | uemis.c | 23 |
9 files changed, 179 insertions, 29 deletions
@@ -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 @@ -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 @@ -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; } @@ -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; @@ -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); } @@ -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 (;;) { @@ -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) |