comparison src/p2_deco.c @ 628:cd58f7fc86db

3.05 stable work
author heinrichsweikamp
date Thu, 19 Sep 2019 12:01:29 +0200
parents c40025d8e750
children 237931377539
comparison
equal deleted inserted replaced
627:bf5fee575701 628:cd58f7fc86db
1 // *************************************************************************** 1 // ***************************************************************************
2 // p2_deco.c combined next generation V3.03.4 2 // p2_deco.c combined next generation V3.04.3
3 // 3 //
4 // Created on: 12.05.2009 4 // Created on: 12.05.2009
5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others 5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others
6 // 6 //
7 // *************************************************************************** 7 // ***************************************************************************
102 // ********************************************************************************************************************************* 102 // *********************************************************************************************************************************
103 103
104 104
105 // deco engine scheduling 105 // deco engine scheduling
106 #define INVOKES_PER_SECOND 2 // number of invocations of the deco engine per second (use powers of 2 only: 1, 2, 4, ...) 106 #define INVOKES_PER_SECOND 2 // number of invocations of the deco engine per second (use powers of 2 only: 1, 2, 4, ...)
107
108 #ifdef _hwos_sport
109 #define BUDGET_PER_SECOND 320 // [ms] total time budget per second for the deco engine, each invocation will preempt after BUDGET_PER_SECOND / INVOKES_PER_SECOND
110 #else
107 #define BUDGET_PER_SECOND 640 // [ms] total time budget per second for the deco engine, each invocation will preempt after BUDGET_PER_SECOND / INVOKES_PER_SECOND 111 #define BUDGET_PER_SECOND 640 // [ms] total time budget per second for the deco engine, each invocation will preempt after BUDGET_PER_SECOND / INVOKES_PER_SECOND
108 112 #endif
109 113
110 // ambient pressure at different mountain heights 114 // ambient pressure at different mountain heights
111 #define P_ambient_1000m 0.880 // [bar] based on 990 hPa and 20°C at sea level, 15°C at altitude 115 #define P_ambient_1000m 0.880 // [bar] based on 990 hPa and 20°C at sea level, 15°C at altitude
112 #define P_ambient_2000m 0.782 // [bar] 116 #define P_ambient_2000m 0.782 // [bar]
113 #define P_ambient_3000m 0.695 // [bar] 117 #define P_ambient_3000m 0.695 // [bar]
124 #define BAR_TO_METER 10.0150 // conversion factor (1.0/METER_TO_BAR) 128 #define BAR_TO_METER 10.0150 // conversion factor (1.0/METER_TO_BAR)
125 #define SURFACE_DESAT_FACTOR 0.70420 // surface desaturation safety factor 129 #define SURFACE_DESAT_FACTOR 0.70420 // surface desaturation safety factor
126 #define HYST 1.0E-06 // threshold for tissue graphics on-gassing / off-gassing visualization 130 #define HYST 1.0E-06 // threshold for tissue graphics on-gassing / off-gassing visualization
127 131
128 // thresholds 132 // thresholds
129 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning 133 #define CNS_LIMIT_WARNING 100 // threshold for CNS warning
130 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention 134 #define CNS_LIMIT_ATTENTION 70 // threshold for CNS attention
131 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar]
132 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention [1.00 = 100%]
133 #define PRESSURE_LIMIT_WARNING 200 // threshold for pressure reading warning : 20.0 bar 135 #define PRESSURE_LIMIT_WARNING 200 // threshold for pressure reading warning : 20.0 bar
134 #define PRESSURE_LIMIT_ATTENTION 500 // threshold for pressure reading attention: 50.0 bar 136 #define PRESSURE_LIMIT_ATTENTION 500 // threshold for pressure reading attention: 50.0 bar
137 #define GAS_NEEDS_LIMIT_ATTENTION 0.70 // threshold for gas needs attention [1.00 = 100%]
135 #define O2_CONSUMPTION_LIMIT_ATTENTION 20 // threshold for O2 "SAC" attention: 2.0 l/min 138 #define O2_CONSUMPTION_LIMIT_ATTENTION 20 // threshold for O2 "SAC" attention: 2.0 l/min
139 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar]
136 #define ppO2_MARGIN_ON_MAX 3 // [cbar] margin on ppO2 max to compensate for surface pressures > 1.000 mbar 140 #define ppO2_MARGIN_ON_MAX 3 // [cbar] margin on ppO2 max to compensate for surface pressures > 1.000 mbar
141 #define STOP_CHAINING_LIMIT 5 // max. number of chained stop table entries before deco calculation is aborted
142
137 143
138 // deco engine states and modes - (char_O_)main_status: controls current tissue and deco status calculation (as-is situation) 144 // deco engine states and modes - (char_O_)main_status: controls current tissue and deco status calculation (as-is situation)
139 #define CALC_VOLUME 0x01 // =1: calculate gas needs 145 #define CALC_VOLUME 0x01 // =1: calculate gas needs
140 #define CALCULATE_BOTTOM 0x02 // =1: calculate gas needs in deco calculator mode, =0: in dive mode 146 #define CALCULATE_BOTTOM 0x02 // =1: calculate gas needs in deco calculator mode, =0: in dive mode
141 #define CAVE_MODE 0x04 // =1: calculate ascent and gas needs using backtracking data 147 #define CAVE_MODE 0x04 // =1: calculate ascent and gas needs using backtracking data
160 #define CALC_ALT 0x02 // internal: calculating an alternative deco plan 166 #define CALC_ALT 0x02 // internal: calculating an alternative deco plan
161 #define COMPLETED_ALT 0x02 // output: calculation of an alternative deco plan has completed 167 #define COMPLETED_ALT 0x02 // output: calculation of an alternative deco plan has completed
162 #define INITIALIZE 0x04 // input: initialize deco engine 168 #define INITIALIZE 0x04 // input: initialize deco engine
163 #define INITIALIZE_START_NORM 0x05 // input: initialize deco engine and start calculation of a normal deco plan 169 #define INITIALIZE_START_NORM 0x05 // input: initialize deco engine and start calculation of a normal deco plan
164 #define INITIALIZE_START_ALT 0x06 // input: initialize deco engine and start calculation of an alternative deco plan 170 #define INITIALIZE_START_ALT 0x06 // input: initialize deco engine and start calculation of an alternative deco plan
165 // 0x08 // unused - reserved for further deco engine commands 171 #define DECO_CALCULATOR_MODE 0x08 // input: deco engine is run from deco calculator
166 172
167 #define BAILOUT_MODE 0x10 // =1: allow gas switches before first deco stop 173 #define BAILOUT_MODE 0x10 // =1: allow gas switches before first deco stop
168 #define DELAYED_ASCENT 0x20 // =1: figure in a delayed ascent (fTTS) 174 #define DELAYED_ASCENT 0x20 // =1: figure in a delayed ascent (fTTS)
169 175
170 // MODE_MASK 0xC0 // mask for simulated tissues mode selection 176 // MODE_MASK 0xC0 // mask for simulated tissues mode selection
179 #define DECO_WARNING_MBUBBLES 0x04 // micro bubbles likely to develop now 185 #define DECO_WARNING_MBUBBLES 0x04 // micro bubbles likely to develop now
180 #define DECO_WARNING_MBUBBLES_lock 0x08 // ditto, but sometime during the dive 186 #define DECO_WARNING_MBUBBLES_lock 0x08 // ditto, but sometime during the dive
181 #define DECO_WARNING_OUTSIDE 0x10 // tissue pressures outside the Buhlmann model now 187 #define DECO_WARNING_OUTSIDE 0x10 // tissue pressures outside the Buhlmann model now
182 #define DECO_WARNING_OUTSIDE_lock 0x20 // tissue pressures outside the model sometime during the dive 188 #define DECO_WARNING_OUTSIDE_lock 0x20 // tissue pressures outside the model sometime during the dive
183 #define DECO_ATTENTION_OUTSIDE 0x40 // tissue pressures are very close to the Buhlmann limit 189 #define DECO_ATTENTION_OUTSIDE 0x40 // tissue pressures are very close to the Buhlmann limit
184 #define DECO_WARNING_STOPTABLE_OVERFLOW 0x80 // internal error: no more space in the deco stops table 190 #define DECO_WARNING_INCOMPLETE 0x80 // internal error: deco calculation incomplete
185 191
186 // deco engine status (char_O_)deco_info 192 // deco engine status (char_O_)deco_info
187 #define DECO_FLAG 0x01 // =1: deco ppO2 levels are permitted 193 #define DECO_MODE 0x01 // =1: deco ppO2 levels are permitted
188 #define IND_DOUBLE_SWITCH_FLAG 0x02 // =1: switch to other tank advice active 194 #define IND_DOUBLE_SWITCH_FLAG 0x02 // =1: switch to other tank advice active
189 // 0x04 // --- unused 195 // 0x04 // --- unused
190 #define DECO_ZONE 0x08 // =1: fTTS < TTS (not updated when in bailout mode) 196 #define DECO_ZONE 0x08 // =1: fTTS < TTS (not updated when in bailout mode)
191 #define DECO_CEILING 0x10 // =1: ceiling depth > 0 197 #define DECO_CEILING 0x10 // =1: ceiling depth > 0
192 #define DECO_STOPS 0x20 // =1: deco stops found 198 #define DECO_STOPS 0x20 // =1: deco stops found
200 206
201 207
202 // deco engine control - next_planning_phase 208 // deco engine control - next_planning_phase
203 #define PHASE_00_DONE 0x00 // calculation cycle finished 209 #define PHASE_00_DONE 0x00 // calculation cycle finished
204 #define PHASE_10_DIVE_INIT 0x10 // once-per-dive initialization of the deco engine 210 #define PHASE_10_DIVE_INIT 0x10 // once-per-dive initialization of the deco engine
205 #define PHASE_11_CYCLIC_INIT 0x11 // once-every-cycle initialization of the deco engine 211 #define PHASE_20_CYCLIC_INIT 0x20 // once-every-cycle initialization of the deco engine
206 #define PHASE_20_EXTENDED_BOTTOM_TIME 0x20 // calculate extended bottom time 212 #define PHASE_30_EXTENDED_BOTTOM_TIME 0x30 // calculate extended bottom time
207 #define PHASE_30_NDL_TIME 0x30 // calculate NDL time 213 #define PHASE_40_BOTTOM_GAS_NEED 0x40 // calculate gas needs for bottom segment
208 #define PHASE_40_CAVE_ASCENT 0x40 // calculate cave mode return/ascent 214 #define PHASE_50_NDL_TIME 0x50 // calculate NDL time
209 #define PHASE_60_DECO_ASCENT 0x60 // calculate open water deco ascent 215 #define PHASE_60_CAVE_RETURN 0x60 // calculate cave mode return
210 #define PHASE_70_RESULTS 0x70 // results - initialization 216 #define PHASE_70_OPEN_WATER_ASCENT 0x70 // calculate open water ascent
211 #define PHASE_71_RESULTS_STOPS_TABLE 0x71 // results - publish stops table 217 #define PHASE_80_RESULTS 0x80 // results - initialization
212 #define PHASE_72_RESULTS_NDL 0x72 // results - publish data / within NDL 218 #define PHASE_81_RESULTS_STOPS_TABLE 0x81 // results - publish stops table
213 #define PHASE_73_RESULTS_DECO 0x73 // results - publish data / in deco 219 #define PHASE_82_RESULTS_NDL 0x82 // results - publish data / within NDL
214 #define PHASE_80_GAS_NEEDS_SWITCHES 0x80 // calculate gas needs - find gas switches in NDL bailout mode 220 #define PHASE_83_RESULTS_DECO 0x83 // results - publish data / in deco
215 #define PHASE_81_GAS_NEEDS_ASCENT 0x81 // calculate gas needs - needs of bottom segment and ascent 221 #define PHASE_84_GAS_NEEDS_PRESSURES 0x84 // results - convert gas needs from volumes to pressures
216 #define PHASE_82_GAS_NEEDS_PRESSURES 0x82 // calculate gas needs - conversion from volumes to pressures
217 #define PHASE_90_FINISH 0x90 // finish calculation cycle 222 #define PHASE_90_FINISH 0x90 // finish calculation cycle
218
219
220 // gas needs calculation - gas_needs_next_phase
221 #define GAS_NEEDS_INIT 0x00 // initialization
222 #define GAS_NEEDS_BOTTOM_SEGMENT 0x10 // demand during bottom segment
223 #define GAS_NEEDS_INITIAL_ASCENT 0x20 // demand of initial ascent
224 #define GAS_NEEDS_STOP 0x30 // demand on a stop
225 #define GAS_NEEDS_INTERMEDIATE_ASCENT 0x40 // demand on ascent between two stops
226 #define GAS_NEEDS_FINAL_ASCENT 0x50 // demand during final ascent
227 #define GAS_NEEDS_DONE 0x60 // calculation finished
228 223
229 224
230 // flags used with integer numbers 225 // flags used with integer numbers
231 #define INT_FLAG_INVALID 0x0400 // =1: value not valid 226 #define INT_FLAG_INVALID 0x0400 // =1: value not valid
232 #define INT_FLAG_NOT_COMPUTED_YET 0x0800 // =1: value not computed yet 227 #define INT_FLAG_NOT_COMPUTED_YET 0x0800 // =1: value not computed yet
263 static void calc_hauptroutine_data_input(void);// Initializes environment data and sets gas ratios for the real tissues. 258 static void calc_hauptroutine_data_input(void);// Initializes environment data and sets gas ratios for the real tissues.
264 259
265 // Functions combined for real Tissues & Deco Calculations 260 // Functions combined for real Tissues & Deco Calculations
266 static void calc_alveolar_pressures(void); // Computes the partial pressures from the gas ratios and many more parameters, 261 static void calc_alveolar_pressures(void); // Computes the partial pressures from the gas ratios and many more parameters,
267 // needs either calc_hauptroutine_data_input() be called beforehand or 262 // needs either calc_hauptroutine_data_input() be called beforehand or
268 // gas_find_current()/gas_find_better() and gas_set_ratios(). 263 // gas_take_current() or gas_find_best()/gas_take_best() and gas_set_ratios().
269 static void calc_tissues(void); // Updates the tissues dependent on the partial pressures of N2 and He. 264 static void calc_tissues(void); // Updates the tissues dependent on the partial pressures of N2 and He.
270 static void calc_CNS(void); // Updates the CNS value dependent on the partial pressure of the O2. 265 static void calc_CNS(void); // Updates the CNS value dependent on the partial pressure of the O2.
271 static void calc_limit(PARAMETER float GF_current); 266 static void calc_limit(PARAMETER float GF_current);
272 // Calculates ceiling, current GF (supersaturation) and some more data. 267 // Calculates ceiling, current GF (supersaturation) and some more data.
273 268
276 static void calc_TR_functions(void); // Calculates SAC etc. 271 static void calc_TR_functions(void); // Calculates SAC etc.
277 #endif 272 #endif
278 273
279 // Functions dedicated to Deco Calculations 274 // Functions dedicated to Deco Calculations
280 static void clear_deco_table(void); // Clears the deco stops table, invoked at the start of each calculation cycle. 275 static void clear_deco_table(void); // Clears the deco stops table, invoked at the start of each calculation cycle.
281 static void gas_find_current(void); // Sets the first gas used for deco calculation, invoked at start of cycle, too. 276 static void gas_take_current(void); // Sets the first gas used for deco calculation, invoked at start of cycle, too.
282 static unsigned char gas_find_better(void); // Checks for, and eventually switches to, a better gas. 277 static unsigned char gas_find_best(void); // Searches for the best gas available.
278 static void gas_take_best(void); // Switches to the best gas that has been found found before by gas_find_best().
283 static void gas_set_ratios(void); // Sets the gas ratios for use in deco calculation (simulated tissues), 279 static void gas_set_ratios(void); // Sets the gas ratios for use in deco calculation (simulated tissues),
284 // needs to be called after each gas change (gas_find_current/_better). 280 // needs to be called after each gas change (gas_take_current/_better).
285 static void calc_NDL_time_tissue(void); // Calculates the remaining NDL time for a given tissue. 281 static void calc_NDL_time_tissue(void); // Calculates the remaining NDL time for a given tissue.
286 static void find_NDL_gas_changes(void); // Finds the gas changes in an OC bailout ascent that is within NDL.
287 static unsigned char find_next_stop(void); // Finds the next stop when in a deco ascent. 282 static unsigned char find_next_stop(void); // Finds the next stop when in a deco ascent.
288 static unsigned char update_deco_table(PARAMETER unsigned char time_increment); 283 static unsigned char update_deco_table(PARAMETER unsigned char time_increment);
289 // Enters a new stop or extends an existing stop in the deco stops table. 284 // Enters a new stop or extends an existing stop in the deco stops table.
290 static void calc_ascenttime(void); // Calculates the ascent time from current depth and deco stop times.
291 static void calc_gas_needs_ascent(void); // Calculates required gas volumes and pressures from the data in stops table.
292 static void calc_due_by_depth_time_sac(void); // Calculates gas volume required for a given depth, time and usage (SAC rate). 285 static void calc_due_by_depth_time_sac(void); // Calculates gas volume required for a given depth, time and usage (SAC rate).
293 static void convert_gas_needs_to_press(void); // Converts gas volumes into pressures and sets respective flags. 286 static void convert_gas_needs_to_press(void); // Converts gas volumes into pressures and sets respective flags.
294 287
295 // Functions for Results Reporting 288 // Functions for Results Reporting
296 static void publish_deco_table(void); // Copies the internal deco stops table to the export interface. 289 static void publish_deco_table(void); // Copies the internal deco stops table to the export interface.
310 // Reads pre-computed tissue increment factors from a ROM table. 303 // Reads pre-computed tissue increment factors from a ROM table.
311 static void read_Buhlmann_ht(void); // Reads the half-times from a ROM table. 304 static void read_Buhlmann_ht(void); // Reads the half-times from a ROM table.
312 static void adopt_Buhlmann_coefficients(void); // Computes average a and b coefficient by the N2/He tissue ratio. 305 static void adopt_Buhlmann_coefficients(void); // Computes average a and b coefficient by the N2/He tissue ratio.
313 static void push_tissues_to_vault(void); // Stores the state of the real tissues during simulator runs. 306 static void push_tissues_to_vault(void); // Stores the state of the real tissues during simulator runs.
314 static void pull_tissues_from_vault(void); // Restores the state of the real tissues after a simulator run. 307 static void pull_tissues_from_vault(void); // Restores the state of the real tissues after a simulator run.
315 static void calc_N2_equilibrium(void); // Calculate partial pressure of N2 in respired air at surface pressure 308 static void calc_sim_pres_respiration(void); // Calculate sim_pres_respiration from char_depth_sim.
316 static void get_saturation_factors(void); // Get, safeguard and convert the saturation and desaturation factors 309 static void calc_N2_equilibrium(void); // Calculate partial pressure of N2 in respired air at surface pressure.
317 static void apply_saturation_factors(void); // Applies saturation and desaturation factors 310 static void get_saturation_factors(void); // Get, safeguard and convert the saturation and desaturation factors.
311 static void apply_saturation_factors(void); // Applies saturation and desaturation factors.
318 312
319 313
320 // ********************************************************************************************************************************* 314 // *********************************************************************************************************************************
321 // 315 //
322 // V A R I A B L E S D E F I N I T I O N S 316 // V A R I A B L E S D E F I N I T I O N S
330 324
331 // Environmental and Gas Data (52 byte) 325 // Environmental and Gas Data (52 byte)
332 326
333 static float pres_surface; // absolute pressure at the surface 327 static float pres_surface; // absolute pressure at the surface
334 328
335 static float float_depth_real; // current real depth in meters, float 329 static float float_depth_real; // current real depth in meters, float
336 static unsigned char char_depth_real; // current real depth in meters, integer 330 static unsigned char char_depth_real; // current real depth in meters, integer
337 static unsigned char char_depth_sim; // current simulated depth in meters, integer 331 static unsigned char char_depth_sim_start; // start value of simulated depth in meters, integer
338 static unsigned char char_depth_last; // last simulated depth in meters, integer 332 static unsigned char char_depth_sim; // current value of simulated depth in meters, integer
339 static unsigned char char_depth_bottom; // bottom depth in meters, integer 333 static unsigned char char_depth_last; // last value of simulated depth in meters, integer
340 334
341 static float real_pres_respiration; // current real depth in absolute pressure 335 static float real_pres_respiration; // current real depth in absolute pressure
342 static float real_O2_ratio; // real breathed gas oxygen ratio 336 static float real_O2_ratio; // real breathed gas oxygen ratio
343 static float real_N2_ratio; // real breathed gas nitrogen ratio 337 static float real_N2_ratio; // real breathed gas nitrogen ratio
344 static float real_He_ratio; // real breathed gas helium ratio 338 static float real_He_ratio; // real breathed gas helium ratio
366 static float GF_slope; // (GF_high - GF_low) / GF_low_depth in current calculation cycle 360 static float GF_slope; // (GF_high - GF_low) / GF_low_depth in current calculation cycle
367 static float GF_slope_norm; // (GF_high - GF_low) / GF_low_depth_norm in normal plan 361 static float GF_slope_norm; // (GF_high - GF_low) / GF_low_depth_norm in normal plan
368 static float GF_slope_alt; // (GF_high - GF_low) / GF_low_depth_alt in alternative plan 362 static float GF_slope_alt; // (GF_high - GF_low) / GF_low_depth_alt in alternative plan
369 363
370 static float float_ascent_speed; // ascent speed from options_table (5.0 .. 10.0 m/min) 364 static float float_ascent_speed; // ascent speed from options_table (5.0 .. 10.0 m/min)
371 static float float_deco_distance; // additional depth below stop depth for tissue, CNS and gas volume calculation 365 static float float_deco_distance; // additional depth below stop depth - not used any more
372 static float float_saturation_multiplier; // safety factor for on-gassing rates 366 static float float_saturation_multiplier; // safety factor for on-gassing rates
373 static float float_desaturation_multiplier; // safety factor for off-gassing rates 367 static float float_desaturation_multiplier; // safety factor for off-gassing rates
374 368
375 static unsigned char split_N2_He[NUM_COMP]; // used for calculating the desaturation time 369 static unsigned char split_N2_He[NUM_COMP]; // used for calculating the desaturation time
376 370
393 static unsigned char NDL_tissue_start_alt; // tissue to start with when calculating the alternative NDL time 387 static unsigned char NDL_tissue_start_alt; // tissue to start with when calculating the alternative NDL time
394 static unsigned char NDL_tissue_start; // tissue to start with in current cycle 388 static unsigned char NDL_tissue_start; // tissue to start with in current cycle
395 static unsigned char NDL_tissue_lead; // tissue with the shortest NDL time found in current cycle 389 static unsigned char NDL_tissue_lead; // tissue with the shortest NDL time found in current cycle
396 static unsigned char NDL_tissue; // tissue for which the NDL is calculated right now 390 static unsigned char NDL_tissue; // tissue for which the NDL is calculated right now
397 391
392
398 // Result Values from Calculation Functions (9 byte) 393 // Result Values from Calculation Functions (9 byte)
399 394
400 static float ceiling; // minimum tolerated relative pressure (i.e. without surface pressure) 395 static float ceiling; // minimum tolerated relative pressure (i.e. without surface pressure)
401 static float lead_supersat; // supersaturation of the leading tissue, 1.0 = 100% 396 static float lead_supersat; // supersaturation of the leading tissue, 1.0 = 100%
402 static unsigned char lead_tissue; // number of the leading tissue 397 static unsigned char lead_tissue; // number of the leading tissue
409 static float pres_target; // target pressure for a compartment 404 static float pres_target; // target pressure for a compartment
410 static float pres_actual; // current pressure of the compartment 405 static float pres_actual; // current pressure of the compartment
411 static unsigned short int_time; // time it takes for the compartment to reach the target pressure 406 static unsigned short int_time; // time it takes for the compartment to reach the target pressure
412 407
413 408
414 // Gas in Use and Gas Needs (30 byte) 409 // Gas in Use and Gas Needs (26 byte)
415 410
411 static unsigned char sim_gas_last_num; // number of the last used gas
416 static unsigned char sim_gas_current_num; // number of the currently used gas 412 static unsigned char sim_gas_current_num; // number of the currently used gas
417 static unsigned char sim_gas_current_depth; // change depth of the currently used gas 413 static unsigned char sim_gas_current_depth; // change depth of the currently used gas
418 414
419 static unsigned char gas_needs_stop_time; // duration of the stop in minutes 415 static unsigned char sim_gas_best_num; // number of the better gas
420 static unsigned char gas_needs_stop_gas; // gas used now (1-5 or 0) 416 static unsigned char sim_gas_best_depth; // change depth of the better gas
421 static unsigned char gas_needs_stop_gas_last; // gas used before (1-5 or 0) 417
422 static unsigned char gas_needs_stop_depth; // depth of the stop in meters
423 static unsigned char gas_needs_stop_depth_last; // depth of the last stop in meters
424 static unsigned char gas_needs_stop_index; // index to the stop table
425 static unsigned char gas_needs_gas_index; // index to the gas and tank data arrays 418 static unsigned char gas_needs_gas_index; // index to the gas and tank data arrays
426 static unsigned char gas_needs_next_phase; // next phase within the ascent gas needs calculation 419 static float gas_volume_need[NUM_GAS]; // gas volumes required for return/ascent in liters
427 420 static float gas_volume_avail[NUM_GAS]; // gas volumes available for return/ascent in liters
428 static float gas_volume_need[NUM_GAS]; // gas volumes required for return/ascent in liters 421
429 422
430 423 // Transfer Variables for calc_due_by_depth_time_sac() (7 byte)
431 // Transfer Variables between calc_gas_needs_ascent() and calc_due_by_depth_time_sac() (13 byte) 424
432 425 static unsigned char gas_needs_depth; // depth of the stop or half-way point
433 static float gas_needs_float_depth; // depth of the stop or half-way point 426 static unsigned char gas_needs_time; // duration of the stop or ascent phase
434 static float gas_needs_float_time; // duration of the stop or ascent phase 427 static unsigned char gas_needs_usage_rate; // gas usage in l/min
435 static unsigned char gas_needs_stop_usage; // gas usage in l/min
436 static float gas_needs_volume_due; // computed due of gas volume required 428 static float gas_needs_volume_due; // computed due of gas volume required
437
438
439 // CNS Coefficients (10 byte)
440
441 static float var_cns_a; // two coefficients approximation, gain
442 static float var_cns_b; // two coefficients approximation, offset
443 static unsigned short var_cns_c; // one coefficient approximation, value
444
445
446 // Transfer values for convert_float_int and convert_float_to_char() (7 byte)
447
448 static float float_value; // input value, float
449 static unsigned short int_value; // output value, 16 bit
450 static unsigned char char_value; // output value, 8 bit
451 429
452 430
453 // Auxiliary Variables for Data Buffering (28 byte) 431 // Auxiliary Variables for Data Buffering (28 byte)
454 432
455 static float N2_equilibrium; // used for N2 tissue graphics scaling 433 static float N2_equilibrium; // used for N2 tissue graphics scaling
459 static float calc_pres_tissue_He; // auxiliary variable to buffer tissue He pressure 437 static float calc_pres_tissue_He; // auxiliary variable to buffer tissue He pressure
460 static float pres_tissue; // auxiliary variable to buffer total tissue pressure 438 static float pres_tissue; // auxiliary variable to buffer total tissue pressure
461 static float old_pres_respiration; // auxiliary variable to buffer sim_pres_respiration 439 static float old_pres_respiration; // auxiliary variable to buffer sim_pres_respiration
462 440
463 441
464 // Performance Profiling (4 byte) 442 // 244 byte used, 12 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
465
466 static unsigned short profiling_runtime; // performance measurement: runtime of current invocation
467 static unsigned char profiling_runs; // performance measurement: invocations per deco calculation cycle
468 static unsigned char profiling_phase; // performance measurement: current calculation phase
469
470
471 // 255 byte used, 1 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
472 443
473 444
474 //---- Bank 6 parameters ----------------------------------------------------- 445 //---- Bank 6 parameters -----------------------------------------------------
475 #ifndef UNIX 446 #ifndef UNIX
476 # pragma udata bank6=0x600 447 # pragma udata bank6=0x600
480 451
481 static volatile unsigned short tmr5_value; // timer 5 value buffer MUST be at address 0x600 452 static volatile unsigned short tmr5_value; // timer 5 value buffer MUST be at address 0x600
482 static volatile unsigned char tmr5_overflow; // timer 5 overflow flag MUST be at address 0x602 453 static volatile unsigned char tmr5_overflow; // timer 5 overflow flag MUST be at address 0x602
483 454
484 455
485 // Modes, Sequencing and Indexing (11 byte) 456 // Modes, Sequencing and Indexing (12 byte)
486 457
487 static unsigned char main_status; // shadow register for char_O_main_status 458 static unsigned char main_status; // shadow register for char_O_main_status
488 static unsigned char deco_status; // shadow register for char_O_deco_status 459 static unsigned char deco_status; // shadow register for char_O_deco_status
489 static unsigned char deco_info; // shadow register for char_O_deco_info 460 static unsigned char deco_info; // shadow register for char_O_deco_info
490 static unsigned char deco_warnings; // shadow register for char_O_deco_warnings 461 static unsigned char deco_warnings; // shadow register for char_O_deco_warnings
493 static unsigned char sequence_timer; // timer to sequence deco engine tasks 464 static unsigned char sequence_timer; // timer to sequence deco engine tasks
494 static unsigned char ci; // index to the Buhlmann tables (compartment index) 465 static unsigned char ci; // index to the Buhlmann tables (compartment index)
495 static unsigned char cns_i; // index to the CNS tables (ppO2 range index) 466 static unsigned char cns_i; // index to the CNS tables (ppO2 range index)
496 static unsigned char i; // general purpose loop counter and index 467 static unsigned char i; // general purpose loop counter and index
497 static unsigned char fast; // selects 1 minute or 2 second ascent steps 468 static unsigned char fast; // selects 1 minute or 2 second ascent steps
469 static unsigned char stop_index; // current stop table position
470 static unsigned char chained_stops; // counter for chained stop entries
498 471
499 472
500 // Result Values from Calculation Functions (28 byte) 473 // Result Values from Calculation Functions (28 byte)
501 474
502 static float O2_ppO2; // ppO2 - calculated for pure oxygen at current depth 475 static float O2_ppO2; // ppO2 - calculated for pure oxygen at current depth
524 static float var_He_e; // exposition, for current He tissue 497 static float var_He_e; // exposition, for current He tissue
525 static float var_N2_ht; // half-time, for current N2 tissue 498 static float var_N2_ht; // half-time, for current N2 tissue
526 static float var_He_ht; // half-time, for current He tissue 499 static float var_He_ht; // half-time, for current He tissue
527 500
528 501
502 // CNS Coefficients (10 byte)
503
504 static float var_cns_a; // two coefficients approximation, gain
505 static float var_cns_b; // two coefficients approximation, offset
506 static unsigned short var_cns_c; // one coefficient approximation, value
507
508
529 // Vault to back-up & restore Tissue related Data (134 byte) 509 // Vault to back-up & restore Tissue related Data (134 byte)
530 510
531 static float vault_pres_tissue_N2[NUM_COMP]; // stores the nitrogen tissue pressures 511 static float vault_pres_tissue_N2[NUM_COMP]; // stores the nitrogen tissue pressures
532 static float vault_pres_tissue_He[NUM_COMP]; // stores the helium tissue pressures 512 static float vault_pres_tissue_He[NUM_COMP]; // stores the helium tissue pressures
533 static float vault_CNS_fraction_real; // stores current CNS (float representation) 513 static float vault_CNS_fraction_real; // stores current CNS (float representation)
534 static unsigned char vault_deco_warnings; // stores warnings status 514 static unsigned char vault_deco_warnings; // stores warnings status
535 static unsigned char vault_deco_info; // stores info status 515 static unsigned char vault_deco_info; // stores info status
536 516
537 517
518 // Transfer values for convert_float_int and convert_float_to_char() (7 byte)
519
520 static float float_value; // input value, float
521 static unsigned short int_value; // output value, 16 bit
522 static unsigned char char_value; // output value, 8 bit
523
524
525 // Performance Profiling (4 byte)
526
527 static unsigned short profiling_runtime; // performance measurement: runtime of current invocation
528 static unsigned char profiling_runs; // performance measurement: invocations per deco calculation cycle
529 static unsigned char profiling_phase; // performance measurement: current calculation phase
530
531
538 // 7 byte occupied by compiler-placed vars 532 // 7 byte occupied by compiler-placed vars
539 533
540 534
541 // 223 byte used, 33 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char) 535 // 245 byte used, 11 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
542 536
543 537
544 538
545 //---- Bank 12 parameters ----------------------------------------------------- 539 //---- Bank 12 parameters -----------------------------------------------------
546 #ifndef UNIX 540 #ifndef UNIX
599 #ifndef UNIX 593 #ifndef UNIX
600 # pragma romdata CNS_tables = 0x1DC80 // needs to be in the UPPER bank 594 # pragma romdata CNS_tables = 0x1DC80 // needs to be in the UPPER bank
601 #endif 595 #endif
602 596
603 rom const float CNS_ab[2*11] = { 597 rom const float CNS_ab[2*11] = {
604 // CNS increment per 2sec = 1 / (a*ppO2 + b) with ppO2 in [cbar] 598 // CNS increment per 2 sec = 1 / (a*ppO2 + b) with ppO2 in [cbar]
605 // a b for ppO2 cbar range 599 // a b for ppO2 cbar range
606 -533.07, 54000, // 51 - 60 (index 0) 600 -533.07, 54000, // 51 - 60 (index 0)
607 -444.22, 48600, // 61 - 70 (index 1) 601 -444.22, 48600, // 61 - 70 (index 1)
608 -355.38, 42300, // 71 - 80 (index 2) 602 -355.38, 42300, // 71 - 80 (index 2)
609 -266.53, 35100, // 81 - 90 (index 3) 603 -266.53, 35100, // 81 - 90 (index 3)
614 -88.84, 17100, // 131 - 140 (index 8) 608 -88.84, 17100, // 131 - 140 (index 8)
615 -88.84, 17100, // 141 - 150 (index 9) 609 -88.84, 17100, // 141 - 150 (index 9)
616 -222.11, 37350 // 151 - 160 (index 10) 610 -222.11, 37350 // 151 - 160 (index 10)
617 }; 611 };
618 612
619 rom const unsigned short CNS_c[1*20] = { 613 rom const unsigned short CNS_c[1*18] = {
620 // CNS increment per 2sec = c / 100000.0 614 // CNS increment per 2 sec = c / 100000.0
621 // c in [1/100000] for ppO2 cbar range 615 // c in [1/100000] for ppO2 cbar range
622 75, // 161 - 165 (index 0) 616 75, // 161 - 165 (index 0)
623 102, // 166 - 170 (index 1) 617 102, // 166 - 170 (index 1)
624 136, // 171 - 175 (index 2) 618 136, // 171 - 175 (index 2)
625 180, // 176 - 180 (index 3) 619 180, // 176 - 180 (index 3)
634 2900, // 221 - 225 (index 12) 628 2900, // 221 - 225 (index 12)
635 3900, // 226 - 230 (index 13) 629 3900, // 226 - 230 (index 13)
636 4820, // 231 - 235 (index 14) 630 4820, // 231 - 235 (index 14)
637 4820, // 236 - 240 (index 15) 631 4820, // 236 - 240 (index 15)
638 4820, // 241 - 245 (index 16) 632 4820, // 241 - 245 (index 16)
639 4820, // 246 - 250 (index 17) 633 4820 // 246 - 250 (index 17)
640 4820, // 251 - 255 (index 18)
641 0 // not used, just to fill up the memory block
642 }; 634 };
643 635
644 636
645 #ifndef UNIX 637 #ifndef UNIX
646 # pragma romdata Buhlmann_tables = 0x1DD00 // needs to be in the UPPER bank 638 # pragma romdata Buhlmann_tables = 0x1DD00 // needs to be in the UPPER bank
666 0.2480, 0.9602, 0.5172, 0.9217, 658 0.2480, 0.9602, 0.5172, 0.9217,
667 0.2327, 0.9653, 0.5119, 0.9267 659 0.2327, 0.9653, 0.5119, 0.9267
668 }; 660 };
669 661
670 rom const float Buhlmann_ht[2*16] = { 662 rom const float Buhlmann_ht[2*16] = {
671 // Compartment half-life, in minute 663 // Compartment half-life, in minutes
672 //--- N2 ---- He ---------------------- 664 //--- N2 ---- He ----------------------
673 4.0, 1.51, 665 4.0, 1.51,
674 8.0, 3.02, 666 8.0, 3.02,
675 12.5, 4.72, 667 12.5, 4.72,
676 18.5, 6.99, 668 18.5, 6.99,
687 498.0, 188.24, 679 498.0, 188.24,
688 635.0, 240.03 680 635.0, 240.03
689 }; 681 };
690 682
691 rom const float e2secs[2*16] = { 683 rom const float e2secs[2*16] = {
692 // result of 1 - 2^(-1/(2sec*HT)) 684 // Integration constant for 2 seconds,
685 // result of 1 - 2^(-1/(2sec/60sec * HT))
693 //---- N2 ------------- He ------------ 686 //---- N2 ------------- He ------------
694 5.75958E-03, 1.51848E-02, 687 5.75958E-03, 1.51848E-02,
695 2.88395E-03, 7.62144E-03, 688 2.88395E-03, 7.62144E-03,
696 1.84669E-03, 4.88315E-03, 689 1.84669E-03, 4.88315E-03,
697 1.24813E-03, 3.29997E-03, 690 1.24813E-03, 3.29997E-03,
710 //------------------------------------- 703 //-------------------------------------
711 }; 704 };
712 705
713 rom const float e1min[2*16] = { 706 rom const float e1min[2*16] = {
714 // Integration constant for 1 minute, 707 // Integration constant for 1 minute,
715 // Ie. 1- 2^(-1/HT) 708 // result of 1 - 2^(-1/HT)
716 //----- N2 --------- e 1min He -------- 709 //----- N2 --------- e 1min He --------
717 1.59104E-01, 3.68109E-01, 710 1.59104E-01, 3.68109E-01,
718 8.29960E-02, 2.05084E-01, 711 8.29960E-02, 2.05084E-01,
719 5.39424E-02, 1.36579E-01, 712 5.39424E-02, 1.36579E-01,
720 3.67742E-02, 9.44046E-02, 713 3.67742E-02, 9.44046E-02,
732 1.09097E-03, 2.88359E-03 725 1.09097E-03, 2.88359E-03
733 //------------------------------------- 726 //-------------------------------------
734 }; 727 };
735 728
736 rom const float e10min[2*16] = { 729 rom const float e10min[2*16] = {
737 // The 10 min Value in float notation: 730 // Integration constant for 10 minutes,
738 // result of 1 - 2^(-10/ht) 731 // result of 1 - 2^(-10/ht)
739 //---- N2 -------------- He ----------- 732 //---- N2 -------------- He -----------
740 8.23223E-01, 9.89851E-01, 733 8.23223E-01, 9.89851E-01,
741 5.79552E-01, 8.99258E-01, 734 5.79552E-01, 8.99258E-01,
742 4.25651E-01, 7.69737E-01, 735 4.25651E-01, 7.69737E-01,
743 3.12487E-01, 6.29027E-01, 736 3.12487E-01, 6.29027E-01,
762 // H E L P E R F U N C T I O N S 755 // H E L P E R F U N C T I O N S
763 // 756 //
764 // ********************************************************************************************************************************* 757 // *********************************************************************************************************************************
765 758
766 759
767 // moved from 0x0D000 to 0x0C000 in v.108 760 // p2deco code moved from 0x0D000 to 0x0C000 in v.108
768 #ifndef UNIX 761 #ifndef UNIX
769 # pragma code p2_deco = 0x0C000 762 # pragma code p2_deco = 0x0C000
770 #endif 763 #endif
771 764
772 765
778 } 771 }
779 #endif 772 #endif
780 773
781 774
782 ////////////////////////////////////////////////////////////////////////////// 775 //////////////////////////////////////////////////////////////////////////////
783 // When calling C code from ASM context, the data stack pointer and 776 // When calling C code from ASM context, the C data stack pointer need to be
784 // frames should be reset. Bank 8 is used by stack. 777 // reset. The C stack is located in bank 8.
785 778
786 #ifdef CROSS_COMPILE 779 #ifdef CROSS_COMPILE
787 # define RESET_C_STACK 780 # define RESET_C_STACK
788 #else 781 #else
789 # ifdef _DEBUG 782 # ifdef _DEBUG
912 { 905 {
913 #ifndef CROSS_COMPILE 906 #ifndef CROSS_COMPILE
914 // Note: We don't use far ROM pointer, because handling 907 // Note: We don't use far ROM pointer, because handling
915 // 24 bit is too complex, hence we have to set the 908 // 24 bit is too complex, hence we have to set the
916 // UPPER page ourself... 909 // UPPER page ourself...
917 // -> Set to zero if tables are moved to lower pages! 910 // -> set to zero if tables are moved to lower pages!
918 _asm 911 _asm
919 movlw 1 912 movlw 1
920 movwf TBLPTRU,0 913 movwf TBLPTRU,0
921 _endasm 914 _endasm
922 #endif 915 #endif
1045 1038
1046 } 1039 }
1047 1040
1048 1041
1049 ////////////////////////////////////////////////////////////////////////////// 1042 //////////////////////////////////////////////////////////////////////////////
1043 // Calculate sim_pres_respiration from char_depth_sim
1044 //
1045 // Input: char_depth_sim simulated depth in meters
1046 // pres_surface surface pressure
1047 //
1048 // Output: sim_pres_respiration simulated depth in absolute pressure
1049 //
1050 static void calc_sim_pres_respiration(void)
1051 {
1052 sim_pres_respiration = (float)char_depth_sim * METER_TO_BAR + pres_surface;
1053 }
1054
1055
1056 //////////////////////////////////////////////////////////////////////////////
1050 // Calculate partial pressure of N2 in respired air at surface pressure 1057 // Calculate partial pressure of N2 in respired air at surface pressure
1051 // 1058 //
1052 // Input: pres_surface surface pressure 1059 // Input: pres_surface surface pressure
1053 // 1060 //
1054 // Output: N2_equilibrium partial pressure of N2 in surface air 1061 // Output: N2_equilibrium partial pressure of N2 in surface air
1136 ////////////////////////////////////////////////////////////////////////////// 1143 //////////////////////////////////////////////////////////////////////////////
1137 // deco_calc_hauptroutine 1144 // deco_calc_hauptroutine
1138 // 1145 //
1139 // called from: divemode.asm 1146 // called from: divemode.asm
1140 // 1147 //
1141 // Called every second during diving, 1148 // Called two times per second during diving, updates the
1142 // updates tissues on every second invocation. 1149 // tissues every second (i.e. on every second invocation).
1143 // 1150 //
1144 // Every few seconds (or slower when TTS > 16): 1151 // On each computation cycle:
1145 // - Updates deco table (char_O_deco_time/depth) with new values, 1152 // - Updates deco table (char_O_deco_time/depth) with new values,
1146 // - updates ascent time, and 1153 // - updates ascent time, and
1147 // - sets status to zero (so we can check there is new results). 1154 // - sets status to zero (so we can check a cycle has finished).
1148 // 1155 //
1149 void deco_calc_hauptroutine(void) 1156 void deco_calc_hauptroutine(void)
1150 { 1157 {
1151 RESET_C_STACK 1158 RESET_C_STACK
1152 calc_hauptroutine(); 1159 calc_hauptroutine();
1163 void deco_init_output_vars(void) 1170 void deco_init_output_vars(void)
1164 { 1171 {
1165 RESET_C_STACK 1172 RESET_C_STACK
1166 init_output_vars(); 1173 init_output_vars();
1167 } 1174 }
1175
1168 1176
1169 ////////////////////////////////////////////////////////////////////////////// 1177 //////////////////////////////////////////////////////////////////////////////
1170 // deco_clear_tissue 1178 // deco_clear_tissue
1171 // 1179 //
1172 // called from: start.asm 1180 // called from: start.asm
1173 // menu_tree.asm 1181 // menu_tree.asm
1174 // simulator.asm 1182 // simulator.asm
1175 // 1183 //
1176 // Sets all tissues to equilibrium with Air at ambient pressure, 1184 // Sets all tissues to equilibrium with air at ambient pressure,
1177 // resets all CNS values, any warnings and resets all model output. 1185 // resets all CNS values, any warnings and resets all model output.
1178 // 1186 //
1179 void deco_clear_tissue(void) 1187 void deco_clear_tissue(void)
1180 { 1188 {
1181 RESET_C_STACK 1189 RESET_C_STACK
1186 ////////////////////////////////////////////////////////////////////////////// 1194 //////////////////////////////////////////////////////////////////////////////
1187 // deco_calc_dive_interval 1195 // deco_calc_dive_interval
1188 // 1196 //
1189 // called from: simulator.asm 1197 // called from: simulator.asm
1190 // 1198 //
1191 // Updates tissues and CNS value for char_I_dive_interval minutes on air 1199 // Updates tissues and CNS value for char_I_dive_interval minutes on air at
1192 // at ambient pressure and calculates resulting GF factor and ceiling for 1200 // ambient pressure and calculates resulting saturation and ceiling for a
1193 // a GF-high of 100% (ceiling and GF factor not used by simulator.asm) 1201 // GF-high of 100% (ceiling and saturation not used by simulator.asm)
1194 // 1202 //
1195 void deco_calc_dive_interval(void) 1203 void deco_calc_dive_interval(void)
1196 { 1204 {
1197 RESET_C_STACK 1205 RESET_C_STACK
1198 calc_interval(char_I_dive_interval); 1206 calc_interval(char_I_dive_interval);
1207 // surfmode.asm 1215 // surfmode.asm
1208 // menu_tree.asm 1216 // menu_tree.asm
1209 // ghostwriter.asm 1217 // ghostwriter.asm
1210 // 1218 //
1211 // Updates tissues and CNS value for 1 minute on air at ambient pressure and 1219 // Updates tissues and CNS value for 1 minute on air at ambient pressure and
1212 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling 1220 // calculates resulting saturation and ceiling for a GF-high of 100%.
1213 // is not used by *.asm files).
1214 // 1221 //
1215 void deco_calc_dive_interval_1min(void) 1222 void deco_calc_dive_interval_1min(void)
1216 { 1223 {
1217 RESET_C_STACK 1224 RESET_C_STACK
1218 calc_interval(1); 1225 calc_interval(1);
1223 // deco_calc_dive_interval_10min 1230 // deco_calc_dive_interval_10min
1224 // 1231 //
1225 // called from: sleepmode.asm 1232 // called from: sleepmode.asm
1226 // 1233 //
1227 // Updates tissues and CNS value for 10 minutes on air at ambient pressure and 1234 // Updates tissues and CNS value for 10 minutes on air at ambient pressure and
1228 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling 1235 // calculates resulting saturation and ceiling for a GF-high of 100%.
1229 // is not used by sleepmode.asm).
1230 // 1236 //
1231 void deco_calc_dive_interval_10min(void) 1237 void deco_calc_dive_interval_10min(void)
1232 { 1238 {
1233 RESET_C_STACK 1239 RESET_C_STACK
1234 calc_interval(10); 1240 calc_interval(10);
1287 // 1293 //
1288 // ********************************************************************************************************************************* 1294 // *********************************************************************************************************************************
1289 1295
1290 1296
1291 ////////////////////////////////////////////////////////////////////////////// 1297 //////////////////////////////////////////////////////////////////////////////
1292 // find_next_stop 1298 // Calculate the next deco stop
1293 // 1299 //
1294 // INPUT, fixed during dive: 1300 // INPUT, fixed during dive:
1295 // pres_surface : surface pressure (as absolute pressure) 1301 // pres_surface : surface pressure (as absolute pressure)
1296 // char_I_depth_last_deco : depth of the last deco stop 1302 // char_I_depth_last_deco : depth of the last deco stop
1297 // 1303 //
1298 // INPUT, changing during dive: 1304 // INPUT, may change during dive:
1299 // float_depth_real : current real depth in meters (float)
1300 // char_depth_real : current real depth in meters (integer)
1301 // GF_high : GF high factor 1305 // GF_high : GF high factor
1302 // GF_low : GF low factor 1306 // GF_low : GF low factor
1303 // 1307 //
1304 // INPUT & OUTPUT 1308 // INPUT & OUTPUT
1305 // char_depth_sim : simulated depth in meters 1309 // char_depth_sim : simulated depth in meters
1317 // 1321 //
1318 static unsigned char find_next_stop(void) 1322 static unsigned char find_next_stop(void)
1319 { 1323 {
1320 overlay unsigned char depth_1min; 1324 overlay unsigned char depth_1min;
1321 overlay unsigned char depth_limit; 1325 overlay unsigned char depth_limit;
1322 overlay unsigned char first_stop; 1326 overlay unsigned char stop_depth;
1327 overlay unsigned char next_stop;
1323 overlay unsigned char need_stop; 1328 overlay unsigned char need_stop;
1324 1329
1325 1330
1326 // ----------------------------------------------------------------------- 1331 // memorize the depth we came from
1327 // we start with the assumption that a stop is not required
1328 // -----------------------------------------------------------------------
1329
1330 need_stop = 0;
1331
1332 // remember the depth we came from
1333 char_depth_last = char_depth_sim; 1332 char_depth_last = char_depth_sim;
1334 1333
1335 // calculate the limit for the current depth 1334 // calculate the ceiling (minimum relative pressure) for the current depth
1336 if( char_I_deco_model == 0 ) calc_limit(1.0); // straight Buhlmann 1335 if( char_I_deco_model == 0 ) calc_limit(1.0); // deco or not - straight Buhlmann
1337 else if( char_depth_sim >= GF_low_depth ) calc_limit(GF_low); // with GF, below low depth reference 1336 else if( NDL_time ) calc_limit(GF_high); // not in deco
1338 else calc_limit(GF_high - GF_slope * (float)char_depth_sim); // with GF, above low depth reference 1337 else if( char_depth_sim >= GF_low_depth ) calc_limit(GF_low); // in deco with GF, below or at low depth reference
1339 1338 else calc_limit(GF_high - GF_slope * (float)char_depth_sim); // in deco with GF, above low depth reference
1340 // check if we can surface directly 1339
1341 if( ceiling <= 0.0 ) 1340 // convert the ceiling from relative pressure to meters,
1342 { 1341 // rounded up (i.e. made deeper) to next full meter,
1343 // YES - ascent to surface is allowed 1342 // limiting at surface.
1344 char_depth_sim = 0; 1343 depth_limit = (ceiling > 0.0) ? (unsigned char)(ceiling * BAR_TO_METER + 0.99) : 0;
1345 1344
1346 // - done 1345 // calculate the stop depth, i.e. round up (make deeper) to
1347 goto done; 1346 // the next multiple of 3 meters using integer arithmetics
1348 } 1347 stop_depth = 3 * ( (depth_limit + 2) / 3 );
1349
1350 // -----------------------------------------------------------------------
1351 // a stop is required, but maybe not yet within the running minute
1352 // -----------------------------------------------------------------------
1353
1354 // convert the depth we can ascent to from relative pressure to meters,
1355 // rounded up (i.e. made deeper) to next full meter.
1356 depth_limit = (unsigned char)(ceiling * BAR_TO_METER + 0.99);
1357
1358 // calculate the stop depth, i.e. round up to the next multiple of 3 meters
1359 // using integer arithmetics
1360 first_stop = 3 * ( (depth_limit + 2) / 3 );
1361 1348
1362 // apply correction for the shallowest stop 1349 // apply correction for the shallowest stop
1363 if( first_stop == 3 ) first_stop = char_I_depth_last_deco; 1350 if( stop_depth == 3 ) stop_depth = char_I_depth_last_deco;
1364 1351
1365 // compute depth in meters that will be reached in 1 minute of ascent 1352 // compute depth in meters that will be reached in 1 minute of ascent
1366 // at a speed of char_I_ascent_speed (5..10 m/min) 1353 // at a speed of char_I_ascent_speed (5..10 m/min)
1367 if( char_depth_sim > char_I_ascent_speed ) 1354 if( char_depth_sim > char_I_ascent_speed )
1368 { 1355 {
1371 else 1358 else
1372 { 1359 {
1373 depth_1min = 0; 1360 depth_1min = 0;
1374 } 1361 }
1375 1362
1376 // is the stop shallower than the depth that can be reached within 1 minute? 1363 // is the stop depth shallower than the depth that can be reached within 1 minute,
1377 if( depth_1min > first_stop ) 1364 // or are we allowed to surface AND can we reach the surface within 1 minute?
1365 if( ( ( stop_depth < depth_1min ) )
1366 || ( ( stop_depth == 0 ) && ( depth_1min == 0 ) )
1367 )
1378 { 1368 {
1379 // YES - report the depth that will be reached within 1 minute of ascent 1369 // YES - report the depth that will be reached within 1 minute of ascent
1380 char_depth_sim = depth_1min; 1370 char_depth_sim = depth_1min;
1381 1371
1372 // - no stop needed
1373 need_stop = 0;
1374
1382 // - done 1375 // - done
1383 goto done; 1376 goto done;
1384 } 1377 }
1385 1378
1386 // ----------------------------------------------------------------------- 1379 // -----------------------------------------------------------------------
1387 // we need to make a stop now 1380 // we need to make a stop now, or need to stay at the current stop depth
1388 // ----------------------------------------------------------------------- 1381 // -----------------------------------------------------------------------
1389 1382
1390 // set stop data 1383 // set stop data
1391 need_stop = 1; 1384 need_stop = 1;
1392 char_depth_sim = first_stop; 1385 char_depth_sim = stop_depth;
1386
1387 // Apply correction in case the stop is to be placed deeper than a
1388 // previously recorded stop for a gas change. This may happen because
1389 // the deco stops are placed at the next deeper multiple of 3 meters
1390 // instead of the real stop's depth. Correction is to relocate the
1391 // deco stop to the depth of the last gas change. The resulting combined
1392 // stop's duration will be the sum of the configured gas change time plus
1393 // the duration of the deco stop itself.
1394 if( 0 < internal_deco_depth[stop_index] )
1395 if( char_depth_sim > internal_deco_depth[stop_index] )
1396 char_depth_sim = internal_deco_depth[stop_index];
1393 1397
1394 // done so far if using straight Buhlmann 1398 // done so far if using straight Buhlmann
1395 if( char_I_deco_model == 0 ) goto done; 1399 if( char_I_deco_model == 0 ) goto done;
1396 1400
1397 // ----------------------------------------------------------------------- 1401 // -----------------------------------------------------------------------
1398 // we need to make a stop now and we are using the GF extension 1402 // we need to make or hold a stop and we are using the GF extension
1399 // ----------------------------------------------------------------------- 1403 // -----------------------------------------------------------------------
1400 1404
1401 // is the depth limit deeper than the GF low depth reference used up to now? 1405 // is the stop depth deeper than the GF low depth reference used up to now?
1402 if( depth_limit > GF_low_depth ) 1406 if( stop_depth > GF_low_depth )
1403 { 1407 {
1404 // YES - update the reference 1408 // YES - update the reference
1405 GF_low_depth = depth_limit; 1409 GF_low_depth = stop_depth;
1406 GF_slope = (GF_high - GF_low) / (float)GF_low_depth; 1410 GF_slope = (GF_high - GF_low) / (float)GF_low_depth;
1407 1411
1408 // store for use in next cycles 1412 // store for use in next cycles
1409 if( deco_status & CALC_NORM ) 1413 if( deco_status & CALC_NORM )
1410 { 1414 {
1415 { 1419 {
1416 GF_low_depth_alt = GF_low_depth; 1420 GF_low_depth_alt = GF_low_depth;
1417 GF_slope_alt = GF_slope; 1421 GF_slope_alt = GF_slope;
1418 } 1422 }
1419 } 1423 }
1420
1421 // keep the stop as it is when it is the first stop
1422 // (i.e. there are no stops in the stops table yet)
1423 if( internal_deco_depth[0] == 0 ) goto done;
1424
1425 // keep the stop as it is when extended stops are activated
1426 if( main_status & EXTENDED_STOPS ) goto done;
1427 1424
1428 // We have a (first) stop. But with a steep GF slope, the stop(s) after this 1425 // We have a (first) stop. But with a steep GF slope, the stop(s) after this
1429 // first stop may be allowed to ascent to, too. This is because the gradient 1426 // first stop may be allowed to ascent to, too. This is because the gradient
1430 // factor that will be used at the next depth(s) will allow more tissue super- 1427 // factor that will be used at the next depth(s) will allow more tissue super-
1431 // saturation, maybe so much more that the next stop(s) will be allowed to 1428 // saturation, maybe so much more that the next stop(s) will be allowed to
1432 // ascent to. So we have to probe the next stops that are within the reach of 1429 // ascent to. So we have to probe the next stops that are within the reach of
1433 // 1 minute of ascent as well. 1430 // 1 minute of ascent as well.
1434 1431
1435 // no need to probe for a stop that is beyond 1 minute of ascent 1432 // probe all stop depths that are in reach of 1 minute of ascent
1436 while( first_stop >= (depth_1min + 3) ) 1433 next_stop = stop_depth;
1437 { 1434
1438 overlay unsigned char next_stop; 1435 while(next_stop > 0)
1439 1436 {
1440 // compute the depth of the next stop 1437 // compute the depth of the next stop ...
1441 if ( first_stop <= char_I_depth_last_deco ) next_stop = 0; 1438 if ( next_stop <= char_I_depth_last_deco ) next_stop = 0;
1442 else if ( first_stop == 6 ) next_stop = char_I_depth_last_deco; 1439 else if ( next_stop == 6 ) next_stop = char_I_depth_last_deco;
1443 else next_stop = first_stop - 3; 1440 else next_stop -= 3;
1444 1441
1445 // compute the depth limit at the next stop depth 1442 // would the next stop be beyond the 1 minute limit?
1446 calc_limit(GF_high - GF_slope * (float)next_stop); 1443 if( next_stop < depth_1min )
1447 1444 {
1448 // check if ascent to the next stop is allowed 1445 // YES - signal that probing is done
1449 if( next_stop < (unsigned char)(ceiling * BAR_TO_METER + 0.99) ) 1446 next_stop = 0;
1450 {
1451 // NO - the next stop would be too shallow
1452 break;
1453 } 1447 }
1454 else 1448 else
1455 { 1449 {
1456 // YES - the next stop is allowed 1450 // NO - compute the ceiling at the next stop depth
1457 char_depth_sim = next_stop; 1451 calc_limit(GF_high - GF_slope * (float)next_stop);
1458 1452
1459 // - ascent to next stop 1453 // - limit ceiling to positive values, i.e. the surface
1460 first_stop = next_stop; 1454 if( ceiling < 0.0 ) ceiling = 0.0;
1461 1455
1462 // - loop to probe the stop following next 1456 // - check if this stop depth would be allowed
1463 continue; 1457 if( next_stop >= (unsigned char)(ceiling * BAR_TO_METER + 0.99) )
1458 {
1459 // YES - this stop depth is allowed
1460 char_depth_sim = next_stop;
1461
1462 // - no stop needed if stop depth actually is the surface
1463 if( next_stop == 0 ) need_stop = 0;
1464 }
1464 } 1465 }
1465 } 1466 }
1466 1467
1467 1468
1468 // ----------------------------------------------------------------------- 1469 // -----------------------------------------------------------------------
1470 // ----------------------------------------------------------------------- 1471 // -----------------------------------------------------------------------
1471 1472
1472 done: 1473 done:
1473 1474
1474 // calculate absolute pressure at the depth found 1475 // calculate absolute pressure at the depth found
1475 sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; 1476 calc_sim_pres_respiration();
1476 1477
1477 return need_stop; 1478 return need_stop;
1478 } 1479 }
1479 1480
1480 1481
1481 ////////////////////////////////////////////////////////////////////////////// 1482 //////////////////////////////////////////////////////////////////////////////
1482 // publish_deco_table 1483 // Find current gas in the list and get its change depth
1483 //
1484 // Input: internal_deco_depth[] depth in internal stops table
1485 // internal_deco_time[] times ...
1486 // internal_deco_gas[] gases ...
1487 //
1488 // Output: char_O_deco_depth[] depth in the external stops table
1489 // char_O_deco_time[] times ...
1490 // char_O_deco_gas[] gases ...
1491 // char_O_deco_time_for_log times in reverse order
1492 //
1493 static void publish_deco_table(void)
1494 {
1495 overlay unsigned char x = 0;
1496 overlay unsigned char y;
1497
1498
1499 // copy all entries from internal to external stops table
1500 for( y = 0; y < NUM_STOPS; y++ )
1501 {
1502 // remember index of last entry with a non-null depth
1503 if( internal_deco_depth[y] > 0 ) x = y;
1504
1505 // copy depth, time and gas
1506 char_O_deco_depth[y] = internal_deco_depth[y];
1507 char_O_deco_time [y] = internal_deco_time [y];
1508 char_O_deco_gas [y] = internal_deco_gas [y];
1509 }
1510
1511
1512 // copy times of shallowest stops to logging table
1513 for( y = 0; y < NUM_STOPS_LOG; y++, --x )
1514 {
1515 char_O_deco_time_for_log[y] = internal_deco_time [x];
1516
1517 // stop when all entries are copied
1518 if( x == 0 ) break;
1519 }
1520
1521 // fill the remainder of the logging table with null
1522 // if it is not completely filled already
1523 for( y++; y < NUM_STOPS_LOG; y++ )
1524 char_O_deco_time_for_log[y] = 0;
1525 }
1526
1527
1528 //////////////////////////////////////////////////////////////////////////////
1529 // Find current gas in the list (if any) and get its change depth
1530 // 1484 //
1531 // Input: char_I_current_gas_num number of current gas (1..5 or 6) 1485 // Input: char_I_current_gas_num number of current gas (1..5 or 6)
1532 // 1486 //
1533 // Output: sim_gas_current_num 1..6 or 0 for the manually configured gas/dil 1487 // Output: sim_gas_current_num 1..6 or 0 for the manually configured gas/dil
1534 // sim_gas_current_depth change depth (MOD) of the gas/dil in meters 1488 // sim_gas_current_depth change depth (MOD) of the gas/dil in meters
1535 // 1489 //
1536 static void gas_find_current(void) 1490 static void gas_take_current(void)
1537 { 1491 {
1538 assert( 1 <= char_I_current_gas_num && char_I_current_gas_num <= 6 ); 1492 assert( 1 <= char_I_current_gas_num && char_I_current_gas_num <= 6 );
1539 1493
1540 if( char_I_current_gas_num <= NUM_GAS ) // gas/diluent 1-5 1494 if( char_I_current_gas_num <= NUM_GAS ) // gas/diluent 1-5
1541 { 1495 {
1542 sim_gas_current_num = char_I_current_gas_num; 1496 sim_gas_current_num = char_I_current_gas_num;
1543 sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current_num-1]; 1497 sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current_num-1];
1498
1499 // capture case of non-configured change depth
1500 if( sim_gas_current_depth == 0 ) sim_gas_current_depth = 255;
1544 } 1501 }
1545 else 1502 else
1546 { 1503 {
1547 sim_gas_current_num = 0; 1504 sim_gas_current_num = 0;
1548 sim_gas_current_depth = char_I_gas6_depth; 1505 sim_gas_current_depth = char_I_gas6_depth;
1549 } 1506 }
1550 } 1507 }
1551 1508
1552 1509
1553 ////////////////////////////////////////////////////////////////////////////// 1510 //////////////////////////////////////////////////////////////////////////////
1554 // Find the deco gas with the shallowest change depth below or at the current depth 1511 // Find the gas with the shallowest change depth below or at the current depth
1555 // 1512 //
1556 // Input: char_depth_sim simulated depth in meters 1513 // Input: char_depth_sim simulated depth in meters
1557 // sim_gas_current_num number of the currently used gas/dil 1514 // sim_gas_current_num number of the currently used gas/dil
1558 // sim_gas_current_depth change depth of the currently used gas/dil
1559 // char_I_deco_gas_type[] types of the gases/dils 1515 // char_I_deco_gas_type[] types of the gases/dils
1560 // char_I_deco_gas_change[] change depths of the gases/dils 1516 // char_I_deco_gas_change[] change depths of the gases/dils
1561 // 1517 //
1562 // Modified: sim_gas_current_num index of the gas (1..5) - only if return value is true 1518 // Modified: sim_gas_best_num index of the gas (1..5) - only if return value is true
1563 // sim_gas_current_depth switch depth - only if return value is true 1519 // sim_gas_best_depth switch depth - only if return value is true
1564 // 1520 //
1565 // Return value is TRUE if a better gas is available 1521 // Return value is TRUE if a better gas is available
1566 // 1522 //
1567 static unsigned char gas_find_better(void) 1523 static unsigned char gas_find_best(void)
1568 { 1524 {
1569 overlay unsigned char switch_depth = 255; 1525 overlay unsigned char switch_depth = 255;
1570 overlay unsigned char switch_gas = 0; 1526 overlay unsigned char switch_gas = 0;
1571 overlay unsigned char j; 1527 overlay unsigned char j;
1572 1528
1573 // // no automatic gas changes in CCR mode 1529 // loop over all gases to find the shallowest one below or at current depth
1574 // if( (deco_status & MODE_MASK) == MODE_CCR ) return 0;
1575
1576 // loop over all deco gases to find the shallowest one below or at current depth
1577 for( j = 0; j < NUM_GAS; ++j ) 1530 for( j = 0; j < NUM_GAS; ++j )
1578 { 1531 {
1579 // Is this gas not the one we are already breathing?
1580 if( j+1 != sim_gas_current_num )
1581
1582 // Is this gas available? 1532 // Is this gas available?
1583 if( char_I_deco_gas_type[j] > 0 ) 1533 if( char_I_deco_gas_type[j] > 0 )
1584 1534
1585 // Is the change depth of the this gas deeper than or 1535 // Is the change depth of the this gas deeper than or
1586 // at least equal to the current depth? 1536 // at least equal to the current depth?
1587 if( char_I_deco_gas_change[j] >= char_depth_sim ) 1537 if( char_I_deco_gas_change[j] >= char_depth_sim )
1588 1538
1589 // Is the change depth of this gas shallower than the 1539 // Is the change depth of this gas shallower than or
1590 // change depth of the gas we are currently on? 1540 // at least equal to the change depth of the best gas
1591 if( char_I_deco_gas_change[j] < sim_gas_current_depth ) 1541 // found so far, or is it the first better gas found?
1592 1542 if( char_I_deco_gas_change[j] <= switch_depth )
1593 // Is the change depth of this gas shallower than the change 1543
1594 // depth of the best gas found so far, or is it the first 1544 #ifdef _gas_contingency
1595 // better gas found? 1545 // Is there still enough of this gas or doesn't it matter?
1596 if( char_I_deco_gas_change[j] < switch_depth ) 1546 if( ( gas_volume_need[j] < gas_volume_avail[j] ) || ( !char_I_gas_contingency ) )
1547 #endif
1597 1548
1598 // If there is a yes to all these questions, we have a better gas! 1549 // If there is a yes to all these questions, we have a better gas!
1599 { 1550 {
1600 switch_gas = j+1; // remember this gas (1..5) 1551 // memorize this gas (1..5) and its change depth
1601 switch_depth = char_I_deco_gas_change[j]; // remember its change depth 1552 switch_gas = j+1;
1602 } 1553 switch_depth = char_I_deco_gas_change[j];
1603 1554 }
1604 } // continue looping through all gases to eventually find an even better gas 1555 } // continue looping through all gases to eventually find an even better gas
1605 1556
1606 // has a better gas been found? 1557 // has a best gas been found?
1607 if( switch_gas ) 1558 if( switch_gas )
1608 { 1559 {
1609 // YES - set the better gas as the new gas 1560 // YES - export the best gas and its change depth
1610 sim_gas_current_num = switch_gas; 1561 sim_gas_best_num = switch_gas;
1611 1562 sim_gas_best_depth = switch_depth;
1612 // set its change depth as the last used change depth 1563
1613 sim_gas_current_depth = switch_depth; 1564 // is the best gas different from the current gas?
1614 1565 if( sim_gas_best_num != sim_gas_current_num )
1615 assert( sim_gas_current_depth < switch_depth ); 1566 {
1616 1567 // YES - signal advice for a gas change
1617 // signal a better gas was found 1568 return 1;
1618 return 1; 1569 }
1619 } 1570 }
1620 else 1571
1621 { 1572 // no best gas found or current gas is the best gas
1622 // NO - signal no better gas was found 1573 return 0;
1623 return 0; 1574 }
1624 } 1575
1576
1577 //////////////////////////////////////////////////////////////////////////////
1578 // Switch to the best gas
1579 //
1580 // Input: sim_gas_best_num index of the best gas (1..5)
1581 // sim_gas_best_depth switch depth of the best gas
1582 //
1583 // Modified: sim_gas_current_num index of the new gas (1..5)
1584 // sim_gas_current_depth switch depth of the new gas
1585 //
1586 static void gas_take_best(void)
1587 {
1588 // set new gas
1589 sim_gas_current_num = sim_gas_best_num;
1590 sim_gas_current_depth = sim_gas_best_depth;
1625 } 1591 }
1626 1592
1627 1593
1628 ////////////////////////////////////////////////////////////////////////////// 1594 //////////////////////////////////////////////////////////////////////////////
1629 // Set calc_N2/He/O2_ratios by sim_gas_current_num 1595 // Set calc_N2/He/O2_ratios by sim_gas_current_num
1697 // sim_/real_He_ratio : (simulated) He ratio breathed 1663 // sim_/real_He_ratio : (simulated) He ratio breathed
1698 // sim_/real_pres_respiration : (simulated) respiration pressure [bar] 1664 // sim_/real_pres_respiration : (simulated) respiration pressure [bar]
1699 // sim_/real_pSCR_drop : (simulated) pSCR O2 drop 1665 // sim_/real_pSCR_drop : (simulated) pSCR O2 drop
1700 // pres_surface : surface pressure [bar] 1666 // pres_surface : surface pressure [bar]
1701 // char_I_const_ppO2 : ppO2 reported from sensors or setpoint [cbar] 1667 // char_I_const_ppO2 : ppO2 reported from sensors or setpoint [cbar]
1702 // float_deco_distance : safety factor, additional depth below stop depth [bar] 1668 // float_deco_distance : safety factor, additional depth below stop depth [bar] - not used any more
1703 // ppWater : water-vapor pressure inside respiratory tract [bar] 1669 // ppWater : water-vapor pressure inside respiratory tract [bar]
1704 // 1670 //
1705 // Output: ppN2 : respired N2 partial pressure 1671 // Output: ppN2 : respired N2 partial pressure
1706 // ppHe : respired He partial pressure 1672 // ppHe : respired He partial pressure
1707 // char_ppO2 : breathed ppO2 in %, used for CNS calculation 1673 // char_ppO2 : breathed ppO2 in %, used for CNS calculation
1756 { 1722 {
1757 //---- simulated tissues ------------------------------------------------------ 1723 //---- simulated tissues ------------------------------------------------------
1758 1724
1759 // correct sim_pres_respiration if shallower than calculated stop depth 1725 // correct sim_pres_respiration if shallower than calculated stop depth
1760 calc_pres_respiration = ( real_pres_respiration < sim_pres_respiration ) ? real_pres_respiration : sim_pres_respiration; 1726 calc_pres_respiration = ( real_pres_respiration < sim_pres_respiration ) ? real_pres_respiration : sim_pres_respiration;
1727
1728 // +++ pressure surcharge if outside deco stops area yet ???
1761 1729
1762 status = deco_status; 1730 status = deco_status;
1763 calc_O2_ratio = sim_O2_ratio; 1731 calc_O2_ratio = sim_O2_ratio;
1764 calc_N2_ratio = sim_N2_ratio; 1732 calc_N2_ratio = sim_N2_ratio;
1765 1733
1864 else char_ppO2 = (unsigned char)(100 * ppO2 + 0.5); 1832 else char_ppO2 = (unsigned char)(100 * ppO2 + 0.5);
1865 1833
1866 1834
1867 //---- calculate ppN2 and ppHe --------------------------------------------------------------------- 1835 //---- calculate ppN2 and ppHe ---------------------------------------------------------------------
1868 1836
1869 // add deco safety distance when working on simulated tissues 1837 // add deco safety distance when working on simulated tissues - not used any more
1870 if( !(tissue_increment & TISSUE_SELECTOR) ) calc_pres_respiration += float_deco_distance; 1838 // if( !(tissue_increment & TISSUE_SELECTOR) ) calc_pres_respiration += float_deco_distance;
1871 1839
1872 // compute ppN2 and ppHe, capture potential failure conditions first: 1840 // compute ppN2 and ppHe, capture potential failure conditions first:
1873 if( calc_pres_respiration > ppWater ) 1841 if( calc_pres_respiration > ppWater )
1874 { 1842 {
1875 // subtract water vapor pressure 1843 // subtract water vapor pressure
1889 { 1857 {
1890 // calculated respired pressure is < water vapor pressure, thus set ppN2 and ppHe to 0 1858 // calculated respired pressure is < water vapor pressure, thus set ppN2 and ppHe to 0
1891 ppN2 = 0.0; 1859 ppN2 = 0.0;
1892 ppHe = 0.0; 1860 ppHe = 0.0;
1893 } 1861 }
1894 } 1862
1895 1863 #ifdef _helium
1896 1864 // calculating real tissues?
1897 ////////////////////////////////////////////////////////////////////////////// 1865 if( tissue_increment & TISSUE_SELECTOR )
1898 // init_output_vars 1866 {
1899 // 1867 overlay unsigned char temp;
1868
1869 // compute gas density of current mix in multiples of 0.01 grams per liter
1870 int_O_gas_density = (unsigned int)( 17.9 * ppHe + 125.1 * ppN2 + 142.8 * ppO2 );
1871
1872 // convert gas density into a 8 bit integer
1873 temp = (unsigned char)( (int_O_gas_density + 9) / 10 );
1874
1875 // limit to display max and set warning or attention flag
1876 if( temp > 99 ) int_O_gas_density = 999 | INT_FLAG_WARNING;
1877 else if( temp > char_I_gas_density_warn ) int_O_gas_density |= INT_FLAG_WARNING;
1878 else if( temp > char_I_gas_density_att ) int_O_gas_density |= INT_FLAG_ATTENTION;
1879 }
1880 #endif
1881 }
1882
1883
1884 //////////////////////////////////////////////////////////////////////////////
1900 // Initializes all output variables to their default values 1885 // Initializes all output variables to their default values
1901 // 1886 //
1902 static void init_output_vars(void) 1887 static void init_output_vars(void)
1903 { 1888 {
1904 // clear the internal stops table from remains lasting from the previous dive or deco calculator run 1889 // clear the internal stops table from remains lasting from the previous dive or deco calculator run
1937 #ifdef _rx_functions 1922 #ifdef _rx_functions
1938 // clear TR values 1923 // clear TR values
1939 int_O_SAC_measured = 0 + INT_FLAG_NOT_AVAIL; // SAC rate 1924 int_O_SAC_measured = 0 + INT_FLAG_NOT_AVAIL; // SAC rate
1940 int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 1 1925 int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 1
1941 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 2 1926 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 2
1942 #endif 1927 int_O_tank_pressure = 0; // tank pressure for logging
1943 1928 #endif
1944 } 1929
1945 1930 #ifdef _helium
1946 1931 int_O_gas_density = 0;
1947 ////////////////////////////////////////////////////////////////////////////// 1932 #endif
1948 // clear_tissue 1933
1949 // 1934 // also clear any time++ request
1935 char_I_sim_advance_time = 0;
1936 }
1937
1938
1939 //////////////////////////////////////////////////////////////////////////////
1950 // Reset all tissues to surface pressure equilibrium state 1940 // Reset all tissues to surface pressure equilibrium state
1951 // 1941 //
1952 // Input: int_I_pres_surface current surface pressure in hPa (mbar) 1942 // Input: int_I_pres_surface current surface pressure in hPa (mbar)
1953 // 1943 //
1954 // Output: real_pres_tissue_N2[] partial pressure of N2 in real tissues 1944 // Output: real_pres_tissue_N2[] partial pressure of N2 in real tissues
2005 char_O_deco_info = 0; 1995 char_O_deco_info = 0;
2006 } 1996 }
2007 1997
2008 1998
2009 ////////////////////////////////////////////////////////////////////////////// 1999 //////////////////////////////////////////////////////////////////////////////
2010 // calc_hauptroutine 2000 // Deco engine main code
2011 // 2001 //
2012 // This is the major code in dive mode, it calculates the tissue pressures, 2002 // This is the major code in dive mode, it calculates the tissue pressures,
2013 // the bottom time, and it calculates the ascend with all deco stops, etc. 2003 // the bottom time, and it calculates the ascend with all deco stops, etc.
2014 // 2004 //
2015 // Input: char_O_main_status deco engine control and real tissues mode 2005 // Input: char_O_main_status deco engine control and real tissues mode
2019 // char_I_SAC_work gas usage rate during working phase in l/min 2009 // char_I_SAC_work gas usage rate during working phase in l/min
2020 // char_I_SAC_deco gas usage rate during deco stops phase in l/min 2010 // char_I_SAC_deco gas usage rate during deco stops phase in l/min
2021 // 2011 //
2022 // char_I_deco_model selector for GF extension 2012 // char_I_deco_model selector for GF extension
2023 // char_I_ascent_speed ascent speed 2013 // char_I_ascent_speed ascent speed
2024 // char_I_deco_distance safety distance between stop depth and calculated depth
2025 // char_I_saturation_multiplier safety factor for tissue saturation 2014 // char_I_saturation_multiplier safety factor for tissue saturation
2026 // char_I_desaturation_multiplier safety factor for tissue desaturation 2015 // char_I_desaturation_multiplier safety factor for tissue desaturation
2027 // 2016 //
2028 // char_I_pressure_gas[] amount of gas available for ascent in bar 2017 // char_I_pressure_gas[] amount of gas available for ascent in bar
2029 // int_I_pressure_drop[] pressure drop used to calculate SAC rate 2018 // int_I_pressure_drop[] pressure drop used to calculate SAC rate
2054 // int_IO_pressure_need[] pressure needs to pressure reading 1 & 2 2043 // int_IO_pressure_need[] pressure needs to pressure reading 1 & 2
2055 // 2044 //
2056 static void calc_hauptroutine(void) 2045 static void calc_hauptroutine(void)
2057 { 2046 {
2058 overlay unsigned short int_ppO2_min; 2047 overlay unsigned short int_ppO2_min;
2059 overlay unsigned short int_ppO2_max; 2048 overlay unsigned short int_ppO2_max_warn;
2049 overlay unsigned short int_ppO2_max_att;
2060 overlay unsigned short int_ppO2_max_dil; 2050 overlay unsigned short int_ppO2_max_dil;
2061 overlay unsigned short int_ppO2_max_max;
2062 overlay float EAD; 2051 overlay float EAD;
2063 overlay float END; 2052 overlay float END;
2064 2053
2065 //============================================================================================= 2054 //=============================================================================================
2066 2055
2110 2099
2111 // clear all command flags on the master mode to signal that the command is read 2100 // clear all command flags on the master mode to signal that the command is read
2112 char_O_deco_status &= ~COMMAND_MASK; 2101 char_O_deco_status &= ~COMMAND_MASK;
2113 2102
2114 // set the calculation phase to start with to doing the cyclic initialization 2103 // set the calculation phase to start with to doing the cyclic initialization
2115 next_planning_phase = PHASE_11_CYCLIC_INIT; 2104 next_planning_phase = PHASE_20_CYCLIC_INIT;
2116 2105
2117 // continue in CALCULATING 2106 // continue in CALCULATING
2118 2107
2119 2108
2120 case CALCULATING: 2109 case CALCULATING:
2153 #endif 2142 #endif
2154 { 2143 {
2155 // acquire current environmental data 2144 // acquire current environmental data
2156 calc_hauptroutine_data_input(); 2145 calc_hauptroutine_data_input();
2157 2146
2158 // calculate ppO2, ppN2 and ppHe 2147 // calculate ppO2, ppN2 and ppHe for real tissues
2159 calc_alveolar_pressures(); 2148 calc_alveolar_pressures();
2160 2149
2161 // add decent calculation here and include trigger in above if-statement 2150 // add decent calculation here and include trigger in above if-statement
2162 // TODO 2151 // TODO
2163 2152
2237 float_value = OC_ppO2; convert_float_to_int(); int_O_pure_ppO2 = int_value; // pure gas 2226 float_value = OC_ppO2; convert_float_to_int(); int_O_pure_ppO2 = int_value; // pure gas
2238 float_value = pSCR_ppO2; convert_float_to_int(); int_O_pSCR_ppO2 = int_value; // pSCR calculated 2227 float_value = pSCR_ppO2; convert_float_to_int(); int_O_pSCR_ppO2 = int_value; // pSCR calculated
2239 #endif 2228 #endif
2240 2229
2241 2230
2242 //---- Set/Reset Deco Mode -------------------------------------------------------------------- 2231 //---- Set/Clear Deco Mode ------------------------------------------------------------------
2232
2233 // Clear the deco mode flag if:
2234 // deco mode is set
2235 // AND we are deeper than 7 meters below the deepest deco stop
2236 // (7 meters chosen as to be 2 stop depth intervals plus 1 additional meter below)
2237 if ( ( deco_info & DECO_MODE ) > 0 )
2238 if ( ( char_depth_real ) > char_O_deco_depth[0] + 7 )
2239 deco_info &= ~DECO_MODE;
2243 2240
2244 // Set the deco mode flag if: 2241 // Set the deco mode flag if:
2245 // deco mode is not set 2242 // deco mode is not set
2246 // AND breathing an OC deco gas (gas type 3) 2243 // AND breathing an OC deco gas (gas type 3)
2247 // OR breathing a gas or diluent that officially is disabled (type 0) 2244 // OR breathing a gas or diluent that officially is disabled (type 0)
2248 // OR there is a deco stop and we are less deep than 1 meter below the deepest deco stop 2245 // OR there is a deco stop
2249 if ( ( deco_info & DECO_FLAG ) == 0 ) 2246 if ( ( deco_info & DECO_MODE ) == 0 )
2250 if ( ( char_I_current_gas_type == 3 ) 2247 if ( ( char_I_current_gas_type == 3 )
2251 || ( char_I_current_gas_type == 0 ) 2248 || ( char_I_current_gas_type == 0 )
2252 || ( ( char_O_deco_depth[0] > 0 ) && ( char_depth_real <= char_O_deco_depth[0] + 1 ) ) 2249 || ( char_O_deco_depth[0] > 0 )
2253 ) 2250 )
2254 deco_info |= DECO_FLAG; 2251 deco_info |= DECO_MODE;
2255
2256 // Clear the deco mode flag if:
2257 // deco mode is set
2258 // AND deeper than 7 meters below deepest deco stop (7 meters = 2 stop depth intervals plus 1 meter below stop)
2259 if ( ( deco_info & DECO_FLAG ) > 0 )
2260 if ( ( char_depth_real > char_O_deco_depth[0] + 7 )
2261 )
2262 deco_info &= ~DECO_FLAG;
2263 2252
2264 2253
2265 //---- Compute ppO2 Warnings ------------------------------------------------------------------ 2254 //---- Compute ppO2 Warnings ------------------------------------------------------------------
2266 2255
2267 // compute conditional min values 2256 // compute conditional min value
2268 #ifdef _ccr_pscr 2257 #ifdef _ccr_pscr
2269 int_ppO2_min = ( main_status & MODE_LOOP ) ? (unsigned short)char_I_ppO2_min_loop : (unsigned short)char_I_ppO2_min; 2258 int_ppO2_min = ( main_status & MODE_LOOP ) ? (unsigned short)char_I_ppO2_min_loop : (unsigned short)char_I_ppO2_min;
2270 #else 2259 #else
2271 int_ppO2_min = (unsigned short)char_I_ppO2_min; 2260 int_ppO2_min = (unsigned short)char_I_ppO2_min;
2272 #endif 2261 #endif
2273 2262
2274 // compute conditional max values 2263 // determine the absolute max value (should be the deco one, but who knows...)
2275 int_ppO2_max = ( deco_info & DECO_FLAG ) ? (unsigned short)char_I_ppO2_max_deco : (unsigned short)char_I_ppO2_max_work; 2264 int_ppO2_max_warn = ( char_I_ppO2_max_work > char_I_ppO2_max_deco) ? char_I_ppO2_max_work : char_I_ppO2_max_deco;
2276 2265
2277 // add some margin on ppO2 max to compensate for surface pressures > 1.000 mbar 2266 // add some margin to compensate for surface pressures > 1.000 mbar
2278 int_ppO2_max += ppO2_MARGIN_ON_MAX; 2267 int_ppO2_max_warn += ppO2_MARGIN_ON_MAX;
2279 2268
2280 // get biggest of char_I_ppO2_max_work / char_I_ppO2_max_deco 2269 // determine the normal max value
2281 int_ppO2_max_max = ( char_I_ppO2_max_deco > char_I_ppO2_max_work ) ? char_I_ppO2_max_deco : char_I_ppO2_max_work; 2270 int_ppO2_max_att = ( deco_info & DECO_MODE ) ? (unsigned short)char_I_ppO2_max_deco : (unsigned short)char_I_ppO2_max_work;
2271
2272 // add some margin to compensate for surface pressures > 1.000 mbar
2273 int_ppO2_max_att += ppO2_MARGIN_ON_MAX;
2282 2274
2283 #ifdef _ccr_pscr 2275 #ifdef _ccr_pscr
2284 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold 2276 // default value for the upper diluent ppO2 warning threshold is the upper warning threshold
2285 int_ppO2_max_dil = int_ppO2_max; 2277 int_ppO2_max_dil = int_ppO2_max_warn;
2286 2278
2287 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint 2279 // when enabled and in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
2280 if( char_I_dil_ppO2_check )
2288 if( (main_status & MODE_MASK) == MODE_CCR ) 2281 if( (main_status & MODE_MASK) == MODE_CCR )
2289 { 2282 {
2290 overlay unsigned short max_dil; 2283 overlay unsigned short max_dil;
2291 2284
2292 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint... 2285 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
2293 // (the condition protects from negative numbers which would cause a wrap-around in unsigned integers) 2286 // (the condition protects from negative numbers which would cause a wrap-around in unsigned integers)
2294 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned short)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0; 2287 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned short)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
2295 2288
2296 // ...but never above int_ppO2_max. 2289 // ...but never above int_ppO2_max_warn
2297 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil; 2290 if( max_dil < int_ppO2_max_warn ) int_ppO2_max_dil = max_dil;
2298 2291
2299 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check 2292 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
2300 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks. 2293 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
2301 } 2294 }
2302 #endif 2295 #endif
2303 2296
2304 // check for safe range of breathed gas 2297 // check for safe range of breathed gas
2305 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 2298 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
2306 else if ( int_O_breathed_ppO2 >= int_ppO2_max_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 2299 else if ( int_O_breathed_ppO2 >= int_ppO2_max_warn ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
2307 else if ( deco_info & DECO_FLAG ) ; // no attention generated in deco mode 2300 else if ( deco_info & DECO_MODE ) ; // no attention generated in deco mode
2308 else if ( main_status & MODE_LOOP ) ; // no attention generated in loop modes 2301 else if ( main_status & MODE_LOOP ) ; // no attention generated in loop modes
2309 else if ( int_O_breathed_ppO2 >= (unsigned short)char_I_ppO2_max_work ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; 2302 else if ( int_O_breathed_ppO2 >= int_ppO2_max_att ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
2310 2303
2311 #ifdef _ccr_pscr 2304 #ifdef _ccr_pscr
2312 // check for safe range of pure oxygen 2305 // check for safe range of pure oxygen
2313 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 2306 if ( int_O_O2_ppO2 >= int_ppO2_max_warn ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
2314 2307
2315 // check for safe range of pure diluent 2308 // check for safe range of pure diluent
2316 if ( int_O_pure_ppO2 <= (unsigned short)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 2309 if ( int_O_pure_ppO2 <= (unsigned short)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
2317 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 2310 else if ( int_O_pure_ppO2 >= int_ppO2_max_warn ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
2318 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; 2311 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION;
2319 2312
2320 // check for safe range of calculated pSCR loop gas 2313 // check for safe range of calculated pSCR loop gas
2321 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 2314 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
2322 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 2315 else if ( int_O_pSCR_ppO2 >= int_ppO2_max_warn ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
2323 #endif 2316 #endif
2324 2317
2325 } // tasks every second / on the first section of the second 2318 } // tasks every second / on the first section of the second
2326 2319
2327 2320
2371 2364
2372 // initialize all output variables to defaults 2365 // initialize all output variables to defaults
2373 init_output_vars(); 2366 init_output_vars();
2374 2367
2375 // safeguard input parameters that are constant during the course of the dive 2368 // safeguard input parameters that are constant during the course of the dive
2376 if( char_I_deco_distance > 20 ) char_I_deco_distance = 20;
2377 if( char_I_ascent_speed < 5 ) char_I_ascent_speed = 5; 2369 if( char_I_ascent_speed < 5 ) char_I_ascent_speed = 5;
2378 if( char_I_ascent_speed > 10 ) char_I_ascent_speed = 10; 2370 if( char_I_ascent_speed > 10 ) char_I_ascent_speed = 10;
2379 2371
2380 // convert input parameters to float numbers 2372 // convert input parameters to float numbers
2381 float_deco_distance = 0.01 * char_I_deco_distance;
2382 float_ascent_speed = 1.00 * char_I_ascent_speed; 2373 float_ascent_speed = 1.00 * char_I_ascent_speed;
2374
2383 2375
2384 // initialize values that will be recalculated later on periodically 2376 // initialize values that will be recalculated later on periodically
2385 deco_warnings = 0; // reset all deco warnings 2377 deco_warnings = 0; // reset all deco warnings
2386 deco_info = 0; // reset all deco infos 2378 deco_info = 0; // reset all deco infos
2387 IBCD_tissue_vector = 0; // reset tissue IBCD vector 2379 IBCD_tissue_vector = 0; // reset tissue IBCD vector
2388 NDL_tissue_start_norm = 0; // initialize the tissue to start with when calculating normal NDL time 2380 NDL_tissue_start_norm = 0; // initialize the tissue to start with when calculating normal NDL time
2389 NDL_tissue_start_alt = 0; // initialize the tissue to start with when calculating alternative NDL time 2381 NDL_tissue_start_alt = 0; // initialize the tissue to start with when calculating alternative NDL time
2390 2382
2391 // enforce initialization of GF data on first cyclic initialization 2383 // enforce initialization of GF data on first cyclic initialization
2392 GF_high_last = 0; 2384 GF_high_last = 255;
2393 GF_low_last = 0; 2385 GF_low_last = 255;
2394 2386
2387 #ifdef _gas_contingency
2388 // shall check for gas pan out?
2389 if( char_I_gas_contingency )
2390 {
2391 overlay float reduction = 0.5 * (float)char_I_SAC_deco * (1.0 + (float)char_I_depth_last_deco / 10.0);
2392
2393 // YES - calculate volumes available for each gas
2394 for( i = 0; i < NUM_GAS; i++ )
2395 {
2396 // total available volume = tank size * fill press, char_I_gas_avail_pres is in multiples of 10 bar
2397 gas_volume_avail[i] = (float)char_I_gas_avail_size[i] * (float)char_I_gas_avail_pres[i] * 10.0;
2398
2399 // reduce total available volumes by due for 1/2 minute on last stop
2400 gas_volume_avail[i] -= reduction;
2401 }
2402 }
2403 #endif
2395 2404
2396 #ifdef _cave_mode 2405 #ifdef _cave_mode
2397 char_I_backtrack_time = 0; //clear backtracking time (index to char_I_backtrack_depth) 2406 char_I_backtrack_time = 0; //clear backtracking time (index to char_I_backtrack_depth)
2398 char_I_backtrack_depth = 0; //prime first entry with a depth of 0 meter 2407 char_I_backtrack_depth = 0; //prime first entry with a depth of 0 meter
2399 #endif 2408 #endif
2405 #endif 2414 #endif
2406 2415
2407 2416
2408 // the next calculation phase will do the cyclic initialization of the deco engine if a 2417 // the next calculation phase will do the cyclic initialization of the deco engine if a
2409 // normal or alternative plan shall be calculated, else the calculation cycle is done. 2418 // normal or alternative plan shall be calculated, else the calculation cycle is done.
2410 if( deco_status & PLAN_MASK ) next_planning_phase = PHASE_11_CYCLIC_INIT; 2419 if( deco_status & PLAN_MASK ) next_planning_phase = PHASE_20_CYCLIC_INIT;
2411 else next_planning_phase = PHASE_00_DONE; 2420 else next_planning_phase = PHASE_00_DONE;
2412 2421
2413 break; 2422 break;
2414 2423
2415 2424
2416 // 2425 //
2417 //---- once-per-cycle Initialization of the Deco Engine------------------------------------ 2426 //---- once-per-cycle Initialization of the Deco Engine -----------------------------------
2418 // 2427 //
2419 case PHASE_11_CYCLIC_INIT: 2428 case PHASE_20_CYCLIC_INIT:
2420 2429
2421 // target the simulated tissues (flag bit 7 = 0) 2430 // target the simulated tissues (flag bit 7 = 0)
2422 tissue_increment = 0; 2431 tissue_increment = 0;
2423 2432
2424 // clear the internal stops table 2433 // clear the internal stops table
2433 2442
2434 // initialize GF parameters if using GF model 2443 // initialize GF parameters if using GF model
2435 if( char_I_deco_model != 0 ) 2444 if( char_I_deco_model != 0 )
2436 { 2445 {
2437 // update GF parameters (GFs may have been switched between GF and aGF) 2446 // update GF parameters (GFs may have been switched between GF and aGF)
2438 if( (char_I_GF_High_percentage != GF_high_last) || (char_I_GF_Low_percentage != GF_low_last) ) 2447 if( (char_I_GF_Low_percentage != GF_low_last) || (char_I_GF_High_percentage != GF_high_last) )
2439 { 2448 {
2440 // store new values in integer format 2449 // store new values in integer format
2450 GF_low_last = char_I_GF_Low_percentage;
2441 GF_high_last = char_I_GF_High_percentage; 2451 GF_high_last = char_I_GF_High_percentage;
2442 GF_low_last = char_I_GF_Low_percentage; 2452
2443 2453 // safeguard and store new values in float format
2444 // store new values in float format 2454 GF_low = ( GF_low_last > 10 ) ? 0.01 * GF_low_last : 0.10 ;
2445 GF_high = 0.01 * char_I_GF_High_percentage; 2455 GF_high = ( GF_high_last > GF_low_last ) ? 0.01 * GF_high_last : GF_low;
2446 GF_low = 0.01 * char_I_GF_Low_percentage; 2456
2447 2457
2448 // reset low depth references and slopes 2458 // reset low depth references and slopes
2449 GF_low_depth_norm = 0; 2459 GF_low_depth_norm = 0;
2450 GF_low_depth_alt = 0; 2460 GF_low_depth_alt = 0;
2451 GF_slope_norm = 0.0; 2461 GF_slope_norm = 0.0;
2466 } 2476 }
2467 2477
2468 // initialize the simulated CNS value with the current CNS value of the real tissues 2478 // initialize the simulated CNS value with the current CNS value of the real tissues
2469 CNS_fraction_sim = CNS_fraction_real; 2479 CNS_fraction_sim = CNS_fraction_real;
2470 2480
2471 // initialize the simulated depth with the current depth (in absolute pressure) 2481 // initialize the simulated depth with the current depth,
2482 // memorize current depth as start depth of the simulation
2472 sim_pres_respiration = real_pres_respiration; 2483 sim_pres_respiration = real_pres_respiration;
2473 2484 char_depth_sim = char_depth_real;
2474 // compute the depth in meters where we are now 2485 char_depth_sim_start = char_depth_real;
2475 float_depth_real = (sim_pres_respiration - pres_surface) * BAR_TO_METER;
2476
2477 // convert to integer and round up to next full meter
2478 char_depth_real = (unsigned char)(float_depth_real + 0.99);
2479
2480 // initialize depth for deco ascent calculation
2481 char_depth_sim = char_depth_real;
2482 2486
2483 // Lookup the gas that is currently breathed with the real tissues and set it as 2487 // Lookup the gas that is currently breathed with the real tissues and set it as
2484 // the gas to be used with the simulated tissues, too. This gas will be used until 2488 // the gas to be used with the simulated tissues, too. This gas will be used until
2485 // gas_find_better() is invoked and finds a better gas to switch to. 2489 // gas_find_best()/gas_take_best() is invoked and switches to a better gas.
2486 gas_find_current(); 2490 gas_take_current();
2487 2491
2488 // Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio). These ratios 2492 // Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio).
2489 // can be kept until a gas switch is done. Thus, if a call to gas_find_better() has 2493 // These ratios can be kept until a gas switch is done. Thus, if a call to
2490 // found a better gas and initiated a switch, gas_set_ratios() needs to be called again. 2494 // gas_find_best() has found a better gas and this gas is taken by a call
2495 // to gas_take_best(), gas_set_ratios() needs to be called again.
2491 gas_set_ratios(); 2496 gas_set_ratios();
2492 2497
2493 // compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration 2498 // compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration
2494 calc_alveolar_pressures(); 2499 calc_alveolar_pressures();
2495 2500
2496 // initialize the no decompression limit (NDL) time to 240 minutes 2501 // initialize the no decompression limit (NDL) time to 240 minutes
2497 NDL_time = 240; 2502 NDL_time = 240;
2503
2504 // initialize the total ascent time to 0 minutes
2505 ascent_time = 0;
2498 2506
2499 // retrieve the tissue that had the shortest NDL time during last calculation 2507 // retrieve the tissue that had the shortest NDL time during last calculation
2500 NDL_tissue_start = ( deco_status & CALC_NORM ) ? NDL_tissue_start_norm : NDL_tissue_start_alt; 2508 NDL_tissue_start = ( deco_status & CALC_NORM ) ? NDL_tissue_start_norm : NDL_tissue_start_alt;
2501 2509
2502 // start calculating NDL time with the tissue that had the shortest NDL last time 2510 // start calculating NDL time with the tissue that had the shortest NDL last time
2505 2513
2506 // initialization for calculating the initial ascent 2514 // initialization for calculating the initial ascent
2507 // start with 1 minute ascent steps when calculating the initial ascent 2515 // start with 1 minute ascent steps when calculating the initial ascent
2508 fast = 1; 2516 fast = 1;
2509 2517
2510 // initialization for calc_gas_needs_ascent()
2511 gas_needs_next_phase = GAS_NEEDS_INIT;
2512
2513 // initialization for convert_gas_needs_to_press() 2518 // initialization for convert_gas_needs_to_press()
2514 gas_needs_gas_index = 0; 2519 gas_needs_gas_index = 0;
2515 2520
2521 // shall calculate gas needs?
2522 if( main_status & CALC_VOLUME )
2523 {
2524 // set the usage rate (SAC rate), starting with working part of the dive
2525 gas_needs_usage_rate = char_I_SAC_work;
2526
2527 // clear the gas volume needs for gases 1-5
2528 for( i = 0; i < NUM_GAS; ++i ) gas_volume_need[i] = 0.0;
2529
2530 #ifdef _rx_functions
2531 // only for OSTC TR model with TR functions enabled
2532 if( main_status & TR_FUNCTIONS )
2533 {
2534 // invalidate pressure needs to pressure readings
2535 int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL;
2536 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL;
2537 }
2538 #endif
2539 }
2516 2540
2517 #ifdef _profiling 2541 #ifdef _profiling
2518 profiling_runs = 0; 2542 profiling_runs = 0;
2519 #endif 2543 #endif
2520 2544
2521 // The next calculation phase will 2545 // The next calculation phase will
2522 // - calculate the bottom segment if extended bottom time is configured (fTTS), 2546 // - calculate the extended bottom segment if extended bottom time is configured (fTTS),
2547 // - calculate the bottom segment gas need if gas needs calculation is configured,
2523 // - proceed with calculating the NDL time else. 2548 // - proceed with calculating the NDL time else.
2524 if ( deco_status & DELAYED_ASCENT ) next_planning_phase = PHASE_20_EXTENDED_BOTTOM_TIME; 2549 if ( deco_status & DELAYED_ASCENT ) next_planning_phase = PHASE_30_EXTENDED_BOTTOM_TIME;
2525 else next_planning_phase = PHASE_30_NDL_TIME; 2550 else if ( main_status & CALC_VOLUME ) next_planning_phase = PHASE_40_BOTTOM_GAS_NEED;
2551 else next_planning_phase = PHASE_50_NDL_TIME;
2526 2552
2527 break; 2553 break;
2528 2554
2529 2555
2530 // 2556 //
2531 //---- extended Bottom Time --------------------------------------------------------------- 2557 //---- extended Bottom Time ---------------------------------------------------------------
2532 // 2558 //
2533 case PHASE_20_EXTENDED_BOTTOM_TIME: 2559 case PHASE_30_EXTENDED_BOTTOM_TIME:
2534 2560
2535 // program interval on simulated tissues (flag bit 7 = 0) 2561 // program interval on simulated tissues (flag bit 7 = 0)
2536 tissue_increment = char_I_extra_time; 2562 tissue_increment = char_I_extra_time;
2537 2563
2538 // calculate ppO2, ppN2 and ppHe 2564 // update the simulated tissues for tissue_increment (char_I_extra_time) minutes at depth,
2539 calc_alveolar_pressures(); 2565 // calc_alveolar_pressures() has already been called in cyclic initialization
2540
2541 // update the tissues
2542 calc_tissues(); 2566 calc_tissues();
2543 2567
2544 // update the CNS value 2568 // update the CNS value for tissue_increment (char_I_extra_time) minutes at depth
2545 calc_CNS(); 2569 calc_CNS();
2546 2570
2571 // the next calculation phase will
2572 // - calculate the extended bottom segment gas needs if gas needs calculation is configured,
2573 // - proceed with calculating the NDL time else.
2574 if ( main_status & CALC_VOLUME ) next_planning_phase = PHASE_40_BOTTOM_GAS_NEED;
2575 else next_planning_phase = PHASE_50_NDL_TIME;
2576
2577 break;
2578
2579
2580 //
2581 //---- Bottom Segment Gas Need ------------------------------------------------------------
2582 //
2583 case PHASE_40_BOTTOM_GAS_NEED:
2584
2585 // on gas 1-5 ?
2586 if( sim_gas_current_num )
2587 {
2588 // YES - set the bottom depth
2589 gas_needs_depth = char_depth_sim_start;
2590
2591 // take either the whole bottom time or just the fTTS/bailout extra time
2592 gas_needs_time = ( main_status & CALCULATE_BOTTOM ) ? char_I_bottom_time : char_I_extra_time;
2593
2594 // calculate gas demand
2595 calc_due_by_depth_time_sac();
2596
2597 // take the result
2598 gas_volume_need[sim_gas_current_num-1] = gas_needs_volume_due;
2599 }
2600
2601
2547 // the next calculation phase will calculate the NDL time 2602 // the next calculation phase will calculate the NDL time
2548 next_planning_phase = PHASE_30_NDL_TIME; 2603 next_planning_phase = PHASE_50_NDL_TIME;
2549 2604
2550 break; 2605 break;
2551 2606
2552 2607
2553 // 2608 //
2554 //---- NDL Time --------------------------------------------------------------------------- 2609 //---- NDL Time ---------------------------------------------------------------------------
2555 // 2610 //
2556 case PHASE_30_NDL_TIME: 2611 case PHASE_50_NDL_TIME:
2557 2612
2558 // Calculate the remaining no decompression limit (NDL) time for the tissue NDL_tissue. 2613 // Calculate the remaining no decompression limit (NDL) time for the tissue NDL_tissue.
2559 // NDL_time will be updated if the NDL time found is shorter than the current NDL_time. 2614 // NDL_time will be updated if the NDL time found is shorter than the current NDL_time.
2560 // 2615 //
2561 // In the initialization phase of the calculation cycle: 2616 // In the initialization phase of the calculation cycle:
2578 if( deco_status & CALC_NORM ) NDL_tissue_start_norm = NDL_tissue_lead; 2633 if( deco_status & CALC_NORM ) NDL_tissue_start_norm = NDL_tissue_lead;
2579 else NDL_tissue_start_alt = NDL_tissue_lead; 2634 else NDL_tissue_start_alt = NDL_tissue_lead;
2580 2635
2581 // done with calculating NDL time, set next calculation phase: 2636 // done with calculating NDL time, set next calculation phase:
2582 // - calculate return and ascent in cave mode if configured, else 2637 // - calculate return and ascent in cave mode if configured, else
2583 // - proceed with gathering the results if within NDL time, or 2638 // - proceed with no-stop ascent if within NDL time, or
2584 // - proceed with the initial ascent if beyond NDL time. 2639 // - proceed with deco ascent if beyond NDL time.
2585 #ifdef _cave_mode 2640 #ifdef _cave_mode
2586 if ( main_status & CAVE_MODE ) next_planning_phase = PHASE_40_CAVE_ASCENT; 2641 if ( main_status & CAVE_MODE ) next_planning_phase = PHASE_60_CAVE_RETURN;
2587 else 2642 else
2588 #endif 2643 #endif
2589 if ( NDL_time ) next_planning_phase = PHASE_70_RESULTS; 2644 next_planning_phase = PHASE_70_OPEN_WATER_ASCENT;
2590 else next_planning_phase = PHASE_60_DECO_ASCENT;
2591 } 2645 }
2592 2646
2593 break; 2647 break;
2594 2648
2595 2649
2596 #ifdef _cave_mode 2650 #ifdef _cave_mode
2597 // 2651 //
2598 //---- Cave Mode Return/Ascent ------------------------------------------------------------ 2652 //---- Cave Mode Return -------------------------------------------------------------------
2599 // 2653 //
2600 case PHASE_40_CAVE_ASCENT: 2654 case PHASE_60_CAVE_RETURN:
2601 2655
2602 // TODO 2656 // TODO
2603 2657
2604 // the next calculation phase will gather all results 2658 // the next calculation phase will gather all results
2605 next_planning_phase = PHASE_70_RESULTS; 2659 next_planning_phase = PHASE_80_RESULTS;
2606 2660
2607 break; 2661 break;
2608 #endif 2662 #endif
2609 2663
2610 2664
2611 // 2665 //
2612 //---- Open Water Ascent with Deco Stops -------------------------------------------------- 2666 //---- Open Water Ascent ------------------------------------------------------------------
2613 // 2667 //
2614 case PHASE_60_DECO_ASCENT: 2668 case PHASE_70_OPEN_WATER_ASCENT:
2615 2669
2616 // program 1 minute interval on simulated tissues 2670 // program 1 minute interval on simulated tissues
2617 tissue_increment = 1; 2671 tissue_increment = 1;
2618 2672
2619 // ascent to the next stop depth or the depth that is reachable within one minute of ascent 2673 // memorize current gas in case there will be a gas change
2620 // and decide if a stop is required (return value = 1/true) or not (return value = 0/false) 2674 sim_gas_last_num = sim_gas_current_num;
2675
2676 // find_next_stop():
2677 // stays at the current stop depth, ascents to the next stop depth, or
2678 // ascents to the depth that is reachable within one minute of ascent
2679 // without needing to stop.
2680 //
2681 // return value : 1/true if a stop is required, else 0/false
2682 // char_depth_sim : current depth (depth achieved)
2683 // char_depth_last : last depth (depth we came from)
2684 //
2621 if( find_next_stop() ) 2685 if( find_next_stop() )
2622 { 2686 {
2687 overlay unsigned char silent_stop = 0;
2688 overlay unsigned char gas_change = 0;
2689
2623 //---- stop required -------------------- 2690 //---- stop required --------------------
2624 2691
2625 // check if there is a better gas to switch to 2692 // check if there is a better gas to switch to
2626 if( gas_find_better() ) 2693 if( gas_find_best() )
2627 { 2694 {
2695 // YES - memorize it
2696 gas_change = 1;
2697
2698 // take the gas
2699 gas_take_best();
2700
2628 // set the new calculation ratios for N2, He and O2 2701 // set the new calculation ratios for N2, He and O2
2629 gas_set_ratios(); 2702 gas_set_ratios();
2630 2703
2631 // doing extended stops? 2704 // add the gas change time to the stop time
2632 if( main_status & EXTENDED_STOPS ) 2705 tissue_increment += char_I_gas_change_time;
2706
2707 // extended stops option enabled and
2708 // gas change depth deeper than the current depth ?
2709 if( main_status & EXTENDED_STOPS )
2710 if( sim_gas_current_depth > char_depth_sim )
2633 { 2711 {
2634 // YES - set char_depth_sim to the gas change depth 2712 // YES - make a "silent" stop at the gas change depth
2635 char_depth_sim = sim_gas_current_depth; 2713 // to figure in the gas change
2636 2714 silent_stop = 1;
2637 // - adjust absolute pressure down to the change depth 2715
2638 sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; 2716 // locate the stop at the shallower one of the
2717 // gas change depth or the depth we came from
2718 char_depth_sim = (sim_gas_current_depth < char_depth_last) ?
2719 sim_gas_current_depth : char_depth_last;
2720
2721 // calculate sim_pres_respiration for
2722 // the adjusted value of char_depth_sim
2723 calc_sim_pres_respiration();
2724
2725 // as we didn't travel the full distance,
2726 // account for the gas change time only
2727 tissue_increment = char_I_gas_change_time;
2728
2729 // if run from the deco calculator,
2730 // put the gas change into the stops table or
2731 // abort deco calculation if the table is full
2732 if( deco_status & DECO_CALCULATOR_MODE )
2733 if( !update_deco_table(tissue_increment) )
2734 next_planning_phase = PHASE_80_RESULTS;
2639 } 2735 }
2640 2736 } // better gas
2641 // prime the deco stop with the gas change time 2737
2642 update_deco_table(char_I_gas_change_time); 2738
2643 } 2739 // if the stop is not a silent one,
2644 2740 // add the stop to an existing stop or add a new stop,
2645 // add one minute to an existing stop or add a new stop at char_depth_sim, 2741 // or abort deco calculation if the deco table is full
2646 // or abort stops calculation if the deco table is full 2742 if( !silent_stop )
2647 if( !update_deco_table(1) ) next_planning_phase = PHASE_70_RESULTS; 2743 if( !update_deco_table(tissue_increment) )
2744 next_planning_phase = PHASE_80_RESULTS;
2745
2746
2747 // shall calculate gas needs?
2748 if( main_status & CALC_VOLUME )
2749 {
2750 // encountered a stop, so switch to deco usage rate (SAC deco)
2751 gas_needs_usage_rate = char_I_SAC_deco;
2752
2753 // set the depth for gas need calculation to the shallower one
2754 // of the start depth (current real depth) and the stop depth
2755 // (assumed depth to be) as we may be shallower than we should be
2756 gas_needs_depth = ( char_depth_sim_start < char_depth_sim ) ?
2757 char_depth_sim_start : char_depth_sim;
2758
2759 // did a gas change occur and last gas is 1-5 and a gas change time set?
2760 if( gas_change && sim_gas_last_num && char_I_gas_change_time )
2761 {
2762 // YES - set time it takes for switching the gas
2763 gas_needs_time = char_I_gas_change_time;
2764
2765 // calculate gas demand
2766 calc_due_by_depth_time_sac();
2767
2768 // add the demand to the overall demand on the last gas
2769 gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due;
2770 }
2771
2772 // current gas is 1-5 ?
2773 if( sim_gas_current_num )
2774 {
2775 // YES - time is 1 minute plus the gas change time (if set)
2776 gas_needs_time = tissue_increment;
2777
2778 // calculate gas demand
2779 calc_due_by_depth_time_sac();
2780
2781 // add the demand to the overall demand on the current gas
2782 gas_volume_need[sim_gas_current_num-1] += gas_needs_volume_due;
2783 }
2784 } // gas need
2648 } 2785 }
2649 else 2786 else
2650 { 2787 {
2651 //---- no stop required ----------------- 2788 //---- no stop required -----------------
2652 2789
2653 // check if there is a better gas to switch to, but only: 2790 // switch to a better gas, but only:
2654 // 2791 //
2655 // if extended stops are activated, 2792 // if extended stops are activated OR if in bailout OR if within NDL
2656 // OR if in bailout mode. 2793 // AND if the actual depth is below (deeper) or at the change depth of the
2794 // better gas (switch depth has not been passed yet)
2795 // AND if the depth of the last stop is above (shallower) or at the change
2796 // depth of the better gas (do not switch on final ascent)
2657 // 2797 //
2658 // Attention: do not use a && formula over both 'if' terms, the extended stops / bailout 2798 // Attention: do not use a && formula over all 'if' terms, the
2659 // condition must be checked before a call to gas_find_better() is made! 2799 // conditions need to be evaluated in the given order!
2660 // 2800 //
2661 if( (main_status & EXTENDED_STOPS) || (deco_status & BAILOUT_MODE) ) 2801 if( (main_status & EXTENDED_STOPS) || (deco_status & BAILOUT_MODE) || NDL_time )
2662 if( gas_find_better() ) 2802 if( gas_find_best() )
2803 if( char_depth_real >= sim_gas_best_depth )
2804 if( char_I_depth_last_deco <= sim_gas_best_depth )
2663 { 2805 {
2806 // YES - take the gas
2807 gas_take_best();
2808
2664 // set the new calculation values for N2, He and O2 2809 // set the new calculation values for N2, He and O2
2665 gas_set_ratios(); 2810 gas_set_ratios();
2666 2811
2667 // stop duration is the gas change time, a change time of 0 minutes 2812 // set char_depth_sim to the gas change depth
2668 // will set a tissue calculation interval of 2 seconds 2813 char_depth_sim = sim_gas_current_depth;
2669 tissue_increment += char_I_gas_change_time; 2814
2670 2815 // calculate sim_pres_respiration for
2671 // set char_depth_sim to the gas change depth, but not deeper than 2816 // the adjusted value of char_depth_sim
2672 // the depth we came from. 2817 calc_sim_pres_respiration();
2673 // (char_depth_last holds the depth from before the ascent step) 2818
2674 char_depth_sim = (sim_gas_current_depth < char_depth_last) ? sim_gas_current_depth : char_depth_last; 2819 // as we didn't travel the full distance,
2675 2820 // account for the gas change time only
2676 // adjust sim_pres_respiration to the adjusted value of char_depth_sim 2821 tissue_increment = char_I_gas_change_time;
2677 sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; 2822
2678 2823 // if in deco and
2679 // create a stop for the gas change in the stops table 2824 // if run from the deco calculator:
2680 update_deco_table(char_I_gas_change_time); 2825 // create a stop for the gas change in the stops table,
2681 } 2826 // abort deco calculation if the deco table is full
2682 } 2827 if( !NDL_time )
2683 2828 if( deco_status & DECO_CALCULATOR_MODE )
2684 //---- one minute has passed by now, update the tissues ---------------- 2829 if( !update_deco_table(tissue_increment) )
2830 next_planning_phase = PHASE_80_RESULTS;
2831
2832 // shall calculate gas needs and gas change time is set?
2833 if( main_status & CALC_VOLUME )
2834 if( char_I_gas_change_time )
2835 {
2836 // YES - set depth to current depth
2837 gas_needs_depth = char_depth_sim;
2838
2839 // set time it takes for switching the gas
2840 gas_needs_time = tissue_increment;
2841
2842 // calculate gas demand
2843 calc_due_by_depth_time_sac();
2844
2845 // add gas demand to the overall demand on the new gas
2846 gas_volume_need[sim_gas_current_num-1] += gas_needs_volume_due;
2847
2848 // was the last gas one of the gases 1-5 ?
2849 if( sim_gas_last_num )
2850 {
2851 // YES - add the same demand to the overall demand on the last gas
2852 gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due;
2853 }
2854 } // gas switching needs
2855 } // gas switch
2856
2857 // shall calculate gas needs and
2858 // last (or still current) gas is 1-5 ?
2859 if( main_status & CALC_VOLUME )
2860 if( sim_gas_last_num )
2861 {
2862 // YES - compute distance traveled
2863 gas_needs_depth = char_depth_last - char_depth_sim;
2864
2865 // at least some positive distance traveled?
2866 if( gas_needs_depth > 1 )
2867 {
2868 // YES - set depth to average depth along the distance
2869 gas_needs_depth += 1;
2870 gas_needs_depth /= 2;
2871 gas_needs_depth += char_depth_sim;
2872
2873 // ascent time is 1 minute
2874 gas_needs_time = 1;
2875
2876 // calculate gas demand
2877 calc_due_by_depth_time_sac();
2878
2879 // add to overall demand
2880 gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due;
2881 }
2882 } // gas travel needs
2883
2884 } // stop / no stop
2885
2886 // --- one or more minutes have passed by now ---
2887
2888 // update the ascent time
2889 ascent_time += tissue_increment;
2685 2890
2686 // compute current ppO2, ppN2 and ppHe 2891 // compute current ppO2, ppN2 and ppHe
2687 calc_alveolar_pressures(); 2892 calc_alveolar_pressures();
2688 2893
2689 // update the tissues 2894 // update the tissues
2691 2896
2692 // update the CNS value 2897 // update the CNS value
2693 calc_CNS(); 2898 calc_CNS();
2694 2899
2695 // finish stops calculation if the surface is reached 2900 // finish stops calculation if the surface is reached
2696 if( char_depth_sim == 0 ) next_planning_phase = PHASE_70_RESULTS; 2901 if( char_depth_sim == 0 ) next_planning_phase = PHASE_80_RESULTS;
2697 2902
2698 break; 2903 break;
2699 2904
2700 2905
2701 /// 2906 ///
2702 //--- Results - Initialization ------------------------------------------------------------ 2907 //--- Results - Initialization ------------------------------------------------------------
2703 // 2908 //
2704 case PHASE_70_RESULTS: 2909 case PHASE_80_RESULTS:
2705 2910
2706 // The current depth is needed by calc_ascenttime(), find_NDL_gas_changes() and 2911 // convert the CNS value to integer
2707 // calc_gas_needs_ascent(). As we don't want it to be calculated multiple times, 2912 convert_sim_CNS_for_display();
2708 // it is done here on stockpile. 2913
2709 char_depth_bottom = (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER + 0.5); 2914 if( deco_status & CALC_NORM )
2915 {
2916 // export the integer CNS value
2917 int_O_CNS_norm = int_sim_CNS_fraction;
2918 }
2919 else
2920 {
2921 // export the integer CNS value
2922 int_O_CNS_alt = int_sim_CNS_fraction;
2923 }
2710 2924
2711 // The next calculation phase will 2925 // The next calculation phase will
2712 // - publish the stops table if in normal plan mode, 2926 // - publish the stops table if in normal plan mode,
2713 // - proceed with remaining results dependent on if within NDL, or 2927 // - proceed with remaining results dependent on if within NDL, or
2714 // - in deco 2928 // - in deco
2715 if ( deco_status & CALC_NORM ) next_planning_phase = PHASE_71_RESULTS_STOPS_TABLE; 2929 if ( deco_status & CALC_NORM ) next_planning_phase = PHASE_81_RESULTS_STOPS_TABLE;
2716 else if ( NDL_time ) next_planning_phase = PHASE_72_RESULTS_NDL; 2930 else if ( NDL_time ) next_planning_phase = PHASE_82_RESULTS_NDL;
2717 else next_planning_phase = PHASE_73_RESULTS_DECO; 2931 else next_planning_phase = PHASE_83_RESULTS_DECO;
2718 2932
2719 break; 2933 break;
2720 2934
2721 2935
2722 /// 2936 ///
2723 //--- Publish Stops Table ----------------------------------------------------------------- 2937 //--- Publish Stops Table -----------------------------------------------------------------
2724 // 2938 //
2725 case PHASE_71_RESULTS_STOPS_TABLE: 2939 case PHASE_81_RESULTS_STOPS_TABLE:
2726 2940
2727 // publish the stops table to the display functions 2941 // publish the stops table to the display functions
2728 publish_deco_table(); 2942 publish_deco_table();
2729 2943
2730 // When entering deco and the ceiling depth becomes > 0 but the 2944 // When entering deco and the ceiling depth becomes > 0 but the
2741 // set a stop time of 0 minutes, this will be displayed as "..'" 2955 // set a stop time of 0 minutes, this will be displayed as "..'"
2742 char_O_deco_time[0] = 0; 2956 char_O_deco_time[0] = 0;
2743 } 2957 }
2744 2958
2745 // update deco info vector 2959 // update deco info vector
2746 if( char_O_deco_depth[0] ) deco_info |= DECO_STOPS; // set flag for deco stops found 2960 if( char_O_deco_depth[0] ) deco_info |= DECO_STOPS; // set flag for deco stops found
2747 else deco_info &= ~DECO_STOPS; // clear flag for deco stops found 2961 else deco_info &= ~DECO_STOPS; // clear flag for deco stops found
2748 2962
2749 // The next calculation phase will publish the main results dependent on being 2963 // The next calculation phase will publish the main results dependent on being
2750 // - within NDL, 2964 // - within NDL,
2751 // - in deco. 2965 // - in deco.
2752 if ( NDL_time ) next_planning_phase = PHASE_72_RESULTS_NDL; 2966 if ( NDL_time ) next_planning_phase = PHASE_82_RESULTS_NDL;
2753 else next_planning_phase = PHASE_73_RESULTS_DECO; 2967 else next_planning_phase = PHASE_83_RESULTS_DECO;
2754 2968
2755 break; 2969 break;
2756 2970
2757 2971
2758 /// 2972 ///
2759 //--- Results - within NDL ---------------------------------------------------------------- 2973 //--- Results - within NDL ----------------------------------------------------------------
2760 // 2974 //
2761 case PHASE_72_RESULTS_NDL: 2975 case PHASE_82_RESULTS_NDL:
2762 2976
2763 // results to publish depend on normal or alternative plan 2977 // results to publish depend on normal or alternative plan
2764 if( deco_status & CALC_NORM ) 2978 if( deco_status & CALC_NORM )
2765 { 2979 {
2766 // output the NDL time 2980 // output the NDL time
2767 char_O_NDL_norm = NDL_time; 2981 char_O_NDL_norm = NDL_time;
2768 2982
2769 // clear the normal ascent time 2983 // clear the normal ascent time
2770 int_O_TTS_norm = 0; 2984 int_O_TTS_norm = 0;
2771
2772 // as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now
2773 int_O_CNS_norm = int_O_CNS_current;
2774 } 2985 }
2775 else 2986 else
2776 { 2987 {
2777 // output the NDL time 2988 // output the NDL time
2778 char_O_NDL_alt = NDL_time; 2989 char_O_NDL_alt = NDL_time;
2779 2990
2780 // clear the alternative ascent time 2991 // clear the alternative ascent time
2781 int_O_TTS_alt = 0; 2992 int_O_TTS_alt = 0;
2782
2783 // as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now
2784 int_O_CNS_alt = int_O_CNS_current;
2785 } 2993 }
2786 2994
2787 // The next calculation phase will 2995 // The next calculation phase will
2788 // - finish the calculation cycle if no gas needs calculation configured, else 2996 // - finish the calculation cycle if no gas needs calculation configured, else
2789 // - find gas switches when in bailout mode (we are in NDL), or 2997 // - calculate the gas needs pressures
2790 // - calculate the gas needs along the ascent
2791 if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH; 2998 if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH;
2792 else if ( (deco_status & BAILOUT_MODE) ) next_planning_phase = PHASE_80_GAS_NEEDS_SWITCHES; 2999 else next_planning_phase = PHASE_84_GAS_NEEDS_PRESSURES;
2793 else next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT;
2794 3000
2795 break; 3001 break;
2796 3002
2797 3003
2798 /// 3004 ///
2799 //--- Results - in Deco ------------------------------------------------------------------- 3005 //--- Results - in Deco -------------------------------------------------------------------
2800 // 3006 //
2801 case PHASE_73_RESULTS_DECO: 3007 case PHASE_83_RESULTS_DECO:
2802 3008
2803 // calculate the ascent time 3009 // limit ascent time to display max.
2804 calc_ascenttime(); 3010 if( ascent_time > 999) ascent_time = 999;
2805 3011
2806 // convert the CNS value to integer 3012 // tag ascent time as invalid if there is an overflow in the stops table
2807 convert_sim_CNS_for_display(); 3013 if( deco_warnings & DECO_WARNING_INCOMPLETE ) ascent_time |= INT_FLAG_INVALID;
2808 3014
2809 // results to publish depend on normal or alternative plan 3015 // results to publish depend on normal or alternative plan
2810 if( deco_status & CALC_NORM ) 3016 if( deco_status & CALC_NORM )
2811 { 3017 {
2812 // clear the normal NDL time 3018 // clear the normal NDL time
2813 char_O_NDL_norm = 0; 3019 char_O_NDL_norm = 0;
2814 3020
2815 // export the ascent time 3021 // export the ascent time
2816 int_O_TTS_norm = ascent_time; 3022 int_O_TTS_norm = ascent_time;
2817
2818 // export the integer CNS value
2819 int_O_CNS_norm = int_sim_CNS_fraction;
2820 } 3023 }
2821 else 3024 else
2822 { 3025 {
2823 // clear the alternative NDL time 3026 // clear the alternative NDL time
2824 char_O_NDL_alt = 0; 3027 char_O_NDL_alt = 0;
2825 3028
2826 // export the ascent time 3029 // export the ascent time
2827 int_O_TTS_alt = ascent_time; 3030 int_O_TTS_alt = ascent_time;
2828
2829 // export the integer CNS value
2830 int_O_CNS_alt = int_sim_CNS_fraction;
2831 } 3031 }
2832 3032
2833 // The next calculation phase will 3033 // The next calculation phase will
2834 // - finish the calculation cycle if no gas needs calculation configured, else 3034 // - finish the calculation cycle if no gas needs calculation configured, else
2835 // - calculate the gas needs along the ascent 3035 // - calculate the gas needs along the ascent
2836 if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH; 3036 if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH;
2837 else next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT; 3037 else next_planning_phase = PHASE_84_GAS_NEEDS_PRESSURES;
2838 3038
2839 break; 3039 break;
2840 3040
2841 3041
2842 // 3042 //
2843 //--- Gas Needs - Switches ---------------------------------------------------------------- 3043 //--- Results - convert Gas Needs Volumes to Pressures ------------------------------------
2844 // 3044 //
2845 case PHASE_80_GAS_NEEDS_SWITCHES: 3045 case PHASE_84_GAS_NEEDS_PRESSURES:
2846
2847 // When in bailout mode and within NDL, find the gas switches along the ascent and put
2848 // them into the stops table. The stops table can be "polluted" by now because the table
2849 // has already been published in "clean" state before.
2850 find_NDL_gas_changes();
2851
2852 // the next calculation phase will calculate the gas needs along the ascent
2853 next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT;
2854
2855 break;
2856
2857
2858 //
2859 //--- Gas Needs - calculate Ascent Needs using Data from Stop Table -----------------------
2860 //
2861 case PHASE_81_GAS_NEEDS_ASCENT:
2862
2863 // calculate the gas needs along the ascent
2864 calc_gas_needs_ascent();
2865
2866 // if calculation has finished, advance to next calculation phase
2867 if( gas_needs_next_phase == GAS_NEEDS_DONE ) next_planning_phase = PHASE_82_GAS_NEEDS_PRESSURES;
2868
2869 break;
2870
2871
2872 //
2873 //--- Gas Needs - convert Volumes to Pressures --------------------------------------------
2874 //
2875 case PHASE_82_GAS_NEEDS_PRESSURES:
2876 3046
2877 // convert required volume of the gas pointed to by gas_needs_gas_index 3047 // convert required volume of the gas pointed to by gas_needs_gas_index
2878 // into the respective pressure and set the flags 3048 // into the respective pressure and set the flags
2879 convert_gas_needs_to_press(); 3049 convert_gas_needs_to_press();
2880 3050
2895 // Check if deco obligation is steady state or decreasing. 3065 // Check if deco obligation is steady state or decreasing.
2896 // This works only when an alternative plan is enabled and if it is not a bailout plan, 3066 // This works only when an alternative plan is enabled and if it is not a bailout plan,
2897 // thus BAILOUT_MODE must not be set while doing the alternative plan. 3067 // thus BAILOUT_MODE must not be set while doing the alternative plan.
2898 if( (deco_status & CALC_ALT) && !(deco_status & BAILOUT_MODE) ) 3068 if( (deco_status & CALC_ALT) && !(deco_status & BAILOUT_MODE) )
2899 { 3069 {
2900 if ( int_O_TTS_alt <= int_O_TTS_norm ) deco_info |= DECO_ZONE; 3070 if( int_O_TTS_alt < int_O_TTS_norm ) deco_info |= DECO_ZONE;
2901 else deco_info &= ~DECO_ZONE; 3071 if( int_O_TTS_alt > int_O_TTS_norm ) deco_info &= ~DECO_ZONE;
2902 } 3072 }
2903 3073
2904 // export updated deco infos and warnings 3074 // export updated deco infos and warnings
2905 char_O_deco_info = deco_info; 3075 char_O_deco_info = deco_info;
2906 char_O_deco_warnings = deco_warnings; 3076 char_O_deco_warnings = deco_warnings;
2989 3159
2990 // safeguard further parameters to protect the tissue-flag and the stop table 3160 // safeguard further parameters to protect the tissue-flag and the stop table
2991 if( char_I_sim_advance_time > 127 ) char_I_sim_advance_time = 127; 3161 if( char_I_sim_advance_time > 127 ) char_I_sim_advance_time = 127;
2992 if( char_I_extra_time > 127 ) char_I_extra_time = 127; 3162 if( char_I_extra_time > 127 ) char_I_extra_time = 127;
2993 if( char_I_gas_change_time > 99 ) char_I_gas_change_time = 99; 3163 if( char_I_gas_change_time > 99 ) char_I_gas_change_time = 99;
3164
3165
3166 // compute the depth in meters where we are now
3167 float_depth_real = (real_pres_respiration - pres_surface) * BAR_TO_METER;
3168
3169 // convert to integer and round up to next full meter
3170 char_depth_real = (unsigned char)(float_depth_real + 0.99);
3171
2994 3172
2995 // calculate partial pressure of N2 in respired air at surface pressure 3173 // calculate partial pressure of N2 in respired air at surface pressure
2996 calc_N2_equilibrium(); 3174 calc_N2_equilibrium();
2997 3175
2998 // get, safeguard and convert the saturation and desaturation factors 3176 // get, safeguard and convert the saturation and desaturation factors
3027 #ifdef _ccr_pscr 3205 #ifdef _ccr_pscr
3028 // calculate ppO2 drop in pSCR loop for real tissues 3206 // calculate ppO2 drop in pSCR loop for real tissues
3029 real_pSCR_drop = IG_ratio * float_pSCR_factor; 3207 real_pSCR_drop = IG_ratio * float_pSCR_factor;
3030 #endif 3208 #endif
3031 3209
3032 }
3033
3034
3035 //////////////////////////////////////////////////////////////////////////////
3036 // Find gas changes on an NDL ascent
3037 //
3038 // This function is used for finding the gas changes in an OC bailout ascent
3039 // that is within NDL.
3040 //
3041 // Input: char_depth_bottom depth at which the ascent starts, in meters
3042 //
3043 // Output: gas change stops put into stops table
3044 //
3045 // Destroyed: char_depth_sim
3046 // sim_gas_current_num number of current gas
3047 // sim_gas_current_depth change depth of current gas
3048 //
3049 void find_NDL_gas_changes(void)
3050 {
3051 overlay unsigned char old_depth_limit;
3052
3053 // set gas to start with
3054 gas_find_current();
3055
3056 // loop in ascending until reaching a depth of 3 meters, no gas switches considered thereafter
3057 for( char_depth_sim = char_depth_bottom; char_depth_sim >= 3; )
3058 {
3059 // memorize the depth we came from
3060 old_depth_limit = char_depth_sim;
3061
3062 // ascent - initially in steps of 10 m, then slowing down to 1 m steps to not miss a O2 gas
3063 if ( char_depth_sim > 10 ) char_depth_sim -= 10;
3064 else char_depth_sim -= 1;
3065
3066 // check if there is a better gas to switch to
3067 if( gas_find_better() )
3068 {
3069 // adjust char_depth_sim to the gas change depth, but not deeper than the depth we came from
3070 char_depth_sim = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
3071
3072 // create a stop for the gas change in the stops table
3073 update_deco_table(char_I_gas_change_time);
3074 }
3075 } // for()
3076 } 3210 }
3077 3211
3078 3212
3079 ////////////////////////////////////////////////////////////////////////////// 3213 //////////////////////////////////////////////////////////////////////////////
3080 // calc_tissues 3214 // calc_tissues
3682 } 3816 }
3683 } 3817 }
3684 3818
3685 3819
3686 ////////////////////////////////////////////////////////////////////////////// 3820 //////////////////////////////////////////////////////////////////////////////
3687 // calc_ascenttime
3688 //
3689 // Sum up ascent from bottom to surface at char_I_ascent_speed, slowing down
3690 // to 1 minute per meter for the final ascent when in deco, and all stop times.
3691 //
3692 // Input: char_I_depth_last_deco
3693 // char_I_ascent_speed
3694 // char_depth_bottom
3695 // internal_deco_depth[]
3696 // internal_deco_time[]
3697 //
3698 // Output: ascent_time
3699 //
3700 static void calc_ascenttime(void)
3701 {
3702 // check if there are stops
3703 if( internal_deco_depth[0] )
3704 {
3705 // YES - stops / in deco
3706
3707 // check if already at last stop depth or shallower
3708 if( char_depth_bottom <= char_I_depth_last_deco)
3709 {
3710 // YES - final ascent part only
3711 ascent_time = char_depth_bottom;
3712 }
3713 else
3714 {
3715 // NO - ascent part from bottom to last stop
3716 ascent_time = (char_depth_bottom - char_I_depth_last_deco) / char_I_ascent_speed + 1;
3717
3718 // - ascent part from last stop to surface at 1 meter per minute
3719 ascent_time += char_I_depth_last_deco;
3720 }
3721
3722 // add all stop times
3723 for( i=0; i < NUM_STOPS && internal_deco_depth[i]; i++ )
3724 ascent_time += internal_deco_time[i];
3725
3726 // limit result to display max.
3727 if( ascent_time > 999) ascent_time = 999;
3728
3729 // tag result as invalid if there is an overflow in the stops table
3730 if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) ascent_time |= INT_FLAG_INVALID;
3731 }
3732 else
3733 {
3734 // NO - no stops / within NDL
3735 ascent_time = char_depth_bottom / char_I_ascent_speed + 1;
3736 }
3737 }
3738
3739
3740 //////////////////////////////////////////////////////////////////////////////
3741 // clear_deco_table 3821 // clear_deco_table
3742 // 3822 //
3743 // Modified: internal_deco_time[] stop durations 3823 // Modified: internal_deco_time[] stop durations
3744 // internal_deco_depth[] stop depths 3824 // internal_deco_depth[] stop depths
3745 // internal_deco_gas[] gases used at stops 3825 // internal_deco_gas[] gases used at stops
3751 internal_deco_time [i] = 0; 3831 internal_deco_time [i] = 0;
3752 internal_deco_depth[i] = 0; 3832 internal_deco_depth[i] = 0;
3753 internal_deco_gas[i] = 0; 3833 internal_deco_gas[i] = 0;
3754 } 3834 }
3755 3835
3836 // reset stop table index and chained stops counter
3837 stop_index = 0;
3838 chained_stops = 0;
3839
3756 // clear stop table overflow warning 3840 // clear stop table overflow warning
3757 deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW; 3841 deco_warnings &= ~DECO_WARNING_INCOMPLETE;
3758 } 3842 }
3759 3843
3760 3844
3761 ////////////////////////////////////////////////////////////////////////////// 3845 //////////////////////////////////////////////////////////////////////////////
3762 // update_deco_table 3846 // update_deco_table
3775 // internal_deco_time [] time (in minutes) of each stop 3859 // internal_deco_time [] time (in minutes) of each stop
3776 // internal_deco_gas [] gas used (index 1-5) at each stop 3860 // internal_deco_gas [] gas used (index 1-5) at each stop
3777 // 3861 //
3778 static unsigned char update_deco_table(PARAMETER unsigned char time_increment) 3862 static unsigned char update_deco_table(PARAMETER unsigned char time_increment)
3779 { 3863 {
3780 overlay unsigned char x;
3781
3782 assert( char_depth_sim > 0 ); // no stop at surface 3864 assert( char_depth_sim > 0 ); // no stop at surface
3783 3865
3784 // loop through internal deco table 3866
3785 for( x = 0; x < NUM_STOPS; ++x ) 3867 // is there already a stop entry matching with the current depth and gas?
3786 { 3868 if( internal_deco_depth[stop_index] == char_depth_sim )
3787 // In case the first deco stop is to be placed deeper than previously recorded 3869 if( internal_deco_gas [stop_index] == sim_gas_current_num )
3788 // stops for gas changes during the initial ascent (this may happen because the 3870 {
3789 // deco stops are placed at the next deeper multiple of 3 meters instead of the 3871 // YES - increment stop time if possible, stop time entries are
3790 // real stop's depth), relocate the deco stop to the depth of the last gas change. 3872 // limited to 99 minutes because of display constraints
3791 // The resulting combined stop's duration will be the sum of the configured gas 3873 if( internal_deco_time[stop_index] < (100 - time_increment) )
3792 // change time plus the duration of the deco stop itself. 3874 {
3793 if( internal_deco_depth[x] && (char_depth_sim > internal_deco_depth[x]) ) 3875 // YES - time increment fits into current stop entry,
3794 char_depth_sim = internal_deco_depth[x]; 3876 // increment stop time and return with status 'success'
3795 3877 internal_deco_time[stop_index] += time_increment;
3796 // Is there already a stop entry for our current depth? 3878 return 1;
3797 if( internal_deco_depth[x] == char_depth_sim ) 3879 }
3798 { 3880 else
3799 // Yes - increment stop time if possible 3881 {
3800 // Stop time entries are limited to 99 minutes because of display constraints. 3882 // NO - A chained stop entry will be created further down in the
3801 if( internal_deco_time[x] < (100 - time_increment) ) 3883 // code to continue the stop, but we will limit the number
3884 // of chained stop table entries in order to abort an ever-
3885 // running deco calculation. Too many chained entries?
3886 if( ++chained_stops >= STOP_CHAINING_LIMIT )
3802 { 3887 {
3803 internal_deco_time[x] += time_increment; // increment stop time 3888 // YES - set overflow warning and return with status 'failed'
3804 return 1; // return with status 'success' 3889 deco_warnings |= DECO_WARNING_INCOMPLETE;
3890 return 0;
3805 } 3891 }
3806 } 3892 }
3807 3893 }
3808 // If program flow passes here, there is either no stop entry for the current depth yet, or 3894
3809 // the existing entry is saturated with 99 minutes. So we are looking for the next unused 3895 // the current stop entry does not match the current depth and gas,
3810 // table entry. 3896 // or hasn't enough room left for the time increment
3811 if( internal_deco_depth[x] == 0 ) 3897
3812 { 3898 // is the current stop entry in use?
3813 internal_deco_time[x] = time_increment; // initialize entry with first stop's time, 3899 if( internal_deco_depth[stop_index] > 0 )
3814 internal_deco_depth[x] = char_depth_sim; // ... depth, and 3900 {
3815 internal_deco_gas[x] = sim_gas_current_num; // ... gas 3901 // YES - current entry is in use, need to move on
3816 return 1; // return with status 'success' 3902 // to next entry position if possible
3817 } 3903
3818 } 3904 // have all entry positions been used up?
3819 3905 if( stop_index < (NUM_STOPS - 1) )
3820 // If program flow passes here, all deco table entries are used up. 3906 {
3821 3907 // NO - move on to next entry position
3822 // set overflow warning 3908 stop_index += 1;
3823 deco_warnings |= DECO_WARNING_STOPTABLE_OVERFLOW; 3909 }
3824 3910 else
3825 // return with status 'failed'. 3911 {
3826 return 0; 3912 // YES - set overflow warning and return with status 'failed'
3913 deco_warnings |= DECO_WARNING_INCOMPLETE;
3914 return 0;
3915 }
3916 }
3917
3918 // initial use of a new (or the very first) stop entry,
3919 // store all stop data and return with status 'success'
3920 internal_deco_time [stop_index] = time_increment;
3921 internal_deco_depth[stop_index] = char_depth_sim;
3922 internal_deco_gas [stop_index] = sim_gas_current_num;
3923 return 1;
3924 }
3925
3926
3927 //////////////////////////////////////////////////////////////////////////////
3928 // publish_deco_table
3929 //
3930 // Input: internal_deco_depth[] depth in internal stops table
3931 // internal_deco_time[] times ...
3932 // internal_deco_gas[] gases ...
3933 //
3934 // Output: char_O_deco_depth[] depth in the external stops table
3935 // char_O_deco_time[] times ...
3936 // char_O_deco_gas[] gases ...
3937 // char_O_deco_time_for_log times in reverse order
3938 //
3939 static void publish_deco_table(void)
3940 {
3941 overlay unsigned char x = stop_index;
3942 overlay unsigned char y;
3943
3944
3945 // copy depth, time and gas from internal to external stops table
3946 for( y = 0; y < NUM_STOPS; y++ )
3947 {
3948 char_O_deco_depth[y] = internal_deco_depth[y];
3949 char_O_deco_time [y] = internal_deco_time [y];
3950 char_O_deco_gas [y] = internal_deco_gas [y];
3951 }
3952
3953 // copy times of shallowest stops to logging table
3954 for(y = 0; y < NUM_STOPS_LOG; x-- )
3955 {
3956 // copy all stops that have a non-null stop time
3957 if( internal_deco_time[x] )
3958 char_O_deco_time_for_log[y++] = internal_deco_time[x];
3959
3960 // abort if all stops are copied
3961 if( x == 0) break;
3962 }
3963
3964 // fill the remainder of the logging table with null
3965 // if it is not completely filled already
3966 while( y < NUM_STOPS_LOG )
3967 {
3968 char_O_deco_time_for_log[y++] = 0;
3969 }
3827 } 3970 }
3828 3971
3829 3972
3830 ////////////////////////////////////////////////////////////////////////////// 3973 //////////////////////////////////////////////////////////////////////////////
3831 // calc_desaturation_time_helper 3974 // calc_desaturation_time_helper
4299 // step-wise CNS increment 4442 // step-wise CNS increment
4300 4443
4301 // calculate index for increment look-up 4444 // calculate index for increment look-up
4302 cns_i = (char_ppO2 - 161) / 5; // integer division 4445 cns_i = (char_ppO2 - 161) / 5; // integer division
4303 4446
4447 // indexes > 17 use increment of index 17
4448 if( cns_i > 17 ) cns_i = 17;
4449
4304 // read coefficient (increment) 4450 // read coefficient (increment)
4305 read_CNS_c_coefficient(); 4451 read_CNS_c_coefficient();
4306 4452
4307 // re-scale coefficient from storage format in [1/100000] to productive value 4453 // re-scale coefficient from storage format in [1/100000] to productive value
4308 CNS_fraction_inc = (float)var_cns_c / 100000.0; 4454 CNS_fraction_inc = (float)var_cns_c / 100000.0;
4342 // 4488 //
4343 // Calculates the gas volume required for a given depth, time and usage (SAC) 4489 // Calculates the gas volume required for a given depth, time and usage (SAC)
4344 // rate. It uses a fixed surface pressure of 1.0 bar to deliver stable results 4490 // rate. It uses a fixed surface pressure of 1.0 bar to deliver stable results
4345 // when used through the deco calculator. 4491 // when used through the deco calculator.
4346 // 4492 //
4347 // Input: gas_needs_float_depth depth in meters 4493 // Input: gas_needs_depth depth in meters
4348 // gas_needs_float_time time in minutes 4494 // gas_needs_time time in minutes
4349 // gas_needs_stop_usage gas usage in liters per minute at surface pressure 4495 // gas_needs_usage_rate gas usage in liters per minute at surface pressure
4350 // 4496 //
4351 // Output: gas_needs_volume_due required gas volume in liters 4497 // Output: gas_needs_volume_due required gas volume in liters
4352 // 4498 //
4353 static void calc_due_by_depth_time_sac(void) 4499 static void calc_due_by_depth_time_sac(void)
4354 { 4500 {
4355 gas_needs_volume_due = (gas_needs_float_depth * METER_TO_BAR + 1.0) * gas_needs_float_time * gas_needs_stop_usage; 4501 gas_needs_volume_due = ((float)gas_needs_depth * METER_TO_BAR + pres_surface) * gas_needs_time * gas_needs_usage_rate;
4356 }
4357
4358
4359 //////////////////////////////////////////////////////////////////////////////
4360 // calc_gas_needs_ascent
4361 //
4362 // calculates the gas needs along the ascent
4363 //
4364 // Input: char_depth_bottom depth of the bottom segment
4365 // char_I_bottom_time duration of the bottom segment
4366 // char_I_extra_time extra bottom time for fTTS / delayed ascent
4367 // float_ascent_speed ascent speed, in meters/minute
4368 // internal_deco_depth[] depth of the stops
4369 // internal_deco_time[] duration of the stops
4370 // internal_deco_gas[] gas breathed at the stops
4371 // NDL_time remaining NDL time, used to adjust speed of final ascent
4372 // char_I_SAC_work gas consumption during bottom part and initial ascent, in liters/minute
4373 // char_I_SAC_deco gas consumption during stops and following ascents, in liters/minute
4374 // char_I_gas_avail_size[] size of the tanks for gas 1-5, in liters
4375 // char_I_gas_avail_pres[] fill pressure of the tanks
4376 //
4377 // Output: gas_volume_need[] amount of gas needed, in liters
4378 //
4379 static void calc_gas_needs_ascent(void)
4380 {
4381 switch (gas_needs_next_phase)
4382 {
4383 //---------------------------------------------------------------------
4384
4385 case GAS_NEEDS_INIT:
4386
4387 // set index to the first stop table entry
4388 gas_needs_stop_index = 0;
4389
4390 // clear the gas volume needs
4391 for( i = 0; i < NUM_GAS; ++i ) gas_volume_need[i] = 0.0;
4392
4393 #ifdef _rx_functions
4394 // only for OSTC TR model with TR functions enabled
4395 if( main_status & TR_FUNCTIONS )
4396 {
4397 // invalidate pressure needs to pressure readings
4398 int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL;
4399 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL;
4400 }
4401 #endif
4402
4403 // terminate if in loop mode (CCR, pSCR) as there are no gas needs to calculate,
4404 // else continue with the gas needs of the bottom segment
4405 if ( deco_status & MODE_LOOP ) gas_needs_next_phase = GAS_NEEDS_DONE;
4406 else gas_needs_next_phase = GAS_NEEDS_BOTTOM_SEGMENT;
4407
4408 break;
4409
4410 //---------------------------------------------------------------------
4411
4412 case GAS_NEEDS_BOTTOM_SEGMENT:
4413
4414 // sim_gas_current_num gas used during bottom segment (0, 1-5)
4415 // char_depth_bottom depth of the bottom segment
4416
4417 // get the gas used during bottom segment
4418 gas_find_current();
4419
4420 // initialize variables
4421 gas_needs_stop_gas_last = gas_needs_stop_gas = sim_gas_current_num;
4422
4423 // set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent
4424 gas_needs_stop_usage = char_I_SAC_work;
4425
4426 // volumes are only calculated for gases 1-5, but not the manually configured one
4427 if( gas_needs_stop_gas )
4428 {
4429 // set the bottom depth
4430 gas_needs_float_depth = (float)char_depth_bottom;
4431
4432 // calculate either whole bottom time or just the fTTS/bailout extra time
4433 gas_needs_float_time = ( main_status & CALCULATE_BOTTOM ) ? (float)char_I_bottom_time : (float)char_I_extra_time;
4434
4435 // calculate gas demand
4436 calc_due_by_depth_time_sac();
4437
4438 // take result
4439 gas_volume_need[gas_needs_stop_gas-1] = gas_needs_volume_due;
4440 }
4441
4442 // continue with initial ascent demand
4443 gas_needs_next_phase = GAS_NEEDS_INITIAL_ASCENT;
4444
4445 break;
4446
4447
4448 //---------------------------------------------------------------------
4449
4450 case GAS_NEEDS_INITIAL_ASCENT:
4451
4452 // gas_needs_stop_gas : gas from bottom segment
4453 // char_depth_bottom : depth of the bottom segment
4454 // internal_deco_depth[0]: depth of the first stop, may be 0 if no stop exists
4455
4456 // get the data of the first stop
4457 gas_needs_stop_depth = internal_deco_depth[0];
4458 gas_needs_stop_time = internal_deco_time[0];
4459
4460 // volumes are only calculated for gases 1-5, but not the manually configured one
4461 if( gas_needs_stop_gas )
4462 {
4463 // compute distance between bottom and first stop
4464 gas_needs_float_depth = (float)char_depth_bottom - (float)gas_needs_stop_depth;
4465
4466 // initial ascent exists only if ascent distance is > 0
4467 if( gas_needs_float_depth > 0.0 )
4468 {
4469 // compute ascent time
4470 gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
4471
4472 // compute average depth between bottom and first stop
4473 gas_needs_float_depth = (float)char_depth_bottom - gas_needs_float_depth * 0.5;
4474
4475 // calculate gas demand
4476 calc_due_by_depth_time_sac();
4477
4478 // add to overall demand
4479 gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
4480 }
4481 }
4482
4483 // switch the usage (SAC rate) to deco usage rate
4484 // for stops, intermediate and final ascent
4485 gas_needs_stop_usage = char_I_SAC_deco;
4486
4487 // is there a (first) stop?
4488 if( gas_needs_stop_depth )
4489 {
4490 // YES - continue with stop demand
4491 gas_needs_next_phase = GAS_NEEDS_STOP;
4492
4493 break;
4494 }
4495 else
4496 {
4497 // NO - add demand of a 3 minutes safety stop at 5 meters, at least for contingency...
4498 gas_needs_float_time = 3.0;
4499 gas_needs_float_depth = 5.0;
4500
4501 // calculate gas demand
4502 calc_due_by_depth_time_sac();
4503
4504 // add to overall demand
4505 gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
4506
4507 // calculation finished
4508 gas_needs_next_phase = GAS_NEEDS_DONE;
4509
4510 break;
4511 }
4512
4513
4514 //---------------------------------------------------------------------
4515
4516 case GAS_NEEDS_STOP:
4517
4518 // correct stop depth if shallower than calculated stop depth and convert to float
4519 gas_needs_float_depth = ( char_depth_bottom < gas_needs_stop_depth ) ? (float)char_depth_bottom : (float)gas_needs_stop_depth;
4520
4521 // get the gas on this stop
4522 gas_needs_stop_gas = internal_deco_gas[gas_needs_stop_index];
4523
4524 // do we have a gas change?
4525 if( gas_needs_stop_gas_last && (gas_needs_stop_gas != gas_needs_stop_gas_last) )
4526 {
4527 // YES - spend an additional char_I_gas_change_time on the old gas
4528 gas_needs_float_time = (float)char_I_gas_change_time;
4529
4530 // calculate gas demand
4531 calc_due_by_depth_time_sac();
4532
4533 // add to overall demand
4534 gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due;
4535 }
4536
4537 // calculate demand of (new) gas for the full stop duration
4538 if( gas_needs_stop_gas )
4539 {
4540 // get the duration of the stop
4541 gas_needs_float_time = (float)gas_needs_stop_time;
4542
4543 // calculate gas demand
4544 calc_due_by_depth_time_sac();
4545
4546 // add to overall demand
4547 gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
4548 }
4549
4550 // Continue with the demand of the intermediate ascent to the next stop.
4551 // If there is no further stop, it will divert by itself to final ascent.
4552 gas_needs_next_phase = GAS_NEEDS_INTERMEDIATE_ASCENT;
4553
4554 break;
4555
4556
4557 //---------------------------------------------------------------------
4558
4559 case GAS_NEEDS_INTERMEDIATE_ASCENT:
4560
4561 // store last stop depth and last gas
4562 gas_needs_stop_depth_last = gas_needs_stop_depth;
4563 gas_needs_stop_gas_last = gas_needs_stop_gas;
4564
4565 // check if end of stop table is reached
4566 if( gas_needs_stop_index < NUM_STOPS-1 )
4567 {
4568 // NO - check if there is another stop entry
4569 if( internal_deco_depth[gas_needs_stop_index+1] == 0 )
4570 {
4571 // NO - continue with final ascent demand
4572 gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT;
4573
4574 break;
4575 }
4576 else
4577 {
4578 // YES - goto next stop entry
4579 gas_needs_stop_index++;
4580
4581 // get the depth of the next stop entry
4582 gas_needs_stop_depth = internal_deco_depth[gas_needs_stop_index];
4583
4584 // get the duration of the next stop
4585 gas_needs_stop_time = internal_deco_time[gas_needs_stop_index];
4586 }
4587 }
4588 else
4589 {
4590 // YES - end of stop table reached
4591 // We are stranded at some stop depth and do not know how many more
4592 // stops there may be in front of us and how long they may be. So as
4593 // as last resort to calculate at least something, we assume that the
4594 // rest of the ascent will be done in deco final ascent pace, i.e. at
4595 // 1 meter per minute. Because of the stop table overflow, the result
4596 // will be flagged as being invalid later on.
4597 //
4598 gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT;
4599
4600 break;
4601 }
4602
4603 // volumes are only calculated for gases 1-5, but not the manually configured one
4604 if( gas_needs_stop_gas_last )
4605 {
4606 // compute distance between the two stops
4607 gas_needs_float_depth = (float)(gas_needs_stop_depth_last - gas_needs_stop_depth);
4608
4609 // compute ascent time
4610 gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
4611
4612 // compute average depth between the two stops
4613 gas_needs_float_depth = (float)gas_needs_stop_depth_last - gas_needs_float_depth * 0.5;
4614
4615 // calculate gas demand
4616 calc_due_by_depth_time_sac();
4617
4618 // add to overall demand
4619 gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due;
4620 }
4621
4622 // continue with calculation stop demand
4623 gas_needs_next_phase = GAS_NEEDS_STOP;
4624
4625 break;
4626
4627
4628 //---------------------------------------------------------------------
4629
4630 case GAS_NEEDS_FINAL_ASCENT:
4631
4632 // gas_needs_float_depth: still holds depth of the last stop
4633 // gas_needs_stop_gas : still holds gas from last stop (0 or 1-5)
4634
4635 // volumes are only calculated for gases 1-5, but not the manually configured one
4636 if( gas_needs_stop_gas )
4637 {
4638 // set ascent time dependent on deco status
4639 if( NDL_time )
4640 {
4641 // within NDL - ascent with float_ascent_speed
4642 //
4643 // Remark: When calculating a bailout ascent, there may be stops
4644 // for gas changes although the dive is still within NDL
4645 // and final ascent thus does not need to be slowed down.
4646 gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
4647 }
4648 else
4649 {
4650 // in deco - reduce ascent speed to 1 meter per minute
4651 gas_needs_float_time = gas_needs_float_depth;
4652 }
4653
4654 // set half-way depth
4655 gas_needs_float_depth *= 0.5;
4656
4657 // calculate gas demand
4658 calc_due_by_depth_time_sac();
4659
4660 // add to overall demand
4661 gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
4662 }
4663
4664 // calculation finished
4665 gas_needs_next_phase = GAS_NEEDS_DONE;
4666
4667 break;
4668
4669 } // switch
4670 } 4502 }
4671 4503
4672 4504
4673 ////////////////////////////////////////////////////////////////////////////// 4505 //////////////////////////////////////////////////////////////////////////////
4674 // calc_TR_functions 4506 // calc_TR_functions
4737 4569
4738 // get a copy of the current absolute pressure 4570 // get a copy of the current absolute pressure
4739 pres_respiration_sac = real_pres_respiration; 4571 pres_respiration_sac = real_pres_respiration;
4740 4572
4741 // set threshold for SAC rate attention 4573 // set threshold for SAC rate attention
4742 max_sac_rate = (deco_info & DECO_FLAG) ? char_I_SAC_deco : char_I_SAC_work; 4574 max_sac_rate = (deco_info & DECO_MODE) ? char_I_SAC_deco : char_I_SAC_work;
4743 4575
4744 // char_I_SAC_deco / char_I_SAC_work are in l/min, max_sac_rate is in 0.1 l/min 4576 // char_I_SAC_deco / char_I_SAC_work are in l/min, max_sac_rate is in 0.1 l/min
4745 max_sac_rate *= 10; 4577 max_sac_rate *= 10;
4746 4578
4747 4579
4821 // reconfigure max SAC rate to O2 consumption attention threshold 4653 // reconfigure max SAC rate to O2 consumption attention threshold
4822 max_sac_rate = O2_CONSUMPTION_LIMIT_ATTENTION; 4654 max_sac_rate = O2_CONSUMPTION_LIMIT_ATTENTION;
4823 } 4655 }
4824 4656
4825 4657
4658 // select which pressure reading to log
4659 if( char_I_SAC_mode == 1 ) int_O_tank_pressure = int_IO_pressure_value[0];
4660 else if( char_I_SAC_mode == 2 ) int_O_tank_pressure = int_IO_pressure_value[1];
4661 else int_O_tank_pressure = 0;
4662
4663 // strip flags
4664 int_O_tank_pressure &= 0x0FFF;
4665
4666 // TODO: decide if log shall be in 0.1 bar of full bar only
4667 // scale to full bar only
4668 int_O_tank_pressure /= 10;
4669
4670
4826 // calculate SAC - modes 1 & 2 4671 // calculate SAC - modes 1 & 2
4827 if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) ) 4672 if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) )
4828 { 4673 {
4829 overlay unsigned char reading_index; 4674 overlay unsigned char reading_index;
4830 overlay unsigned char reading_gas; 4675 overlay unsigned char reading_gas;
4923 overlay unsigned short int_pres_warn; 4768 overlay unsigned short int_pres_warn;
4924 overlay unsigned short int_pres_attn; 4769 overlay unsigned short int_pres_attn;
4925 4770
4926 // set warning and attention thresholds 4771 // set warning and attention thresholds
4927 int_pres_warn = 10.0 * (unsigned short)char_I_gas_avail_pres[i]; 4772 int_pres_warn = 10.0 * (unsigned short)char_I_gas_avail_pres[i];
4928 int_pres_attn = GAS_NEEDS_ATTENTION_THRESHOLD * int_pres_warn; 4773 int_pres_attn = GAS_NEEDS_LIMIT_ATTENTION * int_pres_warn;
4929 4774
4930 // convert ascent gas volume need from float to integer [in liter] 4775 // convert ascent gas volume need from float to integer [in liter]
4931 int_O_gas_need_vol[i] = (unsigned short)gas_volume_need[i]; 4776 int_O_gas_need_vol[i] = (unsigned short)gas_volume_need[i];
4932 4777
4933 // compute how much pressure in the tank will be needed [in bar] 4778 // compute how much pressure in the tank will be needed [in bar]
4941 else if ( int_O_gas_need_pres[i] >= int_pres_warn ) int_O_gas_need_pres[i] |= INT_FLAG_WARNING; 4786 else if ( int_O_gas_need_pres[i] >= int_pres_warn ) int_O_gas_need_pres[i] |= INT_FLAG_WARNING;
4942 else if ( int_O_gas_need_pres[i] >= int_pres_attn ) int_O_gas_need_pres[i] |= INT_FLAG_ATTENTION; 4787 else if ( int_O_gas_need_pres[i] >= int_pres_attn ) int_O_gas_need_pres[i] |= INT_FLAG_ATTENTION;
4943 } 4788 }
4944 4789
4945 // set invalid flag if there is an overflow in the stops table 4790 // set invalid flag if there is an overflow in the stops table
4946 if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_O_gas_need_pres[i] |= INT_FLAG_INVALID; 4791 if( deco_warnings & DECO_WARNING_INCOMPLETE ) int_O_gas_need_pres[i] |= INT_FLAG_INVALID;
4947 4792
4948 #ifdef _rx_functions 4793 #ifdef _rx_functions
4949 // only for OSTC TR model with TR functions enabled 4794 // only for OSTC TR model with TR functions enabled
4950 if( main_status & TR_FUNCTIONS ) 4795 if( main_status & TR_FUNCTIONS )
4951 { 4796 {
4963 4808
4964 // limit to 400 bar and multiply by 10 to get required pressure in 0.1 bar 4809 // limit to 400 bar and multiply by 10 to get required pressure in 0.1 bar
4965 int_pres_need = (int_pres_need > 400) ? 4000 | INT_FLAG_OUT_OF_RANGE : 10 * int_pres_need; 4810 int_pres_need = (int_pres_need > 400) ? 4000 | INT_FLAG_OUT_OF_RANGE : 10 * int_pres_need;
4966 4811
4967 // tag as not available if there is an overflow in the stops table 4812 // tag as not available if there is an overflow in the stops table
4968 if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_pres_need |= INT_FLAG_NOT_AVAIL; 4813 if( deco_warnings & DECO_WARNING_INCOMPLETE ) int_pres_need |= INT_FLAG_NOT_AVAIL;
4969 4814
4970 // copy to reading data (in both readings the same gas could be configured) 4815 // copy to reading data (in both readings the same gas could be configured)
4971 if( char_I_pressure_gas[0] == j ) int_O_pressure_need[0] = int_pres_need; 4816 if( char_I_pressure_gas[0] == j ) int_O_pressure_need[0] = int_pres_need;
4972 if( char_I_pressure_gas[1] == j ) int_O_pressure_need[1] = int_pres_need; 4817 if( char_I_pressure_gas[1] == j ) int_O_pressure_need[1] = int_pres_need;
4973 } 4818 }
4987 { 4832 {
4988 // convert to integer 4833 // convert to integer
4989 float_value = CNS_fraction_real; convert_float_to_int(); int_O_CNS_current = int_value; 4834 float_value = CNS_fraction_real; convert_float_to_int(); int_O_CNS_current = int_value;
4990 4835
4991 // set warning & attention flags 4836 // set warning & attention flags
4992 if ( int_O_CNS_current >= CNS_WARNING_THRESHOLD ) int_O_CNS_current |= INT_FLAG_WARNING; 4837 if ( int_O_CNS_current >= CNS_LIMIT_WARNING ) int_O_CNS_current |= INT_FLAG_WARNING;
4993 else if ( int_O_CNS_current >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_current |= INT_FLAG_ATTENTION; 4838 else if ( int_O_CNS_current >= CNS_LIMIT_ATTENTION ) int_O_CNS_current |= INT_FLAG_ATTENTION;
4994 } 4839 }
4995 4840
4996 4841
4997 ////////////////////////////////////////////////////////////////////////////// 4842 //////////////////////////////////////////////////////////////////////////////
4998 // convert the simulated CNS value to integer 4843 // convert the simulated CNS value to integer
5007 { 4852 {
5008 // convert to integer 4853 // convert to integer
5009 float_value = CNS_fraction_sim; convert_float_to_int(); int_sim_CNS_fraction = int_value; 4854 float_value = CNS_fraction_sim; convert_float_to_int(); int_sim_CNS_fraction = int_value;
5010 4855
5011 // set warning & attention flags 4856 // set warning & attention flags
5012 if ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_WARNING; 4857 if ( int_sim_CNS_fraction >= CNS_LIMIT_WARNING ) int_sim_CNS_fraction |= INT_FLAG_WARNING;
5013 else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION; 4858 else if ( int_sim_CNS_fraction >= CNS_LIMIT_ATTENTION ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION;
5014 4859
5015 // set invalid flag if there is an overflow in the stops table 4860 // set invalid flag if there is an overflow in the stops table
5016 if ( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID; 4861 if ( deco_warnings & DECO_WARNING_INCOMPLETE ) int_sim_CNS_fraction |= INT_FLAG_INVALID;
5017 } 4862 }
5018 4863
5019 4864
5020 ////////////////////////////////////////////////////////////////////////////// 4865 //////////////////////////////////////////////////////////////////////////////
5021 // convert the saturation value of the leading tissue to integer 4866 // convert the saturation value of the leading tissue to integer
5058 ////////////////////////////////////////////////////////////////////////////// 4903 //////////////////////////////////////////////////////////////////////////////
5059 // convert the ceiling value to integer 4904 // convert the ceiling value to integer
5060 // 4905 //
5061 // Input: ceiling minimum depth permitted in float 4906 // Input: ceiling minimum depth permitted in float
5062 // 4907 //
5063 // Output: int_O_ceiling minimum depth permitted in mbar 4908 // Output: int_O_ceiling minimum depth permitted in mbar (cm)
5064 // 4909 //
5065 // Modified: deco_info deco engine information vector 4910 // Modified: deco_info deco engine information vector
5066 // 4911 //
5067 static void convert_ceiling_for_display(void) 4912 static void convert_ceiling_for_display(void)
5068 { 4913 {
5069 // Convert ceiling to int_O_ceiling in mbar relative pressure. 4914 // Convert ceiling to int_O_ceiling in mbar relative pressure.
5070 // Round up to next 10 cm so that the ceiling disappears only 4915 // Round up to next 10 cm so that the ceiling disappears only
5071 // when the ceiling limit is really zero. This will coincident 4916 // when the ceiling limit is really zero. This will coincident
5072 // with TTS switching back to NDL time. 4917 // with TTS switching back to NDL time.
4918 // The +1.5 term figures in the conversion factor of 10.015 m/bar
4919 // which is used inside the deco engine but not outside of it.
5073 if ( ceiling <= 0.0 ) int_O_ceiling = 0; 4920 if ( ceiling <= 0.0 ) int_O_ceiling = 0;
5074 else if ( ceiling > 16.0 ) int_O_ceiling = 16000; 4921 else if ( ceiling > 16.0 ) int_O_ceiling = 16000;
5075 else int_O_ceiling = (unsigned short)(ceiling * 1000 + 9); 4922 else int_O_ceiling = (unsigned short)(ceiling * (1000+1.5) + 9);
5076 4923
5077 // set/reset ceiling flag 4924 // set/reset ceiling flag
5078 if ( int_O_ceiling ) deco_info |= DECO_CEILING; 4925 if ( int_O_ceiling ) deco_info |= DECO_CEILING;
5079 else deco_info &= ~DECO_CEILING; 4926 else deco_info &= ~DECO_CEILING;
5080 } 4927 }