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