summaryrefslogtreecommitdiffstats
path: root/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'planner.c')
-rw-r--r--planner.c183
1 files changed, 142 insertions, 41 deletions
diff --git a/planner.c b/planner.c
index d12f660f5..3c9b9df33 100644
--- a/planner.c
+++ b/planner.c
@@ -115,7 +115,7 @@ int get_gasidx(struct dive *dive, struct gasmix *mix)
int gasidx = -1;
while (++gasidx < MAX_CYLINDERS)
- if (gasmix_distance(&dive->cylinder[gasidx].gasmix, mix) < 200)
+ if (gasmix_distance(&dive->cylinder[gasidx].gasmix, mix) < 100)
return gasidx;
return -1;
}
@@ -210,7 +210,7 @@ static int verify_gas_exists(struct gasmix mix_in)
cyl = displayed_dive.cylinder + i;
if (cylinder_nodata(cyl))
continue;
- if (gasmix_distance(&cyl->gasmix, &mix_in) < 200)
+ if (gasmix_distance(&cyl->gasmix, &mix_in) < 100)
return i;
}
fprintf(stderr, "this gas %s should have been on the cylinder list\nThings will fail now\n", gasname(&mix_in));
@@ -307,11 +307,10 @@ static void create_dive_from_plan(struct diveplan *diveplan, bool track_gas)
/* Check for SetPoint change */
if (oldpo2 != po2) {
- if (lasttime)
- /* this is a bad idea - we should get a different SAMPLE_EVENT type
- * reserved for this in libdivecomputer... overloading SMAPLE_EVENT_PO2
- * with a different meaning will only cause confusion elsewhere in the code */
- add_event(dc, lasttime, SAMPLE_EVENT_PO2, 0, po2, "SP change");
+ /* this is a bad idea - we should get a different SAMPLE_EVENT type
+ * reserved for this in libdivecomputer... overloading SMAPLE_EVENT_PO2
+ * with a different meaning will only cause confusion elsewhere in the code */
+ add_event(dc, lasttime, SAMPLE_EVENT_PO2, 0, po2, "SP change");
oldpo2 = po2;
}
@@ -521,7 +520,7 @@ static unsigned int *sort_stops(int *dstops, int dnr, struct gaschanges *gstops,
static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_disclaimer, int error)
{
- char buffer[20000], temp[1000];
+ char buffer[2000000], temp[100000];
int len, lastdepth = 0, lasttime = 0, lastsetpoint = -1, newdepth = 0, lastprintdepth = 0;
struct divedatapoint *dp = diveplan->dp;
bool gaschange = !plan_verbatim, postponed = plan_verbatim;
@@ -780,7 +779,7 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
dive->notes = strdup(buffer);
}
-int ascend_velocity(int depth, int avg_depth, int bottom_time)
+int ascent_velocity(int depth, int avg_depth, int bottom_time)
{
/* We need to make this configurable */
@@ -801,7 +800,62 @@ int ascend_velocity(int depth, int avg_depth, int bottom_time)
}
}
-int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool show_disclaimer)
+void track_ascent_gas(int depth, cylinder_t *cylinder, int avg_depth, int bottom_time, bool safety_stop)
+{
+ while (depth > 0) {
+ int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
+ if (deltad > depth)
+ deltad = depth;
+ update_cylinder_pressure(&displayed_dive, depth, depth - deltad, TIMESTEP, prefs.decosac, cylinder, true);
+ if (depth <= 5000 && depth >= (5000 - deltad) && safety_stop) {
+ update_cylinder_pressure(&displayed_dive, 5000, 5000, 180, prefs.decosac, cylinder, true);
+ safety_stop = false;
+ }
+ depth -= deltad;
+ }
+}
+
+bool trial_ascent(int trial_depth, int stoplevel, int avg_depth, int bottom_time, double tissue_tolerance, struct gasmix *gasmix, int po2, double surface_pressure)
+{
+
+ bool clear_to_ascend = true;
+ char *trial_cache = NULL;
+
+ cache_deco_state(tissue_tolerance, &trial_cache);
+ while (trial_depth > stoplevel) {
+ int deltad = ascent_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP;
+ if (deltad > trial_depth) /* don't test against depth above surface */
+ deltad = trial_depth;
+ tissue_tolerance = add_segment(depth_to_mbar(trial_depth, &displayed_dive) / 1000.0,
+ gasmix,
+ TIMESTEP, po2, &displayed_dive, prefs.decosac);
+ if (deco_allowed_depth(tissue_tolerance, surface_pressure, &displayed_dive, 1) > trial_depth - deltad) {
+ /* We should have stopped */
+ clear_to_ascend = false;
+ break;
+ }
+ trial_depth -= deltad;
+ }
+ restore_deco_state(trial_cache);
+ return clear_to_ascend;
+}
+
+bool enough_gas(int current_cylinder)
+{
+ cylinder_t *cyl;
+ cyl = &displayed_dive.cylinder[current_cylinder];
+
+ if (!cyl->start.mbar)
+ return true;
+ if (cyl->type.size.mliter)
+ return (float) (cyl->end.mbar - prefs.reserve_gas) * cyl->type.size.mliter / 1000.0 > (float) cyl->deco_gas_used.mliter;
+ else
+ return true;
+}
+
+// Work out the stops. Return value is if there were any mandatory stops.
+
+bool plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool show_disclaimer)
{
struct sample *sample;
int po2;
@@ -813,11 +867,10 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
struct gaschanges *gaschanges = NULL;
int gaschangenr;
int *stoplevels = NULL;
- char *trial_cache = NULL;
bool stopping = false;
bool clear_to_ascend;
int clock, previous_point_time;
- int avg_depth, bottom_time = 0;
+ int avg_depth, max_depth, bottom_time = 0;
int last_ascend_rate;
int best_first_ascend_cylinder;
struct gasmix gas;
@@ -825,12 +878,24 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
int breaktime = -1;
int breakcylinder = 0;
int error = 0;
+ bool decodive = false;
set_gf(diveplan->gflow, diveplan->gfhigh, prefs.gf_low_at_maxdepth);
if (!diveplan->surface_pressure)
diveplan->surface_pressure = SURFACE_PRESSURE;
create_dive_from_plan(diveplan, is_planner);
+ if (prefs.verbatim_plan)
+ plan_verbatim = true;
+ if (prefs.display_runtime)
+ plan_display_runtime = true;
+ if (prefs.display_duration)
+ plan_display_duration = true;
+ if (prefs.display_transitions)
+ plan_display_transitions = true;
+ if (prefs.last_stop)
+ decostoplevels[1] = 6000;
+
/* Let's start at the last 'sample', i.e. the last manually entered waypoint. */
sample = &displayed_dive.dc.sample[displayed_dive.dc.samples - 1];
@@ -842,15 +907,15 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
current_cylinder = 0;
}
depth = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].depth.mm;
- avg_depth = average_depth(diveplan);
- last_ascend_rate = ascend_velocity(depth, avg_depth, bottom_time);
+ average_max_depth(diveplan, &avg_depth, &max_depth);
+ last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
/* if all we wanted was the dive just get us back to the surface */
if (!is_planner) {
transitiontime = depth / 75; /* this still needs to be made configurable */
plan_add_segment(diveplan, transitiontime, 0, gas, po2, false);
create_dive_from_plan(diveplan, is_planner);
- return(error);
+ return(false);
}
tissue_tolerance = tissue_at_end(&displayed_dive, cached_datap);
@@ -881,6 +946,57 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
/* Keep time during the ascend */
bottom_time = clock = previous_point_time = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].time.seconds;
gi = gaschangenr - 1;
+ if(prefs.recreational_mode) {
+ bool safety_stop = prefs.safetystop && max_depth >= 10000;
+ track_ascent_gas(depth, &displayed_dive.cylinder[current_cylinder], avg_depth, bottom_time, safety_stop);
+ // How long can we stay at the current depth and still directly ascent to the surface?
+ while (trial_ascent(depth, 0, avg_depth, bottom_time, tissue_tolerance, &displayed_dive.cylinder[current_cylinder].gasmix,
+ po2, diveplan->surface_pressure / 1000.0) &&
+ enough_gas(current_cylinder)) {
+ tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0,
+ &displayed_dive.cylinder[current_cylinder].gasmix,
+ DECOTIMESTEP, po2, &displayed_dive, prefs.bottomsac);
+ update_cylinder_pressure(&displayed_dive, depth, depth, DECOTIMESTEP, prefs.bottomsac, &displayed_dive.cylinder[current_cylinder], false);
+ clock += DECOTIMESTEP;
+ }
+ clock -= DECOTIMESTEP;
+ plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, true);
+ previous_point_time = clock;
+ do {
+ /* Ascend to surface */
+ int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
+ if (ascent_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) {
+ plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
+ previous_point_time = clock;
+ last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
+ }
+ if (depth - deltad < 0)
+ deltad = depth;
+
+ tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0,
+ &displayed_dive.cylinder[current_cylinder].gasmix,
+ TIMESTEP, po2, &displayed_dive, prefs.decosac);
+ clock += TIMESTEP;
+ depth -= deltad;
+ if (depth <= 5000 && depth >= (5000 - deltad) && safety_stop) {
+ plan_add_segment(diveplan, clock - previous_point_time, 5000, gas, po2, false);
+ previous_point_time = clock;
+ clock += 180;
+ plan_add_segment(diveplan, clock - previous_point_time, 5000, gas, po2, false);
+ previous_point_time = clock;
+ safety_stop = false;
+ }
+ } while (depth > 0);
+ plan_add_segment(diveplan, clock - previous_point_time, 0, gas, po2, false);
+ create_dive_from_plan(diveplan, is_planner);
+ add_plan_to_notes(diveplan, &displayed_dive, show_disclaimer, error);
+ fixup_dc_duration(&displayed_dive.dc);
+
+ free(stoplevels);
+ free(gaschanges);
+
+ return(false);
+ }
if (best_first_ascend_cylinder != current_cylinder) {
stopping = true;
@@ -897,12 +1013,12 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
/* We will break out when we hit the surface */
do {
/* Ascend to next stop depth */
- int deltad = ascend_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
- if (ascend_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) {
+ int deltad = ascent_velocity(depth, avg_depth, bottom_time) * TIMESTEP;
+ if (ascent_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) {
plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false);
previous_point_time = clock;
stopping = false;
- last_ascend_rate = ascend_velocity(depth, avg_depth, bottom_time);
+ last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
}
if (depth - deltad < stoplevels[stopidx])
deltad = depth - stoplevels[stopidx];
@@ -936,31 +1052,14 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
--stopidx;
/* Save the current state and try to ascend to the next stopdepth */
- int trial_depth = depth;
- cache_deco_state(tissue_tolerance, &trial_cache);
while (1) {
/* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */
- clear_to_ascend = true;
- while (trial_depth > stoplevels[stopidx]) {
- int deltad = ascend_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP;
- if (deltad > trial_depth) /* don't test against depth above surface */
- deltad = trial_depth;
- tissue_tolerance = add_segment(depth_to_mbar(trial_depth, &displayed_dive) / 1000.0,
- &displayed_dive.cylinder[current_cylinder].gasmix,
- TIMESTEP, po2, &displayed_dive, prefs.decosac);
- if (deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, &displayed_dive, 1) > trial_depth - deltad) {
- /* We should have stopped */
- clear_to_ascend = false;
- break;
- }
- trial_depth -= deltad;
- }
- restore_deco_state(trial_cache);
-
- if (clear_to_ascend)
+ if (trial_ascent(depth, stoplevels[stopidx], avg_depth, bottom_time, tissue_tolerance,
+ &displayed_dive.cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0))
break; /* We did not hit the ceiling */
/* Add a minute of deco time and then try again */
+ decodive = true;
if (!stopping) {
/* The last segment was an ascend segment.
* Add a waypoint for start of this deco stop */
@@ -971,7 +1070,6 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0,
&displayed_dive.cylinder[current_cylinder].gasmix,
DECOTIMESTEP, po2, &displayed_dive, prefs.decosac);
- cache_deco_state(tissue_tolerance, &trial_cache);
clock += DECOTIMESTEP;
/* Finish infinite deco */
if(clock >= 48 * 3600 && depth >= 6000) {
@@ -1003,7 +1101,6 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
}
}
}
- trial_depth = depth;
}
if (stopping) {
/* Next we will ascend again. Add a waypoint if we have spend deco time */
@@ -1023,7 +1120,7 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s
free(stoplevels);
free(gaschanges);
- return error;
+ return decodive;
}
/*
@@ -1082,6 +1179,10 @@ int validate_gas(const char *text, struct gasmix *gas)
o2 = O2_IN_AIR;
he = 0;
text += strlen(translate("gettextFromC", "air"));
+ } else if (!strcasecmp(text, translate("gettextFromC", "oxygen"))) {
+ o2 = 1000;
+ he = 0;
+ text += strlen(translate("gettextFromC", "oxygen"));
} else if (!strncasecmp(text, translate("gettextFromC", "ean"), 3)) {
o2 = get_permille(text + 3, &text);
he = 0;