comparison Discovery/Src/simulation.c @ 981:c6c781a2e85b default

Merge into default
author heinrichsweikamp
date Tue, 11 Feb 2025 18:12:00 +0100
parents 7149f372b0ba
children 7891160acde3
comparison
equal deleted inserted replaced
871:f7318457df4d 981:c6c781a2e85b
49 //Private state variables 49 //Private state variables
50 static float sim_aim_depth_meter; 50 static float sim_aim_depth_meter;
51 static float sim_aim_time_minutes; 51 static float sim_aim_time_minutes;
52 static _Bool sim_heed_decostops = 1; 52 static _Bool sim_heed_decostops = 1;
53 53
54 static const float sim_descent_rate_meter_per_min = 20; 54 static float sim_descent_rate_meter_per_min = 20;
55
56 static uint16_t* pReplayData; /* pointer to source dive data */
57 static uint8_t simReplayActive = 0;
58
59 static uint16_t simScrubberTimeoutCount = 0;
55 60
56 61
57 //Private functions 62 //Private functions
58 static float sim_get_ambient_pressure(SDiveState * pDiveState); 63 static float sim_get_ambient_pressure(SDiveState * pDiveState);
59 static void sim_reduce_deco_time_one_second(SDiveState* pDiveState); 64 static void sim_reduce_deco_time_one_second(SDiveState* pDiveState);
81 ****************************************************************************** 86 ******************************************************************************
82 * @return void 87 * @return void
83 */ 88 */
84 void simulation_start(int aim_depth, uint16_t aim_time_minutes) 89 void simulation_start(int aim_depth, uint16_t aim_time_minutes)
85 { 90 {
91 uint16_t replayDataLength = 0;
92 uint8_t* pReplayMarker;
93 uint16_t max_depth = 10;
94 uint16_t diveMinutes = 0;
95
86 copyDiveSettingsToSim(); 96 copyDiveSettingsToSim();
87 copyVpmRepetetiveDataToSim(); 97 copyVpmRepetetiveDataToSim();
98
88 //vpm_init(&stateSimGetPointerWrite()->vpm, stateSimGetPointerWrite()->diveSettings.vpm_conservatism, 0, 0); 99 //vpm_init(&stateSimGetPointerWrite()->vpm, stateSimGetPointerWrite()->diveSettings.vpm_conservatism, 0, 0);
89 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0; 100 stateSimGetPointerWrite()->lifeData.counterSecondsShallowDepth = 0;
90 stateSimGetPointerWrite()->mode = MODE_DIVE; 101 stateSimGetPointerWrite()->mode = MODE_DIVE;
91 if(aim_depth <= 0) 102 if(aim_depth <= 0)
92 aim_depth = 20; 103 aim_depth = 20;
104 sim_descent_rate_meter_per_min = 20;
93 simulation_set_aim_depth(aim_depth); 105 simulation_set_aim_depth(aim_depth);
94 sim_aim_time_minutes = aim_time_minutes; 106 sim_aim_time_minutes = aim_time_minutes;
95 timer_init(); 107 timer_init();
96 set_stateUsedToSim(); 108 set_stateUsedToSim();
97 stateSim.lifeData.boolResetAverageDepth = 1; 109 stateSim.lifeData.boolResetAverageDepth = 1;
98 decoLock = DECO_CALC_init_as_is_start_of_dive; 110 decoLock = DECO_CALC_init_as_is_start_of_dive;
99 111
100 stateSim.lifeData.apnea_total_max_depth_meter = 0; 112 stateSim.lifeData.apnea_total_max_depth_meter = 0;
113
114 memcpy(stateSim.scrubberDataDive, settingsGetPointer()->scrubberData, sizeof(stateSim.scrubberDataDive));
101 memset(simSensmVOffset,0,sizeof(simSensmVOffset)); 115 memset(simSensmVOffset,0,sizeof(simSensmVOffset));
116 if(getReplayOffset() != 0xFFFF)
117 {
118 simReplayActive = 1;
119 getReplayInfo(&pReplayData, &pReplayMarker, &replayDataLength, &max_depth, &diveMinutes);
120 }
102 } 121 }
103 122
104 /** 123 /**
105 ****************************************************************************** 124 ******************************************************************************
106 * @brief end of simulation 125 * @brief end of simulation
135 154
136 static int last_second = -1; 155 static int last_second = -1;
137 static _Bool two_second = 0; 156 static _Bool two_second = 0;
138 static float lastPressure_bar = 0; 157 static float lastPressure_bar = 0;
139 158
140 if (sim_aim_time_minutes && sim_aim_time_minutes * 60 <= pDiveState->lifeData.dive_time_seconds) { 159 pSettings = settingsGetPointer();
160
161 if ((sim_aim_time_minutes && sim_aim_time_minutes * 60 <= pDiveState->lifeData.dive_time_seconds)
162 && (!simReplayActive))
163 {
141 simulation_set_aim_depth(0); 164 simulation_set_aim_depth(0);
142 } 165 }
143 166
144 float localCalibCoeff[3] = { 0.0, 0.0, 0.0 }; 167 float localCalibCoeff[3] = { 0.0, 0.0, 0.0 };
145 uint8_t index, index2; 168 uint8_t index, index2;
146 169
147 if(checkOncePerSecond) 170 if(checkOncePerSecond)
148 { 171 {
149 172 int now = current_second();
150 pSettings = settingsGetPointer(); 173 if( last_second == now)
174 return;
175 last_second = now;
176
177 if(!two_second)
178 two_second = 1;
179 else
180 {
181 two_second = 0;
182 }
183
151 for(index = 0; index < 3; index++) 184 for(index = 0; index < 3; index++)
152 { 185 {
153 localCalibCoeff[index] = pSettings->ppo2sensors_calibCoeff[index]; 186 if(pDiveState->lifeData.extIf_sensor_map[index] == SENSOR_DIGO2M)
154 if(localCalibCoeff[index] < 0.01)
155 { 187 {
156 for(index2 = 0; index2 < 3; index2++) /* no valid coeff => check other entries */ 188 localCalibCoeff[index] = 0.01;
157 { 189 }
158 if(pSettings->ppo2sensors_calibCoeff[index2] > 0.01) 190 else
159 { 191 {
160 localCalibCoeff[index] = pSettings->ppo2sensors_calibCoeff[index2]; 192 localCalibCoeff[index] = pSettings->ppo2sensors_calibCoeff[index];
161 break; 193 if(localCalibCoeff[index] < 0.01)
162 } 194 {
163 if(index2 == 3) /* no coeff at all => use default */ 195 for(index2 = 0; index2 < 3; index2++) /* no valid coeff => check other entries */
164 { 196 {
165 localCalibCoeff[index] = 0.02; 197 if(pSettings->ppo2sensors_calibCoeff[index2] > 0.01)
166 } 198 {
167 } 199 localCalibCoeff[index] = pSettings->ppo2sensors_calibCoeff[index2];
200 break;
201 }
202 if(index2 == 3) /* no coeff at all => use default */
203 {
204 localCalibCoeff[index] = 0.02;
205 }
206 }
207 }
168 } 208 }
169 } 209 }
170 210
171 pDiveState->lifeData.temperature_celsius = pRealState->lifeData.temperature_celsius; 211 pDiveState->lifeData.temperature_celsius = pRealState->lifeData.temperature_celsius;
172 pDiveState->lifeData.battery_charge = pRealState->lifeData.battery_charge; 212 pDiveState->lifeData.battery_charge = pRealState->lifeData.battery_charge;
181 221
182 #ifdef ENABLE_BOTTLE_SENSOR 222 #ifdef ENABLE_BOTTLE_SENSOR
183 pDiveState->lifeData.bottle_bar[pDiveState->lifeData.actualGas.GasIdInSettings] = pRealState->lifeData.bottle_bar[pRealState->lifeData.actualGas.GasIdInSettings]; 223 pDiveState->lifeData.bottle_bar[pDiveState->lifeData.actualGas.GasIdInSettings] = pRealState->lifeData.bottle_bar[pRealState->lifeData.actualGas.GasIdInSettings];
184 pDiveState->lifeData.bottle_bar_age_MilliSeconds[pDiveState->lifeData.actualGas.GasIdInSettings] = pRealState->lifeData.bottle_bar_age_MilliSeconds[pRealState->lifeData.actualGas.GasIdInSettings]; 224 pDiveState->lifeData.bottle_bar_age_MilliSeconds[pDiveState->lifeData.actualGas.GasIdInSettings] = pRealState->lifeData.bottle_bar_age_MilliSeconds[pRealState->lifeData.actualGas.GasIdInSettings];
185 #endif 225 #endif
186 int now = current_second();
187 if( last_second == now)
188 return;
189 last_second = now;
190
191 if(!two_second)
192 two_second = 1;
193 else
194 {
195 two_second = 0;
196 if(lastPressure_bar >= 0)
197 {
198 //2 seconds * 30 == 1 minute, bar * 10 = meter
199 pDiveState->lifeData.ascent_rate_meter_per_min = (lastPressure_bar - pDiveState->lifeData.pressure_ambient_bar) * 30 * 10;
200 }
201 lastPressure_bar = pDiveState->lifeData.pressure_ambient_bar;
202 }
203 } 226 }
204 else if(pDiveState->lifeData.depth_meter <= (float)(decom_get_actual_deco_stop(pDiveState) + 0.001)) 227 else if(pDiveState->lifeData.depth_meter <= (float)(decom_get_actual_deco_stop(pDiveState) + 0.001))
205 sim_reduce_deco_time_one_second(pDiveState); 228 {
229 if(decoLock == DECO_CALC_FINSHED_vpm)
230 {
231 sim_reduce_deco_time_one_second(&stateDeco);
232 }
233 else
234 {
235 sim_reduce_deco_time_one_second(pDiveState);
236 }
237 }
206 238
207 pDiveState->lifeData.dive_time_seconds += 1; 239 pDiveState->lifeData.dive_time_seconds += 1;
208 pDiveState->lifeData.pressure_ambient_bar = sim_get_ambient_pressure(pDiveState); 240 pDiveState->lifeData.pressure_ambient_bar = sim_get_ambient_pressure(pDiveState);
241 if(pDiveState->lifeData.depth_meter < 1.5)
242 {
243 lastPressure_bar = 0;
244 pDiveState->lifeData.ascent_rate_meter_per_min = 0;
245 }
246
247 if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (isLoopMode(pSettings->dive_mode)) && (pDiveState->mode == MODE_DIVE) && isLoopMode(pDiveState->diveSettings.diveMode))
248 {
249 simScrubberTimeoutCount++;
250 if(simScrubberTimeoutCount >= 60) /* resolution is minutes */
251 {
252 simScrubberTimeoutCount = 0;
253 if(pDiveState->scrubberDataDive[pSettings->scubberActiveId].TimerCur > MIN_SCRUBBER_TIME)
254 {
255 pDiveState->scrubberDataDive[pSettings->scubberActiveId].TimerCur--;
256 }
257 translateDate(stateUsed->lifeData.dateBinaryFormat, &pDiveState->scrubberDataDive[pSettings->scubberActiveId].lastDive);
258 }
259 }
260
261
262 if(lastPressure_bar > 0)
263 {
264 //1 second * 60 == 1 minute, bar * 10 = meter
265 pDiveState->lifeData.ascent_rate_meter_per_min = (lastPressure_bar - pDiveState->lifeData.pressure_ambient_bar) * 600.0;
266 }
267 lastPressure_bar = pDiveState->lifeData.pressure_ambient_bar;
209 268
210 pDiveState->lifeData.sensorVoltage_mV[0] = pRealState->lifeData.sensorVoltage_mV[0] + simSensmVOffset[0]; 269 pDiveState->lifeData.sensorVoltage_mV[0] = pRealState->lifeData.sensorVoltage_mV[0] + simSensmVOffset[0];
211 if(pDiveState->lifeData.sensorVoltage_mV[0] < 0.0) { pDiveState->lifeData.sensorVoltage_mV[0] = 0.0; } 270 if(pDiveState->lifeData.sensorVoltage_mV[0] < 0.0) { pDiveState->lifeData.sensorVoltage_mV[0] = 0.0; }
212 pDiveState->lifeData.sensorVoltage_mV[1] = pRealState->lifeData.sensorVoltage_mV[1] + simSensmVOffset[1]; 271 pDiveState->lifeData.sensorVoltage_mV[1] = pRealState->lifeData.sensorVoltage_mV[1] + simSensmVOffset[1];
213 if(pDiveState->lifeData.sensorVoltage_mV[1] < 0.0) { pDiveState->lifeData.sensorVoltage_mV[1] = 0.0; } 272 if(pDiveState->lifeData.sensorVoltage_mV[1] < 0.0) { pDiveState->lifeData.sensorVoltage_mV[1] = 0.0; }
347 { 406 {
348 //Calc next depth 407 //Calc next depth
349 uint8_t actual_deco_stop = decom_get_actual_deco_stop(pDiveState); 408 uint8_t actual_deco_stop = decom_get_actual_deco_stop(pDiveState);
350 float depth_meter = pDiveState->lifeData.depth_meter; 409 float depth_meter = pDiveState->lifeData.depth_meter;
351 float surface_pressure_bar = pDiveState->lifeData.pressure_surface_bar; 410 float surface_pressure_bar = pDiveState->lifeData.pressure_surface_bar;
411 static uint8_t sampleToggle = 0;
412 static float sim_ascent_rate_meter_per_min_local = 0;
413 uint8_t sampleTime = getReplayDataResolution();
414
415 if(simReplayActive) /* precondition: function is called once per second, sample rate is a multiple of second */
416 {
417 if(sampleToggle == 0)
418 {
419 sampleToggle = sampleTime - 1;
420 sim_aim_depth_meter = (float)(*pReplayData++/100.0);
421 if(sim_aim_depth_meter > depth_meter)
422 {
423 sim_descent_rate_meter_per_min = (sim_aim_depth_meter - depth_meter) * (60 / sampleTime);
424 }
425 else
426 {
427 sim_ascent_rate_meter_per_min_local = (depth_meter - sim_aim_depth_meter) * (60 / sampleTime);
428 }
429 }
430 else
431 {
432 sampleToggle--;
433 }
434 }
435 else
436 {
437 sim_ascent_rate_meter_per_min_local = pDiveState->diveSettings.ascentRate_meterperminute;
438 }
439
352 if(depth_meter < sim_aim_depth_meter) 440 if(depth_meter < sim_aim_depth_meter)
353 { 441 {
354 depth_meter = depth_meter + sim_descent_rate_meter_per_min / 60; 442 depth_meter = depth_meter + sim_descent_rate_meter_per_min / 60;
355 if(depth_meter > sim_aim_depth_meter) 443 if(depth_meter > sim_aim_depth_meter)
356 depth_meter = sim_aim_depth_meter; 444 depth_meter = sim_aim_depth_meter;
357 } 445 }
358 else if(depth_meter > sim_aim_depth_meter) 446 else if(depth_meter > sim_aim_depth_meter)
359 { 447 {
360 448
361 depth_meter -= pDiveState->diveSettings.ascentRate_meterperminute / 60; 449 depth_meter -= sim_ascent_rate_meter_per_min_local / 60;
362 if(depth_meter < sim_aim_depth_meter) 450 if(depth_meter < sim_aim_depth_meter)
363 depth_meter = sim_aim_depth_meter; 451 depth_meter = sim_aim_depth_meter;
364 452
365 if(sim_heed_decostops && depth_meter < actual_deco_stop) 453 if(sim_heed_decostops && depth_meter < actual_deco_stop)
366 { 454 {
367 if(actual_deco_stop < (depth_meter + pDiveState->diveSettings.ascentRate_meterperminute / 60)) 455 if(actual_deco_stop < (depth_meter + sim_ascent_rate_meter_per_min_local / 60))
368 depth_meter = actual_deco_stop; 456 depth_meter = actual_deco_stop;
369 else 457 else
370 depth_meter += pDiveState->diveSettings.ascentRate_meterperminute / 60; 458 depth_meter += sim_ascent_rate_meter_per_min_local / 60;
371 } 459 }
372 460
373 } 461 }
374 462
375 return surface_pressure_bar + depth_meter / 10; 463 return surface_pressure_bar + depth_meter / 10;
385 * @return void 473 * @return void
386 */ 474 */
387 static void sim_reduce_deco_time_one_second(SDiveState* pDiveState) 475 static void sim_reduce_deco_time_one_second(SDiveState* pDiveState)
388 { 476 {
389 SDecoinfo* pDecoinfo; 477 SDecoinfo* pDecoinfo;
478 int8_t index = 0;
479
480
390 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE) 481 if(pDiveState->diveSettings.deco_type.ub.standard == GF_MODE)
391 pDecoinfo = &pDiveState->decolistBuehlmann; 482 pDecoinfo = &pDiveState->decolistBuehlmann;
392 else 483 else
393 pDecoinfo = &pDiveState->decolistVPM; 484 pDecoinfo = &pDiveState->decolistVPM;
394 485
395 //Reduce deco time of deepest stop by one second 486 //Reduce deco time of deepest stop by one second
396 for(int i = DECOINFO_STRUCT_MAX_STOPS -1 ;i >= 0; i--) 487 for(index = DECOINFO_STRUCT_MAX_STOPS -1 ;index >= 0; index--)
397 { 488 {
398 if(pDecoinfo->output_stop_length_seconds[i] > 0) 489 if(pDecoinfo->output_stop_length_seconds[index] > 0)
399 { 490 {
400 pDecoinfo->output_stop_length_seconds[i]--; 491 pDecoinfo->output_stop_length_seconds[index]--;
401 break; 492 break;
402 } 493 }
403 } 494 }
495 /* update TTS */
496 if(pDecoinfo->output_time_to_surface_seconds)
497 {
498 pDecoinfo->output_time_to_surface_seconds--;
499 }
404 } 500 }
405 501
406 SDecoinfo* simulation_decoplaner(uint16_t depth_meter, uint16_t intervall_time_minutes, uint16_t dive_time_minutes, uint8_t *gasChangeListDepthGas20x2) 502 SDecoinfo* simulation_decoplaner(uint16_t depth_meter, uint16_t intervall_time_minutes, uint16_t dive_time_minutes, uint8_t *gasChangeListDepthGas20x2)
407 { 503 {
408 uint8_t ptrGasChangeList = 0; // new hw 160704 504 uint8_t ptrGasChangeList = 0; // new hw 160704
409 505 #ifdef ENABLE_DECOCALC_OPTION
506 uint8_t index = 0;
507 #endif
410 for (int i = 0; i < 40; i++) 508 for (int i = 0; i < 40; i++)
411 gasChangeListDepthGas20x2[i] = 0; 509 gasChangeListDepthGas20x2[i] = 0;
412 510
413 SDiveState * pDiveState = &stateSim; 511 SDiveState * pDiveState = &stateSim;
414 copyDiveSettingsToSim(); 512 copyDiveSettingsToSim();
513
514 #ifdef ENABLE_DECOCALC_OPTION
515 /* activate deco calculation for all deco gases */
516 for(index = 0; index < 1 + (2*NUM_GASES); index++)
517 {
518 if(pDiveState->diveSettings.gas[index].note.ub.deco)
519 {
520 pDiveState->diveSettings.gas[index].note.ub.decocalc = 1;
521 }
522 }
523 #endif
524
415 vpm_init(&pDiveState->vpm, pDiveState->diveSettings.vpm_conservatism, 0, 0); 525 vpm_init(&pDiveState->vpm, pDiveState->diveSettings.vpm_conservatism, 0, 0);
416 //buehlmann_init(); 526 //buehlmann_init();
417 //timer_init(); 527 //timer_init();
418 memset(&pDiveState->events,0, sizeof(SEvents)); 528 memset(&pDiveState->events,0, sizeof(SEvents));
419 pDiveState->diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0; 529 pDiveState->diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0;
464 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255; 574 gasChangeListDepthGas20x2[ptrGasChangeList++] = 255;
465 575
466 // ascend (deco) gases 576 // ascend (deco) gases
467 for(int i=1; i<=5;i++) 577 for(int i=1; i<=5;i++)
468 { 578 {
469 if(pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0) 579 if((pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero == 0)
580 #ifdef ENABLE_DECOCALC_OPTION
581 || (pDiveState->diveSettings.gas[pDiveState->diveSettings.decogaslist[i].GasIdInSettings].note.ub.decocalc == 0)
582 #endif
583 )
470 break; 584 break;
471 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero; 585 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].change_during_ascent_depth_meter_otherwise_zero;
472 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].GasIdInSettings; 586 gasChangeListDepthGas20x2[ptrGasChangeList++] = pDiveState->diveSettings.decogaslist[i].GasIdInSettings;
473 } 587 }
474 gasChangeListDepthGas20x2[0] = 0; 588 gasChangeListDepthGas20x2[0] = 0;
485 else 599 else
486 { 600 {
487 /* this does modify the cns now 11.06.2015 */ 601 /* this does modify the cns now 11.06.2015 */
488 vpm_calc(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->vpm,&pDiveState->decolistVPM, DECOSTOPS); 602 vpm_calc(&pDiveState->lifeData,&pDiveState->diveSettings,&pDiveState->vpm,&pDiveState->decolistVPM, DECOSTOPS);
489 pDiveState->lifeData.cns += vpm_get_CNS(); 603 pDiveState->lifeData.cns += vpm_get_CNS();
604
605 while(decoLock == DECO_CALC_FINSHED_vpm)
606 {
607 HAL_Delay(2); /* The deco data is copied during the timer ISR => wait till this has happened */
608 }
490 return &pDiveState->decolistVPM; 609 return &pDiveState->decolistVPM;
491 } 610 }
492 } 611 }
493 612
494 static float sGChelper_bar(uint16_t depth_meter) 613 static float sGChelper_bar(uint16_t depth_meter)
637 } 756 }
638 timeSummary += timeThis; 757 timeSummary += timeThis;
639 outputSummary->timeToFirstStop = (uint16_t)timeSummary; 758 outputSummary->timeToFirstStop = (uint16_t)timeSummary;
640 outputSummary->depthMeterFirstStop = actualDepthPoint; 759 outputSummary->depthMeterFirstStop = actualDepthPoint;
641 760
642 //ascent 761 if(decoInfoInput->output_time_to_surface_seconds)
643 nextDepthPoint = 0; 762 {
644 timeThis = 0; 763 outputSummary->timeToSurface = outputSummary->timeAtBottom + (decoInfoInput->output_time_to_surface_seconds / 60);
645 if(actualDepthPoint > nextDepthPoint) // only if deco 764 }
646 { 765 else
647 // ascent time 766 {
648 timeThis = ((float)(actualDepthPoint - nextDepthPoint)) / sim_ascent_rate_meter_per_min_local; 767 outputSummary->timeToSurface = outputSummary->timeToFirstStop;
649 768 }
650 // deco stop time
651 for(ptrDecoInfo=0;ptrDecoInfo < DECOINFO_STRUCT_MAX_STOPS; ptrDecoInfo++)
652 {
653 timeThis += decoInfoInput->output_stop_length_seconds[ptrDecoInfo] / 60;
654 if(!decoInfoInput->output_stop_length_seconds[ptrDecoInfo]) break;
655 }
656 }
657 timeSummary += timeThis;
658 outputSummary->timeToSurface = (uint16_t)timeSummary;
659
660 } 769 }
661 770
662 771
663 /** 772 /**
664 ****************************************************************************** 773 ******************************************************************************