38
|
1 /**
|
|
2 ******************************************************************************
|
|
3 * @file check_warning.c
|
|
4 * @author heinrichs weikamp gmbh
|
|
5 * @date 17-Nov-2014
|
|
6 * @version V0.0.1
|
|
7 * @since 17-Nov-2014
|
|
8 * @brief check and set warnings for warnings
|
|
9 *
|
|
10 @verbatim
|
|
11 ==============================================================================
|
|
12 ##### How to use #####
|
|
13 ==============================================================================
|
|
14 OSTC3 Warnings:
|
|
15 niedriger Batteriezustand (
|
|
16 zu hoher oder zu niedriger Sauerstoffpartialdruck (ppO2) 0.2 - 1.6
|
|
17 zu hoher CNS (Gefahr der Sauerstoffvergiftung) 90%
|
|
18 zu hohe Gradientenfaktoren 90 - 90
|
|
19 Missachtung der Dekostopps (der �berschrittene Dekostopp wird rot angezeigt) 0 m
|
|
20 zu hohe Aufstiegsgeschwindigkeit 30 m/min
|
|
21 aGF-Warnung: die Berechnung der Dekompression wird �ber alternative GF-Werte durchgef�hrt
|
|
22 Fallback-Warnung bei ausgefallenem Sensor
|
|
23
|
|
24 @endverbatim
|
|
25 ******************************************************************************
|
|
26 * @attention
|
|
27 *
|
|
28 * <h2><center>© COPYRIGHT(c) 2014 heinrichs weikamp</center></h2>
|
|
29 *
|
|
30 ******************************************************************************
|
|
31 */
|
|
32
|
|
33 /* Includes ------------------------------------------------------------------*/
|
|
34
|
|
35 #include "data_exchange.h"
|
|
36 #include "check_warning.h"
|
|
37 #include "settings.h"
|
|
38 #include "decom.h"
|
|
39 #include "tCCR.h"
|
|
40
|
|
41 /* Private variables wit access ----------------------------------------------*/
|
|
42 uint8_t betterGasId = 0;
|
|
43 uint8_t betterSetpointId = 0;
|
|
44 int8_t fallback = 0;
|
|
45
|
|
46 /* Private function prototypes -----------------------------------------------*/
|
|
47 int8_t check_fallback(SDiveState * pDiveState);
|
|
48 int8_t check_ppO2(SDiveState * pDiveState);
|
|
49 int8_t check_O2_sensors(SDiveState * pDiveState);
|
|
50 int8_t check_CNS(SDiveState * pDiveState);
|
|
51 int8_t check_Deco(SDiveState * pDiveState);
|
|
52 int8_t check_AscentRate(SDiveState * pDiveState);
|
|
53 int8_t check_aGF(SDiveState * pDiveState);
|
|
54 int8_t check_BetterGas(SDiveState * pDiveState);
|
|
55 int8_t check_BetterSetpoint(SDiveState * pDiveState);
|
|
56 int8_t check_Battery(SDiveState * pDiveState);
|
|
57
|
|
58 int8_t check_helper_same_oxygen_and_helium_content(SGasLine * gas1, SGasLine * gas2);
|
|
59
|
|
60 /* Exported functions --------------------------------------------------------*/
|
|
61
|
|
62 void check_warning(void)
|
|
63 {
|
|
64 SDiveState * pDiveState;
|
|
65
|
|
66 if(stateUsed == stateRealGetPointer())
|
|
67 pDiveState = stateRealGetPointerWrite();
|
|
68 else
|
|
69 pDiveState = stateSimGetPointerWrite();
|
|
70
|
|
71 check_warning2(pDiveState);
|
|
72 }
|
|
73
|
|
74
|
|
75 void check_warning2(SDiveState * pDiveState)
|
|
76 {
|
|
77 pDiveState->warnings.numWarnings = 0;
|
|
78
|
|
79 pDiveState->warnings.numWarnings += check_aGF(pDiveState);
|
|
80 pDiveState->warnings.numWarnings += check_AscentRate(pDiveState);
|
|
81 pDiveState->warnings.numWarnings += check_CNS(pDiveState);
|
|
82 pDiveState->warnings.numWarnings += check_Deco(pDiveState);
|
|
83 pDiveState->warnings.numWarnings += check_ppO2(pDiveState);
|
|
84 pDiveState->warnings.numWarnings += check_O2_sensors(pDiveState);
|
|
85 pDiveState->warnings.numWarnings += check_BetterGas(pDiveState);
|
|
86 pDiveState->warnings.numWarnings += check_BetterSetpoint(pDiveState);
|
|
87 pDiveState->warnings.numWarnings += check_Battery(pDiveState);
|
|
88 pDiveState->warnings.numWarnings += check_fallback(pDiveState);
|
|
89 }
|
|
90
|
|
91
|
|
92 void set_warning_fallback(void)
|
|
93 {
|
|
94 fallback = 1;
|
|
95 }
|
|
96
|
|
97
|
|
98 void clear_warning_fallback(void)
|
|
99 {
|
|
100 fallback = 0;
|
|
101 }
|
|
102
|
|
103
|
|
104 uint8_t actualBetterGasId(void)
|
|
105 {
|
|
106 return betterGasId;
|
|
107 }
|
|
108
|
|
109
|
|
110 uint8_t actualBetterSetpointId(void)
|
|
111 {
|
|
112 return betterSetpointId;
|
|
113 }
|
|
114
|
|
115
|
|
116 uint8_t actualLeftMaxDepth(const SDiveState * pDiveState)
|
|
117 {
|
|
118 if(pDiveState->lifeData.depth_meter > (pDiveState->lifeData.max_depth_meter - 3.0f))
|
|
119 return 0;
|
|
120 else
|
|
121 return 1;
|
|
122 }
|
|
123
|
|
124
|
|
125 /* Private functions ---------------------------------------------------------*/
|
|
126 int8_t check_fallback(SDiveState * pDiveState)
|
|
127 {
|
|
128 if(fallback && ((pDiveState->mode != MODE_DIVE) || (pDiveState->diveSettings.diveMode != DIVEMODE_CCR)))
|
|
129 fallback = 0;
|
|
130
|
|
131 pDiveState->warnings.fallback = fallback;
|
|
132 return pDiveState->warnings.fallback;
|
|
133 }
|
|
134
|
|
135
|
|
136 int8_t check_ppO2(SDiveState * pDiveState)
|
|
137 {
|
|
138 if(pDiveState->mode != MODE_DIVE)
|
|
139 {
|
|
140 pDiveState->warnings.ppO2Low = 0;
|
|
141 pDiveState->warnings.ppO2High = 0;
|
|
142 return 0;
|
|
143 }
|
|
144
|
|
145 uint8_t localPPO2, testPPO2high;
|
|
146
|
|
147 if(pDiveState->lifeData.ppO2 < 0)
|
|
148 localPPO2 = 0;
|
|
149 else
|
|
150 if(pDiveState->lifeData.ppO2 >= 2.5f)
|
|
151 localPPO2 = 255;
|
|
152 else
|
|
153 localPPO2 = (uint8_t)(pDiveState->lifeData.ppO2 * 100);
|
|
154
|
|
155 if((localPPO2 + 1) <= settingsGetPointer()->ppO2_min)
|
|
156 pDiveState->warnings.ppO2Low = 1;
|
|
157 else
|
|
158 pDiveState->warnings.ppO2Low = 0;
|
|
159
|
|
160 if(actualLeftMaxDepth(pDiveState))
|
|
161 testPPO2high = settingsGetPointer()->ppO2_max_deco;
|
|
162 else
|
|
163 testPPO2high = settingsGetPointer()->ppO2_max_std;
|
|
164
|
|
165 if(localPPO2 >= (testPPO2high + 1))
|
|
166 pDiveState->warnings.ppO2High = 1;
|
|
167 else
|
|
168 pDiveState->warnings.ppO2High = 0;
|
|
169
|
|
170 return pDiveState->warnings.ppO2Low + pDiveState->warnings.ppO2High;
|
|
171 }
|
|
172
|
|
173
|
|
174 int8_t check_O2_sensors(SDiveState * pDiveState)
|
|
175 {
|
|
176 pDiveState->warnings.sensorLinkLost = 0;
|
|
177 pDiveState->warnings.sensorOutOfBounds[0] = 0;
|
|
178 pDiveState->warnings.sensorOutOfBounds[1] = 0;
|
|
179 pDiveState->warnings.sensorOutOfBounds[2] = 0;
|
|
180
|
|
181 if((pDiveState->diveSettings.diveMode == DIVEMODE_CCR) && (pDiveState->diveSettings.CCR_Mode == CCRMODE_Sensors))
|
|
182 {
|
|
183 if(!get_HUD_battery_voltage_V())
|
|
184 pDiveState->warnings.sensorLinkLost = 1;
|
|
185
|
|
186 test_HUD_sensor_values_outOfBounds(&pDiveState->warnings.sensorOutOfBounds[0], &pDiveState->warnings.sensorOutOfBounds[1], &pDiveState->warnings.sensorOutOfBounds[2]);
|
|
187
|
|
188 }
|
|
189 return pDiveState->warnings.sensorLinkLost
|
|
190 + pDiveState->warnings.sensorOutOfBounds[0]
|
|
191 + pDiveState->warnings.sensorOutOfBounds[1]
|
|
192 + pDiveState->warnings.sensorOutOfBounds[2];
|
|
193 }
|
|
194
|
|
195
|
|
196 int8_t check_BetterGas(SDiveState * pDiveState)
|
|
197 {
|
|
198 if(stateUsed->mode != MODE_DIVE)
|
|
199 {
|
|
200 pDiveState->warnings.betterGas = 0;
|
|
201 betterGasId = 0;
|
|
202 return 0;
|
|
203 }
|
|
204
|
|
205 uint8_t gasIdOffset;
|
|
206 uint8_t bestGasDepth, betterGasIdLocal;
|
|
207
|
|
208 SLifeData* pLifeData = &pDiveState->lifeData;
|
|
209 SDiveSettings* pDiveSettings = &pDiveState->diveSettings;
|
|
210
|
|
211 pDiveState->warnings.betterGas = 0;
|
|
212 betterGasId = 0;
|
|
213 betterGasIdLocal = pLifeData->actualGas.GasIdInSettings;
|
|
214 bestGasDepth = 255;
|
|
215
|
|
216 if(pDiveSettings->diveMode == DIVEMODE_CCR)
|
|
217 gasIdOffset = NUM_OFFSET_DILUENT;
|
|
218 else
|
|
219 gasIdOffset = 0;
|
|
220
|
|
221 /* life data is float, gas data is uint8 */
|
|
222 if(actualLeftMaxDepth(pDiveState)) /* deco gases */
|
|
223 {
|
|
224 for(int i=1+gasIdOffset; i<= 5+gasIdOffset; i++)
|
|
225 {
|
|
226 if( (pDiveSettings->gas[i].note.ub.active)
|
|
227 && (pDiveSettings->gas[i].note.ub.deco)
|
|
228 && (pDiveSettings->gas[i].depth_meter)
|
|
229 && (pDiveSettings->gas[i].depth_meter >= (pLifeData->depth_meter - 0.01f ))
|
|
230 && (pDiveSettings->gas[i].depth_meter <= bestGasDepth)
|
|
231 )
|
|
232 {
|
|
233 betterGasIdLocal = i;
|
|
234 bestGasDepth = pDiveSettings->gas[i].depth_meter;
|
|
235 }
|
|
236 }
|
|
237
|
|
238 if(betterGasIdLocal != pLifeData->actualGas.GasIdInSettings)
|
|
239 {
|
|
240 if(!check_helper_same_oxygen_and_helium_content(&pDiveSettings->gas[betterGasIdLocal], &pDiveSettings->gas[pLifeData->actualGas.GasIdInSettings]))
|
|
241 {
|
|
242 betterGasId = betterGasIdLocal;
|
|
243 pDiveState->warnings.betterGas = 1;
|
|
244 }
|
|
245 }
|
|
246 }
|
|
247 else /* travel gases */
|
|
248 {
|
|
249 bestGasDepth = 0;
|
|
250 //check for travalgas
|
|
251 for(int i=1+gasIdOffset; i<= 5+gasIdOffset; i++)
|
|
252 {
|
|
253 if( (pDiveSettings->gas[i].note.ub.active)
|
|
254 && (pDiveSettings->gas[i].note.ub.travel)
|
|
255 && (pDiveSettings->gas[i].depth_meter_travel)
|
|
256 && (pDiveSettings->gas[i].depth_meter_travel <= (pLifeData->depth_meter + 0.01f ))
|
|
257 && (pDiveSettings->gas[i].depth_meter_travel >= bestGasDepth)
|
|
258 )
|
|
259 {
|
|
260 betterGasIdLocal = i;
|
|
261 bestGasDepth = pDiveSettings->gas[i].depth_meter;
|
|
262 }
|
|
263 }
|
|
264
|
|
265 if(betterGasIdLocal != pLifeData->actualGas.GasIdInSettings)
|
|
266 {
|
|
267 if(!check_helper_same_oxygen_and_helium_content(&pDiveSettings->gas[betterGasIdLocal], &pDiveSettings->gas[pLifeData->actualGas.GasIdInSettings]))
|
|
268 {
|
|
269 betterGasId = betterGasIdLocal;
|
|
270 pDiveState->warnings.betterGas = 1;
|
|
271 }
|
|
272 }
|
|
273 }
|
|
274 return pDiveState->warnings.betterGas;
|
|
275 }
|
|
276
|
|
277 /* check for better travel!!! setpoint hw 151210
|
|
278 */
|
|
279 int8_t check_BetterSetpoint(SDiveState * pDiveState)
|
|
280 {
|
|
281 pDiveState->warnings.betterSetpoint = 0;
|
|
282 betterSetpointId = 0;
|
|
283
|
|
284 if((stateUsed->mode != MODE_DIVE) || (pDiveState->diveSettings.diveMode != DIVEMODE_CCR) || (pDiveState->diveSettings.CCR_Mode != CCRMODE_FixedSetpoint))
|
|
285 {
|
|
286 return 0;
|
|
287 }
|
|
288
|
|
289 uint8_t bestSetpointDepth = 0; // travel the deeper, the better
|
|
290 uint8_t betterSetpointIdLocal = 0; // nothing better
|
|
291
|
|
292 if(!actualLeftMaxDepth(pDiveState)) /* travel gases */
|
|
293 {
|
|
294 for(int i=1; i<=NUM_GASES; i++)
|
|
295 {
|
|
296 if( (pDiveState->diveSettings.setpoint[i].note.ub.active)
|
|
297 && (pDiveState->diveSettings.setpoint[i].depth_meter)
|
|
298 && (pDiveState->diveSettings.setpoint[i].depth_meter <= ( pDiveState->lifeData.depth_meter + 0.01f ))
|
|
299 && (pDiveState->diveSettings.setpoint[i].depth_meter >= bestSetpointDepth)
|
|
300 )
|
|
301 {
|
|
302 betterSetpointIdLocal = i;
|
|
303 bestSetpointDepth = pDiveState->diveSettings.setpoint[i].depth_meter;
|
|
304 }
|
|
305 }
|
|
306 if((betterSetpointIdLocal) && (pDiveState->diveSettings.setpoint[betterSetpointIdLocal].setpoint_cbar != pDiveState->lifeData.actualGas.setPoint_cbar))
|
|
307 {
|
|
308 betterSetpointId = betterSetpointIdLocal;
|
|
309 pDiveState->warnings.betterSetpoint = 1;
|
|
310 }
|
|
311 }
|
|
312 return pDiveState->warnings.betterSetpoint;
|
|
313 }
|
|
314
|
|
315
|
|
316 /* hw 151030
|
|
317 */
|
|
318 int8_t check_helper_same_oxygen_and_helium_content(SGasLine * gas1, SGasLine * gas2)
|
|
319 {
|
|
320 if(gas1->helium_percentage != gas2->helium_percentage)
|
|
321 return 0;
|
|
322 else
|
|
323 if(gas1->oxygen_percentage != gas2->oxygen_percentage)
|
|
324 return 0;
|
|
325 else
|
|
326 return 1;
|
|
327 }
|
|
328
|
|
329
|
|
330 int8_t check_CNS(SDiveState * pDiveState)
|
|
331 {
|
|
332 if(stateUsed->mode != MODE_DIVE)
|
|
333 {
|
|
334 pDiveState->warnings.cnsHigh = 0;
|
|
335 return 0;
|
|
336 }
|
|
337
|
|
338 if(pDiveState->lifeData.cns >= (float)(settingsGetPointer()->CNS_max))
|
|
339 pDiveState->warnings.cnsHigh = 1;
|
|
340 else
|
|
341 pDiveState->warnings.cnsHigh = 0;
|
|
342 return pDiveState->warnings.cnsHigh;
|
|
343 }
|
|
344
|
|
345
|
|
346 int8_t check_Battery(SDiveState * pDiveState)
|
|
347 {
|
|
348 if(pDiveState->lifeData.battery_charge < 10)
|
|
349 pDiveState->warnings.lowBattery = 1;
|
|
350 else
|
|
351 pDiveState->warnings.lowBattery = 0;
|
|
352
|
|
353 return pDiveState->warnings.lowBattery;
|
|
354 }
|
|
355
|
|
356
|
|
357 int8_t check_Deco(SDiveState * pDiveState)
|
|
358 {
|
|
359 if(stateUsed->mode != MODE_DIVE)
|
|
360 {
|
|
361 pDiveState->warnings.decoMissed = 0;
|
|
362 return 0;
|
|
363 }
|
|
364
|
|
365 uint8_t depthNext = decom_get_actual_deco_stop(pDiveState);
|
|
366
|
|
367 if(!depthNext)
|
|
368 pDiveState->warnings.decoMissed = 0;
|
|
369 else
|
|
370 if(pDiveState->lifeData.depth_meter + 0.1f < (float)depthNext)
|
|
371 pDiveState->warnings.decoMissed = 1;
|
|
372 else
|
|
373 pDiveState->warnings.decoMissed = 0;
|
|
374
|
|
375 return pDiveState->warnings.decoMissed;
|
|
376 }
|
|
377
|
|
378
|
|
379 int8_t check_AscentRate(SDiveState * pDiveState)
|
|
380 {
|
|
381 if(stateUsed->mode != MODE_DIVE)
|
|
382 {
|
|
383 pDiveState->warnings.ascentRateHigh = 0;
|
|
384 return 0;
|
|
385 }
|
|
386
|
|
387 float warnAscentRateFloat;
|
|
388
|
|
389 warnAscentRateFloat = (float)(settingsGetPointer()->ascent_MeterPerMinute_max);
|
|
390
|
|
391 if(pDiveState->lifeData.ascent_rate_meter_per_min >= warnAscentRateFloat)
|
|
392 pDiveState->warnings.ascentRateHigh = 1;
|
|
393 else
|
|
394 pDiveState->warnings.ascentRateHigh = 0;
|
|
395 return pDiveState->warnings.ascentRateHigh;
|
|
396 }
|
|
397
|
|
398
|
|
399 int8_t check_aGF(SDiveState * pDiveState)
|
|
400 {
|
|
401 if(stateUsed->mode != MODE_DIVE)
|
|
402 {
|
|
403 pDiveState->warnings.aGf = 0;
|
|
404 return 0;
|
|
405 }
|
|
406
|
|
407 pDiveState->warnings.aGf = 0;
|
|
408 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE)
|
|
409 {
|
|
410 if((pDiveState->diveSettings.gf_high != settingsGetPointer()->GF_high) || (pDiveState->diveSettings.gf_low != settingsGetPointer()->GF_low))
|
|
411 pDiveState->warnings.aGf = 1;
|
|
412 }
|
|
413 return pDiveState->warnings.aGf;
|
|
414 }
|
|
415
|
|
416 /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/
|
|
417
|