comparison Discovery/Src/tCCR.c @ 634:7c73f066cd16

Enable sensor check for Analog PPO2 mode: Checks which may trigger a fallback warning were not activated in previous versions. Beside enabling the checks the test logic has been changed. Before the change an avarage was build automatically using the remaining both sensors if one sensor failed. The scenario that also one of the remaining sensors may be out of bounds was not covered. The new implementation allows an out of bounds detection for all sensors in parallel. In that special case the last valid value will be used until the diver takes action (Fallback warning)
author Ideenmodellierer
date Wed, 24 Feb 2021 19:18:26 +0100
parents 64bf41faab83
children 66c8a4ff9fc4
comparison
equal deleted inserted replaced
633:68d95049f11a 634:7c73f066cd16
32 #include "ostc.h" 32 #include "ostc.h"
33 #include "data_central.h" 33 #include "data_central.h"
34 #include "data_exchange.h" 34 #include "data_exchange.h"
35 #include "check_warning.h" 35 #include "check_warning.h"
36 #include "configuration.h" 36 #include "configuration.h"
37 #include <math.h>
37 38
38 /* Private types -------------------------------------------------------------*/ 39 /* Private types -------------------------------------------------------------*/
39 typedef struct 40 typedef struct
40 { 41 {
41 uint8_t hud_firmwareVersion; 42 uint8_t hud_firmwareVersion;
45 uint8_t temp1; 46 uint8_t temp1;
46 uint16_t battery_voltage_mV; 47 uint16_t battery_voltage_mV;
47 uint16_t checksum; 48 uint16_t checksum;
48 } SIrLink; 49 } SIrLink;
49 50
51 typedef enum
52 {
53 sensorOK = 0,
54 sensorSuspect,
55 SensorOutOfBounds
56 } sensorTrustState_t;
57
58
50 #define HUD_BABBLING_IDIOT (30u) /* 30 Bytes received without break */ 59 #define HUD_BABBLING_IDIOT (30u) /* 30 Bytes received without break */
51 #define HUD_RX_FRAME_LENGTH (15u) /* Length of a HUD data frame */ 60 #define HUD_RX_FRAME_LENGTH (15u) /* Length of a HUD data frame */
52 #define HUD_RX_FRAME_BREAK_MS (100u) /* Time used to detect a gap between two byte receptions => frame start */ 61 #define HUD_RX_FRAME_BREAK_MS (100u) /* Time used to detect a gap between two byte receptions => frame start */
53 #define HUD_RX_START_DELAY_MS (500u) /* Delay for start of RX function to avoid start of reception while a transmission is ongoing. */ 62 #define HUD_RX_START_DELAY_MS (500u) /* Delay for start of RX function to avoid start of reception while a transmission is ongoing. */
54 /* Based on an assumed cycle time by the sensor of 1 second. Started at time of last RX */ 63 /* Based on an assumed cycle time by the sensor of 1 second. Started at time of last RX */
55 64
56 #define BOTTLE_SENSOR_TIMEOUT (6000u) /* signal pressure budget as not received after 10 minutes (6000 * 100ms) */ 65 #define BOTTLE_SENSOR_TIMEOUT (6000u) /* signal pressure budget as not received after 10 minutes (6000 * 100ms) */
57 66
67 #define MAX_SENSOR_COMPARE_DEVIATION (0.15f) /* max deviation between two sensors allowed before their results are rated as suspect */
68
58 /* Private variables ---------------------------------------------------------*/ 69 /* Private variables ---------------------------------------------------------*/
59 static SIrLink receiveHUD[2]; 70 static SIrLink receiveHUD[2];
60 static uint8_t boolHUDdata = 0; 71 static uint8_t boolHUDdata = 0;
61 static uint8_t data_old__lost_connection_to_HUD = 1; 72 static uint8_t data_old__lost_connection_to_HUD = 1;
62 73
130 141
131 void test_O2_sensor_values_outOfBounds(int8_t * outOfBouds1, int8_t * outOfBouds2, int8_t * outOfBouds3) 142 void test_O2_sensor_values_outOfBounds(int8_t * outOfBouds1, int8_t * outOfBouds2, int8_t * outOfBouds3)
132 { 143 {
133 uint8_t sensorNotActiveBinary; 144 uint8_t sensorNotActiveBinary;
134 uint8_t sensorActive[3]; 145 uint8_t sensorActive[3];
146 sensorTrustState_t sensorState[3];
147 uint8_t index;
148
135 149
136 // test1: user deactivation 150 // test1: user deactivation
137 sensorNotActiveBinary = stateUsed->diveSettings.ppo2sensors_deactivated; 151 sensorNotActiveBinary = stateUsed->diveSettings.ppo2sensors_deactivated;
138 152
139 for(int i=0;i<3;i++) 153 for(int i=0;i<3;i++)
152 } 166 }
153 167
154 // test2: mV of remaining sensors 168 // test2: mV of remaining sensors
155 for(int i=0;i<3;i++) 169 for(int i=0;i<3;i++)
156 { 170 {
171 sensorState[i] = sensorOK;
172
157 if(sensorActive[i]) 173 if(sensorActive[i])
158 { 174 {
159 if( (stateUsed->lifeData.sensorVoltage_mV[i] < 8) || 175 if( (stateUsed->lifeData.sensorVoltage_mV[i] < 8) ||
160 (stateUsed->lifeData.sensorVoltage_mV[i] > 250)) 176 (stateUsed->lifeData.sensorVoltage_mV[i] > 250))
161 { 177 {
194 if(!sensorActive[2]) 210 if(!sensorActive[2])
195 *outOfBouds3 = 1; 211 *outOfBouds3 = 1;
196 } 212 }
197 else 213 else
198 { 214 {
199 uint8_t sensor_id_ordered[3]; 215 /* Check two or more of Three */
200 float difference[2]; 216 /* compare every sensor with each other. If there is only one mismatch the value might be OK. In case both comparisons fail the sensor is out of bounds */
201 217 if(fabsf(stateUsed->lifeData.ppO2Sensor_bar[0] - stateUsed->lifeData.ppO2Sensor_bar[1]) > MAX_SENSOR_COMPARE_DEVIATION)
202 if((stateUsed->lifeData.ppO2Sensor_bar[1] > stateUsed->lifeData.ppO2Sensor_bar[0])) 218 {
203 { 219 sensorState[0]++;
204 sensor_id_ordered[0] = 0; 220 sensorState[1]++;
205 sensor_id_ordered[1] = 1; 221 }
206 } 222 if(fabsf(stateUsed->lifeData.ppO2Sensor_bar[0] - stateUsed->lifeData.ppO2Sensor_bar[2]) > MAX_SENSOR_COMPARE_DEVIATION)
207 else 223 {
208 { 224 sensorState[0]++;
209 sensor_id_ordered[0] = 1; 225 sensorState[2]++;
210 sensor_id_ordered[1] = 0; 226 }
211 } 227 if(fabsf(stateUsed->lifeData.ppO2Sensor_bar[1] - stateUsed->lifeData.ppO2Sensor_bar[2]) > MAX_SENSOR_COMPARE_DEVIATION)
212 if(stateUsed->lifeData.ppO2Sensor_bar[2] > stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[1]]) 228 {
213 { 229 sensorState[1]++;
214 sensor_id_ordered[2] = 2; 230 sensorState[2]++;
215 } 231 }
216 else 232 for(index = 0; index < 3; index++)
217 { 233 {
218 sensor_id_ordered[2] = sensor_id_ordered[1]; 234 if(sensorState[index] == SensorOutOfBounds)
219 if(stateUsed->lifeData.ppO2Sensor_bar[2] > stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[0]]) 235 {
220 { 236 switch(index)
221 sensor_id_ordered[1] = 2; 237 {
222 } 238 case 0:
223 else 239 *outOfBouds1 = 1;
224 { 240 break;
225 sensor_id_ordered[1] = sensor_id_ordered[0]; 241 case 1:
226 sensor_id_ordered[0] = 2; 242 *outOfBouds2 = 1;
227 } 243 break;
228 } 244 case 2:
229 245 *outOfBouds3 = 1;
230 difference[0] = stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[1]]- stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[0]]; 246 break;
231 difference[1] = stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[2]]- stateUsed->lifeData.ppO2Sensor_bar[sensor_id_ordered[1]]; 247 default:
232 248 break;
233 if((difference[0] > difference[1]) && (difference[0] > 0.15)) /* was 15cBar ==> 0.15 bar */ 249 }
234 { 250 }
235 switch(sensor_id_ordered[0]) 251 }
236 { 252 }
237 case 0:
238 *outOfBouds1 = 1;
239 break;
240 case 1:
241 *outOfBouds2 = 1;
242 break;
243 case 2:
244 *outOfBouds3 = 1;
245 break;
246 }
247 }
248 else
249 if((difference[0] < difference[1]) && (difference[1] > 0.15))
250 {
251 switch(sensor_id_ordered[2])
252 {
253 case 0:
254 *outOfBouds1 = 1;
255 break;
256 case 1:
257 *outOfBouds2 = 1;
258 break;
259 case 2:
260 *outOfBouds3 = 1;
261 break;
262 }
263 }
264 }
265
266 } 253 }
267 254
268 255
269 uint8_t get_ppO2SensorWeightedResult_cbar(void) 256 uint8_t get_ppO2SensorWeightedResult_cbar(void)
270 { 257 {
258 static uint8_t lastValidValue = 0;
271 int8_t sensorOutOfBound[3]; 259 int8_t sensorOutOfBound[3];
272 uint16_t result = 0; 260 uint16_t result = 0;
273 uint8_t count = 0; 261 uint8_t count = 0;
274 uint8_t retVal = 0; 262 uint8_t retVal = 0;
275 263
281 { 269 {
282 result += stateUsed->lifeData.ppO2Sensor_bar[i] * 100.0; /* convert centibar used by HUB */ 270 result += stateUsed->lifeData.ppO2Sensor_bar[i] * 100.0; /* convert centibar used by HUB */
283 count++; 271 count++;
284 } 272 }
285 } 273 }
286 if(count == 0) // all sensors out of bounds! 274 if(count == 0) /* all sensors out of bounds! => return last valid value as workaround till diver takes action */
287 { 275 {
288 set_warning_fallback(); 276 set_warning_fallback();
277 retVal = lastValidValue;
289 } 278 }
290 else 279 else
291 { 280 {
292 retVal = (uint8_t)(result / count); 281 retVal = (uint8_t)(result / count);
282 lastValidValue = retVal;
293 } 283 }
294 return retVal; 284 return retVal;
295 } 285 }
296 286
297 287