mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-28 05:00:20 +00:00
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 <Jan.Schubert@GMX.li> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
37282176d5
commit
9df9fc088d
3 changed files with 67 additions and 14 deletions
3
dive.h
3
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
76
planner.c
76
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.</small>"));
|
||||
"once the depth given has been reached.\n"
|
||||
"CC SetPoint specifies CC dives, leave empty for OC.</small>"));
|
||||
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);
|
||||
|
|
Loading…
Reference in a new issue