Mercurial > public > ostc4
annotate Discovery/Src/data_central.c @ 250:822416168585 bm-2
Buelmann: new implementation for ceiling
Since my first functional fix in the ceiling computation in
commit ceecabfddb57, I noticed that the computation used a
linear search, that became rather computational expensive after
that commit. The simple question is: why not a binary search?
So, this commit implements the binary search. But there is a long
story attached to this. Comparing ceiling results from hwOS and this
OSTC4 code were very different. Basically, the original OSTC4
algorithm computed the ceiling using the same GFlow to GFhigh
slope, in such a way, that the ceiling was in sync with the
presented deco stops, where the hwOS code presents a GFhigh
based ceiling.
This said, it is more logical when the OSTC4 and hwOS code give
similar results. This new recursive algorithm gives very similar
results for the ceiling compared to hwOS.
To be complete here, the Buelmann ceiling is the depth to which
you can ascend, so that the leading tissue reaches GFhigh. This
also explains why the deepest deco stop is normally deeper than
the ceiling (unless one dives with GF like 80/80).
The code implemented here is rather straightforward recursion.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
author | Jan Mulder <jlmulder@xs4all.nl> |
---|---|
date | Thu, 11 Apr 2019 17:48:48 +0200 |
parents | 2bb1db22b5f5 |
children | 2e58a4094770 |
rev | line source |
---|---|
38 | 1 /** |
2 ****************************************************************************** | |
3 * @copyright heinrichs weikamp | |
4 * @file data_central.c | |
5 * @author heinrichs weikamp gmbh | |
6 * @date 10-November-2014 | |
7 * @version V1.0.2 | |
8 * @since 10-Nov-2014 | |
9 * @brief All the data EXCEPT | |
10 * - settings (settings.c) | |
11 * feste Werte, die nur an der Oberfl�che ge�ndert werden | |
12 * - dataIn and dataOut (data_exchange.h and data_exchange_main.c) | |
13 * Austausch mit Small CPU | |
14 * @bug | |
15 * @warning | |
16 @verbatim | |
17 ============================================================================== | |
18 ##### SDiveState Real and Sim ##### | |
19 ============================================================================== | |
20 [..] SDiveSettings | |
21 copy of parts of Settings that are necessary during the dive | |
22 and could be modified during the dive without post dive changes. | |
23 | |
24 [..] SLifeData | |
25 written in DataEX_copy_to_LifeData(); | |
26 block 1 "lifedata" set by SmallCPU in stateReal | |
27 block 2 "actualGas" set by main CPU from user input and send to Small CPU | |
28 block 3 "calculated data" set by main CPU based on "lifedata" | |
29 | |
30 [..] SVpm | |
31 | |
32 [..] SEvents | |
33 | |
34 [..] SDecoinfo | |
35 | |
36 [..] mode | |
37 set by SmallCPU in stateReal, can be surface, dive, ... | |
38 | |
39 [..] data_old__lost_connection_to_slave | |
40 set by DataEX_copy_to_LifeData(); | |
41 | |
42 ============================================================================== | |
43 ##### SDiveState Deco ##### | |
44 ============================================================================== | |
45 [..] kjbkldafj�lasdfjasdf | |
46 | |
47 ============================================================================== | |
48 ##### decoLock ##### | |
49 ============================================================================== | |
50 [..] The handler that synchronizes the data between IRQ copy and main deco loop | |
51 | |
52 | |
53 @endverbatim | |
54 ****************************************************************************** | |
55 * @attention | |
56 * | |
57 * <h2><center>© COPYRIGHT(c) 2015 heinrichs weikamp</center></h2> | |
58 * | |
59 ****************************************************************************** | |
60 */ | |
61 | |
62 /* Includes ------------------------------------------------------------------*/ | |
63 #include <string.h> | |
64 #include "data_central.h" | |
65 #include "calc_crush.h" | |
66 #include "decom.h" | |
67 #include "stm32f4xx_hal.h" | |
68 #include "settings.h" | |
69 #include "data_exchange_main.h" | |
70 #include "ostc.h" // for button adjust on hw testboard 1 | |
71 #include "tCCR.h" | |
72 #include "crcmodel.h" | |
73 | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
149
diff
changeset
|
74 static SDiveState stateReal = { 0 }; |
38 | 75 SDiveState stateSim = { 0 }; |
76 SDiveState stateDeco = { 0 }; | |
77 | |
78 SDevice stateDevice = | |
79 { | |
80 /* max is 0x7FFFFFFF, min is 0x80000000 but also defined in stdint.h :-) */ | |
81 | |
82 /* count, use 0 */ | |
83 .batteryChargeCompleteCycles.value_int32 = 0, | |
84 .batteryChargeCycles.value_int32 = 0, | |
85 .diveCycles.value_int32 = 0, | |
86 .hoursOfOperation.value_int32 = 0, | |
87 | |
88 /* max values, use min. */ | |
89 .temperatureMaximum.value_int32 = INT32_MIN, | |
90 .depthMaximum.value_int32 = INT32_MIN, | |
91 | |
92 /* min values, use max. */ | |
93 .temperatureMinimum.value_int32 = INT32_MAX, | |
94 .voltageMinimum.value_int32 = INT32_MAX, | |
95 }; | |
96 | |
97 SVpmRepetitiveData stateVPM = | |
98 { | |
99 .repetitive_variables_not_valid = 1, | |
100 .is_data_from_RTE_CPU = 0, | |
101 }; | |
102 | |
103 const SDiveState * stateUsed = &stateReal; | |
104 | |
105 | |
106 void set_stateUsedToReal(void) | |
107 { | |
108 stateUsed = &stateReal; | |
109 } | |
110 | |
111 void set_stateUsedToSim(void) | |
112 { | |
113 stateUsed = &stateSim; | |
114 } | |
115 | |
116 _Bool is_stateUsedSetToSim(void) | |
117 { | |
225
2bb1db22b5f5
cleanup: random set of cleanups
Jan Mulder <jlmulder@xs4all.nl>
parents:
149
diff
changeset
|
118 return stateUsed == &stateSim; |
38 | 119 } |
120 | |
121 const SDiveState * stateRealGetPointer(void) | |
122 { | |
123 return &stateReal; | |
124 } | |
125 | |
126 SDiveState * stateRealGetPointerWrite(void) | |
127 { | |
128 return &stateReal; | |
129 } | |
130 | |
131 | |
132 const SDiveState * stateSimGetPointer(void) | |
133 { | |
134 return &stateSim; | |
135 } | |
136 | |
137 | |
138 SDiveState * stateSimGetPointerWrite(void) | |
139 { | |
140 return &stateSim; | |
141 } | |
142 | |
143 | |
144 const SDevice * stateDeviceGetPointer(void) | |
145 { | |
146 return &stateDevice; | |
147 } | |
148 | |
149 | |
150 SDevice * stateDeviceGetPointerWrite(void) | |
151 { | |
152 return &stateDevice; | |
153 } | |
154 | |
155 | |
156 const SVpmRepetitiveData * stateVpmRepetitiveDataGetPointer(void) | |
157 { | |
158 return &stateVPM; | |
159 } | |
160 | |
161 | |
162 SVpmRepetitiveData * stateVpmRepetitiveDataGetPointerWrite(void) | |
163 { | |
164 return &stateVPM; | |
165 } | |
166 | |
167 | |
168 uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow) | |
169 { | |
170 if(ticksstart <= ticksnow) | |
171 return ticksnow - ticksstart; | |
172 else | |
173 return 0xFFFFFFFF - ticksstart + ticksnow; | |
174 } | |
175 | |
176 | |
177 uint8_t decoLock = DECO_CALC_undefined; | |
178 int ascent_rate_meter_per_min = 12; | |
179 int descent_rate_meter_per_min = 20; | |
180 int max_depth = 70; | |
181 int bottom_time = 10; | |
182 | |
183 _Bool vpm_crush(SDiveState* pDiveState); | |
184 void setSimulationValues(int _ascent_rate_meter_per_min, int _descent_rate_meter_per_min, int _max_depth, int _bottom_time ) | |
185 { | |
186 ascent_rate_meter_per_min = _ascent_rate_meter_per_min; | |
187 descent_rate_meter_per_min = _descent_rate_meter_per_min; | |
188 max_depth = _max_depth; | |
189 bottom_time = _bottom_time; | |
190 } | |
191 | |
192 | |
193 | |
194 int current_second(void) { | |
195 | |
196 return HAL_GetTick() / 1000; | |
197 // printf("milliseconds: %lld\n", milliseconds); | |
198 //return milliseconds; | |
199 } | |
200 | |
201 | |
202 | |
203 #define OXY_ONE_SIXTIETH_PART 0.0166667f | |
204 | |
205 /*void oxygen_calculate_cns(float* oxygen_cns, float pressure_oxygen_real) | |
206 { | |
207 int cns_no_range = 0; | |
208 _Bool not_found = 1; | |
209 //for the cns calculation | |
210 const float cns_ppo2_ranges[60][2] = { {0.50, 0.00}, {0.60, 0.14}, {0.64, 0.15}, {0.66, 0.16}, {0.68, 0.17}, {0.70, 0.18}, | |
211 {0.74, 0.19}, {0.76, 0.20}, {0.78, 0.21}, {0.80, 0.22}, {0.82, 0.23}, {0.84, 0.24}, | |
212 {0.86, 0.25}, {0.88, 0.26}, {0.90, 0.28}, {0.92, 0.29}, {0.94, 0.30}, {0.96, 0.31}, | |
213 {0.98, 0.32}, {1.00, 0.33}, {1.02, 0.35}, {1.04, 0.36}, {1.06, 0.38}, {1.08, 0.40}, | |
214 {1.10, 0.42}, {1.12, 0.43}, {1.14, 0.43}, {1.16, 0.44}, {1.18, 0.46}, {1.20, 0.47}, | |
215 {1.22, 0.48}, {1.24, 0.51}, {1.26, 0.52}, {1.28, 0.54}, {1.30, 0.56}, {1.32, 0.57}, | |
216 {1.34, 0.60}, {1.36, 0.62}, {1.38, 0.63}, {1.40, 0.65}, {1.42, 0.68}, {1.44, 0.71}, | |
217 {1.46, 0.74}, {1.48, 0.78}, {1.50, 0.83}, {1.52, 0.93}, {1.54, 1.04}, {1.56, 1.19}, | |
218 {1.58, 1.47}, {1.60, 2.22}, {1.62, 5.00}, {1.65, 6.25}, {1.67, 7.69}, {1.70, 10.0}, | |
219 {1.72,12.50}, {1.74,20.00}, {1.77,25.00}, {1.79,31.25}, {1.80,50.00}, {1.82,100.0}}; | |
220 //find the correct cns range for the corresponding ppo2 | |
221 cns_no_range = 58; | |
222 while (cns_no_range && not_found) | |
223 { | |
224 if (pressure_oxygen_real > cns_ppo2_ranges[cns_no_range][0]) | |
225 { | |
226 cns_no_range++; | |
227 not_found = 0; | |
228 } | |
229 else | |
230 cns_no_range--; | |
231 } | |
232 | |
233 //calculate cns for the actual ppo2 for 1 second | |
234 *oxygen_cns += OXY_ONE_SIXTIETH_PART * cns_ppo2_ranges[cns_no_range][1]; | |
235 }*/ | |
236 | |
237 uint8_t calc_MOD(uint8_t gasId) | |
238 { | |
239 int16_t oxygen, maxppO2, result; | |
240 SSettings *pSettings; | |
241 | |
242 pSettings = settingsGetPointer(); | |
243 | |
244 oxygen = (int16_t)(pSettings->gas[gasId].oxygen_percentage); | |
245 | |
246 if(pSettings->gas[gasId].note.ub.deco > 0) | |
247 maxppO2 =(int16_t)(pSettings->ppO2_max_deco); | |
248 else | |
249 maxppO2 =(int16_t)(pSettings->ppO2_max_std); | |
250 | |
251 result = 10 * maxppO2; | |
252 result /= oxygen; | |
253 result -= 10; | |
254 | |
255 if(result < 0) | |
256 return 0; | |
257 | |
258 if(result > 255) | |
259 return 255; | |
260 | |
261 return result; | |
262 } | |
263 | |
264 uint8_t calc_MinOD(uint8_t gasId) | |
265 { | |
266 int16_t oxygen, minppO2, result; | |
267 SSettings *pSettings; | |
268 | |
269 pSettings = settingsGetPointer(); | |
270 | |
271 oxygen = (int16_t)(pSettings->gas[gasId].oxygen_percentage); | |
272 minppO2 =(int16_t)(pSettings->ppO2_min); | |
273 result = 10 * minppO2; | |
274 result += 9; | |
275 result /= oxygen; | |
276 result -= 10; | |
277 | |
278 if(result < 0) | |
279 return 0; | |
280 | |
281 if(result > 255) | |
282 return 255; | |
283 | |
284 return result; | |
285 } | |
286 /* | |
287 float calc_ppO2(float input_ambient_pressure_bar, SGas* pGas) | |
288 { | |
289 float percent_N2 = 0; | |
290 float percent_He = 0; | |
291 float percent_O2 = 0; | |
292 decom_get_inert_gases(input_ambient_pressure_bar, pGas, &percent_N2, &percent_He); | |
293 percent_O2 = 1 - percent_N2 - percent_He; | |
294 | |
295 return (input_ambient_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_O2; | |
296 }*/ | |
297 | |
298 float get_ambiant_pressure_simulation(long dive_time_seconds, float surface_pressure_bar ) | |
299 { | |
300 static | |
301 long descent_time; | |
302 float depth_meter; | |
303 | |
304 descent_time = 60 * max_depth / descent_rate_meter_per_min; | |
305 | |
306 if(dive_time_seconds <= descent_time) | |
307 { | |
308 depth_meter = ((float)(dive_time_seconds * descent_rate_meter_per_min)) / 60; | |
309 return surface_pressure_bar + depth_meter / 10; | |
310 } | |
311 //else if(dive_time_seconds <= (descent_time + bottom_time * 60)) | |
312 return surface_pressure_bar + max_depth / 10; | |
313 | |
314 | |
315 | |
316 } | |
317 | |
318 void UpdateLifeDataTest(SDiveState * pDiveState) | |
319 { | |
320 static int last_second = -1; | |
321 int now = current_second(); | |
322 if(last_second == now) | |
323 return; | |
324 last_second = now; | |
325 | |
326 pDiveState->lifeData.dive_time_seconds += 1; | |
327 pDiveState->lifeData.pressure_ambient_bar = get_ambiant_pressure_simulation(pDiveState->lifeData.dive_time_seconds,pDiveState->lifeData.pressure_surface_bar); | |
328 | |
329 pDiveState->lifeData.depth_meter = (pDiveState->lifeData.pressure_ambient_bar - pDiveState->lifeData.pressure_surface_bar) * 10.0f; | |
330 if(pDiveState->lifeData.max_depth_meter < pDiveState->lifeData.depth_meter) | |
331 pDiveState->lifeData.max_depth_meter = pDiveState->lifeData.depth_meter; | |
332 decom_tissues_exposure(1, &pDiveState->lifeData); | |
333 pDiveState->lifeData.ppO2 = decom_calc_ppO2( pDiveState->lifeData.pressure_ambient_bar, &pDiveState->lifeData.actualGas); | |
334 decom_oxygen_calculate_cns(& pDiveState->lifeData.cns, pDiveState->lifeData.ppO2); | |
335 | |
336 vpm_crush(pDiveState); | |
337 } | |
338 | |
339 | |
340 _Bool vpm_crush(SDiveState* pDiveState) | |
341 { | |
342 int i = 0; | |
343 static float starting_ambient_pressure = 0; | |
344 static float ending_ambient_pressure = 0; | |
345 static float time_calc_begin = -1; | |
346 static float initial_helium_pressure[16]; | |
347 static float initial_nitrogen_pressure[16]; | |
348 ending_ambient_pressure = pDiveState->lifeData.pressure_ambient_bar * 10; | |
349 | |
350 if((pDiveState->lifeData.dive_time_seconds <= 4) || (starting_ambient_pressure >= ending_ambient_pressure)) | |
351 { | |
352 time_calc_begin = pDiveState->lifeData.dive_time_seconds; | |
353 starting_ambient_pressure = pDiveState->lifeData.pressure_ambient_bar * 10; | |
354 for( i = 0; i < 16; i++) | |
355 { | |
356 initial_helium_pressure[i] = pDiveState->lifeData.tissue_helium_bar[i] * 10; | |
357 initial_nitrogen_pressure[i] = pDiveState->lifeData.tissue_nitrogen_bar[i] * 10; | |
358 } | |
359 return false; | |
360 } | |
361 if(pDiveState->lifeData.dive_time_seconds - time_calc_begin >= 4) | |
362 { | |
363 if(ending_ambient_pressure > starting_ambient_pressure + 0.5f) | |
364 { | |
365 float rate = (ending_ambient_pressure - starting_ambient_pressure) * 60 / 4; | |
366 calc_crushing_pressure(&pDiveState->lifeData, &pDiveState->vpm, initial_helium_pressure, initial_nitrogen_pressure, starting_ambient_pressure, rate); | |
367 | |
368 time_calc_begin = pDiveState->lifeData.dive_time_seconds; | |
369 starting_ambient_pressure = pDiveState->lifeData.pressure_ambient_bar * 10; | |
370 for( i = 0; i < 16; i++) | |
371 { | |
372 initial_helium_pressure[i] = pDiveState->lifeData.tissue_helium_bar[i] * 10; | |
373 initial_nitrogen_pressure[i] = pDiveState->lifeData.tissue_nitrogen_bar[i] * 10; | |
374 } | |
375 | |
376 return true; | |
377 } | |
378 | |
379 } | |
380 return false; | |
381 }; | |
382 | |
383 | |
384 void createDiveSettings(void) | |
385 { | |
386 SSettings* pSettings = settingsGetPointer(); | |
387 | |
388 setActualGasFirst(&stateReal.lifeData); | |
389 | |
390 stateReal.diveSettings.compassHeading = pSettings->compassBearing; | |
391 stateReal.diveSettings.ascentRate_meterperminute = 10; | |
392 | |
393 stateReal.diveSettings.diveMode = pSettings->dive_mode; | |
394 stateReal.diveSettings.CCR_Mode = pSettings->CCR_Mode; | |
395 if(stateReal.diveSettings.diveMode == DIVEMODE_CCR) | |
396 stateReal.diveSettings.ccrOption = 1; | |
397 else | |
398 stateReal.diveSettings.ccrOption = 0; | |
399 memcpy(stateReal.diveSettings.gas, pSettings->gas,sizeof(pSettings->gas)); | |
400 memcpy(stateReal.diveSettings.setpoint, pSettings->setpoint,sizeof(pSettings->setpoint)); | |
401 stateReal.diveSettings.gf_high = pSettings->GF_high; | |
402 stateReal.diveSettings.gf_low = pSettings->GF_low; | |
403 stateReal.diveSettings.input_next_stop_increment_depth_bar = ((float)pSettings->stop_increment_depth_meter) / 10.0f; | |
404 stateReal.diveSettings.last_stop_depth_bar = ((float)pSettings->last_stop_depth_meter) / 10.0f; | |
405 stateReal.diveSettings.vpm_conservatism = pSettings->VPM_conservatism.ub.standard; | |
406 stateReal.diveSettings.deco_type.uw = pSettings->deco_type.uw; | |
407 stateReal.diveSettings.fallbackOption = pSettings->fallbackToFixedSetpoint; | |
408 stateReal.diveSettings.ppo2sensors_deactivated = pSettings->ppo2sensors_deactivated; | |
409 stateReal.diveSettings.future_TTS_minutes = pSettings->future_TTS; | |
410 | |
411 decom_CreateGasChangeList(&stateReal.diveSettings, &stateReal.lifeData); // decogaslist | |
412 stateReal.diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0; | |
413 | |
414 /* for safety */ | |
415 stateReal.diveSettings.input_second_to_last_stop_depth_bar = stateReal.diveSettings.last_stop_depth_bar + stateReal.diveSettings.input_next_stop_increment_depth_bar; | |
416 /* and the proper calc */ | |
417 for(int i = 1; i <10; i++) | |
418 { | |
419 if(stateReal.diveSettings.input_next_stop_increment_depth_bar * i > stateReal.diveSettings.last_stop_depth_bar) | |
420 { | |
421 stateReal.diveSettings.input_second_to_last_stop_depth_bar = stateReal.diveSettings.input_next_stop_increment_depth_bar * i; | |
422 break; | |
423 } | |
424 } | |
425 } | |
426 | |
427 | |
428 void copyDiveSettingsToSim(void) | |
429 { | |
430 memcpy(&stateSim, &stateReal, sizeof(stateReal)); | |
431 } | |
432 | |
433 | |
434 void copyVpmRepetetiveDataToSim(void) | |
435 { | |
436 SDiveState * pSimData = stateSimGetPointerWrite(); | |
437 const SVpmRepetitiveData * pVpmData = stateVpmRepetitiveDataGetPointer(); | |
438 | |
439 if(pVpmData->is_data_from_RTE_CPU) | |
440 { | |
441 for(int i=0; i<16;i++) | |
442 { | |
443 pSimData->vpm.adjusted_critical_radius_he[i] = pVpmData->adjusted_critical_radius_he[i]; | |
444 pSimData->vpm.adjusted_critical_radius_n2[i] = pVpmData->adjusted_critical_radius_n2[i]; | |
445 | |
446 pSimData->vpm.adjusted_crushing_pressure_he[i] = pVpmData->adjusted_crushing_pressure_he[i]; | |
447 pSimData->vpm.adjusted_crushing_pressure_n2[i] = pVpmData->adjusted_crushing_pressure_n2[i]; | |
448 | |
449 pSimData->vpm.initial_allowable_gradient_he[i] = pVpmData->initial_allowable_gradient_he[i]; | |
450 pSimData->vpm.initial_allowable_gradient_n2[i] = pVpmData->initial_allowable_gradient_n2[i]; | |
451 | |
452 pSimData->vpm.max_actual_gradient[i] = pVpmData->max_actual_gradient[i]; | |
453 } | |
454 pSimData->vpm.repetitive_variables_not_valid = pVpmData->repetitive_variables_not_valid; | |
455 } | |
456 } | |
457 | |
458 | |
459 void updateSetpointStateUsed(void) | |
460 { | |
461 SLifeData *pLifeDataWrite; | |
462 | |
463 if(is_stateUsedSetToSim()) | |
464 pLifeDataWrite = &stateSimGetPointerWrite()->lifeData; | |
465 else | |
466 pLifeDataWrite = &stateRealGetPointerWrite()->lifeData; | |
467 | |
468 if(stateUsed->diveSettings.diveMode != DIVEMODE_CCR) | |
469 { | |
470 pLifeDataWrite->actualGas.setPoint_cbar = 0; | |
471 pLifeDataWrite->ppO2 = decom_calc_ppO2(stateUsed->lifeData.pressure_ambient_bar, &stateUsed->lifeData.actualGas); | |
472 } | |
473 else | |
474 { | |
475 if(stateUsed->diveSettings.CCR_Mode == CCRMODE_Sensors) | |
476 { | |
477 pLifeDataWrite->actualGas.setPoint_cbar = get_ppO2SensorWeightedResult_cbar(); | |
478 } | |
479 | |
480 if((stateUsed->lifeData.pressure_ambient_bar * 100) < stateUsed->lifeData.actualGas.setPoint_cbar) | |
481 pLifeDataWrite->ppO2 = stateUsed->lifeData.pressure_ambient_bar; | |
482 else | |
483 pLifeDataWrite->ppO2 = ((float)stateUsed->lifeData.actualGas.setPoint_cbar) / 100; | |
484 } | |
485 } | |
486 | |
487 /* | |
488 void fallbackToFixedSetpoints(SLifeData *lifeData) | |
489 { | |
490 | |
491 } | |
492 */ | |
493 | |
494 void setActualGasFirst(SLifeData *lifeData) | |
495 { | |
496 SSettings* pSettings = settingsGetPointer(); | |
497 uint8_t start = 0; | |
498 uint8_t gasId = 0; | |
499 uint8_t setpoint_cbar = 0; | |
500 | |
501 if(pSettings->dive_mode == DIVEMODE_CCR) | |
502 { | |
503 setpoint_cbar = pSettings->setpoint[1].setpoint_cbar; | |
504 start = NUM_OFFSET_DILUENT+1; | |
505 } | |
506 else | |
507 { | |
508 setpoint_cbar = 0; | |
509 start = 1; | |
510 } | |
511 | |
512 gasId = start; | |
513 for(int i=start;i<=NUM_GASES+start;i++) | |
514 { | |
515 if(pSettings->gas[i].note.ub.first) | |
516 { | |
517 gasId = i; | |
518 break; | |
519 } | |
520 } | |
521 setActualGas(lifeData, gasId, setpoint_cbar); | |
522 } | |
523 | |
524 void setActualGasAir(SLifeData *lifeData) | |
525 { | |
526 uint8_t nitrogen; | |
527 nitrogen = 79; | |
528 lifeData->actualGas.GasIdInSettings = 0; | |
529 lifeData->actualGas.nitrogen_percentage = nitrogen; | |
530 lifeData->actualGas.helium_percentage =0; | |
531 lifeData->actualGas.setPoint_cbar = 0; | |
532 lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0; | |
533 } | |
534 | |
535 | |
536 void setActualGas(SLifeData *lifeData, uint8_t gasId, uint8_t setpoint_cbar) | |
537 { | |
538 SSettings* pSettings = settingsGetPointer(); | |
539 uint8_t nitrogen; | |
540 | |
541 nitrogen = 100; | |
542 nitrogen -= pSettings->gas[gasId].oxygen_percentage; | |
543 nitrogen -= pSettings->gas[gasId].helium_percentage; | |
544 | |
545 lifeData->actualGas.GasIdInSettings = gasId; | |
546 lifeData->actualGas.nitrogen_percentage = nitrogen; | |
547 lifeData->actualGas.helium_percentage = pSettings->gas[gasId].helium_percentage; | |
548 lifeData->actualGas.setPoint_cbar = setpoint_cbar; | |
549 lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0; | |
550 | |
551 if((pSettings->dive_mode == DIVEMODE_CCR) && (gasId > NUM_OFFSET_DILUENT)) | |
552 lifeData->lastDiluent_GasIdInSettings = gasId; | |
553 } | |
554 | |
555 | |
556 void setActualGas_DM(SLifeData *lifeData, uint8_t gasId, uint8_t setpoint_cbar) | |
557 { | |
558 //Real dive => Set events for logbook | |
559 if(stateUsed == stateRealGetPointer()) | |
560 { | |
561 SDiveState * pStateUsed; | |
562 pStateUsed = stateRealGetPointerWrite(); | |
563 | |
564 if(stateUsed->diveSettings.ccrOption && gasId < 6) | |
565 { | |
566 if(lifeData->actualGas.GasIdInSettings != gasId) | |
567 { | |
568 SSettings* pSettings = settingsGetPointer(); | |
569 pStateUsed->events.bailout = 1; | |
570 pStateUsed->events.info_bailoutO2 = pSettings->gas[gasId].oxygen_percentage; | |
571 pStateUsed->events.info_bailoutHe = pSettings->gas[gasId].helium_percentage; | |
572 } | |
573 } | |
574 else | |
575 { | |
576 if(lifeData->actualGas.GasIdInSettings != gasId) | |
577 { | |
578 pStateUsed->events.gasChange = 1; | |
579 pStateUsed->events.info_GasChange = gasId; | |
580 } | |
581 if( lifeData->actualGas.setPoint_cbar != setpoint_cbar) | |
582 { | |
583 // setPoint_cbar = 255 -> change to sensor mode | |
584 pStateUsed->events.setpointChange = 1; | |
585 pStateUsed->events.info_SetpointChange = setpoint_cbar; | |
586 } | |
587 } | |
588 } | |
589 setActualGas(lifeData, gasId, setpoint_cbar); | |
590 } | |
591 | |
592 void setActualGas_ExtraGas(SLifeData *lifeData, uint8_t oxygen, uint8_t helium, uint8_t setpoint_cbar) | |
593 { | |
594 uint8_t nitrogen; | |
595 | |
596 nitrogen = 100; | |
597 nitrogen -= oxygen; | |
598 nitrogen -= helium; | |
599 | |
600 //Real dive => Set events for logbook | |
601 if(stateUsed == stateRealGetPointer()) | |
602 { | |
603 SDiveState * pStateUsed; | |
604 pStateUsed = stateRealGetPointerWrite(); | |
605 if((lifeData->actualGas.nitrogen_percentage != nitrogen) || (lifeData->actualGas.helium_percentage != helium)) | |
606 { | |
607 pStateUsed->events.manuelGasSet = 1; | |
608 pStateUsed->events.info_manuelGasSetHe = helium; | |
609 pStateUsed->events.info_manuelGasSetO2 = oxygen; | |
610 } | |
611 if( lifeData->actualGas.setPoint_cbar != setpoint_cbar) | |
612 { | |
613 pStateUsed->events.setpointChange = 1; | |
614 pStateUsed->events.info_SetpointChange = setpoint_cbar; | |
615 } | |
616 } | |
617 lifeData->actualGas.GasIdInSettings = 0; | |
618 lifeData->actualGas.nitrogen_percentage = nitrogen; | |
619 lifeData->actualGas.helium_percentage = helium; | |
620 lifeData->actualGas.setPoint_cbar = setpoint_cbar; | |
621 lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0; | |
622 | |
623 } | |
624 | |
625 void setButtonResponsiveness(uint8_t *ButtonSensitivyList) | |
626 { | |
627 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
628 | |
629 for(int i=0; i<4; i++) | |
630 { | |
631 pDataOut->data.buttonResponsiveness[i] = settingsHelperButtonSens_translate_percentage_to_hwOS_values(ButtonSensitivyList[i]); | |
632 } | |
633 pDataOut->setButtonSensitivityNow = 1; | |
634 } | |
635 | |
636 | |
637 void setDate(RTC_DateTypeDef Sdate) | |
638 { | |
639 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
640 | |
641 pDataOut->data.newDate = Sdate; | |
642 pDataOut->setDateNow = 1; | |
643 } | |
644 | |
645 | |
646 void setTime(RTC_TimeTypeDef Stime) | |
647 { | |
648 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
649 | |
650 pDataOut->data.newTime = Stime; | |
651 pDataOut->setTimeNow = 1; | |
652 } | |
653 | |
654 | |
655 void setBatteryPercentage(uint8_t newChargePercentage) | |
656 { | |
657 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
658 | |
659 pDataOut->data.newBatteryGaugePercentageFloat = settingsGetPointer()->lastKnownBatteryPercentage; | |
660 pDataOut->setBatteryGaugeNow = 1; | |
661 } | |
662 | |
663 | |
664 void calibrateCompass(void) | |
665 { | |
666 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
667 pDataOut->calibrateCompassNow = 1; | |
668 } | |
669 | |
670 | |
671 void clearDeco(void) | |
672 { | |
673 SDataReceiveFromMaster *pDataOut = dataOutGetPointer(); | |
674 pDataOut->clearDecoNow = 1; | |
675 | |
676 stateRealGetPointerWrite()->cnsHigh_at_the_end_of_dive = 0; | |
677 stateRealGetPointerWrite()->decoMissed_at_the_end_of_dive = 0; | |
678 } | |
679 | |
680 | |
681 int32_t helper_days_from_civil(int32_t y, uint32_t m, uint32_t d) | |
682 { | |
683 y += 2000; | |
684 y -= m <= 2; | |
685 int32_t era = (y >= 0 ? y : y-399) / 400; | |
686 uint32_t yoe = (uint32_t)(y - era * 400); // [0, 399] | |
687 uint32_t doy = (153*(m + (m > 2 ? -3 : 9)) + 2)/5 + d-1; // [0, 365] | |
688 uint32_t doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] | |
689 return era * 146097 + (int32_t)(doe) - 719468; | |
690 } | |
691 | |
692 | |
693 uint8_t helper_weekday_from_days(int32_t z) | |
694 { | |
695 return (uint8_t)(z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6); | |
696 } | |
697 | |
698 | |
699 void setWeekday(RTC_DateTypeDef *sDate) | |
700 { | |
701 uint8_t day; | |
702 // [0, 6] -> [Sun, Sat] | |
703 day = helper_weekday_from_days(helper_days_from_civil(sDate->Year, sDate->Month, sDate->Date)); | |
704 // [1, 7] -> [Mon, Sun] | |
705 if(day == 0) | |
706 day = 7; | |
707 sDate->WeekDay = day; | |
708 } | |
709 | |
710 | |
711 void translateDate(uint32_t datetmpreg, RTC_DateTypeDef *sDate) | |
712 { | |
713 datetmpreg = (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK); | |
714 | |
715 /* Fill the structure fields with the read parameters */ | |
716 sDate->Year = (uint8_t)((datetmpreg & (RTC_DR_YT | RTC_DR_YU)) >> 16); | |
717 sDate->Month = (uint8_t)((datetmpreg & (RTC_DR_MT | RTC_DR_MU)) >> 8); | |
718 sDate->Date = (uint8_t)(datetmpreg & (RTC_DR_DT | RTC_DR_DU)); | |
719 sDate->WeekDay = (uint8_t)((datetmpreg & (RTC_DR_WDU)) >> 13); | |
720 | |
721 /* Convert the date structure parameters to Binary format */ | |
722 sDate->Year = (uint8_t)RTC_Bcd2ToByte(sDate->Year); | |
723 sDate->Month = (uint8_t)RTC_Bcd2ToByte(sDate->Month); | |
724 sDate->Date = (uint8_t)RTC_Bcd2ToByte(sDate->Date); | |
725 } | |
726 | |
727 void translateTime(uint32_t tmpreg, RTC_TimeTypeDef *sTime) | |
728 { | |
729 tmpreg = (uint32_t)(tmpreg & RTC_TR_RESERVED_MASK); | |
730 | |
731 /* Fill the structure fields with the read parameters */ | |
732 sTime->Hours = (uint8_t)((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> 16); | |
733 sTime->Minutes = (uint8_t)((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >>8); | |
734 sTime->Seconds = (uint8_t)(tmpreg & (RTC_TR_ST | RTC_TR_SU)); | |
735 sTime->TimeFormat = (uint8_t)((tmpreg & (RTC_TR_PM)) >> 16); | |
736 | |
737 /* Convert the time structure parameters to Binary format */ | |
738 sTime->Hours = (uint8_t)RTC_Bcd2ToByte(sTime->Hours); | |
739 sTime->Minutes = (uint8_t)RTC_Bcd2ToByte(sTime->Minutes); | |
740 sTime->Seconds = (uint8_t)RTC_Bcd2ToByte(sTime->Seconds); | |
741 sTime->SubSeconds = 0; | |
742 } | |
743 | |
744 | |
745 /* | |
746 void initDiveState(SDiveSettings * pDiveSettings, SVpm * pVpm) | |
747 { | |
748 SSettings* pSettings = settingsGetPointer(); | |
749 for(int i = 0; i< NUM_GASES; i++) | |
750 { | |
751 pDiveSettings->gas[i] = pSettings->gas[i]; | |
752 pDiveSettings->gas[NUM_OFFSET_DILUENT + i] = pSettings->gas[NUM_OFFSET_DILUENT + i]; | |
753 pDiveSettings->setpoint[i] = pSettings->setpoint[i]; | |
754 } | |
755 pDiveSettings->diveMode = pSettings->dive_mode; | |
756 | |
757 pDiveSettings->gf_high = pSettings->GF_high; | |
758 pDiveSettings->gf_low = pSettings->GF_low; | |
759 pDiveSettings->last_stop_depth_bar = ((float)pSettings->last_stop_depth_meter) / 10.0; | |
760 pDiveSettings->ascentRate_meterperminute = 10; | |
761 pDiveSettings->vpm_conservatism = 1; | |
762 | |
763 pDiveSettings->input_next_stop_increment_depth_bar = ((float)pSettings->stop_increment_depth_meter) / 10.0f; | |
764 | |
765 vpm_init(pVpm, pDiveSettings->vpm_conservatism, 0, 0); | |
766 } | |
767 */ | |
768 _Bool deco_zone_reached(void) | |
769 { | |
770 if(stateUsed->diveSettings.deco_type.ub.standard == GF_MODE) | |
771 return stateUsed->lifeData.pressure_ambient_bar <= stateUsed->diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero; | |
772 else | |
773 return stateUsed->vpm.deco_zone_reached; | |
774 | |
775 } | |
776 | |
777 | |
778 void resetEvents(void) | |
779 { | |
149 | 780 SDiveState * pStateUsed; |
38 | 781 if(stateUsed == stateRealGetPointer()) |
149 | 782 { |
38 | 783 pStateUsed = stateRealGetPointerWrite(); |
149 | 784 } |
38 | 785 else |
149 | 786 { |
38 | 787 pStateUsed = stateSimGetPointerWrite(); |
149 | 788 } |
789 memset(&pStateUsed->events,0, sizeof(SEvents)); | |
38 | 790 } |
791 | |
792 | |
793 /* This is derived from crc32b but does table lookup. First the table | |
794 itself is calculated, if it has not yet been set up. | |
795 Not counting the table setup (which would probably be a separate | |
796 function), when compiled to Cyclops with GCC, this function executes in | |
797 7 + 13n instructions, where n is the number of bytes in the input | |
798 message. It should be doable in 4 + 9n instructions. In any case, two | |
799 of the 13 or 9 instrucions are load byte. | |
800 This is Figure 14-7 in the text. */ | |
801 | |
802 /* http://www.hackersdelight.org/ i guess ;-) *hw */ | |
803 | |
804 uint32_t crc32c_checksum(uint8_t* message, uint16_t length, uint8_t* message2, uint16_t length2) { | |
805 int i, j; | |
806 uint32_t byte, crc, mask; | |
807 static unsigned int table[256] = {0}; | |
808 | |
809 /* Set up the table, if necessary. */ | |
810 if (table[1] == 0) { | |
811 for (byte = 0; byte <= 255; byte++) { | |
812 crc = byte; | |
813 for (j = 7; j >= 0; j--) { // Do eight times. | |
814 mask = -(crc & 1); | |
815 crc = (crc >> 1) ^ (0xEDB88320 & mask); | |
816 } | |
817 table[byte] = crc; | |
818 } | |
819 } | |
820 | |
821 /* Through with table setup, now calculate the CRC. */ | |
822 i = 0; | |
823 crc = 0xFFFFFFFF; | |
824 while (length--) { | |
825 byte = message[i]; | |
826 crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF]; | |
827 i = i + 1; | |
828 } | |
829 if(length2) | |
830 { | |
831 i = 0; | |
832 while (length2--) { | |
833 byte = message2[i]; | |
834 crc = (crc >> 8) ^ table[(crc ^ byte) & 0xFF]; | |
835 i = i + 1; | |
836 } | |
837 } | |
838 return ~crc; | |
839 } | |
840 | |
841 | |
842 uint32_t CRC_CalcBlockCRC_moreThan768000(uint32_t *buffer1, uint32_t *buffer2, uint32_t words) | |
843 { | |
844 cm_t crc_model; | |
845 uint32_t word_to_do; | |
846 uint8_t byte_to_do; | |
847 int i; | |
848 | |
849 // Values for the STM32F generator. | |
850 | |
851 crc_model.cm_width = 32; // 32-bit CRC | |
852 crc_model.cm_poly = 0x04C11DB7; // CRC-32 polynomial | |
853 crc_model.cm_init = 0xFFFFFFFF; // CRC initialized to 1's | |
854 crc_model.cm_refin = FALSE; // CRC calculated MSB first | |
855 crc_model.cm_refot = FALSE; // Final result is not bit-reversed | |
856 crc_model.cm_xorot = 0x00000000; // Final result XOR'ed with this | |
857 | |
858 cm_ini(&crc_model); | |
859 | |
860 while (words--) | |
861 { | |
862 // The STM32F10x hardware does 32-bit words at a time!!! | |
863 if(words > (768000/4)) | |
864 word_to_do = *buffer2++; | |
865 else | |
866 word_to_do = *buffer1++; | |
867 | |
868 // Do all bytes in the 32-bit word. | |
869 | |
870 for (i = 0; i < sizeof(word_to_do); i++) | |
871 { | |
872 // We calculate a *byte* at a time. If the CRC is MSB first we | |
873 // do the next MS byte and vica-versa. | |
874 | |
875 if (crc_model.cm_refin == FALSE) | |
876 { | |
877 // MSB first. Do the next MS byte. | |
878 | |
879 byte_to_do = (uint8_t) ((word_to_do & 0xFF000000) >> 24); | |
880 word_to_do <<= 8; | |
881 } | |
882 else | |
883 { | |
884 // LSB first. Do the next LS byte. | |
885 | |
886 byte_to_do = (uint8_t) (word_to_do & 0x000000FF); | |
887 word_to_do >>= 8; | |
888 } | |
889 | |
890 cm_nxt(&crc_model, byte_to_do); | |
891 } | |
892 } | |
893 | |
894 // Return the final result. | |
895 | |
896 return (cm_crc(&crc_model)); | |
897 } | |
898 | |
899 | |
900 uint32_t CRC_CalcBlockCRC(uint32_t *buffer, uint32_t words) | |
901 { | |
902 cm_t crc_model; | |
903 uint32_t word_to_do; | |
904 uint8_t byte_to_do; | |
905 int i; | |
906 | |
907 // Values for the STM32F generator. | |
908 | |
909 crc_model.cm_width = 32; // 32-bit CRC | |
910 crc_model.cm_poly = 0x04C11DB7; // CRC-32 polynomial | |
911 crc_model.cm_init = 0xFFFFFFFF; // CRC initialized to 1's | |
912 crc_model.cm_refin = FALSE; // CRC calculated MSB first | |
913 crc_model.cm_refot = FALSE; // Final result is not bit-reversed | |
914 crc_model.cm_xorot = 0x00000000; // Final result XOR'ed with this | |
915 | |
916 cm_ini(&crc_model); | |
917 | |
918 while (words--) | |
919 { | |
920 // The STM32F10x hardware does 32-bit words at a time!!! | |
921 | |
922 word_to_do = *buffer++; | |
923 | |
924 // Do all bytes in the 32-bit word. | |
925 | |
926 for (i = 0; i < sizeof(word_to_do); i++) | |
927 { | |
928 // We calculate a *byte* at a time. If the CRC is MSB first we | |
929 // do the next MS byte and vica-versa. | |
930 | |
931 if (crc_model.cm_refin == FALSE) | |
932 { | |
933 // MSB first. Do the next MS byte. | |
934 | |
935 byte_to_do = (uint8_t) ((word_to_do & 0xFF000000) >> 24); | |
936 word_to_do <<= 8; | |
937 } | |
938 else | |
939 { | |
940 // LSB first. Do the next LS byte. | |
941 | |
942 byte_to_do = (uint8_t) (word_to_do & 0x000000FF); | |
943 word_to_do >>= 8; | |
944 } | |
945 | |
946 cm_nxt(&crc_model, byte_to_do); | |
947 } | |
948 } | |
949 | |
950 // Return the final result. | |
951 | |
952 return (cm_crc(&crc_model)); | |
953 } | |
954 | |
955 | |
956 _Bool is_ambient_pressure_close_to_surface(SLifeData *lifeData) | |
957 { | |
958 if(lifeData->pressure_ambient_bar < (lifeData->pressure_surface_bar + 0.04f)) | |
959 return true; | |
960 else | |
961 return false; | |
962 } |