diff options
author | Dirk Hohndel <dirk@hohndel.org> | 2012-12-01 13:02:30 -0800 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2012-12-04 21:05:26 -0800 |
commit | dcb6574dc4252c4ff598efb17269b7f1255afec1 (patch) | |
tree | c774cd0bb3c85c36988976ce1ab6086c9e996f7b | |
parent | 7383f7fe0a77c906aafcd61ccfc09dc1866c5416 (diff) | |
download | subsurface-dcb6574dc4252c4ff598efb17269b7f1255afec1.tar.gz |
Improve deco handling and add NDL support
This commit changes the code that was recently introduced to deal with
deco ceilings. Instead of handling these through events we now store the
ceiling (which in reality is the deepest deco stop with all known dive
computers) and the stop time at that ceiling in the samples.
This also adds support for NDL (non stop dive limit) which both dive
computers that appear to give us ceiling / deco information appear to
give us as well (when the diver isn't in deco).
If the mouse hovers over the profile we now add support for displaying the
NDL, the current deco obligation and (if we are able to tell from the
data) whether we are at a safety stop.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r-- | dive.h | 3 | ||||
-rw-r--r-- | gtk-gui.c | 2 | ||||
-rw-r--r-- | libdivecomputer.c | 24 | ||||
-rw-r--r-- | parse-xml.c | 15 | ||||
-rw-r--r-- | profile.c | 173 | ||||
-rw-r--r-- | save-xml.c | 27 |
6 files changed, 151 insertions, 93 deletions
@@ -223,6 +223,9 @@ struct sample { temperature_t temperature; pressure_t cylinderpressure; int cylinderindex; + duration_t ndl; + duration_t stoptime; + depth_t stopdepth; }; /* @@ -1274,7 +1274,7 @@ static gboolean profile_tooltip (GtkWidget *widget, gint x, gint y, gint tx = x - drawing_area->x; /* get transformed coordinates */ gint ty = y - drawing_area->y; gint width, height, time = -1; - char buffer[80], plot[80]; + char buffer[256], plot[256]; const char *event = ""; if (tx < 0 || ty < 0) diff --git a/libdivecomputer.c b/libdivecomputer.c index dba6e6fe5..2162c0fff 100644 --- a/libdivecomputer.c +++ b/libdivecomputer.c @@ -10,6 +10,7 @@ #include "display-gtk.h" #include "libdivecomputer.h" +#include "libdivecomputer/version.h" /* Christ. Libdivecomputer has the worst configuration system ever. */ #ifdef HW_FROG_H @@ -86,7 +87,7 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp }; const int nr_events = sizeof(events) / sizeof(const char *); const char *name; - + static int stoptime = 0, stopdepth = 0, ndl = 0; /* * Just ignore surface events. They are pointless. What "surface" * means depends on the dive computer (and possibly even settings @@ -96,6 +97,27 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp if (value.event.type == SAMPLE_EVENT_SURFACE) return; + /* libdivecomputer 0.3 provides us with deco / ndl information for at least + * the OSTC. Sadly, it does so through events - so we convert this into our + * preferred sample format here */ +#if DC_VERSION_CHECK(0, 3, 0) + if (value.event.type == SAMPLE_EVENT_DECOSTOP) { + /* packed value - time in seconds in high 16 bit + * depth in m(!) in low 16 bits */ + stoptime = value.event.value >> 16; + stopdepth = (value.event.value && 0xFFFF) * 1000; + ndl = 0; + } + if (value.event.type == SAMPLE_EVENT_NDL) { + stopdepth = 0; + stoptime = 0; + ndl = value.event.value; + } + sample->stoptime.seconds = stoptime; + sample->stopdepth.mm = stopdepth; + sample->ndl.seconds = ndl; +#endif + /* * Other evens might be more interesting, but for now we just print them out. */ diff --git a/parse-xml.c b/parse-xml.c index 9226aa63d..2470f8bb4 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -168,6 +168,7 @@ static struct { } cur_event; static struct tm cur_tm; static int cur_cylinder_index, cur_ws_index; +static int lastndl, laststoptime, laststopdepth; static enum import_source { UNKNOWN, @@ -668,6 +669,12 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu return; if (MATCH(".sample.time", sampletime, &sample->time)) return; + if (MATCH(".sample.ndl", sampletime, &sample->ndl)) + return; + if (MATCH(".sample.stoptime", sampletime, &sample->stoptime)) + return; + if (MATCH(".sample.stopdepth", depth, &sample->stopdepth)) + return; switch (import_source) { case DIVINGLOG: @@ -1027,6 +1034,9 @@ static void ws_end(void) static void sample_start(void) { cur_sample = prepare_sample(get_dc()); + cur_sample->ndl.seconds = lastndl; + cur_sample->stoptime.seconds = laststoptime; + cur_sample->stopdepth.mm = laststopdepth; } static void sample_end(void) @@ -1035,6 +1045,9 @@ static void sample_end(void) return; finish_sample(get_dc()); + lastndl = cur_sample->ndl.seconds; + laststoptime = cur_sample->stoptime.seconds; + laststopdepth = cur_sample->stopdepth.mm; cur_sample = NULL; } @@ -1058,6 +1071,8 @@ static void divecomputer_start(void) /* .. this is the one we'll use */ cur_dc = dc; + + lastndl = laststoptime = laststopdepth = 0; } static void divecomputer_end(void) @@ -37,6 +37,7 @@ struct plot_info { int endpressure, maxpressure; int mintemp, maxtemp, endtemp; double endtempcoord; + gboolean has_ndl; struct plot_data { unsigned int same_cylinder:1; unsigned int cylinderindex; @@ -47,7 +48,9 @@ struct plot_info { int temperature; /* Depth info */ int depth; - int ceiling; + int ndl; + int stoptime; + int stopdepth; int smoothed; double po2, pn2, phe; velocity_t velocity; @@ -194,15 +197,17 @@ static void dump_pi (struct plot_info *pi) " maxpressure:%d mintemp:%d maxtemp:%d\n", pi->nr, pi->maxtime, pi->meandepth, pi->maxdepth, pi->maxpressure, pi->mintemp, pi->maxtemp); - for (i = 0; i < pi->nr; i++) + for (i = 0; i < pi->nr; i++) { + struct plot_data *entry = &pi->entry[i]; printf(" entry[%d]:{same_cylinder:%d cylinderindex:%d sec:%d pressure:{%d,%d}\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].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); + " time:%d:%02d temperature:%d depth:%d stopdepth:%d stoptime:%d ndl:%d smoothed:%d po2:%lf phe:%lf pn2:%lf sum-pp %lf}\n", + i, entry->same_cylinder, entry->cylinderindex, entry->sec, + entry->pressure[0], entry->pressure[1], + entry->sec / 60, entry->sec % 60, + entry->temperature, entry->depth, entry->stopdepth, entry->stoptime, entry->ndl, entry->smoothed, + entry->po2, entry->phe, entry->pn2, + entry->po2 + entry->phe + entry->pn2); + } printf(" }\n"); } @@ -370,50 +375,27 @@ static void plot_one_event(struct graphics_context *gc, struct plot_info *pi, st break; depth = data->depth; } - /* don't draw NDL event triangles */ - if (strcmp(event->name, "non stop time")) { - /* draw a little triangular marker and attach tooltip */ - x = SCALEX(gc, event->time.seconds); - y = SCALEY(gc, depth); - set_source_rgba(gc, ALERT_BG); - cairo_move_to(gc->cr, x-15, y+6); - cairo_line_to(gc->cr, x-3 , y+6); - cairo_line_to(gc->cr, x-9, y-6); - cairo_line_to(gc->cr, x-15, y+6); - cairo_stroke_preserve(gc->cr); - cairo_fill(gc->cr); - set_source_rgba(gc, ALERT_FG); - cairo_move_to(gc->cr, x-9, y-3); - cairo_line_to(gc->cr, x-9, y+1); - cairo_move_to(gc->cr, x-9, y+4); - cairo_line_to(gc->cr, x-9, y+4); - cairo_stroke(gc->cr); - } + /* draw a little triangular marker and attach tooltip */ + x = SCALEX(gc, event->time.seconds); + y = SCALEY(gc, depth); + set_source_rgba(gc, ALERT_BG); + cairo_move_to(gc->cr, x-15, y+6); + cairo_line_to(gc->cr, x-3 , y+6); + cairo_line_to(gc->cr, x-9, y-6); + cairo_line_to(gc->cr, x-15, y+6); + cairo_stroke_preserve(gc->cr); + cairo_fill(gc->cr); + set_source_rgba(gc, ALERT_FG); + cairo_move_to(gc->cr, x-9, y-3); + cairo_line_to(gc->cr, x-9, y+1); + cairo_move_to(gc->cr, x-9, y+4); + cairo_line_to(gc->cr, x-9, y+4); + cairo_stroke(gc->cr); /* we display the event on screen - so translate */ - if (event->value) { - if (event->type == SAMPLE_EVENT_DECOSTOP) { - /* deal with the packed depth / time data */ - int seconds = (event->value >> 16) % 60; - if (seconds) - snprintf(buffer, sizeof(buffer), "%s: %dmin %ds @ %dm", _(event->name), (event->value >> 16) / 60, - seconds, event->value & 0xFFFF); - else - snprintf(buffer, sizeof(buffer), "%s: %dmin @ %dm", _(event->name), (event->value >> 16) / 60, - event->value & 0xFFFF); -#if DC_VERSION_CHECK(0, 3, 0) - } else if (event->type == SAMPLE_EVENT_NDL) { - int seconds = event->value % 60; - if (seconds) - snprintf(buffer, sizeof(buffer), "%s: %dmin %ds", _(event->name), event->value / 60, seconds); - else - snprintf(buffer, sizeof(buffer), "%s: %dmin", _(event->name), event->value / 60); -#endif - } else { - snprintf(buffer, sizeof(buffer), "%s: %d", _(event->name), event->value); - } - } else { + 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); } @@ -1026,8 +1008,11 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi /* 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); + if (entry->ndl) { + /* non-zero NDL implies this is a safety stop, no ceiling */ + line_to(gc, entry->sec, 0); + } else if (entry->stopdepth < entry->depth) { + line_to(gc, entry->sec, entry->stopdepth); } else { line_to(gc, entry->sec, entry->depth); } @@ -1047,8 +1032,8 @@ static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi 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); + if (entry->ndl == 0 && entry->stopdepth > entry->depth) { + line_to(gc, entry->sec, entry->stopdepth); } else { line_to(gc, entry->sec, entry->depth); } @@ -1707,14 +1692,14 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer { int cylinderindex = -1; int lastdepth, lastindex; - int i, pi_idx, nr, sec, cyl, ceiling = 0; + int i, pi_idx, nr, sec, cyl, stoptime, ndl, stopdepth; 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, *deco_ev, *ndl_ev; + struct event *ev; double amb_pressure; /* we want to potentially add synthetic plot_info elements for the gas changes */ @@ -1739,9 +1724,6 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer /* we already have a sample at the time of the event */ ev = get_next_event(ev->next, "gaschange"); } - /* find the first deco/ceiling event (if any) */ - deco_ev = get_next_event(dc->events, "deco stop"); - ndl_ev = get_next_event(dc->events, "non stop time"); sec = 0; lastindex = 0; lastdepth = -1; @@ -1756,22 +1738,10 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer continue; } entry = pi->entry + i + pi_idx; - while (deco_ev && deco_ev->time.seconds <= sample->time.seconds) { - struct event *next_deco_ev = get_next_event(deco_ev->next, "deco stop"); - if (!next_deco_ev || next_deco_ev->time.seconds > sample->time.seconds) - break; - deco_ev = next_deco_ev; - } - if (deco_ev) - ndl_ev = get_next_event(deco_ev, "non stop time"); - /* if there is an NDL event that comes after the latest deco stop event but - * prior to this sample, then deco has ended */ - if (ndl_ev && ndl_ev->time.seconds <= sample->time.seconds) { - ceiling = 0; - } else if (deco_ev && deco_ev->time.seconds <= sample->time.seconds) { - ceiling = 1000 * (deco_ev->value & 0xffff); - deco_ev = get_next_event(deco_ev->next, "deco stop"); - } + ndl = sample->ndl.seconds; + pi->has_ndl |= ndl; + stopdepth = sample->stopdepth.mm; + stoptime = sample->stoptime.seconds; 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 */ @@ -1789,8 +1759,12 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer } else entry->depth = sample->depth.mm; (entry + 1)->depth = entry->depth; - entry->ceiling = ceiling; - (entry + 1)->ceiling = ceiling; + entry->stopdepth = stopdepth; + entry->stoptime = stoptime; + entry->ndl = ndl; + (entry + 1)->stopdepth = stopdepth; + (entry + 1)->stoptime = stoptime; + (entry + 1)->ndl = ndl; pi_idx += 2; entry = pi->entry + i + pi_idx; ev = get_next_event(ev->next, "gaschange"); @@ -1801,7 +1775,9 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer * real even by one second (to keep time monotonous) */ entry->sec = ev->time.seconds; entry->depth = sample->depth.mm; - entry->ceiling = ceiling; + entry->stopdepth = stopdepth; + entry->stoptime = stoptime; + entry->ndl = ndl; pi_idx++; entry = pi->entry + i + pi_idx; ev = get_next_event(ev->next, "gaschange"); @@ -1809,7 +1785,9 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer } sec = entry->sec = sample->time.seconds + delay; depth = entry->depth = sample->depth.mm; - entry->ceiling = ceiling; + entry->stopdepth = stopdepth; + entry->stoptime = stoptime; + entry->ndl = ndl; entry->cylinderindex = sample->cylinderindex; SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar; entry->temperature = sample->temperature.mkelvin; @@ -2061,7 +2039,8 @@ void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale) } } -static void plot_string(struct plot_data *entry, char *buf, size_t bufsize, int depth, int pressure, int temp) +static void plot_string(struct plot_data *entry, char *buf, size_t bufsize, + int depth, int pressure, int temp, gboolean has_ndl) { int pressurevalue; const char *depth_unit, *pressure_unit, *temp_unit; @@ -2080,6 +2059,30 @@ static void plot_string(struct plot_data *entry, char *buf, size_t bufsize, int memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\nT:%.1f %s", buf2, tempvalue, temp_unit); } + if (entry->stopdepth) { + depthvalue = get_depth_units(entry->stopdepth, NULL, &depth_unit); + memcpy(buf2, buf, bufsize); + if (entry->ndl) { + /* this is a safety stop as we still have ndl */ + if (entry->stoptime) + snprintf(buf, bufsize, "%s\nSafetystop:%umin @ %.0f %s", buf2, entry->stoptime / 60, + depthvalue, depth_unit); + else + snprintf(buf, bufsize, "%s\nSafetystop:unkn time @ %.0f %s", buf2, + depthvalue, depth_unit); + } else { + /* actual deco stop */ + if (entry->stoptime) + snprintf(buf, bufsize, "%s\nDeco:%umin @ %.0f %s", buf2, entry->stoptime / 60, + depthvalue, depth_unit); + else + snprintf(buf, bufsize, "%s\nDeco:unkn time @ %.0f %s", buf2, + depthvalue, depth_unit); + } + } else if (has_ndl) { + memcpy(buf2, buf, bufsize); + snprintf(buf, bufsize, "%s\nNDL:%umin", buf2, entry->ndl / 60); + } if (partial_pressure_graphs.po2) { memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, "%s\npO" UTF8_SUBSCRIPT_2 ":%.1f", buf2, entry->po2); @@ -2110,11 +2113,9 @@ void get_plot_details(struct graphics_context *gc, int time, char *buf, size_t b temp = entry->temperature; if (GET_PRESSURE(entry)) pressure = GET_PRESSURE(entry); - if (entry->sec >= time) { - plot_string(entry, buf, bufsize, entry->depth, pressure, temp); - return; - } + if (entry->sec >= time) + break; } - plot_string(entry, buf, bufsize, entry->depth, pressure, temp); + plot_string(entry, buf, bufsize, entry->depth, pressure, temp, pi->has_ndl); } } diff --git a/save-xml.c b/save-xml.c index 8d7d7f889..d4bc36cab 100644 --- a/save-xml.c +++ b/save-xml.c @@ -293,7 +293,7 @@ static void show_index(FILE *f, int value, const char *pre, const char *post) fprintf(f, " %s%d%s", pre, value, post); } -static void save_sample(FILE *f, struct sample *sample) +static void save_sample(FILE *f, struct sample *sample, const struct sample *prev) { fprintf(f, " <sample time='%u:%02u min'", FRACTION(sample->time.seconds,60)); show_milli(f, " depth='", sample->depth.mm, " m", "'"); @@ -301,6 +301,13 @@ static void save_sample(FILE *f, struct sample *sample) show_pressure(f, sample->cylinderpressure, " pressure='", "'"); if (sample->cylinderindex) fprintf(f, " cylinderindex='%d'", sample->cylinderindex); + /* the deco/ndl values are stored whenever they change */ + if (sample->ndl.seconds != prev->ndl.seconds) + fprintf(f, " ndl='%u:%02u min'", FRACTION(sample->ndl.seconds, 60)); + if (sample->stoptime.seconds != prev->stoptime.seconds) + fprintf(f, " stoptime='%u:%02u min'", FRACTION(sample->stoptime.seconds, 60)); + if (sample->stopdepth.mm != prev->stopdepth.mm) + show_milli(f, " stopdepth='", sample->stopdepth.mm, " m", "'"); fprintf(f, " />\n"); } @@ -346,10 +353,20 @@ static void save_trip(FILE *f, dive_trip_t *trip) show_utf8(f, trip->notes, "<notes>","</notes>\n", 0); } -static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc) +static void save_samples(FILE *f, int nr, struct sample *s) { - int i; + static const struct sample empty_sample; + const struct sample *prev = &empty_sample; + + while (--nr >= 0) { + save_sample(f, s, prev); + prev = s; + s++; + } +} +static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc) +{ fprintf(f, " <divecomputer"); if (dc->model) show_utf8(f, dc->model, " model='", "'", 1); @@ -361,8 +378,8 @@ static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc) show_date(f, dc->when); fprintf(f, ">\n"); save_events(f, dc->events); - for (i = 0; i < dc->samples; i++) - save_sample(f, dc->sample+i); + save_samples(f, dc->samples, dc->sample); + fprintf(f, " </divecomputer>\n"); } |