Mercurial > public > hwos_code
diff 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 |
line wrap: on
line diff
--- a/src/p2_deco.c Sun Jun 30 23:22:32 2019 +0200 +++ b/src/p2_deco.c Thu Sep 19 12:01:29 2019 +0200 @@ -1,5 +1,5 @@ // *************************************************************************** -// p2_deco.c combined next generation V3.03.4 +// p2_deco.c combined next generation V3.04.3 // // Created on: 12.05.2009 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others @@ -104,8 +104,12 @@ // deco engine scheduling #define INVOKES_PER_SECOND 2 // number of invocations of the deco engine per second (use powers of 2 only: 1, 2, 4, ...) + +#ifdef _hwos_sport +#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 +#else #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 - +#endif // ambient pressure at different mountain heights #define P_ambient_1000m 0.880 // [bar] based on 990 hPa and 20°C at sea level, 15°C at altitude @@ -126,14 +130,16 @@ #define HYST 1.0E-06 // threshold for tissue graphics on-gassing / off-gassing visualization // thresholds -#define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning -#define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention -#define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] -#define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention [1.00 = 100%] +#define CNS_LIMIT_WARNING 100 // threshold for CNS warning +#define CNS_LIMIT_ATTENTION 70 // threshold for CNS attention #define PRESSURE_LIMIT_WARNING 200 // threshold for pressure reading warning : 20.0 bar #define PRESSURE_LIMIT_ATTENTION 500 // threshold for pressure reading attention: 50.0 bar +#define GAS_NEEDS_LIMIT_ATTENTION 0.70 // threshold for gas needs attention [1.00 = 100%] #define O2_CONSUMPTION_LIMIT_ATTENTION 20 // threshold for O2 "SAC" attention: 2.0 l/min +#define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] #define ppO2_MARGIN_ON_MAX 3 // [cbar] margin on ppO2 max to compensate for surface pressures > 1.000 mbar +#define STOP_CHAINING_LIMIT 5 // max. number of chained stop table entries before deco calculation is aborted + // deco engine states and modes - (char_O_)main_status: controls current tissue and deco status calculation (as-is situation) #define CALC_VOLUME 0x01 // =1: calculate gas needs @@ -162,7 +168,7 @@ #define INITIALIZE 0x04 // input: initialize deco engine #define INITIALIZE_START_NORM 0x05 // input: initialize deco engine and start calculation of a normal deco plan #define INITIALIZE_START_ALT 0x06 // input: initialize deco engine and start calculation of an alternative deco plan -// 0x08 // unused - reserved for further deco engine commands +#define DECO_CALCULATOR_MODE 0x08 // input: deco engine is run from deco calculator #define BAILOUT_MODE 0x10 // =1: allow gas switches before first deco stop #define DELAYED_ASCENT 0x20 // =1: figure in a delayed ascent (fTTS) @@ -181,10 +187,10 @@ #define DECO_WARNING_OUTSIDE 0x10 // tissue pressures outside the Buhlmann model now #define DECO_WARNING_OUTSIDE_lock 0x20 // tissue pressures outside the model sometime during the dive #define DECO_ATTENTION_OUTSIDE 0x40 // tissue pressures are very close to the Buhlmann limit -#define DECO_WARNING_STOPTABLE_OVERFLOW 0x80 // internal error: no more space in the deco stops table +#define DECO_WARNING_INCOMPLETE 0x80 // internal error: deco calculation incomplete // deco engine status (char_O_)deco_info -#define DECO_FLAG 0x01 // =1: deco ppO2 levels are permitted +#define DECO_MODE 0x01 // =1: deco ppO2 levels are permitted #define IND_DOUBLE_SWITCH_FLAG 0x02 // =1: switch to other tank advice active // 0x04 // --- unused #define DECO_ZONE 0x08 // =1: fTTS < TTS (not updated when in bailout mode) @@ -202,31 +208,20 @@ // deco engine control - next_planning_phase #define PHASE_00_DONE 0x00 // calculation cycle finished #define PHASE_10_DIVE_INIT 0x10 // once-per-dive initialization of the deco engine -#define PHASE_11_CYCLIC_INIT 0x11 // once-every-cycle initialization of the deco engine -#define PHASE_20_EXTENDED_BOTTOM_TIME 0x20 // calculate extended bottom time -#define PHASE_30_NDL_TIME 0x30 // calculate NDL time -#define PHASE_40_CAVE_ASCENT 0x40 // calculate cave mode return/ascent -#define PHASE_60_DECO_ASCENT 0x60 // calculate open water deco ascent -#define PHASE_70_RESULTS 0x70 // results - initialization -#define PHASE_71_RESULTS_STOPS_TABLE 0x71 // results - publish stops table -#define PHASE_72_RESULTS_NDL 0x72 // results - publish data / within NDL -#define PHASE_73_RESULTS_DECO 0x73 // results - publish data / in deco -#define PHASE_80_GAS_NEEDS_SWITCHES 0x80 // calculate gas needs - find gas switches in NDL bailout mode -#define PHASE_81_GAS_NEEDS_ASCENT 0x81 // calculate gas needs - needs of bottom segment and ascent -#define PHASE_82_GAS_NEEDS_PRESSURES 0x82 // calculate gas needs - conversion from volumes to pressures +#define PHASE_20_CYCLIC_INIT 0x20 // once-every-cycle initialization of the deco engine +#define PHASE_30_EXTENDED_BOTTOM_TIME 0x30 // calculate extended bottom time +#define PHASE_40_BOTTOM_GAS_NEED 0x40 // calculate gas needs for bottom segment +#define PHASE_50_NDL_TIME 0x50 // calculate NDL time +#define PHASE_60_CAVE_RETURN 0x60 // calculate cave mode return +#define PHASE_70_OPEN_WATER_ASCENT 0x70 // calculate open water ascent +#define PHASE_80_RESULTS 0x80 // results - initialization +#define PHASE_81_RESULTS_STOPS_TABLE 0x81 // results - publish stops table +#define PHASE_82_RESULTS_NDL 0x82 // results - publish data / within NDL +#define PHASE_83_RESULTS_DECO 0x83 // results - publish data / in deco +#define PHASE_84_GAS_NEEDS_PRESSURES 0x84 // results - convert gas needs from volumes to pressures #define PHASE_90_FINISH 0x90 // finish calculation cycle -// gas needs calculation - gas_needs_next_phase -#define GAS_NEEDS_INIT 0x00 // initialization -#define GAS_NEEDS_BOTTOM_SEGMENT 0x10 // demand during bottom segment -#define GAS_NEEDS_INITIAL_ASCENT 0x20 // demand of initial ascent -#define GAS_NEEDS_STOP 0x30 // demand on a stop -#define GAS_NEEDS_INTERMEDIATE_ASCENT 0x40 // demand on ascent between two stops -#define GAS_NEEDS_FINAL_ASCENT 0x50 // demand during final ascent -#define GAS_NEEDS_DONE 0x60 // calculation finished - - // flags used with integer numbers #define INT_FLAG_INVALID 0x0400 // =1: value not valid #define INT_FLAG_NOT_COMPUTED_YET 0x0800 // =1: value not computed yet @@ -265,7 +260,7 @@ // Functions combined for real Tissues & Deco Calculations static void calc_alveolar_pressures(void); // Computes the partial pressures from the gas ratios and many more parameters, // needs either calc_hauptroutine_data_input() be called beforehand or - // gas_find_current()/gas_find_better() and gas_set_ratios(). + // gas_take_current() or gas_find_best()/gas_take_best() and gas_set_ratios(). static void calc_tissues(void); // Updates the tissues dependent on the partial pressures of N2 and He. static void calc_CNS(void); // Updates the CNS value dependent on the partial pressure of the O2. static void calc_limit(PARAMETER float GF_current); @@ -278,17 +273,15 @@ // Functions dedicated to Deco Calculations static void clear_deco_table(void); // Clears the deco stops table, invoked at the start of each calculation cycle. -static void gas_find_current(void); // Sets the first gas used for deco calculation, invoked at start of cycle, too. -static unsigned char gas_find_better(void); // Checks for, and eventually switches to, a better gas. +static void gas_take_current(void); // Sets the first gas used for deco calculation, invoked at start of cycle, too. +static unsigned char gas_find_best(void); // Searches for the best gas available. +static void gas_take_best(void); // Switches to the best gas that has been found found before by gas_find_best(). static void gas_set_ratios(void); // Sets the gas ratios for use in deco calculation (simulated tissues), - // needs to be called after each gas change (gas_find_current/_better). + // needs to be called after each gas change (gas_take_current/_better). static void calc_NDL_time_tissue(void); // Calculates the remaining NDL time for a given tissue. -static void find_NDL_gas_changes(void); // Finds the gas changes in an OC bailout ascent that is within NDL. static unsigned char find_next_stop(void); // Finds the next stop when in a deco ascent. static unsigned char update_deco_table(PARAMETER unsigned char time_increment); // Enters a new stop or extends an existing stop in the deco stops table. -static void calc_ascenttime(void); // Calculates the ascent time from current depth and deco stop times. -static void calc_gas_needs_ascent(void); // Calculates required gas volumes and pressures from the data in stops table. static void calc_due_by_depth_time_sac(void); // Calculates gas volume required for a given depth, time and usage (SAC rate). static void convert_gas_needs_to_press(void); // Converts gas volumes into pressures and sets respective flags. @@ -312,9 +305,10 @@ static void adopt_Buhlmann_coefficients(void); // Computes average a and b coefficient by the N2/He tissue ratio. static void push_tissues_to_vault(void); // Stores the state of the real tissues during simulator runs. static void pull_tissues_from_vault(void); // Restores the state of the real tissues after a simulator run. -static void calc_N2_equilibrium(void); // Calculate partial pressure of N2 in respired air at surface pressure -static void get_saturation_factors(void); // Get, safeguard and convert the saturation and desaturation factors -static void apply_saturation_factors(void); // Applies saturation and desaturation factors +static void calc_sim_pres_respiration(void); // Calculate sim_pres_respiration from char_depth_sim. +static void calc_N2_equilibrium(void); // Calculate partial pressure of N2 in respired air at surface pressure. +static void get_saturation_factors(void); // Get, safeguard and convert the saturation and desaturation factors. +static void apply_saturation_factors(void); // Applies saturation and desaturation factors. // ********************************************************************************************************************************* @@ -332,11 +326,11 @@ static float pres_surface; // absolute pressure at the surface -static float float_depth_real; // current real depth in meters, float -static unsigned char char_depth_real; // current real depth in meters, integer -static unsigned char char_depth_sim; // current simulated depth in meters, integer -static unsigned char char_depth_last; // last simulated depth in meters, integer -static unsigned char char_depth_bottom; // bottom depth in meters, integer +static float float_depth_real; // current real depth in meters, float +static unsigned char char_depth_real; // current real depth in meters, integer +static unsigned char char_depth_sim_start; // start value of simulated depth in meters, integer +static unsigned char char_depth_sim; // current value of simulated depth in meters, integer +static unsigned char char_depth_last; // last value of simulated depth in meters, integer static float real_pres_respiration; // current real depth in absolute pressure static float real_O2_ratio; // real breathed gas oxygen ratio @@ -368,7 +362,7 @@ static float GF_slope_alt; // (GF_high - GF_low) / GF_low_depth_alt in alternative plan static float float_ascent_speed; // ascent speed from options_table (5.0 .. 10.0 m/min) -static float float_deco_distance; // additional depth below stop depth for tissue, CNS and gas volume calculation +static float float_deco_distance; // additional depth below stop depth - not used any more static float float_saturation_multiplier; // safety factor for on-gassing rates static float float_desaturation_multiplier; // safety factor for off-gassing rates @@ -395,6 +389,7 @@ static unsigned char NDL_tissue_lead; // tissue with the shortest NDL time found in current cycle static unsigned char NDL_tissue; // tissue for which the NDL is calculated right now + // Result Values from Calculation Functions (9 byte) static float ceiling; // minimum tolerated relative pressure (i.e. without surface pressure) @@ -411,45 +406,28 @@ static unsigned short int_time; // time it takes for the compartment to reach the target pressure -// Gas in Use and Gas Needs (30 byte) - +// Gas in Use and Gas Needs (26 byte) + +static unsigned char sim_gas_last_num; // number of the last used gas static unsigned char sim_gas_current_num; // number of the currently used gas static unsigned char sim_gas_current_depth; // change depth of the currently used gas -static unsigned char gas_needs_stop_time; // duration of the stop in minutes -static unsigned char gas_needs_stop_gas; // gas used now (1-5 or 0) -static unsigned char gas_needs_stop_gas_last; // gas used before (1-5 or 0) -static unsigned char gas_needs_stop_depth; // depth of the stop in meters -static unsigned char gas_needs_stop_depth_last; // depth of the last stop in meters -static unsigned char gas_needs_stop_index; // index to the stop table +static unsigned char sim_gas_best_num; // number of the better gas +static unsigned char sim_gas_best_depth; // change depth of the better gas + static unsigned char gas_needs_gas_index; // index to the gas and tank data arrays -static unsigned char gas_needs_next_phase; // next phase within the ascent gas needs calculation - -static float gas_volume_need[NUM_GAS]; // gas volumes required for return/ascent in liters - - -// Transfer Variables between calc_gas_needs_ascent() and calc_due_by_depth_time_sac() (13 byte) - -static float gas_needs_float_depth; // depth of the stop or half-way point -static float gas_needs_float_time; // duration of the stop or ascent phase -static unsigned char gas_needs_stop_usage; // gas usage in l/min +static float gas_volume_need[NUM_GAS]; // gas volumes required for return/ascent in liters +static float gas_volume_avail[NUM_GAS]; // gas volumes available for return/ascent in liters + + +// Transfer Variables for calc_due_by_depth_time_sac() (7 byte) + +static unsigned char gas_needs_depth; // depth of the stop or half-way point +static unsigned char gas_needs_time; // duration of the stop or ascent phase +static unsigned char gas_needs_usage_rate; // gas usage in l/min static float gas_needs_volume_due; // computed due of gas volume required -// CNS Coefficients (10 byte) - -static float var_cns_a; // two coefficients approximation, gain -static float var_cns_b; // two coefficients approximation, offset -static unsigned short var_cns_c; // one coefficient approximation, value - - -// Transfer values for convert_float_int and convert_float_to_char() (7 byte) - -static float float_value; // input value, float -static unsigned short int_value; // output value, 16 bit -static unsigned char char_value; // output value, 8 bit - - // Auxiliary Variables for Data Buffering (28 byte) static float N2_equilibrium; // used for N2 tissue graphics scaling @@ -461,14 +439,7 @@ static float old_pres_respiration; // auxiliary variable to buffer sim_pres_respiration -// Performance Profiling (4 byte) - -static unsigned short profiling_runtime; // performance measurement: runtime of current invocation -static unsigned char profiling_runs; // performance measurement: invocations per deco calculation cycle -static unsigned char profiling_phase; // performance measurement: current calculation phase - - -// 255 byte used, 1 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char) +// 244 byte used, 12 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char) //---- Bank 6 parameters ----------------------------------------------------- @@ -482,7 +453,7 @@ static volatile unsigned char tmr5_overflow; // timer 5 overflow flag MUST be at address 0x602 -// Modes, Sequencing and Indexing (11 byte) +// Modes, Sequencing and Indexing (12 byte) static unsigned char main_status; // shadow register for char_O_main_status static unsigned char deco_status; // shadow register for char_O_deco_status @@ -495,6 +466,8 @@ static unsigned char cns_i; // index to the CNS tables (ppO2 range index) static unsigned char i; // general purpose loop counter and index static unsigned char fast; // selects 1 minute or 2 second ascent steps +static unsigned char stop_index; // current stop table position +static unsigned char chained_stops; // counter for chained stop entries // Result Values from Calculation Functions (28 byte) @@ -526,6 +499,13 @@ static float var_He_ht; // half-time, for current He tissue +// CNS Coefficients (10 byte) + +static float var_cns_a; // two coefficients approximation, gain +static float var_cns_b; // two coefficients approximation, offset +static unsigned short var_cns_c; // one coefficient approximation, value + + // Vault to back-up & restore Tissue related Data (134 byte) static float vault_pres_tissue_N2[NUM_COMP]; // stores the nitrogen tissue pressures @@ -535,10 +515,24 @@ static unsigned char vault_deco_info; // stores info status +// Transfer values for convert_float_int and convert_float_to_char() (7 byte) + +static float float_value; // input value, float +static unsigned short int_value; // output value, 16 bit +static unsigned char char_value; // output value, 8 bit + + +// Performance Profiling (4 byte) + +static unsigned short profiling_runtime; // performance measurement: runtime of current invocation +static unsigned char profiling_runs; // performance measurement: invocations per deco calculation cycle +static unsigned char profiling_phase; // performance measurement: current calculation phase + + // 7 byte occupied by compiler-placed vars -// 223 byte used, 33 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char) +// 245 byte used, 11 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char) @@ -601,7 +595,7 @@ #endif rom const float CNS_ab[2*11] = { -// CNS increment per 2sec = 1 / (a*ppO2 + b) with ppO2 in [cbar] +// CNS increment per 2 sec = 1 / (a*ppO2 + b) with ppO2 in [cbar] // a b for ppO2 cbar range -533.07, 54000, // 51 - 60 (index 0) -444.22, 48600, // 61 - 70 (index 1) @@ -616,8 +610,8 @@ -222.11, 37350 // 151 - 160 (index 10) }; -rom const unsigned short CNS_c[1*20] = { -// CNS increment per 2sec = c / 100000.0 +rom const unsigned short CNS_c[1*18] = { +// CNS increment per 2 sec = c / 100000.0 // c in [1/100000] for ppO2 cbar range 75, // 161 - 165 (index 0) 102, // 166 - 170 (index 1) @@ -636,9 +630,7 @@ 4820, // 231 - 235 (index 14) 4820, // 236 - 240 (index 15) 4820, // 241 - 245 (index 16) - 4820, // 246 - 250 (index 17) - 4820, // 251 - 255 (index 18) - 0 // not used, just to fill up the memory block + 4820 // 246 - 250 (index 17) }; @@ -668,7 +660,7 @@ }; rom const float Buhlmann_ht[2*16] = { -// Compartment half-life, in minute +// Compartment half-life, in minutes //--- N2 ---- He ---------------------- 4.0, 1.51, 8.0, 3.02, @@ -689,7 +681,8 @@ }; rom const float e2secs[2*16] = { -// result of 1 - 2^(-1/(2sec*HT)) +// Integration constant for 2 seconds, +// result of 1 - 2^(-1/(2sec/60sec * HT)) //---- N2 ------------- He ------------ 5.75958E-03, 1.51848E-02, 2.88395E-03, 7.62144E-03, @@ -712,7 +705,7 @@ rom const float e1min[2*16] = { // Integration constant for 1 minute, -// Ie. 1- 2^(-1/HT) +// result of 1 - 2^(-1/HT) //----- N2 --------- e 1min He -------- 1.59104E-01, 3.68109E-01, 8.29960E-02, 2.05084E-01, @@ -734,8 +727,8 @@ }; rom const float e10min[2*16] = { -// The 10 min Value in float notation: -// result of 1 - 2^(-10/ht) +// Integration constant for 10 minutes, +// result of 1 - 2^(-10/ht) //---- N2 -------------- He ----------- 8.23223E-01, 9.89851E-01, 5.79552E-01, 8.99258E-01, @@ -764,7 +757,7 @@ // ********************************************************************************************************************************* -// moved from 0x0D000 to 0x0C000 in v.108 +// p2deco code moved from 0x0D000 to 0x0C000 in v.108 #ifndef UNIX # pragma code p2_deco = 0x0C000 #endif @@ -780,8 +773,8 @@ ////////////////////////////////////////////////////////////////////////////// -// When calling C code from ASM context, the data stack pointer and -// frames should be reset. Bank 8 is used by stack. +// When calling C code from ASM context, the C data stack pointer need to be +// reset. The C stack is located in bank 8. #ifdef CROSS_COMPILE # define RESET_C_STACK @@ -914,7 +907,7 @@ // Note: We don't use far ROM pointer, because handling // 24 bit is too complex, hence we have to set the // UPPER page ourself... - // -> Set to zero if tables are moved to lower pages! + // -> set to zero if tables are moved to lower pages! _asm movlw 1 movwf TBLPTRU,0 @@ -1047,6 +1040,20 @@ ////////////////////////////////////////////////////////////////////////////// +// Calculate sim_pres_respiration from char_depth_sim +// +// Input: char_depth_sim simulated depth in meters +// pres_surface surface pressure +// +// Output: sim_pres_respiration simulated depth in absolute pressure +// +static void calc_sim_pres_respiration(void) +{ + sim_pres_respiration = (float)char_depth_sim * METER_TO_BAR + pres_surface; +} + + +////////////////////////////////////////////////////////////////////////////// // Calculate partial pressure of N2 in respired air at surface pressure // // Input: pres_surface surface pressure @@ -1138,13 +1145,13 @@ // // called from: divemode.asm // -// Called every second during diving, -// updates tissues on every second invocation. +// Called two times per second during diving, updates the +// tissues every second (i.e. on every second invocation). // -// Every few seconds (or slower when TTS > 16): +// On each computation cycle: // - Updates deco table (char_O_deco_time/depth) with new values, // - updates ascent time, and -// - sets status to zero (so we can check there is new results). +// - sets status to zero (so we can check a cycle has finished). // void deco_calc_hauptroutine(void) { @@ -1166,6 +1173,7 @@ init_output_vars(); } + ////////////////////////////////////////////////////////////////////////////// // deco_clear_tissue // @@ -1173,7 +1181,7 @@ // menu_tree.asm // simulator.asm // -// Sets all tissues to equilibrium with Air at ambient pressure, +// Sets all tissues to equilibrium with air at ambient pressure, // resets all CNS values, any warnings and resets all model output. // void deco_clear_tissue(void) @@ -1188,9 +1196,9 @@ // // called from: simulator.asm // -// Updates tissues and CNS value for char_I_dive_interval minutes on air -// at ambient pressure and calculates resulting GF factor and ceiling for -// a GF-high of 100% (ceiling and GF factor not used by simulator.asm) +// Updates tissues and CNS value for char_I_dive_interval minutes on air at +// ambient pressure and calculates resulting saturation and ceiling for a +// GF-high of 100% (ceiling and saturation not used by simulator.asm) // void deco_calc_dive_interval(void) { @@ -1209,8 +1217,7 @@ // ghostwriter.asm // // Updates tissues and CNS value for 1 minute on air at ambient pressure and -// calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling -// is not used by *.asm files). +// calculates resulting saturation and ceiling for a GF-high of 100%. // void deco_calc_dive_interval_1min(void) { @@ -1225,8 +1232,7 @@ // called from: sleepmode.asm // // Updates tissues and CNS value for 10 minutes on air at ambient pressure and -// calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling -// is not used by sleepmode.asm). +// calculates resulting saturation and ceiling for a GF-high of 100%. // void deco_calc_dive_interval_10min(void) { @@ -1289,15 +1295,13 @@ ////////////////////////////////////////////////////////////////////////////// -// find_next_stop +// Calculate the next deco stop // // INPUT, fixed during dive: // pres_surface : surface pressure (as absolute pressure) // char_I_depth_last_deco : depth of the last deco stop // -// INPUT, changing during dive: -// float_depth_real : current real depth in meters (float) -// char_depth_real : current real depth in meters (integer) +// INPUT, may change during dive: // GF_high : GF high factor // GF_low : GF low factor // @@ -1319,48 +1323,31 @@ { overlay unsigned char depth_1min; overlay unsigned char depth_limit; - overlay unsigned char first_stop; + overlay unsigned char stop_depth; + overlay unsigned char next_stop; overlay unsigned char need_stop; - // ----------------------------------------------------------------------- - // we start with the assumption that a stop is not required - // ----------------------------------------------------------------------- - - need_stop = 0; - - // remember the depth we came from + // memorize the depth we came from char_depth_last = char_depth_sim; - // calculate the limit for the current depth - if( char_I_deco_model == 0 ) calc_limit(1.0); // straight Buhlmann - else if( char_depth_sim >= GF_low_depth ) calc_limit(GF_low); // with GF, below low depth reference - else calc_limit(GF_high - GF_slope * (float)char_depth_sim); // with GF, above low depth reference - - // check if we can surface directly - if( ceiling <= 0.0 ) - { - // YES - ascent to surface is allowed - char_depth_sim = 0; - - // - done - goto done; - } - - // ----------------------------------------------------------------------- - // a stop is required, but maybe not yet within the running minute - // ----------------------------------------------------------------------- - - // convert the depth we can ascent to from relative pressure to meters, - // rounded up (i.e. made deeper) to next full meter. - depth_limit = (unsigned char)(ceiling * BAR_TO_METER + 0.99); - - // calculate the stop depth, i.e. round up to the next multiple of 3 meters - // using integer arithmetics - first_stop = 3 * ( (depth_limit + 2) / 3 ); + // calculate the ceiling (minimum relative pressure) for the current depth + if( char_I_deco_model == 0 ) calc_limit(1.0); // deco or not - straight Buhlmann + else if( NDL_time ) calc_limit(GF_high); // not in deco + else if( char_depth_sim >= GF_low_depth ) calc_limit(GF_low); // in deco with GF, below or at low depth reference + else calc_limit(GF_high - GF_slope * (float)char_depth_sim); // in deco with GF, above low depth reference + + // convert the ceiling from relative pressure to meters, + // rounded up (i.e. made deeper) to next full meter, + // limiting at surface. + depth_limit = (ceiling > 0.0) ? (unsigned char)(ceiling * BAR_TO_METER + 0.99) : 0; + + // calculate the stop depth, i.e. round up (make deeper) to + // the next multiple of 3 meters using integer arithmetics + stop_depth = 3 * ( (depth_limit + 2) / 3 ); // apply correction for the shallowest stop - if( first_stop == 3 ) first_stop = char_I_depth_last_deco; + if( stop_depth == 3 ) stop_depth = char_I_depth_last_deco; // compute depth in meters that will be reached in 1 minute of ascent // at a speed of char_I_ascent_speed (5..10 m/min) @@ -1373,36 +1360,53 @@ depth_1min = 0; } - // is the stop shallower than the depth that can be reached within 1 minute? - if( depth_1min > first_stop ) + // is the stop depth shallower than the depth that can be reached within 1 minute, + // or are we allowed to surface AND can we reach the surface within 1 minute? + if( ( ( stop_depth < depth_1min ) ) + || ( ( stop_depth == 0 ) && ( depth_1min == 0 ) ) + ) { // YES - report the depth that will be reached within 1 minute of ascent char_depth_sim = depth_1min; + // - no stop needed + need_stop = 0; + // - done goto done; } // ----------------------------------------------------------------------- - // we need to make a stop now + // we need to make a stop now, or need to stay at the current stop depth // ----------------------------------------------------------------------- // set stop data need_stop = 1; - char_depth_sim = first_stop; + char_depth_sim = stop_depth; + + // Apply correction in case the stop is to be placed deeper than a + // previously recorded stop for a gas change. This may happen because + // the deco stops are placed at the next deeper multiple of 3 meters + // instead of the real stop's depth. Correction is to relocate the + // deco stop to the depth of the last gas change. The resulting combined + // stop's duration will be the sum of the configured gas change time plus + // the duration of the deco stop itself. + if( 0 < internal_deco_depth[stop_index] ) + if( char_depth_sim > internal_deco_depth[stop_index] ) + char_depth_sim = internal_deco_depth[stop_index]; // done so far if using straight Buhlmann if( char_I_deco_model == 0 ) goto done; // ----------------------------------------------------------------------- - // we need to make a stop now and we are using the GF extension + // we need to make or hold a stop and we are using the GF extension // ----------------------------------------------------------------------- - // is the depth limit deeper than the GF low depth reference used up to now? - if( depth_limit > GF_low_depth ) + // is the stop depth deeper than the GF low depth reference used up to now? + if( stop_depth > GF_low_depth ) { // YES - update the reference - GF_low_depth = depth_limit; + GF_low_depth = stop_depth; GF_slope = (GF_high - GF_low) / (float)GF_low_depth; // store for use in next cycles @@ -1418,13 +1422,6 @@ } } - // keep the stop as it is when it is the first stop - // (i.e. there are no stops in the stops table yet) - if( internal_deco_depth[0] == 0 ) goto done; - - // keep the stop as it is when extended stops are activated - if( main_status & EXTENDED_STOPS ) goto done; - // We have a (first) stop. But with a steep GF slope, the stop(s) after this // first stop may be allowed to ascent to, too. This is because the gradient // factor that will be used at the next depth(s) will allow more tissue super- @@ -1432,35 +1429,39 @@ // ascent to. So we have to probe the next stops that are within the reach of // 1 minute of ascent as well. - // no need to probe for a stop that is beyond 1 minute of ascent - while( first_stop >= (depth_1min + 3) ) + // probe all stop depths that are in reach of 1 minute of ascent + next_stop = stop_depth; + + while(next_stop > 0) { - overlay unsigned char next_stop; - - // compute the depth of the next stop - if ( first_stop <= char_I_depth_last_deco ) next_stop = 0; - else if ( first_stop == 6 ) next_stop = char_I_depth_last_deco; - else next_stop = first_stop - 3; - - // compute the depth limit at the next stop depth - calc_limit(GF_high - GF_slope * (float)next_stop); - - // check if ascent to the next stop is allowed - if( next_stop < (unsigned char)(ceiling * BAR_TO_METER + 0.99) ) + // compute the depth of the next stop ... + if ( next_stop <= char_I_depth_last_deco ) next_stop = 0; + else if ( next_stop == 6 ) next_stop = char_I_depth_last_deco; + else next_stop -= 3; + + // would the next stop be beyond the 1 minute limit? + if( next_stop < depth_1min ) { - // NO - the next stop would be too shallow - break; + // YES - signal that probing is done + next_stop = 0; } else { - // YES - the next stop is allowed - char_depth_sim = next_stop; - - // - ascent to next stop - first_stop = next_stop; - - // - loop to probe the stop following next - continue; + // NO - compute the ceiling at the next stop depth + calc_limit(GF_high - GF_slope * (float)next_stop); + + // - limit ceiling to positive values, i.e. the surface + if( ceiling < 0.0 ) ceiling = 0.0; + + // - check if this stop depth would be allowed + if( next_stop >= (unsigned char)(ceiling * BAR_TO_METER + 0.99) ) + { + // YES - this stop depth is allowed + char_depth_sim = next_stop; + + // - no stop needed if stop depth actually is the surface + if( next_stop == 0 ) need_stop = 0; + } } } @@ -1472,68 +1473,21 @@ done: // calculate absolute pressure at the depth found - sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; + calc_sim_pres_respiration(); return need_stop; } ////////////////////////////////////////////////////////////////////////////// -// publish_deco_table -// -// Input: internal_deco_depth[] depth in internal stops table -// internal_deco_time[] times ... -// internal_deco_gas[] gases ... -// -// Output: char_O_deco_depth[] depth in the external stops table -// char_O_deco_time[] times ... -// char_O_deco_gas[] gases ... -// char_O_deco_time_for_log times in reverse order -// -static void publish_deco_table(void) -{ - overlay unsigned char x = 0; - overlay unsigned char y; - - - // copy all entries from internal to external stops table - for( y = 0; y < NUM_STOPS; y++ ) - { - // remember index of last entry with a non-null depth - if( internal_deco_depth[y] > 0 ) x = y; - - // copy depth, time and gas - char_O_deco_depth[y] = internal_deco_depth[y]; - char_O_deco_time [y] = internal_deco_time [y]; - char_O_deco_gas [y] = internal_deco_gas [y]; - } - - - // copy times of shallowest stops to logging table - for( y = 0; y < NUM_STOPS_LOG; y++, --x ) - { - char_O_deco_time_for_log[y] = internal_deco_time [x]; - - // stop when all entries are copied - if( x == 0 ) break; - } - - // fill the remainder of the logging table with null - // if it is not completely filled already - for( y++; y < NUM_STOPS_LOG; y++ ) - char_O_deco_time_for_log[y] = 0; -} - - -////////////////////////////////////////////////////////////////////////////// -// Find current gas in the list (if any) and get its change depth +// Find current gas in the list and get its change depth // // Input: char_I_current_gas_num number of current gas (1..5 or 6) // // Output: sim_gas_current_num 1..6 or 0 for the manually configured gas/dil // sim_gas_current_depth change depth (MOD) of the gas/dil in meters // -static void gas_find_current(void) +static void gas_take_current(void) { assert( 1 <= char_I_current_gas_num && char_I_current_gas_num <= 6 ); @@ -1541,6 +1495,9 @@ { sim_gas_current_num = char_I_current_gas_num; sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current_num-1]; + + // capture case of non-configured change depth + if( sim_gas_current_depth == 0 ) sim_gas_current_depth = 255; } else { @@ -1551,34 +1508,27 @@ ////////////////////////////////////////////////////////////////////////////// -// Find the deco gas with the shallowest change depth below or at the current depth +// Find the gas with the shallowest change depth below or at the current depth // // Input: char_depth_sim simulated depth in meters // sim_gas_current_num number of the currently used gas/dil -// sim_gas_current_depth change depth of the currently used gas/dil // char_I_deco_gas_type[] types of the gases/dils // char_I_deco_gas_change[] change depths of the gases/dils // -// Modified: sim_gas_current_num index of the gas (1..5) - only if return value is true -// sim_gas_current_depth switch depth - only if return value is true +// Modified: sim_gas_best_num index of the gas (1..5) - only if return value is true +// sim_gas_best_depth switch depth - only if return value is true // // Return value is TRUE if a better gas is available // -static unsigned char gas_find_better(void) +static unsigned char gas_find_best(void) { overlay unsigned char switch_depth = 255; overlay unsigned char switch_gas = 0; overlay unsigned char j; - // // no automatic gas changes in CCR mode - // if( (deco_status & MODE_MASK) == MODE_CCR ) return 0; - - // loop over all deco gases to find the shallowest one below or at current depth + // loop over all gases to find the shallowest one below or at current depth for( j = 0; j < NUM_GAS; ++j ) { - // Is this gas not the one we are already breathing? - if( j+1 != sim_gas_current_num ) - // Is this gas available? if( char_I_deco_gas_type[j] > 0 ) @@ -1586,42 +1536,58 @@ // at least equal to the current depth? if( char_I_deco_gas_change[j] >= char_depth_sim ) - // Is the change depth of this gas shallower than the - // change depth of the gas we are currently on? - if( char_I_deco_gas_change[j] < sim_gas_current_depth ) - - // Is the change depth of this gas shallower than the change - // depth of the best gas found so far, or is it the first - // better gas found? - if( char_I_deco_gas_change[j] < switch_depth ) + // Is the change depth of this gas shallower than or + // at least equal to the change depth of the best gas + // found so far, or is it the first better gas found? + if( char_I_deco_gas_change[j] <= switch_depth ) + +#ifdef _gas_contingency + // Is there still enough of this gas or doesn't it matter? + if( ( gas_volume_need[j] < gas_volume_avail[j] ) || ( !char_I_gas_contingency ) ) +#endif // If there is a yes to all these questions, we have a better gas! { - switch_gas = j+1; // remember this gas (1..5) - switch_depth = char_I_deco_gas_change[j]; // remember its change depth + // memorize this gas (1..5) and its change depth + switch_gas = j+1; + switch_depth = char_I_deco_gas_change[j]; } - } // continue looping through all gases to eventually find an even better gas - // has a better gas been found? + // has a best gas been found? if( switch_gas ) { - // YES - set the better gas as the new gas - sim_gas_current_num = switch_gas; - - // set its change depth as the last used change depth - sim_gas_current_depth = switch_depth; - - assert( sim_gas_current_depth < switch_depth ); - - // signal a better gas was found - return 1; + // YES - export the best gas and its change depth + sim_gas_best_num = switch_gas; + sim_gas_best_depth = switch_depth; + + // is the best gas different from the current gas? + if( sim_gas_best_num != sim_gas_current_num ) + { + // YES - signal advice for a gas change + return 1; + } } - else - { - // NO - signal no better gas was found - return 0; - } + + // no best gas found or current gas is the best gas + return 0; +} + + +////////////////////////////////////////////////////////////////////////////// +// Switch to the best gas +// +// Input: sim_gas_best_num index of the best gas (1..5) +// sim_gas_best_depth switch depth of the best gas +// +// Modified: sim_gas_current_num index of the new gas (1..5) +// sim_gas_current_depth switch depth of the new gas +// +static void gas_take_best(void) +{ + // set new gas + sim_gas_current_num = sim_gas_best_num; + sim_gas_current_depth = sim_gas_best_depth; } @@ -1699,7 +1665,7 @@ // sim_/real_pSCR_drop : (simulated) pSCR O2 drop // pres_surface : surface pressure [bar] // char_I_const_ppO2 : ppO2 reported from sensors or setpoint [cbar] -// float_deco_distance : safety factor, additional depth below stop depth [bar] +// float_deco_distance : safety factor, additional depth below stop depth [bar] - not used any more // ppWater : water-vapor pressure inside respiratory tract [bar] // // Output: ppN2 : respired N2 partial pressure @@ -1759,6 +1725,8 @@ // correct sim_pres_respiration if shallower than calculated stop depth calc_pres_respiration = ( real_pres_respiration < sim_pres_respiration ) ? real_pres_respiration : sim_pres_respiration; + // +++ pressure surcharge if outside deco stops area yet ??? + status = deco_status; calc_O2_ratio = sim_O2_ratio; calc_N2_ratio = sim_N2_ratio; @@ -1866,8 +1834,8 @@ //---- calculate ppN2 and ppHe --------------------------------------------------------------------- - // add deco safety distance when working on simulated tissues - if( !(tissue_increment & TISSUE_SELECTOR) ) calc_pres_respiration += float_deco_distance; + // add deco safety distance when working on simulated tissues - not used any more + // if( !(tissue_increment & TISSUE_SELECTOR) ) calc_pres_respiration += float_deco_distance; // compute ppN2 and ppHe, capture potential failure conditions first: if( calc_pres_respiration > ppWater ) @@ -1891,12 +1859,29 @@ ppN2 = 0.0; ppHe = 0.0; } + +#ifdef _helium + // calculating real tissues? + if( tissue_increment & TISSUE_SELECTOR ) + { + overlay unsigned char temp; + + // compute gas density of current mix in multiples of 0.01 grams per liter + int_O_gas_density = (unsigned int)( 17.9 * ppHe + 125.1 * ppN2 + 142.8 * ppO2 ); + + // convert gas density into a 8 bit integer + temp = (unsigned char)( (int_O_gas_density + 9) / 10 ); + + // limit to display max and set warning or attention flag + if( temp > 99 ) int_O_gas_density = 999 | INT_FLAG_WARNING; + else if( temp > char_I_gas_density_warn ) int_O_gas_density |= INT_FLAG_WARNING; + else if( temp > char_I_gas_density_att ) int_O_gas_density |= INT_FLAG_ATTENTION; + } +#endif } ////////////////////////////////////////////////////////////////////////////// -// init_output_vars -// // Initializes all output variables to their default values // static void init_output_vars(void) @@ -1939,14 +1924,19 @@ int_O_SAC_measured = 0 + INT_FLAG_NOT_AVAIL; // SAC rate int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 1 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL; // pressure need to reading 2 + int_O_tank_pressure = 0; // tank pressure for logging #endif +#ifdef _helium + int_O_gas_density = 0; +#endif + + // also clear any time++ request + char_I_sim_advance_time = 0; } ////////////////////////////////////////////////////////////////////////////// -// clear_tissue -// // Reset all tissues to surface pressure equilibrium state // // Input: int_I_pres_surface current surface pressure in hPa (mbar) @@ -2007,7 +1997,7 @@ ////////////////////////////////////////////////////////////////////////////// -// calc_hauptroutine +// Deco engine main code // // This is the major code in dive mode, it calculates the tissue pressures, // the bottom time, and it calculates the ascend with all deco stops, etc. @@ -2021,7 +2011,6 @@ // // char_I_deco_model selector for GF extension // char_I_ascent_speed ascent speed -// char_I_deco_distance safety distance between stop depth and calculated depth // char_I_saturation_multiplier safety factor for tissue saturation // char_I_desaturation_multiplier safety factor for tissue desaturation // @@ -2056,9 +2045,9 @@ static void calc_hauptroutine(void) { overlay unsigned short int_ppO2_min; - overlay unsigned short int_ppO2_max; + overlay unsigned short int_ppO2_max_warn; + overlay unsigned short int_ppO2_max_att; overlay unsigned short int_ppO2_max_dil; - overlay unsigned short int_ppO2_max_max; overlay float EAD; overlay float END; @@ -2112,7 +2101,7 @@ char_O_deco_status &= ~COMMAND_MASK; // set the calculation phase to start with to doing the cyclic initialization - next_planning_phase = PHASE_11_CYCLIC_INIT; + next_planning_phase = PHASE_20_CYCLIC_INIT; // continue in CALCULATING @@ -2155,7 +2144,7 @@ // acquire current environmental data calc_hauptroutine_data_input(); - // calculate ppO2, ppN2 and ppHe + // calculate ppO2, ppN2 and ppHe for real tissues calc_alveolar_pressures(); // add decent calculation here and include trigger in above if-statement @@ -2239,52 +2228,56 @@ #endif - //---- Set/Reset Deco Mode -------------------------------------------------------------------- + //---- Set/Clear Deco Mode ------------------------------------------------------------------ + + // Clear the deco mode flag if: + // deco mode is set + // AND we are deeper than 7 meters below the deepest deco stop + // (7 meters chosen as to be 2 stop depth intervals plus 1 additional meter below) + if ( ( deco_info & DECO_MODE ) > 0 ) + if ( ( char_depth_real ) > char_O_deco_depth[0] + 7 ) + deco_info &= ~DECO_MODE; // Set the deco mode flag if: // deco mode is not set // AND breathing an OC deco gas (gas type 3) // OR breathing a gas or diluent that officially is disabled (type 0) - // OR there is a deco stop and we are less deep than 1 meter below the deepest deco stop - if ( ( deco_info & DECO_FLAG ) == 0 ) - if ( ( char_I_current_gas_type == 3 ) - || ( char_I_current_gas_type == 0 ) - || ( ( char_O_deco_depth[0] > 0 ) && ( char_depth_real <= char_O_deco_depth[0] + 1 ) ) + // OR there is a deco stop + if ( ( deco_info & DECO_MODE ) == 0 ) + if ( ( char_I_current_gas_type == 3 ) + || ( char_I_current_gas_type == 0 ) + || ( char_O_deco_depth[0] > 0 ) ) - deco_info |= DECO_FLAG; - - // Clear the deco mode flag if: - // deco mode is set - // AND deeper than 7 meters below deepest deco stop (7 meters = 2 stop depth intervals plus 1 meter below stop) - if ( ( deco_info & DECO_FLAG ) > 0 ) - if ( ( char_depth_real > char_O_deco_depth[0] + 7 ) - ) - deco_info &= ~DECO_FLAG; + deco_info |= DECO_MODE; //---- Compute ppO2 Warnings ------------------------------------------------------------------ - // compute conditional min values + // compute conditional min value #ifdef _ccr_pscr int_ppO2_min = ( main_status & MODE_LOOP ) ? (unsigned short)char_I_ppO2_min_loop : (unsigned short)char_I_ppO2_min; #else int_ppO2_min = (unsigned short)char_I_ppO2_min; #endif - // compute conditional max values - int_ppO2_max = ( deco_info & DECO_FLAG ) ? (unsigned short)char_I_ppO2_max_deco : (unsigned short)char_I_ppO2_max_work; - - // add some margin on ppO2 max to compensate for surface pressures > 1.000 mbar - int_ppO2_max += ppO2_MARGIN_ON_MAX; - - // get biggest of char_I_ppO2_max_work / char_I_ppO2_max_deco - int_ppO2_max_max = ( char_I_ppO2_max_deco > char_I_ppO2_max_work ) ? char_I_ppO2_max_deco : char_I_ppO2_max_work; + // determine the absolute max value (should be the deco one, but who knows...) + int_ppO2_max_warn = ( char_I_ppO2_max_work > char_I_ppO2_max_deco) ? char_I_ppO2_max_work : char_I_ppO2_max_deco; + + // add some margin to compensate for surface pressures > 1.000 mbar + int_ppO2_max_warn += ppO2_MARGIN_ON_MAX; + + // determine the normal max value + int_ppO2_max_att = ( deco_info & DECO_MODE ) ? (unsigned short)char_I_ppO2_max_deco : (unsigned short)char_I_ppO2_max_work; + + // add some margin to compensate for surface pressures > 1.000 mbar + int_ppO2_max_att += ppO2_MARGIN_ON_MAX; #ifdef _ccr_pscr - // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold - int_ppO2_max_dil = int_ppO2_max; - - // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint + // default value for the upper diluent ppO2 warning threshold is the upper warning threshold + int_ppO2_max_dil = int_ppO2_max_warn; + + // when enabled and in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint + if( char_I_dil_ppO2_check ) if( (main_status & MODE_MASK) == MODE_CCR ) { overlay unsigned short max_dil; @@ -2293,8 +2286,8 @@ // (the condition protects from negative numbers which would cause a wrap-around in unsigned integers) max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned short)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0; - // ...but never above int_ppO2_max. - if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil; + // ...but never above int_ppO2_max_warn + if( max_dil < int_ppO2_max_warn ) int_ppO2_max_dil = max_dil; // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks. @@ -2302,24 +2295,24 @@ #endif // check for safe range of breathed gas - if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; - else if ( int_O_breathed_ppO2 >= int_ppO2_max_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; - else if ( deco_info & DECO_FLAG ) ; // no attention generated in deco mode - else if ( main_status & MODE_LOOP ) ; // no attention generated in loop modes - else if ( int_O_breathed_ppO2 >= (unsigned short)char_I_ppO2_max_work ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; + if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; + else if ( int_O_breathed_ppO2 >= int_ppO2_max_warn ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; + else if ( deco_info & DECO_MODE ) ; // no attention generated in deco mode + else if ( main_status & MODE_LOOP ) ; // no attention generated in loop modes + else if ( int_O_breathed_ppO2 >= int_ppO2_max_att ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; #ifdef _ccr_pscr // check for safe range of pure oxygen - if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; + if ( int_O_O2_ppO2 >= int_ppO2_max_warn ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; // check for safe range of pure diluent - if ( int_O_pure_ppO2 <= (unsigned short)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; - else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; - else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; + if ( int_O_pure_ppO2 <= (unsigned short)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; + else if ( int_O_pure_ppO2 >= int_ppO2_max_warn ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; + else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; // check for safe range of calculated pSCR loop gas - if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; - else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; + if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; + else if ( int_O_pSCR_ppO2 >= int_ppO2_max_warn ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; #endif } // tasks every second / on the first section of the second @@ -2373,14 +2366,13 @@ init_output_vars(); // safeguard input parameters that are constant during the course of the dive - if( char_I_deco_distance > 20 ) char_I_deco_distance = 20; if( char_I_ascent_speed < 5 ) char_I_ascent_speed = 5; if( char_I_ascent_speed > 10 ) char_I_ascent_speed = 10; // convert input parameters to float numbers - float_deco_distance = 0.01 * char_I_deco_distance; float_ascent_speed = 1.00 * char_I_ascent_speed; + // initialize values that will be recalculated later on periodically deco_warnings = 0; // reset all deco warnings deco_info = 0; // reset all deco infos @@ -2389,9 +2381,26 @@ NDL_tissue_start_alt = 0; // initialize the tissue to start with when calculating alternative NDL time // enforce initialization of GF data on first cyclic initialization - GF_high_last = 0; - GF_low_last = 0; - + GF_high_last = 255; + GF_low_last = 255; + +#ifdef _gas_contingency + // shall check for gas pan out? + if( char_I_gas_contingency ) + { + overlay float reduction = 0.5 * (float)char_I_SAC_deco * (1.0 + (float)char_I_depth_last_deco / 10.0); + + // YES - calculate volumes available for each gas + for( i = 0; i < NUM_GAS; i++ ) + { + // total available volume = tank size * fill press, char_I_gas_avail_pres is in multiples of 10 bar + gas_volume_avail[i] = (float)char_I_gas_avail_size[i] * (float)char_I_gas_avail_pres[i] * 10.0; + + // reduce total available volumes by due for 1/2 minute on last stop + gas_volume_avail[i] -= reduction; + } + } +#endif #ifdef _cave_mode char_I_backtrack_time = 0; //clear backtracking time (index to char_I_backtrack_depth) @@ -2407,16 +2416,16 @@ // the next calculation phase will do the cyclic initialization of the deco engine if a // normal or alternative plan shall be calculated, else the calculation cycle is done. - if( deco_status & PLAN_MASK ) next_planning_phase = PHASE_11_CYCLIC_INIT; + if( deco_status & PLAN_MASK ) next_planning_phase = PHASE_20_CYCLIC_INIT; else next_planning_phase = PHASE_00_DONE; break; // - //---- once-per-cycle Initialization of the Deco Engine------------------------------------ + //---- once-per-cycle Initialization of the Deco Engine ----------------------------------- // - case PHASE_11_CYCLIC_INIT: + case PHASE_20_CYCLIC_INIT: // target the simulated tissues (flag bit 7 = 0) tissue_increment = 0; @@ -2435,15 +2444,16 @@ if( char_I_deco_model != 0 ) { // update GF parameters (GFs may have been switched between GF and aGF) - if( (char_I_GF_High_percentage != GF_high_last) || (char_I_GF_Low_percentage != GF_low_last) ) + if( (char_I_GF_Low_percentage != GF_low_last) || (char_I_GF_High_percentage != GF_high_last) ) { // store new values in integer format + GF_low_last = char_I_GF_Low_percentage; GF_high_last = char_I_GF_High_percentage; - GF_low_last = char_I_GF_Low_percentage; - - // store new values in float format - GF_high = 0.01 * char_I_GF_High_percentage; - GF_low = 0.01 * char_I_GF_Low_percentage; + + // safeguard and store new values in float format + GF_low = ( GF_low_last > 10 ) ? 0.01 * GF_low_last : 0.10 ; + GF_high = ( GF_high_last > GF_low_last ) ? 0.01 * GF_high_last : GF_low; + // reset low depth references and slopes GF_low_depth_norm = 0; @@ -2468,26 +2478,21 @@ // initialize the simulated CNS value with the current CNS value of the real tissues CNS_fraction_sim = CNS_fraction_real; - // initialize the simulated depth with the current depth (in absolute pressure) + // initialize the simulated depth with the current depth, + // memorize current depth as start depth of the simulation sim_pres_respiration = real_pres_respiration; - - // compute the depth in meters where we are now - float_depth_real = (sim_pres_respiration - pres_surface) * BAR_TO_METER; - - // convert to integer and round up to next full meter - char_depth_real = (unsigned char)(float_depth_real + 0.99); - - // initialize depth for deco ascent calculation - char_depth_sim = char_depth_real; + char_depth_sim = char_depth_real; + char_depth_sim_start = char_depth_real; // Lookup the gas that is currently breathed with the real tissues and set it as // the gas to be used with the simulated tissues, too. This gas will be used until - // gas_find_better() is invoked and finds a better gas to switch to. - gas_find_current(); - - // Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio). These ratios - // can be kept until a gas switch is done. Thus, if a call to gas_find_better() has - // found a better gas and initiated a switch, gas_set_ratios() needs to be called again. + // gas_find_best()/gas_take_best() is invoked and switches to a better gas. + gas_take_current(); + + // Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio). + // These ratios can be kept until a gas switch is done. Thus, if a call to + // gas_find_best() has found a better gas and this gas is taken by a call + // to gas_take_best(), gas_set_ratios() needs to be called again. gas_set_ratios(); // compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration @@ -2496,6 +2501,9 @@ // initialize the no decompression limit (NDL) time to 240 minutes NDL_time = 240; + // initialize the total ascent time to 0 minutes + ascent_time = 0; + // retrieve the tissue that had the shortest NDL time during last calculation NDL_tissue_start = ( deco_status & CALC_NORM ) ? NDL_tissue_start_norm : NDL_tissue_start_alt; @@ -2507,22 +2515,40 @@ // start with 1 minute ascent steps when calculating the initial ascent fast = 1; - // initialization for calc_gas_needs_ascent() - gas_needs_next_phase = GAS_NEEDS_INIT; - // initialization for convert_gas_needs_to_press() gas_needs_gas_index = 0; + // shall calculate gas needs? + if( main_status & CALC_VOLUME ) + { + // set the usage rate (SAC rate), starting with working part of the dive + gas_needs_usage_rate = char_I_SAC_work; + + // clear the gas volume needs for gases 1-5 + for( i = 0; i < NUM_GAS; ++i ) gas_volume_need[i] = 0.0; + +#ifdef _rx_functions + // only for OSTC TR model with TR functions enabled + if( main_status & TR_FUNCTIONS ) + { + // invalidate pressure needs to pressure readings + int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL; + int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL; + } +#endif + } #ifdef _profiling profiling_runs = 0; #endif // The next calculation phase will - // - calculate the bottom segment if extended bottom time is configured (fTTS), + // - calculate the extended bottom segment if extended bottom time is configured (fTTS), + // - calculate the bottom segment gas need if gas needs calculation is configured, // - proceed with calculating the NDL time else. - if ( deco_status & DELAYED_ASCENT ) next_planning_phase = PHASE_20_EXTENDED_BOTTOM_TIME; - else next_planning_phase = PHASE_30_NDL_TIME; + if ( deco_status & DELAYED_ASCENT ) next_planning_phase = PHASE_30_EXTENDED_BOTTOM_TIME; + else if ( main_status & CALC_VOLUME ) next_planning_phase = PHASE_40_BOTTOM_GAS_NEED; + else next_planning_phase = PHASE_50_NDL_TIME; break; @@ -2530,22 +2556,51 @@ // //---- extended Bottom Time --------------------------------------------------------------- // - case PHASE_20_EXTENDED_BOTTOM_TIME: + case PHASE_30_EXTENDED_BOTTOM_TIME: // program interval on simulated tissues (flag bit 7 = 0) tissue_increment = char_I_extra_time; - // calculate ppO2, ppN2 and ppHe - calc_alveolar_pressures(); - - // update the tissues + // update the simulated tissues for tissue_increment (char_I_extra_time) minutes at depth, + // calc_alveolar_pressures() has already been called in cyclic initialization calc_tissues(); - // update the CNS value + // update the CNS value for tissue_increment (char_I_extra_time) minutes at depth calc_CNS(); + // the next calculation phase will + // - calculate the extended bottom segment gas needs if gas needs calculation is configured, + // - proceed with calculating the NDL time else. + if ( main_status & CALC_VOLUME ) next_planning_phase = PHASE_40_BOTTOM_GAS_NEED; + else next_planning_phase = PHASE_50_NDL_TIME; + + break; + + + // + //---- Bottom Segment Gas Need ------------------------------------------------------------ + // + case PHASE_40_BOTTOM_GAS_NEED: + + // on gas 1-5 ? + if( sim_gas_current_num ) + { + // YES - set the bottom depth + gas_needs_depth = char_depth_sim_start; + + // take either the whole bottom time or just the fTTS/bailout extra time + gas_needs_time = ( main_status & CALCULATE_BOTTOM ) ? char_I_bottom_time : char_I_extra_time; + + // calculate gas demand + calc_due_by_depth_time_sac(); + + // take the result + gas_volume_need[sim_gas_current_num-1] = gas_needs_volume_due; + } + + // the next calculation phase will calculate the NDL time - next_planning_phase = PHASE_30_NDL_TIME; + next_planning_phase = PHASE_50_NDL_TIME; break; @@ -2553,7 +2608,7 @@ // //---- NDL Time --------------------------------------------------------------------------- // - case PHASE_30_NDL_TIME: + case PHASE_50_NDL_TIME: // Calculate the remaining no decompression limit (NDL) time for the tissue NDL_tissue. // NDL_time will be updated if the NDL time found is shorter than the current NDL_time. @@ -2580,14 +2635,13 @@ // done with calculating NDL time, set next calculation phase: // - calculate return and ascent in cave mode if configured, else - // - proceed with gathering the results if within NDL time, or - // - proceed with the initial ascent if beyond NDL time. + // - proceed with no-stop ascent if within NDL time, or + // - proceed with deco ascent if beyond NDL time. #ifdef _cave_mode - if ( main_status & CAVE_MODE ) next_planning_phase = PHASE_40_CAVE_ASCENT; + if ( main_status & CAVE_MODE ) next_planning_phase = PHASE_60_CAVE_RETURN; else #endif - if ( NDL_time ) next_planning_phase = PHASE_70_RESULTS; - else next_planning_phase = PHASE_60_DECO_ASCENT; + next_planning_phase = PHASE_70_OPEN_WATER_ASCENT; } break; @@ -2595,93 +2649,244 @@ #ifdef _cave_mode // - //---- Cave Mode Return/Ascent ------------------------------------------------------------ + //---- Cave Mode Return ------------------------------------------------------------------- // - case PHASE_40_CAVE_ASCENT: + case PHASE_60_CAVE_RETURN: // TODO // the next calculation phase will gather all results - next_planning_phase = PHASE_70_RESULTS; + next_planning_phase = PHASE_80_RESULTS; break; #endif // - //---- Open Water Ascent with Deco Stops -------------------------------------------------- + //---- Open Water Ascent ------------------------------------------------------------------ // - case PHASE_60_DECO_ASCENT: + case PHASE_70_OPEN_WATER_ASCENT: // program 1 minute interval on simulated tissues tissue_increment = 1; - // ascent to the next stop depth or the depth that is reachable within one minute of ascent - // and decide if a stop is required (return value = 1/true) or not (return value = 0/false) + // memorize current gas in case there will be a gas change + sim_gas_last_num = sim_gas_current_num; + + // find_next_stop(): + // stays at the current stop depth, ascents to the next stop depth, or + // ascents to the depth that is reachable within one minute of ascent + // without needing to stop. + // + // return value : 1/true if a stop is required, else 0/false + // char_depth_sim : current depth (depth achieved) + // char_depth_last : last depth (depth we came from) + // if( find_next_stop() ) { + overlay unsigned char silent_stop = 0; + overlay unsigned char gas_change = 0; + //---- stop required -------------------- // check if there is a better gas to switch to - if( gas_find_better() ) + if( gas_find_best() ) { + // YES - memorize it + gas_change = 1; + + // take the gas + gas_take_best(); + // set the new calculation ratios for N2, He and O2 gas_set_ratios(); - // doing extended stops? - if( main_status & EXTENDED_STOPS ) + // add the gas change time to the stop time + tissue_increment += char_I_gas_change_time; + + // extended stops option enabled and + // gas change depth deeper than the current depth ? + if( main_status & EXTENDED_STOPS ) + if( sim_gas_current_depth > char_depth_sim ) { - // YES - set char_depth_sim to the gas change depth - char_depth_sim = sim_gas_current_depth; - - // - adjust absolute pressure down to the change depth - sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; + // YES - make a "silent" stop at the gas change depth + // to figure in the gas change + silent_stop = 1; + + // locate the stop at the shallower one of the + // gas change depth or the depth we came from + char_depth_sim = (sim_gas_current_depth < char_depth_last) ? + sim_gas_current_depth : char_depth_last; + + // calculate sim_pres_respiration for + // the adjusted value of char_depth_sim + calc_sim_pres_respiration(); + + // as we didn't travel the full distance, + // account for the gas change time only + tissue_increment = char_I_gas_change_time; + + // if run from the deco calculator, + // put the gas change into the stops table or + // abort deco calculation if the table is full + if( deco_status & DECO_CALCULATOR_MODE ) + if( !update_deco_table(tissue_increment) ) + next_planning_phase = PHASE_80_RESULTS; } - - // prime the deco stop with the gas change time - update_deco_table(char_I_gas_change_time); - } - - // add one minute to an existing stop or add a new stop at char_depth_sim, - // or abort stops calculation if the deco table is full - if( !update_deco_table(1) ) next_planning_phase = PHASE_70_RESULTS; + } // better gas + + + // if the stop is not a silent one, + // add the stop to an existing stop or add a new stop, + // or abort deco calculation if the deco table is full + if( !silent_stop ) + if( !update_deco_table(tissue_increment) ) + next_planning_phase = PHASE_80_RESULTS; + + + // shall calculate gas needs? + if( main_status & CALC_VOLUME ) + { + // encountered a stop, so switch to deco usage rate (SAC deco) + gas_needs_usage_rate = char_I_SAC_deco; + + // set the depth for gas need calculation to the shallower one + // of the start depth (current real depth) and the stop depth + // (assumed depth to be) as we may be shallower than we should be + gas_needs_depth = ( char_depth_sim_start < char_depth_sim ) ? + char_depth_sim_start : char_depth_sim; + + // did a gas change occur and last gas is 1-5 and a gas change time set? + if( gas_change && sim_gas_last_num && char_I_gas_change_time ) + { + // YES - set time it takes for switching the gas + gas_needs_time = char_I_gas_change_time; + + // calculate gas demand + calc_due_by_depth_time_sac(); + + // add the demand to the overall demand on the last gas + gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due; + } + + // current gas is 1-5 ? + if( sim_gas_current_num ) + { + // YES - time is 1 minute plus the gas change time (if set) + gas_needs_time = tissue_increment; + + // calculate gas demand + calc_due_by_depth_time_sac(); + + // add the demand to the overall demand on the current gas + gas_volume_need[sim_gas_current_num-1] += gas_needs_volume_due; + } + } // gas need } else { //---- no stop required ----------------- - // check if there is a better gas to switch to, but only: + // switch to a better gas, but only: // - // if extended stops are activated, - // OR if in bailout mode. + // if extended stops are activated OR if in bailout OR if within NDL + // AND if the actual depth is below (deeper) or at the change depth of the + // better gas (switch depth has not been passed yet) + // AND if the depth of the last stop is above (shallower) or at the change + // depth of the better gas (do not switch on final ascent) // - // Attention: do not use a && formula over both 'if' terms, the extended stops / bailout - // condition must be checked before a call to gas_find_better() is made! + // Attention: do not use a && formula over all 'if' terms, the + // conditions need to be evaluated in the given order! // - if( (main_status & EXTENDED_STOPS) || (deco_status & BAILOUT_MODE) ) - if( gas_find_better() ) + if( (main_status & EXTENDED_STOPS) || (deco_status & BAILOUT_MODE) || NDL_time ) + if( gas_find_best() ) + if( char_depth_real >= sim_gas_best_depth ) + if( char_I_depth_last_deco <= sim_gas_best_depth ) { + // YES - take the gas + gas_take_best(); + // set the new calculation values for N2, He and O2 gas_set_ratios(); - // stop duration is the gas change time, a change time of 0 minutes - // will set a tissue calculation interval of 2 seconds - tissue_increment += char_I_gas_change_time; - - // set char_depth_sim to the gas change depth, but not deeper than - // the depth we came from. - // (char_depth_last holds the depth from before the ascent step) - char_depth_sim = (sim_gas_current_depth < char_depth_last) ? sim_gas_current_depth : char_depth_last; - - // adjust sim_pres_respiration to the adjusted value of char_depth_sim - sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface; - - // create a stop for the gas change in the stops table - update_deco_table(char_I_gas_change_time); - } - } - - //---- one minute has passed by now, update the tissues ---------------- + // set char_depth_sim to the gas change depth + char_depth_sim = sim_gas_current_depth; + + // calculate sim_pres_respiration for + // the adjusted value of char_depth_sim + calc_sim_pres_respiration(); + + // as we didn't travel the full distance, + // account for the gas change time only + tissue_increment = char_I_gas_change_time; + + // if in deco and + // if run from the deco calculator: + // create a stop for the gas change in the stops table, + // abort deco calculation if the deco table is full + if( !NDL_time ) + if( deco_status & DECO_CALCULATOR_MODE ) + if( !update_deco_table(tissue_increment) ) + next_planning_phase = PHASE_80_RESULTS; + + // shall calculate gas needs and gas change time is set? + if( main_status & CALC_VOLUME ) + if( char_I_gas_change_time ) + { + // YES - set depth to current depth + gas_needs_depth = char_depth_sim; + + // set time it takes for switching the gas + gas_needs_time = tissue_increment; + + // calculate gas demand + calc_due_by_depth_time_sac(); + + // add gas demand to the overall demand on the new gas + gas_volume_need[sim_gas_current_num-1] += gas_needs_volume_due; + + // was the last gas one of the gases 1-5 ? + if( sim_gas_last_num ) + { + // YES - add the same demand to the overall demand on the last gas + gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due; + } + } // gas switching needs + } // gas switch + + // shall calculate gas needs and + // last (or still current) gas is 1-5 ? + if( main_status & CALC_VOLUME ) + if( sim_gas_last_num ) + { + // YES - compute distance traveled + gas_needs_depth = char_depth_last - char_depth_sim; + + // at least some positive distance traveled? + if( gas_needs_depth > 1 ) + { + // YES - set depth to average depth along the distance + gas_needs_depth += 1; + gas_needs_depth /= 2; + gas_needs_depth += char_depth_sim; + + // ascent time is 1 minute + gas_needs_time = 1; + + // calculate gas demand + calc_due_by_depth_time_sac(); + + // add to overall demand + gas_volume_need[sim_gas_last_num-1] += gas_needs_volume_due; + } + } // gas travel needs + + } // stop / no stop + + // --- one or more minutes have passed by now --- + + // update the ascent time + ascent_time += tissue_increment; // compute current ppO2, ppN2 and ppHe calc_alveolar_pressures(); @@ -2693,7 +2898,7 @@ calc_CNS(); // finish stops calculation if the surface is reached - if( char_depth_sim == 0 ) next_planning_phase = PHASE_70_RESULTS; + if( char_depth_sim == 0 ) next_planning_phase = PHASE_80_RESULTS; break; @@ -2701,20 +2906,29 @@ /// //--- Results - Initialization ------------------------------------------------------------ // - case PHASE_70_RESULTS: - - // The current depth is needed by calc_ascenttime(), find_NDL_gas_changes() and - // calc_gas_needs_ascent(). As we don't want it to be calculated multiple times, - // it is done here on stockpile. - char_depth_bottom = (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER + 0.5); + case PHASE_80_RESULTS: + + // convert the CNS value to integer + convert_sim_CNS_for_display(); + + if( deco_status & CALC_NORM ) + { + // export the integer CNS value + int_O_CNS_norm = int_sim_CNS_fraction; + } + else + { + // export the integer CNS value + int_O_CNS_alt = int_sim_CNS_fraction; + } // The next calculation phase will // - publish the stops table if in normal plan mode, // - proceed with remaining results dependent on if within NDL, or // - in deco - if ( deco_status & CALC_NORM ) next_planning_phase = PHASE_71_RESULTS_STOPS_TABLE; - else if ( NDL_time ) next_planning_phase = PHASE_72_RESULTS_NDL; - else next_planning_phase = PHASE_73_RESULTS_DECO; + if ( deco_status & CALC_NORM ) next_planning_phase = PHASE_81_RESULTS_STOPS_TABLE; + else if ( NDL_time ) next_planning_phase = PHASE_82_RESULTS_NDL; + else next_planning_phase = PHASE_83_RESULTS_DECO; break; @@ -2722,7 +2936,7 @@ /// //--- Publish Stops Table ----------------------------------------------------------------- // - case PHASE_71_RESULTS_STOPS_TABLE: + case PHASE_81_RESULTS_STOPS_TABLE: // publish the stops table to the display functions publish_deco_table(); @@ -2743,14 +2957,14 @@ } // update deco info vector - if( char_O_deco_depth[0] ) deco_info |= DECO_STOPS; // set flag for deco stops found + if( char_O_deco_depth[0] ) deco_info |= DECO_STOPS; // set flag for deco stops found else deco_info &= ~DECO_STOPS; // clear flag for deco stops found // The next calculation phase will publish the main results dependent on being // - within NDL, // - in deco. - if ( NDL_time ) next_planning_phase = PHASE_72_RESULTS_NDL; - else next_planning_phase = PHASE_73_RESULTS_DECO; + if ( NDL_time ) next_planning_phase = PHASE_82_RESULTS_NDL; + else next_planning_phase = PHASE_83_RESULTS_DECO; break; @@ -2758,7 +2972,7 @@ /// //--- Results - within NDL ---------------------------------------------------------------- // - case PHASE_72_RESULTS_NDL: + case PHASE_82_RESULTS_NDL: // results to publish depend on normal or alternative plan if( deco_status & CALC_NORM ) @@ -2768,9 +2982,6 @@ // clear the normal ascent time int_O_TTS_norm = 0; - - // as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now - int_O_CNS_norm = int_O_CNS_current; } else { @@ -2779,18 +2990,13 @@ // clear the alternative ascent time int_O_TTS_alt = 0; - - // as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now - int_O_CNS_alt = int_O_CNS_current; } // The next calculation phase will // - finish the calculation cycle if no gas needs calculation configured, else - // - find gas switches when in bailout mode (we are in NDL), or - // - calculate the gas needs along the ascent + // - calculate the gas needs pressures if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH; - else if ( (deco_status & BAILOUT_MODE) ) next_planning_phase = PHASE_80_GAS_NEEDS_SWITCHES; - else next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT; + else next_planning_phase = PHASE_84_GAS_NEEDS_PRESSURES; break; @@ -2798,13 +3004,13 @@ /// //--- Results - in Deco ------------------------------------------------------------------- // - case PHASE_73_RESULTS_DECO: - - // calculate the ascent time - calc_ascenttime(); - - // convert the CNS value to integer - convert_sim_CNS_for_display(); + case PHASE_83_RESULTS_DECO: + + // limit ascent time to display max. + if( ascent_time > 999) ascent_time = 999; + + // tag ascent time as invalid if there is an overflow in the stops table + if( deco_warnings & DECO_WARNING_INCOMPLETE ) ascent_time |= INT_FLAG_INVALID; // results to publish depend on normal or alternative plan if( deco_status & CALC_NORM ) @@ -2814,9 +3020,6 @@ // export the ascent time int_O_TTS_norm = ascent_time; - - // export the integer CNS value - int_O_CNS_norm = int_sim_CNS_fraction; } else { @@ -2825,54 +3028,21 @@ // export the ascent time int_O_TTS_alt = ascent_time; - - // export the integer CNS value - int_O_CNS_alt = int_sim_CNS_fraction; } // The next calculation phase will // - finish the calculation cycle if no gas needs calculation configured, else // - calculate the gas needs along the ascent if ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH; - else next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT; + else next_planning_phase = PHASE_84_GAS_NEEDS_PRESSURES; break; // - //--- Gas Needs - Switches ---------------------------------------------------------------- - // - case PHASE_80_GAS_NEEDS_SWITCHES: - - // When in bailout mode and within NDL, find the gas switches along the ascent and put - // them into the stops table. The stops table can be "polluted" by now because the table - // has already been published in "clean" state before. - find_NDL_gas_changes(); - - // the next calculation phase will calculate the gas needs along the ascent - next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT; - - break; - - + //--- Results - convert Gas Needs Volumes to Pressures ------------------------------------ // - //--- Gas Needs - calculate Ascent Needs using Data from Stop Table ----------------------- - // - case PHASE_81_GAS_NEEDS_ASCENT: - - // calculate the gas needs along the ascent - calc_gas_needs_ascent(); - - // if calculation has finished, advance to next calculation phase - if( gas_needs_next_phase == GAS_NEEDS_DONE ) next_planning_phase = PHASE_82_GAS_NEEDS_PRESSURES; - - break; - - - // - //--- Gas Needs - convert Volumes to Pressures -------------------------------------------- - // - case PHASE_82_GAS_NEEDS_PRESSURES: + case PHASE_84_GAS_NEEDS_PRESSURES: // convert required volume of the gas pointed to by gas_needs_gas_index // into the respective pressure and set the flags @@ -2897,8 +3067,8 @@ // thus BAILOUT_MODE must not be set while doing the alternative plan. if( (deco_status & CALC_ALT) && !(deco_status & BAILOUT_MODE) ) { - if ( int_O_TTS_alt <= int_O_TTS_norm ) deco_info |= DECO_ZONE; - else deco_info &= ~DECO_ZONE; + if( int_O_TTS_alt < int_O_TTS_norm ) deco_info |= DECO_ZONE; + if( int_O_TTS_alt > int_O_TTS_norm ) deco_info &= ~DECO_ZONE; } // export updated deco infos and warnings @@ -2992,6 +3162,14 @@ if( char_I_extra_time > 127 ) char_I_extra_time = 127; if( char_I_gas_change_time > 99 ) char_I_gas_change_time = 99; + + // compute the depth in meters where we are now + float_depth_real = (real_pres_respiration - pres_surface) * BAR_TO_METER; + + // convert to integer and round up to next full meter + char_depth_real = (unsigned char)(float_depth_real + 0.99); + + // calculate partial pressure of N2 in respired air at surface pressure calc_N2_equilibrium(); @@ -3033,50 +3211,6 @@ ////////////////////////////////////////////////////////////////////////////// -// Find gas changes on an NDL ascent -// -// This function is used for finding the gas changes in an OC bailout ascent -// that is within NDL. -// -// Input: char_depth_bottom depth at which the ascent starts, in meters -// -// Output: gas change stops put into stops table -// -// Destroyed: char_depth_sim -// sim_gas_current_num number of current gas -// sim_gas_current_depth change depth of current gas -// -void find_NDL_gas_changes(void) -{ - overlay unsigned char old_depth_limit; - - // set gas to start with - gas_find_current(); - - // loop in ascending until reaching a depth of 3 meters, no gas switches considered thereafter - for( char_depth_sim = char_depth_bottom; char_depth_sim >= 3; ) - { - // memorize the depth we came from - old_depth_limit = char_depth_sim; - - // ascent - initially in steps of 10 m, then slowing down to 1 m steps to not miss a O2 gas - if ( char_depth_sim > 10 ) char_depth_sim -= 10; - else char_depth_sim -= 1; - - // check if there is a better gas to switch to - if( gas_find_better() ) - { - // adjust char_depth_sim to the gas change depth, but not deeper than the depth we came from - char_depth_sim = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit; - - // create a stop for the gas change in the stops table - update_deco_table(char_I_gas_change_time); - } - } // for() -} - - -////////////////////////////////////////////////////////////////////////////// // calc_tissues // // INPUT: ppN2 partial pressure of inspired N2 @@ -3684,60 +3818,6 @@ ////////////////////////////////////////////////////////////////////////////// -// calc_ascenttime -// -// Sum up ascent from bottom to surface at char_I_ascent_speed, slowing down -// to 1 minute per meter for the final ascent when in deco, and all stop times. -// -// Input: char_I_depth_last_deco -// char_I_ascent_speed -// char_depth_bottom -// internal_deco_depth[] -// internal_deco_time[] -// -// Output: ascent_time -// -static void calc_ascenttime(void) -{ - // check if there are stops - if( internal_deco_depth[0] ) - { - // YES - stops / in deco - - // check if already at last stop depth or shallower - if( char_depth_bottom <= char_I_depth_last_deco) - { - // YES - final ascent part only - ascent_time = char_depth_bottom; - } - else - { - // NO - ascent part from bottom to last stop - ascent_time = (char_depth_bottom - char_I_depth_last_deco) / char_I_ascent_speed + 1; - - // - ascent part from last stop to surface at 1 meter per minute - ascent_time += char_I_depth_last_deco; - } - - // add all stop times - for( i=0; i < NUM_STOPS && internal_deco_depth[i]; i++ ) - ascent_time += internal_deco_time[i]; - - // limit result to display max. - if( ascent_time > 999) ascent_time = 999; - - // tag result as invalid if there is an overflow in the stops table - if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) ascent_time |= INT_FLAG_INVALID; - } - else - { - // NO - no stops / within NDL - ascent_time = char_depth_bottom / char_I_ascent_speed + 1; - } -} - - -////////////////////////////////////////////////////////////////////////////// // clear_deco_table // // Modified: internal_deco_time[] stop durations @@ -3753,8 +3833,12 @@ internal_deco_gas[i] = 0; } + // reset stop table index and chained stops counter + stop_index = 0; + chained_stops = 0; + // clear stop table overflow warning - deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW; + deco_warnings &= ~DECO_WARNING_INCOMPLETE; } @@ -3777,53 +3861,112 @@ // static unsigned char update_deco_table(PARAMETER unsigned char time_increment) { - overlay unsigned char x; - assert( char_depth_sim > 0 ); // no stop at surface - // loop through internal deco table - for( x = 0; x < NUM_STOPS; ++x ) + + // is there already a stop entry matching with the current depth and gas? + if( internal_deco_depth[stop_index] == char_depth_sim ) + if( internal_deco_gas [stop_index] == sim_gas_current_num ) { - // In case the first deco stop is to be placed deeper than previously recorded - // stops for gas changes during the initial ascent (this may happen because the - // deco stops are placed at the next deeper multiple of 3 meters instead of the - // real stop's depth), relocate the deco stop to the depth of the last gas change. - // The resulting combined stop's duration will be the sum of the configured gas - // change time plus the duration of the deco stop itself. - if( internal_deco_depth[x] && (char_depth_sim > internal_deco_depth[x]) ) - char_depth_sim = internal_deco_depth[x]; - - // Is there already a stop entry for our current depth? - if( internal_deco_depth[x] == char_depth_sim ) + // YES - increment stop time if possible, stop time entries are + // limited to 99 minutes because of display constraints + if( internal_deco_time[stop_index] < (100 - time_increment) ) { - // Yes - increment stop time if possible - // Stop time entries are limited to 99 minutes because of display constraints. - if( internal_deco_time[x] < (100 - time_increment) ) + // YES - time increment fits into current stop entry, + // increment stop time and return with status 'success' + internal_deco_time[stop_index] += time_increment; + return 1; + } + else + { + // NO - A chained stop entry will be created further down in the + // code to continue the stop, but we will limit the number + // of chained stop table entries in order to abort an ever- + // running deco calculation. Too many chained entries? + if( ++chained_stops >= STOP_CHAINING_LIMIT ) { - internal_deco_time[x] += time_increment; // increment stop time - return 1; // return with status 'success' + // YES - set overflow warning and return with status 'failed' + deco_warnings |= DECO_WARNING_INCOMPLETE; + return 0; } } - - // If program flow passes here, there is either no stop entry for the current depth yet, or - // the existing entry is saturated with 99 minutes. So we are looking for the next unused - // table entry. - if( internal_deco_depth[x] == 0 ) + } + + // the current stop entry does not match the current depth and gas, + // or hasn't enough room left for the time increment + + // is the current stop entry in use? + if( internal_deco_depth[stop_index] > 0 ) + { + // YES - current entry is in use, need to move on + // to next entry position if possible + + // have all entry positions been used up? + if( stop_index < (NUM_STOPS - 1) ) { - internal_deco_time[x] = time_increment; // initialize entry with first stop's time, - internal_deco_depth[x] = char_depth_sim; // ... depth, and - internal_deco_gas[x] = sim_gas_current_num; // ... gas - return 1; // return with status 'success' + // NO - move on to next entry position + stop_index += 1; + } + else + { + // YES - set overflow warning and return with status 'failed' + deco_warnings |= DECO_WARNING_INCOMPLETE; + return 0; } } - // If program flow passes here, all deco table entries are used up. - - // set overflow warning - deco_warnings |= DECO_WARNING_STOPTABLE_OVERFLOW; - - // return with status 'failed'. - return 0; + // initial use of a new (or the very first) stop entry, + // store all stop data and return with status 'success' + internal_deco_time [stop_index] = time_increment; + internal_deco_depth[stop_index] = char_depth_sim; + internal_deco_gas [stop_index] = sim_gas_current_num; + return 1; +} + + +////////////////////////////////////////////////////////////////////////////// +// publish_deco_table +// +// Input: internal_deco_depth[] depth in internal stops table +// internal_deco_time[] times ... +// internal_deco_gas[] gases ... +// +// Output: char_O_deco_depth[] depth in the external stops table +// char_O_deco_time[] times ... +// char_O_deco_gas[] gases ... +// char_O_deco_time_for_log times in reverse order +// +static void publish_deco_table(void) +{ + overlay unsigned char x = stop_index; + overlay unsigned char y; + + + // copy depth, time and gas from internal to external stops table + for( y = 0; y < NUM_STOPS; y++ ) + { + char_O_deco_depth[y] = internal_deco_depth[y]; + char_O_deco_time [y] = internal_deco_time [y]; + char_O_deco_gas [y] = internal_deco_gas [y]; + } + + // copy times of shallowest stops to logging table + for(y = 0; y < NUM_STOPS_LOG; x-- ) + { + // copy all stops that have a non-null stop time + if( internal_deco_time[x] ) + char_O_deco_time_for_log[y++] = internal_deco_time[x]; + + // abort if all stops are copied + if( x == 0) break; + } + + // fill the remainder of the logging table with null + // if it is not completely filled already + while( y < NUM_STOPS_LOG ) + { + char_O_deco_time_for_log[y++] = 0; + } } @@ -4301,6 +4444,9 @@ // calculate index for increment look-up cns_i = (char_ppO2 - 161) / 5; // integer division + // indexes > 17 use increment of index 17 + if( cns_i > 17 ) cns_i = 17; + // read coefficient (increment) read_CNS_c_coefficient(); @@ -4344,329 +4490,15 @@ // rate. It uses a fixed surface pressure of 1.0 bar to deliver stable results // when used through the deco calculator. // -// Input: gas_needs_float_depth depth in meters -// gas_needs_float_time time in minutes -// gas_needs_stop_usage gas usage in liters per minute at surface pressure +// Input: gas_needs_depth depth in meters +// gas_needs_time time in minutes +// gas_needs_usage_rate gas usage in liters per minute at surface pressure // -// Output: gas_needs_volume_due required gas volume in liters +// Output: gas_needs_volume_due required gas volume in liters // static void calc_due_by_depth_time_sac(void) { - gas_needs_volume_due = (gas_needs_float_depth * METER_TO_BAR + 1.0) * gas_needs_float_time * gas_needs_stop_usage; -} - - -////////////////////////////////////////////////////////////////////////////// -// calc_gas_needs_ascent -// -// calculates the gas needs along the ascent -// -// Input: char_depth_bottom depth of the bottom segment -// char_I_bottom_time duration of the bottom segment -// char_I_extra_time extra bottom time for fTTS / delayed ascent -// float_ascent_speed ascent speed, in meters/minute -// internal_deco_depth[] depth of the stops -// internal_deco_time[] duration of the stops -// internal_deco_gas[] gas breathed at the stops -// NDL_time remaining NDL time, used to adjust speed of final ascent -// char_I_SAC_work gas consumption during bottom part and initial ascent, in liters/minute -// char_I_SAC_deco gas consumption during stops and following ascents, in liters/minute -// char_I_gas_avail_size[] size of the tanks for gas 1-5, in liters -// char_I_gas_avail_pres[] fill pressure of the tanks -// -// Output: gas_volume_need[] amount of gas needed, in liters -// -static void calc_gas_needs_ascent(void) -{ - switch (gas_needs_next_phase) - { - //--------------------------------------------------------------------- - - case GAS_NEEDS_INIT: - - // set index to the first stop table entry - gas_needs_stop_index = 0; - - // clear the gas volume needs - for( i = 0; i < NUM_GAS; ++i ) gas_volume_need[i] = 0.0; - -#ifdef _rx_functions - // only for OSTC TR model with TR functions enabled - if( main_status & TR_FUNCTIONS ) - { - // invalidate pressure needs to pressure readings - int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL; - int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL; - } -#endif - - // terminate if in loop mode (CCR, pSCR) as there are no gas needs to calculate, - // else continue with the gas needs of the bottom segment - if ( deco_status & MODE_LOOP ) gas_needs_next_phase = GAS_NEEDS_DONE; - else gas_needs_next_phase = GAS_NEEDS_BOTTOM_SEGMENT; - - break; - - //--------------------------------------------------------------------- - - case GAS_NEEDS_BOTTOM_SEGMENT: - - // sim_gas_current_num gas used during bottom segment (0, 1-5) - // char_depth_bottom depth of the bottom segment - - // get the gas used during bottom segment - gas_find_current(); - - // initialize variables - gas_needs_stop_gas_last = gas_needs_stop_gas = sim_gas_current_num; - - // set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent - gas_needs_stop_usage = char_I_SAC_work; - - // volumes are only calculated for gases 1-5, but not the manually configured one - if( gas_needs_stop_gas ) - { - // set the bottom depth - gas_needs_float_depth = (float)char_depth_bottom; - - // calculate either whole bottom time or just the fTTS/bailout extra time - gas_needs_float_time = ( main_status & CALCULATE_BOTTOM ) ? (float)char_I_bottom_time : (float)char_I_extra_time; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // take result - gas_volume_need[gas_needs_stop_gas-1] = gas_needs_volume_due; - } - - // continue with initial ascent demand - gas_needs_next_phase = GAS_NEEDS_INITIAL_ASCENT; - - break; - - - //--------------------------------------------------------------------- - - case GAS_NEEDS_INITIAL_ASCENT: - - // gas_needs_stop_gas : gas from bottom segment - // char_depth_bottom : depth of the bottom segment - // internal_deco_depth[0]: depth of the first stop, may be 0 if no stop exists - - // get the data of the first stop - gas_needs_stop_depth = internal_deco_depth[0]; - gas_needs_stop_time = internal_deco_time[0]; - - // volumes are only calculated for gases 1-5, but not the manually configured one - if( gas_needs_stop_gas ) - { - // compute distance between bottom and first stop - gas_needs_float_depth = (float)char_depth_bottom - (float)gas_needs_stop_depth; - - // initial ascent exists only if ascent distance is > 0 - if( gas_needs_float_depth > 0.0 ) - { - // compute ascent time - gas_needs_float_time = gas_needs_float_depth / float_ascent_speed; - - // compute average depth between bottom and first stop - gas_needs_float_depth = (float)char_depth_bottom - gas_needs_float_depth * 0.5; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due; - } - } - - // switch the usage (SAC rate) to deco usage rate - // for stops, intermediate and final ascent - gas_needs_stop_usage = char_I_SAC_deco; - - // is there a (first) stop? - if( gas_needs_stop_depth ) - { - // YES - continue with stop demand - gas_needs_next_phase = GAS_NEEDS_STOP; - - break; - } - else - { - // NO - add demand of a 3 minutes safety stop at 5 meters, at least for contingency... - gas_needs_float_time = 3.0; - gas_needs_float_depth = 5.0; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due; - - // calculation finished - gas_needs_next_phase = GAS_NEEDS_DONE; - - break; - } - - - //--------------------------------------------------------------------- - - case GAS_NEEDS_STOP: - - // correct stop depth if shallower than calculated stop depth and convert to float - gas_needs_float_depth = ( char_depth_bottom < gas_needs_stop_depth ) ? (float)char_depth_bottom : (float)gas_needs_stop_depth; - - // get the gas on this stop - gas_needs_stop_gas = internal_deco_gas[gas_needs_stop_index]; - - // do we have a gas change? - if( gas_needs_stop_gas_last && (gas_needs_stop_gas != gas_needs_stop_gas_last) ) - { - // YES - spend an additional char_I_gas_change_time on the old gas - gas_needs_float_time = (float)char_I_gas_change_time; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due; - } - - // calculate demand of (new) gas for the full stop duration - if( gas_needs_stop_gas ) - { - // get the duration of the stop - gas_needs_float_time = (float)gas_needs_stop_time; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due; - } - - // Continue with the demand of the intermediate ascent to the next stop. - // If there is no further stop, it will divert by itself to final ascent. - gas_needs_next_phase = GAS_NEEDS_INTERMEDIATE_ASCENT; - - break; - - - //--------------------------------------------------------------------- - - case GAS_NEEDS_INTERMEDIATE_ASCENT: - - // store last stop depth and last gas - gas_needs_stop_depth_last = gas_needs_stop_depth; - gas_needs_stop_gas_last = gas_needs_stop_gas; - - // check if end of stop table is reached - if( gas_needs_stop_index < NUM_STOPS-1 ) - { - // NO - check if there is another stop entry - if( internal_deco_depth[gas_needs_stop_index+1] == 0 ) - { - // NO - continue with final ascent demand - gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT; - - break; - } - else - { - // YES - goto next stop entry - gas_needs_stop_index++; - - // get the depth of the next stop entry - gas_needs_stop_depth = internal_deco_depth[gas_needs_stop_index]; - - // get the duration of the next stop - gas_needs_stop_time = internal_deco_time[gas_needs_stop_index]; - } - } - else - { - // YES - end of stop table reached - // We are stranded at some stop depth and do not know how many more - // stops there may be in front of us and how long they may be. So as - // as last resort to calculate at least something, we assume that the - // rest of the ascent will be done in deco final ascent pace, i.e. at - // 1 meter per minute. Because of the stop table overflow, the result - // will be flagged as being invalid later on. - // - gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT; - - break; - } - - // volumes are only calculated for gases 1-5, but not the manually configured one - if( gas_needs_stop_gas_last ) - { - // compute distance between the two stops - gas_needs_float_depth = (float)(gas_needs_stop_depth_last - gas_needs_stop_depth); - - // compute ascent time - gas_needs_float_time = gas_needs_float_depth / float_ascent_speed; - - // compute average depth between the two stops - gas_needs_float_depth = (float)gas_needs_stop_depth_last - gas_needs_float_depth * 0.5; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due; - } - - // continue with calculation stop demand - gas_needs_next_phase = GAS_NEEDS_STOP; - - break; - - - //--------------------------------------------------------------------- - - case GAS_NEEDS_FINAL_ASCENT: - - // gas_needs_float_depth: still holds depth of the last stop - // gas_needs_stop_gas : still holds gas from last stop (0 or 1-5) - - // volumes are only calculated for gases 1-5, but not the manually configured one - if( gas_needs_stop_gas ) - { - // set ascent time dependent on deco status - if( NDL_time ) - { - // within NDL - ascent with float_ascent_speed - // - // Remark: When calculating a bailout ascent, there may be stops - // for gas changes although the dive is still within NDL - // and final ascent thus does not need to be slowed down. - gas_needs_float_time = gas_needs_float_depth / float_ascent_speed; - } - else - { - // in deco - reduce ascent speed to 1 meter per minute - gas_needs_float_time = gas_needs_float_depth; - } - - // set half-way depth - gas_needs_float_depth *= 0.5; - - // calculate gas demand - calc_due_by_depth_time_sac(); - - // add to overall demand - gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due; - } - - // calculation finished - gas_needs_next_phase = GAS_NEEDS_DONE; - - break; - - } // switch + gas_needs_volume_due = ((float)gas_needs_depth * METER_TO_BAR + pres_surface) * gas_needs_time * gas_needs_usage_rate; } @@ -4739,7 +4571,7 @@ pres_respiration_sac = real_pres_respiration; // set threshold for SAC rate attention - max_sac_rate = (deco_info & DECO_FLAG) ? char_I_SAC_deco : char_I_SAC_work; + max_sac_rate = (deco_info & DECO_MODE) ? char_I_SAC_deco : char_I_SAC_work; // char_I_SAC_deco / char_I_SAC_work are in l/min, max_sac_rate is in 0.1 l/min max_sac_rate *= 10; @@ -4823,6 +4655,19 @@ } + // select which pressure reading to log + if( char_I_SAC_mode == 1 ) int_O_tank_pressure = int_IO_pressure_value[0]; + else if( char_I_SAC_mode == 2 ) int_O_tank_pressure = int_IO_pressure_value[1]; + else int_O_tank_pressure = 0; + + // strip flags + int_O_tank_pressure &= 0x0FFF; + + // TODO: decide if log shall be in 0.1 bar of full bar only + // scale to full bar only + int_O_tank_pressure /= 10; + + // calculate SAC - modes 1 & 2 if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) ) { @@ -4925,7 +4770,7 @@ // set warning and attention thresholds int_pres_warn = 10.0 * (unsigned short)char_I_gas_avail_pres[i]; - int_pres_attn = GAS_NEEDS_ATTENTION_THRESHOLD * int_pres_warn; + int_pres_attn = GAS_NEEDS_LIMIT_ATTENTION * int_pres_warn; // convert ascent gas volume need from float to integer [in liter] int_O_gas_need_vol[i] = (unsigned short)gas_volume_need[i]; @@ -4943,7 +4788,7 @@ } // set invalid flag if there is an overflow in the stops table - if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_O_gas_need_pres[i] |= INT_FLAG_INVALID; + if( deco_warnings & DECO_WARNING_INCOMPLETE ) int_O_gas_need_pres[i] |= INT_FLAG_INVALID; #ifdef _rx_functions // only for OSTC TR model with TR functions enabled @@ -4965,7 +4810,7 @@ int_pres_need = (int_pres_need > 400) ? 4000 | INT_FLAG_OUT_OF_RANGE : 10 * int_pres_need; // tag as not available if there is an overflow in the stops table - if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_pres_need |= INT_FLAG_NOT_AVAIL; + if( deco_warnings & DECO_WARNING_INCOMPLETE ) int_pres_need |= INT_FLAG_NOT_AVAIL; // copy to reading data (in both readings the same gas could be configured) if( char_I_pressure_gas[0] == j ) int_O_pressure_need[0] = int_pres_need; @@ -4989,8 +4834,8 @@ float_value = CNS_fraction_real; convert_float_to_int(); int_O_CNS_current = int_value; // set warning & attention flags - if ( int_O_CNS_current >= CNS_WARNING_THRESHOLD ) int_O_CNS_current |= INT_FLAG_WARNING; - else if ( int_O_CNS_current >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_current |= INT_FLAG_ATTENTION; + if ( int_O_CNS_current >= CNS_LIMIT_WARNING ) int_O_CNS_current |= INT_FLAG_WARNING; + else if ( int_O_CNS_current >= CNS_LIMIT_ATTENTION ) int_O_CNS_current |= INT_FLAG_ATTENTION; } @@ -5009,11 +4854,11 @@ float_value = CNS_fraction_sim; convert_float_to_int(); int_sim_CNS_fraction = int_value; // set warning & attention flags - if ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_WARNING; - else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION; + if ( int_sim_CNS_fraction >= CNS_LIMIT_WARNING ) int_sim_CNS_fraction |= INT_FLAG_WARNING; + else if ( int_sim_CNS_fraction >= CNS_LIMIT_ATTENTION ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION; // set invalid flag if there is an overflow in the stops table - if ( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID; + if ( deco_warnings & DECO_WARNING_INCOMPLETE ) int_sim_CNS_fraction |= INT_FLAG_INVALID; } @@ -5060,7 +4905,7 @@ // // Input: ceiling minimum depth permitted in float // -// Output: int_O_ceiling minimum depth permitted in mbar +// Output: int_O_ceiling minimum depth permitted in mbar (cm) // // Modified: deco_info deco engine information vector // @@ -5070,9 +4915,11 @@ // Round up to next 10 cm so that the ceiling disappears only // when the ceiling limit is really zero. This will coincident // with TTS switching back to NDL time. + // The +1.5 term figures in the conversion factor of 10.015 m/bar + // which is used inside the deco engine but not outside of it. if ( ceiling <= 0.0 ) int_O_ceiling = 0; else if ( ceiling > 16.0 ) int_O_ceiling = 16000; - else int_O_ceiling = (unsigned short)(ceiling * 1000 + 9); + else int_O_ceiling = (unsigned short)(ceiling * (1000+1.5) + 9); // set/reset ceiling flag if ( int_O_ceiling ) deco_info |= DECO_CEILING;