aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/schedule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/schedule.c')
-rw-r--r--src/schedule.c144
1 files changed, 59 insertions, 85 deletions
diff --git a/src/schedule.c b/src/schedule.c
index 5528ce3..1827ff3 100644
--- a/src/schedule.c
+++ b/src/schedule.c
@@ -10,6 +10,12 @@
int SWITCH_INTERMEDIATE = SWITCH_INTERMEDIATE_DEFAULT;
+static void emit_waypoint(const decostate_t *ds, segtype_t type, const waypoint_callback_t *wp_cb)
+{
+ if (wp_cb && wp_cb->fn)
+ wp_cb->fn(ds, type, wp_cb->arg);
+}
+
const gas_t *best_gas(double depth, const gas_t *gasses, int nof_gasses)
{
const gas_t *best = NULL;
@@ -27,38 +33,33 @@ const gas_t *best_gas(double depth, const gas_t *gasses, int nof_gasses)
return best;
}
-int direct_ascent(const decostate_t *ds, double depth, double time, const gas_t *gas)
+int direct_ascent(const decostate_t *ds, double ascrate)
{
decostate_t ds_ = *ds;
assert(ds_.firststop == -1);
- add_segment_ascdec(&ds_, depth, abs_depth(0), time, gas);
+ add_segment_ascdec(&ds_, ds_.depth, abs_depth(0), gauge_depth(ds_.depth) / ascrate, ds_.gas);
return gauge_depth(ceiling(&ds_, ds_.gfhi)) <= 0;
}
void simulate_dive(decostate_t *ds, const waypoint_t *waypoints, int nof_waypoints, const waypoint_callback_t *wp_cb)
{
- double depth = abs_depth(0);
-
for (int i = 0; i < nof_waypoints; i++) {
double d = waypoints[i].depth;
double t = waypoints[i].time;
const gas_t *g = waypoints[i].gas;
- if (d != depth)
- add_segment_ascdec(ds, depth, d, t, g);
+ if (d != ds->depth)
+ add_segment_ascdec(ds, ds->depth, d, t, g);
else
add_segment_const(ds, d, t, g);
- depth = d;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = d, .time = t, .gas = g}, SEG_DIVE, wp_cb->arg);
+ emit_waypoint(ds, SEG_DIVE, wp_cb);
}
}
-double calc_ndl(decostate_t *ds, double depth, double ascrate, const gas_t *gas)
+double calc_ndl(decostate_t *ds, double ascrate)
{
double ndl = 0;
@@ -66,33 +67,33 @@ double calc_ndl(decostate_t *ds, double depth, double ascrate, const gas_t *gas)
decostate_t ds_ = *ds;
while (ndl < 360) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_ROUGH, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_ROUGH, ds_.gas);
- if (!direct_ascent(&ds_, depth, gauge_depth(depth) / ascrate, gas))
+ if (!direct_ascent(&ds_, ascrate))
break;
- ndl += tmp;
+ ndl = ds_.runtime - ds->runtime;
}
/* fine steps */
ds_ = *ds;
if (ndl)
- add_segment_const(&ds_, depth, ndl, gas);
+ add_segment_const(&ds_, ds_.depth, ndl, ds_.gas);
while (ndl < 360) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_FINE, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_FINE, ds_.gas);
- if (!direct_ascent(&ds_, depth, gauge_depth(depth) / ascrate, gas))
+ if (!direct_ascent(&ds_, ascrate))
break;
- ndl += tmp;
+ ndl = ds_.runtime - ds->runtime;
}
return ndl;
}
-double deco_stop(decostate_t *ds, double depth, double next_stop, double current_gf, const gas_t *gas)
+static void deco_stop(decostate_t *ds, double next_stop, double current_gf)
{
double stoplen = 0;
@@ -100,86 +101,68 @@ double deco_stop(decostate_t *ds, double depth, double next_stop, double current
decostate_t ds_ = *ds;
for (;;) {
- double tmp = add_segment_const(&ds_, depth, STOPLEN_ROUGH, gas);
+ add_segment_const(&ds_, ds_.depth, STOPLEN_ROUGH, ds_.gas);
if (ceiling(&ds_, current_gf) <= next_stop)
break;
- stoplen += tmp;
+ stoplen = ds_.runtime - ds->runtime;
}
if (stoplen)
- add_segment_const(ds, depth, stoplen, gas);
+ add_segment_const(ds, ds->depth, stoplen, ds->gas);
/* fine steps */
while (ceiling(ds, current_gf) > next_stop)
- stoplen += add_segment_const(ds, depth, STOPLEN_FINE, gas);
-
- return stoplen;
+ add_segment_const(ds, ds->depth, STOPLEN_FINE, ds->gas);
}
-static int surfaced(double depth)
+static int surfaced(decostate_t *ds)
{
- return fabs(depth - SURFACE_PRESSURE) < 1E-2;
+ return ds->depth - SURFACE_PRESSURE < 1E-2;
}
-decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas, const gas_t *deco_gasses,
- int nof_gasses, const waypoint_callback_t *wp_cb)
+decoinfo_t calc_deco(decostate_t *ds, const gas_t *deco_gasses, int nof_gasses, const waypoint_callback_t *wp_cb)
{
- decoinfo_t ret = {.tts = 0, .ndl = 0};
-
- /* setup start parameters */
- double depth = start_depth;
- const gas_t *gas = start_gas;
-
+ const double runtime_start = ds->runtime;
const double asc_per_min = msw_to_bar(9);
+ double next_stop;
+ double current_gf;
+ const gas_t *best;
+
/* check if direct ascent is possible */
- if (direct_ascent(ds, depth, gauge_depth(depth) / asc_per_min, gas)) {
- ret.ndl = calc_ndl(ds, depth, asc_per_min, gas);
- return ret;
- }
+ if (direct_ascent(ds, asc_per_min))
+ return (decoinfo_t){.tts = 0, .ndl = calc_ndl(ds, asc_per_min)};
- double next_stop = abs_depth(ds->ceil_multiple * (ceil(gauge_depth(depth) / ds->ceil_multiple) - 1));
+ /* prepare for the first stop */
+ next_stop = abs_depth(ds->ceil_multiple * (ceil(gauge_depth(ds->depth) / ds->ceil_multiple) - 1));
- if (next_stop == depth)
+ if (next_stop == ds->depth)
next_stop -= ds->ceil_multiple;
- double current_gf = get_gf(ds, next_stop);
-
- /* extra bookkeeping because waypoints and segments do not match 1:1 */
- double last_waypoint_depth = depth;
- double waypoint_time;
+ current_gf = get_gf(ds, next_stop);
+ /* alternate between ascending and stopping until we surface */
for (;;) {
- while (ceiling(ds, current_gf) < next_stop && !surfaced(depth)) {
+ /* ascend */
+ while (ceiling(ds, current_gf) < next_stop && !surfaced(ds)) {
/* switch to better gas if available */
- const gas_t *best = best_gas(depth, deco_gasses, nof_gasses);
+ best = best_gas(ds->depth, deco_gasses, nof_gasses);
- if (SWITCH_INTERMEDIATE && best && best != gas) {
- /* emit waypoint */
- waypoint_time = fabs(last_waypoint_depth - depth) / asc_per_min;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = waypoint_time, .gas = gas}, SEG_TRAVEL,
- wp_cb->arg);
-
- last_waypoint_depth = depth;
+ if (SWITCH_INTERMEDIATE && best && best != ds->gas) {
+ /* emit waypoint because we're about to switch gas */
+ emit_waypoint(ds, SEG_TRAVEL, wp_cb);
/* switch gas */
- gas = best;
-
- ret.tts += add_segment_const(ds, depth, 1, gas);
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = 1, .gas = gas}, SEG_GAS_SWITCH, wp_cb->arg);
+ add_segment_const(ds, ds->depth, 1, best);
+ emit_waypoint(ds, SEG_GAS_SWITCH, wp_cb);
continue;
}
/* ascend to next stop */
- ret.tts += add_segment_ascdec(ds, depth, next_stop, fabs(depth - next_stop) / asc_per_min, gas);
- depth = next_stop;
+ add_segment_ascdec(ds, ds->depth, next_stop, fabs(ds->depth - next_stop) / asc_per_min, ds->gas);
/* make next stop shallower */
next_stop -= ds->ceil_multiple;
@@ -192,7 +175,7 @@ decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas
}
if (ds->firststop == -1) {
- ds->firststop = depth;
+ ds->firststop = ds->depth;
/*
* if the first stop wasn't know yet during the previous call to
@@ -205,31 +188,22 @@ decoinfo_t calc_deco(decostate_t *ds, double start_depth, const gas_t *start_gas
continue;
}
- /* emit waypoint */
- waypoint_time = fabs(last_waypoint_depth - depth) / asc_per_min;
- enum segtype_t segtype = surfaced(depth) ? SEG_SURFACE : SEG_TRAVEL;
-
- if (wp_cb && wp_cb->fn && waypoint_time)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = waypoint_time, .gas = gas}, segtype, wp_cb->arg);
-
- last_waypoint_depth = depth;
-
/* terminate if we surfaced */
- if (surfaced(depth))
- return ret;
+ if (surfaced(ds)) {
+ emit_waypoint(ds, SEG_SURFACE, wp_cb);
+ return (decoinfo_t){.ndl = 0, .tts = ds->runtime - runtime_start};
+ }
+
+ emit_waypoint(ds, SEG_TRAVEL, wp_cb);
/* switch to better gas if available */
- const gas_t *best = best_gas(depth, deco_gasses, nof_gasses);
+ best = best_gas(ds->depth, deco_gasses, nof_gasses);
if (best)
- gas = best;
+ ds->gas = best;
/* stop until ceiling rises above next stop */
- double stoplen = deco_stop(ds, depth, next_stop, current_gf, gas);
-
- ret.tts += stoplen;
-
- if (wp_cb && wp_cb->fn)
- wp_cb->fn(ds, (waypoint_t){.depth = depth, .time = stoplen, .gas = gas}, SEG_DECO_STOP, wp_cb->arg);
+ deco_stop(ds, next_stop, current_gf);
+ emit_waypoint(ds, SEG_DECO_STOP, wp_cb);
}
}