From 9df9fc088daedc71b56acc176cf3b8ee3de870fa Mon Sep 17 00:00:00 2001 From: Jan Schubert Date: Wed, 23 Jan 2013 20:12:24 +0100 Subject: Dive planning for closed circuit rebreather This misses a single issue to be used as a base for further discussion: The CC setpoint is used for the next segment, not the one specified for. I also have in mind to modify the existing code to use setpoints specified in mbar and plain integer instead of float values. Signed-off-by: Jan Schubert Signed-off-by: Dirk Hohndel --- dive.h | 3 ++- divelist.c | 2 +- planner.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/dive.h b/dive.h index 6a6ab3eee..0d14e43c0 100644 --- a/dive.h +++ b/dive.h @@ -587,6 +587,7 @@ struct divedatapoint { int depth; int o2; int he; + int po2; gboolean entered; struct divedatapoint *next; }; @@ -600,7 +601,7 @@ struct diveplan { }; void plan(struct diveplan *diveplan, char **cache_datap, struct dive **divep); -void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he); +void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he, int po2); void add_duration_to_nth_dp(struct diveplan *diveplan, int idx, int duration, gboolean is_rel); void add_depth_to_nth_dp(struct diveplan *diveplan, int idx, int depth); void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he); diff --git a/divelist.c b/divelist.c index f6ddb0cd3..d6c68eaaf 100644 --- a/divelist.c +++ b/divelist.c @@ -763,7 +763,7 @@ static int calculate_otu(struct dive *dive, struct divecomputer *dc) struct sample *psample = sample - 1; t = sample->time.seconds - psample->time.seconds; if (sample->po2) { - po2 = sample->po2; + po2 = sample->po2 / 1000; } else { int o2 = active_o2(dive, dc, sample->time); po2 = o2 / 1000.0 * depth_to_mbar(sample->depth.mm, dive) / 1000.0; diff --git a/planner.c b/planner.c index 1b63a768f..40b7d25f0 100644 --- a/planner.c +++ b/planner.c @@ -112,7 +112,7 @@ double tissue_at_end(struct dive *dive, char **cached_datap) for (j = t0; j < t1; j++) { int depth = interpolate(lastdepth, sample->depth.mm, j - t0, t1 - t0); tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0, - &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive); + &dive->cylinder[gasidx].gasmix, 1, sample->po2 / 1000, dive); } psample = sample; t0 = t1; @@ -139,7 +139,7 @@ int time_at_last_depth(struct dive *dive, int next_stop, char **cached_data_p) while (deco_allowed_depth(tissue_tolerance, surface_pressure, dive, 1) > next_stop) { wait++; tissue_tolerance = add_segment(depth_to_mbar(depth, dive) / 1000.0, - &dive->cylinder[gasidx].gasmix, 1, sample->po2, dive); + &dive->cylinder[gasidx].gasmix, 1, 1.1, dive); } return wait; } @@ -197,6 +197,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan) add_gas(dive, oldo2, oldhe); while (dp) { int o2 = dp->o2, he = dp->he; + int po2 = dp->po2; int time = dp->time; int depth = dp->depth; struct sample *sample; @@ -223,6 +224,7 @@ struct dive *create_dive_from_plan(struct diveplan *diveplan) /* Create sample */ sample = prepare_sample(dc); + sample->po2 = po2; sample->time.seconds = time; sample->depth.mm = depth; finish_sample(dc); @@ -250,7 +252,7 @@ void free_dps(struct divedatapoint *dp) } } -struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he) +struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he, int po2) { struct divedatapoint *dp; @@ -259,6 +261,7 @@ struct divedatapoint *create_dp(int time_incr, int depth, int o2, int he) dp->depth = depth; dp->o2 = o2; dp->he = he; + dp->po2 = po2; dp->entered = FALSE; dp->next = NULL; return dp; @@ -275,7 +278,7 @@ struct divedatapoint *get_nth_dp(struct diveplan *diveplan, int idx) dp = dp->next; } while (i++ <= idx) { - *ldpp = dp = create_dp(0, 0, 0, 0); + *ldpp = dp = create_dp(0, 0, 0, 0, 0); ldpp = &((*ldpp)->next); } return dp; @@ -309,6 +312,13 @@ void add_gas_to_nth_dp(struct diveplan *diveplan, int idx, int o2, int he) dp->o2 = o2; dp->he = he; } + +void add_po2_to_nth_dp(struct diveplan *diveplan, int idx, int po2) +{ + struct divedatapoint *dp = get_nth_dp(diveplan, idx); + dp->po2 = po2; +} + void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp) { struct divedatapoint **lastdp = &diveplan->dp; @@ -325,9 +335,9 @@ void add_to_end_of_diveplan(struct diveplan *diveplan, struct divedatapoint *dp) dp->time += lasttime; } -void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he) +void plan_add_segment(struct diveplan *diveplan, int duration, int depth, int o2, int he, int po2) { - struct divedatapoint *dp = create_dp(duration, depth, o2, he); + struct divedatapoint *dp = create_dp(duration, depth, o2, he, po2); add_to_end_of_diveplan(diveplan, dp); } @@ -528,7 +538,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep) { struct dive *dive; struct sample *sample; - int wait_time, o2, he; + int wait_time, o2, he, po2; int ceiling, depth, transitiontime; int stopidx, gi; double tissue_tolerance; @@ -551,6 +561,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep) o2 = dive->cylinder[0].gasmix.o2.permille; he = dive->cylinder[0].gasmix.he.permille; get_gas_from_events(&dive->dc, sample->time.seconds, &o2, &he); + po2 = dive->dc.sample[dive->dc.samples - 1].po2; depth = dive->dc.sample[dive->dc.samples - 1].depth.mm; tissue_tolerance = tissue_at_end(dive, cached_datap); ceiling = deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, dive, 1); @@ -581,7 +592,7 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep) #if DEBUG_PLAN & 2 printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx] / 1000.0); #endif - plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he); + plan_add_segment(diveplan, transitiontime, stoplevels[stopidx], o2, he, po2); /* re-create the dive */ delete_single_dive(dive_table.nr - 1); *divep = dive = create_dive_from_plan(diveplan); @@ -605,12 +616,12 @@ void plan(struct diveplan *diveplan, char **cached_datap, struct dive **divep) printf("waittime %d:%02d at depth %5.2lfm\n", FRACTION(wait_time, 60), stoplevels[stopidx] / 1000.0); #endif if (wait_time) - plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he); + plan_add_segment(diveplan, wait_time, stoplevels[stopidx], o2, he, po2); transitiontime = (stoplevels[stopidx] - stoplevels[stopidx - 1]) / 150; #if DEBUG_PLAN & 2 printf("transitiontime %d:%02d to depth %5.2lfm\n", FRACTION(transitiontime, 60), stoplevels[stopidx - 1] / 1000.0); #endif - plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he); + plan_add_segment(diveplan, transitiontime, stoplevels[stopidx - 1], o2, he, po2); /* re-create the dive */ delete_single_dive(dive_table.nr - 1); *divep = dive = create_dive_from_plan(diveplan); @@ -827,6 +838,29 @@ static int validate_depth(const char *text, int *mm_p) return 1; } +static int validate_po2(const char *text, int *mbar_po2) +{ + int po2; + + if (!text) + return 0; + + po2 = get_tenths(text, &text); + if (po2 < 0) + return 0; + + while (isspace(*text)) + text++; + + while (isspace(*text)) + text++; + if (*text) + return 0; + + *mbar_po2 = po2 * 100; + return 1; +} + static int validate_volume(const char *text, int *sac) { int volume, imperial; @@ -880,7 +914,7 @@ static GtkWidget *add_entry_to_box(GtkWidget *box, const char *label) } #define MAX_WAYPOINTS 8 -GtkWidget *entry_depth[MAX_WAYPOINTS], *entry_duration[MAX_WAYPOINTS], *entry_gas[MAX_WAYPOINTS]; +GtkWidget *entry_depth[MAX_WAYPOINTS], *entry_duration[MAX_WAYPOINTS], *entry_gas[MAX_WAYPOINTS], *entry_po2[MAX_WAYPOINTS]; int nr_waypoints = 0; static GtkListStore *gas_model = NULL; struct diveplan diveplan = {}; @@ -980,6 +1014,19 @@ static gboolean duration_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpoint return FALSE; } +static gboolean po2_focus_out_cb(GtkWidget *entry, GdkEvent * event, gpointer data) +{ + const char *po2text; + int po2; + int idx = data - NULL; + + po2text = gtk_entry_get_text(GTK_ENTRY(entry)); + if (validate_po2(po2text, &po2)) + add_po2_to_nth_dp(&diveplan, idx, po2); + show_planned_dive(); + return FALSE; +} + /* Subsurface follows the lead of most divecomputers to use times * without timezone - so all times are implicitly assumed to be * local time of the dive location; so in order to give the current @@ -1077,15 +1124,19 @@ static void add_waypoint_widgets(GtkWidget *box, int idx) entry_depth[idx] = add_entry_to_box(hbox, _("Ending Depth")); entry_duration[idx] = add_entry_to_box(hbox, _("Segment Time")); entry_gas[idx] = add_gas_combobox_to_box(hbox, _("Gas Used"), idx); + entry_po2[idx] = add_entry_to_box(hbox, _("CC SetPoint")); } else { entry_depth[idx] = add_entry_to_box(hbox, NULL); entry_duration[idx] = add_entry_to_box(hbox, NULL); entry_gas[idx] = add_gas_combobox_to_box(hbox, NULL, idx); + entry_po2[idx] = add_entry_to_box(hbox, NULL); } gtk_widget_add_events(entry_depth[idx], GDK_FOCUS_CHANGE_MASK); g_signal_connect(entry_depth[idx], "focus-out-event", G_CALLBACK(depth_focus_out_cb), NULL + idx); gtk_widget_add_events(entry_duration[idx], GDK_FOCUS_CHANGE_MASK); g_signal_connect(entry_duration[idx], "focus-out-event", G_CALLBACK(duration_focus_out_cb), NULL + idx); + gtk_widget_add_events(entry_po2[idx], GDK_FOCUS_CHANGE_MASK); + g_signal_connect(entry_po2[idx], "focus-out-event", G_CALLBACK(po2_focus_out_cb), NULL + idx); } static void add_waypoint_cb(GtkButton *button, gpointer _data) @@ -1141,7 +1192,8 @@ void input_plan() "An empty gas means 'use previous gas' (or AIR if no gas was specified).\n" "An entry that has a depth and a gas given but no time is special; it " "informs the planner that the gas specified is available for the ascent " - "once the depth given has been reached.")); + "once the depth given has been reached.\n" + "CC SetPoint specifies CC dives, leave empty for OC.")); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(outervbox), label, TRUE, TRUE, 0); -- cgit v1.2.3-70-g09d2