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