2121
2222#include <stdlib.h>
2323#include <string.h>
24+ #include <stdbool.h>
2425
2526#include <libdivecomputer/units.h>
2627
101102#define PETREL 3
102103#define TERIC 8
103104
105+ #define SENSOR_CALIBRATION_DEFAULT 2100
106+
104107#define UNDEFINED 0xFFFFFFFF
105108
106109typedef struct shearwater_predator_parser_t shearwater_predator_parser_t ;
@@ -149,6 +152,7 @@ struct shearwater_predator_parser_t {
149152 unsigned int hpccr ;
150153 unsigned int calibrated ;
151154 double calibration [3 ];
155+ bool needs_divecan_calibration_estimate ;
152156 unsigned int divemode ;
153157 unsigned int serial ;
154158 unsigned int units ;
@@ -280,6 +284,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const
280284 for (unsigned int i = 0 ; i < 3 ; ++ i ) {
281285 parser -> calibration [i ] = 0.0 ;
282286 }
287+ parser -> needs_divecan_calibration_estimate = false;
283288 parser -> units = METRIC ;
284289 parser -> density = DEF_DENSITY_SALT ;
285290 parser -> atmospheric = DEF_ATMOSPHERIC / (BAR / 1000 );
@@ -748,9 +753,17 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
748753 unsigned int base = parser -> opening [3 ] + (pnf ? 6 : 86 );
749754 parser -> calibrated = data [base ];
750755
756+ unsigned int calibration_count = 0 ;
757+ unsigned int calibration_default_count = 0 ;
751758 for (size_t i = 0 ; i < 3 ; ++ i ) {
752759 if (parser -> calibrated & (1 << i )) {
753760 unsigned int calibration = array_uint16_be (data + base + 1 + i * 2 );
761+
762+ calibration_count ++ ;
763+ if (calibration == SENSOR_CALIBRATION_DEFAULT ) {
764+ calibration_default_count ++ ;
765+ }
766+
754767 parser -> calibration [i ] = calibration / 100000.0 ;
755768 if (parser -> model == PREDATOR ) {
756769 // The Predator expects the mV output of the cells to be
@@ -759,14 +772,26 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
759772 // sensors lines up and matches the average.
760773 parser -> calibration [i ] *= 2.2 ;
761774 }
775+ }
776+ }
762777
763- static const char * name [] = {
764- "Sensor 1 calibration [bar / V]" ,
765- "Sensor 2 calibration [bar / V]" ,
766- "Sensor 3 calibration [bar / V]" ,
767- };
768- dc_field_add_string_fmt (& parser -> cache , name [i ], "%.2f" , parser -> calibration [i ] * 1000 );
769-
778+ if (calibration_count > 0 ) {
779+ if (calibration_default_count < calibration_count ) {
780+ for (size_t i = 0 ; i < 3 ; ++ i ) {
781+ if (parser -> calibrated & (1 << i )) {
782+ static const char * name [] = {
783+ "Sensor 1 calibration [bar / V]" ,
784+ "Sensor 2 calibration [bar / V]" ,
785+ "Sensor 3 calibration [bar / V]" ,
786+ };
787+ dc_field_add_string_fmt (& parser -> cache , name [i ], "%.2f" , parser -> calibration [i ] * 1000 );
788+ }
789+ }
790+ } else {
791+ // All calibrated sensors report the default calibration value
792+ // so this could be a DiveCAN controller, where the calibration values
793+ // are stored in the CCR's sensor module.
794+ parser -> needs_divecan_calibration_estimate = true;
770795 }
771796 }
772797
@@ -1041,21 +1066,65 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
10411066 if (ccr ) {
10421067 // PPO2
10431068 if ((status & PPO2_EXTERNAL ) == 0 ) {
1044- sample .ppo2 .sensor = DC_SENSOR_NONE ;
1045- sample .ppo2 .value = data [offset + pnf + 6 ] / 100.0 ;
1046- if (callback ) callback (DC_SAMPLE_PPO2 , & sample , userdata );
1069+ double calculated_ppo2 = data [offset + pnf + 6 ] / 100.0 ;
1070+
1071+ if (parser -> needs_divecan_calibration_estimate ) {
1072+ double ppo2_sum = 0.0 ;
1073+ unsigned int ppo2_count = 0 ;
1074+ if (parser -> calibrated & 0x01 ) {
1075+ ppo2_sum += data [offset + pnf + 12 ] * SENSOR_CALIBRATION_DEFAULT ;
1076+ ppo2_count ++ ;
1077+ }
1078+
1079+ if (parser -> calibrated & 0x02 ) {
1080+ ppo2_sum += data [offset + pnf + 14 ] * SENSOR_CALIBRATION_DEFAULT ;
1081+ ppo2_count ++ ;
1082+ }
10471083
1048- sample .ppo2 .sensor = 0 ;
1049- sample .ppo2 .value = data [offset + pnf + 12 ] * parser -> calibration [0 ];
1050- if (callback && (parser -> calibrated & 0x01 )) callback (DC_SAMPLE_PPO2 , & sample , userdata );
1084+ if (parser -> calibrated & 0x04 ) {
1085+ ppo2_sum += data [offset + pnf + 15 ] * SENSOR_CALIBRATION_DEFAULT ;
1086+ ppo2_count ++ ;
1087+ }
1088+
1089+ double calibration = SENSOR_CALIBRATION_DEFAULT ;
1090+ double calibration_scaling_factor = calculated_ppo2 / (ppo2_sum / ppo2_count );
1091+ if (calibration_scaling_factor < 0.95 || calibration_scaling_factor > 1.05 ) {
1092+ // The calibration scaling is significant, use it.
1093+ calibration *= calibration_scaling_factor ;
1094+ }
1095+
1096+ parser -> calibration [0 ] = calibration ;
1097+ parser -> calibration [1 ] = calibration ;
1098+ parser -> calibration [2 ] = calibration ;
1099+
1100+ dc_field_add_string_fmt (& parser -> cache , "Estimated DiveCAN calibration [bar / V]" , "%.2f" , calibration * 1000 );
1101+
1102+ parser -> needs_divecan_calibration_estimate = false;
1103+ }
10511104
1052- sample .ppo2 .sensor = 1 ;
1053- sample .ppo2 .value = data [offset + pnf + 14 ] * parser -> calibration [1 ];
1054- if (callback && (parser -> calibrated & 0x02 )) callback (DC_SAMPLE_PPO2 , & sample , userdata );
1105+ if (callback ) {
1106+ sample .ppo2 .sensor = DC_SENSOR_NONE ;
1107+ sample .ppo2 .value = calculated_ppo2 ;
1108+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
10551109
1056- sample .ppo2 .sensor = 2 ;
1057- sample .ppo2 .value = data [offset + pnf + 15 ] * parser -> calibration [2 ];
1058- if (callback && (parser -> calibrated & 0x04 )) callback (DC_SAMPLE_PPO2 , & sample , userdata );
1110+ if (parser -> calibrated & 0x01 ) {
1111+ sample .ppo2 .sensor = 0 ;
1112+ sample .ppo2 .value = data [offset + pnf + 12 ] * parser -> calibration [0 ];
1113+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1114+ }
1115+
1116+ if (parser -> calibrated & 0x02 ) {
1117+ sample .ppo2 .sensor = 1 ;
1118+ sample .ppo2 .value = data [offset + pnf + 14 ] * parser -> calibration [1 ];
1119+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1120+ }
1121+
1122+ if (parser -> calibrated & 0x04 ) {
1123+ sample .ppo2 .sensor = 2 ;
1124+ sample .ppo2 .value = data [offset + pnf + 15 ] * parser -> calibration [2 ];
1125+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1126+ }
1127+ }
10591128 }
10601129
10611130 // Setpoint
0 commit comments