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