Mercurial > public > ostc4
annotate Discovery/Src/simulation.c @ 218:ff59d1d07f9c Improve_IPC_Sync
Splitted 120 seconds UART timeout into chunks of 500ms
The UART connection via Bluetooth was realized using a receive call with 120 seconds timeout. By cancellation it seemed for the user as if the connection would have been aborted. In reality the received function keeped executing the wait for RX data till timeout occure. To avaoid this the timeout has been splitted into several calls with 500ms timeout => If the user disconnects by pressing "back" the COMM function is now ended.
author | ideenmodellierer |
---|---|
date | Sun, 31 Mar 2019 15:44:12 +0200 |
parents | 1719b9d1094b |
children | 2bb1db22b5f5 |
rev | line source |
---|---|
38 | 1 /////////////////////////////////////////////////////////////////////////////// |
2 /// -*- coding: UTF-8 -*- | |
3 /// | |
4 /// \file Discovery/Src/simulation.c | |
5 /// \brief Contains dive simulation functionality | |
6 /// \author Heinrichs Weikamp gmbh | |
7 /// \date 13-Oct-2014 | |
8 /// | |
9 /// \details | |
10 /// The simulation uses "extern SDiveState stateSim" defined in dataCentral.h" | |
11 /// | |
12 /// simulation_start(void) sets stateUsed to stateSim and initializes simulation | |
13 /// simulation_UpdateLifeData should be called at least once per second | |
14 /// simulation_end() sets stateUsed back to stateReal | |
15 /// | |
16 /// $Id$ | |
17 /////////////////////////////////////////////////////////////////////////////// | |
18 /// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh | |
19 /// | |
20 /// This program is free software: you can redistribute it and/or modify | |
21 /// it under the terms of the GNU General Public License as published by | |
22 /// the Free Software Foundation, either version 3 of the License, or | |
23 /// (at your option) any later version. | |
24 /// | |
25 /// This program is distributed in the hope that it will be useful, | |
26 /// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 /// GNU General Public License for more details. | |
29 /// | |
30 /// You should have received a copy of the GNU General Public License | |
31 /// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
32 ////////////////////////////////////////////////////////////////////////////// | |
33 | |
34 #include <string.h> | |
35 #include "simulation.h" | |
36 | |
37 #include "decom.h" | |
38 #include "calc_crush.h" | |
39 #include "data_exchange.h" | |
40 #include "timer.h" | |
41 #include "check_warning.h" | |
42 #include "vpm.h" | |
43 #include "buehlmann.h" | |
44 #include "logbook_miniLive.h" | |
45 | |
46 //Private state variables | |
47 float sim_aim_depth_meter; | |
48 _Bool sim_head_decostops = 1; | |
49 | |
50 const float sim_descent_rate_meter_per_min = 20; | |
51 | |
52 | |
53 //Private functions | |
54 float sim_get_ambiant_pressure(SDiveState * pDiveState); | |
55 void sim_reduce_deco_time_one_second(SDiveState* pDiveState); | |
56 | |
57 /** | |
58 ****************************************************************************** | |
59 * @brief sets heed_decostops_while_ascending | |
60 ****************************************************************************** | |
61 * @param heed_decostops_while_ascending : true -> deco_stops are considered while ascending | |
62 * @return void | |
63 */ | |
64 void simulation_set_heed_decostops(_Bool heed_decostops_while_ascending) | |
65 { | |
66 sim_head_decostops = heed_decostops_while_ascending; | |
67 } | |
68 | |
69 /** | |
70 ****************************************************************************** | |
71 * @brief start of simulation | |
72 ****************************************************************************** | |
73 * @return void | |
74 */ | |
75 void simulation_start(int aim_depth) | |
76 { | |
77 copyDiveSettingsToSim(); | |
78 copyVpmRepetetiveDataToSim(); | |
79 //vpm_init(&stateSimGetPointerWrite()->vpm, stateSimGetPointerWrite()->diveSettings.vpm_conservatism, 0, 0); | |
80 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0; | |
81 stateSimGetPointerWrite()->mode = MODE_DIVE; | |
82 if(aim_depth <= 0) | |
83 aim_depth = 20; | |
84 simulation_set_aim_depth(aim_depth); | |
85 timer_init(); | |
86 stateUsed = &stateSim; | |
87 stateSim.lifeData.boolResetAverageDepth = 1; | |
88 decoLock = DECO_CALC_init_as_is_start_of_dive; | |
89 | |
90 stateSim.lifeData.apnea_total_max_depth_meter = 0; | |
91 } | |
92 | |
93 /** | |
94 ****************************************************************************** | |
95 * @brief end of simulation | |
96 ****************************************************************************** | |
97 * | |
98 * @return void | |
99 */ | |
100 void simulation_exit(void) | |
101 { | |
102 timer_Stopwatch_Stop(); | |
103 set_stateUsedToReal(); | |
104 } | |
105 | |
106 /** | |
107 ****************************************************************************** | |
108 * @brief simulates change of Lifedata (saturation, depth change, etc.) within one second | |
109 ****************************************************************************** | |
110 * | |
111 * @param checkOncePerSecond : true -> simulation in real time (function is evaluated only once per second) | |
112 * and copy of parts of LifeData from SmallCPU with each call from HAL_TIM_PeriodElapsedCallback() | |
113 * : false -> fast simulation (many simulation cycles per second are possible) | |
114 * @return void | |
115 */ | |
116 void simulation_UpdateLifeData( _Bool checkOncePerSecond) | |
117 { | |
118 SDiveState * pDiveState = &stateSim; | |
119 | |
120 static int last_second = -1; | |
121 static _Bool two_second = 0; | |
122 static float lastPressure_bar = 0; | |
123 | |
124 if(checkOncePerSecond) | |
125 { | |
126 pDiveState->lifeData.temperature_celsius = stateRealGetPointer()->lifeData.temperature_celsius; | |
127 pDiveState->lifeData.compass_heading = stateRealGetPointer()->lifeData.compass_heading; | |
128 pDiveState->lifeData.battery_charge = stateRealGetPointer()->lifeData.battery_charge; | |
129 | |
130 int now = current_second(); | |
131 if( last_second == now) | |
132 return; | |
133 last_second = now; | |
134 | |
135 if(!two_second) | |
136 two_second = 1; | |
137 else | |
138 { | |
139 two_second = 0; | |
140 if(lastPressure_bar >= 0) | |
141 { | |
142 //2 seconds * 30 == 1 minute, bar * 10 = meter | |
143 pDiveState->lifeData.ascent_rate_meter_per_min = (lastPressure_bar - pDiveState->lifeData.pressure_ambient_bar) * 30 * 10; | |
144 } | |
145 lastPressure_bar = pDiveState->lifeData.pressure_ambient_bar; | |
146 } | |
147 } | |
148 else if(pDiveState->lifeData.depth_meter <= (float)(decom_get_actual_deco_stop(pDiveState) + 0.001)) | |
149 sim_reduce_deco_time_one_second(pDiveState); | |
150 | |
151 pDiveState->lifeData.ppO2Sensor_bar[0] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[0]; | |
152 pDiveState->lifeData.ppO2Sensor_bar[1] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[1]; | |
153 pDiveState->lifeData.ppO2Sensor_bar[2] = stateRealGetPointer()->lifeData.ppO2Sensor_bar[2]; | |
154 pDiveState->lifeData.sensorVoltage_mV[0] = stateRealGetPointer()->lifeData.sensorVoltage_mV[0]; | |
155 pDiveState->lifeData.sensorVoltage_mV[1] = stateRealGetPointer()->lifeData.sensorVoltage_mV[1]; | |
156 pDiveState->lifeData.sensorVoltage_mV[2] = stateRealGetPointer()->lifeData.sensorVoltage_mV[2]; | |
157 | |
158 pDiveState->lifeData.dive_time_seconds += 1; | |
159 pDiveState->lifeData.pressure_ambient_bar = sim_get_ambiant_pressure(pDiveState); | |
160 | |
161 if(!is_ambient_pressure_close_to_surface(&pDiveState->lifeData) && !(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) ) | |
162 { | |
163 pDiveState->lifeData.dive_time_seconds_without_surface_time += 1; | |
164 } | |
165 | |
166 if(is_ambient_pressure_close_to_surface(&pDiveState->lifeData)) // new hw 170214 | |
167 { | |
168 if(!(stateSimGetPointer()->lifeData.counterSecondsShallowDepth)) | |
169 { | |
170 if(pDiveState->diveSettings.diveMode != DIVEMODE_Apnea) | |
171 pDiveState->lifeData.counterSecondsShallowDepth = settingsGetPointer()->timeoutDiveReachedZeroDepth - 15; | |
172 else | |
173 { | |
174 pDiveState->lifeData.apnea_last_dive_time_seconds = pDiveState->lifeData.dive_time_seconds; | |
175 if(pDiveState->lifeData.apnea_last_dive_time_seconds > pDiveState->lifeData.dive_time_seconds_without_surface_time) | |
176 pDiveState->lifeData.apnea_last_dive_time_seconds = pDiveState->lifeData.dive_time_seconds_without_surface_time; | |
177 pDiveState->lifeData.apnea_last_max_depth_meter = pDiveState->lifeData.max_depth_meter; | |
178 pDiveState->lifeData.counterSecondsShallowDepth = 1; | |
179 } | |
180 } | |
181 } | |
182 else | |
183 { | |
184 pDiveState->lifeData.counterSecondsShallowDepth = 0; | |
185 } | |
186 | |
187 pDiveState->lifeData.depth_meter = (pDiveState->lifeData.pressure_ambient_bar - pDiveState->lifeData.pressure_surface_bar) * 10.0f; | |
188 if(pDiveState->lifeData.max_depth_meter < pDiveState->lifeData.depth_meter) | |
189 pDiveState->lifeData.max_depth_meter = pDiveState->lifeData.depth_meter; | |
190 | |
191 /* apnoe specials | |
192 */ | |
193 if(pDiveState->diveSettings.diveMode == DIVEMODE_Apnea) | |
194 { | |
195 if(pDiveState->lifeData.max_depth_meter > pDiveState->lifeData.apnea_total_max_depth_meter) | |
196 pDiveState->lifeData.apnea_total_max_depth_meter = pDiveState->lifeData.max_depth_meter; | |
197 | |
198 if(pDiveState->lifeData.counterSecondsShallowDepth) | |
199 { | |
200 pDiveState->lifeData.dive_time_seconds = 0; | |
201 pDiveState->lifeData.max_depth_meter = 0; | |
202 pDiveState->lifeData.boolResetAverageDepth = 1; | |
203 pDiveState->lifeData.boolResetStopwatch = 1; | |
204 } | |
205 } | |
206 | |
207 /* average depth | |
208 */ | |
209 float *AvgDepthValue = &pDiveState->lifeData.average_depth_meter; | |
210 float DepthNow = pDiveState->lifeData.depth_meter; | |
211 uint32_t *AvgDepthCount = &pDiveState->lifeData.internal.average_depth_meter_Count; | |
212 uint32_t *AvgDepthTimer = &pDiveState->lifeData.internal.average_depth_last_update_dive_time_seconds_without_surface_time; | |
213 uint32_t AvgSecondsSinceLast; | |
214 uint32_t DiveTime = pDiveState->lifeData.dive_time_seconds_without_surface_time; | |
215 | |
216 if(pDiveState->lifeData.boolResetAverageDepth) | |
217 { | |
218 *AvgDepthValue = DepthNow; | |
219 *AvgDepthCount = 1; | |
220 *AvgDepthTimer = DiveTime; | |
221 pDiveState->lifeData.boolResetAverageDepth = 0; | |
222 } | |
223 else if (DiveTime > *AvgDepthTimer) | |
224 { | |
225 AvgSecondsSinceLast = DiveTime - *AvgDepthTimer; | |
226 for(int i=0;i<AvgSecondsSinceLast;i++) | |
227 { | |
228 *AvgDepthValue = (*AvgDepthValue * *AvgDepthCount + DepthNow) / (*AvgDepthCount + 1); | |
229 *AvgDepthCount += 1; | |
230 } | |
231 *AvgDepthTimer = DiveTime; | |
232 } | |
233 if(*AvgDepthCount == 0) | |
234 *AvgDepthValue = 0; | |
235 | |
236 /* Exposure Tissues | |
237 */ | |
238 decom_tissues_exposure(1, &pDiveState->lifeData); | |
239 /* moved to updateSetpointStateUsed() | |
240 pDiveState->lifeData.ppO2 = decom_calc_ppO2( pDiveState->lifeData.pressure_ambient_bar, &pDiveState->lifeData.actualGas); | |
241 */ | |
242 decom_oxygen_calculate_cns_exposure(1, &pDiveState->lifeData.actualGas, pDiveState->lifeData.pressure_ambient_bar, &pDiveState->lifeData.cns); | |
243 //if((pDiveState->lifeData.depth_meter < 0.1f) || (pDiveState->lifeData.dive_time_seconds > 1*60*60)) | |
244 // if(pDiveState->lifeData.dive_time_seconds > 1*60*60) | |
245 if(pDiveState->lifeData.dive_time_seconds > 5*60*60) // test Dirk Berben | |
246 { | |
247 simulation_exit(); | |
248 } | |
249 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) | |
250 { | |
251 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth += 1; | |
252 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth >= settingsGetPointer()->timeoutDiveReachedZeroDepth) | |
253 simulation_exit(); | |
254 } | |
255 vpm_crush(pDiveState); | |
256 } | |
257 | |
258 /** | |
259 ****************************************************************************** | |
260 * @brief adds extra time for fast simulation | |
261 ****************************************************************************** | |
262 *@param minutes | |
263 * @return float : new pressure | |
264 */ | |
265 void simulation_add_time(int minutes) | |
266 { | |
267 for(int i = 0; i < 60 * minutes; i++) | |
268 { | |
269 simulation_UpdateLifeData(0); | |
270 updateMiniLiveLogbook(0); | |
271 timer_UpdateSecond(0); | |
272 } | |
273 } | |
274 | |
275 /** | |
276 ****************************************************************************** | |
277 * @brief get aim_depth | |
278 ****************************************************************************** | |
279 * @return sim_aim_depth_meter; | |
280 */ | |
281 | |
282 uint16_t simulation_get_aim_depth(void) | |
283 { | |
284 return (uint16_t)sim_aim_depth_meter; | |
285 } | |
286 | |
287 /** | |
288 ****************************************************************************** | |
289 * @brief get heed decostops | |
290 ****************************************************************************** | |
291 * @return true if ascend follows decostops; | |
292 */ | |
293 | |
294 _Bool simulation_get_heed_decostops(void) | |
295 { | |
296 return sim_head_decostops; | |
297 } | |
298 | |
299 /** | |
300 ****************************************************************************** | |
301 * @brief sets aim_depth | |
302 ****************************************************************************** | |
303 *@param depth_meter | |
304 * @return float : new pressure | |
305 */ | |
306 void simulation_set_aim_depth(int depth_meter) | |
307 { | |
308 sim_aim_depth_meter = depth_meter; | |
309 } | |
310 | |
311 /** | |
312 ****************************************************************************** | |
313 * @brief simulates ambiant pressure depending on aim depth | |
314 ****************************************************************************** | |
315 * @note if aim_depth != actual depth, the depth change within one second | |
316 * (depending on descent or ascent) rate is calculated | |
317 * @param SDiveState* pDiveState: | |
318 * @return float : new ambiant pressure | |
319 */ | |
320 float sim_get_ambiant_pressure(SDiveState * pDiveState) | |
321 { | |
322 //Calc next depth | |
323 uint8_t actual_deco_stop = decom_get_actual_deco_stop(pDiveState); | |
324 float depth_meter = pDiveState->lifeData.depth_meter; | |
325 float surface_pressure_bar = pDiveState->lifeData.pressure_surface_bar; | |
326 if(depth_meter < sim_aim_depth_meter) | |
327 { | |
328 depth_meter = depth_meter + sim_descent_rate_meter_per_min / 60; | |
329 if(depth_meter > sim_aim_depth_meter) | |
330 depth_meter = sim_aim_depth_meter; | |
331 } | |
332 else if(depth_meter > sim_aim_depth_meter) | |
333 { | |
334 | |
335 depth_meter -= pDiveState->diveSettings.ascentRate_meterperminute / 60; | |
336 if(depth_meter < sim_aim_depth_meter) | |
337 depth_meter = sim_aim_depth_meter; | |
338 | |
339 if(sim_head_decostops && depth_meter < actual_deco_stop) | |
340 { | |
341 if(actual_deco_stop < (depth_meter + pDiveState->diveSettings.ascentRate_meterperminute / 60)) | |
342 depth_meter = actual_deco_stop; | |
343 else | |
344 depth_meter += pDiveState->diveSettings.ascentRate_meterperminute / 60; | |
345 } | |
346 | |
347 } | |
348 | |
349 return surface_pressure_bar + depth_meter / 10; | |
350 } | |
351 | |
352 | |
353 /** | |
354 ****************************************************************************** | |
355 * @brief Reduces deco time of deepest stop by one second | |
356 ****************************************************************************** | |
357 * @note called during fast simulation | |
358 * @param SDiveState* pDiveState: | |
359 * @return void | |
360 */ | |
361 void sim_reduce_deco_time_one_second(SDiveState* pDiveState) | |
362 { | |
363 SDecoinfo* pDecoinfo; | |
364 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
365 pDecoinfo = &pDiveState->decolistBuehlmann; | |
366 else | |
367 pDecoinfo = &pDiveState->decolistVPM; | |
368 | |
369 //Reduce deco time of deepest stop by one second | |
370 for(int i = DECOINFO_STRUCT_MAX_STOPS -1 ;i >= 0; i--) | |
371 { | |
372 if(pDecoinfo->output_stop_length_seconds[i] > 0) | |
373 { | |
374 pDecoinfo->output_stop_length_seconds[i]--; | |
375 break; | |
376 } | |
377 } | |
378 } | |
379 | |
380 SDecoinfo* simulation_decoplaner(uint16_t depth_meter, uint16_t intervall_time_minutes, uint16_t dive_time_minutes, uint8_t *gasChangeListDepthGas20x2) | |
381 { | |
382 uint8_t ptrGasChangeList = 0; // new hw 160704 | |
383 | |
384 SDiveState * pDiveState = &stateSim; | |
385 copyDiveSettingsToSim(); | |
386 vpm_init(&pDiveState->vpm, pDiveState->diveSettings.vpm_conservatism, 0, 0); | |
387 //buehlmann_init(); | |
388 //timer_init(); | |
389 memset(&pDiveState->events,0, sizeof(SEvents)); | |
390 pDiveState->diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0; | |
391 //Calc desaturation during intervall (with Air) | |
392 setActualGasAir(&pDiveState->lifeData); | |
393 if(intervall_time_minutes > 0) | |
394 { | |
395 decom_tissues_exposure(intervall_time_minutes * 60, &pDiveState->lifeData); | |
396 decom_oxygen_calculate_cns_degrade(&pDiveState->lifeData.cns, intervall_time_minutes * 60); | |
397 } | |
398 | |
399 //Switch to first Gas | |
400 setActualGasFirst(&pDiveState->lifeData); | |
401 | |
402 // new hw 160704 | |
403 if(gasChangeListDepthGas20x2) | |
404 { | |
405 gasChangeListDepthGas20x2[ptrGasChangeList++] = 0; | |
406 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->lifeData.actualGas.GasIdInSettings; | |
407 gasChangeListDepthGas20x2[0] =0; // depth zero | |
408 } | |
409 | |
410 //Going down / descent | |
411 simulation_set_aim_depth(depth_meter); | |
412 for(int i = 0; i < 60 * dive_time_minutes; i++) | |
413 { | |
414 simulation_UpdateLifeData(0); | |
415 check_warning2(pDiveState); | |
416 if(pDiveState->warnings.betterGas) | |
417 { | |
418 setActualGas(&pDiveState->lifeData,actualBetterGasId(),pDiveState->lifeData.actualGas.setPoint_cbar); | |
419 if(gasChangeListDepthGas20x2 && (pDiveState->diveSettings.diveMode == DIVEMODE_OC)) | |
420 { | |
421 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->lifeData.depth_meter; | |
422 gasChangeListDepthGas20x2[ptrGasChangeList++] = actualBetterGasId(); | |
423 } | |
424 } | |
425 } | |
426 | |
427 decom_CreateGasChangeList(&pDiveState->diveSettings, &pDiveState->lifeData); // was there before and needed for buehlmann_calc_deco and vpm_calc | |
428 | |
429 // new hw 160704 | |
430 if(gasChangeListDepthGas20x2 && (pDiveState->diveSettings.diveMode == DIVEMODE_OC)) | |
431 { | |
432 // change direction from better gas to deco gas | |
433 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255; | |
434 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255; | |
435 | |
436 // ascend (deco) gases | |
437 for(int i=1; i<=5;i++) | |
438 { | |
439 if(pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0) | |
440 break; | |
441 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero; | |
442 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].GasIdInSettings; | |
443 } | |
444 gasChangeListDepthGas20x2[0] = 0; | |
445 } | |
446 | |
447 // deco and ascend calc | |
448 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
449 { | |
450 /* this does modify the cns now 11.06.2015 */ | |
451 buehlmann_calc_deco(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->decolistBuehlmann); | |
452 pDiveState->lifeData.cns += buehlmann_get_gCNS(); | |
453 return &pDiveState->decolistBuehlmann; | |
454 } | |
455 else | |
456 { | |
457 /* this does modify the cns now 11.06.2015 */ | |
458 vpm_calc(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->vpm,&pDiveState->decolistVPM, DECOSTOPS); | |
459 pDiveState->lifeData.cns += vpm_get_CNS(); | |
460 return &pDiveState->decolistVPM; | |
461 } | |
462 } | |
463 | |
464 float sGChelper_bar(uint16_t depth_meter) | |
465 { | |
466 SDiveState * pDiveState = &stateSim; | |
467 float ambient, surface, density, meter; | |
468 | |
469 surface = pDiveState->lifeData.pressure_surface_bar; | |
470 | |
471 if(!depth_meter) | |
472 return surface; | |
473 | |
474 density = ((float)( 100 + settingsGetPointer()->salinity)) / 100.0f; | |
475 meter = depth_meter * (0.09807f * density); | |
476 ambient = (meter + surface); | |
477 | |
478 return ambient; | |
479 } | |
480 | |
481 | |
482 /** | |
483 ****************************************************************************** | |
484 * @brief simulation_helper_change_points | |
485 ****************************************************************************** | |
486 * @param | |
487 * @return void | |
488 */ | |
489 void simulation_helper_change_points(SSimDataSummary *outputSummary, uint16_t depth_meter, uint16_t dive_time_minutes, SDecoinfo *decoInfoInput, const uint8_t *gasChangeListDepthGas20x2) | |
490 { | |
491 uint8_t ptrDecoInfo = 0; | |
492 uint16_t actualDepthPoint = 0; | |
493 uint16_t nextDepthPoint = 0; | |
494 uint8_t actualConsumGasId = 0; | |
495 uint8_t nextGasChangeMeter = 0; | |
496 uint8_t ptrChangeList = 0; | |
497 | |
498 float timeThis = 0; | |
499 float timeSummary = 0; | |
500 float sim_descent_rate_meter_per_min_local = 10; | |
501 float sim_ascent_rate_meter_per_min_local = 10; | |
502 | |
503 SDiveState * pDiveState = &stateSim; | |
504 | |
505 uint8_t depthDecoNext, depthLast, depthSecond, depthInc; | |
506 | |
507 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
508 { | |
509 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
510 sim_ascent_rate_meter_per_min_local = pDiveState->diveSettings.ascentRate_meterperminute; | |
511 } | |
512 else | |
513 { | |
514 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
515 sim_ascent_rate_meter_per_min_local = 10;// fix in vpm_calc_deco(); | |
516 } | |
517 | |
518 outputSummary->descentRateMeterPerMinute = sim_descent_rate_meter_per_min_local; | |
519 outputSummary->ascentRateMeterPerMinute = sim_ascent_rate_meter_per_min_local; | |
520 | |
521 // bottom gas ppO2 | |
522 if(gasChangeListDepthGas20x2) | |
523 { | |
524 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
525 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
526 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
527 | |
528 while(actualDepthPoint < depth_meter) | |
529 { | |
530 if(nextGasChangeMeter && (nextGasChangeMeter < depth_meter) && (gasChangeListDepthGas20x2[ptrChangeList] != 255)) // list has 255,255 for turn from travel to deco | |
531 { | |
532 nextDepthPoint = nextGasChangeMeter; | |
533 } | |
534 else | |
535 { | |
536 nextDepthPoint = depth_meter; | |
537 } | |
538 | |
539 if(actualConsumGasId > 5) // safety first | |
540 actualConsumGasId = 0; | |
541 | |
542 actualDepthPoint = nextDepthPoint; | |
543 | |
544 if(actualDepthPoint != depth_meter) | |
545 { | |
546 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
547 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
548 } | |
549 } | |
550 } | |
551 else | |
552 { | |
553 actualConsumGasId = pDiveState->lifeData.actualGas.GasIdInSettings; | |
554 nextGasChangeMeter = 0; | |
555 } | |
556 outputSummary->ppO2AtBottom = (sGChelper_bar(depth_meter) - WATER_VAPOUR_PRESSURE) * pDiveState->diveSettings.gas[actualConsumGasId].oxygen_percentage / 100.0f; | |
557 | |
558 | |
559 // going down | |
560 actualDepthPoint = 0; | |
561 nextDepthPoint = depth_meter; | |
562 | |
563 timeThis = ((float)(nextDepthPoint - actualDepthPoint)) / sim_descent_rate_meter_per_min_local; | |
564 timeSummary += timeThis; | |
565 outputSummary->timeToBottom = (uint16_t)timeThis; | |
566 | |
567 // bottom time | |
568 timeThis = ((float)dive_time_minutes) - timeSummary; | |
569 timeSummary += timeThis; | |
570 outputSummary->timeAtBottom = (uint16_t)timeSummary; | |
571 | |
572 | |
573 // ascend to first deco stop | |
574 actualDepthPoint = depth_meter; // that is where we are | |
575 timeThis = 0; | |
576 | |
577 if(!decoInfoInput->output_stop_length_seconds[0]) // NDL dive | |
578 { | |
579 depthLast = 0; | |
580 ptrDecoInfo = 0; | |
581 depthDecoNext = 0; | |
582 } | |
583 else | |
584 { | |
585 // prepare deco stop list | |
586 depthLast = (uint8_t)(stateUsed->diveSettings.last_stop_depth_bar * 10); | |
587 depthSecond = (uint8_t)(stateUsed->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
588 depthInc = (uint8_t)(stateUsed->diveSettings.input_next_stop_increment_depth_bar * 10); | |
589 | |
590 for(ptrDecoInfo=DECOINFO_STRUCT_MAX_STOPS-1; ptrDecoInfo>0; ptrDecoInfo--) | |
591 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
592 | |
593 if(ptrDecoInfo == 0) | |
594 { | |
595 depthDecoNext = depthLast; | |
596 } | |
597 else | |
598 depthDecoNext = depthSecond + (( ptrDecoInfo - 1 )* depthInc); | |
599 } | |
600 | |
601 nextDepthPoint = depthDecoNext; | |
602 if(actualDepthPoint > nextDepthPoint) | |
603 { | |
604 // flip signs! It's going up | |
605 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
606 actualDepthPoint = nextDepthPoint; // that is where we are | |
607 } | |
608 timeSummary += timeThis; | |
609 outputSummary->timeToFirstStop = (uint16_t)timeSummary; | |
610 outputSummary->depthMeterFirstStop = actualDepthPoint; | |
611 | |
612 //ascent | |
613 nextDepthPoint = 0; | |
614 timeThis = 0; | |
615 if(actualDepthPoint > nextDepthPoint) // only if deco | |
616 { | |
617 // ascent time | |
618 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
619 | |
620 // deco stop time | |
621 for(ptrDecoInfo=0;ptrDecoInfo < DECOINFO_STRUCT_MAX_STOPS; ptrDecoInfo++) | |
622 { | |
623 timeThis += decoInfoInput->output_stop_length_seconds[ptrDecoInfo] / 60; | |
624 if(!decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
625 } | |
626 } | |
627 timeSummary += timeThis; | |
628 outputSummary->timeToSurface = (uint16_t)timeSummary; | |
629 | |
630 } | |
631 | |
632 | |
633 /** | |
634 ****************************************************************************** | |
635 * @brief simulation_gas_consumption | |
636 ****************************************************************************** | |
637 * @note called by openEdit_PlanResult() in tMenuEditPlanner.c | |
638 * @note the ascend and descend time is taken from pDiveState->lifeData.ascent_rate_meter_per_min and const float sim_descent_rate_meter_per_min | |
639 * @param outputConsumptionList list from 1 to 5 for gas 1 to 5 | |
640 * @param depth_meter for descend | |
641 * @param dive_time_minutes for descend and bottom time | |
642 * @param the calculated deco list | |
643 * @param gasConsumTravelInput: how many l/min for all but deco stops | |
644 * @param gasConsumDecoInput: how many l/min for deco stops only | |
645 * @return void | |
646 */ | |
647 | |
648 void simulation_gas_consumption(uint16_t *outputConsumptionList, uint16_t depth_meter, uint16_t dive_time_minutes, SDecoinfo *decoInfoInput, uint8_t gasConsumTravelInput, uint8_t gasConsumDecoInput, const uint8_t *gasChangeListDepthGas20x2) | |
649 { | |
650 uint8_t ptrDecoInfo = 0; | |
651 uint8_t ptrChangeList = 0; | |
652 uint8_t actualConsumGasId = 0; | |
653 uint8_t nextGasChangeMeter = 0; | |
654 uint16_t actualDepthPoint = 0; | |
655 uint16_t nextDepthPoint = 0; | |
656 uint16_t inBetweenDepthPoint = 0; | |
657 float timeThis = 0; | |
658 float consumThis = 0; | |
659 float timeSummary = 0; | |
660 float outputConsumptionTempFloat[6]; | |
661 float sim_descent_rate_meter_per_min_local = 10; | |
662 float sim_ascent_rate_meter_per_min_local = 10; | |
663 | |
664 SDiveState * pDiveState = &stateSim; | |
665 | |
51
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
666 uint8_t depthDecoNext = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
667 uint8_t depthLast = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
668 uint8_t depthSecond = 0; |
8f8ea3a32e82
Resolved warnings pointing to possible invalid memory access
Ideenmodellierer
parents:
38
diff
changeset
|
669 uint8_t depthInc = 0; |
38 | 670 |
671 for(int i = 1; i < 6; i++) | |
672 outputConsumptionTempFloat[i] = 0; | |
673 | |
674 if(gasChangeListDepthGas20x2) | |
675 { | |
676 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
677 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
678 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
679 } | |
680 else | |
681 { | |
682 actualConsumGasId = pDiveState->lifeData.actualGas.GasIdInSettings; | |
683 nextGasChangeMeter = 0; | |
684 } | |
685 | |
686 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) | |
687 { | |
688 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
689 sim_ascent_rate_meter_per_min_local = pDiveState->diveSettings.ascentRate_meterperminute; | |
690 } | |
691 else | |
692 { | |
693 sim_descent_rate_meter_per_min_local = sim_descent_rate_meter_per_min; // const float | |
694 sim_ascent_rate_meter_per_min_local = 10;// fix in vpm_calc_deco(); | |
695 } | |
696 | |
697 // while((nextGasChangeMeter < depth_meter) && (actualDepthPoint < depth_meter)) | |
698 while(actualDepthPoint < depth_meter) | |
699 { | |
700 if(nextGasChangeMeter && (nextGasChangeMeter < depth_meter) && (gasChangeListDepthGas20x2[ptrChangeList] != 255)) // list has 255,255 for turn from travel to deco | |
701 { | |
702 nextDepthPoint = nextGasChangeMeter; | |
703 } | |
704 else | |
705 { | |
706 nextDepthPoint = depth_meter; | |
707 } | |
708 | |
709 if(actualConsumGasId > 5) // safety first | |
710 actualConsumGasId = 0; | |
711 | |
712 timeThis = ((float)(nextDepthPoint - actualDepthPoint)) / sim_descent_rate_meter_per_min_local; | |
713 if(actualDepthPoint) // not if on surface | |
714 { | |
715 consumThis = ((float)gasConsumTravelInput) * sGChelper_bar(actualDepthPoint) * timeThis; | |
716 } | |
717 consumThis += ((float)gasConsumTravelInput) * sGChelper_bar(nextDepthPoint -actualDepthPoint) * timeThis / 2; | |
718 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
719 timeSummary += timeThis; | |
720 | |
721 actualDepthPoint = nextDepthPoint; | |
722 | |
723 if(actualDepthPoint != depth_meter) | |
724 { | |
725 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
726 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
727 } | |
728 } | |
729 | |
730 // bottom Time | |
731 timeThis = ((float)dive_time_minutes) - timeSummary; | |
732 | |
733 if(timeThis > 0) | |
734 { | |
735 consumThis = ((float)gasConsumTravelInput) * sGChelper_bar(depth_meter) * timeThis; | |
736 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
737 } | |
738 | |
739 // ascend with deco stops prepare | |
740 if(gasChangeListDepthGas20x2) | |
741 { | |
742 ptrChangeList++;// gasChangeListDepthGas20x2[ptrChangeList++]; // should be the 255 | |
743 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
744 } | |
745 else | |
746 { | |
747 nextGasChangeMeter = 0; | |
748 } | |
749 | |
750 | |
751 if(!decoInfoInput->output_stop_length_seconds[0]) // NDL dive | |
752 { | |
753 depthLast = 0; | |
754 ptrDecoInfo = 0; | |
755 } | |
756 else | |
757 { | |
758 // prepare deco stop list | |
759 depthLast = (uint8_t)(stateUsed->diveSettings.last_stop_depth_bar * 10); | |
760 depthSecond = (uint8_t)(stateUsed->diveSettings.input_second_to_last_stop_depth_bar * 10); | |
761 depthInc = (uint8_t)(stateUsed->diveSettings.input_next_stop_increment_depth_bar * 10); | |
762 | |
763 for(ptrDecoInfo=DECOINFO_STRUCT_MAX_STOPS-1; ptrDecoInfo>0; ptrDecoInfo--) | |
764 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break; | |
765 } | |
766 | |
767 actualDepthPoint = depth_meter; // that is where we are | |
768 | |
769 // ascend with deco stops | |
770 while(actualDepthPoint) | |
771 { | |
772 if(ptrDecoInfo == 0) | |
773 { | |
774 depthDecoNext = depthLast; | |
775 } | |
776 else | |
777 depthDecoNext = depthSecond + (( ptrDecoInfo - 1 )* depthInc); | |
778 | |
779 if(nextGasChangeMeter && (nextGasChangeMeter > depthDecoNext)) | |
780 { | |
781 nextDepthPoint = nextGasChangeMeter; | |
782 } | |
783 else | |
784 { | |
785 nextDepthPoint = depthDecoNext; | |
786 } | |
787 | |
788 if(actualConsumGasId > 5) // safety first | |
789 actualConsumGasId = 0; | |
790 | |
791 if(actualDepthPoint > nextDepthPoint) | |
792 { | |
793 // flip signs! It's going up | |
794 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; | |
795 inBetweenDepthPoint = nextDepthPoint + ((actualDepthPoint - nextDepthPoint)/2); | |
796 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(inBetweenDepthPoint) * timeThis; | |
797 /* | |
798 if(nextDepthPoint) | |
799 { | |
800 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(nextDepthPoint) * timeThis; | |
801 } | |
802 else | |
803 { | |
804 consumThis = 0; | |
805 } | |
806 consumThis += ((float)gasConsumDecoInput) * sGChelper_bar(actualDepthPoint - nextDepthPoint) * timeThis / 2; | |
807 */ | |
808 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
809 } | |
810 | |
811 if(nextGasChangeMeter && (nextDepthPoint == nextGasChangeMeter)) | |
812 { | |
813 actualConsumGasId = gasChangeListDepthGas20x2[ptrChangeList++]; | |
814 nextGasChangeMeter = gasChangeListDepthGas20x2[ptrChangeList++]; | |
815 } | |
816 | |
817 if(actualConsumGasId > 5) // safety first | |
818 actualConsumGasId = 0; | |
819 | |
820 if(nextDepthPoint && (nextDepthPoint == depthDecoNext)) | |
821 { | |
822 if(decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) | |
823 { | |
824 timeThis = ((float)(decoInfoInput->output_stop_length_seconds[ptrDecoInfo])) / 60.0f; | |
825 consumThis = ((float)gasConsumDecoInput) * sGChelper_bar(nextDepthPoint) * timeThis; | |
826 outputConsumptionTempFloat[actualConsumGasId] += consumThis; | |
827 } | |
828 if(ptrDecoInfo != 0) | |
829 { | |
830 ptrDecoInfo--; | |
831 } | |
832 else | |
833 { | |
834 depthLast = 0; | |
835 } | |
836 } | |
837 actualDepthPoint = nextDepthPoint; | |
838 } | |
839 | |
840 // copy and return | |
841 for(int i = 1; i < 6; i++) | |
842 outputConsumptionList[i] = (uint16_t)(outputConsumptionTempFloat[i]); | |
843 } | |
844 | |
845 /** | |
846 ****************************************************************************** | |
847 * @brief Simulator control during simulated dive | |
848 ****************************************************************************** | |
849 * @note called by user via tHomeDiveMenuControl() | |
850 * @param void | |
851 * @return void | |
852 */ | |
853 | |
854 | |
855 void Sim_Descend (void) | |
856 { | |
857 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0; | |
858 if(simulation_get_aim_depth() < 200) | |
859 simulation_set_aim_depth(simulation_get_aim_depth() + 1); | |
860 } | |
861 | |
862 | |
863 void Sim_Ascend (void) | |
864 { | |
865 if(simulation_get_aim_depth() > 0) | |
866 simulation_set_aim_depth(simulation_get_aim_depth() - 1); | |
867 } | |
868 | |
869 | |
870 void Sim_Divetime (void) | |
871 { | |
872 simulation_add_time(5); | |
873 } | |
874 | |
875 | |
876 void Sim_Quit (void) | |
877 { | |
878 if(stateSimGetPointer()->lifeData.counterSecondsShallowDepth) | |
879 { | |
880 simulation_exit(); | |
881 return; | |
882 } | |
883 | |
884 if(simulation_get_aim_depth() > 0) | |
885 { | |
886 simulation_set_aim_depth(0); | |
887 } | |
888 else | |
889 { | |
890 stateSimGetPointerWrite()->lifeData.depth_meter = 0; | |
891 if(stateSimGetPointer()->diveSettings.diveMode == DIVEMODE_Apnea) | |
892 { | |
893 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 1; | |
894 } | |
895 else | |
896 { | |
897 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = settingsGetPointer()->timeoutDiveReachedZeroDepth - 15; | |
898 } | |
899 } | |
900 } |