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 ;
@@ -159,6 +163,12 @@ struct shearwater_predator_parser_t {
159
163
struct dc_field_cache cache ;
160
164
};
161
165
166
+ struct dc_parser_sensor_calibration_t {
167
+ double sum_ppo2 ;
168
+ double sum_calculated_ppo2 ;
169
+ unsigned int ppo2_sample_count ;
170
+ };
171
+
162
172
static dc_status_t shearwater_predator_parser_get_datetime (dc_parser_t * abstract , dc_datetime_t * datetime );
163
173
static dc_status_t shearwater_predator_parser_get_field (dc_parser_t * abstract , dc_field_type_t type , unsigned int flags , void * value );
164
174
static dc_status_t shearwater_predator_parser_samples_foreach (dc_parser_t * abstract , dc_sample_callback_t callback , void * userdata );
@@ -280,6 +290,7 @@ shearwater_common_parser_create (dc_parser_t **out, dc_context_t *context, const
280
290
for (unsigned int i = 0 ; i < 3 ; ++ i ) {
281
291
parser -> calibration [i ] = 0.0 ;
282
292
}
293
+ parser -> needs_divecan_calibration_estimate = false;
283
294
parser -> units = METRIC ;
284
295
parser -> density = DEF_DENSITY_SALT ;
285
296
parser -> atmospheric = DEF_ATMOSPHERIC / (BAR / 1000 );
@@ -412,6 +423,20 @@ add_battery_type(shearwater_predator_parser_t *parser, const unsigned char *data
412
423
}
413
424
}
414
425
426
+ static void print_calibration (shearwater_predator_parser_t * parser )
427
+ {
428
+ for (size_t i = 0 ; i < 3 ; ++ i ) {
429
+ if (parser -> calibrated & (1 << i )) {
430
+ static const char * name [] = {
431
+ "Sensor 1 calibration [bar / V]" ,
432
+ "Sensor 2 calibration [bar / V]" ,
433
+ "Sensor 3 calibration [bar / V]" ,
434
+ };
435
+ dc_field_add_string_fmt (& parser -> cache , name [i ], "%.2f" , parser -> calibration [i ] * 1000 );
436
+ }
437
+ }
438
+ }
439
+
415
440
static dc_status_t
416
441
shearwater_predator_parser_cache (shearwater_predator_parser_t * parser )
417
442
{
@@ -748,9 +773,17 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
748
773
unsigned int base = parser -> opening [3 ] + (pnf ? 6 : 86 );
749
774
parser -> calibrated = data [base ];
750
775
776
+ unsigned int calibration_count = 0 ;
777
+ unsigned int calibration_default_count = 0 ;
751
778
for (size_t i = 0 ; i < 3 ; ++ i ) {
752
779
if (parser -> calibrated & (1 << i )) {
753
780
unsigned int calibration = array_uint16_be (data + base + 1 + i * 2 );
781
+
782
+ calibration_count ++ ;
783
+ if (calibration == SENSOR_CALIBRATION_DEFAULT ) {
784
+ calibration_default_count ++ ;
785
+ }
786
+
754
787
parser -> calibration [i ] = calibration / 100000.0 ;
755
788
if (parser -> model == PREDATOR ) {
756
789
// The Predator expects the mV output of the cells to be
@@ -759,14 +792,17 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
759
792
// sensors lines up and matches the average.
760
793
parser -> calibration [i ] *= 2.2 ;
761
794
}
795
+ }
796
+ }
762
797
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
-
798
+ if (calibration_count > 0 ) {
799
+ if (calibration_default_count < calibration_count ) {
800
+ print_calibration (parser );
801
+ } else {
802
+ // All calibrated sensors report the default calibration value
803
+ // so this could be a DiveCAN controller, where the calibration values
804
+ // are stored in the CCR's sensor module.
805
+ parser -> needs_divecan_calibration_estimate = true;
770
806
}
771
807
}
772
808
@@ -858,6 +894,35 @@ shearwater_predator_parser_cache (shearwater_predator_parser_t *parser)
858
894
break ;
859
895
}
860
896
897
+ dc_status_t rc = DC_STATUS_SUCCESS ;
898
+ if (parser -> needs_divecan_calibration_estimate ) {
899
+ struct dc_parser_sensor_calibration_t data = { 0 };
900
+
901
+ rc = shearwater_predator_parser_samples_foreach (abstract , NULL , (void * )& data );
902
+
903
+ bool calibrated = false;
904
+ if (data .sum_ppo2 != 0 ) {
905
+ double calibration = data .sum_calculated_ppo2 / data .sum_ppo2 ;
906
+ if (calibration < 0.98 || calibration > 1.02 ) {
907
+ // The calibration scaling is significant, use it.
908
+ calibration *= SENSOR_CALIBRATION_DEFAULT / 100000.0 ;
909
+ parser -> calibration [0 ] = calibration ;
910
+ parser -> calibration [1 ] = calibration ;
911
+ parser -> calibration [2 ] = calibration ;
912
+
913
+ dc_field_add_string_fmt (& parser -> cache , "Estimated (DiveCAN?) sensor calibration [bar / V]" , "%.2f" , calibration * 1000 );
914
+
915
+ calibrated = true;
916
+ }
917
+ }
918
+
919
+ if (!calibrated ) {
920
+ print_calibration (parser );
921
+ }
922
+
923
+ parser -> needs_divecan_calibration_estimate = false;
924
+ }
925
+
861
926
return DC_STATUS_SUCCESS ;
862
927
}
863
928
@@ -1041,21 +1106,58 @@ shearwater_predator_parser_samples_foreach (dc_parser_t *abstract, dc_sample_cal
1041
1106
if (ccr ) {
1042
1107
// PPO2
1043
1108
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 );
1109
+ double calculated_ppo2 = data [offset + pnf + 6 ] / 100.0 ;
1047
1110
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 );
1111
+ if (parser -> needs_divecan_calibration_estimate ) {
1112
+ struct dc_parser_sensor_calibration_t * out = (struct dc_parser_sensor_calibration_t * )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
+ double ppo2_sum = 0.0 ;
1115
+ unsigned int ppo2_count = 0 ;
1116
+ if (parser -> calibrated & 0x01 ) {
1117
+ ppo2_sum += data [offset + pnf + 12 ] * SENSOR_CALIBRATION_DEFAULT / 100000.0 ;
1118
+ ppo2_count ++ ;
1119
+ }
1055
1120
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 );
1121
+ if (parser -> calibrated & 0x02 ) {
1122
+ ppo2_sum += data [offset + pnf + 14 ] * SENSOR_CALIBRATION_DEFAULT / 100000.0 ;
1123
+ ppo2_count ++ ;
1124
+ }
1125
+
1126
+ if (parser -> calibrated & 0x04 ) {
1127
+ ppo2_sum += data [offset + pnf + 15 ] * SENSOR_CALIBRATION_DEFAULT / 100000.0 ;
1128
+ ppo2_count ++ ;
1129
+ }
1130
+
1131
+ double ppo2 = ppo2_sum / ppo2_count ;
1132
+
1133
+ out -> sum_ppo2 += ppo2 ;
1134
+ out -> sum_calculated_ppo2 += calculated_ppo2 ;
1135
+ out -> ppo2_sample_count ++ ;
1136
+ }
1137
+
1138
+ if (callback ) {
1139
+ sample .ppo2 .sensor = DC_SENSOR_NONE ;
1140
+ sample .ppo2 .value = calculated_ppo2 ;
1141
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1142
+
1143
+ if (parser -> calibrated & 0x01 ) {
1144
+ sample .ppo2 .sensor = 0 ;
1145
+ sample .ppo2 .value = data [offset + pnf + 12 ] * parser -> calibration [0 ];
1146
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1147
+ }
1148
+
1149
+ if (parser -> calibrated & 0x02 ) {
1150
+ sample .ppo2 .sensor = 1 ;
1151
+ sample .ppo2 .value = data [offset + pnf + 14 ] * parser -> calibration [1 ];
1152
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1153
+ }
1154
+
1155
+ if (parser -> calibrated & 0x04 ) {
1156
+ sample .ppo2 .sensor = 2 ;
1157
+ sample .ppo2 .value = data [offset + pnf + 15 ] * parser -> calibration [2 ];
1158
+ callback (DC_SAMPLE_PPO2 , & sample , userdata );
1159
+ }
1160
+ }
1059
1161
}
1060
1162
1061
1163
// Setpoint
0 commit comments