summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Willem Ferguson <willemferguson@zoology.up.ac.za>2018-04-02 17:16:07 +0200
committerGravatar Lubomir I. Ivanov <neolit123@gmail.com>2018-05-14 23:47:00 +0300
commitcf377beb2ea13833fa4a867b9c99153ecd9fff22 (patch)
tree4412c032ab354d5593ed064d362d1ca2d8ec9a46
parent9b4728c7a96edf48f7150bec943fb8484d9332cd (diff)
downloadsubsurface-cf377beb2ea13833fa4a867b9c99153ecd9fff22.tar.gz
Incorporate bailout events in CCR & PSCR gas calculations.
This is a first step to interpret bailout events. 1) The event structures have a new attribute: divemode. Currently interpreted dive modes are OC, CCR, PSCR. 2) When doing fill_pressures(), the calculation is aware of divemode. When divemode is OC (==bailout), then the appropriate calculations of gas pressures are done. 3) Two new functions get_next_divemodechange() and get_divemode_at_time() are created to find divemode changes in the events linked list and to determine the dive mode at any point during the dive. 4) fill_pressures gets a small amendment to facilitate the correct calculations, depending on divemode. The cases where fill_pressures() is used *outside the planner* are changed. The result is that, for dives with bailout, the correct gas pressures are shown on the dive profile. The deco for bailout dives is not yet correct. This is the next step. Signed-off-by: Willem Ferguson <willemferguson@zoology.up.ac.za>
-rw-r--r--core/dive.c60
-rw-r--r--core/dive.h5
-rw-r--r--core/plannernotes.c16
-rw-r--r--core/profile.c16
m---------libdivecomputer0
5 files changed, 89 insertions, 8 deletions
diff --git a/core/dive.c b/core/dive.c
index 1ce8421fe..680635e8f 100644
--- a/core/dive.c
+++ b/core/dive.c
@@ -241,6 +241,63 @@ 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
+ * setting or manipulation outside of this function. */
+ struct event *ev = *evd;
+ while (ev) { // Step through the events.
+ for (int i=0; i<3; i++) { // For each event name search for one of the above strings
+ if (!strcmp(ev->name,divemode_text[i])) { // if the event name is one of the divemode names
+ ev->type = DIVEMODECHANGE_EVENTTYPE + i;
+ ev->divemode = i; // set the event type to the dive mode
+ *evd = ev->next;
+ return (ev);
+ }
+ }
+ ev = ev->next;
+ }
+ *evd = NULL;
+ return (NULL);
+}
+
+struct event *peek_next_divemodechange(struct event *evd)
+{ // Starting at event evd, return the subsequent divemode change event, remembering its divemode.
+ struct event *ev = evd;
+ while (ev) { // Step through the events.
+ for (int i=0; i<3; i++) { // For each event name search for one of the above strings
+ if (!strcmp(ev->name,divemode_text[i])) { // if the event name is one of the divemode names
+ ev->divemode = i;
+ return (ev); // ... then return the event.
+ }
+ }
+ ev = ev->next;
+ }
+ return (NULL);
+}
+
+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
+ }
+ }
+ 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)
{
@@ -2050,11 +2107,12 @@ int gasmix_distance(const struct gasmix *a, const struct gasmix *b)
* amb_pressure = ambient pressure applicable to the record in calling function
* *pressures = structure for communicating o2 sensor values from and gas pressures to the calling function.
* *mix = structure containing cylinder gas mixture information.
+ * divemode = the dive mode pertaining to this point in the dive profile.
* This function called by: calculate_gas_information_new() in profile.c; add_segment() in deco.c.
*/
extern void fill_pressures(struct gas_pressures *pressures, const double amb_pressure, const struct gasmix *mix, double po2, enum dive_comp_type divemode)
{
- if (po2) { // This is probably a CCR dive where pressures->o2 is defined
+ if ((divemode != OC) && po2) { // This is a rebreather dive where pressures->o2 is defined
if (po2 >= amb_pressure) {
pressures->o2 = amb_pressure;
pressures->n2 = pressures->he = 0.0;
diff --git a/core/dive.h b/core/dive.h
index 9d1805b86..4e45ca860 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -14,7 +14,6 @@
#include <string.h>
#include <sys/stat.h>
#include "divesite.h"
-
#include <libxml/tree.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
@@ -92,6 +91,7 @@ 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;
@@ -364,6 +364,9 @@ struct dive_components {
unsigned int weights : 1;
};
+extern struct event *get_next_divemodechange(struct event **evd);
+extern enum dive_comp_type get_divemode_at_time(struct divecomputer *dc, int dtime, struct event **ev_dmc);
+
/* picture list and methods related to dive picture handling */
struct picture {
char *filename;
diff --git a/core/plannernotes.c b/core/plannernotes.c
index 1b28252d3..269b391a8 100644
--- a/core/plannernotes.c
+++ b/core/plannernotes.c
@@ -537,12 +537,26 @@ void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool show_d
/* Print warnings for pO2 */
dp = diveplan->dp;
bool o2warning_exist = false;
+ enum dive_comp_type current_divemode;
+ double amb;
+ struct event *nextev, *evd = dive->dc.events;
+
+ current_divemode = dive->dc.divemode;
+ nextev = get_next_divemodechange(&evd);
+
if (dive->dc.divemode != CCR) {
while (dp) {
if (dp->time != 0) {
struct gas_pressures pressures;
struct gasmix *gasmix = &dive->cylinder[dp->cylinderid].gasmix;
- fill_pressures(&pressures, depth_to_atm(dp->depth.mm, dive), gasmix, 0.0, dive->dc.divemode);
+
+ if (nextev && (dp->time >= nextev->time.seconds)) { // If there are divemode changes and divedatapoint time
+ current_divemode = nextev->divemode; // has reached that of the current divemode event, then set the
+ nextev = get_next_divemodechange(&evd); // current divemode and find the next divemode event
+ }
+
+ amb = depth_to_atm(dp->depth.mm, dive);
+ fill_pressures(&pressures, amb, gasmix, (current_divemode == OC) ? 0.0 : amb * gasmix->o2.permille / 1000.0, current_divemode);
if (pressures.o2 > (dp->entered ? prefs.bottompo2 : prefs.decopo2) / 1000.0) {
const char *depth_unit;
diff --git a/core/profile.c b/core/profile.c
index 1bdb8e956..bfe8c223c 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -1200,19 +1200,25 @@ static int calculate_ccr_po2(struct plot_data *entry, struct divecomputer *dc)
static void calculate_gas_information_new(struct dive *dive, struct divecomputer *dc, struct plot_info *pi)
{
int i;
+ enum dive_comp_type current_divemode;
double amb_pressure;
struct gasmix *gasmix = NULL;
- struct event *ev = NULL;
+ struct event *nextev, *evg = NULL, *evd = dc->events;
+
+ current_divemode = dc->divemode;
+ nextev = get_next_divemodechange(&evd);
for (i = 1; i < pi->nr; i++) {
int fn2, fhe;
struct plot_data *entry = pi->entry + i;
- gasmix = get_gasmix(dive, dc, entry->sec, &ev, gasmix);
-
+ gasmix = get_gasmix(dive, dc, entry->sec, &evg, gasmix);
+ if (nextev && (entry->sec > nextev->time.seconds)) { // If there are divemode changes and sample time
+ current_divemode = nextev->divemode; // has reached that of the current divemode event, then set the
+ nextev = get_next_divemodechange(&evd); // current divemode and find the next divemode event
+ }
amb_pressure = depth_to_bar(entry->depth, dive);
-
- fill_pressures(&entry->pressures, amb_pressure, gasmix, entry->o2pressure.mbar / 1000.0, dive->dc.divemode);
+ fill_pressures(&entry->pressures, amb_pressure, gasmix, (current_divemode == OC) ? 0.0 : entry->o2pressure.mbar / 1000.0, current_divemode);
fn2 = (int)(1000.0 * entry->pressures.n2 / amb_pressure);
fhe = (int)(1000.0 * entry->pressures.he / amb_pressure);
if (dc->divemode == PSCR) // OC pO2 is calulated for PSCR with or without external PO2 monitoring.
diff --git a/libdivecomputer b/libdivecomputer
-Subproject e0761561e959dbfa7922ac2942fce4c044eef71
+Subproject e97a47cca55973199715df0f818b4955e60d3a3