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