In the attached screenshot the green line is the voted PO2 from the DC (I
changed the colours because... messing around. They're not colour blindness
friendly). On my JJ the reported PO2 from the dive computer (Petrel 2) is
slightly lower than the uncalibrated sensor values.

I've tested saving/loading from XML and saving/loading from git, which work.

In a nutshell I've added an additional field in both libdivecomputer and
Subsurface. If the additional field is populated, Subsurface will use that
instead of trying to average/calculate the PO2.

I still need to test what it does on Android. I still need to clean up
stuff. There's probably a better way of implementing this functionality.

Aaron

On Sun, Jun 17, 2018 at 5:18 PM, Aaron Scheiner <[email protected]> wrote:

> I'm in the same boat and last week I started working on adding an
> additional field to both subsurface and libdivecomputer (I called it voted
> PO2). I managed to get the import and display of it working before I got
> interrupted by other stuff. It has subsequently occurred to me that this
> may not be the best approach.
>
> I'll have a look at it again and try and come up with a better way.
>
> Aaron
>
> On Sun, Jun 17, 2018, 11:53 Davide DB <[email protected]> wrote:
>
>> On Thu, Jun 14, 2018, 15:34 Long, Martin <[email protected]> wrote:
>>
>>> I'm in agreement with Davide that any interim solution we can get
>>> running is better than the way it is working now. It's a regression, and
>>> tbh if there isn't an interim solution then it ought to be reverted to the
>>> old behaviour. At the moment I'm having to use Shearwater desktop for
>>> reviewing all my logs.
>>>
>>
>> I had to stop using Subsurface for the time being. First time in so many
>> years.
>>
>> If the bug will be solved I would have to transfer and compile from
>> scratch more than 60 dives (until now). I don't know if I will have the
>> time or will to do all this work and frankly speaking I'm tired to be
>> always a minority.
>>
>> Farewell my friends. It has been a nice journey. Thank you all for the
>> amazing work.
>>
>>>
>>
>> davide@mobile
>>
>>
>>
>>> _______________________________________________
>> subsurface mailing list
>> [email protected]
>> http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
>>
>
diff --git a/core/color.cpp b/core/color.cpp
index c0b8a4643..0a959ab92 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -29,9 +29,10 @@ void fill_profile_color()
 	profile_color[PHE] = COLOR(PEANUT, BLACK1_LOW_TRANS, PEANUT);
 	profile_color[PHE_ALERT] = COLOR(RED1, BLACK1_LOW_TRANS, RED1);
 	profile_color[O2SETPOINT] = COLOR(PIRATEGOLD1_MED_TRANS, BLACK1_LOW_TRANS, PIRATEGOLD1_MED_TRANS);
-	profile_color[CCRSENSOR1] = COLOR(TUNDORA1_MED_TRANS, BLACK1_LOW_TRANS, TUNDORA1_MED_TRANS);
-	profile_color[CCRSENSOR2] = COLOR(ROYALBLUE2_LOW_TRANS, BLACK1_LOW_TRANS, ROYALBLUE2_LOW_TRANS);
-	profile_color[CCRSENSOR3] = COLOR(PEANUT, BLACK1_LOW_TRANS, PEANUT);
+	profile_color[CCRSENSOR1] = COLOR(RED1, BLACK1_LOW_TRANS, RED1);
+	profile_color[CCRSENSOR2] = COLOR(NITROX_YELLOW, BLACK1_LOW_TRANS, NITROX_YELLOW);
+	profile_color[CCRSENSOR3] = COLOR(ROYALBLUE2, BLACK1_LOW_TRANS, ROYALBLUE2);
+	profile_color[CCRVOTEDSENSOR] = COLOR(BLACK1_HIGH_TRANS,BLACK1_HIGH_TRANS,BLACK1_HIGH_TRANS);
 	profile_color[SCR_OCPO2] = COLOR(PIRATEGOLD1_MED_TRANS, BLACK1_LOW_TRANS, PIRATEGOLD1_MED_TRANS);
 
 	profile_color[PP_LINES] = COLOR(BLACK1_HIGH_TRANS, BLACK1_LOW_TRANS, BLACK1_HIGH_TRANS);
diff --git a/core/color.h b/core/color.h
index bf2f1ddcb..7ac269bfd 100644
--- a/core/color.h
+++ b/core/color.h
@@ -103,6 +103,7 @@ typedef enum {
 	CCRSENSOR1,
 	CCRSENSOR2,
 	CCRSENSOR3,
+	CCRVOTEDSENSOR,
 	SCR_OCPO2,
 	PP_LINES,
 
diff --git a/core/dive.h b/core/dive.h
index 5c7b74395..16b0ce2d4 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -174,6 +174,7 @@ struct sample                         // BASE TYPE BYTES  UNITS    RANGE
 	pressure_t pressure[MAX_SENSORS]; // int32_t    4    mbar   (0-2 Mbar)             cylinder pressures (main and CCR o2)
 	o2pressure_t setpoint;            // uint16_t   2    mbar   (0-65 bar)             O2 partial pressure (will be setpoint)
 	o2pressure_t o2sensor[3];         // uint16_t   6    mbar   (0-65 bar)             Up to 3 PO2 sensor values (rebreather)
+	o2pressure_t votedpo2;            // uint16_t   2    mbar   (0-65 bar)             O2 partial pressure (as displayed by DC)
 	bearing_t bearing;                // int16_t    2  degrees  (-1 no val, 0-360 deg) compass bearing
 	uint8_t sensor[MAX_SENSORS];      // uint8_t    1  sensorID (0-255)                ID of cylinder pressure sensor
 	uint16_t cns;                     // uint16_t   1     %     (0-64k %)              cns% accumulated
diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c
index 3443886b6..7f54ac079 100644
--- a/core/libdivecomputer.c
+++ b/core/libdivecomputer.c
@@ -403,6 +403,9 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
 		if (nsensor > dc->no_o2sensors)
 			dc->no_o2sensors = nsensor;
 		break;
+	case DC_SAMPLE_VOTED_PPO2:
+        sample->votedpo2.mbar = lrint(value.ppo2 * 1000);
+	    break;
 	case DC_SAMPLE_CNS:
 		sample->cns = cns = lrint(value.cns * 100);
 		break;
diff --git a/core/load-git.c b/core/load-git.c
index b42492854..1fc8fc9ba 100644
--- a/core/load-git.c
+++ b/core/load-git.c
@@ -529,9 +529,14 @@ static void parse_sample_keyvalue(void *_sample, const char *key, const char *va
 		sample->o2sensor[2].mbar = p.mbar;
 		return;
 	}
-	if (!strcmp(key, "o2pressure")) {
-		pressure_t p = get_pressure(value);
-		sample->pressure[1].mbar = p.mbar;
+    if (!strcmp(key, "o2pressure")) {
+        pressure_t p = get_pressure(value);
+        sample->pressure[1].mbar = p.mbar;
+        return;
+    }
+	if (!strcmp(key, "votedpo2")) {
+        pressure_t p = get_pressure(value);
+        sample->votedpo2.mbar = p.mbar;
 		return;
 	}
 	if (!strcmp(key, "heartbeat")) {
diff --git a/core/parse-xml.c b/core/parse-xml.c
index ff9fa2421..a583c97ef 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -887,6 +887,8 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
 		return;
 	if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2])) // up to 3 CCR sensors
 		return;
+	if (MATCH("votedpo2.sample", double_to_o2pressure, &sample->votedpo2)) // the voted po2
+		return;
 	if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint))
 		return;
 	if (MATCH("heartbeat", get_uint8, &sample->heartbeat))
diff --git a/core/profile.c b/core/profile.c
index 113f62845..e819cf539 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -582,9 +582,13 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *
 		entry->cns = sample->cns;
 		if (dc->divemode == CCR || (dc->divemode == PSCR && dc->no_o2sensors)) {
 			entry->o2pressure.mbar = entry->o2setpoint.mbar = sample->setpoint.mbar;     // for rebreathers
+            if (entry->votedpo2.mbar > 0) {
+                entry->o2pressure.mbar = entry->votedpo2.mbar;
+            }
 			entry->o2sensor[0].mbar = sample->o2sensor[0].mbar; // for up to three rebreather O2 sensors
 			entry->o2sensor[1].mbar = sample->o2sensor[1].mbar;
 			entry->o2sensor[2].mbar = sample->o2sensor[2].mbar;
+			entry->votedpo2.mbar = sample->votedpo2.mbar;
 		} else {
 			entry->pressures.o2 = sample->setpoint.mbar / 1000.0;
 		}
@@ -1165,6 +1169,12 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne
  */
 static int calculate_ccr_po2(struct plot_data *entry, struct divecomputer *dc)
 {
+	/* If the DC reported a voted PO2/Average PO2, use that.
+	 */
+	if (entry->votedpo2.mbar > 0) {
+		return entry->votedpo2.mbar;
+	}
+
 	int sump = 0, minp = 999999, maxp = -999999;
 	int diff_limit = 100; // The limit beyond which O2 sensor differences are considered significant (default = 100 mbar)
 	int i, np = 0;
@@ -1284,6 +1294,8 @@ void fill_o2_values(struct dive *dive, struct divecomputer *dc, struct plot_info
 	}
 }
 
+// take me out
+
 #ifdef DEBUG_GAS
 /* A CCR debug function that writes the cylinder pressure and the oxygen values to the file debug_print_profiledata.dat:
  * Called in create_plot_info_new()
@@ -1301,7 +1313,7 @@ static void debug_print_profiledata(struct plot_info *pi)
 			entry = pi->entry + i;
 			fprintf(f1, "%d gas=%8d %8d ; dil=%8d %8d ; o2_sp= %d %d %d %d PO2= %f\n", i, SENSOR_PRESSURE(entry),
 				INTERPOLATED_PRESSURE(entry), O2CYLINDER_PRESSURE(entry), INTERPOLATED_O2CYLINDER_PRESSURE(entry),
-				entry->o2pressure.mbar, entry->o2sensor[0].mbar, entry->o2sensor[1].mbar, entry->o2sensor[2].mbar, entry->pressures.o2);
+				entry->o2pressure.mbar, entry->o2sensor[0].mbar, entry->o2sensor[1].mbar, entry->o2sensor[2].mbar, entry->pressures.o2, entry->votedpo2.mbar);
 		}
 		fclose(f1);
 	}
diff --git a/core/profile.h b/core/profile.h
index 58c44d955..cdc93dcac 100644
--- a/core/profile.h
+++ b/core/profile.h
@@ -46,6 +46,7 @@ struct plot_data {
 	pressure_t o2pressure;  // for rebreathers, this is consensus measured po2, or setpoint otherwise. 0 for OC.
 	pressure_t o2sensor[3]; //for rebreathers with up to 3 PO2 sensors
 	pressure_t o2setpoint;
+	pressure_t votedpo2;
 	pressure_t scr_OC_pO2;
 	double mod, ead, end, eadd;
 	velocity_t velocity;
diff --git a/core/save-git.c b/core/save-git.c
index 5d117748a..49e29f38e 100644
--- a/core/save-git.c
+++ b/core/save-git.c
@@ -285,6 +285,11 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
 		put_format(b, ":%d", sensor);
 	}
 
+	if (sample->votedpo2.mbar > 0 && sample->votedpo2.mbar != old->votedpo2.mbar) {
+        put_milli(b, " votedpo2=", sample->votedpo2.mbar, "bar");
+		old->votedpo2.mbar = sample->votedpo2.mbar;
+	}
+
 	/* the deco/ndl values are stored whenever they change */
 	if (sample->ndl.seconds != old->ndl.seconds) {
 		put_format(b, " ndl=%u:%02u", FRACTION(sample->ndl.seconds, 60));
diff --git a/core/save-xml.c b/core/save-xml.c
index 7198421e1..3f84453fa 100644
--- a/core/save-xml.c
+++ b/core/save-xml.c
@@ -281,6 +281,11 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
 		old->o2sensor[2] = sample->o2sensor[2];
 	}
 
+	if (sample->votedpo2.mbar > 0 && sample->votedpo2.mbar != old->votedpo2.mbar) {
+		put_milli(b, " votedpo2='", sample->votedpo2.mbar, " bar'");
+		old->votedpo2.mbar = sample->votedpo2.mbar;
+	}
+
 	if (sample->setpoint.mbar != old->setpoint.mbar) {
 		put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
 		old->setpoint = sample->setpoint;
diff --git a/libdivecomputer b/libdivecomputer
index e97a47cca..f203bb03c 160000
--- a/libdivecomputer
+++ b/libdivecomputer
@@ -1 +1 @@
-Subproject commit e97a47cca55973199715df0f818b4955e60d3a31
+Subproject commit f203bb03c85d2487db1e2be5ab6eee9ebc7f57c4
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index 25bff64ea..54e93d1ec 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -111,6 +111,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent),
 	ccrsensor1GasItem(new PartialPressureGasItem()),
 	ccrsensor2GasItem(new PartialPressureGasItem()),
 	ccrsensor3GasItem(new PartialPressureGasItem()),
+    ccrsensorVotedGasItem(new PartialPressureGasItem()),
 	ocpo2GasItem(new PartialPressureGasItem()),
 #ifndef SUBSURFACE_MOBILE
 	diveCeiling(new DiveCalculatedCeiling(this)),
@@ -201,6 +202,7 @@ void ProfileWidget2::addItemsToScene()
 	scene()->addItem(ccrsensor1GasItem);
 	scene()->addItem(ccrsensor2GasItem);
 	scene()->addItem(ccrsensor3GasItem);
+    scene()->addItem(ccrsensorVotedGasItem);
 	scene()->addItem(ocpo2GasItem);
 #ifndef SUBSURFACE_MOBILE
 	scene()->addItem(toolTipItem);
@@ -319,6 +321,7 @@ void ProfileWidget2::setupItemOnScene()
 	createPPGas(ccrsensor1GasItem, DivePlotDataModel::CCRSENSOR1, CCRSENSOR1, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ccrsensor2GasItem, DivePlotDataModel::CCRSENSOR2, CCRSENSOR2, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ccrsensor3GasItem, DivePlotDataModel::CCRSENSOR3, CCRSENSOR3, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
+	createPPGas(ccrsensorVotedGasItem, DivePlotDataModel::CCRVOTEDSENSOR, CCRVOTEDSENSOR, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ocpo2GasItem, DivePlotDataModel::SCR_OC_PO2, SCR_OCPO2, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 
 #undef CREATE_PP_GAS
@@ -336,6 +339,7 @@ void ProfileWidget2::setupItemOnScene()
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor1GasItem, &PartialPressureGasItem::setVisible);
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor2GasItem, &PartialPressureGasItem::setVisible);
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor3GasItem, &PartialPressureGasItem::setVisible);
+	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensorVotedGasItem, &PartialPressureGasItem::setVisible);
 
 	heartBeatAxis->setTextVisible(true);
 	heartBeatAxis->setLinesVisible(true);
@@ -605,6 +609,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 	ccrsensor1GasItem->setVisible(sensorflag);
 	ccrsensor2GasItem->setVisible(sensorflag && (currentdc->no_o2sensors > 1));
 	ccrsensor3GasItem->setVisible(sensorflag && (currentdc->no_o2sensors > 2));
+	ccrsensorVotedGasItem->setVisible(sensorflag);
 	ocpo2GasItem->setVisible((currentdc->divemode == PSCR) && prefs.show_scr_ocpo2);
 
 	/* This struct holds all the data that's about to be plotted.
@@ -713,6 +718,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 		ccrsensor1GasItem->setVisible(prefs.show_ccr_sensors);
 		ccrsensor2GasItem->setVisible(prefs.show_ccr_sensors && (currentdc->no_o2sensors > 1));
 		ccrsensor3GasItem->setVisible(prefs.show_ccr_sensors && (currentdc->no_o2sensors > 1));
+		ccrsensorVotedGasItem->setVisible(true);
 		ocpo2GasItem->setVisible((currentdc->divemode == PSCR) && prefs.show_scr_ocpo2);
 		temperatureItem->setVisible(false);
 	} else {
@@ -725,6 +731,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 		ccrsensor1GasItem->setVisible(false);
 		ccrsensor2GasItem->setVisible(false);
 		ccrsensor3GasItem->setVisible(false);
+		ccsensorVotedGasItem->setVisible(false);
 		ocpo2GasItem->setVisible(false);
 	}
 #endif
@@ -1090,6 +1097,7 @@ void ProfileWidget2::setEmptyState()
 	ccrsensor1GasItem->setVisible(false);
 	ccrsensor2GasItem->setVisible(false);
 	ccrsensor3GasItem->setVisible(false);
+	ccrsensorVotedGasItem->setVisible(false);
 	ocpo2GasItem->setVisible(false);
 #ifndef SUBSURFACE_MOBILE
 	toolTipItem->setVisible(false);
@@ -1211,6 +1219,7 @@ void ProfileWidget2::setProfileState()
 	ccrsensor1GasItem->setVisible(sensorflag);
 	ccrsensor2GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 1));
 	ccrsensor3GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 2));
+	ccrsensorVotedGasItem->setVisible(sensorflag);
 	ocpo2GasItem->setVisible(current_dive && (current_dc->divemode == PSCR) && prefs.show_scr_ocpo2);
 
 	heartBeatItem->setVisible(prefs.hrgraph);
diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h
index 91774c9a9..6c3a8c19b 100644
--- a/profile-widget/profilewidget2.h
+++ b/profile-widget/profilewidget2.h
@@ -204,6 +204,7 @@ private:
 	PartialPressureGasItem *ccrsensor1GasItem;
 	PartialPressureGasItem *ccrsensor2GasItem;
 	PartialPressureGasItem *ccrsensor3GasItem;
+	PartialPressureGasItem *ccrsensorVotedGasItem;
 	PartialPressureGasItem *ocpo2GasItem;
 #ifndef SUBSURFACE_MOBILE
 	DiveCalculatedCeiling *diveCeiling;
diff --git a/qt-models/diveplotdatamodel.cpp b/qt-models/diveplotdatamodel.cpp
index 35490a0a3..18ac69b6b 100644
--- a/qt-models/diveplotdatamodel.cpp
+++ b/qt-models/diveplotdatamodel.cpp
@@ -61,6 +61,8 @@ QVariant DivePlotDataModel::data(const QModelIndex &index, int role) const
 			return item.o2sensor[1].mbar / 1000.0;
 		case CCRSENSOR3:
 			return item.o2sensor[2].mbar / 1000.0;
+		case CCRVOTEDSENSOR:
+			return item.votedpo2.mbar / 1000.0;
 		case SCR_OC_PO2:
 			return item.scr_OC_pO2.mbar / 1000.0;
 		case HEARTBEAT:
@@ -144,6 +146,8 @@ QVariant DivePlotDataModel::headerData(int section, Qt::Orientation orientation,
 		return tr("Sensor 2");
 	case CCRSENSOR3:
 		return tr("Sensor 3");
+	case CCRVOTEDSENSOR:
+	    return tr("Voted PO2");
 	case AMBPRESSURE:
 		return tr("Ambient pressure");
 	case HEARTBEAT:
diff --git a/qt-models/diveplotdatamodel.h b/qt-models/diveplotdatamodel.h
index 51dc44176..01d3bd28f 100644
--- a/qt-models/diveplotdatamodel.h
+++ b/qt-models/diveplotdatamodel.h
@@ -64,6 +64,7 @@ public:
 		CCRSENSOR1,
 		CCRSENSOR2,
 		CCRSENSOR3,
+		CCRVOTEDSENSOR,
 		SCR_OC_PO2,
 		HEARTBEAT,
 		AMBPRESSURE,
diff --git a/core/color.cpp b/core/color.cpp
index c0b8a4643..0a959ab92 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -29,9 +29,10 @@ void fill_profile_color()
 	profile_color[PHE] = COLOR(PEANUT, BLACK1_LOW_TRANS, PEANUT);
 	profile_color[PHE_ALERT] = COLOR(RED1, BLACK1_LOW_TRANS, RED1);
 	profile_color[O2SETPOINT] = COLOR(PIRATEGOLD1_MED_TRANS, BLACK1_LOW_TRANS, PIRATEGOLD1_MED_TRANS);
-	profile_color[CCRSENSOR1] = COLOR(TUNDORA1_MED_TRANS, BLACK1_LOW_TRANS, TUNDORA1_MED_TRANS);
-	profile_color[CCRSENSOR2] = COLOR(ROYALBLUE2_LOW_TRANS, BLACK1_LOW_TRANS, ROYALBLUE2_LOW_TRANS);
-	profile_color[CCRSENSOR3] = COLOR(PEANUT, BLACK1_LOW_TRANS, PEANUT);
+	profile_color[CCRSENSOR1] = COLOR(RED1, BLACK1_LOW_TRANS, RED1);
+	profile_color[CCRSENSOR2] = COLOR(NITROX_YELLOW, BLACK1_LOW_TRANS, NITROX_YELLOW);
+	profile_color[CCRSENSOR3] = COLOR(ROYALBLUE2, BLACK1_LOW_TRANS, ROYALBLUE2);
+	profile_color[CCRVOTEDSENSOR] = COLOR(BLACK1_HIGH_TRANS,BLACK1_HIGH_TRANS,BLACK1_HIGH_TRANS);
 	profile_color[SCR_OCPO2] = COLOR(PIRATEGOLD1_MED_TRANS, BLACK1_LOW_TRANS, PIRATEGOLD1_MED_TRANS);
 
 	profile_color[PP_LINES] = COLOR(BLACK1_HIGH_TRANS, BLACK1_LOW_TRANS, BLACK1_HIGH_TRANS);
diff --git a/core/color.h b/core/color.h
index bf2f1ddcb..7ac269bfd 100644
--- a/core/color.h
+++ b/core/color.h
@@ -103,6 +103,7 @@ typedef enum {
 	CCRSENSOR1,
 	CCRSENSOR2,
 	CCRSENSOR3,
+	CCRVOTEDSENSOR,
 	SCR_OCPO2,
 	PP_LINES,
 
diff --git a/core/dive.h b/core/dive.h
index 5c7b74395..16b0ce2d4 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -174,6 +174,7 @@ struct sample                         // BASE TYPE BYTES  UNITS    RANGE
 	pressure_t pressure[MAX_SENSORS]; // int32_t    4    mbar   (0-2 Mbar)             cylinder pressures (main and CCR o2)
 	o2pressure_t setpoint;            // uint16_t   2    mbar   (0-65 bar)             O2 partial pressure (will be setpoint)
 	o2pressure_t o2sensor[3];         // uint16_t   6    mbar   (0-65 bar)             Up to 3 PO2 sensor values (rebreather)
+	o2pressure_t votedpo2;            // uint16_t   2    mbar   (0-65 bar)             O2 partial pressure (as displayed by DC)
 	bearing_t bearing;                // int16_t    2  degrees  (-1 no val, 0-360 deg) compass bearing
 	uint8_t sensor[MAX_SENSORS];      // uint8_t    1  sensorID (0-255)                ID of cylinder pressure sensor
 	uint16_t cns;                     // uint16_t   1     %     (0-64k %)              cns% accumulated
diff --git a/core/libdivecomputer.c b/core/libdivecomputer.c
index 3443886b6..7f54ac079 100644
--- a/core/libdivecomputer.c
+++ b/core/libdivecomputer.c
@@ -403,6 +403,9 @@ sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
 		if (nsensor > dc->no_o2sensors)
 			dc->no_o2sensors = nsensor;
 		break;
+	case DC_SAMPLE_VOTED_PPO2:
+        sample->votedpo2.mbar = lrint(value.ppo2 * 1000);
+	    break;
 	case DC_SAMPLE_CNS:
 		sample->cns = cns = lrint(value.cns * 100);
 		break;
diff --git a/core/load-git.c b/core/load-git.c
index b42492854..1fc8fc9ba 100644
--- a/core/load-git.c
+++ b/core/load-git.c
@@ -529,9 +529,14 @@ static void parse_sample_keyvalue(void *_sample, const char *key, const char *va
 		sample->o2sensor[2].mbar = p.mbar;
 		return;
 	}
-	if (!strcmp(key, "o2pressure")) {
-		pressure_t p = get_pressure(value);
-		sample->pressure[1].mbar = p.mbar;
+    if (!strcmp(key, "o2pressure")) {
+        pressure_t p = get_pressure(value);
+        sample->pressure[1].mbar = p.mbar;
+        return;
+    }
+	if (!strcmp(key, "votedpo2")) {
+        pressure_t p = get_pressure(value);
+        sample->votedpo2.mbar = p.mbar;
 		return;
 	}
 	if (!strcmp(key, "heartbeat")) {
diff --git a/core/parse-xml.c b/core/parse-xml.c
index ff9fa2421..a583c97ef 100644
--- a/core/parse-xml.c
+++ b/core/parse-xml.c
@@ -887,6 +887,8 @@ static void try_to_fill_sample(struct sample *sample, const char *name, char *bu
 		return;
 	if (MATCH("sensor3.sample", double_to_o2pressure, &sample->o2sensor[2])) // up to 3 CCR sensors
 		return;
+	if (MATCH("votedpo2.sample", double_to_o2pressure, &sample->votedpo2)) // the voted po2
+		return;
 	if (MATCH("po2.sample", double_to_o2pressure, &sample->setpoint))
 		return;
 	if (MATCH("heartbeat", get_uint8, &sample->heartbeat))
diff --git a/core/profile.c b/core/profile.c
index 113f62845..e819cf539 100644
--- a/core/profile.c
+++ b/core/profile.c
@@ -582,9 +582,13 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer *
 		entry->cns = sample->cns;
 		if (dc->divemode == CCR || (dc->divemode == PSCR && dc->no_o2sensors)) {
 			entry->o2pressure.mbar = entry->o2setpoint.mbar = sample->setpoint.mbar;     // for rebreathers
+            if (entry->votedpo2.mbar > 0) {
+                entry->o2pressure.mbar = entry->votedpo2.mbar;
+            }
 			entry->o2sensor[0].mbar = sample->o2sensor[0].mbar; // for up to three rebreather O2 sensors
 			entry->o2sensor[1].mbar = sample->o2sensor[1].mbar;
 			entry->o2sensor[2].mbar = sample->o2sensor[2].mbar;
+			entry->votedpo2.mbar = sample->votedpo2.mbar;
 		} else {
 			entry->pressures.o2 = sample->setpoint.mbar / 1000.0;
 		}
@@ -1165,6 +1169,12 @@ void calculate_deco_information(struct deco_state *ds, struct deco_state *planne
  */
 static int calculate_ccr_po2(struct plot_data *entry, struct divecomputer *dc)
 {
+	/* If the DC reported a voted PO2/Average PO2, use that.
+	 */
+	if (entry->votedpo2.mbar > 0) {
+		return entry->votedpo2.mbar;
+	}
+
 	int sump = 0, minp = 999999, maxp = -999999;
 	int diff_limit = 100; // The limit beyond which O2 sensor differences are considered significant (default = 100 mbar)
 	int i, np = 0;
@@ -1284,6 +1294,8 @@ void fill_o2_values(struct dive *dive, struct divecomputer *dc, struct plot_info
 	}
 }
 
+// take me out
+
 #ifdef DEBUG_GAS
 /* A CCR debug function that writes the cylinder pressure and the oxygen values to the file debug_print_profiledata.dat:
  * Called in create_plot_info_new()
@@ -1301,7 +1313,7 @@ static void debug_print_profiledata(struct plot_info *pi)
 			entry = pi->entry + i;
 			fprintf(f1, "%d gas=%8d %8d ; dil=%8d %8d ; o2_sp= %d %d %d %d PO2= %f\n", i, SENSOR_PRESSURE(entry),
 				INTERPOLATED_PRESSURE(entry), O2CYLINDER_PRESSURE(entry), INTERPOLATED_O2CYLINDER_PRESSURE(entry),
-				entry->o2pressure.mbar, entry->o2sensor[0].mbar, entry->o2sensor[1].mbar, entry->o2sensor[2].mbar, entry->pressures.o2);
+				entry->o2pressure.mbar, entry->o2sensor[0].mbar, entry->o2sensor[1].mbar, entry->o2sensor[2].mbar, entry->pressures.o2, entry->votedpo2.mbar);
 		}
 		fclose(f1);
 	}
diff --git a/core/profile.h b/core/profile.h
index 58c44d955..cdc93dcac 100644
--- a/core/profile.h
+++ b/core/profile.h
@@ -46,6 +46,7 @@ struct plot_data {
 	pressure_t o2pressure;  // for rebreathers, this is consensus measured po2, or setpoint otherwise. 0 for OC.
 	pressure_t o2sensor[3]; //for rebreathers with up to 3 PO2 sensors
 	pressure_t o2setpoint;
+	pressure_t votedpo2;
 	pressure_t scr_OC_pO2;
 	double mod, ead, end, eadd;
 	velocity_t velocity;
diff --git a/core/save-git.c b/core/save-git.c
index 5d117748a..49e29f38e 100644
--- a/core/save-git.c
+++ b/core/save-git.c
@@ -285,6 +285,11 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
 		put_format(b, ":%d", sensor);
 	}
 
+	if (sample->votedpo2.mbar > 0 && sample->votedpo2.mbar != old->votedpo2.mbar) {
+        put_milli(b, " votedpo2=", sample->votedpo2.mbar, "bar");
+		old->votedpo2.mbar = sample->votedpo2.mbar;
+	}
+
 	/* the deco/ndl values are stored whenever they change */
 	if (sample->ndl.seconds != old->ndl.seconds) {
 		put_format(b, " ndl=%u:%02u", FRACTION(sample->ndl.seconds, 60));
diff --git a/core/save-xml.c b/core/save-xml.c
index 7198421e1..3f84453fa 100644
--- a/core/save-xml.c
+++ b/core/save-xml.c
@@ -281,6 +281,11 @@ static void save_sample(struct membuffer *b, struct sample *sample, struct sampl
 		old->o2sensor[2] = sample->o2sensor[2];
 	}
 
+	if (sample->votedpo2.mbar > 0 && sample->votedpo2.mbar != old->votedpo2.mbar) {
+		put_milli(b, " votedpo2='", sample->votedpo2.mbar, " bar'");
+		old->votedpo2.mbar = sample->votedpo2.mbar;
+	}
+
 	if (sample->setpoint.mbar != old->setpoint.mbar) {
 		put_milli(b, " po2='", sample->setpoint.mbar, " bar'");
 		old->setpoint = sample->setpoint;
diff --git a/libdivecomputer b/libdivecomputer
index e97a47cca..f203bb03c 160000
--- a/libdivecomputer
+++ b/libdivecomputer
@@ -1 +1 @@
-Subproject commit e97a47cca55973199715df0f818b4955e60d3a31
+Subproject commit f203bb03c85d2487db1e2be5ab6eee9ebc7f57c4
diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp
index 25bff64ea..54e93d1ec 100644
--- a/profile-widget/profilewidget2.cpp
+++ b/profile-widget/profilewidget2.cpp
@@ -111,6 +111,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent),
 	ccrsensor1GasItem(new PartialPressureGasItem()),
 	ccrsensor2GasItem(new PartialPressureGasItem()),
 	ccrsensor3GasItem(new PartialPressureGasItem()),
+    ccrsensorVotedGasItem(new PartialPressureGasItem()),
 	ocpo2GasItem(new PartialPressureGasItem()),
 #ifndef SUBSURFACE_MOBILE
 	diveCeiling(new DiveCalculatedCeiling(this)),
@@ -201,6 +202,7 @@ void ProfileWidget2::addItemsToScene()
 	scene()->addItem(ccrsensor1GasItem);
 	scene()->addItem(ccrsensor2GasItem);
 	scene()->addItem(ccrsensor3GasItem);
+    scene()->addItem(ccrsensorVotedGasItem);
 	scene()->addItem(ocpo2GasItem);
 #ifndef SUBSURFACE_MOBILE
 	scene()->addItem(toolTipItem);
@@ -319,6 +321,7 @@ void ProfileWidget2::setupItemOnScene()
 	createPPGas(ccrsensor1GasItem, DivePlotDataModel::CCRSENSOR1, CCRSENSOR1, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ccrsensor2GasItem, DivePlotDataModel::CCRSENSOR2, CCRSENSOR2, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ccrsensor3GasItem, DivePlotDataModel::CCRSENSOR3, CCRSENSOR3, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
+	createPPGas(ccrsensorVotedGasItem, DivePlotDataModel::CCRVOTEDSENSOR, CCRVOTEDSENSOR, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 	createPPGas(ocpo2GasItem, DivePlotDataModel::SCR_OC_PO2, SCR_OCPO2, PO2_ALERT, &prefs.pp_graphs.po2_threshold_min, &prefs.pp_graphs.po2_threshold_max);
 
 #undef CREATE_PP_GAS
@@ -336,6 +339,7 @@ void ProfileWidget2::setupItemOnScene()
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor1GasItem, &PartialPressureGasItem::setVisible);
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor2GasItem, &PartialPressureGasItem::setVisible);
 	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensor3GasItem, &PartialPressureGasItem::setVisible);
+	connect(SettingsObjectWrapper::instance()->techDetails, &TechnicalDetailsSettings::showCCRSensorsChanged, ccrsensorVotedGasItem, &PartialPressureGasItem::setVisible);
 
 	heartBeatAxis->setTextVisible(true);
 	heartBeatAxis->setLinesVisible(true);
@@ -605,6 +609,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 	ccrsensor1GasItem->setVisible(sensorflag);
 	ccrsensor2GasItem->setVisible(sensorflag && (currentdc->no_o2sensors > 1));
 	ccrsensor3GasItem->setVisible(sensorflag && (currentdc->no_o2sensors > 2));
+	ccrsensorVotedGasItem->setVisible(sensorflag);
 	ocpo2GasItem->setVisible((currentdc->divemode == PSCR) && prefs.show_scr_ocpo2);
 
 	/* This struct holds all the data that's about to be plotted.
@@ -713,6 +718,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 		ccrsensor1GasItem->setVisible(prefs.show_ccr_sensors);
 		ccrsensor2GasItem->setVisible(prefs.show_ccr_sensors && (currentdc->no_o2sensors > 1));
 		ccrsensor3GasItem->setVisible(prefs.show_ccr_sensors && (currentdc->no_o2sensors > 1));
+		ccrsensorVotedGasItem->setVisible(true);
 		ocpo2GasItem->setVisible((currentdc->divemode == PSCR) && prefs.show_scr_ocpo2);
 		temperatureItem->setVisible(false);
 	} else {
@@ -725,6 +731,7 @@ void ProfileWidget2::plotDive(struct dive *d, bool force, bool doClearPictures)
 		ccrsensor1GasItem->setVisible(false);
 		ccrsensor2GasItem->setVisible(false);
 		ccrsensor3GasItem->setVisible(false);
+		ccsensorVotedGasItem->setVisible(false);
 		ocpo2GasItem->setVisible(false);
 	}
 #endif
@@ -1090,6 +1097,7 @@ void ProfileWidget2::setEmptyState()
 	ccrsensor1GasItem->setVisible(false);
 	ccrsensor2GasItem->setVisible(false);
 	ccrsensor3GasItem->setVisible(false);
+	ccrsensorVotedGasItem->setVisible(false);
 	ocpo2GasItem->setVisible(false);
 #ifndef SUBSURFACE_MOBILE
 	toolTipItem->setVisible(false);
@@ -1211,6 +1219,7 @@ void ProfileWidget2::setProfileState()
 	ccrsensor1GasItem->setVisible(sensorflag);
 	ccrsensor2GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 1));
 	ccrsensor3GasItem->setVisible(sensorflag && (current_dc->no_o2sensors > 2));
+	ccrsensorVotedGasItem->setVisible(sensorflag);
 	ocpo2GasItem->setVisible(current_dive && (current_dc->divemode == PSCR) && prefs.show_scr_ocpo2);
 
 	heartBeatItem->setVisible(prefs.hrgraph);
diff --git a/profile-widget/profilewidget2.h b/profile-widget/profilewidget2.h
index 91774c9a9..6c3a8c19b 100644
--- a/profile-widget/profilewidget2.h
+++ b/profile-widget/profilewidget2.h
@@ -204,6 +204,7 @@ private:
 	PartialPressureGasItem *ccrsensor1GasItem;
 	PartialPressureGasItem *ccrsensor2GasItem;
 	PartialPressureGasItem *ccrsensor3GasItem;
+	PartialPressureGasItem *ccrsensorVotedGasItem;
 	PartialPressureGasItem *ocpo2GasItem;
 #ifndef SUBSURFACE_MOBILE
 	DiveCalculatedCeiling *diveCeiling;
diff --git a/qt-models/diveplotdatamodel.cpp b/qt-models/diveplotdatamodel.cpp
index 35490a0a3..18ac69b6b 100644
--- a/qt-models/diveplotdatamodel.cpp
+++ b/qt-models/diveplotdatamodel.cpp
@@ -61,6 +61,8 @@ QVariant DivePlotDataModel::data(const QModelIndex &index, int role) const
 			return item.o2sensor[1].mbar / 1000.0;
 		case CCRSENSOR3:
 			return item.o2sensor[2].mbar / 1000.0;
+		case CCRVOTEDSENSOR:
+			return item.votedpo2.mbar / 1000.0;
 		case SCR_OC_PO2:
 			return item.scr_OC_pO2.mbar / 1000.0;
 		case HEARTBEAT:
@@ -144,6 +146,8 @@ QVariant DivePlotDataModel::headerData(int section, Qt::Orientation orientation,
 		return tr("Sensor 2");
 	case CCRSENSOR3:
 		return tr("Sensor 3");
+	case CCRVOTEDSENSOR:
+	    return tr("Voted PO2");
 	case AMBPRESSURE:
 		return tr("Ambient pressure");
 	case HEARTBEAT:
diff --git a/qt-models/diveplotdatamodel.h b/qt-models/diveplotdatamodel.h
index 51dc44176..01d3bd28f 100644
--- a/qt-models/diveplotdatamodel.h
+++ b/qt-models/diveplotdatamodel.h
@@ -64,6 +64,7 @@ public:
 		CCRSENSOR1,
 		CCRSENSOR2,
 		CCRSENSOR3,
+		CCRVOTEDSENSOR,
 		SCR_OC_PO2,
 		HEARTBEAT,
 		AMBPRESSURE,
_______________________________________________
subsurface mailing list
[email protected]
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to