diff options
author | Willem Ferguson <willemferguson@zoology.up.ac.za> | 2018-04-03 19:30:27 +0200 |
---|---|---|
committer | Lubomir I. Ivanov <neolit123@gmail.com> | 2018-05-14 23:47:00 +0300 |
commit | 27a0542220ae3766f0a98058c28e86d6c6d43a62 (patch) | |
tree | cf5a13544588d53667c2a4272a9053406b32d6a6 /core | |
parent | cf377beb2ea13833fa4a867b9c99153ecd9fff22 (diff) | |
download | subsurface-27a0542220ae3766f0a98058c28e86d6c6d43a62.tar.gz |
Implement bailout outside of the dive planner
This is the second step for implementing bailout. The indirect
calls to fill_pressures through add_segment() (in deco.c) are
addressed. Bailout is now fully implemented in the dive log but
not in the dive planner.
1) The parameters to add_segment() are changed to take a
divemode as the second last parameter, and not a *dive.
2) Call to add_segment() in profile.c and in divelist.c are
adapted. In divelist.c some calls to add_segment were left
using dc-> divemode instead of possible bailout. This appears
tp be the most appropriate route.
3) The functions get_divemode_from_time() and get_next_divemodechange()
in dive.c have had some small changes.
4) The calls to get_segment(0 in planner.c were changed to reflect
the new parameter list, but not updated to reflect bailout. This
is the next step.
Signed-off-by: Willem Ferguson <willemferguson@zoology.up.ac.za>
Diffstat (limited to 'core')
-rw-r--r-- | core/deco.c | 4 | ||||
-rw-r--r-- | core/dive.c | 45 | ||||
-rw-r--r-- | core/dive.h | 4 | ||||
-rw-r--r-- | core/divelist.c | 8 | ||||
-rw-r--r-- | core/planner.c | 16 | ||||
-rw-r--r-- | core/profile.c | 21 |
6 files changed, 59 insertions, 39 deletions
diff --git a/core/deco.c b/core/deco.c index 5135860b8..b8780557c 100644 --- a/core/deco.c +++ b/core/deco.c @@ -478,14 +478,14 @@ void calc_crushing_pressure(struct deco_state *ds, double pressure) } /* add period_in_seconds at the given pressure and gas to the deco calculation */ -void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int ccpo2, const struct dive *dive, int sac) +void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int ccpo2, enum dive_comp_type divemode, int sac) { (void) sac; int ci; struct gas_pressures pressures; bool icd = false; fill_pressures(&pressures, pressure - ((in_planner() && (decoMode() == VPMB)) ? WV_PRESSURE_SCHREINER : WV_PRESSURE), - gasmix, (double) ccpo2 / 1000.0, dive->dc.divemode); + gasmix, (double) ccpo2 / 1000.0, divemode); for (ci = 0; ci < 16; ci++) { double pn2_oversat = pressures.n2 - ds->tissue_n2_sat[ci]; diff --git a/core/dive.c b/core/dive.c index 680635e8f..66f05b0b3 100644 --- a/core/dive.c +++ b/core/dive.c @@ -244,7 +244,7 @@ void add_extra_data(struct divecomputer *dc, const char *key, const char *value) struct event *get_next_divemodechange(struct event **evd) { /* Starting at the event pointed to by evd, find the next divemode change event and initialise its * type and divemode. Requires an external pointer (evd) to a divemode change event, usually - * initialised to dc->events. This function is self-tracking and the value of evd needs no + * a copy of dc->events. This function is self-tracking and the value of evd needs no * setting or manipulation outside of this function. */ struct event *ev = *evd; while (ev) { // Step through the events. @@ -277,27 +277,40 @@ struct event *peek_next_divemodechange(struct event *evd) return (NULL); } +/* +enum dive_comp_type get_divemode_at_time(struct divecomputer *dc, int divetime, struct event **ev_dmc) +{ // The dummy version of this function, call parameters compatible with self-tracking version. + return dc->divemode; +} + +enum dive_comp_type get_divemode_at_time(struct divecomputer *dc, int divetime, struct event **ev_dmc) +{ // The non-self-tracking version of this function, call parameters compatible with self-tracking version. + struct event *ev, *ev_ndc = dc->events; + enum dive_comp_type mode = dc->divemode; + ev = get_next_divemodechange(&ev_ndc); + while (ev && (divetime >= ev->time.seconds)) { + mode = ev->divemode; + ev = get_next_divemodechange(&ev_ndc); + } + return mode; +} */ + enum dive_comp_type get_divemode_at_time(struct divecomputer *dc, int dtime, struct event **ev_dmc) { /* For a particular dive computer and its linked list of events, find the divemode dtime seconds * into the dive. Requires an external pointer (ev_dmc) to a divemode change event, usually - * initialised by a call to get_next_divemodechange(dc->events). This function is self-tracking - * and the value of ev_dmc needs no setting or manipulation outside of this function. */ - enum dive_comp_type mode; - struct event *ev = *ev_dmc; // ev_dmc points to event initialised by get_next_divemodechange() - if (!ev) - mode = dc->divemode; // if there is no divemodechange event, default to dc->divemode - else { - mode = ev->divemode; // If there is a starting divemodechange event, use the divemode of that event. - while (ev && (dtime >= ev->time.seconds)) { // If dtime is AFTER this event time, store divemode - mode = ev->divemode; - *ev_dmc = ev; - ev = peek_next_divemodechange(ev->next); // peek at the time of the following divemode change event - } - } + * initialised by a call to get_next_divemodechange(©-of-dc->events). This function is self-tracking + * and the value of ev_dmc needs no manipulation outside of this function. */ + enum dive_comp_type mode = dc->divemode; + struct event *ev_last = *ev_dmc, *ev = *ev_dmc; // ev_dmc points to event initialised by get_next_divemodechange() + while (ev && (dtime >= ev->time.seconds)) { // If dtime is AFTER this event time, store divemode + mode = ev->divemode; + ev_last = ev; + ev = peek_next_divemodechange(ev->next); // peek at the time of the following divemode change event + } + *ev_dmc = ev_last; return (mode); } - /* this returns a pointer to static variable - so use it right away after calling */ struct gasmix *get_gasmix_from_event(struct dive *dive, struct event *ev) { diff --git a/core/dive.h b/core/dive.h index 4e45ca860..dc204b1d6 100644 --- a/core/dive.h +++ b/core/dive.h @@ -83,6 +83,7 @@ struct event { /* This is the annoying libdivecomputer format. */ int flags, value; /* .. and this is our "extended" data for some event types */ + enum dive_comp_type divemode; union { /* * Currently only for gas switch events. @@ -91,7 +92,6 @@ struct event { * case, the get_cylinder_index() function will give the best * match with the cylinders in the dive based on gasmix. */ - enum dive_comp_type divemode; struct { int index; struct gasmix mix; @@ -854,7 +854,7 @@ struct deco_state { bool icd_warning; }; -extern void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int setpoint, const struct dive *dive, int sac); +extern void add_segment(struct deco_state *ds, double pressure, const struct gasmix *gasmix, int period_in_seconds, int setpoint, enum dive_comp_type divemode, int sac); extern void clear_deco(struct deco_state *ds, double surface_pressure); extern void dump_tissues(struct deco_state *ds); extern void set_gf(short gflow, short gfhigh); diff --git a/core/divelist.c b/core/divelist.c index caa659527..c79cb56b5 100644 --- a/core/divelist.c +++ b/core/divelist.c @@ -415,6 +415,7 @@ static void add_dive_to_deco(struct deco_state *ds, struct dive *dive) struct divecomputer *dc = &dive->dc; struct gasmix *gasmix = NULL; struct event *ev = NULL; + struct event *ev_dmc = dc->events, *ev_dmt = get_next_divemodechange(&ev_dmc); int i; if (!dc) @@ -430,7 +431,8 @@ static void add_dive_to_deco(struct deco_state *ds, struct dive *dive) for (j = t0; j < t1; j++) { int depth = interpolate(psample->depth.mm, sample->depth.mm, j - t0, t1 - t0); gasmix = get_gasmix(dive, dc, j, &ev, gasmix); - add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, sample->setpoint.mbar, dive, dive->sac); + add_segment(ds, depth_to_bar(depth, dive), gasmix, 1, sample->setpoint.mbar, + get_divemode_at_time(dc, j, &ev_dmt), dive->sac); } } } @@ -584,7 +586,7 @@ int init_decompression(struct deco_state *ds, struct dive *dive) #endif return surface_time; } - add_segment(ds, surface_pressure, &air, surface_time, 0, dive, prefs.decosac); + add_segment(ds, surface_pressure, &air, surface_time, 0, dive->dc.divemode, prefs.decosac); #if DECO_CALC_DEBUG & 2 printf("Tissues after surface intervall of %d:%02u:\n", FRACTION(surface_time, 60)); dump_tissues(ds); @@ -622,7 +624,7 @@ int init_decompression(struct deco_state *ds, struct dive *dive) #endif return surface_time; } - add_segment(ds, surface_pressure, &air, surface_time, 0, dive, prefs.decosac); + add_segment(ds, surface_pressure, &air, surface_time, 0, dive->dc.divemode, prefs.decosac); #if DECO_CALC_DEBUG & 2 printf("Tissues after surface intervall of %d:%02u:\n", FRACTION(surface_time, 60)); dump_tissues(ds); diff --git a/core/planner.c b/core/planner.c index 33a61094d..62776d690 100644 --- a/core/planner.c +++ b/core/planner.c @@ -121,7 +121,7 @@ void interpolate_transition(struct deco_state *ds, struct dive *dive, duration_t for (j = t0.seconds; j < t1.seconds; j++) { int depth = interpolate(d0.mm, d1.mm, j - t0.seconds, t1.seconds - t0.seconds); - add_segment(ds, 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->dc.divemode, prefs.bottomsac); } if (d1.mm > d0.mm) calc_crushing_pressure(ds, depth_to_bar(d1.mm, &displayed_dive)); @@ -573,7 +573,7 @@ bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth, int sto if (wait_time) add_segment(ds, depth_to_bar(trial_depth, dive), gasmix, - wait_time, po2, dive, prefs.decosac); + wait_time, po2, dive->dc.divemode, prefs.decosac); if (decoMode() == VPMB && (deco_allowed_depth(tissue_tolerance_calc(ds, dive,depth_to_bar(stoplevel, dive)), surface_pressure, dive, 1) > stoplevel)) { @@ -588,7 +588,7 @@ bool trial_ascent(struct deco_state *ds, int wait_time, int trial_depth, int sto deltad = trial_depth; add_segment(ds, depth_to_bar(trial_depth, dive), gasmix, - TIMESTEP, po2, dive, prefs.decosac); + TIMESTEP, po2, dive->dc.divemode, prefs.decosac); 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 */ @@ -781,7 +781,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i do { add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[current_cylinder].gasmix, - timestep, po2, dive, prefs.bottomsac); + timestep, po2, dive->dc.divemode, prefs.bottomsac); update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false); clock += timestep; } while (trial_ascent(ds, 0, depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, @@ -901,7 +901,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[current_cylinder].gasmix, - TIMESTEP, po2, dive, prefs.decosac); + TIMESTEP, po2, dive->dc.divemode, prefs.decosac); last_segment_min_switch = false; clock += TIMESTEP; depth -= deltad; @@ -940,7 +940,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) { add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[current_cylinder].gasmix, - prefs.min_switch_duration, po2, dive, prefs.decosac); + prefs.min_switch_duration, po2, dive->dc.divemode, prefs.decosac); clock += prefs.min_switch_duration; last_segment_min_switch = true; } @@ -994,7 +994,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i if (!last_segment_min_switch && get_o2(&dive->cylinder[current_cylinder].gasmix) != 1000) { add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[current_cylinder].gasmix, - prefs.min_switch_duration, po2, dive, prefs.decosac); + prefs.min_switch_duration, po2, dive->dc.divemode, prefs.decosac); clock += prefs.min_switch_duration; last_segment_min_switch = true; } @@ -1049,7 +1049,7 @@ bool plan(struct deco_state *ds, struct diveplan *diveplan, struct dive *dive, i } } add_segment(ds, depth_to_bar(depth, dive), &dive->cylinder[stop_cylinder].gasmix, - laststoptime, po2, dive, prefs.decosac); + laststoptime, po2, dive->dc.divemode, prefs.decosac); last_segment_min_switch = false; decostoptable[decostopcounter].depth = depth; decostoptable[decostopcounter].time = laststoptime; diff --git a/core/profile.c b/core/profile.c index bfe8c223c..b8dd17728 100644 --- a/core/profile.c +++ b/core/profile.c @@ -907,7 +907,7 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc #ifndef SUBSURFACE_MOBILE /* calculate DECO STOP / TTS / NDL */ -static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct plot_data *entry, struct gasmix *gasmix, double surface_pressure) +static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct plot_data *entry, struct gasmix *gasmix, double surface_pressure,enum dive_comp_type divemode) { /* FIXME: This should be configurable */ /* ascent speed up to first deco stop */ @@ -942,7 +942,7 @@ static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct p ) { entry->ndl_calc += time_stepsize; add_segment(ds, depth_to_bar(entry->depth, dive), - gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.bottomsac); + gasmix, time_stepsize, entry->o2pressure.mbar, divemode, prefs.bottomsac); } /* we don't need to calculate anything else */ return; @@ -954,7 +954,7 @@ static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct p /* Add segments for movement to stopdepth */ for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_step, entry->tts_calc += ascent_s_per_step) { add_segment(ds, depth_to_bar(ascent_depth, dive), - gasmix, ascent_s_per_step, entry->o2pressure.mbar, dive, prefs.decosac); + gasmix, ascent_s_per_step, entry->o2pressure.mbar, divemode, prefs.decosac); next_stop = ROUND_UP(deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth, dive)), surface_pressure, dive, 1), deco_stepsize); } @@ -975,13 +975,13 @@ static void calculate_ndl_tts(struct deco_state *ds, struct dive *dive, struct p if (entry->tts_calc > MAX_PROFILE_DECO) break; add_segment(ds, depth_to_bar(ascent_depth, dive), - gasmix, time_stepsize, entry->o2pressure.mbar, dive, prefs.decosac); + gasmix, time_stepsize, entry->o2pressure.mbar, divemode, prefs.decosac); if (deco_allowed_depth(tissue_tolerance_calc(ds, dive, depth_to_bar(ascent_depth,dive)), surface_pressure, dive, 1) <= next_stop) { /* move to the next stop and add the travel between stops */ for (; ascent_depth > next_stop; ascent_depth -= ascent_mm_per_deco_step, entry->tts_calc += ascent_s_per_deco_step) add_segment(ds, depth_to_bar(ascent_depth, dive), - gasmix, ascent_s_per_deco_step, entry->o2pressure.mbar, dive, prefs.decosac); + gasmix, ascent_s_per_deco_step, entry->o2pressure.mbar, divemode, prefs.decosac); ascent_depth = next_stop; next_stop -= deco_stepsize; } @@ -996,6 +996,8 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne double surface_pressure = (dc->surface_pressure.mbar ? dc->surface_pressure.mbar : get_surface_pressure_in_mbar(dive, true)) / 1000.0; bool first_iteration = true; int prev_deco_time = 10000000, time_deep_ceiling = 0; + enum dive_comp_type current_divemode; + if (!in_planner()) { ds->deco_time = 0; } else { @@ -1010,18 +1012,20 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne } /* For VPM-B outside the planner, iterate until deco time converges (usually one or two iterations after the initial) * Set maximum number of iterations to 10 just in case */ + while ((abs(prev_deco_time - ds->deco_time) >= 30) && (count_iteration < 10)) { int last_ndl_tts_calc_time = 0, first_ceiling = 0, current_ceiling, last_ceiling = 0, final_tts = 0 , time_clear_ceiling = 0; if (decoMode() == VPMB) ds->first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive); struct gasmix *gasmix = NULL; - struct event *ev = NULL; + struct event *ev = NULL, *ev_dmc = dc->events, *ev_dmt = get_next_divemodechange(&ev_dmc); for (i = 1; i < pi->nr; i++) { struct plot_data *entry = pi->entry + i; int j, t0 = (entry - 1)->sec, t1 = entry->sec; int time_stepsize = 20; + current_divemode = get_divemode_at_time(dc, entry->sec, &ev_dmt); gasmix = get_gasmix(dive, dc, t1, &ev, gasmix); entry->ambpressure = depth_to_bar(entry->depth, dive); @@ -1037,7 +1041,7 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) { int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0); add_segment(ds, depth_to_bar(depth, dive), - gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac); + gasmix, time_stepsize, entry->o2pressure.mbar, current_divemode, entry->sac); entry->icd_warning = ds->icd_warning; if ((t1 - j < time_stepsize) && (j < t1)) time_stepsize = t1 - j; @@ -1112,7 +1116,7 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne /* We are going to mess up deco state, so store it for later restore */ struct deco_state *cache_data = NULL; cache_deco_state(ds, &cache_data); - calculate_ndl_tts(ds, dive, entry, gasmix, surface_pressure); + calculate_ndl_tts(ds, dive, entry, gasmix, surface_pressure, current_divemode); if (decoMode() == VPMB && !in_planner() && i == pi->nr - 1) final_tts = entry->tts_calc; /* Restore "real" deco state for next real time step */ @@ -1146,6 +1150,7 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne prev_deco_time = ds->deco_time = 0; } } + free(cache_data_initial); #if DECO_CALC_DEBUG & 1 dump_tissues(ds); |