summaryrefslogtreecommitdiffstats
path: root/core/planner.c
diff options
context:
space:
mode:
authorGravatar Robert C. Helling <helling@atdotde.de>2017-11-22 20:42:33 +0100
committerGravatar Robert C. Helling <helling@atdotde.de>2017-11-25 20:13:01 +0100
commit8e21a65653514d9340ef45c9b9c53dfe5d280350 (patch)
tree2ada40567e25bc45035698748f368127b1cca199 /core/planner.c
parenta9ceecc2e3646432d6688d04b592c48f9c63ae65 (diff)
downloadsubsurface-8e21a65653514d9340ef45c9b9c53dfe5d280350.tar.gz
Localize global planner state
For UI responsiveness, we need to be able to run the planner in the background. This needs the planner state to be localized (and we need to pass a pointer around). In order to not let too many lines overrun (and to save typing in the future) I have renamed instances of struct deco_state to ds. Yes this should have gone to a separate commit but I accidentally commit --amend'ed it. Computing of planner variations is temporarily disabled. Unlock the planner when returning early So we don't deadlock in add dive and recreational mode (which use the planner without actually planning). Signed-off-by: Robert C. Helling <helling@atdotde.de>
Diffstat (limited to 'core/planner.c')
-rw-r--r--core/planner.c118
1 files changed, 59 insertions, 59 deletions
diff --git a/core/planner.c b/core/planner.c
index a137753b2..6aa5cc2f4 100644
--- a/core/planner.c
+++ b/core/planner.c
@@ -114,20 +114,20 @@ int get_gasidx(struct dive *dive, struct gasmix *mix)
return find_best_gasmix_match(mix, dive->cylinder, 0);
}
-void interpolate_transition(struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, const struct gasmix *gasmix, o2pressure_t po2)
+void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t t0, duration_t t1, depth_t d0, depth_t d1, const struct gasmix *gasmix, o2pressure_t po2)
{
uint32_t j;
for (j = t0.seconds; j < t1.seconds; j++) {
int depth = interpolate(d0.mm, d1.mm, j - t0.seconds, t1.seconds - t0.seconds);
- add_segment(depth_to_bar(depth, dive), gasmix, 1, po2.mbar, dive, prefs.bottomsac);
+ add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, po2.mbar, dive, prefs.bottomsac);
}
if (d1.mm > d0.mm)
- calc_crushing_pressure(depth_to_bar(d1.mm, &displayed_dive));
+ calc_crushing_pressure(ds, depth_to_bar(d1.mm, &displayed_dive));
}
/* returns the tissue tolerance at the end of this (partial) dive */
-int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
+int tissue_at_end(struct deco_state *ds, struct dive *dive, struct deco_state **cached_datap)
{
struct divecomputer *dc;
struct sample *sample, *psample;
@@ -140,10 +140,10 @@ int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
if (!dive)
return 0;
if (*cached_datap) {
- restore_deco_state(*cached_datap, true);
+ restore_deco_state(*cached_datap, ds, true);
} else {
- surface_interval = init_decompression(dive);
- cache_deco_state(cached_datap);
+ surface_interval = init_decompression(ds, dive);
+ cache_deco_state(ds, cached_datap);
}
dc = &dive->dc;
if (!dc->samples)
@@ -174,19 +174,19 @@ int tissue_at_end(struct dive *dive, struct deco_state **cached_datap)
*/
if ((decoMode() == VPMB) && (lastdepth.mm > sample->depth.mm)) {
pressure_t ceiling_pressure;
- nuclear_regeneration(t0.seconds);
- vpmb_start_gradient();
- ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(dive,
+ nuclear_regeneration(ds, t0.seconds);
+ vpmb_start_gradient(ds);
+ ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(ds, dive,
depth_to_bar(lastdepth.mm, dive)),
dive->surface_pressure.mbar / 1000.0,
dive,
1),
dive);
- if (ceiling_pressure.mbar > deco_state->max_bottom_ceiling_pressure.mbar)
- deco_state->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
+ if (ceiling_pressure.mbar > ds->max_bottom_ceiling_pressure.mbar)
+ ds->max_bottom_ceiling_pressure.mbar = ceiling_pressure.mbar;
}
- interpolate_transition(dive, t0, t1, lastdepth, sample->depth, &gas, setpoint);
+ interpolate_transition(ds, dive, t0, t1, lastdepth, sample->depth, &gas, setpoint);
psample = sample;
t0 = t1;
}
@@ -556,7 +556,7 @@ void track_ascent_gas(int depth, cylinder_t *cylinder, int avg_depth, int bottom
}
// Determine whether ascending to the next stop will break the ceiling. Return true if the ascent is ok, false if it isn't.
-bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure, struct dive *dive)
+bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth, int stoplevel, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure, struct dive *dive)
{
bool clear_to_ascend = true;
@@ -565,15 +565,15 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
// For consistency with other VPM-B implementations, we should not start the ascent while the ceiling is
// deeper than the next stop (thus the offgasing during the ascent is ignored).
// However, we still need to make sure we don't break the ceiling due to on-gassing during ascent.
- cache_deco_state(&trial_cache);
+ cache_deco_state(ds, &trial_cache);
if (wait_time)
- add_segment(depth_to_bar(trial_depth, dive),
+ add_segment(ds, depth_to_bar(trial_depth, dive),
gasmix,
wait_time, po2, dive, prefs.decosac);
- if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(dive,
- depth_to_bar(stoplevel, dive)),
- surface_pressure, dive, 1) > stoplevel)) {
- restore_deco_state(trial_cache, false);
+ if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(ds, dive,depth_to_bar(stoplevel, dive)),
+ surface_pressure, dive, 1)
+ > stoplevel)) {
+ restore_deco_state(trial_cache, ds, false);
free(trial_cache);
return false;
}
@@ -582,10 +582,10 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
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;
- add_segment(depth_to_bar(trial_depth, dive),
+ add_segment(ds, depth_to_bar(trial_depth, dive),
gasmix,
TIMESTEP, po2, dive, prefs.decosac);
- if (deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(trial_depth, dive)),
+ if (deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(trial_depth, dive)),
surface_pressure, dive, 1) > trial_depth - deltad) {
/* We should have stopped */
clear_to_ascend = false;
@@ -593,7 +593,7 @@ bool trial_ascent(int wait_time, int trial_depth, int stoplevel, int avg_depth,
}
trial_depth -= deltad;
}
- restore_deco_state(trial_cache, false);
+ restore_deco_state(trial_cache, ds, false);
free(trial_cache);
return clear_to_ascend;
}
@@ -621,18 +621,18 @@ bool enough_gas(int current_cylinder)
* So we always test at the upper bundary, not in the middle!
*/
-int wait_until(struct dive *dive, int clock, int min, int leap, int stepsize, int depth, int target_depth, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure)
+int wait_until(struct deco_state *ds, struct dive *dive, int clock, int min, int leap, int stepsize, int depth, int target_depth, int avg_depth, int bottom_time, struct gasmix *gasmix, int po2, double surface_pressure)
{
// Round min + leap up to the next multiple of stepsize
int upper = min + leap + stepsize - 1 - (min + leap - 1) % stepsize;
// Is the upper boundary too small?
- if (!trial_ascent(upper - clock, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure, dive))
- return wait_until(dive, clock, upper, leap, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
+ if (!trial_ascent(ds, upper - clock, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure, dive))
+ return wait_until(ds, dive, clock, upper, leap, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
if (upper - min <= stepsize)
return upper;
- return wait_until(dive, clock, min, leap / 2, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
+ return wait_until(ds, dive, clock, min, leap / 2, stepsize, depth, target_depth, avg_depth, bottom_time, gasmix, po2, surface_pressure);
}
// Work out the stops. Return value is if there were any mandatory stops.
@@ -646,8 +646,9 @@ void printdecotable(struct decostop *table)
}
}
-bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer)
+bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, int timestep, struct decostop *decostoptable, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer)
{
+
int bottom_depth;
int bottom_gi;
int bottom_stopidx;
@@ -690,8 +691,8 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (!diveplan->surface_pressure)
diveplan->surface_pressure = SURFACE_PRESSURE;
dive->surface_pressure.mbar = diveplan->surface_pressure;
- clear_deco(dive->surface_pressure.mbar / 1000.0);
- deco_state->max_bottom_ceiling_pressure.mbar = deco_state->first_ceiling_pressure.mbar = 0;
+ clear_deco(ds, dive->surface_pressure.mbar / 1000.0);
+ ds->max_bottom_ceiling_pressure.mbar = ds->first_ceiling_pressure.mbar = 0;
create_dive_from_plan(diveplan, dive, is_planner);
// Do we want deco stop array in metres or feet?
@@ -730,6 +731,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
transitiontime = depth / 75; /* this still needs to be made configurable */
plan_add_segment(diveplan, transitiontime, 0, current_cylinder, po2, false);
create_dive_from_plan(diveplan, dive, is_planner);
+ unlock_planner();
return false;
}
@@ -761,21 +763,21 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
gi = gaschangenr - 1;
/* Set tissue tolerance and initial vpmb gradient at start of ascent phase */
- diveplan->surface_interval = tissue_at_end(dive, cached_datap);
- nuclear_regeneration(clock);
- vpmb_start_gradient();
+ diveplan->surface_interval = tissue_at_end(ds, dive, cached_datap);
+ nuclear_regeneration(ds, clock);
+ vpmb_start_gradient(ds);
if (decoMode() == RECREATIONAL) {
bool safety_stop = prefs.safetystop && max_depth >= 10000;
track_ascent_gas(depth, &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?
do {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
timestep, po2, dive, prefs.bottomsac);
update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false);
clock += timestep;
- } while (trial_ascent(0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
+ } while (trial_ascent(ds, 0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix,
po2, diveplan->surface_pressure / 1000.0, dive) &&
enough_gas(current_cylinder));
@@ -816,6 +818,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
free(stoplevels);
free(gaschanges);
+ unlock_planner();
return false;
}
@@ -830,10 +833,10 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
}
// VPM-B or Buehlmann Deco
- tissue_at_end(dive, cached_datap);
+ tissue_at_end(ds, dive, cached_datap);
previous_deco_time = 100000000;
- deco_state->deco_time = 10000000;
- cache_deco_state(&bottom_cache); // Lets us make several iterations
+ ds->deco_time = 10000000;
+ cache_deco_state(ds, &bottom_cache); // Lets us make several iterations
bottom_depth = depth;
bottom_gi = gi;
bottom_gas = gas;
@@ -842,12 +845,12 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
//CVA
do {
decostopcounter = 0;
- is_final_plan = (decoMode() == BUEHLMANN) || (previous_deco_time - deco_state->deco_time < 10); // CVA time converges
- if (deco_state->deco_time != 10000000)
- vpmb_next_gradient(deco_state->deco_time, diveplan->surface_pressure / 1000.0);
+ is_final_plan = (decoMode() == BUEHLMANN) || (previous_deco_time - ds->deco_time < 10); // CVA time converges
+ if (ds->deco_time != 10000000)
+ vpmb_next_gradient(ds, ds->deco_time, diveplan->surface_pressure / 1000.0);
- previous_deco_time = deco_state->deco_time;
- restore_deco_state(bottom_cache, true);
+ previous_deco_time = ds->deco_time;
+ restore_deco_state(bottom_cache, ds, true);
depth = bottom_depth;
gi = bottom_gi;
@@ -857,14 +860,11 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
decodive = false;
first_stop_depth = 0;
stopidx = bottom_stopidx;
- deco_state->first_ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(dive,
- depth_to_bar(depth, dive)),
- diveplan->surface_pressure / 1000.0,
- dive,
- 1),
- dive);
- if (deco_state->max_bottom_ceiling_pressure.mbar > deco_state->first_ceiling_pressure.mbar)
- deco_state->first_ceiling_pressure.mbar = deco_state->max_bottom_ceiling_pressure.mbar;
+ ds->first_ceiling_pressure.mbar = depth_to_mbar(
+ deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(depth, dive)), diveplan->surface_pressure / 1000.0, dive, 1),
+ dive);
+ if (ds->max_bottom_ceiling_pressure.mbar > ds->first_ceiling_pressure.mbar)
+ ds->first_ceiling_pressure.mbar = ds->max_bottom_ceiling_pressure.mbar;
last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time);
/* Always prefer the best_first_ascend_cylinder if it has the right gasmix.
@@ -893,7 +893,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (depth - deltad < stoplevels[stopidx])
deltad = depth - stoplevels[stopidx];
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
TIMESTEP, po2, dive, prefs.decosac);
last_segment_min_switch = false;
@@ -922,7 +922,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
if (current_cylinder != gaschanges[gi].gasidx) {
if (!prefs.switch_at_req_stop ||
- !trial_ascent(0, depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
+ !trial_ascent(ds, 0, depth, stoplevels[stopidx - 1], avg_depth, bottom_time,
&dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive) || get_o2(&dive->cylinder[current_cylinder].gasmix) < 160) {
current_cylinder = gaschanges[gi].gasidx;
gas = dive->cylinder[current_cylinder].gasmix;
@@ -932,7 +932,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
prefs.min_switch_duration, po2, dive, prefs.decosac);
clock += prefs.min_switch_duration;
@@ -952,7 +952,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
/* Save the current state and try to ascend to the next stopdepth */
while (1) {
/* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */
- if (trial_ascent(0, depth, stoplevels[stopidx], avg_depth, bottom_time,
+ if (trial_ascent(ds, 0, depth, stoplevels[stopidx], avg_depth, bottom_time,
&dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0, dive)) {
decostoptable[decostopcounter].depth = depth;
decostoptable[decostopcounter].time = 0;
@@ -986,7 +986,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
#endif
/* Stop for the minimum duration to switch gas unless we switch to o2 */
if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) {
- add_segment(depth_to_bar(depth, dive),
+ add_segment(ds, depth_to_bar(depth, dive),
&dive->cylinder[current_cylinder].gasmix,
prefs.min_switch_duration, po2, dive, prefs.decosac);
clock += prefs.min_switch_duration;
@@ -995,7 +995,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
pendinggaschange = false;
}
- int new_clock = wait_until(dive, clock, clock, laststoptime * 2 + 1, timestep, depth, stoplevels[stopidx], avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0);
+ int new_clock = wait_until(ds, dive, clock, clock, laststoptime * 2 + 1, timestep, depth, stoplevels[stopidx], avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0);
laststoptime = new_clock - clock;
/* Finish infinite deco */
if (clock >= 48 * 3600 && depth >= 6000) {
@@ -1043,7 +1043,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
}
}
}
- add_segment(depth_to_bar(depth, dive), &dive->cylinder[stop_cylinder].gasmix,
+ add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[stop_cylinder].gasmix,
laststoptime, po2, dive, prefs.decosac);
last_segment_min_switch = false;
decostoptable[decostopcounter].depth = depth;
@@ -1066,7 +1066,7 @@ bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct dec
* otherwise odd things can happen, such as CVA causing the final ascent to start *later*
* if the ascent rate is slower, which is completely nonsensical.
* Assume final ascent takes 20s, which is the time taken to ascend at 9m/min from 3m */
- deco_state->deco_time = clock - bottom_time - stoplevels[stopidx + 1] / last_ascend_rate + 20;
+ ds->deco_time = clock - bottom_time - stoplevels[stopidx + 1] / last_ascend_rate + 20;
} while (!is_final_plan);
decostoptable[decostopcounter].depth = 0;