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