summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2012-12-11 13:09:48 -0800
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-12-11 13:09:48 -0800
commit91577f11b5373557dca50627b8e3348b6dee2514 (patch)
tree8f9179a9b1f42375f4a34743efc111594bb1a7c4
parentc6ca263fb024bf06f76a5a89fbcd982f3f658d39 (diff)
parent563af1daa781a53fad308870320f99a1903d5058 (diff)
downloadsubsurface-91577f11b5373557dca50627b8e3348b6dee2514.tar.gz
Merge branch 'cns' into cns-merge
I foolishly changed visible_columns in both the (ill-named) cns branch and master... Signed-off-by: Dirk Hohndel <dirk@hohndel.org> Conflicts: divelist.c gtk-gui.c profile.c
-rw-r--r--color.h1
-rw-r--r--display-gtk.h1
-rw-r--r--display.h1
-rw-r--r--dive.c7
-rw-r--r--dive.h4
-rw-r--r--divelist.c31
-rw-r--r--gtk-gui.c10
-rw-r--r--libdivecomputer.c32
-rw-r--r--parse-xml.c19
-rw-r--r--profile.c392
-rw-r--r--save-xml.c4
-rw-r--r--uemis.c1
12 files changed, 188 insertions, 315 deletions
diff --git a/color.h b/color.h
index 38839ae7f..23065d306 100644
--- a/color.h
+++ b/color.h
@@ -31,6 +31,7 @@
// Monochromes
#define BLACK1_LOW_TRANS { 0.0, 0.0, 0.0, 0.75 }
+#define BLACK1_HIGH_TRANS { 0.0, 0.0, 0.0, 0.25 }
#define TUNDORA1_MED_TRANS { 0.3, 0.3, 0.3, 0.5 }
#define MERCURY1_MED_TRANS { 0.9, 0.9, 0.9, 0.5 }
#define CONCRETE1_LOWER_TRANS { 0.95, 0.95, 0.95, 0.9 }
diff --git a/display-gtk.h b/display-gtk.h
index b48c87eed..b2903d7e9 100644
--- a/display-gtk.h
+++ b/display-gtk.h
@@ -19,6 +19,7 @@ typedef struct {
gboolean nitrox;
gboolean sac;
gboolean otu;
+ gboolean maxcns;
} visible_cols_t;
typedef struct {
diff --git a/display.h b/display.h
index b2187d224..fbffc8f95 100644
--- a/display.h
+++ b/display.h
@@ -19,6 +19,7 @@ struct plot_info {
int minpressure, maxpressure;
int mintemp, maxtemp;
double endtempcoord;
+ double maxpp;
gboolean has_ndl;
struct plot_data *entry;
};
diff --git a/dive.c b/dive.c
index b197c835f..4dbf979b3 100644
--- a/dive.c
+++ b/dive.c
@@ -419,6 +419,7 @@ struct dive *fixup_dive(struct dive *dive)
add_location(dive->location);
add_suit(dive->suit);
sanitize_cylinder_info(dive);
+ dive->maxcns = dive->cns;
dc = &dive->dc;
for (i = 0; i < dc->samples; i++) {
struct sample *sample = dc->sample + i;
@@ -479,6 +480,8 @@ struct dive *fixup_dive(struct dive *dive)
depthtime += (time - lasttime) * (lastdepth + depth) / 2;
lastdepth = depth;
lasttime = time;
+ if (sample->cns > dive->maxcns)
+ dive->maxcns = sample->cns;
}
dive->start = start;
dive->end = end;
@@ -708,6 +711,10 @@ add_sample_b:
sample.cylinderpressure = as->cylinderpressure;
if (as->cylinderindex)
sample.cylinderindex = as->cylinderindex;
+ if (as->cns)
+ sample.cns = as->cns;
+ if (as->po2)
+ sample.po2 = as->po2;
merge_one_sample(&sample, at, res);
diff --git a/dive.h b/dive.h
index 487bc0d0e..7927512b7 100644
--- a/dive.h
+++ b/dive.h
@@ -230,6 +230,8 @@ struct sample {
duration_t ndl;
duration_t stoptime;
depth_t stopdepth;
+ int cns;
+ int po2;
};
/*
@@ -314,7 +316,7 @@ struct dive {
cylinder_t cylinder[MAX_CYLINDERS];
weightsystem_t weightsystem[MAX_WEIGHTSYSTEMS];
char *suit;
- int sac, otu;
+ int sac, otu, cns, maxcns;
/* Eventually we'll do multiple dive computers */
struct divecomputer dc;
diff --git a/divelist.c b/divelist.c
index 676ba62ae..a917889c4 100644
--- a/divelist.c
+++ b/divelist.c
@@ -28,7 +28,7 @@ struct DiveList {
GtkWidget *container_widget;
GtkTreeStore *model, *listmodel, *treemodel;
GtkTreeViewColumn *nr, *date, *stars, *depth, *duration, *location;
- GtkTreeViewColumn *temperature, *cylinder, *totalweight, *suit, *nitrox, *sac, *otu;
+ GtkTreeViewColumn *temperature, *cylinder, *totalweight, *suit, *nitrox, *sac, *otu, *maxcns;
int changed;
};
@@ -61,6 +61,7 @@ enum {
DIVE_NITROX, /* int: dummy */
DIVE_SAC, /* int: in ml/min */
DIVE_OTU, /* int: in OTUs */
+ DIVE_MAXCNS, /* int: in % */
DIVE_LOCATION, /* "2nd Cathedral, Lanai" */
DIVELIST_COLUMNS
};
@@ -691,6 +692,26 @@ static void otu_data_func(GtkTreeViewColumn *col,
g_object_set(renderer, "text", buffer, NULL);
}
+/* Render the CNS data (in full %) */
+static void cns_data_func(GtkTreeViewColumn *col,
+ GtkCellRenderer *renderer,
+ GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ int value, idx;
+ char buffer[16];
+
+ gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_MAXCNS, &value, -1);
+
+ if (idx < 0 || !value)
+ *buffer = '\0';
+ else
+ snprintf(buffer, sizeof(buffer), "%d%%", value);
+
+ g_object_set(renderer, "text", buffer, NULL);
+}
+
/* calculate OTU for a dive */
static int calculate_otu(struct dive *dive, struct divecomputer *dc)
{
@@ -841,6 +862,7 @@ static void fill_one_dive(struct dive *dive,
DIVE_RATING, dive->rating,
DIVE_SAC, dive->sac,
DIVE_OTU, dive->otu,
+ DIVE_MAXCNS, dive->maxcns,
DIVE_TOTALWEIGHT, total_weight(dive),
DIVE_SUIT, suit,
-1);
@@ -920,6 +942,7 @@ void update_dive_list_col_visibility(void)
gtk_tree_view_column_set_visible(dive_list.nitrox, prefs.visible_cols.nitrox);
gtk_tree_view_column_set_visible(dive_list.sac, prefs.visible_cols.sac);
gtk_tree_view_column_set_visible(dive_list.otu, prefs.visible_cols.otu);
+ gtk_tree_view_column_set_visible(dive_list.maxcns, prefs.visible_cols.maxcns);
return;
}
@@ -1273,6 +1296,7 @@ static struct divelist_column {
[DIVE_NITROX] = { "O" UTF8_SUBSCRIPT_2 "%", nitrox_data_func, nitrox_sort_func, 0, &prefs.visible_cols.nitrox },
[DIVE_SAC] = { N_("SAC"), sac_data_func, NULL, 0, &prefs.visible_cols.sac },
[DIVE_OTU] = { N_("OTU"), otu_data_func, NULL, 0, &prefs.visible_cols.otu },
+ [DIVE_MAXCNS] = { N_("maxCNS"), cns_data_func, NULL, 0, &prefs.visible_cols.maxcns },
[DIVE_LOCATION] = { N_("Location"), NULL, NULL, ALIGN_LEFT },
};
@@ -1456,6 +1480,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b)
DIVE_CYLINDER, &cylinder_text,
DIVE_SAC, &store_dive.sac,
DIVE_OTU, &store_dive.otu,
+ DIVE_MAXCNS, &store_dive.maxcns,
DIVE_LOCATION, &store_dive.location,
-1);
gtk_tree_store_set(STORE(dive_list), b,
@@ -1471,6 +1496,7 @@ static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b)
DIVE_CYLINDER, cylinder_text,
DIVE_SAC, store_dive.sac,
DIVE_OTU, store_dive.otu,
+ DIVE_MAXCNS, store_dive.maxcns,
DIVE_LOCATION, store_dive.location,
-1);
free(cylinder_text);
@@ -2386,6 +2412,7 @@ GtkWidget *dive_list_create(void)
G_TYPE_INT, /* Nitrox */
G_TYPE_INT, /* SAC */
G_TYPE_INT, /* OTU */
+ G_TYPE_INT, /* MAXCNS */
G_TYPE_STRING /* Location */
);
dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS,
@@ -2402,6 +2429,7 @@ GtkWidget *dive_list_create(void)
G_TYPE_INT, /* Nitrox */
G_TYPE_INT, /* SAC */
G_TYPE_INT, /* OTU */
+ G_TYPE_INT, /* MAXCNS */
G_TYPE_STRING /* Location */
);
dive_list.model = dive_list.treemodel;
@@ -2429,6 +2457,7 @@ GtkWidget *dive_list_create(void)
dive_list.nitrox = divelist_column(&dive_list, dl_column + DIVE_NITROX);
dive_list.sac = divelist_column(&dive_list, dl_column + DIVE_SAC);
dive_list.otu = divelist_column(&dive_list, dl_column + DIVE_OTU);
+ dive_list.maxcns = divelist_column(&dive_list, dl_column + DIVE_MAXCNS);
dive_list.location = divelist_column(&dive_list, dl_column + DIVE_LOCATION);
fill_dive_list();
diff --git a/gtk-gui.c b/gtk-gui.c
index 8633369b0..c7087acce 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -488,6 +488,7 @@ static void name(GtkWidget *w, gpointer data) \
}
OPTIONCALLBACK(otu_toggle, prefs.visible_cols.otu)
+OPTIONCALLBACK(maxcns_toggle, prefs.visible_cols.maxcns)
OPTIONCALLBACK(sac_toggle, prefs.visible_cols.sac)
OPTIONCALLBACK(nitrox_toggle, prefs.visible_cols.nitrox)
OPTIONCALLBACK(temperature_toggle, prefs.visible_cols.temperature)
@@ -693,6 +694,11 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(otu_toggle), NULL);
+ button = gtk_check_button_new_with_label(_("maxCNS"));
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.visible_cols.maxcns);
+ gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
+ g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(maxcns_toggle), NULL);
+
frame = gtk_frame_new(_("Profile Settings"));
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 5);
@@ -774,6 +780,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
sscanf(pn2_threshold_text, "%lf", &prefs.pp_graphs.pn2_threshold);
phe_threshold_text = gtk_entry_get_text(GTK_ENTRY(entry_phe));
sscanf(phe_threshold_text, "%lf", &prefs.pp_graphs.phe_threshold);
+
update_screen();
subsurface_set_conf("feet", PREF_BOOL, BOOL_TO_PTR(prefs.output_units.length == FEET));
@@ -789,6 +796,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
subsurface_set_conf("NITROX", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.nitrox));
subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.sac));
subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.otu));
+ subsurface_set_conf("MAXCNS", PREF_BOOL, BOOL_TO_PTR(prefs.visible_cols.maxcns));
subsurface_set_conf("divelist_font", PREF_STRING, divelist_font);
subsurface_set_conf("autogroup", PREF_BOOL, BOOL_TO_PTR(autogroup));
@@ -1148,8 +1156,8 @@ void init_ui(int *argcp, char ***argvp)
prefs.visible_cols.suit = PTR_TO_BOOL(subsurface_get_conf("SUIT", PREF_BOOL));
prefs.visible_cols.nitrox = PTR_TO_BOOL(subsurface_get_conf("NITROX", PREF_BOOL));
prefs.visible_cols.otu = PTR_TO_BOOL(subsurface_get_conf("OTU", PREF_BOOL));
+ prefs.visible_cols.maxcns = PTR_TO_BOOL(subsurface_get_conf("MAXCNS", PREF_BOOL));
prefs.visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL));
-
prefs.pp_graphs.po2 = PTR_TO_BOOL(subsurface_get_conf("po2graph", PREF_BOOL));
prefs.pp_graphs.pn2 = PTR_TO_BOOL(subsurface_get_conf("pn2graph", PREF_BOOL));
prefs.pp_graphs.phe = PTR_TO_BOOL(subsurface_get_conf("phegraph", PREF_BOOL));
diff --git a/libdivecomputer.c b/libdivecomputer.c
index ca91dc892..51c6a5775 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -22,7 +22,7 @@
static const char *progress_bar_text = "";
static double progress_bar_fraction = 0.0;
-static int stoptime, stopdepth, ndl;
+static int stoptime, stopdepth, ndl, po2, cns;
static GError *error(const char *fmt, ...)
{
@@ -97,10 +97,10 @@ static void handle_event(struct divecomputer *dc, struct sample *sample, dc_samp
if (value.event.type == SAMPLE_EVENT_SURFACE)
return;
- /* libdivecomputer 0.3 provides us with deco / ndl information for at least
- * the OSTC. Sadly, it does so through events - so we convert this into our
- * preferred sample format here */
-#if DC_VERSION_CHECK(0, 3, 0)
+ /* an early development version of libdivecomputer 0.3 provided us with deco / ndl information for
+ * a couple of dive computers through events; this got fixed later in the release cycle but for a
+ * short while I'll keep the code around that converts the events into our preferred sample format here */
+#if 0
if (value.event.type == SAMPLE_EVENT_DECOSTOP) {
/* packed value - time in seconds in high 16 bit
* depth in m(!) in low 16 bits */
@@ -152,6 +152,8 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
sample->ndl.seconds = ndl;
sample->stoptime.seconds = stoptime;
sample->stopdepth.mm = stopdepth;
+ sample->po2 = po2;
+ sample->cns = cns;
}
sample = prepare_sample(dc);
sample->time.seconds = value.time;
@@ -185,6 +187,26 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
printf("%02X", ((unsigned char *) value.vendor.data)[i]);
printf("</vendor>\n");
break;
+#if DC_VERSION_CHECK(0, 3, 0)
+ case DC_SAMPLE_SETPOINT:
+ /* for us a setpoint means constant pO2 from here */
+ sample->po2 = po2 = value.setpoint * 1000 + 0.5;
+ break;
+ case DC_SAMPLE_PPO2:
+ sample->po2 = po2 = value.ppo2 * 1000 + 0.5;
+ break;
+ case DC_SAMPLE_CNS:
+ sample->cns = cns = value.cns * 100 + 0.5;
+ break;
+ case DC_SAMPLE_DECO:
+ if (value.deco.type == DC_DECO_NDL) {
+ ndl = value.deco.time;
+ } else if (value.deco.type == DC_DECO_DECOSTOP ||
+ value.deco.type == DC_DECO_DEEPSTOP) {
+ stopdepth = value.deco.depth * 1000.0 + 0.5;
+ stoptime = value.deco.time;
+ }
+#endif
default:
break;
}
diff --git a/parse-xml.c b/parse-xml.c
index eb4d4832e..916a780d1 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -147,7 +147,7 @@ static struct {
} cur_event;
static struct tm cur_tm;
static int cur_cylinder_index, cur_ws_index;
-static int lastndl, laststoptime, laststopdepth;
+static int lastndl, laststoptime, laststopdepth, lastcns, lastpo2;
static enum import_source {
UNKNOWN,
@@ -463,6 +463,13 @@ static void get_index(char *buffer, void *_i)
free(buffer);
}
+static void double_to_permil(char *buffer, void *_i)
+{
+ int *i = _i;
+ *i = g_ascii_strtod(buffer, NULL) * 1000.0 + 0.5;
+ free(buffer);
+}
+
static void hex_value(char *buffer, void *_i)
{
uint32_t *i = _i;
@@ -654,6 +661,10 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
return;
if (MATCH(".sample.stopdepth", depth, &sample->stopdepth))
return;
+ if (MATCH(".sample.cns", get_index, &sample->cns))
+ return;
+ if (MATCH(".sample.po2", double_to_permil, &sample->po2))
+ return;
switch (import_source) {
case DIVINGLOG:
@@ -1064,6 +1075,8 @@ static void sample_start(void)
cur_sample->ndl.seconds = lastndl;
cur_sample->stoptime.seconds = laststoptime;
cur_sample->stopdepth.mm = laststopdepth;
+ cur_sample->cns = lastcns;
+ cur_sample->po2 = lastpo2;
}
static void sample_end(void)
@@ -1075,6 +1088,8 @@ static void sample_end(void)
lastndl = cur_sample->ndl.seconds;
laststoptime = cur_sample->stoptime.seconds;
laststopdepth = cur_sample->stopdepth.mm;
+ lastcns = cur_sample->cns;
+ lastpo2 = cur_sample->po2;
cur_sample = NULL;
}
@@ -1099,7 +1114,7 @@ static void divecomputer_start(void)
/* .. this is the one we'll use */
cur_dc = dc;
- lastndl = laststoptime = laststopdepth = 0;
+ lastcns = lastpo2 = lastndl = laststoptime = laststopdepth = 0;
}
static void divecomputer_end(void)
diff --git a/profile.c b/profile.c
index 047767ebd..1d0ec38e2 100644
--- a/profile.c
+++ b/profile.c
@@ -41,6 +41,7 @@ struct plot_data {
int ndl;
int stoptime;
int stopdepth;
+ int cns;
int smoothed;
double po2, pn2, phe;
velocity_t velocity;
@@ -68,7 +69,7 @@ typedef enum {
VELO_STABLE, VELO_SLOW, VELO_MODERATE, VELO_FAST, VELO_CRAZY,
/* gas colors */
- PO2, PO2_ALERT, PN2, PN2_ALERT, PHE, PHE_ALERT,
+ PO2, PO2_ALERT, PN2, PN2_ALERT, PHE, PHE_ALERT, PP_LINES,
/* Other colors */
TEXT_BACKGROUND, ALERT_BG, ALERT_FG, EVENTS, SAMPLE_DEEP, SAMPLE_SHALLOW,
@@ -108,6 +109,7 @@ static const color_t profile_color[] = {
[PN2_ALERT] = {{RED1, BLACK1_LOW_TRANS}},
[PHE] = {{PEANUT, PEANUT_MED_TRANS}},
[PHE_ALERT] = {{RED1, PEANUT_MED_TRANS}},
+ [PP_LINES] = {{BLACK1_HIGH_TRANS, BLACK1_HIGH_TRANS}},
[TEXT_BACKGROUND] = {{CONCRETE1_LOWER_TRANS, WHITE1}},
[ALERT_BG] = {{BROOM1_LOWER_TRANS, BLACK1_LOW_TRANS}},
@@ -356,6 +358,11 @@ static void plot_one_event(struct graphics_context *gc, struct plot_info *pi, st
}
}
}
+ if (event->time.seconds < 30 && !strcmp(event->name, "gaschange"))
+ /* a gas change in the first 30 seconds is the way of some dive computers
+ * to tell us the gas that is used; let's not plot a marker for that */
+ return;
+
for (i = 0; i < pi->nr; i++) {
struct plot_data *data = pi->entry + i;
if (event->time.seconds < data->sec)
@@ -516,186 +523,6 @@ static void plot_depth_scale(struct graphics_context *gc, struct plot_info *pi)
}
}
-/* ap points to an array of int with pi->nr + 1 elements that is
- * ininitialized with just one -1 entry
- * this adds entries (if they aren't too close to an existing one)
- * and keeps things sorted
- * we KNOW the array is big enough to hold all possible indices
- * a2p is a secondary array - we insert value at the same relative
- * positio as idx in ap */
-static void add_index(int idx, int margin, int **ap, int **a2p, int value)
-{
- int j, i = 0;
- int *a = *ap;
- int *a2 = *a2p;
-
- while (a[i] != -1 && a[i] < idx)
- i++;
- if (a[i] == idx)
- return;
- /* already have a POI to the left with the same vertical positiom and too close */
- if ((i > 0 && a[i - 1] != -1 && a2[i - 1] == value && idx - a[i - 1] < margin))
- return;
- /* already have a POI to the right with the same vertical positiom and too close */
- if (a[i] != -1 && a2[i] == value && a[i] - idx < margin)
- return;
- if (a[i] != -1 && a[i] - idx < margin)
- return;
- j = i;
- while (a[j] != -1)
- j++;
- while (j >= i) {
- a[j+1] = a[j];
- a2[j+1] = a2[j];
- j--;
- }
- a[i] = idx;
- a2[i] = value;
-}
-
-#define LI(_i,_j) MAX((_i)-(_j), 0)
-#define RI(_i,_j) MIN((_i)+(_j), nr - 1)
-#define SPIKE(_i,_s) if (fabs(_s) > fabs(spk_data[_i])) spk_data[_i] = (_s)
-/* this is an attempt at a metric that finds spikes in a data series */
-static void calculate_spikyness(int nr, double *data, double *spk_data, int deltax, double deltay)
-{
- int i, j;
- double dminl, dminr, dmaxl, dmaxr;
-
-#if DEBUG_PROFILE > 2
- printf("Spike data: \n 0 ");
-#endif
- for (i = 0; i < nr; i++) {
- dminl = dminr = dmaxl = dmaxr = data[i];
- spk_data[i] = 0.0;
- for (j = 1; j < deltax; j++) {
- if (data[LI(i,j)] < dminl)
- dminl = data[LI(i,j)];
- if (data[LI(i,j)] > dmaxl)
- dmaxl = data[LI(i,j)];
-
- if (data[RI(i,j)] < dminr)
- dminr = data[RI(i,j)];
- if (data[RI(i,j)] > dmaxr)
- dmaxr = data[RI(i,j)];
-
- /* don't do super narrow */
- if (j < deltax / 3)
- continue;
- /* falling edge on left */
- if (dmaxl == data[i] && dmaxr - data[i] < 0.1 * (data[i] - dminl))
- SPIKE(i,(data[i] - dminl) / j);
- /* falling edge on right */
- if (dmaxr == data[i] && dmaxl - data[i] < 0.1 * (data[i] - dminr))
- SPIKE(i,(data[i] - dminr) / j);
-
- /* minima get a negative spike value */
- /* rising edge on left */
- if (dminl == data[i] && data[i] - dminr < 0.1 * (dmaxl - data[i]))
- SPIKE(i,(data[i] - dmaxl) / j);
- /* rising edge on right */
- if (dminr == data[i] && data[i] - dminl < 0.1 * (dmaxr - data[i]))
- SPIKE(i,(data[i] - dmaxr) / j);
- }
-#if DEBUG_PROFILE > 2
- fprintf(debugfile, "%.4lf ", spk_data[i]);
- if (i % 12 == 11)
- fprintf(debugfile, "\n%2d ", (i + 1) / 12);
-#endif
- }
-#if DEBUG_PROFILE > 2
- printf("\n");
-#endif
-}
-
-/* only show one spike in a deltax wide region - pick the highest (and first if the same) */
-static gboolean higher_spike(double *spk_data, int idx, int nr, int deltax)
-{
- int i;
- double s = spk_data[idx];
- for (i = MAX(0, idx - deltax); i <= MIN(idx + deltax, nr - 1); i++) {
- if (s > 0) {
- if (spk_data[i] > s)
- return TRUE;
- } else {
- if (spk_data[i] < s)
- return TRUE;
- }
- if (spk_data[i] == s && i < idx)
- return TRUE;
- }
- return FALSE;
-}
-
-/* this figures out which time stamps provide "interesting" formations in the graphs;
- * this includes local minima and maxima as well as long plateaus.
- * pass in the function that returns the value at a certain point (as double),
- * the delta in time (expressed as number of data points of "significant time")
- * the delta at which the value is considered to have been "significantly changed" and
- * the number of points to cover
- * returns a list of indices that ends with a -1 of times that are "interesting" */
-static void find_points_of_interest(struct plot_info *pi, double (*value_func)(int, struct plot_info *),
- int deltax, double deltay, int **poip, int **poip_vpos)
-{
- int i, j, nr = pi->nr;
- double *data, *data_max, *data_min, *spk_data;
- double min, max;
- int *pois;
-
- /* avoid all the function calls by creating a local array and
- * have some helper arrays to make our lifes easier */
-
- data = malloc(nr * sizeof(double));
- data_max = malloc(nr * sizeof(double));
- data_min = malloc(nr * sizeof(double));
- spk_data = malloc(nr * sizeof(double));
-
- pois = *poip = malloc((nr + 1) * sizeof(int));
- *poip_vpos = malloc((nr + 1) * sizeof(int));
- pois[0] = -1;
- pois[1] = -1;
-
- /* copy the data and get the absolute minimum and maximum while we do it */
- for (i = 0; i < nr; i++) {
- data_max[i] = data_min[i] = data[i] = value_func(i, pi);
- if (i == 0 || data[i] < min)
- min = data[i];
- if (i == 0 || data[i] > max)
- max = data[i];
- }
- /* next find out if there are real spikes in the graph */
- calculate_spikyness(nr, data, spk_data, deltax, deltay);
-
- /* now process all data points */
- for (i = 0; i < nr; i++) {
- /* get the local min/max */
- for (j = MAX(0, i - deltax); j < i + deltax && j < nr; j++) {
- if (data[j] < data[i])
- data_min[i] = data[j];
- if (data[j] > data[i])
- data_max[i] = data[j];
- }
- /* is i the overall minimum or maximum */
- if (data[i] == max && (i == 0 || data[i - 1] != max))
- add_index(i, deltax, poip, poip_vpos, BOTTOM);
- if (data[i] == min && (i == 0 || data[i - 1] != min))
- add_index(i, deltax, poip, poip_vpos, TOP);
- /* is i a spike? */
- if (fabs(spk_data[i]) > 0.01 && ! higher_spike(spk_data, i, nr, deltax)) {
- if (spk_data[i] > 0.0)
- add_index(i, deltax, poip, poip_vpos, BOTTOM);
- if (spk_data[i] < 0.0)
- add_index(i, deltax, poip, poip_vpos, TOP);
- }
- /* is i a significant local minimum or maximum? */
- if (data[i] == data_min[i] && data_max[i] - data[i] > deltay)
- add_index(i, deltax, poip, poip_vpos, TOP);
- if (data[i] == data_max[i] && data[i] - data_min[i] > deltay)
- add_index(i, deltax, poip, poip_vpos, BOTTOM);
- }
- /* still need to search for plateaus */
-}
-
static void setup_pp_limits(struct graphics_context *gc, struct plot_info *pi)
{
int maxdepth;
@@ -711,99 +538,22 @@ static void setup_pp_limits(struct graphics_context *gc, struct plot_info *pi)
gc->bottomy = -gc->topy / 20;
}
-static void plot_single_pp_text(struct graphics_context *gc, int sec, double pp,
- double vpos, color_indice_t color)
-{
- text_render_options_t tro = {12, color, CENTER, vpos};
- plot_text(gc, &tro, sec, pp, "%.1lf", pp);
-}
-
-#define MAXPP(_mpp, _pp) { _mpp = 0; \
- for(i = 0; i< pi->nr; i++) \
- if (pi->entry[i]._pp > _mpp) \
- _mpp = pi->entry[i]._pp; \
- }
-
-static double po2_value(int idx, struct plot_info *pi)
-{
- return pi->entry[idx].po2;
-}
-
-static double pn2_value(int idx, struct plot_info *pi)
-{
- return pi->entry[idx].pn2;
-}
-
-static double phe_value(int idx, struct plot_info *pi)
-{
- return pi->entry[idx].phe;
-}
-
-static double plot_single_gas_pp_text(struct graphics_context *gc, struct plot_info *pi,
- double (*value_func)(int, struct plot_info *),
- double value_threshold, int color)
-{
- int *pois, *pois_vpos;
- int i, two_minutes = 1;
- double maxpp = 0.0;
-
- /* don't bother with local min/max if the dive is under two minutes */
- if (pi->entry[pi->nr - 1].sec > 120) {
- int idx = 0;
- while (pi->entry[idx].sec == 0)
- idx++;
- while (pi->entry[idx + two_minutes].sec < 120)
- two_minutes++;
- } else {
- two_minutes = pi->nr;
- }
- find_points_of_interest(pi, value_func, two_minutes, value_threshold, &pois, &pois_vpos);
- for (i = 0; pois[i] != -1; i++) {
- struct plot_data *entry = pi->entry + pois[i];
- double value = value_func(pois[i], pi);
-
-#if DEBUG_PROFILE > 1
- fprintf(debugfile, "POI at %d sec value %lf\n", entry->sec, entry->po2);
-#endif
- plot_single_pp_text(gc, entry->sec, value, pois_vpos[i], color);
- if (value > maxpp)
- maxpp = value;
- }
- free(pois);
- free(pois_vpos);
-
- return maxpp;
-}
-
static void plot_pp_text(struct graphics_context *gc, struct plot_info *pi)
{
- double pp, dpp, m, maxpp = 0.0;
+ double pp, dpp, m;
int hpos;
- static const text_render_options_t tro = {11, PN2, LEFT, MIDDLE};
+ static const text_render_options_t tro = {11, PP_LINES, LEFT, MIDDLE};
setup_pp_limits(gc, pi);
-
- if (prefs.pp_graphs.po2) {
- maxpp = plot_single_gas_pp_text(gc, pi, po2_value, 0.4, PO2);
- }
- if (prefs.pp_graphs.pn2) {
- m = plot_single_gas_pp_text(gc, pi, pn2_value, 0.6, PN2);
- if (m > maxpp)
- maxpp = m;
- }
- if (prefs.pp_graphs.phe) {
- m = plot_single_gas_pp_text(gc, pi, phe_value, 0.4, PHE);
- if (m > maxpp)
- maxpp = m;
- }
- /* while this is somewhat useful, I don't like the way it looks...
- * for now I'll leave the code here, but disable it */
- if (0) {
- pp = floor(maxpp * 10.0) / 10.0 + 0.2;
- dpp = floor(2.0 * pp) / 10.0;
- hpos = pi->entry[pi->nr - 1].sec + 30;
- for (m = 0.0; m <= pp; m += dpp)
- plot_text(gc, &tro, hpos, m, "%.1f", m);
+ pp = floor(pi->maxpp * 10.0) / 10.0 + 0.2;
+ dpp = floor(2.0 * pp) / 10.0;
+ hpos = pi->entry[pi->nr - 1].sec;
+ set_source_rgba(gc, PP_LINES);
+ for (m = 0.0; m <= pp; m += dpp) {
+ move_to(gc, 0, m);
+ line_to(gc, hpos, m);
+ cairo_stroke(gc->cr);
+ plot_text(gc, &tro, hpos + 30, m, "%.1f", m);
}
}
@@ -814,31 +564,6 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p
setup_pp_limits(gc, pi);
- if (prefs.pp_graphs.po2) {
- set_source_rgba(gc, PO2);
- entry = pi->entry;
- move_to(gc, entry->sec, entry->po2);
- for (i = 1; i < pi->nr; i++) {
- entry++;
- if (entry->po2 < prefs.pp_graphs.po2_threshold)
- line_to(gc, entry->sec, entry->po2);
- else
- move_to(gc, entry->sec, entry->po2);
- }
- cairo_stroke(gc->cr);
-
- set_source_rgba(gc, PO2_ALERT);
- entry = pi->entry;
- move_to(gc, entry->sec, entry->po2);
- for (i = 1; i < pi->nr; i++) {
- entry++;
- if (entry->po2 >= prefs.pp_graphs.po2_threshold)
- line_to(gc, entry->sec, entry->po2);
- else
- move_to(gc, entry->sec, entry->po2);
- }
- cairo_stroke(gc->cr);
- }
if (prefs.pp_graphs.pn2) {
set_source_rgba(gc, PN2);
entry = pi->entry;
@@ -889,6 +614,31 @@ static void plot_pp_gas_profile(struct graphics_context *gc, struct plot_info *p
}
cairo_stroke(gc->cr);
}
+ if (prefs.pp_graphs.po2) {
+ set_source_rgba(gc, PO2);
+ entry = pi->entry;
+ move_to(gc, entry->sec, entry->po2);
+ for (i = 1; i < pi->nr; i++) {
+ entry++;
+ if (entry->po2 < prefs.pp_graphs.po2_threshold)
+ line_to(gc, entry->sec, entry->po2);
+ else
+ move_to(gc, entry->sec, entry->po2);
+ }
+ cairo_stroke(gc->cr);
+
+ set_source_rgba(gc, PO2_ALERT);
+ entry = pi->entry;
+ move_to(gc, entry->sec, entry->po2);
+ for (i = 1; i < pi->nr; i++) {
+ entry++;
+ if (entry->po2 >= prefs.pp_graphs.po2_threshold)
+ line_to(gc, entry->sec, entry->po2);
+ else
+ move_to(gc, entry->sec, entry->po2);
+ }
+ cairo_stroke(gc->cr);
+ }
}
static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi)
@@ -1605,14 +1355,20 @@ static int get_cylinder_index(struct dive *dive, struct event *ev)
*
* Crazy suunto gas change events. We really should do
* this in libdivecomputer or something.
+ *
+ * There are two different gas change events that can get
+ * us here - GASCHANGE2 has the He value in the high 16
+ * bits; looking at the possible values we can actually
+ * handle them with the same code since the high 16 bits
+ * will be 0 with the GASCHANGE event - and that means no He
*/
for (i = 0; i < MAX_CYLINDERS; i++) {
cylinder_t *cyl = dive->cylinder+i;
int o2 = (cyl->gasmix.o2.permille + 5) / 10;
- if (o2 == ev->value)
+ int he = (cyl->gasmix.he.permille + 5) / 10;
+ if (o2 == (ev->value & 0xFFFF) && he == (ev->value >> 16))
return i;
}
-
return 0;
}
@@ -1750,14 +1506,14 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
{
int cylinderindex = -1;
int lastdepth, lastindex;
- int i, pi_idx, nr, sec, cyl, stoptime, ndl, stopdepth;
+ int i, pi_idx, nr, sec, cyl, stoptime, ndl, stopdepth, cns;
struct plot_info *pi;
pr_track_t *track_pr[MAX_CYLINDERS] = {NULL, };
pr_track_t *pr_track, *current;
gboolean missing_pr = FALSE;
struct plot_data *entry = NULL;
struct event *ev;
- double amb_pressure;
+ double amb_pressure, po2;
/* The plot-info is embedded in the graphics context */
pi = &gc->pi;
@@ -1800,6 +1556,8 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
pi->has_ndl |= ndl;
stopdepth = sample->stopdepth.mm;
stoptime = sample->stoptime.seconds;
+ po2 = sample->po2 / 1000.0;
+ cns = sample->cns;
while (ev && ev->time.seconds < sample->time.seconds) {
/* insert two fake plot info structures for the end of
* the old tank and the start of the new tank */
@@ -1820,9 +1578,13 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
entry->stopdepth = stopdepth;
entry->stoptime = stoptime;
entry->ndl = ndl;
+ entry->cns = cns;
+ entry->po2 = po2;
(entry + 1)->stopdepth = stopdepth;
(entry + 1)->stoptime = stoptime;
(entry + 1)->ndl = ndl;
+ (entry + 1)->cns = cns;
+ (entry + 1)->po2 = po2;
pi_idx += 2;
entry = pi->entry + i + pi_idx;
ev = get_next_event(ev->next, "gaschange");
@@ -1836,6 +1598,8 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
entry->stopdepth = stopdepth;
entry->stoptime = stoptime;
entry->ndl = ndl;
+ entry->cns = cns;
+ entry->po2 = po2;
pi_idx++;
entry = pi->entry + i + pi_idx;
ev = get_next_event(ev->next, "gaschange");
@@ -1846,6 +1610,8 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
entry->stopdepth = stopdepth;
entry->stoptime = stoptime;
entry->ndl = ndl;
+ entry->cns = cns;
+ entry->po2 = po2;
entry->cylinderindex = sample->cylinderindex;
SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar;
entry->temperature = sample->temperature.mkelvin;
@@ -1901,10 +1667,26 @@ static struct plot_info *create_plot_info(struct dive *dive, struct divecomputer
if (!fo2)
fo2 = AIR_PERMILLE;
- entry->po2 = fo2 / 1000.0 * amb_pressure;
- entry->phe = fhe / 1000.0 * amb_pressure;
- entry->pn2 = (1000 - fo2 - fhe) / 1000.0 * amb_pressure;
-
+ if (entry->po2) {
+ /* we have an O2 partial pressure in the sample - so this
+ * is likely a CC dive... use that instead of the value
+ * from the cylinder info */
+ double po2 = entry->po2 > amb_pressure ? amb_pressure : entry->po2;
+ double ratio = (double)fhe / (1000.0 - fo2);
+ entry->phe = (amb_pressure - po2) * ratio;
+ entry->pn2 = amb_pressure - po2 - entry->phe;
+ entry->po2 = po2;
+ } else {
+ entry->po2 = fo2 / 1000.0 * amb_pressure;
+ entry->phe = fhe / 1000.0 * amb_pressure;
+ entry->pn2 = (1000 - fo2 - fhe) / 1000.0 * amb_pressure;
+ }
+ if (entry->po2 > pi->maxpp)
+ pi->maxpp = entry->po2;
+ if (entry->phe > pi->maxpp)
+ pi->maxpp = entry->phe;
+ if (entry->pn2 > pi->maxpp)
+ pi->maxpp = entry->pn2;
/* finally, do the discrete integration to get the SAC rate equivalent */
current->pressure_time += (entry->sec - (entry-1)->sec) *
depth_to_mbar((entry->depth + (entry-1)->depth) / 2, dive) / 1000.0;
@@ -2142,15 +1924,15 @@ static void plot_string(struct plot_data *entry, char *buf, size_t bufsize,
}
if (prefs.pp_graphs.po2) {
memcpy(buf2, buf, bufsize);
- snprintf(buf, bufsize, "%s\npO" UTF8_SUBSCRIPT_2 ":%.1f", buf2, entry->po2);
+ snprintf(buf, bufsize, "%s\npO" UTF8_SUBSCRIPT_2 ":%.2f", buf2, entry->po2);
}
if (prefs.pp_graphs.pn2) {
memcpy(buf2, buf, bufsize);
- snprintf(buf, bufsize, "%s\npN" UTF8_SUBSCRIPT_2 ":%.1f", buf2, entry->pn2);
+ snprintf(buf, bufsize, "%s\npN" UTF8_SUBSCRIPT_2 ":%.2f", buf2, entry->pn2);
}
if (prefs.pp_graphs.phe) {
memcpy(buf2, buf, bufsize);
- snprintf(buf, bufsize, "%s\npHe:%.1f", buf2, entry->phe);
+ snprintf(buf, bufsize, "%s\npHe:%.2f", buf2, entry->phe);
}
free(buf2);
}
diff --git a/save-xml.c b/save-xml.c
index 1d38cc1b8..fb9eb413a 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -334,6 +334,10 @@ static void save_sample(FILE *f, struct sample *sample, const struct sample *pre
fprintf(f, " stoptime='%u:%02u min'", FRACTION(sample->stoptime.seconds, 60));
if (sample->stopdepth.mm != prev->stopdepth.mm)
show_milli(f, " stopdepth='", sample->stopdepth.mm, " m", "'");
+ if (sample->cns != prev->cns)
+ fprintf(f, " cns='%u%%'", sample->cns);
+ if (sample->po2 != prev->po2)
+ fprintf(f, " po2='%u.%2u bar'", FRACTION(sample->po2, 1000));
fprintf(f, " />\n");
}
diff --git a/uemis.c b/uemis.c
index e4a4adb21..8d05a99f9 100644
--- a/uemis.c
+++ b/uemis.c
@@ -349,6 +349,7 @@ void uemis_parse_divelog_binary(char *base64, void *datap) {
sample->cylinderindex = u_sample->active_tank;
sample->cylinderpressure.mbar =
(u_sample->tank_pressure_high * 256 + u_sample->tank_pressure_low) * 10;
+ sample->cns = u_sample->cns;
uemis_event(dive, dc, sample, u_sample);
finish_sample(dc);
i += 0x25;