21
21
22
22
#include <stdlib.h>
23
23
#include <string.h>
24
+ #include <stdbool.h>
24
25
25
26
#include <libdivecomputer/units.h>
26
27
101
102
#define PETREL 3
102
103
#define TERIC 8
103
104
105
+ #define SENSOR_CALIBRATION_DEFAULT 2100
106
+
104
107
#define UNDEFINED 0xFFFFFFFF
105
108
106
109
typedef struct shearwater_predator_parser_t shearwater_predator_parser_t ;
@@ -149,6 +152,7 @@ struct shearwater_predator_parser_t {
149
152
unsigned int hpccr ;
150
153
unsigned int calibrated ;
151
154
double calibration [3 ];
155
+ bool needs_divecan_calibration_estimate ;
152
156
unsigned int divemode ;
153
157
unsigned int serial ;
154
158
unsigned int units ;
@@ -280,6 +284,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const
280
284
for (unsigned int i = 0 ; i < 3 ; ++ i ) {
281
285
parser -> calibration [i ] = 0.0 ;
282
286
}
287
+ parser -> needs_divecan_calibration_estimate = false;
283
288
parser -> units = METRIC ;
284
289
parser -> density = DEF_DENSITY_SALT ;
285
290
parser -> atmospheric = DEF_ATMOSPHERIC / (BAR / 1000 );
@@ -748,9 +753,17 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
748
753
unsigned int base = parser -> opening [3 ] + (pnf ? 6 : 86 );
749
754
parser -> calibrated = data [base ];
750
755
756
+ unsigned int calibration_count = 0 ;
757
+ unsigned int calibration_default_count = 0 ;
751
758
for (size_t i = 0 ; i < 3 ; ++ i ) {
752
759
if (parser -> calibrated & (1 << i )) {
753
760
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
+
754
767
parser -> calibration [i ] = calibration / 100000.0 ;
755
768
if (parser -> model == PREDATOR ) {
756
769
// The Predator expects the mV output of the cells to be
@@ -759,14 +772,26 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
759
772
// sensors lines up and matches the average.
760
773
parser -> calibration [i ] *= 2.2 ;
761
774
}
775
+ }
776
+ }
762
777
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;
770
795
}
771
796
}
772
797
@@ -858,6 +883,10 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
858
883
break ;
859
884
}
860
885
886
+ if (parser -> needs_divecan_calibration_estimate ) {
887
+ return shearwater_predator_parser_samples_foreach (abstract , NULL , NULL );
888
+ }
889
+
861
890
return DC_STATUS_SUCCESS ;
862
891
}
863
892
@@ -1041,21 +1070,65 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
1041
1070
if (ccr ) {
1042
1071
// PPO2
1043
1072
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 );
1073
+ double calculated_ppo2 = data [offset + pnf + 6 ] / 100.0 ;
1074
+
1075
+ if (parser -> needs_divecan_calibration_estimate ) {
1076
+ double ppo2_sum = 0.0 ;
1077
+ unsigned int ppo2_count = 0 ;
1078
+ if (parser -> calibrated & 0x01 ) {
1079
+ ppo2_sum += data [offset + pnf + 12 ] * SENSOR_CALIBRATION_DEFAULT ;
1080
+ ppo2_count ++ ;
1081
+ }
1082
+
1083
+ if (parser -> calibrated & 0x02 ) {
1084
+ ppo2_sum += data [offset + pnf + 14 ] * SENSOR_CALIBRATION_DEFAULT ;
1085
+ ppo2_count ++ ;
1086
+ }
1087
+
1088
+ if (parser -> calibrated & 0x04 ) {
1089
+ ppo2_sum += data [offset + pnf + 15 ] * SENSOR_CALIBRATION_DEFAULT ;
1090
+ ppo2_count ++ ;
1091
+ }
1092
+
1093
+ double calibration = SENSOR_CALIBRATION_DEFAULT ;
1094
+ double calibration_scaling_factor = calculated_ppo2 / (ppo2_sum / ppo2_count );
1095
+ if (calibration_scaling_factor < 0.95 || calibration_scaling_factor > 1.05 ) {
1096
+ // The calibration scaling is significant, use it.
1097
+ calibration *= calibration_scaling_factor ;
1098
+ }
1099
+
1100
+ parser -> calibration [0 ] = calibration ;
1101
+ parser -> calibration [1 ] = calibration ;
1102
+ parser -> calibration [2 ] = calibration ;
1103
+
1104
+ dc_field_add_string_fmt (& parser -> cache , "Estimated DiveCAN calibration [bar / V]" , "%.2f" , calibration * 1000 );
1047
1105
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 );
1106
+ parser -> needs_divecan_calibration_estimate = false;
1107
+ }
1108
+
1109
+ if (callback ) {
1110
+ sample .ppo2 .sensor = DC_SENSOR_NONE ;
1111
+ sample .ppo2 .value = calculated_ppo2 ;
1112
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1051
1113
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 );
1114
+ if (parser -> calibrated & 0x01 ) {
1115
+ sample .ppo2 .sensor = 0 ;
1116
+ sample .ppo2 .value = data [offset + pnf + 12 ] * parser -> calibration [0 ];
1117
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1118
+ }
1055
1119
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 );
1120
+ if (parser -> calibrated & 0x02 ) {
1121
+ sample .ppo2 .sensor = 1 ;
1122
+ sample .ppo2 .value = data [offset + pnf + 14 ] * parser -> calibration [1 ];
1123
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1124
+ }
1125
+
1126
+ if (parser -> calibrated & 0x04 ) {
1127
+ sample .ppo2 .sensor = 2 ;
1128
+ sample .ppo2 .value = data [offset + pnf + 15 ] * parser -> calibration [2 ];
1129
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1130
+ }
1131
+ }
1059
1132
}
1060
1133
1061
1134
// Setpoint
0 commit comments