comparison src/p2_deco.c @ 604:ca4556fb60b9

bump to 2.99beta, work on 3.00 stable
author heinrichsweikamp
date Thu, 22 Nov 2018 19:47:26 +0100
parents ab88a7e3de94
children d866684249bd
comparison
equal deleted inserted replaced
603:00b24fb4324d 604:ca4556fb60b9
1 // *************************************************************************** 1 // ***************************************************************************
2 // p2_deco.c REFACTORED VERSION V2.97 SP1 2 // p2_deco.c REFACTORED VERSION V2.99e
3 // 3 //
4 // Created on: 12.05.2009 4 // Created on: 12.05.2009
5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others 5 // Author: heinrichs weikamp, contributions by Ralph Lembcke and others
6 // 6 //
7 // *************************************************************************** 7 // ***************************************************************************
8 8
9 ////////////////////////////////////////////////////////////////////////////// 9 //////////////////////////////////////////////////////////////////////////////
10 // OSTC - diving computer code 10 // OSTC - diving computer code
11 // Copyright (C) 2011 HeinrichsWeikamp GbR 11 // Copyright (C) 2018 HeinrichsWeikamp GmbH
12 // 12 //
13 // This program is free software: you can redistribute it and/or modify 13 // This program is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by 14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or 15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version. 16 // (at your option) any later version.
72 // 2018/02/17: [rl] switch-over to new ceiling rounding (V2.98a) 72 // 2018/02/17: [rl] switch-over to new ceiling rounding (V2.98a)
73 // 73 //
74 // 74 //
75 // Literature: 75 // Literature:
76 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002]; 76 // Buhlmann, Albert: Tauchmedizin; 4. Auflage [2002];
77 // Schr"oder, Kai & Reith, Steffen; 2000; S"attigungsvorg"ange beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq 77 // Schroeder, Kai & Reith, Steffen; 2000; Saettigungsvorgaenge beim Tauchen, das Modell ZH-L16, Funktionsweise von Tauchcomputern; http://www.achim-und-kai.de/kai/tausim/saett_faq
78 // Morrison, Stuart; 2000; DIY DECOMPRESSION; http://www.lizardland.co.uk/DIYDeco.html 78 // Morrison, Stuart; 2000; DIY DECOMPRESSION; http://www.lizardland.co.uk/DIYDeco.html
79 // Balthasar, Steffen; Dekompressionstheorie I: Neo Haldane Modelle; http://www.txfreak.de/dekompressionstheorie_1.pdf 79 // Balthasar, Steffen; Dekompressionstheorie I: Neo Haldane Modelle; http://www.txfreak.de/dekompressionstheorie_1.pdf
80 // Baker, Erik C.; Clearing Up The Confusion About "Deep Stops" 80 // Baker, Erik C.; Clearing Up The Confusion About "Deep Stops"
81 // Baker, Erik C.; Understanding M-values; http://www.txfreak.de/understanding_m-values.pdf 81 // Baker, Erik C.; Understanding M-values; http://www.txfreak.de/understanding_m-values.pdf
82 // 82
83 // 83
84 84 // *********************************************************************************************************************************
85 // ********************* 85 //
86 // ** I N C L U D E S ** 86 // I N C L U D E S
87 // ********************* 87 //
88 #include <math.h> 88 // *********************************************************************************************************************************
89 89
90 // *********************************************** 90 #include <math.h>
91 // ** V A R I A B L E S D E F I N I T I O N S **
92 // ***********************************************
93
94 #include "p2_definitions.h" 91 #include "p2_definitions.h"
95 #define TEST_MAIN 92 #define TEST_MAIN
96 #include "shared_definitions.h" 93 #include "shared_definitions.h"
97 94
95
96 // *********************************************************************************************************************************
97 //
98 // C O N S T A N T S D E F I N I T I O N S
99 //
100 // *********************************************************************************************************************************
101
102 // conditional compiles
103 #define _rx_functions // if defined, compile transmitter functions (default: included *)
104 //#define _cave_mode // if defined, compile cave mode into firmware (default: not included *) ## OPTION IS UNDER CONSTRUCTION ##
105 // * option needs to be included / excluded in hwos.inc, too!
98 106
99 // ambient pressure at different mountain heights 107 // ambient pressure at different mountain heights
100 #define P_ambient_1000m 0.880 // [bar] based on 990 hPa and 20°C at sea level, 15°C at altitude 108 #define P_ambient_1000m 0.880 // [bar] based on 990 hPa and 20°C at sea level, 15°C at altitude
101 #define P_ambient_2000m 0.782 // [bar] 109 #define P_ambient_2000m 0.782 // [bar]
102 #define P_ambient_3000m 0.695 // [bar] 110 #define P_ambient_3000m 0.695 // [bar]
106 // 0.735 bar is a typical cabin pressure for nowadays commercial jet aircrafts 114 // 0.735 bar is a typical cabin pressure for nowadays commercial jet aircrafts
107 // ----- 115 // -----
108 // 0.135 bar safety margin 116 // 0.135 bar safety margin
109 117
110 // constants and factors 118 // constants and factors
111 #define ppWater 0.0627 // water vapor partial pressure in the lungs 119 #define ppWater 0.06270 // water vapor partial pressure in the lungs
112 #define METER_TO_BAR 0.09985 // conversion factor 120 #define METER_TO_BAR 0.09985 // conversion factor
113 #define BAR_TO_METER 10.0150 // conversion factor (1.0/METER_TO_BAR) 121 #define BAR_TO_METER 10.0150 // conversion factor (1.0/METER_TO_BAR)
114 #define SURFACE_DESAT_FACTOR 0.7042 // surface desaturation safety factor 122 #define SURFACE_DESAT_FACTOR 0.70420 // surface desaturation safety factor
115 #define HYST 1.0E-06 // threshold for tissue graphics on-gassing / off-gassing visualization 123 #define HYST 1.0E-06 // threshold for tissue graphics on-gassing / off-gassing visualization
116 124
125
117 // thresholds 126 // thresholds
118 #define GF_WARNING_THRESHOLD 100 // threshold for GF warning (attention threshold is current GF_high)
119 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning 127 #define CNS_WARNING_THRESHOLD 100 // threshold for CNS warning
120 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention 128 #define CNS_ATTENTION_THRESHOLD 70 // threshold for CNS attention
121 #define ppO2_ATTENTION_THRESHOLD 130 // threshold for ppO2 attention (thresholds for warnings come by options_table.asm)
122 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar] 129 #define ppO2_GAP_TO_SETPOINT 10 // gap between setpoint and max. ppO2 of the pure diluent [cbar]
123 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention 130 #define GAS_NEEDS_ATTENTION_THRESHOLD 0.70 // threshold for gas needs attention [1.00 = 100%]
124 131 #define PRESSURE_LIMIT_WARNING 200 // threshold for pressure reading warning : 20.0 bar
125 // deco engine states and modes - char_O_deco_status 132 #define PRESSURE_LIMIT_ATTENTION 500 // threshold for pressure reading attention: 50.0 bar
126 #define DECO_STATUS_MASK 0x03 133 #define O2_CONSUMPTION_LIMIT_ATTENTION 20 // threshold for O2 "SAC" attention: 2.0 l/min
127 #define DECO_STATUS_START 0x00 134
128 #define DECO_STATUS_FINISHED 0x00 135 // deco engine states and modes - char_O_main_status: controls current tissue and deco status calculation (as-is situation)
129 #define DECO_STATUS_STOPS 0x01 136 #define DECO_COMPLETED_NORM 0x01 // the calculation of a normal deco plan has just been completed
130 #define DECO_STATUS_RESULTS 0x02 137 #define DECO_COMPLETED_ALT 0x02 // the calculation of an alternative deco plan has just been completed
131 #define DECO_STATUS_INIT 0x03 138 //#define DECO_MODE_MASK 0x0C // mask for mode selection ==> current diving mode
132 139 //#define DECO_MODE_LOOP 0x04 // see below
133 #define DECO_MODE_MASK 0x0C 140 //#define DECO_MODE_CCR 0x04 // see below
134 #define DECO_MODE_LOOP 0x04 141 //#define DECO_MODE_PSCR 0x08 // see below
142
143 #define DECO_USE_Z_FACTOR 0x10 // =1: figure in Z factor when converting gas volumes <-> pressures
144 #define DECO_CAVE_MODE 0x20 // =1: activate ascent gas needs calculation under cave constraints
145 #define DECO_BOTTOM_CALCULATE 0x40 // =1: switch to deco calculator interface
146 #define DECO_TR_FUNCTIONS 0x80 // =1: activate TR functions (pressure reading) processing
147
148 // deco engine states and modes - char_O_deco_status: controls deco plan calculation (to-be scenario)
149 #define DECO_STATUS_MASK 0x03 // bit mask for values below
150 #define DECO_STATUS_START 0x00 // value commands the start of a new deco calculation cycle
151 #define DECO_STATUS_FINISHED 0x00 // value indicates completion of deco calculation
152 #define DECO_STATUS_STOPS 0x01 // value indicated calculation is ongoing, currently calculating the stops
153 #define DECO_STATUS_RESULTS 0x02 // value indicates calculation is ongoing, currently calculating the results
154 #define DECO_STATUS_INIT 0x03 // value to be set once for the first invocation at the begin of a new dive
155
156 #define DECO_MODE_MASK 0x0C // mask for mode selection ==> diving mode during ascent
157 #define DECO_MODE_LOOP 0x04 // =1: CCR (DECO_MODE_PSCR needs to be cleared) or pSCR mode
135 #define DECO_MODE_CCR 0x04 // to be used with == operator in combination with DECO_MODE_MASK only! 158 #define DECO_MODE_CCR 0x04 // to be used with == operator in combination with DECO_MODE_MASK only!
136 #define DECO_MODE_PSCR 0x08 159 #define DECO_MODE_PSCR 0x08 // =1: pSCR mode (DECO_MODE_LOOP needs to be set, too)
137 160
138 #define DECO_PLAN_ALTERNATE 0x10 161 #define DECO_PLAN_ALTERNATE 0x10 // =1: calculate the 2nd (alternative) deco plan
139 #define DECO_CNS_CALCULATE 0x20 162 #define DECO_BAILOUT_MODE 0x20 // =1: do a bailout calculation, i.e. allow gas switches before first deco stop
140 #define DECO_VOLUME_CALCULATE 0x40 163 #define DECO_VOLUME_CALCULATE 0x40 // =1: calculate ascent gas needs
141 #define DECO_ASCENT_DELAYED 0x80 164 #define DECO_ASCENT_DELAYED 0x80 // =1: calculate a delayed ascent (fTTS)
142 165
143 // deco engine states and modes - char_O_main_status 166 // deco engine warnings - char_O_deco_warnings
144 //#define DECO_MODE_MASK 0x0C 167 #define DECO_WARNING_IBCD 0x01 // IBCD occurring now
145 //#define DECO_MODE_LOOP 0x04 168 #define DECO_WARNING_IBCD_lock 0x02 // IBCD has occurred during the dive
146 //#define DECO_MODE_CCR 0x04 // to be used with == operator in combination with DECO_MODE_MASK only! 169 #define DECO_WARNING_MBUBBLES 0x04 // micro bubbles likely to develop now
147 //#define DECO_MODE_PSCR 0x08 170 #define DECO_WARNING_MBUBBLES_lock 0x08 // ditto, but sometime during the dive
148 #define DECO_GASCHANGE_OVRD 0x10 171 #define DECO_WARNING_OUTSIDE 0x10 // tissue pressures outside the Buhlmann model now
149 #define DECO_BOTTOM_CALCULATE 0x40 172 #define DECO_WARNING_OUTSIDE_lock 0x20 // tissue pressures outside the model sometime during the dive
150 173 #define DECO_ATTENTION_OUTSIDE 0x40 // tissue pressures are very close to the Buhlmann limit
151 // deco engine states and modes - tissue_increment 174 #define DECO_WARNING_STOPTABLE_OVERFLOW 0x80 // internal error: no more space in the deco stops table
175
176 // deco engine status (char_O_deco_info)
177 #define DECO_FLAG 0x01 // =1: deco ppO2 levels are permitted
178 #define IND_DOUBLE_SWITCH_FLAG 0x02 // =1: switch to other tank advice active
179 #define DECO_STEADY 0x04 // =1: fTTS = TTS (not updated when in bailout mode)
180 #define DECO_DECREASING 0x08 // =1: fTTS < TTS (not updated when in bailout mode)
181 #define DECO_CEILING 0x10 // =1: ceiling depth > 0
182 #define GAS_NEEDS_CAVE 0x20 // =1: indicated gas needs are calculated in cave mode
183
184 // deco engine control - tissue_increment
152 #define TIME_MASK 0x7F // (127 decimal, bits 0-6 set) 185 #define TIME_MASK 0x7F // (127 decimal, bits 0-6 set)
153 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 set) 186 #define TISSUE_FLAG 0x80 // (128 decimal, bit 7 set)
154 187
155 // deco engine warnings
156 #define DECO_WARNING_IBCD 0x01
157 #define DECO_WARNING_IBCD_lock 0x02
158 #define DECO_WARNING_MBUBBLES 0x04
159 #define DECO_WARNING_MBUBBLES_lock 0x08
160 #define DECO_WARNING_OUTSIDE 0x10
161 #define DECO_WARNING_OUTSIDE_lock 0x20
162 #define DECO_WARNING_STOPTABLE_OVERFLOW 0x40
163 #define DECO_FLAG 0x80
164 188
165 // flags used with integer numbers 189 // flags used with integer numbers
166 #define INT_FLAG_INVALID 0x0400 190 #define INT_FLAG_INVALID 0x0400 // =1: value not valid
167 #define INT_FLAG_ZERO 0x0800 191 #define INT_FLAG_ZERO 0x0800 // =1: value is zero
168 #define INT_FLAG_LOW 0x1000 192 #define INT_FLAG_LOW 0x1000 // =1: value is below a lower warning threshold
169 #define INT_FLAG_HIGH 0x2000 193 #define INT_FLAG_NOT_AVAIL 0x1000 // =1: value is not available (not computed)
170 #define INT_FLAG_ATTENTION 0x4000 194 #define INT_FLAG_HIGH 0x2000 // =1: value is above an upper warning threshold
171 #define INT_FLAG_WARNING 0x8000 195 #define INT_FLAG_OUTDATED 0x2000 // =1: value has not been updated for too long
172 196 #define INT_FLAG_ATTENTION 0x4000 // =1: value exceeds the attention threshold
173 197 #define INT_FLAG_WARNING 0x8000 // =1: value exceeds the warning threshold
174 198 #define INT_FLAG_OUT_OF_RANGE 0x8000 // =1: value exceeds presentable range
175 // ************************* 199
176 // ** P R O T O T Y P E S ** 200
177 // ************************* 201
178 202 // *********************************************************************************************************************************
179 static void calc_hauptroutine(void); 203 //
180 static void calc_hauptroutine_data_input(void); 204 // ** P R O T O T Y P E S **
181 static void calc_hauptroutine_calc_deco(void); 205 //
182 static void calc_alveolar_pressures(void); 206 // The Functions are listed in sequence of intended usage / application.
183 static void calc_tissues(void); 207 //
184 static void calc_NDL_time(void); 208 // *********************************************************************************************************************************
185 static void calc_ascenttime(void); 209
186 static void calc_CNS_increment(void); 210 // Functions used in surface mode
187 static void calc_desaturation_time(void); 211 static void calc_interval(PARAMETER unsigned char time_increment);
188 static void calc_ascent_to_first_stop(void); 212 // Calculates the tissue off-gassing under surface conditions.
189 static void calc_limit(PARAMETER float GF_current); 213 static void calc_desaturation_time(void); // Calculates the desaturation and no-fly times.
190 static void calc_interval(PARAMETER unsigned char time_increment); 214 static void clear_tissue(void); // Resets all tissues to surface pressure equilibrium state.
191 215
192 static void gas_find_current(void); 216 // Main entry point in dive mode
193 static void gas_set_ratios(void); 217 static void calc_hauptroutine(void); // Sequences all calculations for the real tissues and the deco calculation.
194 static void convert_CNS_for_display(void); 218
195 static void convert_sim_CNS_for_display(void); 219 // Functions dedicated to the real tissues
196 static void publish_deco_table(void); 220 static void calc_hauptroutine_data_input(void);// Initializes environment data and sets gas ratios for the real tissues.
197 static void clear_deco_table(void); 221
198 static void clear_tissue(void); 222 // Functions combined for real tissues & deco calculations
199 223 static void calc_alveolar_pressures(void); // Computes the partial pressures from the gas ratios and many more parameters,
200 static unsigned char calc_nextdecodepth(void); 224 // needs either calc_hauptroutine_data_input() be called beforehand or
201 static unsigned char gas_find_better(void); 225 // gas_find_current()/gas_find_better() and gas_set_ratios().
226 static void calc_tissues(void); // Updates the tissues dependent on the partial pressures of N2 and He.
227 static void calc_CNS(void); // Updates the CNS value dependent on the partial pressure of the O2.
228 static void calc_limit(PARAMETER float GF_current);
229 // Calculates ceiling, current GF (supersaturation) and some more data.
230
231 // Functions dedicated to deco calculations
232 static void clear_deco_table(void); // Clears the deco stops table, invoked at the start of each calculation cycle.
233 static void gas_find_current(void); // Sets the first gas used for deco calculation, invoked at start of cycle, too.
234 static unsigned char gas_find_better(void); // Checks for, and eventually switches to, a better gas.
235 static void gas_set_ratios(void); // Sets the gas ratios for use in deco calculation (simulated tissues),
236 // needs to be called after each gas change (gas_find_current/_better).
237 static void calc_NDL_time(void); // Calculates remaining NDL time.
238 static void find_NDL_gas_changes(void); // Finds the gas changes in an OC bailout ascent that is within NDL
239 static void calc_ascent_to_first_stop(void); // Calculates ascent to the first deco stop.
240 static void calc_hauptroutine_calc_deco(void); // Calculates the subsequent ascent until reaching surface.
241 static unsigned char calc_nextdecodepth(void); // Calculates the depth of the next required deco stop.
202 static unsigned char update_deco_table(PARAMETER unsigned char time_increment); 242 static unsigned char update_deco_table(PARAMETER unsigned char time_increment);
203 243 // Enters a new stop or extends an existing stop in the deco stops table.
244 static void calc_ascenttime(void); // Calculates the ascent time from current depth and deco stop times.
245 static void gas_volumes(void); // Calculates required gas volumes and pressures from the data in stops table.
246
247 // Functions for results reporting
248 static void publish_deco_table(void); // Copies the internal deco stops table to the export interface.
249 static void convert_CNS_for_display(void); // Converts the current CNS value from float to integer.
250 static void convert_sim_CNS_for_display(void); // Converts the end-of-dive CNS value from float to integer.
251 static void convert_GF_for_display(void); // Converts leading tissue supersaturation value from float to integer, 1.0 = 100%.
252 static void convert_ceiling_for_display(void); // Converts ceiling from float to integer in mbar relative pressure.
253
254
255 // internal helper functions
256 static unsigned short tmr5(void); // Reads a hardware timer which is used for preemptive scheduling.
257 static void read_Buhlmann_coefficients(void); // Reads the a and b coefficients from a ROM table.
258 static void read_Buhlmann_times(PARAMETER char period);
259 // Reads pre-computed tissue increment factors from a ROM table.
260 static void read_Buhlmann_ht(void); // Reads the half-times from a ROM table.
261 static void adopt_Buhlmann_coefficients(void); // Computes average a and b coefficient by the N2/He tissue ratio.
262 static void temp_tissue_safety(void); // Applies safety margins to the tissue increments.
263 static void push_tissues_to_vault(void); // Stores the state of the real tissues during simulator runs.
264 static void pull_tissues_from_vault(void); // Restores the state of the real tissues after a simulator run.
265
266
267
268 // *********************************************************************************************************************************
269 //
270 // V A R I A B L E S D E F I N I T I O N S
271 //
272 // *********************************************************************************************************************************
204 273
205 //---- Bank 5 parameters ----------------------------------------------------- 274 //---- Bank 5 parameters -----------------------------------------------------
206 #ifndef UNIX 275 #ifndef UNIX
207 # pragma udata bank5=0x500 276 # pragma udata bank5=0x500
208 #endif 277 #endif
209 278
210 // general deco parameters 279 // general deco parameters
211 280
212 static float GF_low; // initialized from deco parameters, constant during all computations 281 static float GF_low; // initialized from deco parameters
213 static float GF_high; // initialized from deco parameters, constant during all computations 282 static float GF_high; // initialized from deco parameters
214 static float GF_delta; // initialized from deco parameters, constant during all computations 283 static float GF_delta; // initialized from deco parameters
284
215 static float locked_GF_step_norm; // GF_delta / low_depth_norm in normal plan 285 static float locked_GF_step_norm; // GF_delta / low_depth_norm in normal plan
216 static float locked_GF_step_alt; // GF_delta / low_depth_alt in alternative plan 286 static float locked_GF_step_alt; // GF_delta / low_depth_alt in alternative plan
217 287
218 static float low_depth_norm; // Depth of deepest stop in normal plan 288 static float low_depth_norm; // depth of deepest stop in normal plan
219 static float low_depth_alt; // Depth of deepest stop in alternative plan 289 static float low_depth_alt; // depth of deepest stop in alternative plan
220 290
221 static float float_ascent_speed; // ascent speed from options_table (1.0 .. 10.0 m/min) 291 static float float_ascent_speed; // ascent speed from options_table (5.0 .. 10.0 m/min)
222 static float float_deco_distance; // additional depth below stop depth for tissue, CNS and gas volume calculation 292 static float float_deco_distance; // additional depth below stop depth for tissue, CNS and gas volume calculation
223 static float float_saturation_multiplier; // safety factor for on-gassing rates 293 static float float_saturation_multiplier; // safety factor for on-gassing rates
224 static float float_desaturation_multiplier; // safety factor for off-gassing rates 294 static float float_desaturation_multiplier; // safety factor for off-gassing rates
225 295
296 static unsigned char split_N2_He[NUM_COMP]; // used for calculating the desaturation time
297
226 // real context: what we are doing now 298 // real context: what we are doing now
227 299
228 static float ceiling; // minimum tolerated relative pressure (i.e. without surface pressue)
229 static float CNS_fraction; // current CNS (1.00 = 100%) 300 static float CNS_fraction; // current CNS (1.00 = 100%)
230 301
231 static unsigned short deco_tissue_vector; // 16 bit vector to memories all tissues that are in decompression 302 static unsigned short deco_tissue_vector; // 16 bit vector to memorize all tissues that are in decompression
232 static unsigned short IBCD_tissue_vector; // 16 bit vector to memories all tissues that experience IBCD 303 static unsigned short IBCD_tissue_vector; // 16 bit vector to memorize all tissues that experience IBCD
304
305 static float pres_respiration_sac; // current depth in absolute pressure, used in SAC calculation
306 static float float_sac; // used in SAC calculation
307 static unsigned int max_sac_rate; // used in SAC calculation to determine SAC rate attention
308
233 309
234 // simulation context: used to predict ascent 310 // simulation context: used to predict ascent
235 311
236 static float sim_ceiling; // minimum tolerated relative pressure (i.e. without surface pressue) 312 static float sim_CNS_fraction; // CNS after predicted ascent, 0.01 = 1%, as float
237 static float sim_CNS_fraction; // CNS increase during predicted ascent, 0.01 = 1% 313
238 314 static unsigned int int_sim_CNS_fraction; // CNS after predicted ascent, 1 = 1%, as integer
239 static unsigned int int_sim_CNS_fraction; // CNS increase during predicted ascent, in %
240 315
241 static unsigned char sim_depth_limit; // depth of next stop in meters, used in deco calculations 316 static unsigned char sim_depth_limit; // depth of next stop in meters, used in deco calculations
242 static unsigned char split_N2_He[NUM_COMP]; // used for calculating the desaturation time 317 static unsigned char NDL_lead_tissue; // used to cache the tissue to start with when calculating the NDL
243 static unsigned char NDL_lead_tissue; // used to cache tissue to start with calculating NDL 318
244 319
320 // result values from calculation functions
321
322 static float ceiling; // minimum tolerated relative pressure (i.e. without surface pressure)
323 static float lead_supersat; // supersaturation of the leading tissue, 1.0 = 100%
324 static unsigned char lead_number; // number of the leading tissue
245 325
246 // stops table 326 // stops table
247 327
248 static unsigned char internal_deco_depth[NUM_STOPS]; // depth of the stop 328 static unsigned char internal_deco_depth[NUM_STOPS]; // depths of the stops
249 static unsigned char internal_deco_time[NUM_STOPS]; // duration of the stop 329 static unsigned char internal_deco_time[NUM_STOPS]; // durations of the stops
250 static unsigned char internal_deco_gas[NUM_STOPS]; // gas used at the stop 330 static unsigned char internal_deco_gas[NUM_STOPS]; // gases used on the stops
251 331
252 332
253 // transfer variables between calc_desaturation_time() and calc_desaturation_time_helper() 333 // transfer variables between calc_desaturation_time() and calc_desaturation_time_helper()
254 334
255 static float desat_factor; // used to cache a pre-computed factor 335 static float desat_factor; // used to cache a pre-computed factor
257 static float pres_target; // target pressure for a compartment 337 static float pres_target; // target pressure for a compartment
258 static float pres_actual; // current pressure of the compartment 338 static float pres_actual; // current pressure of the compartment
259 static unsigned int int_time; // time it takes for the compartment to reach the target pressure 339 static unsigned int int_time; // time it takes for the compartment to reach the target pressure
260 340
261 341
262 // transfer variables between gas_volumes() and gas_volumes_helper() 342 // transfer variables between gas_volumes() and gas_volumes_helper_1/_2()
263 343
264 static float float_depth; // depth of the stop or half-way point 344 static float float_depth; // depth of the stop or half-way point
265 static float float_time; // duration of the stop or ascent phase 345 static float float_time; // duration of the stop or ascent phase
346 static unsigned char char_usage; // gas usage in l/min
347 static unsigned char gas_num; // number of the gas/tank
266 static float volume; // computed volume of gas 348 static float volume; // computed volume of gas
267 static unsigned char usage; // gas usage in l/min 349 static unsigned int int_volume; // required gas volume in liter
350 static unsigned int int_pres_need; // required gas volume in bar
268 351
269 352
270 // auxiliary variables for data buffering 353 // auxiliary variables for data buffering
271 354
272 static float N2_equilibrium; // used for N2 tissue graphics scaling 355 static float N2_equilibrium; // used for N2 tissue graphics scaling
273 static float temp_tissue; // auxiliary variable to buffer tissue pressures 356 static float temp_tissue; // auxiliary variable to buffer tissue pressures
274 static float float_pSCR_factor; // pre-computed factor for pSCR ppO2 drop calculation 357 static float float_pSCR_factor; // pre-computed factor for pSCR ppO2 drop calculation
275 358 static float calc_pres_tissue_N2; // auxiliary variable to buffer tissue N2 pressure
276 359 static float calc_pres_tissue_He; // auxiliary variable to buffer tissue He pressure
277 // 35 byte free space left in this bank (4 bytes per float, 2 bytes per int/short, 1 byte per char) 360 static float pres_tissue; // auxiliary variable to buffer total tissue pressure
361
362 // 11 byte free space left in this bank (4 bytes per float, 2 bytes per int/short, 1 byte per char)
278 363
279 364
280 //---- Bank 6 parameters ----------------------------------------------------- 365 //---- Bank 6 parameters -----------------------------------------------------
281 #ifndef UNIX 366 #ifndef UNIX
282 # pragma udata bank6=0x600 367 # pragma udata bank6=0x600
291 376
292 // environmental and gas data 377 // environmental and gas data
293 378
294 static float pres_surface; // absolute pressure at the surface 379 static float pres_surface; // absolute pressure at the surface
295 380
296 static unsigned char bottom_depth; // bottom depth in meters, used by CNS and gas needs calculation 381 static unsigned char char_bottom_depth; // bottom depth in meters, used by ascent time and gas needs calculation
297 382
298 static float pres_respiration; // current depth in absolute pressure 383 static float real_pres_respiration; // current real depth in absolute pressure
299 static float O2_ratio; // real breathed gas oxygen ratio 384 static float real_O2_ratio; // real breathed gas oxygen ratio
300 static float N2_ratio; // real breathed gas nitrogen ratio 385 static float real_N2_ratio; // real breathed gas nitrogen ratio
301 static float He_ratio; // real breathed gas helium ratio 386 static float real_He_ratio; // real breathed gas helium ratio
302 static float pSCR_drop; // real ppO2 drop in pSCR loop 387 static float real_pSCR_drop; // real ppO2 drop in pSCR loop
303 388
304 static float sim_pres_respiration; // simulated current depth in abs.pressure, used for deco calculations 389 static float sim_pres_respiration; // simulated current depth in abs.pressure, used for deco calculations
305 static float sim_O2_ratio; // simulated breathed gas oxygen ratio 390 static float sim_O2_ratio; // simulated breathed gas oxygen ratio
306 static float sim_N2_ratio; // simulated breathed gas nitrogen ratio 391 static float sim_N2_ratio; // simulated breathed gas nitrogen ratio
307 static float sim_He_ratio; // simulated breathed gas helium ratio 392 static float sim_He_ratio; // simulated breathed gas helium ratio
308 static float sim_pSCR_drop; // simulated ppO2 drop in pSCR loop 393 static float sim_pSCR_drop; // simulated ppO2 drop in pSCR loop
309 394
395
396 // result values from calculation functions
397
310 static float O2_ppO2; // ppO2 - calculated for pure oxygen at current depth 398 static float O2_ppO2; // ppO2 - calculated for pure oxygen at current depth
311 static float OC_ppO2; // ppO2 - calculated for breathed in OC mode 399 static float OC_ppO2; // ppO2 - calculated for breathing in OC mode
312 static float pSCR_ppO2; // ppO2 - calculated for breathed from pSCR loop 400 static float pSCR_ppO2; // ppO2 - calculated for breathing in pSCR mode
313 401
314 static float ppO2; // partial pressure of breathed oxygen 402 static float ppO2; // partial pressure of breathed oxygen
315 static float ppN2; // partial pressure of breathed nitrogen 403 static float ppN2; // partial pressure of breathed nitrogen
316 static float ppHe; // partial pressure of breathed helium 404 static float ppHe; // partial pressure of breathed helium
317
318
319 // Result values from calculation functions
320
321 static float CNS_fraction_inc; // increment of CNS load, 0.01 = 1%
322 405
323 static unsigned char char_ppO2; // partial pressure of breathed oxygen, as integer 100 = 1.00 bar 406 static unsigned char char_ppO2; // partial pressure of breathed oxygen, as integer 100 = 1.00 bar
324 static unsigned char NDL_time; // time in minutes until reaching NDL 407 static unsigned char NDL_time; // time in minutes until reaching NDL
325 static unsigned int ascent_time; // time in minutes needed for the ascent 408 static unsigned int ascent_time; // time in minutes needed for the ascent
326 409
331 static float var_N2_b; // Buhlmann b, for current N2 tissue 414 static float var_N2_b; // Buhlmann b, for current N2 tissue
332 static float var_He_a; // Buhlmann a, for current He tissue 415 static float var_He_a; // Buhlmann a, for current He tissue
333 static float var_He_b; // Buhlmann b, for current He tissue 416 static float var_He_b; // Buhlmann b, for current He tissue
334 static float var_N2_e; // exposition, for current N2 tissue 417 static float var_N2_e; // exposition, for current N2 tissue
335 static float var_He_e; // exposition, for current He tissue 418 static float var_He_e; // exposition, for current He tissue
336 static float var_N2_ht; // half-time for current N2 tissue 419 static float var_N2_ht; // half-time, for current N2 tissue
337 static float var_He_ht; // half-time for current N2 tissue 420 static float var_He_ht; // half-time, for current He tissue
338 421
339 422
340 // Gas switch history 423 // gas in use
341 424
342 static unsigned char sim_gas_first_used; // Number of first used gas, for bottom segment 425 static unsigned char sim_gas_current; // number of the currently used gas
343 static unsigned char sim_gas_last_used; // number of last used gas 426 static unsigned char sim_gas_current_depth; // change depth of the currently used gas
344 static unsigned char sim_gas_last_depth; // change depth of last used gas 427
345 428
346 429 // vault to back-up & restore tissue data
347 // Vault to back-up & restore tissue data
348 430
349 static float pres_tissue_N2_vault[NUM_COMP]; // stores the nitrogen tissue pressures 431 static float pres_tissue_N2_vault[NUM_COMP]; // stores the nitrogen tissue pressures
350 static float pres_tissue_He_vault[NUM_COMP]; // stores the helium tissue pressures 432 static float pres_tissue_He_vault[NUM_COMP]; // stores the helium tissue pressures
351 static float cns_vault_float; // stores current CNS (float representation) 433 static float cns_vault_float; // stores current CNS (float representation)
352 static unsigned char deco_warnings_vault; // stores warnings status 434 static unsigned char deco_warnings_vault; // stores warnings status
373 455
374 //---- Bank 8 parameters ----------------------------------------------------- 456 //---- Bank 8 parameters -----------------------------------------------------
375 #ifndef UNIX 457 #ifndef UNIX
376 # pragma udata overlay bank8=0x800 458 # pragma udata overlay bank8=0x800
377 459
378 static char md_pi_subst[256]; // Overlay C-code data stack here, too. 460 static char md_pi_subst[256]; // overlay C-code data stack here, too
379 461
380 # define C_STACK md_pi_subst 462 # define C_STACK md_pi_subst
381 #endif 463 #endif
382 464
383 465
386 #ifndef UNIX 468 #ifndef UNIX
387 # pragma udata bank6 469 # pragma udata bank6
388 #endif 470 #endif
389 471
390 472
391 ////////////////////////////////////////////////////////////////////////////// 473 // *********************************************************************************************************************************
392 ////////////////////////////////////////////////////////////////////////////// 474 //
393 //////////////// THE LOOKUP TABLES //////////////// 475 // L O O K - U P T A B L E S
394 ////////////////////////////////////////////////////////////////////////////// 476 //
395 ////////////////////////////////////////////////////////////////////////////// 477 // *********************************************************************************************************************************
396 478
397 #ifndef UNIX 479 #ifndef UNIX
398 # pragma romdata Buhlmann_tables = 0x1DD00 // Needs to be in UPPER bank. 480 # pragma romdata Buhlmann_tables = 0x1DD00 // needs to be in the UPPER bank
399 #endif 481 #endif
400 482
401 rom const float Buhlmann_ab[4*16] = { 483 rom const float Buhlmann_ab[4*16] = {
402 // Data ZH-L16C, from Bühlmann Tauchmedizin 2002, option 1a (4mn) 484 // Data ZH-L16C, from Bühlmann Tauchmedizin 2002, option 1a (4mn)
403 // a for N2 b for N2 a of He b for He 485 // a for N2 b for N2 a of He b for He
506 1.38222E-02, 3.61528E-02, 588 1.38222E-02, 3.61528E-02,
507 1.08563E-02, 2.84646E-02 589 1.08563E-02, 2.84646E-02
508 //------------------------------------- 590 //-------------------------------------
509 }; 591 };
510 592
511 ////////////////////////////////////////////////////////////////////////////// 593
512 ////////////////////////////////////////////////////////////////////////////// 594 // *********************************************************************************************************************************
513 //////////////// THE SUBROUTINES //////////////// 595 //
514 ////////////////////////////////////////////////////////////////////////////// 596 // H E L P E R F U N C T I O N S
515 ////////////////////////////////////////////////////////////////////////////// 597 //
516 // 598 // *********************************************************************************************************************************
517 // all new in v.102 599
600
518 // moved from 0x0D000 to 0x0C000 in v.108 601 // moved from 0x0D000 to 0x0C000 in v.108
519 #ifndef UNIX 602 #ifndef UNIX
520 # pragma code p2_deco = 0x0C000 603 # pragma code p2_deco = 0x0C000
521 #endif 604 #endif
522 605
523 //////////////////////////////////////////////////////////////////////////////
524 //////////////////////////////////////////////////////////////////////////////
525 //////////////// U T I L I T I E S ////////////////
526 //////////////////////////////////////////////////////////////////////////////
527 //////////////////////////////////////////////////////////////////////////////
528 606
529 ////////////////////////////////////////////////////////////////////////////// 607 //////////////////////////////////////////////////////////////////////////////
530 // Bump to blue-screen when an assert is wrong 608 // Bump to blue-screen when an assert is wrong
531 #ifdef __DEBUG 609 #ifdef __DEBUG
532 void assert_failed(PARAMETER short int line) 610 void assert_failed(PARAMETER short int line)
533 { 611 {
534 } 612 }
535 #endif 613 #endif
614
536 615
537 ////////////////////////////////////////////////////////////////////////////// 616 //////////////////////////////////////////////////////////////////////////////
538 // When calling C code from ASM context, the data stack pointer and 617 // When calling C code from ASM context, the data stack pointer and
539 // frames should be reset. Bank8 is used by stack 618 // frames should be reset. Bank8 is used by stack
540 619
544 # ifdef __DEBUG 623 # ifdef __DEBUG
545 # define RESET_C_STACK fillDataStack(); 624 # define RESET_C_STACK fillDataStack();
546 void fillDataStack(void) 625 void fillDataStack(void)
547 { 626 {
548 _asm 627 _asm
549 LFSR 1,C_STACK 628 LFSR 1,C_STACK
550 MOVLW 0xCC 629 MOVLW 0xCC
551 loop: MOVWF POSTINC1,0 630 loop: MOVWF POSTINC1,0
552 TSTFSZ FSR1L,0 631 TSTFSZ FSR1L,0
553 BRA loop 632 BRA loop
554 633
555 LFSR 1,C_STACK 634 LFSR 1,C_STACK
556 LFSR 2,C_STACK 635 LFSR 2,C_STACK
557 _endasm 636 _endasm
558 } 637 }
559 # else 638 # else
560 # define RESET_C_STACK \ 639 # define RESET_C_STACK \
561 _asm \ 640 _asm \
562 LFSR 1, C_STACK \ 641 LFSR 1,C_STACK \
563 LFSR 2, C_STACK \ 642 LFSR 2,C_STACK \
564 _endasm 643 _endasm
565 # endif 644 # endif
566 #endif 645 #endif
567 646
568 ////////////////////////////////////////////////////////////////////////////// 647
569 // Fast subroutine to read timer 5. 648 //////////////////////////////////////////////////////////////////////////////
570 // Note: result is in 1/32 of milliseconds (30,51757813 us/bit to be precise) 649 // Fast subroutine to read timer 5
650 // Note: result is in 1/32 of milliseconds (30.51757813 us/bit to be precise)
571 static unsigned short tmr5(void) 651 static unsigned short tmr5(void)
572 { 652 {
573 #ifndef CROSS_COMPILE 653 #ifndef CROSS_COMPILE
574 _asm 654 _asm
575 movff 0xf7c,PRODL // TMR5L 655 movff 0xf7c,PRODL // TMR5L
576 movff 0xf7d,PRODH // TMR5H 656 movff 0xf7d,PRODH // TMR5H
577 _endasm // result in PRODH:PRODL. 657 _endasm // result in PRODH:PRODL
578 #else 658 #else
579 return 0; 659 return 0;
580 #endif 660 #endif
581 } 661 }
582 662
583 ////////////////////////////////////////////////////////////////////////////// 663
584 // read Buhlmann tables A and B for compartment ci 664 //////////////////////////////////////////////////////////////////////////////
665 // read Buhlmann coefficients a and b for compartment ci
585 // 666 //
586 static void read_Buhlmann_coefficients(void) 667 static void read_Buhlmann_coefficients(void)
587 { 668 {
588 #ifndef CROSS_COMPILE 669 #ifndef CROSS_COMPILE
589 // Note: we don't use far rom pointer, because the 670 // Note: We don't use far ROM pointer, because handling
590 // 24 bits is too complex, hence we have to set 671 // 24 bit is too complex, hence we have to set the
591 // the UPPER page ourself... 672 // UPPER page ourself...
592 // --> Set zero if tables are moved to lower pages ! 673 // -> Set to zero if tables are moved to lower pages!
593 _asm 674 _asm
594 movlw 1 675 movlw 1
595 movwf TBLPTRU,0 676 movwf TBLPTRU,0
596 _endasm 677 _endasm
597 #endif 678 #endif
598 679
599 assert( ci < NUM_COMP ); 680 assert( ci < NUM_COMP );
600 681
601 // Use an interleaved array (AoS) to access coefficients with a 682 // use an interleaved array (AoS) to access coefficients with a single addressing
602 // single addressing.
603 { 683 {
604 overlay rom const float* ptr = &Buhlmann_ab[4*ci]; 684 overlay rom const float* ptr = &Buhlmann_ab[4*ci];
605 var_N2_a = *ptr++; 685 var_N2_a = *ptr++;
606 var_N2_b = *ptr++; 686 var_N2_b = *ptr++;
607 var_He_a = *ptr++; 687 var_He_a = *ptr++;
608 var_He_b = *ptr++; 688 var_He_b = *ptr++;
609 } 689 }
610 } 690 }
611 691
612 ////////////////////////////////////////////////////////////////////////////// 692
613 // read Buhlmann tables for compartment ci 693 //////////////////////////////////////////////////////////////////////////////
614 // If period == 0 : 2sec interval 694 // read Buhlmann increments for compartment ci
615 // 1 : 1 min interval 695 // If period == 0 : 2 sec interval
616 // 2 : 10 min interval. 696 // 1 : 1 min interval
697 // 2 : 10 min interval
617 static void read_Buhlmann_times(PARAMETER char period) 698 static void read_Buhlmann_times(PARAMETER char period)
618 { 699 {
619 #ifndef CROSS_COMPILE 700 #ifndef CROSS_COMPILE
620 // Note: we don't use far rom pointer, because the 701 // Note: We don't use far ROM pointer, because handling
621 // 24 bits is to complex, hence we have to set 702 // 24 bit is to complex, hence we have to set the
622 // the UPPER page ourself... 703 // UPPER page ourself...
623 // --> Set zero if tables are moved to lower pages! 704 // -> set to zero if tables are moved to lower pages!
624 _asm 705 _asm
625 movlw 1 706 movlw 1
626 movwf TBLPTRU,0 707 movwf TBLPTRU,0
627 _endasm 708 _endasm
628 #endif 709 #endif
629 710
630 assert( ci < NUM_COMP ); 711 assert( ci < NUM_COMP );
631 712
659 default: 740 default:
660 assert(0); // Never go there... 741 assert(0); // Never go there...
661 } 742 }
662 } 743 }
663 744
664 ////////////////////////////////////////////////////////////////////////////// 745
665 // read Buhlmann tables for compartment ci 746 //////////////////////////////////////////////////////////////////////////////
747 // read Buhlmann half-times for compartment ci
666 // 748 //
667 static void read_Buhlmann_ht(void) 749 static void read_Buhlmann_ht(void)
668 { 750 {
669 751
670 #ifndef CROSS_COMPILE 752 #ifndef CROSS_COMPILE
671 // Note: we don't use far rom pointer, because the 753 // Note: We don't use far ROM pointer, because handling
672 // 24 bits is to complex, hence we have to set 754 // 24 bit is to complex, hence we have to set the
673 // the UPPER page ourself... 755 // UPPER page ourself...
674 // --> Set zero if tables are moved to lower pages ! 756 // -> Set to zero if tables are moved to lower pages!
675 _asm 757 _asm
676 movlw 1 758 movlw 1
677 movwf TBLPTRU,0 759 movwf TBLPTRU,0
678 _endasm 760 _endasm
679 #endif 761 #endif
680 762
681 assert( ci < NUM_COMP ); 763 assert( ci < NUM_COMP );
682 { 764 {
683 overlay rom const float* ptr = &Buhlmann_ht[2*ci]; 765 overlay rom const float* ptr = &Buhlmann_ht[2*ci];
684 var_N2_ht = *ptr++; 766 var_N2_ht = *ptr++;
685 var_He_ht = *ptr++; 767 var_He_ht = *ptr++;
686 } 768 }
687 769
688 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 ); 770 assert( 4.0 <= var_N2_ht && var_N2_ht <= 635.0 );
689 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 ); 771 assert( 1.5099 <= var_He_ht && var_He_ht <= 240.03 );
690 } 772 }
691 773
692 ////////////////////////////////////////////////////////////////////////////// 774
693 ////////////////////////////////////////////////////////////////////////////// 775 //////////////////////////////////////////////////////////////////////////////
694 //////////////// THE JUMP-IN CODE for the asm code //////////////// 776 // compute adopted Buhlmann coefficients
695 ////////////////////////////////////////////////////////////////////////////// 777 //
696 ////////////////////////////////////////////////////////////////////////////// 778 static void adopt_Buhlmann_coefficients(void)
779 {
780 // adopt a and b coefficients to current N2/He ratio inside the tissue
781 var_N2_a = (var_N2_a * calc_pres_tissue_N2 + var_He_a * calc_pres_tissue_He) / pres_tissue;
782 var_N2_b = (var_N2_b * calc_pres_tissue_N2 + var_He_b * calc_pres_tissue_He) / pres_tissue;
783 }
784
785
786 // *********************************************************************************************************************************
787 //
788 // J U M P I N F U N C T I O N S
789 //
790 // *********************************************************************************************************************************
791
697 792
698 ////////////////////////////////////////////////////////////////////////////// 793 //////////////////////////////////////////////////////////////////////////////
699 // deco_calc_hauptroutine 794 // deco_calc_hauptroutine
700 // 795 //
701 // called from: divemode.asm 796 // called from: divemode.asm
733 ////////////////////////////////////////////////////////////////////////////// 828 //////////////////////////////////////////////////////////////////////////////
734 // deco_calc_dive_interval 829 // deco_calc_dive_interval
735 // 830 //
736 // called from: simulator.asm 831 // called from: simulator.asm
737 // 832 //
738 // Updates tissues and CNS value for char_I_dive_interval minutes on Air 833 // Updates tissues and CNS value for char_I_dive_interval minutes on air
739 // at ambient pressure and calculates resulting GF factor and ceiling for 834 // at ambient pressure and calculates resulting GF factor and ceiling for
740 // a GF-high of 100% (ceiling and GF factor not used by simulator.asm) 835 // a GF-high of 100% (ceiling and GF factor not used by simulator.asm)
741 // 836 //
742 void deco_calc_dive_interval(void) 837 void deco_calc_dive_interval(void)
743 { 838 {
752 // sleepmode.asm 847 // sleepmode.asm
753 // surfmode.asm 848 // surfmode.asm
754 // menu_tree.asm 849 // menu_tree.asm
755 // ghostwriter.asm 850 // ghostwriter.asm
756 // 851 //
757 // Updates tissues and CNS value for 1 minute on Air at ambient pressure and 852 // Updates tissues and CNS value for 1 minute on air at ambient pressure and
758 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling 853 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling
759 // is not used by *.asm files). 854 // is not used by *.asm files).
760 // 855 //
761 void deco_calc_dive_interval_1min(void) 856 void deco_calc_dive_interval_1min(void)
762 { 857 {
764 calc_interval(1); 859 calc_interval(1);
765 } 860 }
766 861
767 862
768 ////////////////////////////////////////////////////////////////////////////// 863 //////////////////////////////////////////////////////////////////////////////
769 // deco_calc_dive_interval_1min 864 // deco_calc_dive_interval_10min
770 // 865 //
771 // called from: sleepmode.asm 866 // called from: sleepmode.asm
772 // 867 //
773 // Updates tissues and CNS value for 10 minutes on Air at ambient pressure and 868 // Updates tissues and CNS value for 10 minutes on air at ambient pressure and
774 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling 869 // calculates resulting GF factor and ceiling for a GF-high of 100% (ceiling
775 // is not used by sleepmode.asm). 870 // is not used by sleepmode.asm).
776 // 871 //
777 void deco_calc_dive_interval_10min(void) 872 void deco_calc_dive_interval_10min(void)
778 { 873 {
822 { 917 {
823 RESET_C_STACK 918 RESET_C_STACK
824 pull_tissues_from_vault(); 919 pull_tissues_from_vault();
825 } 920 }
826 921
827 ////////////////////////////////////////////////////////////////////////////// 922
828 ////////////////////////////////////////////////////////////////////////////// 923 // *********************************************************************************************************************************
829 //////////////// THE FUNCTIONS //////////////// 924 //
830 ////////////////////////////////////////////////////////////////////////////// 925 // M A I N F U N C T I O N S
831 ////////////////////////////////////////////////////////////////////////////// 926 //
927 // *********************************************************************************************************************************
832 928
833 929
834 ////////////////////////////////////////////////////////////////////////////// 930 //////////////////////////////////////////////////////////////////////////////
835 // calc_nextdecodepth 931 // calc_nextdecodepth
836 // 932 //
837 // new in v.102
838 //
839 // INPUT, changing during dive: 933 // INPUT, changing during dive:
840 // sim_pres_respiration : current depth in absolute pressure 934 // sim_pres_respiration : current depth in absolute pressure
841 // 935 //
842 // INPUT, fixed during dive: 936 // INPUT, fixed during dive:
843 // pres_surface 937 // pres_surface
844 // GF_delta 938 // GF_delta
845 // GF_high 939 // GF_high
846 // GF_low 940 // GF_low
847 // char_I_depth_last_deco 941 // char_I_depth_last_deco
848 // 942 //
849 // MODIFIED 943 // MODIFIED
850 // locked_GF_step_norm/_alt : used for GF model 944 // locked_GF_step_norm/_alt : used for GF model
851 // low_depth_norm/_alt : used for GF model 945 // low_depth_norm/_alt : used for GF model
852 // 946 //
853 // OUTPUT 947 // OUTPUT
854 // sim_depth_limit : depth of next stop in meters (if RETURN == true ) 948 // sim_depth_limit : depth of next stop in meters (if RETURN == true )
855 // depth we can ascent to without stop (if RETURN == false) 949 // next possible depth without stop (if RETURN == false)
856 // 950 //
857 // RETURN TRUE if a stop is needed. 951 // RETURN TRUE if a stop is needed, else false
858 // 952 //
859 static unsigned char calc_nextdecodepth(void) 953 static unsigned char calc_nextdecodepth(void)
860 { 954 {
861 overlay unsigned char need_stop; 955 overlay unsigned char need_stop;
862 956
865 959
866 // compute depth in meters after 1 minute of ascent at float_ascent_speed (5..10 m/min) 960 // compute depth in meters after 1 minute of ascent at float_ascent_speed (5..10 m/min)
867 overlay float min_depth = (depth > float_ascent_speed) ? (depth - float_ascent_speed) : 0.0; 961 overlay float min_depth = (depth > float_ascent_speed) ? (depth - float_ascent_speed) : 0.0;
868 962
869 963
870 // allow for 200mbar of weather dependent surface pressure change 964 // target the simulated tissues
871 assert( depth >= -0.2 ); 965 tissue_increment = 0;
872
873 966
874 //---- check if a stop is needed for deco reasons ---------------------------- 967 //---- check if a stop is needed for deco reasons ----------------------------
875 968
876 // switch on deco model 969 // switch on deco model
877 if( char_I_deco_model != 0 ) 970 if( char_I_deco_model != 0 )
887 980
888 // calculate minimum depth we can ascent to in bar relative pressure 981 // calculate minimum depth we can ascent to in bar relative pressure
889 calc_limit(GF_low); 982 calc_limit(GF_low);
890 983
891 // check if we can surface directly 984 // check if we can surface directly
892 if( sim_ceiling <= 0.0 ) 985 if( ceiling <= 0.0 )
893 { 986 {
894 min_depth = 0.0; // set minimum depth to 0 meters = surface 987 min_depth = 0.0; // set minimum depth to 0 meters = surface
895 goto no_deco_stop; // done. 988 goto no_deco_stop; // done
896 } 989 }
897 990
898 // convert minimum depth we can ascent to from relative pressure to depth in meters 991 // convert minimum depth we can ascent to from relative pressure to depth in meters
899 limit_depth = sim_ceiling * BAR_TO_METER; 992 limit_depth = ceiling * BAR_TO_METER;
900 993
901 // recall low_depth dependent on current plan 994 // recall low_depth dependent on current plan
902 low_depth = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? low_depth_alt : low_depth_norm; 995 low_depth = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? low_depth_alt : low_depth_norm;
903 996
904 // Store the deepest point needing a deco stop as the LOW reference for GF. 997 // Store the deepest point needing a deco stop as the LOW reference for GF.
905 // NOTE: following stops will be validated using this LOW-HIGH GF scale, 998 // NOTE: following stops will be validated using this LOW-HIGH GF scale,
906 // so if we want to keep coherency, we should not validate this stop 999 // so if we want to keep coherency, we should not validate this stop
907 // yet, but apply the search to it, as for all the following stops afterward. 1000 // yet, but apply the search to it, as for all the following stops afterward.
908 if( limit_depth > low_depth ) 1001 if( limit_depth > low_depth )
923 locked_GF_step_norm = locked_GF_step; 1016 locked_GF_step_norm = locked_GF_step;
924 } 1017 }
925 } 1018 }
926 else 1019 else
927 { 1020 {
928 // recall locked_GF_step dependent on current plan 1021 // recall locked_GF_step dependent of current plan
929 locked_GF_step = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? locked_GF_step_alt : locked_GF_step_norm; 1022 locked_GF_step = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? locked_GF_step_alt : locked_GF_step_norm;
930 } 1023 }
931 1024
932 // invalidate this stop if we can ascent for 1 minute without going above minimum required deco depth 1025 // invalidate this stop if we can ascent for 1 minute without going above minimum required deco depth
933 if( limit_depth < min_depth ) goto no_deco_stop; 1026 if( limit_depth < min_depth ) goto no_deco_stop;
934 1027
935 1028
936 // if program execution passes here, we need a deco stop 1029 //---- if program execution passes here, we need a deco stop --------------------------------
937 1030
938 // Round to multiple of 3 meters 1031 // round to multiple of 3 meters (limit depth is in meters of depth)
939 first_stop = 3 * (unsigned char)(0.9995 + limit_depth * 0.333333); 1032 first_stop = 3 * (unsigned char)(0.4999 + limit_depth * 0.333333);
940 1033
941 // check a constraint 1034 // check a constraint
942 assert( first_stop < 128 ); 1035 assert( first_stop < 128 );
943 1036
944 // apply correction for the shallowest stop, use char_I_depth_last_deco (3..6 m) instead 1037 // apply correction for the shallowest stop, use char_I_depth_last_deco (3..6 m) instead
945 if( first_stop == 3 ) first_stop = char_I_depth_last_deco; 1038 if( first_stop == 3 ) first_stop = char_I_depth_last_deco;
946 1039
947 // We have a stop candidate. 1040 // We have a stop candidate.
948 // But maybe ascending to the next stop will diminish the constraint, 1041 // But maybe ascending to the next stop will diminish the constraint,
949 // because the GF might decrease more than the pressure gradient... 1042 // because the GF might decrease more than the pressure gradient...
950 while(first_stop > 0) 1043 while( first_stop > 0 )
951 { 1044 {
952 // Next depth 1045 // next depth
953 overlay unsigned char next_stop; 1046 overlay unsigned char next_stop;
954 1047
955 // invalidate this stop if we can ascent one more minute without going above minimum required deco depth 1048 // invalidate this stop if we can ascent one more minute without going above minimum required deco depth
956 if( first_stop <= (unsigned char)min_depth ) goto no_deco_stop; 1049 if( first_stop <= (unsigned char)min_depth ) goto no_deco_stop;
957 1050
963 // compute limit with the GF of the new stop candidate 1056 // compute limit with the GF of the new stop candidate
964 if( (low_depth == 0.0) || (next_stop > low_depth) ) calc_limit(GF_low); 1057 if( (low_depth == 0.0) || (next_stop > low_depth) ) calc_limit(GF_low);
965 else calc_limit(GF_high - next_stop * locked_GF_step); 1058 else calc_limit(GF_high - next_stop * locked_GF_step);
966 1059
967 // check if ascent to the next stop candidate is possible 1060 // check if ascent to the next stop candidate is possible
968 if( sim_ceiling * BAR_TO_METER >= next_stop ) goto deco_stop_found; // no - ascent to next_stop forbidden 1061 if( ceiling * BAR_TO_METER >= next_stop )
1062 goto deco_stop_found; // no - ascent to next_stop forbidden
969 1063
970 // else, validate that stop and loop... 1064 // else, validate that stop and loop...
971 first_stop = next_stop; 1065 first_stop = next_stop;
972 } 1066 }
973 1067
992 1086
993 // calculate minimum depth we can ascent to in bar relative pressure 1087 // calculate minimum depth we can ascent to in bar relative pressure
994 calc_limit(1.0); 1088 calc_limit(1.0);
995 1089
996 // check if we can surface directly 1090 // check if we can surface directly
997 if (sim_ceiling >= 0) 1091 if( ceiling >= 0 )
998 { 1092 {
999 // no - set flag for stop needed to 'yes' 1093 // no - set flag for stop needed to 'yes'
1000 need_stop = 1; 1094 need_stop = 1;
1001 1095
1002 // convert stop depth in relative pressure to stop index 1096 // convert stop depth in relative pressure to stop index
1003 limit_depth = sim_ceiling * BAR_TO_METER / 3; 1097 limit_depth = ceiling * BAR_TO_METER / 3.0;
1004 1098
1005 // convert stop index to depth in meters, rounded to multiple of 3 meters 1099 // convert stop index to depth in meters, rounded to multiple of 3 meters
1006 sim_depth_limit = 3 * (short)(limit_depth + 0.99); 1100 sim_depth_limit = 3 * (short)(limit_depth + 0.99);
1007 1101
1008 // correct last stop to 4m/5m/6m 1102 // correct last stop to 4m/5m/6m
1016 // set depth we can ascent to as 0 = surface 1110 // set depth we can ascent to as 0 = surface
1017 sim_depth_limit = 0; 1111 sim_depth_limit = 0;
1018 } 1112 }
1019 } 1113 }
1020 1114
1021 // After the first deco stop, gas changes are only done at deco stops now! 1115 // ---- After the first deco stop, gas changes are only done at deco stops now! -----------------------
1022 1116
1023 // check if a stop is found and there is a better gas to switch to 1117 // check if a stop is found and there is a better gas to switch to
1024 if( need_stop ) 1118 if( need_stop )
1025 if( gas_find_better() ) 1119 if( gas_find_better() )
1026 { 1120 {
1027 // set the new calculation ratios for N2, He and O2 1121 // set the new calculation ratios for N2, He and O2
1028 gas_set_ratios(); 1122 gas_set_ratios();
1029 1123
1030 // prime the deco stop with the gas change time 1124 // prime the deco stop with the gas change time
1031 update_deco_table(char_I_gas_change_time); 1125 update_deco_table(char_I_gas_change_time);
1032 } 1126 }
1033 1127
1034 return need_stop; 1128 return need_stop;
1035 } 1129 }
1130
1036 1131
1037 ////////////////////////////////////////////////////////////////////////////// 1132 //////////////////////////////////////////////////////////////////////////////
1038 // publish_deco_table 1133 // publish_deco_table
1039 // 1134 //
1040 // Buffer the stops, once computed, so we can continue to display them 1135 // Buffer the stops, once computed, so we can continue to display them
1048 // Copy depth of the first (deepest) stop, because when reversing 1143 // Copy depth of the first (deepest) stop, because when reversing
1049 // order, it will be hard to find... 1144 // order, it will be hard to find...
1050 char_O_first_deco_depth = internal_deco_depth[0]; 1145 char_O_first_deco_depth = internal_deco_depth[0];
1051 char_O_first_deco_time = internal_deco_time [0]; 1146 char_O_first_deco_time = internal_deco_time [0];
1052 1147
1053 for(x=0; x<NUM_STOPS; x++) 1148 for( x = 0; x < NUM_STOPS; x++ )
1054 { 1149 {
1055 char_O_deco_depth[x] = internal_deco_depth[x]; 1150 char_O_deco_depth[x] = internal_deco_depth[x];
1056 char_O_deco_time [x] = internal_deco_time [x]; 1151 char_O_deco_time [x] = internal_deco_time [x];
1057 char_O_deco_gas [x] = internal_deco_gas [x]; 1152 char_O_deco_gas [x] = internal_deco_gas [x];
1058 } 1153 }
1059 1154
1060 //Now fill the char_O_deco_time_for_log array 1155 // Now fill the char_O_deco_time_for_log array
1061 //---- First: search the first non-null depth 1156 // ---- First: search the first non-null depth
1062 for(x=(NUM_STOPS-1); x != 0; --x) 1157 for( x = (NUM_STOPS-1); x != 0; --x )
1063 if( internal_deco_depth[x] != 0 ) break; 1158 if( internal_deco_depth[x] != 0 ) break;
1064 1159
1065 //---- Second: copy to output table (in reverse order) 1160 //---- Second: copy to output table (in reverse order)
1066 for(y=0; y<NUM_STOPS; y++, --x) 1161 for( y = 0; y < NUM_STOPS; y++, --x )
1067 { 1162 {
1068 char_O_deco_time_for_log[y] = internal_deco_time [x]; 1163 char_O_deco_time_for_log[y] = internal_deco_time [x];
1069 1164
1070 // Stop only once the last transfer is done. 1165 // Stop when the last transfer is done.
1071 if( x == 0 ) break; 1166 if( x == 0 ) break;
1072 } 1167 }
1073 1168
1074 //---- Third: fill table with null until end 1169 //---- Third: fill table with null until end
1075 for(y++; y<NUM_STOPS; y++) 1170 for( y++; y < NUM_STOPS; y++ )
1076 char_O_deco_time_for_log[y] = 0; 1171 char_O_deco_time_for_log[y] = 0;
1077 } 1172 }
1173
1078 1174
1079 ////////////////////////////////////////////////////////////////////////////// 1175 //////////////////////////////////////////////////////////////////////////////
1080 // temp_tissue_safety 1176 // temp_tissue_safety
1081 // 1177 //
1082 // outsourced in v.102 1178 // outsourced in v.102
1091 if( temp_tissue < 0.0 ) temp_tissue *= float_desaturation_multiplier; 1187 if( temp_tissue < 0.0 ) temp_tissue *= float_desaturation_multiplier;
1092 else temp_tissue *= float_saturation_multiplier; 1188 else temp_tissue *= float_saturation_multiplier;
1093 } 1189 }
1094 1190
1095 1191
1096
1097 ////////////////////////////////////////////////////////////////////////////// 1192 //////////////////////////////////////////////////////////////////////////////
1098 // Find current gas in the list (if any) and get its change depth 1193 // Find current gas in the list (if any) and get its change depth
1099 // 1194 //
1100 // Input: char_I_current_gas : 1..5 or 6 1195 // Input: char_I_current_gas : 1..5 or 6
1101 // 1196 //
1102 // Output: sim_gas_last_used : 1..6 or 0 if it is the gas set as FIRST 1197 // Output: sim_gas_current : 1..6 or 0 for the manually configured gas/dil
1103 // sim_gas_last_depth : change depth in meters or 0 if it is the gas set as FIRST 1198 // sim_gas_current_depth : change depth (MOD) of the gas/dil in meters
1104 // 1199 //
1105 static void gas_find_current(void) 1200 static void gas_find_current(void)
1106 { 1201 {
1107 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 ); 1202 assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 );
1108 1203
1109 if( char_I_current_gas <= NUM_GAS ) // Gas 1-5 1204 if( char_I_current_gas <= NUM_GAS ) // gas/diluent 1-5
1110 { 1205 {
1111 sim_gas_last_used = sim_gas_first_used = char_I_current_gas; 1206 sim_gas_current = char_I_current_gas;
1112 sim_gas_last_depth = char_I_deco_gas_change[sim_gas_last_used-1]; // > 0 for OC deco gases, 1207 sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current-1];
1113 // > 0 for first & normal diluents,
1114 // = 0 else
1115 } 1208 }
1116 else 1209 else
1117 { 1210 {
1118 sim_gas_last_used = sim_gas_first_used = 0; // Gas 6 (the manually set one) has number 0 here 1211 sim_gas_current = 0;
1119 sim_gas_last_depth = 0; // handle it as a travel/normal gas 1212 sim_gas_current_depth = char_I_gas6_depth;
1120 } 1213 }
1121 } 1214 }
1122 1215
1123 1216
1124 ////////////////////////////////////////////////////////////////////////////// 1217 //////////////////////////////////////////////////////////////////////////////
1125 // Find the deco gas with the shallowest change depth beyond current depth 1218 // Find the deco gas with the shallowest change depth below or at the current depth
1126 // 1219 //
1127 // INPUT sim_depth_limit : current depth in meters 1220 // INPUT sim_depth_limit : current depth in meters
1128 // char_I_deco_gas_change[] : change depths of the deco gases 1221 // sim_gas_current : number of the currently used gas/dil
1129 // sim_gas_last_depth : change depth of the currently used gas, 0 if on the gas set as FIRST 1222 // sim_gas_current_depth : change depth of the currently used gas/dil
1130 // 1223 // char_I_deco_gas_type[] : types of the gases/dils
1131 // OUTPUT sim_gas_last_depth : switch depth - only if return value is true 1224 // char_I_deco_gas_change[] : change depths of the gases/dils
1132 // sim_gas_last_used : index of the gas (1..5) - only if return value is true 1225 //
1226 // MODIFIED sim_gas_current : index of the gas (1..5) - only if return value is true
1227 // sim_gas_current_depth : switch depth - only if return value is true
1133 // 1228 //
1134 // RETURNS TRUE if a better gas is available 1229 // RETURNS TRUE if a better gas is available
1135 // 1230 //
1136 static unsigned char gas_find_better(void) 1231 static unsigned char gas_find_better(void)
1137 { 1232 {
1138 overlay unsigned char switch_depth = 255; 1233 overlay unsigned char switch_depth = 255;
1139 overlay unsigned char switch_gas = 0; 1234 overlay unsigned char switch_gas = 0;
1140 overlay unsigned char j; 1235 overlay unsigned char j;
1141 1236
1142 1237 // no automatic gas changes in CCR mode
1143 // no automatic gas changes in CCR mode and - as of now - in pSCR mode 1238 if( (char_O_deco_status & DECO_MODE_MASK) == DECO_MODE_CCR ) return 0;
1144 if( char_O_deco_status & DECO_MODE_LOOP ) return 0; 1239
1145 1240 // loop over all deco gases to find the shallowest one below or at current depth
1146 // Loop over all deco gases to find the shallowest one below or at current depth. 1241 for( j = 0; j < NUM_GAS; ++j )
1147 for(j=0; j<NUM_GAS; ++j) 1242 {
1148 { 1243 // Is this gas not the one we are already breathing?
1149 // Is this the gas we are already breathing? 1244 if( j+1 != sim_gas_current )
1150 // If yes, skip this gas. 1245
1151 if( j+1 == sim_gas_last_used ) continue; 1246 // Is this - an (active) deco gas,
1152 1247 // - or if in deco phase, any gas but disabled
1153 // Is the change depth of the gas shallower than the current depth? 1248 // - or if in bailout, any gas but disabled,
1154 // If yes, skip this gas as it is not to be used yet. 1249 // - or if in pSCR mode, any gas but disabled?
1155 // Remark: this check will also skip all disabled gases and the gas set 1250 if( ( ( char_I_deco_gas_type[j] == 3 ) )
1156 // as 'first' because these have their change depth set to 0. 1251 || ( ( char_O_deco_info & DECO_FLAG ) && ( char_I_deco_gas_type[j] != 0 ) )
1157 if( sim_depth_limit > char_I_deco_gas_change[j] ) continue; 1252 || ( ( char_O_deco_status & DECO_BAILOUT_MODE ) && ( char_I_deco_gas_type[j] != 0 ) )
1158 1253 || ( ( char_O_main_status & DECO_MODE_PSCR ) && ( char_I_deco_gas_type[j] != 0 ) ) )
1159 // Is the change depth of the gas deeper or equal than the change depth of the 1254
1160 // gas we are currently one? 1255 // Is the change depth of the this gas deeper than or
1161 // If yes, skip this gas as it is not better than the current one. 1256 // at least equal to the current depth?
1162 // Remark: if there is more than one gas with the same change depth, 1257 if( char_I_deco_gas_change[j] >= sim_depth_limit )
1163 // the last one from the list will be taken. 1258
1164 if( sim_gas_last_depth && (char_I_deco_gas_change[j] >= sim_gas_last_depth) ) continue; 1259 // Is the change depth of this gas shallower than the
1165 1260 // change depth of the gas we are currently on?
1166 // Is the change depth of the gas shallower or equal to the change depth 1261 if( char_I_deco_gas_change[j] < sim_gas_current_depth )
1167 // of the best gas found so far, or is it the first better gas found? 1262
1168 // If yes, we have a better gas 1263 // Is the change depth of this gas shallower than the change
1264 // depth of the best gas found so far, or is it the first
1265 // better gas found?
1169 if( char_I_deco_gas_change[j] < switch_depth ) 1266 if( char_I_deco_gas_change[j] < switch_depth )
1267
1268 // If there is a yes to all these questions, we have a better gas!
1170 { 1269 {
1171 switch_gas = j+1; // remember this gas (1..5) 1270 switch_gas = j+1; // remember this gas (1..5)
1172 switch_depth = char_I_deco_gas_change[j]; // remember its change depth 1271 switch_depth = char_I_deco_gas_change[j]; // remember its change depth
1173 } 1272 }
1273
1174 } // continue looping through all gases to eventually find an even better gas 1274 } // continue looping through all gases to eventually find an even better gas
1175 1275
1176 // has a better gas been found? 1276 // has a better gas been found?
1177 if( switch_gas ) 1277 if( switch_gas )
1178 { 1278 {
1179 // yes 1279 // YES - set the better gas as the new gas
1180 sim_gas_last_used = switch_gas; // report the index of the better 1280 sim_gas_current = switch_gas;
1181 sim_gas_last_depth = switch_depth; // report its change depth 1281
1182 1282 // set its change depth as the last used change depth
1183 assert( sim_gas_last_depth < switch_depth ); 1283 sim_gas_current_depth = switch_depth;
1184 1284
1185 return 1; // signal a better gas was found 1285 assert( sim_gas_current_depth < switch_depth );
1286
1287 // signal a better gas was found
1288 return 1;
1186 } 1289 }
1187 else 1290 else
1188 { 1291 {
1189 return 0; // signal no better gas was found 1292 // NO - signal no better gas was found
1190 } 1293 return 0;
1191 } 1294 }
1192 1295 }
1193 ////////////////////////////////////////////////////////////////////////////// 1296
1194 // Set calc_N2/He/O2_ratios by sim_gas_last_used 1297
1195 // 1298 //////////////////////////////////////////////////////////////////////////////
1196 // Input: sim_gas_last_used : index of gas to use 1299 // Set calc_N2/He/O2_ratios by sim_gas_current
1197 // N2_ratio, He_ratio : if gas = 0 (the manually set gas) 1300 //
1198 // char_I_deco_O2/He_ratio[] : if gas = 1..5 (the configured gases) 1301 // Input: sim_gas_current : index of gas to use
1199 // 1302 // real_O2_ratio, real_He_ratio : if gas = 0 (the manually set gas)
1200 // Output: sim_N2_ratio, sim_He_ratio : ratios of the inert gases 1303 // char_I_deco_O2/He_ratio[] : if gas = 1..5 (the configured gases)
1201 // sim_pSCR_drop : ppO2 drop in pSCR loop 1304 //
1305 // Output: sim_N2_ratio, sim_He_ratio : ratios of the inert gases
1306 // sim_pSCR_drop : ppO2 drop in pSCR loop
1202 // 1307 //
1203 static void gas_set_ratios(void) 1308 static void gas_set_ratios(void)
1204 { 1309 {
1205 overlay float sim_IG_ratio; 1310 overlay float sim_IG_ratio;
1206 1311
1207 assert( 0 <= sim_gas_last_used <= NUM_GAS ); 1312 assert( 0 <= sim_gas_current <= NUM_GAS );
1208 1313
1209 1314
1210 // get gas ratios 1315 // get gas ratios
1211 if( sim_gas_last_used == 0 ) 1316 if( sim_gas_current == 0 )
1212 { 1317 {
1213 sim_O2_ratio = O2_ratio; 1318 sim_O2_ratio = real_O2_ratio;
1214 sim_He_ratio = He_ratio; 1319 sim_He_ratio = real_He_ratio;
1215 } 1320 }
1216 else 1321 else
1217 { 1322 {
1218 sim_O2_ratio = 0.01 * char_I_deco_O2_ratio[sim_gas_last_used-1]; 1323 sim_O2_ratio = 0.01 * char_I_deco_O2_ratio[sim_gas_current-1];
1219 sim_He_ratio = 0.01 * char_I_deco_He_ratio[sim_gas_last_used-1]; 1324 sim_He_ratio = 0.01 * char_I_deco_He_ratio[sim_gas_current-1];
1220 } 1325 }
1221 1326
1222 // inert gas ratio (local helper variable) 1327 // inert gas ratio (local helper variable)
1223 sim_IG_ratio = 1.00 - sim_O2_ratio; 1328 sim_IG_ratio = 1.00 - sim_O2_ratio;
1224 1329
1225 // N2 ratio 1330 // N2 ratio
1226 sim_N2_ratio = sim_IG_ratio - sim_He_ratio; 1331 sim_N2_ratio = sim_IG_ratio - sim_He_ratio;
1227 1332
1228 // ppO2 drop in pSCR loop 1333 // ppO2 drop in pSCR loop
1229 sim_pSCR_drop = sim_IG_ratio * float_pSCR_factor; 1334 sim_pSCR_drop = sim_IG_ratio * float_pSCR_factor;
1230 1335
1231 1336
1232 assert( 0.0 <= sim_N2_ratio && sim_N2_ratio <= 0.95 ); 1337 assert( 0.0 <= sim_N2_ratio && sim_N2_ratio <= 0.95 );
1233 assert( 0.0 <= sim_He_ratio && sim_He_ratio <= 0.95 ); 1338 assert( 0.0 <= sim_He_ratio && sim_He_ratio <= 0.95 );
1234 assert( (sim_N2_ratio + sim_He_ratio) <= 0.95 ); 1339 assert( (sim_N2_ratio + sim_He_ratio) <= 0.95 );
1235 } 1340 }
1236 1341
1237 ////////////////////////////////////////////////////////////////////////////// 1342
1238 // Compute respired ppN2 and ppHe 1343 //////////////////////////////////////////////////////////////////////////////
1239 // 1344 // Compute respired ppO2, ppN2 and ppHe
1240 // Input: tissue_increment : selector for targeting simulated or real tissues 1345 //
1241 // char_O_main_status : breathing mode for real tissues 1346 // Input: tissue_increment : selector for targeting simulated or real tissues
1242 // char_O_deco_status : breathing mode for simulated tissues 1347 // char_O_main_status : breathing mode for real tissues
1243 // (sim_)O2_ratio : (simulated) O2 ratio breathed 1348 // char_O_deco_status : breathing mode for simulated tissues
1244 // (sim_)N2_ratio : (simulated) N2 ratio breathed 1349 // sim_/real_O2_ratio : (simulated) O2 ratio breathed
1245 // (sim_)He_ratio : (simulated) He ratio breathed 1350 // sim_/real_N2_ratio : (simulated) N2 ratio breathed
1246 // (sim_)pres_respiration : (simulated) respiration pressure 1351 // sim_/real_He_ratio : (simulated) He ratio breathed
1247 // char_I_const_ppO2 : ppO2 reported from sensors or setpoint 1352 // sim_/real_pres_respiration : (simulated) respiration pressure [bar]
1248 // char_I_PSCR_drop : pSCR parameter 1353 // sim_/real_pSCR_drop : (simulated) pSCR O2 drop
1249 // char_I_PSCR_lungratio : pSCR parameter 1354 // pres_surface : surface pressure [bar]
1250 // pres_surface : surface pressure 1355 // char_I_const_ppO2 : ppO2 reported from sensors or setpoint [cbar]
1251 // float_deco_distance : safety factor 1356 // float_deco_distance : safety factor, additional depth below stop depth [bar]
1252 // ppWater : water-vapor pressure inside respiratory tract 1357 // ppWater : water-vapor pressure inside respiratory tract [bar]
1253 // 1358 //
1254 // Output: ppN2 : respired N2 partial pressure 1359 // Output: ppN2 : respired N2 partial pressure
1255 // ppHe : respired He partial pressure 1360 // ppHe : respired He partial pressure
1256 // char_ppO2 : breathed ppO2 in %, to be used for CNS calculation 1361 // char_ppO2 : breathed ppO2 in %, used in CNS calculation
1257 // 1362 //
1258 void calc_alveolar_pressures(void) 1363 void calc_alveolar_pressures(void)
1259 { 1364 {
1260 overlay float pres_diluent; 1365 overlay float calc_pres_respiration;
1261 overlay float calc_O2_ratio; 1366 overlay float calc_O2_ratio;
1262 overlay float calc_N2_ratio; 1367 overlay float calc_N2_ratio;
1263 overlay float calc_He_ratio; 1368 overlay float calc_He_ratio;
1264 overlay float calc_pSCR_drop; 1369 overlay float calc_pSCR_drop;
1265 1370
1266 overlay unsigned char status; 1371 overlay unsigned char status;
1267 1372
1268 1373
1269 assert( 0.00 <= N2_ratio && N2_ratio <= 1.00 ); 1374 assert( 0.00 <= real_N2_ratio && real_N2_ratio <= 1.00 );
1270 assert( 0.00 <= He_ratio && He_ratio <= 1.00 ); 1375 assert( 0.00 <= real_He_ratio && real_He_ratio <= 1.00 );
1271 assert( (N2_ratio + He_ratio) <= 1.00 ); 1376 assert( (real_N2_ratio + real_He_ratio) <= 1.00 );
1272 assert( 0.800 < pres_respiration && pres_respiration < 14.0 ); 1377 assert( 0.800 < real_pres_respiration && real_pres_respiration < 14.0 );
1273 1378
1274 assert( 0.00 <= sim_N2_ratio && N2_ratio <= 1.00 ); 1379 assert( 0.00 <= sim_N2_ratio && real_N2_ratio <= 1.00 );
1275 assert( 0.00 <= sim_He_ratio && He_ratio <= 1.00 ); 1380 assert( 0.00 <= sim_He_ratio && real_He_ratio <= 1.00 );
1276 assert( (sim_N2_ratio + sim_He_ratio) <= 1.00 ); 1381 assert( (sim_N2_ratio + sim_He_ratio) <= 1.00 );
1277 assert( 0.800 < sim_pres_respiration && sim_pres_respiration < 14.0 ); 1382 assert( 0.800 < sim_pres_respiration && sim_pres_respiration < 14.0 );
1278 1383
1279 1384
1280 // get input data according to context 1385 // get input data according to context
1281 if( tissue_increment & TISSUE_FLAG ) 1386 if( tissue_increment & TISSUE_FLAG )
1282 { 1387 {
1283 //---- real tissues ----------------------------------------------------------- 1388 //---- real tissues -----------------------------------------------------------
1284 status = char_O_main_status; 1389 status = char_O_main_status;
1285 pres_diluent = pres_respiration; 1390 calc_pres_respiration = real_pres_respiration;
1286 calc_pSCR_drop = pSCR_drop; 1391 calc_pSCR_drop = real_pSCR_drop;
1287 1392
1288 calc_O2_ratio = O2_ratio; 1393 calc_O2_ratio = real_O2_ratio;
1289 calc_N2_ratio = N2_ratio; 1394 calc_N2_ratio = real_N2_ratio;
1290 calc_He_ratio = He_ratio; 1395 calc_He_ratio = real_He_ratio;
1291 } 1396 }
1292 else 1397 else
1293 { 1398 {
1294 //---- simulated tissues ------------------------------------------------------ 1399 //---- simulated tissues ------------------------------------------------------
1295 status = char_O_deco_status; 1400 status = char_O_deco_status;
1296 pres_diluent = sim_pres_respiration; 1401 calc_pres_respiration = sim_pres_respiration;
1297 calc_pSCR_drop = sim_pSCR_drop; 1402 calc_pSCR_drop = sim_pSCR_drop;
1298 1403
1299 calc_O2_ratio = sim_O2_ratio; 1404 calc_O2_ratio = sim_O2_ratio;
1300 calc_N2_ratio = sim_N2_ratio; 1405 calc_N2_ratio = sim_N2_ratio;
1301 calc_He_ratio = sim_He_ratio; 1406 calc_He_ratio = sim_He_ratio;
1302
1303 // take deco offset into account, but not at surface
1304 if( pres_diluent > pres_surface ) pres_diluent += float_deco_distance;
1305 } 1407 }
1306 1408
1307 //---- OC, CCR and Bailout Mode Gas Calculations ----------------------------------- 1409 //---- OC, CCR and Bailout Mode Gas Calculations -----------------------------------
1308 1410
1309 // calculate ppO2 of pure oxygen 1411 // calculate ppO2 of pure oxygen
1310 O2_ppO2 = (pres_diluent - ppWater); 1412 O2_ppO2 = calc_pres_respiration - ppWater;
1311 1413
1312 // capture failure condition in case pres_respiration is < ppWater (should never happen...) 1414 // capture failure condition in case real_pres_respiration is < ppWater (should never happen...)
1313 if( O2_ppO2 < 0.0 ) O2_ppO2 = 0.0; 1415 if( O2_ppO2 < 0.0 ) O2_ppO2 = 0.0;
1314 1416
1315 // calculate ppO2 of the pure gas (OC, diluent) 1417 // calculate ppO2 of the pure gas (OC, diluent)
1316 OC_ppO2 = O2_ppO2 * calc_O2_ratio; 1418 OC_ppO2 = O2_ppO2 * calc_O2_ratio;
1317 1419
1324 1426
1325 //---- Loop modes : adjust ppN2 and ppHe for change in ppO2 due to setpoint (CCR) or drop (pSCR) --- 1427 //---- Loop modes : adjust ppN2 and ppHe for change in ppO2 due to setpoint (CCR) or drop (pSCR) ---
1326 if( status & DECO_MODE_LOOP ) 1428 if( status & DECO_MODE_LOOP )
1327 { 1429 {
1328 overlay float const_ppO2; 1430 overlay float const_ppO2;
1431 overlay float max_ppO2;
1329 1432
1330 // get the current sensor reading (CCR / pSCR if fitted) or the fixed setpoint (CCR) / a zero (pSCR) 1433 // get the current sensor reading (CCR / pSCR if fitted) or the fixed setpoint (CCR) / a zero (pSCR)
1331 const_ppO2 = 0.01 * char_I_const_ppO2; 1434 const_ppO2 = 0.01 * char_I_const_ppO2;
1332 1435
1333 // Limit the setpoint to the maximum physically possible ppO2. This prevents for 1436 // Limit the setpoint to the maximum physically possible ppO2. This prevents for
1334 // example calculating with a setpoint of 1.3 bar in only 2 meters of depth. 1437 // example calculating with a setpoint of 1.3 bar in only 2 meters of depth.
1335 // Additionally, if limiting occurs, the ppO2 can be further reduced to account 1438 // Additionally, the ppO2 can be further reduced to account for exhaled inert gases
1336 // for residual inert gases by the user-adjustable setting char_I_cc_max_frac_o2. 1439 // accumulating in the loop by the user-adjustable setting char_I_cc_max_frac_o2.
1337 1440 // (ppWater is neglected here)
1338 if( const_ppO2 > pres_diluent ) // no ppWater subtracted here to give some margin for 1441 max_ppO2 = 0.01 * char_I_cc_max_frac_o2 * calc_pres_respiration;
1339 { // sensors delivering data a little bit over target 1442
1340 const_ppO2 = 0.01 * char_I_cc_max_frac_o2 * (pres_diluent - ppWater); 1443 if( const_ppO2 > max_ppO2 ) const_ppO2 = max_ppO2;
1341 }
1342 1444
1343 // check which kind of loop we are on 1445 // check which kind of loop we are on
1344 if( status & DECO_MODE_PSCR ) 1446 if( status & DECO_MODE_PSCR )
1345 { 1447 {
1346 //---- pSCR Mode -------------------------------------------------------------------------- 1448 //---- pSCR Mode --------------------------------------------------------------------------
1352 } 1454 }
1353 else 1455 else
1354 { 1456 {
1355 //---- CCR Mode --------------------------------------------------------------------------- 1457 //---- CCR Mode ---------------------------------------------------------------------------
1356 1458
1357 // derive breathed ppO2 from (char_I_)const_ppO2, 1459 // derive breathed ppO2 from (char_I_)const_ppO2, which holds sensor reading or selected setpoint
1358 // which holds sensor reading or fixed setpoint
1359 ppO2 = const_ppO2; 1460 ppO2 = const_ppO2;
1360 } 1461 }
1361 1462
1362 // adjust diluent pressure (ppN2 + ppHe) for change 1463 // adjust overall gas pressure for change in ppO2 due to setpoint (CCR) or drop (pSCR),
1363 // in ppO2 due to setpoint (CCR) or drop (pSCR) 1464 // capture potential failure conditions first:
1364 pres_diluent -= ppO2; 1465 if( ( calc_pres_respiration < ppO2 ) // sensor reading or selected setpoint is higher than ambient pressure
1365 pres_diluent /= calc_N2_ratio + calc_He_ratio; 1466 || ( calc_O2_ratio > 0.995 ) ) // diluent is pure O2, i.e. calc_N2_ratio + calc_He_ratio = 0 yielding a div/0
1366 1467 {
1367 // capture all failure conditions, including div/0 1468 // failure condition present, set predetermined result
1368 // in case diluent is pure O2 1469 calc_pres_respiration = 0.0;
1369 if( (pres_diluent < 0.0) || (calc_O2_ratio > 99.5) ) 1470 }
1370 { 1471 else
1371 pres_diluent = 0.0; 1472 {
1372 ppO2 = OC_ppO2; 1473 // no failure conditions present, equation can be executed
1474 calc_pres_respiration -= ppO2;
1475 calc_pres_respiration /= calc_N2_ratio + calc_He_ratio;
1373 } 1476 }
1374 } 1477 }
1375 else 1478 else
1376 { //---- OC mode --------------------------------------------------------------------------------- 1479 {
1480 //---- OC mode ---------------------------------------------------------------------------------
1377 1481
1378 // breathed ppO2 is ppO2 of pure gas 1482 // breathed ppO2 is ppO2 of pure gas
1379 ppO2 = OC_ppO2; 1483 ppO2 = OC_ppO2;
1380 } 1484 }
1381 1485
1382 1486
1383 // derive char_ppO2 in [cbar], used for calculating CNS% 1487 //---- derive char_ppO2 in [cbar], used for calculating CNS% ---------------------------------------
1488
1384 if ( ppO2 < 0.01 ) char_ppO2 = 0; 1489 if ( ppO2 < 0.01 ) char_ppO2 = 0;
1385 else if ( ppO2 >= 2.545 ) char_ppO2 = 255; 1490 else if ( ppO2 >= 2.545 ) char_ppO2 = 255;
1386 else char_ppO2 = (unsigned char)(100 * ppO2 + 0.5); 1491 else char_ppO2 = (unsigned char)(100 * ppO2 + 0.5);
1387 1492
1388 1493
1389 //---- calculate ppN2 and ppHe --------------------------------------------------------------------- 1494 //---- calculate ppN2 and ppHe ---------------------------------------------------------------------
1390 1495
1391 if( pres_diluent > ppWater ) 1496 // add deco safety distance when working on simulated tissues
1392 { 1497 if( !(tissue_increment & TISSUE_FLAG) ) calc_pres_respiration += float_deco_distance;
1393 ppN2 = calc_N2_ratio * (pres_diluent - ppWater); 1498
1394 ppHe = calc_He_ratio * (pres_diluent - ppWater); 1499 // compute ppN2 and ppHe, capture potential failure conditions first:
1500 if( calc_pres_respiration > ppWater )
1501 {
1502 // subtract water vapor pressure
1503 calc_pres_respiration -= ppWater;
1504
1505 // calculate partial pressures
1506 ppN2 = calc_N2_ratio * calc_pres_respiration;
1507 ppHe = calc_He_ratio * calc_pres_respiration;
1395 } 1508 }
1396 else 1509 else
1397 { 1510 {
1511 // calculated respired pressure is < water vapor pressure, thus set ppN2 and ppHe to 0
1398 ppN2 = 0.0; 1512 ppN2 = 0.0;
1399 ppHe = 0.0; 1513 ppHe = 0.0;
1400 } 1514 }
1401 } 1515 }
1402 1516
1517
1403 ////////////////////////////////////////////////////////////////////////////// 1518 //////////////////////////////////////////////////////////////////////////////
1404 // clear_tissue 1519 // clear_tissue
1405 // 1520 //
1406 // optimized in v.101 (var_N2_a) 1521 // optimized in v.101 (var_N2_a)
1407 // 1522 //
1408 // preload tissues with standard pressure for the given ambient pressure. 1523 // Reset all tissues to surface pressure equilibrium state.
1409 // 1524 //
1410 static void clear_tissue(void) 1525 static void clear_tissue(void)
1411 { 1526 {
1412 pres_respiration = 0.001 * int_I_pres_respiration; 1527 // safety limit to prevent improper initialization values
1413 N2_equilibrium = 0.7902 * (pres_respiration - ppWater); 1528 if( int_I_pres_respiration < 500) int_I_pres_respiration = 500; // min. respiration pressure = 500 mbar
1414 1529
1415 for(ci=0; ci<NUM_COMP; ci++) 1530 real_pres_respiration = 0.001 * int_I_pres_respiration;
1531 N2_equilibrium = 0.7902 * (real_pres_respiration - ppWater);
1532
1533 for( ci = 0; ci < NUM_COMP; ci++ )
1416 { 1534 {
1417 // cycle through the 16 Buhlmann N2 tissues 1535 // cycle through the 16 Buhlmann N2 tissues
1418 pres_tissue_N2[ci] = N2_equilibrium; // initialize data for "real" tissue 1536 pres_tissue_N2[ci] = N2_equilibrium; // initialize data for "real" tissue
1419 char_O_tissue_N2_saturation[ci] = 11; // initialize data for tissue graphics 1537 char_O_tissue_N2_saturation[ci] = 11; // initialize data for tissue graphics
1420 1538
1426 // reset CNS values 1544 // reset CNS values
1427 CNS_fraction = 0.0; 1545 CNS_fraction = 0.0;
1428 int_O_CNS_fraction = int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = 0; 1546 int_O_CNS_fraction = int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = 0;
1429 1547
1430 1548
1431 // reset any warnings 1549 // reset any warnings and status data
1432 char_O_deco_warnings = 0; 1550 char_O_deco_warnings = 0;
1551 char_O_deco_status = 0;
1433 1552
1434 // reset some more vars to their defaults 1553 // reset some more vars to their defaults
1435 char_O_nullzeit = 240; 1554 char_O_nullzeit = 240;
1436 int_O_ascenttime = 0; 1555 int_O_ascenttime = 0;
1437 int_O_alternate_ascenttime = 0; 1556 int_O_alternate_ascenttime = 0;
1450 static void calc_hauptroutine(void) 1569 static void calc_hauptroutine(void)
1451 { 1570 {
1452 overlay unsigned int int_ppO2_min; 1571 overlay unsigned int int_ppO2_min;
1453 overlay unsigned int int_ppO2_max; 1572 overlay unsigned int int_ppO2_max;
1454 overlay unsigned int int_ppO2_max_dil; 1573 overlay unsigned int int_ppO2_max_dil;
1574 overlay unsigned int int_ppO2_max_max;
1455 overlay float EAD; 1575 overlay float EAD;
1456 overlay float END; 1576 overlay float END;
1457 1577
1458 1578
1459 //--- Set-up Part -------------------------------------------------------------------------------- 1579 //--- Set-up Part --------------------------------------------------------------------------------
1580
1581 // clear flags indicating a calculation has been completed
1582 char_O_main_status &= ~( DECO_COMPLETED_NORM + DECO_COMPLETED_ALT );
1460 1583
1461 // twosectimer: 1584 // twosectimer:
1462 // calc_hauptroutine is now invoked every second to speed up the deco planning. 1585 // calc_hauptroutine is now invoked every second to speed up the deco planning.
1463 // Because the tissue and CNS calculations are based on a two seconds period, a 1586 // Because the tissue and CNS calculations are based on a two seconds period, a
1464 // toggle-timer is used by the respective routines to skip every 2nd invocation. 1587 // toggle-timer is used to skip every 2nd invocation.
1465 twosectimer = (twosectimer) ? 0 : 1; // toggle the toggle-timer 1588 twosectimer = (twosectimer) ? 0 : 1;
1466 1589
1467 1590 // do initializations that need to be done only once at the beginning of a dive
1468 // set up normal tissue updating or "fast forward" updating for simulator sim+5' function 1591 if( (char_O_deco_status & DECO_STATUS_MASK) == DECO_STATUS_INIT )
1469 // and deco calculator bottom time calculation 1592 {
1470 if( char_I_sim_advance_time > 0 ) 1593 // compute a factor that will be used later on in pSCR calculations
1471 { 1594 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio;
1472 // configure char_I_sim_advance_time minutes of tissue updating
1473 tissue_increment = char_I_sim_advance_time // given number of minutes, limited to 127
1474 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS
1475
1476 char_I_sim_advance_time = 0; // clear "mailbox"
1477 }
1478 else
1479 {
1480 // configure 2 seconds of tissue updating
1481 tissue_increment = 0 // encoding for 2 seconds update
1482 | TISSUE_FLAG; // set flag for updating the "real" tissues & CNS
1483 } 1595 }
1484 1596
1485 1597
1486 //---- Calculations Part ---------------------------------------------------------------------- 1598 //---- Calculations Part ----------------------------------------------------------------------
1487 1599
1488 // acquire current environment data 1600 // acquire current environment data
1489 calc_hauptroutine_data_input(); 1601 calc_hauptroutine_data_input();
1490 1602
1491 // calculate ppN2 and ppHe 1603 // target the real tissues with 2 second increments by default
1604 tissue_increment = TISSUE_FLAG | 0;
1605
1606 // calculate ppO2, ppN2 and ppHe
1492 calc_alveolar_pressures(); 1607 calc_alveolar_pressures();
1493 1608
1494 // All deco code is invoked every second. But as the tissue and CNS updates are based 1609 // All deco code is invoked every second. But as the tissue and CNS updates are based
1495 // on 2 seconds periods, each update is done only on each 2nd second. 1610 // on 2 seconds periods, each update is done only on each 2nd second. In case a "fast
1496 // In case a "fast forward" of the tissues is commanded, the 2-seconds rule is over raided. 1611 // forward" of the tissues is commanded, the 2-seconds rule is over-raided.
1497 // To distribute computational load, updating of tissues and CNS is done in alternation. 1612 if( twosectimer || char_I_sim_advance_time )
1498 if( twosectimer || (tissue_increment & TIME_MASK) ) 1613 {
1499 { 1614 // Set up normal tissue updating or "fast forward" updating for simulator
1615 // sim+5' function and deco calculator bottom time calculation.
1616 if( char_I_sim_advance_time > 0 )
1617 {
1618 // configure "fast forward" tissue updating
1619 tissue_increment = TISSUE_FLAG | char_I_sim_advance_time;
1620
1621 // clear the "mailbox"
1622 char_I_sim_advance_time = 0;
1623 }
1624
1500 // calculate the real tissues 1625 // calculate the real tissues
1501 calc_tissues(); 1626 calc_tissues();
1502 1627
1503 // calculate ceiling (at GF_high) and current GF 1628 // update the CNS value for the real tissues
1504 calc_limit(GF_high); 1629 calc_CNS();
1505 } 1630
1506 1631 // calculate ceiling (at GF_high or 100%) and leading tissue supersaturation
1507 if( !twosectimer || (tissue_increment & TIME_MASK) ) 1632 if( char_I_deco_model ) calc_limit(GF_high); // GF factors enabled
1508 { 1633 else calc_limit( 1.0 ); // classic Buhlmann
1509 // calculate CNS value increment for the real tissues 1634
1510 calc_CNS_increment(); 1635 // convert ceiling from float to integer for export [mbar relative pressure]
1511 1636 convert_ceiling_for_display();
1512 // increment CNS value of the real tissues 1637
1513 CNS_fraction += CNS_fraction_inc; 1638 // convert leading tissue supersaturation value from float to integer for export [%]
1514 1639 convert_GF_for_display();
1515 // compute integer copy of CNS value for display purpose 1640
1641 // convert CNS value from float to integer for export
1516 convert_CNS_for_display(); 1642 convert_CNS_for_display();
1517 } 1643 }
1518
1519 1644
1520 //---- Calculate and Export EAD and END ------------------------------------------------------ 1645 //---- Calculate and Export EAD and END ------------------------------------------------------
1521 1646
1522 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air 1647 // calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air
1523 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER; 1648 EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER;
1524 1649
1525 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too 1650 // calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too
1526 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott, 1651 // Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott,
1527 // 4th edition, 1993, W.B.Saunders Company Ltd, London. 1652 // 4th edition, 1993, W.B.Saunders Company Ltd, London.
1528 END = (pres_respiration - ppHe - pres_surface) * BAR_TO_METER; 1653 END = (real_pres_respiration - ppHe - pres_surface) * BAR_TO_METER;
1529 1654
1530 // export EAD 1655 // export EAD
1531 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0; 1656 if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0;
1532 else char_O_EAD = (unsigned char)(EAD + 0.5); 1657 else char_O_EAD = (unsigned char)(EAD + 0.5);
1533 1658
1537 1662
1538 1663
1539 //---- Compute ppO2 Values in [cbar] --------------------------------------------------------- 1664 //---- Compute ppO2 Values in [cbar] ---------------------------------------------------------
1540 1665
1541 // pure oxygen ppO2 1666 // pure oxygen ppO2
1542 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0; 1667 if ( O2_ppO2 < 0.01 ) int_O_O2_ppO2 = 0;
1543 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999; 1668 else if ( O2_ppO2 >= 9.995 ) int_O_O2_ppO2 = 999;
1544 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5); 1669 else int_O_O2_ppO2 = (unsigned int)(100 * O2_ppO2 + 0.5);
1545 1670
1546 // pure gas ppO2 1671 // pure gas ppO2
1547 if ( OC_ppO2 < 0.01 ) int_O_pure_ppO2 = 0; 1672 if ( OC_ppO2 < 0.01 ) int_O_pure_ppO2 = 0;
1548 else if ( OC_ppO2 >= 9.995 ) int_O_pure_ppO2 = 999; 1673 else if ( OC_ppO2 >= 9.995 ) int_O_pure_ppO2 = 999;
1549 else int_O_pure_ppO2 = (unsigned int)(100 * OC_ppO2 + 0.5); 1674 else int_O_pure_ppO2 = (unsigned int)(100 * OC_ppO2 + 0.5);
1550 1675
1551 // calculated pSCR ppO2 1676 // calculated pSCR ppO2
1552 if ( pSCR_ppO2 < 0.01 ) int_O_pSCR_ppO2 = 0; 1677 if ( pSCR_ppO2 < 0.01 ) int_O_pSCR_ppO2 = 0;
1553 else if ( pSCR_ppO2 >= 9.995 ) int_O_pSCR_ppO2 = 999; 1678 else if ( pSCR_ppO2 >= 9.995 ) int_O_pSCR_ppO2 = 999;
1554 else int_O_pSCR_ppO2 = (unsigned int)(100 * pSCR_ppO2 + 0.5); 1679 else int_O_pSCR_ppO2 = (unsigned int)(100 * pSCR_ppO2 + 0.5);
1555 1680
1556 // breathed ppO2 1681 // breathed ppO2
1557 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0; 1682 if ( ppO2 < 0.01 ) int_O_breathed_ppO2 = 0;
1558 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999; 1683 else if ( ppO2 >= 9.995 ) int_O_breathed_ppO2 = 999;
1559 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5); 1684 else int_O_breathed_ppO2 = (unsigned int)(100 * ppO2 + 0.5);
1560 1685
1561 1686
1687 //---- Set/Reset Deco Mode --------------------------------------------------------------------
1688
1689 // Set the deco mode flag if:
1690 // - breathing an OC deco gas (gas type 3), or
1691 // - breathing a gas or diluent that officially is disabled (type 0), or
1692 // - if nearby or above the deepest deco stop (nearby means 1 meter below, the additional 0.9 serves rounding effects)
1693 if ( ( char_I_current_gas_type == 3 )
1694 || ( char_I_current_gas_type == 0 )
1695 || ( (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER - 1.9) < char_O_first_deco_depth )
1696 )
1697 char_O_deco_info |= DECO_FLAG;
1698 else
1699 char_O_deco_info &= ~DECO_FLAG;
1700
1701
1562 //---- Compute ppO2 Warnings ------------------------------------------------------------------ 1702 //---- Compute ppO2 Warnings ------------------------------------------------------------------
1563 1703
1564 // compute conditional min/max values 1704 // compute conditional min/max values
1565 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min; 1705 int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min;
1566 int_ppO2_max = (char_O_deco_warnings & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max; 1706 int_ppO2_max = (char_O_deco_info & DECO_FLAG ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max;
1707
1708 // get biggest of char_I_ppO2_max / char_I_ppO2_max_deco
1709 int_ppO2_max_max = ( char_I_ppO2_max_deco > char_I_ppO2_max ) ? char_I_ppO2_max_deco : char_I_ppO2_max;
1567 1710
1568 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold 1711 // default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold
1569 int_ppO2_max_dil = int_ppO2_max; 1712 int_ppO2_max_dil = int_ppO2_max;
1570 1713
1571 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint 1714 // when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
1572 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR ) 1715 if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR )
1573 { 1716 {
1574 overlay unsigned int max_dil; 1717 overlay unsigned int max_dil;
1575 1718
1576 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint... 1719 // The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
1577 // (the condition protects from negative numbers which would cause a wrap-around) 1720 // (the condition protects from negative numbers which would cause a wrap-around in unsigned integers)
1578 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0; 1721 max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
1579 1722
1580 // ...but never above int_ppO2_max. 1723 // ...but never above int_ppO2_max.
1581 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil; 1724 if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil;
1582 1725
1583 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check 1726 // We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
1584 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks. 1727 // against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
1585 } 1728 }
1586 1729
1587 // check for safe range of pure oxygen 1730 // check for safe range of pure oxygen
1588 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 1731 if ( int_O_O2_ppO2 >= int_ppO2_max ) int_O_O2_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1589 1732
1590 // check for safe range of breathed gas 1733 // check for safe range of breathed gas
1591 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 1734 if ( int_O_breathed_ppO2 <= int_ppO2_min ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1592 else if ( int_O_breathed_ppO2 >= int_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 1735 else if ( int_O_breathed_ppO2 >= int_ppO2_max_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1593 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes 1736 else if ( char_O_deco_info & DECO_FLAG ) ; // no attention generated in deco mode
1594 else if ( int_O_breathed_ppO2 >= ppO2_ATTENTION_THRESHOLD ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION; 1737 else if ( char_O_main_status & DECO_MODE_LOOP ) ; // no attention generated in loop modes
1738 else if ( int_O_breathed_ppO2 >= (unsigned int)char_I_ppO2_max ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
1595 1739
1596 // check for safe range of pure diluent 1740 // check for safe range of pure diluent
1597 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 1741 if ( int_O_pure_ppO2 <= (unsigned int)char_I_ppO2_min ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1598 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 1742 else if ( int_O_pure_ppO2 >= int_ppO2_max ) int_O_pure_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1599 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION; 1743 else if ( int_O_pure_ppO2 >= int_ppO2_max_dil ) int_O_pure_ppO2 |= INT_FLAG_ATTENTION;
1600 1744
1601 // check for safe range of calculated pSCR loop gas 1745 // check for safe range of calculated pSCR loop gas
1602 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW; 1746 if ( int_O_pSCR_ppO2 <= int_ppO2_min ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
1603 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH; 1747 else if ( int_O_pSCR_ppO2 >= int_ppO2_max ) int_O_pSCR_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
1604 1748
1605 1749
1606 // done with the real tissues 1750 #ifdef _rx_functions
1607 1751
1608 1752 //---- Process Pressure Readings (OSTC TR only) -----------------------------------------------
1609 1753
1610 //---- Toggle between Calculation for NDL (bottom time), ------------------------------------- 1754 // only for OSTC TR model with TR functions enabled
1611 //---- Deco Stops, more Deco Stops and Results Gathering ------------------------------------- 1755 if( char_O_main_status & DECO_TR_FUNCTIONS )
1612 1756 {
1613 1757 // pressure warnings for reading 1, but only if enabled and pressure value available
1614 // all following operations target the simulated tissues, so clear flag in bit 7 1758 if( (char_I_pressure_gas[0] > 0) && !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
1615 tissue_increment = 0; 1759 {
1616 1760 overlay unsigned int pressure_value = int_IO_pressure_value[0] & ~INT_FLAG_OUTDATED;
1617 // branch to the code for the current phase the deco calculations are in 1761
1762 if( (char_I_pressure_gas[0] < 6 ) && !(int_O_pressure_need[0] & INT_FLAG_NOT_AVAIL) )
1763 {
1764 // not a dil and need available: warning & attention by need
1765 if( pressure_value <= int_O_pressure_need[0])
1766 int_IO_pressure_value[0] |= INT_FLAG_WARNING;
1767 else if( pressure_value <= int_O_pressure_need[0] + int_O_pressure_need[0] / 2 )
1768 int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
1769 }
1770 else
1771 {
1772 // a dil or need not available: warning & attention by fixed thresholds
1773 if ( pressure_value <= PRESSURE_LIMIT_WARNING ) int_IO_pressure_value[0] |= INT_FLAG_WARNING;
1774 else if( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
1775 }
1776 }
1777
1778 // pressure warnings for reading 2, but only if enabled and pressure value available
1779 if( (char_I_pressure_gas[1] > 0) && !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
1780 {
1781 overlay unsigned int pressure_value = int_IO_pressure_value[1] & ~INT_FLAG_OUTDATED;
1782
1783 if( (char_I_pressure_gas[1] < 6 ) && !(int_O_pressure_need[1] & INT_FLAG_NOT_AVAIL) )
1784 {
1785 // not a dil and need available: warning & attention by need
1786 if( pressure_value <= int_O_pressure_need[1])
1787 int_IO_pressure_value[1] |= INT_FLAG_WARNING;
1788 else if( pressure_value <= int_O_pressure_need[1] + int_O_pressure_need[1] / 2 )
1789 int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
1790 }
1791 else
1792 {
1793 // a dil or need not available: warning & attention by fixed thresholds
1794 if( pressure_value <= PRESSURE_LIMIT_WARNING ) int_IO_pressure_value[1] |= INT_FLAG_WARNING;
1795 else if( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
1796 }
1797 }
1798
1799 //--- SAC Calculation ---------------------------------------------------------------------
1800 //
1801 // char_I_SAC_mode =0: disabled
1802 // =1: SAC from 1st reading
1803 // =2: SAC from 2nd reading
1804 // =3: SAC from higher one of both pressure drops (independent double mode)
1805 // =4: SAC (O2 usage) from 2nd reading without real_pres_respiration term
1806
1807 // set SAC rate to not available by default
1808 int_O_sac_rate = 0 + INT_FLAG_NOT_AVAIL;
1809
1810 // get a copy of the current absolute pressure
1811 pres_respiration_sac = real_pres_respiration;
1812
1813 // set threshold for SAC rate attention
1814 max_sac_rate = (char_O_deco_info & DECO_FLAG) ? char_I_deco_usage : char_I_bottom_usage;
1815
1816 // char_I_deco_usage / char_I_bottom_usage are in l/min, max_sac_rate is in 0.1 l/min
1817 max_sac_rate *= 10;
1818
1819
1820 // pre-process SAC mode 3 (independent double)
1821 if( char_I_SAC_mode == 3 )
1822 {
1823 overlay unsigned char reading1_gas;
1824 overlay unsigned char reading2_gas;
1825 overlay unsigned char reading1_tanksize;
1826 overlay unsigned char reading2_tanksize;
1827 overlay unsigned short reading1_press;
1828 overlay unsigned short reading2_press;
1829 overlay unsigned short reading1_drop;
1830 overlay unsigned short reading2_drop;
1831
1832 // get gas numbers (1-10) of both readings
1833 reading1_gas = char_I_pressure_gas[0];
1834 reading2_gas = char_I_pressure_gas[1];
1835
1836 // default to no SAC calculation
1837 char_I_SAC_mode = 0;
1838
1839 // clear switch advice by default
1840 char_O_deco_info &= ~IND_DOUBLE_SWITCH_FLAG;
1841
1842 // check if both readings are configured and available
1843 if( reading1_gas )
1844 if( reading2_gas )
1845 if( !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
1846 if( !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
1847 if( !(int_I_pressure_drop[0] & INT_FLAG_NOT_AVAIL) )
1848 if( !(int_I_pressure_drop[1] & INT_FLAG_NOT_AVAIL) )
1849 {
1850 // get tank pressures, stripping flags
1851 reading1_press = int_IO_pressure_value[0] & 0x0FFF; // in 0.1 bar
1852 reading2_press = int_IO_pressure_value[1] & 0x0FFF; // in 0.1 bar
1853
1854 // get pressure drops as integers, stripping flags and shifting right
1855 // to avoid an overflow when multiplying with the tank size later on
1856 reading1_drop = (int_I_pressure_drop[0] & 0x0FFF) >> 2;
1857 reading2_drop = (int_I_pressure_drop[1] & 0x0FFF) >> 2;
1858
1859 // get tank sizes
1860 reading1_tanksize = char_I_tank_size[reading1_gas-1];
1861 reading2_tanksize = char_I_tank_size[reading2_gas-1];
1862
1863 // set mode to calculate SAC on the reading with the higher absolute drop
1864 char_I_SAC_mode = (reading1_drop * reading1_tanksize > reading2_drop * reading2_tanksize) ? 1 : 2;
1865
1866 // compute switch advice if pressure (in 0.1 bar) of tank breathed from is
1867 // more than char_I_max_pres_diff (in bar) below pressure of the other tank.
1868 if( char_I_SAC_mode == 1 )
1869 {
1870 // breathing from reading 1, switch advice if pressure on reading 1 lower than on 2
1871 if( (reading1_press + 10*char_I_max_pres_diff) <= reading2_press )
1872 char_O_deco_info |= IND_DOUBLE_SWITCH_FLAG;
1873 }
1874 else
1875 {
1876 // breathing from reading 2, switch advice if pressure on reading 2 lower than on 1
1877 if( (reading2_press + 10*char_I_max_pres_diff) <= reading1_press )
1878 char_O_deco_info |= IND_DOUBLE_SWITCH_FLAG;
1879 }
1880 }
1881 }
1882
1883
1884 // pre-process SAC mode 4 (O2 usage by reading 2)
1885 if( char_I_SAC_mode == 4 )
1886 {
1887 // O2 usage on CCR is independent from absolute pressure
1888 pres_respiration_sac = 1.0;
1889
1890 // O2 pressure drop is measured via reading 2
1891 char_I_SAC_mode = 2;
1892
1893 // reconfigure max SAC rate to O2 consumption attention threshold
1894 max_sac_rate = O2_CONSUMPTION_LIMIT_ATTENTION;
1895 }
1896
1897
1898 // calculate SAC - modes 1 & 2
1899 if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) )
1900 {
1901 overlay unsigned char reading_index;
1902 overlay unsigned char reading_gas;
1903 overlay unsigned char reading_tanksize;
1904 overlay float reading_drop;
1905
1906 // set index: char_I_SAC_mode = 1 -> reading one, index 0
1907 // = 2 -> two, 1
1908 reading_index = char_I_SAC_mode - 1;
1909
1910 // get gas number (1-10)
1911 reading_gas = char_I_pressure_gas[reading_index];
1912
1913 // check if reading is configured and available
1914 if( reading_gas )
1915 if( !(int_I_pressure_drop[reading_index] & INT_FLAG_NOT_AVAIL) )
1916 {
1917 // get tank size (in liter)
1918 reading_tanksize = char_I_tank_size[reading_gas-1];
1919
1920 // get pressure drop as float, stripping flags (in 1/5120 bar/sec)
1921 reading_drop = (float)(int_I_pressure_drop[reading_index] & 0x0FFF);
1922
1923 // check if pressure drop is within range
1924 if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUT_OF_RANGE) )
1925 {
1926 // calculate SAC, 10 is factor to have result in 0.1 liter/min
1927 // 60 is factor for 60 seconds per 1 minute,
1928 // 5120 accounts for reading_drop being in 1/5120 bar/sec
1929 // 10*60/5120 = 60/512 = 15/128
1930 float_sac = reading_drop * 15/128 * reading_tanksize / pres_respiration_sac;
1931
1932 // limit result to 999 (99.9 liter/min)
1933 if ( float_sac >= 998.5 )
1934 {
1935 int_O_sac_rate = 999 + INT_FLAG_ATTENTION;
1936 }
1937 else
1938 {
1939 // convert float to integer
1940 int_O_sac_rate = (unsigned short)(float_sac + 0.5);
1941
1942 // set attention flag if exceeding SAC threshold, but only if pressure drop is not outdated
1943 if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED) )
1944 if( int_O_sac_rate >= max_sac_rate )
1945 {
1946 int_O_sac_rate |= INT_FLAG_ATTENTION;
1947 }
1948 }
1949 }
1950 else
1951 {
1952 // pressure drop is out of range, so SAC will be set out of range, too
1953 int_O_sac_rate = 999 + INT_FLAG_ATTENTION;
1954 }
1955
1956 // copy outdated flag from int_I_pressure_drop to int_O_sac_rate
1957 if( int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED )
1958 {
1959 int_O_sac_rate |= INT_FLAG_OUTDATED;
1960 }
1961 }
1962 }
1963 } // TR functions
1964
1965 #endif
1966
1967
1968 //---- End of Computations for the real Tissues -----------------------------------------------
1969 //
1970 //=============================================================================================
1971 //
1972 //---- Begin of Computations for Ascent and Decompression -------------------------------------
1973
1974 // branch to the code for the current phase the deco calculations are in, i.e.
1975 // toggle between calculating NDL (remaining bottom time), deco stops, and results
1618 switch( char_O_deco_status & DECO_STATUS_MASK ) 1976 switch( char_O_deco_status & DECO_STATUS_MASK )
1619 { 1977 {
1620 overlay unsigned char i; 1978 overlay unsigned char i;
1621 1979
1980 default:
1981
1622 case DECO_STATUS_INIT: //---- At surface: Start a new dive --------------------- 1982 case DECO_STATUS_INIT: //---- At surface: Start a new dive ---------------------
1623 1983
1624 // clear the internal stops table from remains lasting from the last dive 1984 // clear the internal stops table from remains lasting from the previous dive or deco calculator run
1625 clear_deco_table(); 1985 clear_deco_table();
1626 1986
1627 // publish the cleared stops table to the display functions 1987 // publish the cleared stops table to the display functions
1628 publish_deco_table(); 1988 publish_deco_table();
1629 1989
1630 // clear the gas needs table 1990 // clear the gas needs table
1631 for(i=0; i<NUM_GAS; ++i) 1991 for( i = 0; i < NUM_GAS; ++i )
1632 { 1992 {
1633 int_O_gas_volumes[i] = 0; 1993 int_O_ascent_volumes[i] = 0;
1634 int_O_tank_pres_need[i] = 0 + INT_FLAG_ZERO; 1994 int_O_ascent_pres_need[i] = 0 + INT_FLAG_ZERO;
1635 } 1995 }
1636 1996
1637 // initialize the balancing between N2 and He for later no-fly time calculation 1997 // safety limits to prevent eventual infinite looping (bricking the OSTC)
1638 for(i=0; i<NUM_COMP; ++i) 1998 if( char_I_ascent_speed < 5 ) char_I_ascent_speed = 5; // min. 5 m/min
1639 { 1999 if( char_I_deco_distance > 20 ) char_I_deco_distance = 20; // max. 20 dm (= 2 m)
1640 split_N2_He[i] = 90; // assumes 90% of total tissue pressure will be needed for N2 2000 if( char_I_desaturation_multiplier < 50 ) char_I_desaturation_multiplier = 50; // min. 50 %
1641 }
1642
1643 // ** UNDER CONSTRUCTION - temporary code only **
1644 char_I_gas_change_time = 1; // TODO: validate proper operation before enabling this options-table parameter
1645 char_I_ascent_speed = 10; // TODO: validate proper operation before enabling this options-table parameter,
1646 // caution: values < 10 may have an impact on the deco calculation run-times!
1647 2001
1648 // initialize values that are constant during the course of the dive 2002 // initialize values that are constant during the course of the dive
1649 float_ascent_speed = 1.00 * char_I_ascent_speed; 2003 float_ascent_speed = 1.00 * char_I_ascent_speed; // in meter/minute
1650 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier; 2004 float_deco_distance = 0.01 * char_I_deco_distance; // in bar
1651 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier; 2005 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier; // as factor, 1.0 = 100%
1652 float_deco_distance = 0.01 * char_I_deco_distance; 2006 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier; // as factor, 1.0 = 100%
1653 2007
1654 // initialize values that will be recalculated later on periodically 2008 // initialize values that will be recalculated later on periodically
1655 char_O_nullzeit = 0; // reset NDL time for the normal plan 2009 char_O_nullzeit = 0; // reset NDL time for the normal plan
1656 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan 2010 char_O_alternate_nullzeit = 0; // reset NDL time for the alternative plan
1657 int_O_ascenttime = 0; // reset ascent time for the normal plan 2011 int_O_ascenttime = 0; // reset ascent time for the normal plan
1658 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan 2012 int_O_alternate_ascenttime = 0; // reset ascent time for the alternative plan
1659 char_O_deco_warnings = 0; // reset all deco warnings 2013 char_O_deco_warnings = 0; // reset all deco warnings
1660 deco_tissue_vector = 0; // reset tissue deco vector 2014 char_O_deco_info = 0; // reset all deco infos
1661 IBCD_tissue_vector = 0; // reset tissue IBCD vector 2015 deco_tissue_vector = 0; // reset tissue deco vector
1662 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation 2016 IBCD_tissue_vector = 0; // reset tissue IBCD vector
2017 NDL_lead_tissue = 0; // reset first tissue to look at during NDL calculation
1663 2018
1664 // tag desaturation time as invalid (it will not be computed during a dive) 2019 // tag desaturation time as invalid (it will not be computed during a dive)
1665 int_O_desaturation_time = 65535; 2020 int_O_desaturation_time = 65535;
1666 2021
2022 // initialize values for first stop depth and GF slope
2023 low_depth_norm = 0.0; // reset depth of first stop in normal plan
2024 locked_GF_step_norm = 0.0; // reset GF slope in normal plan
2025 low_depth_alt = 0.0; // reset depth of first stop in alternative plan
2026 locked_GF_step_alt = 0.0; // reset GF slope in alternative plan
2027
1667 // initialize CNS values 2028 // initialize CNS values
1668 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction; 2029 int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1669
1670 // Values that should be reset just once for the full real dive.
1671 // This is used to record the lowest stop for the whole dive,
1672 // including ACCROSS all simulated ascents.
1673 low_depth_norm = low_depth_alt = 0.0;
1674 locked_GF_step_norm = locked_GF_step_alt = 0.0;
1675 2030
1676 // 2031 //
1677 // --> code execution continues in state DECO_STATUS_START 2032 // --> code execution continues in state DECO_STATUS_START
1678 // 2033 //
1679 2034
1680 case DECO_STATUS_START: //---- Bottom Time & initial Ascent -------------------- 2035 case DECO_STATUS_START: //---- Start a new deco calculation cycle --------------
1681 default:
1682 2036
1683 // clear the internal(!) stops table 2037 // clear the internal(!) stops table
1684 clear_deco_table(); 2038 clear_deco_table();
1685 2039
1686 // initialize the simulated tissues with the current state of the real tissues 2040 // initialize the simulated tissues with the current state of the real tissues
1687 for(i=0; i<NUM_COMP; i++) 2041 for( i = 0; i < NUM_COMP; i++ )
1688 { 2042 {
1689 sim_pres_tissue_N2[i] = pres_tissue_N2[i]; 2043 sim_pres_tissue_N2[i] = pres_tissue_N2[i];
1690 sim_pres_tissue_He[i] = pres_tissue_He[i]; 2044 sim_pres_tissue_He[i] = pres_tissue_He[i];
1691 } 2045 }
1692 2046
2047 // initialize the simulated CNS value with the current CNS of the real tissues
2048 sim_CNS_fraction = CNS_fraction;
2049
2050 // initialize the simulated depth with the current depth (in absolute pressure)
2051 sim_pres_respiration = real_pres_respiration;
2052
1693 // Lookup the current gas and store it also as the first gas used. 2053 // Lookup the current gas and store it also as the first gas used.
1694 // This gas will be used for the bottom segment of the dive and for 2054 // This gas will be used until gas_find_better() is invoked and finds
1695 // the period of delayed ascent when calculating fTTS or bailout. 2055 // a better gas to switch to.
1696 gas_find_current(); 2056 gas_find_current();
1697 2057
1698 // setup the calculation ratio's for N2, He and O2 (sim_N2/He/O2_ratio) 2058 // Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio).
2059 // These ratios will be used and remain valid to use until a gas switch
2060 // is done. Thus, if a call to gas_find_better() has found a better gas,
2061 // gas_set_ratios() needs to be called again.
1699 gas_set_ratios(); 2062 gas_set_ratios();
1700 2063
1701 // initialize depth in absolute pressure, it is needed by 2064 // Calculate the effect of extended bottom time due to delayed ascent,
1702 // - calc_alveolar_pressures(), 2065 // if requested.
1703 // - calc_ascent_to_first_stop(), and
1704 // - calc_hauptroutine_calc_deco()
1705 sim_pres_respiration = pres_respiration;
1706
1707 // calculate ppN2 and ppHe from sim_N2/He_ratio (<- tissue_increment has been set to 0)
1708 calc_alveolar_pressures();
1709
1710 // calculate the effect of extended bottom time due to delayed ascent
1711 if( char_O_deco_status & DECO_ASCENT_DELAYED ) 2066 if( char_O_deco_status & DECO_ASCENT_DELAYED )
1712 { 2067 {
1713 // program interval on simulated tissues (flag bit 7 = 0) 2068 // program interval on simulated tissues (flag bit 7 = 0)
1714 tissue_increment = char_I_extra_time; 2069 tissue_increment = char_I_extra_time;
1715 2070
2071 // calculate ppO2, ppN2 and ppHe from sim_N2/real_He_ratio
2072 calc_alveolar_pressures();
2073
1716 // update the tissues 2074 // update the tissues
1717 calc_tissues(); 2075 calc_tissues();
1718 } 2076
1719 2077 // update the CNS value
1720 // calculate if we are within no decompression limit (NDL) 2078 calc_CNS();
2079 }
2080
2081 // Calculate the remaining no decompression limit (NDL) time. calc_NDL_time()
2082 // is very fast in detecting if being beyond NDL, so there is enough time left
2083 // in this phase to do the initial ascent calculation if found to be outside NDL.
1721 calc_NDL_time(); 2084 calc_NDL_time();
1722 2085
1723 // Calculate the initial ascent if in deco. calc_NDL_time() is very fast
1724 // in detecting being beyond NDL, so there is enough time left in this
1725 // phase to do the initial ascent calculation.
1726 if( NDL_time == 0 ) 2086 if( NDL_time == 0 )
1727 { 2087 {
1728 //--- in deco -------------------------------------------------------- 2088 // calculate ascent to first stop using the set ascent rate,
1729 2089 // re-calculating the tissues and limits every minute along the ascent.
1730 // calculate ascent to first stop
1731 calc_ascent_to_first_stop(); 2090 calc_ascent_to_first_stop();
1732 2091
1733 // continue with calculating the stops 2092 // continue in next cycle(s) with calculating the initial ascent and stops
1734 char_O_deco_status &= ~DECO_STATUS_MASK; // clear status bits and set status bits for 2093 char_O_deco_status &= ~DECO_STATUS_MASK;
1735 char_O_deco_status |= DECO_STATUS_STOPS; // calculation of stops on next invocation 2094 char_O_deco_status |= DECO_STATUS_STOPS;
1736 } 2095 }
1737 else 2096 else
1738 { 2097 {
1739 //--- within NDL ----------------------------------------------------- 2098 // within NDL - continue in next cycle with gathering all results
1740
1741 // continue with gathering all results
1742 char_O_deco_status &= ~DECO_STATUS_MASK; 2099 char_O_deco_status &= ~DECO_STATUS_MASK;
1743 char_O_deco_status |= DECO_STATUS_RESULTS; 2100 char_O_deco_status |= DECO_STATUS_RESULTS;
1744 } 2101 }
1745 2102
1746 break; 2103 break;
1749 case DECO_STATUS_STOPS: //---- Calculate Stops --------------------------------- 2106 case DECO_STATUS_STOPS: //---- Calculate Stops ---------------------------------
1750 2107
1751 // calculate the stops 2108 // calculate the stops
1752 calc_hauptroutine_calc_deco(); 2109 calc_hauptroutine_calc_deco();
1753 2110
1754 // calc_hauptroutine_calc_deco iterates in this phase as long as it is 2111 // calc_hauptroutine_calc_deco() iterates in this phase as long as it is
1755 // calculating the stops. Once done, it will set the status to doing the 2112 // calculating the stops. Once done, it will set the status to doing the
1756 // results gathering. 2113 // results gathering.
1757 2114
1758 break; 2115 break;
1759 2116
1760 2117
1761 case DECO_STATUS_RESULTS: //--- Gathering of all Results ----------------------- 2118 case DECO_STATUS_RESULTS: //--- Gather Results ---------------------------------
1762 2119
1763 // if in normal plan, publish the stops table to the display functions 2120 // if in normal plan, publish the stops table
1764 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) ) publish_deco_table(); 2121 if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) )
1765 2122 {
1766 // The current depth is needed by calc_CNS_planning() and gas_volumes(). 2123 // publish the stops table to the display functions
1767 // As it may be needed in different code blocks below but we don't want 2124 publish_deco_table();
1768 // it to be in the code multiple times, it's done here on stockpile. 2125
1769 bottom_depth = (unsigned char)((pres_respiration - pres_surface) * BAR_TO_METER); 2126 // When entering deco and the ceiling depth becomes > 0 but the
1770 2127 // deco calculation reveals no distinct deco stop yet because
1771 // Calculate the ascent time. 2128 // the deco obligation will vanish during the ascent, create an
1772 // When within NDL, potential gas switches will be treated as done "on the fly". 2129 // artificial stop to signal that expedite surfacing ("popping
1773 calc_ascenttime(); 2130 // up") is not allowed anymore.
2131 if( char_O_first_deco_depth == 0 ) // simulation reveals no stop required
2132 if( int_O_ceiling > 0 ) // real status reveals a ceiling
2133 {
2134 // set a pro forma stop at 3 meters
2135 char_O_first_deco_depth = 3;
2136
2137 // set a stop time of 0 minute, this will be displayed as "..'"
2138 char_O_first_deco_time = 0;
2139 }
2140 }
2141
2142 // The current depth is needed by calc_ascenttime() and gas_volumes(). As we
2143 // don't want it to be calculated multiple times, it's done here on stockpile.
2144 char_bottom_depth = (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER + 0.5);
1774 2145
1775 // results to publish depend whether within NDL or in deco 2146 // results to publish depend whether within NDL or in deco
1776 if( NDL_time ) 2147 if( NDL_time )
1777 { 2148 {
1778 //---- within NDL ---------------------------------------------- 2149 //---- within NDL ----------------------------------------------
1779
1780 // Calculate the initial ascent (not yet done when within NDL) -
1781 // just to get potential gas switches into the stops table for use
1782 // by gas_volumes(). The stops table can be polluted by now because
1783 // the clean table has already been published to the display
1784 // functions before.
1785 calc_ascent_to_first_stop();
1786 2150
1787 // check which plan we are on 2151 // check which plan we are on
1788 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) 2152 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1789 { 2153 {
1790 //---- alternate dive plan --------------------------------- 2154 //---- alternate dive plan ---------------------------------
1791 2155
1792 // As we are in no stop, CNS at end of dive is more or less
1793 // the same CNS as we have right now. It's so simple that we
1794 // don't check if it requested to be computed or not...
1795 int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1796
1797 // output NDL time 2156 // output NDL time
1798 char_O_alternate_nullzeit = NDL_time; 2157 char_O_alternate_nullzeit = NDL_time;
1799 2158
1800 // clear ascent time 2159 // clear ascent time
1801 int_O_alternate_ascenttime = 0; 2160 int_O_alternate_ascenttime = 0;
2161
2162 // As we are in no stop, CNS at end of dive is more or less
2163 // the same CNS as we have right now.
2164 int_O_alternate_CNS_fraction = int_O_CNS_fraction;
1802 } 2165 }
1803 else 2166 else
1804 { 2167 {
1805 //---- normal dive plan ------------------------------------ 2168 //---- normal dive plan ------------------------------------
1806 2169
1807 // As we are in no stop, CNS at end of dive is more or less
1808 // the same CNS as we have right now. It's so simple that we
1809 // don't check if it requested to be computed or not...
1810 int_O_normal_CNS_fraction = int_O_CNS_fraction;
1811
1812 // output NDL time 2170 // output NDL time
1813 char_O_nullzeit = NDL_time; 2171 char_O_nullzeit = NDL_time;
1814 2172
1815 // clear ascent time 2173 // clear ascent time
1816 int_O_ascenttime = 0; 2174 int_O_ascenttime = 0;
2175
2176 // As we are in no stop, CNS at end of dive is more or less
2177 // the same CNS as we have right now.
2178 int_O_normal_CNS_fraction = int_O_CNS_fraction;
1817 } 2179 }
1818 } // NDL 2180 } // NDL
1819 else 2181 else
1820 { 2182 {
1821 //---- in DECO ------------------------------------------------- 2183 //---- in DECO -------------------------------------------------
2184
2185 // calculate the ascent time
2186 calc_ascenttime();
1822 2187
1823 // check which plan we are on 2188 // check which plan we are on
1824 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) 2189 if( char_O_deco_status & DECO_PLAN_ALTERNATE )
1825 { 2190 {
1826 //---- alternative plan ---------------------------------------------------- 2191 //---- alternative plan ----------------------------------------------------
1827 2192
1828 // clear NDL time 2193 // clear the NDL time
1829 char_O_alternate_nullzeit = 0; 2194 char_O_alternate_nullzeit = 0;
1830 2195
1831 // output ascent time 2196 // export the ascent time
1832 int_O_alternate_ascenttime = ascent_time; 2197 int_O_alternate_ascenttime = ascent_time;
1833 2198
1834 // shall the CNS at the end of the dive be calculated? 2199 // convert the CNS value to integer for export
1835 if( char_O_deco_status & DECO_CNS_CALCULATE ) 2200 convert_sim_CNS_for_display();
1836 { 2201
1837 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction 2202 // export the integer CNS value
1838 calc_CNS_planning(); 2203 int_O_alternate_CNS_fraction = int_sim_CNS_fraction;
1839
1840 // add current CNS value
1841 sim_CNS_fraction += CNS_fraction;
1842
1843 // convert to integer value
1844 convert_sim_CNS_for_display();
1845
1846 // export result
1847 int_O_alternate_CNS_fraction = int_sim_CNS_fraction;
1848 }
1849 2204
1850 } // alternative plan 2205 } // alternative plan
1851 else 2206 else
1852 { 2207 {
1853 //---- normal plan --------------------------------------------------------- 2208 //---- normal plan ---------------------------------------------------------
1854 2209
1855 // clear NDL time 2210 // clear the NDL time
1856 char_O_nullzeit = 0; 2211 char_O_nullzeit = 0;
1857 2212
1858 // output ascent time 2213 // export the ascent time
1859 int_O_ascenttime = ascent_time; 2214 int_O_ascenttime = ascent_time;
1860 2215
1861 // shall the CNS at the end of the dive be calculated? 2216 // convert the CNS value to integer for export
1862 if( char_O_deco_status & DECO_CNS_CALCULATE ) 2217 convert_sim_CNS_for_display();
1863 { 2218
1864 // calculate the CNS for the predicted ascent, result in sim_CNS_fraction 2219 // export the integer CNS value
1865 calc_CNS_planning(); 2220 int_O_normal_CNS_fraction = int_sim_CNS_fraction;
1866
1867 // add current CNS value
1868 sim_CNS_fraction += CNS_fraction;
1869
1870 // convert to integer value
1871 convert_sim_CNS_for_display();
1872
1873 // export result
1874 int_O_normal_CNS_fraction = int_sim_CNS_fraction;
1875 }
1876 2221
1877 } // normal plan 2222 } // normal plan
1878 } // DECO 2223 } // NDL / DECO
1879 2224
1880 // if requested, calculate the required gas volumes and tank pressures at the end of the dive 2225
1881 if( char_O_deco_status & DECO_VOLUME_CALCULATE ) gas_volumes(); 2226 // Check if deco obligation is steady or decreasing. This works only when an alternative plan is enabled and
1882 2227 // if it is not a bailout plan, thus DECO_BAILOUT_MODE must not be set while doing the DECO_PLAN_ALTERNATE.
1883 // signal that the computation cycle is finished 2228 if( (char_O_deco_status & DECO_PLAN_ALTERNATE) && !(char_O_deco_status & DECO_BAILOUT_MODE) )
2229 {
2230 // Set DECO_DECREASING flag when fTTS < TTS and DECO_STEADY flag when fTTS = TTS.
2231 if ( int_O_alternate_ascenttime < int_O_ascenttime ) char_O_deco_info |= DECO_DECREASING;
2232 else if ( int_O_alternate_ascenttime == int_O_ascenttime ) char_O_deco_info |= DECO_STEADY;
2233 }
2234
2235 // Clear DECO_DECREASING flag when fTTS >= TTS and DECO_STEADY flag when fTTS > TTS.
2236 // This works in any planning mode combination.
2237 if ( int_O_alternate_ascenttime > int_O_ascenttime ) char_O_deco_info &= ~(DECO_DECREASING + DECO_STEADY);
2238 else if ( int_O_alternate_ascenttime == int_O_ascenttime ) char_O_deco_info &= ~(DECO_DECREASING );
2239
2240 // If requested, calculate the required gas volumes and tank pressures at the end of the dive.
2241 if( char_O_deco_status & DECO_VOLUME_CALCULATE )
2242 {
2243 // When in bailout mode and within NDL, find the gas changes along the ascent and put
2244 // them into the stops table for use by gas_volumes(). The stops table can be "polluted"
2245 // by now because the table has already been published in "clean" state before.
2246 if( (NDL_time) && ( char_O_deco_status & DECO_BAILOUT_MODE ) )
2247 {
2248 // find the gas changes and put them into the stops table
2249 find_NDL_gas_changes();
2250 }
2251
2252 // calculate the required gas volumes and tank pressures
2253 gas_volumes();
2254 }
2255
2256 // set the computation cycle to finished
1884 char_O_deco_status &= ~DECO_STATUS_MASK; 2257 char_O_deco_status &= ~DECO_STATUS_MASK;
2258
2259 // set flag indicating that deco calculation has been completed
2260 if( char_O_deco_status & DECO_PLAN_ALTERNATE ) char_O_main_status |= DECO_COMPLETED_ALT;
2261 else char_O_main_status |= DECO_COMPLETED_NORM;
2262
1885 2263
1886 break; 2264 break;
1887 2265
1888 } // switch 2266 } // switch
1889 } 2267 }
1896 // 2274 //
1897 void calc_hauptroutine_data_input(void) 2275 void calc_hauptroutine_data_input(void)
1898 { 2276 {
1899 overlay float IG_ratio; 2277 overlay float IG_ratio;
1900 2278
2279 // safety limits to prevent eventual infinite looping (bricking the OSTC)
2280 if( int_I_pres_surface < 500) int_I_pres_surface = 500; // min. surface pressure = 500 mbar
2281 if( int_I_pres_respiration < 500) int_I_pres_respiration = 500; // min. respiration pressure = 500 mbar
2282
2283 // safe-guard further parameters to protect the tissue-flag
2284 if( char_I_sim_advance_time > 127 ) char_I_sim_advance_time = 127;
2285 if( char_I_extra_time > 127 ) char_I_extra_time = 127;
2286 if( char_I_gas_change_time > 99 ) char_I_gas_change_time = 99;
2287
1901 // get the current pressures 2288 // get the current pressures
1902 pres_surface = 0.001 * int_I_pres_surface; 2289 pres_surface = 0.001 * int_I_pres_surface;
1903 pres_respiration = 0.001 * int_I_pres_respiration; 2290 real_pres_respiration = 0.001 * int_I_pres_respiration;
1904 2291
1905 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling 2292 // N2 tissue pressure at surface equilibrium, used for tissue graphics scaling
1906 N2_equilibrium = 0.7902 * (pres_surface - ppWater); 2293 N2_equilibrium = 0.7902 * (pres_surface - ppWater);
1907 2294
1908 // read the GF settings (they may have been switch between GF/aGF) 2295 // read the GF settings (they may have been switch between GF/aGF)
1909 GF_high = 0.01 * char_I_GF_High_percentage; 2296 GF_high = 0.01 * char_I_GF_High_percentage;
1910 GF_low = 0.01 * char_I_GF_Low_percentage; 2297 GF_low = 0.01 * char_I_GF_Low_percentage;
1911 GF_delta = GF_high - GF_low; 2298 GF_delta = GF_high - GF_low;
1912 2299
1913 // get the currently breathed gas mixture 2300 // get the currently breathed gas mixture
1914 O2_ratio = 0.01 * char_I_O2_ratio; 2301 real_O2_ratio = 0.01 * char_I_O2_ratio;
1915 He_ratio = 0.01 * char_I_He_ratio; 2302 real_He_ratio = 0.01 * char_I_He_ratio;
1916 2303
1917 // inert gas ratio (local helper variable) 2304 // inert gas ratio (local helper variable)
1918 IG_ratio = 1.00 - O2_ratio; 2305 IG_ratio = 1.00 - real_O2_ratio;
1919 2306
1920 // N2 ratio 2307 // N2 ratio
1921 N2_ratio = IG_ratio - He_ratio; 2308 real_N2_ratio = IG_ratio - real_He_ratio;
1922 2309
1923 // precomputed values for ppO2 drop in pSCR loop 2310 // compute values for ppO2 drop in pSCR loop
1924 float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio; 2311 real_pSCR_drop = IG_ratio * float_pSCR_factor;
1925 pSCR_drop = IG_ratio * float_pSCR_factor; 2312 }
1926 } 2313
1927 2314
1928 2315 //////////////////////////////////////////////////////////////////////////////
1929 ////////////////////////////////////////////////////////////////////////////// 2316 // Compute stops
1930 // Compute stops. 2317 //
1931 // 2318 // Note: because this can be very long, break on 16 iterations, or after
1932 // Note: because this can be very long, break on 16 iterations, and set state 2319 // 512 ms, whichever comes first. Set state to DECO_STATUS_RESULTS
1933 // to DECO_STATUS_FINISHED when finished, or to DECO_STATUS_STOPS when 2320 // when finished, or keep DECO_STATUS_STOPS when needing to continue.
1934 // needing to continue.
1935 // Note: because each iteration might be very long too (~ 66 ms in 1.84beta),
1936 // break the loop when elapsed time exceeds 512 milliseconds.
1937 // 2321 //
1938 void calc_hauptroutine_calc_deco(void) 2322 void calc_hauptroutine_calc_deco(void)
1939 { 2323 {
1940 overlay unsigned char loop; 2324 overlay unsigned char loop;
1941 2325
1942 2326 for( loop = 0; loop < 16; ++loop )
1943 for(loop = 0; loop < 16; ++loop) 2327 {
1944 { 2328 // limit execution time to 512 ms using timer 5
1945 // limit loops to 512ms, using timer 5
1946 if( tmr5() & (512*32) ) break; 2329 if( tmr5() & (512*32) ) break;
1947 2330
1948 // calc_nextdecodepth() 2331 // calc_nextdecodepth()
1949 // 2332 //
1950 // INPUT sim_pres_respiration : current depth in absolute pressure 2333 // INPUT sim_pres_respiration : current depth in absolute pressure
1951 // OUTPUT sim_depth_limit : depth of next stop in meters 2334 // OUTPUT sim_depth_limit : depth of next stop in meters (if RETURN = true)
1952 // RETURN true if a stop is needed 2335 // next depth without need of a stop (if RETURN = false)
2336 // RETURN true if a stop is needed, else false
1953 // 2337 //
1954 // The function manages gas changes by itself, including priming 2338 // The function manages gas changes by itself, including priming
1955 // the deco stop with the configured gas change time. 2339 // the deco stop with the configured gas change time.
1956 // 2340 //
1957 if( calc_nextdecodepth() ) 2341 if( calc_nextdecodepth() )
1958 { 2342 {
1959 if( sim_depth_limit == 0 ) goto Surface; // this check should not bee needed as in 2343 // this check should not be needed as in this case the RETURN value will be false
1960 // this case the RETURN value will be false 2344 if( sim_depth_limit == 0 ) goto Surface;
1961 2345
1962 //---- stop required at sim_depth_limit ------------------------------------- 2346 //---- stop required at sim_depth_limit ----------------------
1963 2347
1964 // convert stop depth in meters to absolute pressure 2348 // convert stop depth in meters to absolute pressure
1965 sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface; 2349 sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface;
1966 2350
1967 // add one minute to the current stop, or add a new stop, 2351 // Add one minute to the current stop, or add a new stop,
1968 // or abort deco calculation if the deco table is full. 2352 // or abort deco calculation if the deco table is full.
1969 if( !update_deco_table(1) ) goto Surface; 2353 if( !update_deco_table(1) ) goto Surface;
1970 } 2354 }
1971 else 2355 else
1972 { 2356 {
1985 2369
1986 return; 2370 return;
1987 } 2371 }
1988 } 2372 }
1989 2373
1990 2374 //---- as one minute as passed now, update the tissues -----------
1991 //---- as one minute as passed now, update the tissues ---------------------- 2375
1992 2376 // program 1 minute interval on simulated tissues
1993 // program 1 minute interval on simulated tissues (Flagbit 7 = 0)
1994 tissue_increment = 1; 2377 tissue_increment = 1;
1995 2378
1996 // compute current ppN2 and ppHe 2379 // compute current ppO2, ppN2 and ppHe
1997 calc_alveolar_pressures(); 2380 calc_alveolar_pressures();
1998 2381
1999 // update the tissues 2382 // update the tissues
2000 calc_tissues(); 2383 calc_tissues();
2001 } 2384
2002 } 2385 // update the CNS value
2003 2386 calc_CNS();
2004 2387 }
2005 ////////////////////////////////////////////////////////////////////////////// 2388 }
2006 // Calculate ascent to first deco stop. 2389
2007 // 2390
2008 // 2391 //////////////////////////////////////////////////////////////////////////////
2009 // Modified: sim_pres_respiration : current depth in ascent and deco simulation, in bar absolute pressure 2392 // Find gas changes on an NDL ascent
2393 //
2394 // This function is a variant of calc_ascent_to_first_stop() to be used solely
2395 // for finding the gas changes in an OC bailout ascent that is within NDL.
2396 //
2397 // Input : char_bottom_depth : depth at which the ascent starts, in meters
2398 //
2399 // Output : gas change stops put into stops table
2400 //
2401 // Destroyed: sim_depth_limit
2402 // sim_gas_current
2403 // sim_gas_current_depth
2404 //
2405 void find_NDL_gas_changes(void)
2406 {
2407 overlay unsigned char old_depth_limit;
2408
2409 // set gas to start with
2410 gas_find_current();
2411
2412 // loop in ascending until reaching a depth of 3 meters, no gas switches considered thereafter
2413 for( sim_depth_limit = char_bottom_depth; sim_depth_limit >= 3; )
2414 {
2415 // memorize the depth we came from
2416 old_depth_limit = sim_depth_limit;
2417
2418 // ascent - initially in steps of 10 m, then slowing down to 1 m steps to not miss a O2 gas
2419 if( sim_depth_limit > 10 ) sim_depth_limit -= 10;
2420 else sim_depth_limit -= 1;
2421
2422 // check if there is a better gas to switch to
2423 if( gas_find_better() )
2424 {
2425 // adjust sim_depth_limit to the gas change depth, but not deeper than the depth we came from
2426 sim_depth_limit = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
2427
2428 // create a stop for the gas change in the stops table
2429 update_deco_table(char_I_gas_change_time);
2430 }
2431 } // for()
2432 }
2433
2434
2435 //////////////////////////////////////////////////////////////////////////////
2436 // Calculate ascent to first deco stop
2437 //
2438 // Modified : sim_pres_respiration : current depth in ascent and deco simulation, in bar absolute pressure
2439 //
2440 // Output : sim_depth_limit : depth in meters of the 1st stop, if a stop is found
2441 //
2442 // Destroyed: tissue_increment : tissue and update period selector
2010 // 2443 //
2011 void calc_ascent_to_first_stop(void) 2444 void calc_ascent_to_first_stop(void)
2012 { 2445 {
2013 overlay unsigned char fast = 1; // 1 = 1 minute steps, 0 = 2 seconds steps 2446 overlay float old_pres_respiration;
2014 overlay unsigned char gaschange = 0; // 1 = do a gas change, 0 = no better gas available 2447 overlay unsigned char fast = 1; // 0: 2 seconds step, 1: 1 minute step
2015 2448
2016 2449 // target the simulated tissues
2017 //---- Loop until first deco stop or surface is reached ---------- 2450 tissue_increment = 0;
2451
2452 // loop until first deco stop or the surface is reached
2018 for(;;) 2453 for(;;)
2019 { 2454 {
2020 // depth in absolute pressure we came from 2455 // memorize depth in absolute pressure we came from
2021 overlay float old_deco = sim_pres_respiration; 2456 old_pres_respiration = sim_pres_respiration;
2022 2457
2023 // try ascending 1 full minute (fast) or 2 seconds (!fast) 2458 // try ascending 1 full minute (fast) or 2 seconds (!fast)
2024 if ( fast ) sim_pres_respiration -= float_ascent_speed * METER_TO_BAR; // 1 min at float_ascent_speed ( 5 .. 10 m/min) 2459 if( fast ) sim_pres_respiration -= float_ascent_speed * METER_TO_BAR; // 1 min at float_ascent_speed ( 5 .. 10 m)
2025 else sim_pres_respiration -= (float_ascent_speed/30.0) * METER_TO_BAR; // 2 sec at float_ascent_speed (17 .. 33 cm/min) 2460 else sim_pres_respiration -= 0.0333 * float_ascent_speed * METER_TO_BAR; // 2 sec at float_ascent_speed (17 .. 33 cm)
2026 2461
2027 // but don't go over surface 2462 // but don't go over surface
2028 if( sim_pres_respiration < pres_surface ) sim_pres_respiration = pres_surface; 2463 if( sim_pres_respiration < pres_surface ) sim_pres_respiration = pres_surface;
2029 2464
2030 // compute current ceiling of the simulated tissues 2465 // compute ceiling of the simulated tissues
2031 if ( char_I_deco_model != 0 ) calc_limit(GF_low); 2466 if( char_I_deco_model != 0 ) calc_limit(GF_low);
2032 else calc_limit(1.0); 2467 else calc_limit(1.0);
2033 2468
2034 // did we overshoot the first deco stop? 2469 // did we overshoot the ceiling?
2035 if( sim_pres_respiration < (sim_ceiling + pres_surface) ) 2470 if( sim_pres_respiration < (ceiling + pres_surface) )
2036 { 2471 {
2037 // YES - back to last depth below first stop 2472 // YES - back to memorized depth
2038 sim_pres_respiration = old_deco; 2473 sim_pres_respiration = old_pres_respiration;
2039 2474
2040 // switch to 2 seconds ascent if not yet in, else done 2475 // switch to 2 seconds ascent if not yet in, else done
2041 if( fast ) 2476 if( fast )
2042 { 2477 {
2043 fast = 0; // retry with 2 seconds ascent steps 2478 fast = 0; // ascent with 2 seconds ascent steps
2044 continue; 2479 continue;
2045 } 2480 }
2046 else 2481 else
2047 { 2482 {
2048 break; // done... 2483 break; // done, stop required
2049 } 2484 }
2050 } 2485 }
2051 2486
2052 // If code execution passes along here, we did not overshoot the first stop. 2487 // if code execution passes along here, we did not overshoot the ceiling
2053 2488
2054 // did we reach the surface? if yes, done! 2489 // did we reach the surface? If yes, deco has vanished, no stop required, done.
2055 if( sim_pres_respiration == pres_surface ) break; 2490 if( sim_pres_respiration == pres_surface ) break;
2056 2491
2057 // depth in meters where we are now (no round-up) 2492 // depth in meters where we are now (no round-up)
2058 sim_depth_limit = (unsigned char)((sim_pres_respiration - pres_surface) * BAR_TO_METER); 2493 sim_depth_limit = (unsigned char)((sim_pres_respiration - pres_surface) * BAR_TO_METER);
2059 2494
2060 // Check if there is a better gas to switch to, but only in alternative plan mode 2495 // program interval on simulated tissues:
2061 // or if override is set. If yes, introduce a stop for the gas change. 2496 // fast = 1 -> 1 minute,
2062 if( (char_O_deco_status & DECO_PLAN_ALTERNATE) || (char_O_main_status & DECO_GASCHANGE_OVRD) ) 2497 // fast = 0 -> 2 seconds
2498 tissue_increment = fast;
2499
2500 // Check if there is a better gas to switch to, but only if bailout mode is enabled.
2501 // If yes, introduce a stop for the gas change.
2502 if( char_O_deco_status & DECO_BAILOUT_MODE )
2063 if( gas_find_better() ) 2503 if( gas_find_better() )
2064 { 2504 {
2065 // depth in meters we came from 2505 overlay unsigned char old_depth_limit;
2066 overlay unsigned char old_depth_limit = (unsigned char)((old_deco - pres_surface) * BAR_TO_METER);
2067
2068 // adjust sim_depth_limit to the gas change depth, but not deeper than the depth we came from
2069 sim_depth_limit = (sim_gas_last_depth < old_depth_limit) ? sim_gas_last_depth : old_depth_limit;
2070
2071 // create a stop for the gas change
2072 update_deco_table(char_I_gas_change_time);
2073 2506
2074 // set the new calculation values for N2, He and O2 2507 // set the new calculation values for N2, He and O2
2075 gas_set_ratios(); 2508 gas_set_ratios();
2076 2509
2077 // signal to create a stop for the gas change and update the tissues 2510 // add gas change time: a gas change time of
2078 gaschange = char_I_gas_change_time; 2511 // 0 minutes will keep the 1 minute / 2 seconds interval selection,
2079 2512 // >= 1 minute will add the the 1 minute interval but overrule a 2 seconds interval.
2080 // Adjust the depth for the tissue update to the stop depth. In case of fast mode, this 2513 tissue_increment += char_I_gas_change_time;
2081 // imposes that the ascent from the 'old_deco' depth to this stop took 1 minute although 2514
2082 // we might have only ascended one or two meters... 2515 // depth in meters we came from
2516 old_depth_limit = (unsigned char)((old_pres_respiration - pres_surface) * BAR_TO_METER);
2517
2518 // adjust sim_depth_limit to the gas change depth, but not deeper than the depth we came from
2519 sim_depth_limit = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
2520
2521 // Adjust the depth for the tissue update to the current depth. In case of fast mode,
2522 // this imposes that the ascent from the 'old_pres_respiration' depth to this depth
2523 // took one minute although we might have only ascended one or two meters...
2083 sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface; 2524 sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface;
2084 } 2525
2085 2526 // create a stop for the gas change in the stops table
2086 // Did one minute pass by and/or do we have a gas change? 2527 update_deco_table(char_I_gas_change_time);
2087 // Remark: The 2 seconds ascent iterations towards the first deco stop in !fast speed may take 2528 }
2088 // up to 28 seconds in total - for this rough half of a minute no tissue updates will be computed. 2529
2089 // Well, it could be done by setting tissue_increment = 0 in !fast condition and making calls to 2530 // omit the 2 seconds interval updates (do only updates for >= 1 minute)
2090 // calc_alveolar_pressures() and calc_tissues() - see code commented out below. 2531 // It's a trade-off between computational effort and accuracy...
2091 if( fast || gaschange ) 2532 if( tissue_increment )
2092 { 2533 {
2093 // program interval on simulated tissues (flag bit 7 = 0) 2534 // compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration
2094 tissue_increment = fast + gaschange;
2095
2096 // clear gas change signal
2097 gaschange = 0;
2098 // }
2099 // else
2100 // {
2101 // // program 2 seconds interval on simulated tissues (flag bit 7 = 0)
2102 // tissue_increment = 0;
2103 // }
2104 // {
2105 // compute ppN2/ppHe for current depth from sim_pres_respiration
2106 calc_alveolar_pressures(); 2535 calc_alveolar_pressures();
2107 2536
2108 // update the tissues 2537 // update the tissues
2109 calc_tissues(); 2538 calc_tissues();
2110 } 2539
2111 } 2540 // update the CNS value
2541 calc_CNS();
2542 }
2543
2544 } // for()
2112 } 2545 }
2113 2546
2114 2547
2115 ////////////////////////////////////////////////////////////////////////////// 2548 //////////////////////////////////////////////////////////////////////////////
2116 // calc_tissues 2549 // calc_tissues
2137 2570
2138 assert( 0.00 <= ppN2 && ppN2 < 11.2 ); // 80% N2 at 130m 2571 assert( 0.00 <= ppN2 && ppN2 < 11.2 ); // 80% N2 at 130m
2139 assert( 0.00 <= ppHe && ppHe < 12.6 ); // 90% He at 130m 2572 assert( 0.00 <= ppHe && ppHe < 12.6 ); // 90% He at 130m
2140 2573
2141 2574
2142 for (ci=0;ci<NUM_COMP;ci++) // iterate through all compartments 2575 for( ci=0; ci < NUM_COMP; ci++ ) // iterate through all compartments
2143 { 2576 {
2144 i = tissue_increment & TIME_MASK; // extract number of minutes to do (if i > 0) 2577 i = tissue_increment & TIME_MASK; // extract number of minutes to do (if i > 0)
2145 // or if one 2 second period is to do (if i = 0) 2578 // or if one 2 second period is to do (if i = 0)
2146 2579
2147 if( i == 0 ) // check if we shall do one 2-seconds period 2580 if( i == 0 ) // check if we shall do one 2-seconds period
2228 } 2661 }
2229 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing 2662 else if ( temp_tissue > +HYST ) // check if the tissue in on-gassing
2230 { 2663 {
2231 deco_tissue_vector &= ~(1 << ci); // tag tissue as not being in decompression 2664 deco_tissue_vector &= ~(1 << ci); // tag tissue as not being in decompression
2232 2665
2233 if( ((temp_tissue_N2 > 0.0) && (temp_tissue_He < 0.0)) // check for counter diffusion 2666 if( ((temp_tissue_N2 > 0.0) && (temp_tissue_He < 0.0)) // check for counter diffusion
2234 || ((temp_tissue_N2 < 0.0) && (temp_tissue_He > 0.0)) ) 2667 || ((temp_tissue_N2 < 0.0) && (temp_tissue_He > 0.0)) )
2235 { 2668 {
2236 IBCD_tissue_vector |= (1 << ci); // tag tissue as experiencing mentionable IBCD 2669 IBCD_tissue_vector |= (1 << ci); // tag tissue as experiencing mentionable IBCD
2237 } 2670 }
2238 } 2671 }
2239 2672
2240 2673
2241 // keep the saturating / desaturating flags from last invocation 2674 // keep the saturating / desaturating flags from last invocation
2242 char_O_tissue_N2_saturation[ci] &= 128; 2675 char_O_tissue_N2_saturation[ci] &= 128;
2243 char_O_tissue_He_saturation[ci] &= 128; 2676 char_O_tissue_He_saturation[ci] &= 128;
2244 2677
2245 // flip the flags applying a hysteresis of HYST (actual value: see #define of HYST) 2678 // flip the flags applying a hysteresis of HYST (actual value: see #define of HYST)
2246 if( temp_tissue_N2 > +HYST ) char_O_tissue_N2_saturation[ci] = 128; // set flag for tissue pressure is increasing 2679 if( temp_tissue_N2 > +HYST ) char_O_tissue_N2_saturation[ci] = 128; // set flag for tissue pressure is increasing
2247 else if( temp_tissue_N2 < -HYST ) char_O_tissue_N2_saturation[ci] = 0; // clear flag (-> tissue pressure is decreasing) 2680 else if( temp_tissue_N2 < -HYST ) char_O_tissue_N2_saturation[ci] = 0; // clear flag (-> tissue pressure is decreasing)
2248 2681
2250 else if( temp_tissue_He < -HYST ) char_O_tissue_He_saturation[ci] = 0; // clear flag (-> tissue pressure is decreasing) 2683 else if( temp_tissue_He < -HYST ) char_O_tissue_He_saturation[ci] = 0; // clear flag (-> tissue pressure is decreasing)
2251 2684
2252 2685
2253 // For N2 tissue display purpose: 2686 // For N2 tissue display purpose:
2254 // Scale tissue press so that saturation in 70m on AIR gives a value of approx. 80. 2687 // Scale tissue press so that saturation in 70m on AIR gives a value of approx. 80.
2255 // The surface steady-state tissue loading of [0.7902 * (pres_respiration - ppWater)] bar 2688 // The surface steady-state tissue loading of [0.7902 * (real_pres_respiration - ppWater)] bar
2256 // gives then a 10. If N2 is completely washed out of the tissue, result will be 0. 2689 // gives then a 10. If N2 is completely washed out of the tissue, result will be 0.
2257 // This scaling is adapted to the capabilities of the tissue graphics in the custom views. 2690 // This scaling is adapted to the capabilities of the tissue graphics in the custom views.
2258 temp_tissue = (pres_tissue_N2[ci] / N2_equilibrium) * 10; 2691 temp_tissue = (pres_tissue_N2[ci] / N2_equilibrium) * 10;
2259 2692
2260 // limit to 127 to leave space for sat/desat flag 2693 // limit to 127 to leave space for sat/desat flag
2269 // With no He in a tissue, result will be 0. 2702 // With no He in a tissue, result will be 0.
2270 // This scaling is adapted to the capabilities of the tissue graphics in the custom views. 2703 // This scaling is adapted to the capabilities of the tissue graphics in the custom views.
2271 temp_tissue = pres_tissue_He[ci] * 7.7; 2704 temp_tissue = pres_tissue_He[ci] * 7.7;
2272 2705
2273 // limit to 127 to leave space for sat/desat flag 2706 // limit to 127 to leave space for sat/desat flag
2274 if (temp_tissue > 127) temp_tissue = 127; 2707 if (temp_tissue > 127) temp_tissue = 127;
2275 2708
2276 // export as integer 2709 // export as integer
2277 char_O_tissue_He_saturation[ci] += (unsigned char)temp_tissue; 2710 char_O_tissue_He_saturation[ci] += (unsigned char)temp_tissue;
2278 } //if 2711 } //if
2279 2712
2280 } // for 2713 } // for
2281
2282
2283 // set deco flag if we are in deco and at least one of the real tissues is off-gassing
2284 // clear deco flag if all of the real tissues are on-gassing
2285 if ( (char_O_nullzeit == 0) && deco_tissue_vector ) char_O_deco_warnings |= DECO_FLAG;
2286 else if ( !deco_tissue_vector ) char_O_deco_warnings &= ~DECO_FLAG;
2287 } 2714 }
2288 2715
2289 ////////////////////////////////////////////////////////////////////////////// 2716 //////////////////////////////////////////////////////////////////////////////
2290 // calc_limit 2717 // calc_limit
2291 // 2718 //
2293 // tissue_increment : selector for context: real or simulated tissues 2720 // tissue_increment : selector for context: real or simulated tissues
2294 // sim_pres_tissue_N2/_He : tissue pressures (used in simulated tissues context) 2721 // sim_pres_tissue_N2/_He : tissue pressures (used in simulated tissues context)
2295 // pres_tissue_N2/_He : tissue pressures (used in real tissues context) 2722 // pres_tissue_N2/_He : tissue pressures (used in real tissues context)
2296 // 2723 //
2297 // Output: 2724 // Output:
2298 // sim_ceiling : ceiling in bar relative pressure (only in simulated tissues context) 2725 // lead_supersat : supersaturation of the leading tissue, 1.0 = 100%
2299 // ceiling : ceiling in bar relative pressure (only in real tissues context) 2726 // ceiling : ceiling in bar relative pressure
2300 // int_O_ceiling : ceiling in mbar relative pressure (only in real tissues context)
2301 // int_O_gradient_factor : gradient factor in % (only in real tissues context)
2302 // 2727 //
2303 // Modified: 2728 // Modified:
2304 // char_O_deco_warnings : for IBCD, microbubbles and outside warning (only in real tissues context) 2729 // char_O_deco_warnings : for IBCD, microbubbles and outside warning (only in real tissues context)
2305 // 2730 //
2306 static void calc_limit(PARAMETER float GF_parameter) 2731 static void calc_limit(PARAMETER float GF_parameter)
2307 { 2732 {
2308 overlay float lead_tissue_limit = 0.0; 2733 overlay float lead_tissue_limit = 0.0;
2309 overlay float lead_supersat = 0.0; 2734
2310 2735
2311 overlay unsigned char lead_tissue_no = 0; 2736 // set leading tissue number to not yet computed
2312 2737 lead_number = 0;
2738
2739 // initialize leading tissue supersaturation value to null
2740 lead_supersat = 0.0;
2313 2741
2314 // check context 2742 // check context
2315 if( tissue_increment & TISSUE_FLAG ) 2743 if( tissue_increment & TISSUE_FLAG )
2316 { 2744 {
2317 // clear IBCD, microbubbles and outside warning flags (locked warnings will be preserved) 2745 // clear IBCD, microbubbles and outside warning flags (locked warnings will be preserved)
2318 char_O_deco_warnings &= ~(DECO_WARNING_IBCD + DECO_WARNING_MBUBBLES + DECO_WARNING_OUTSIDE); 2746 char_O_deco_warnings &= ~(DECO_WARNING_IBCD + DECO_WARNING_MBUBBLES + DECO_WARNING_OUTSIDE + DECO_ATTENTION_OUTSIDE );
2319 } 2747 }
2320
2321 2748
2322 // loop over all tissues 2749 // loop over all tissues
2323 for(ci=0; ci<NUM_COMP; ci++) 2750 for( ci = 0; ci < NUM_COMP; ci++ )
2324 { 2751 {
2325 overlay float calc_pres_tissue_N2;
2326 overlay float calc_pres_tissue_He;
2327 overlay float pres_tissue;
2328 overlay float pres_min; 2752 overlay float pres_min;
2329 2753
2330 // get the tissue pressures 2754 // get the tissue pressures
2331 if( tissue_increment & TISSUE_FLAG ) 2755 if( tissue_increment & TISSUE_FLAG )
2332 { 2756 {
2345 pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He; 2769 pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He;
2346 2770
2347 // get the coefficients for tissue ci 2771 // get the coefficients for tissue ci
2348 read_Buhlmann_coefficients(); 2772 read_Buhlmann_coefficients();
2349 2773
2350 // adapt the coefficients according to the N2/He ratio in the tissue 2774 // adopt a and b coefficients to current N2/He ratio inside the tissue
2351 var_N2_a = (var_N2_a * calc_pres_tissue_N2 + var_He_a * calc_pres_tissue_He) / pres_tissue; 2775 adopt_Buhlmann_coefficients();
2352 var_N2_b = (var_N2_b * calc_pres_tissue_N2 + var_He_b * calc_pres_tissue_He) / pres_tissue;
2353 2776
2354 // calculate minimum ambient pressure that the tissue can withstand according to straight Buhlmann 2777 // calculate minimum ambient pressure that the tissue can withstand according to straight Buhlmann
2355 pres_min = (pres_tissue - var_N2_a) * var_N2_b; 2778 pres_min = (pres_tissue - var_N2_a) * var_N2_b;
2356 2779
2357 // next calculations are only relevant when invoked on the real tissues 2780 // next calculations are only relevant when invoked on the real tissues
2358 if( tissue_increment & TISSUE_FLAG ) 2781 if( tissue_increment & TISSUE_FLAG )
2359 { 2782 {
2360 overlay float supersat; 2783 overlay float supersat;
2361 overlay float threshold; 2784 overlay float limit_warning;
2362 2785
2363 // calculate current supersaturation value (1.0 = 100%) of this tissue 2786 // calculate current supersaturation value (1.0 = 100%) of this tissue according to straight Buhlmann
2364 supersat = (pres_tissue - pres_respiration) / (pres_tissue - pres_min); 2787 supersat = (pres_tissue - real_pres_respiration) / (pres_tissue - pres_min);
2365 2788
2366 // check if tissue is in supersaturation 2789 // check if tissue is in supersaturation
2367 if( supersat > 0.0 ) 2790 if( supersat > 0.0 )
2368 { 2791 {
2369 // memorize highest supersaturation found 2792 // memorize highest supersaturation found
2370 if( supersat > lead_supersat ) lead_supersat = supersat; 2793 if( supersat > lead_supersat ) lead_supersat = supersat;
2371 2794
2372 // set a threshold value for the microbubbles and outside warnings 2795 // limit value for micro bubbles and outside warnings
2373 // ToDo: finalize the definition of the threshold 2796 limit_warning = 0.02 * ci + 0.9;
2374 threshold = 0.02 * ci + 0.9; 2797
2375 2798 // micro bubbles warning: supersaturation >= limit_warning OR >= 1.0
2376 // check if this tissue is likely to develop microbubbles 2799 if( (supersat >= limit_warning) || (supersat >= 1.0) )
2377 // and/or if this tissue is outside of the Buhlmann model 2800 char_O_deco_warnings |= (DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock);
2378 if( ci <= 5 ) 2801
2379 { 2802 // outside warning: supersaturation >= limit_warning AND >= 1.0
2380 if( supersat >= threshold ) 2803 if( (supersat >= limit_warning) && (supersat >= 1.0) )
2381 { 2804 char_O_deco_warnings |= (DECO_WARNING_OUTSIDE + DECO_WARNING_OUTSIDE_lock );
2382 char_O_deco_warnings |= (DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock);
2383
2384 if( supersat >= 1.0 )
2385 {
2386 char_O_deco_warnings |= (DECO_WARNING_OUTSIDE + DECO_WARNING_OUTSIDE_lock);
2387 }
2388 }
2389 }
2390 else // ci > 5
2391 {
2392 if( supersat >= 1.0 )
2393 {
2394 char_O_deco_warnings |= (DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock);
2395
2396 if( supersat >= threshold )
2397 {
2398 char_O_deco_warnings |= (DECO_WARNING_OUTSIDE + DECO_WARNING_OUTSIDE_lock);
2399 }
2400 }
2401 }
2402 } 2805 }
2403 } 2806 }
2404 2807
2405 // Apply the Eric Baker's varying gradient factor correction if the GF-Model is selected. 2808 // Apply the Eric Baker's varying gradient factor correction if the GF-Model is selected.
2406 // Note: the correction factor depends both on GF and b, so that can change who is the 2809 // Note: the correction factor depends both on GF and b, so that can change which is the
2407 // leading gas... 2810 // leading tissue... (this equation [1] is the inverse of equation [2])
2408 if( char_I_deco_model != 0 ) pres_min = ( pres_tissue - (var_N2_a * GF_parameter) ) 2811 if( char_I_deco_model != 0 ) pres_min = ( pres_tissue - (var_N2_a * GF_parameter) )
2409 / ( 1.0 - GF_parameter + (GF_parameter / var_N2_b ) ); 2812 / ( 1.0 - GF_parameter + (GF_parameter / var_N2_b ) );
2410 2813
2411 // check if this tissue requires a higher ambient pressure than was found to be needed up to now 2814 // check if this tissue requires a higher ambient pressure than was found to be needed up to now
2412 if( pres_min > lead_tissue_limit ) 2815 if( pres_min > lead_tissue_limit )
2413 { 2816 {
2414 lead_tissue_limit = pres_min; 2817 lead_tissue_limit = pres_min;
2415 lead_tissue_no = ci; 2818 lead_number = ci;
2416 } 2819 }
2417 } // for 2820 } // for
2418 2821
2419 2822
2420 // compile outputs 2823 // compute ceiling for the real tissues in bar relative pressure
2824 ceiling = lead_tissue_limit - pres_surface;
2825
2826
2827 // next in real tissue context only
2421 if( tissue_increment & TISSUE_FLAG ) 2828 if( tissue_increment & TISSUE_FLAG )
2422 { 2829 {
2423 //--- real tissues ----------------------------------------------------- 2830 // check if the leading tissue is in IBCD condition
2424 2831 if( (IBCD_tissue_vector & (1 << lead_number))
2425 // check if leading tissue is in IBCD condition 2832 && ((pres_tissue_N2[lead_number] + pres_tissue_He[lead_number]) > real_pres_respiration) )
2426 if( (IBCD_tissue_vector & (1 << lead_tissue_no)) 2833 {
2427 && ((pres_tissue_N2[lead_tissue_no] + pres_tissue_He[lead_tissue_no]) > pres_respiration) ) 2834 // leading tissue is in IBCD condition and in super-saturation, so issue a warning
2428 {
2429 // leading tissue is in IBCD condition and in super-saturation, so issue a warning.
2430 char_O_deco_warnings |= (DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock); 2835 char_O_deco_warnings |= (DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock);
2431 } 2836 }
2432
2433
2434 // compute ceiling in bar relative pressure
2435 ceiling = lead_tissue_limit - pres_surface;
2436
2437 // convert ceiling to int_O_ceiling in mbar
2438 if ( ceiling <= 0 ) int_O_ceiling = 0;
2439 else if ( ceiling > 16 ) int_O_ceiling = 16000;
2440 // Compatibility version
2441 // else int_O_ceiling = (short)(ceiling * 1000);
2442
2443 // New version: Rounds up to next 10 cm so that the ceiling disappears on the display only when the
2444 // ceiling limit is really zero. This will coincident then with TTS switching back to NDL time.
2445 else int_O_ceiling = (short)(ceiling * 1000 + 9);
2446
2447
2448 // convert highest supersaturation found to int_O_gradient_factor in % (1.0 = 100%)
2449 // limit to 255 because of constraints in ghostwriter code
2450 if ( lead_supersat <= 0.0 ) int_O_gradient_factor = 0;
2451 else if( lead_supersat > 2.545 ) int_O_gradient_factor = 255 + INT_FLAG_WARNING;
2452 else
2453 {
2454 int_O_gradient_factor = (unsigned int)(100 * lead_supersat + 0.5);
2455
2456 if ( int_O_gradient_factor >= GF_WARNING_THRESHOLD )
2457 int_O_gradient_factor |= INT_FLAG_WARNING;
2458
2459 else if ( int_O_gradient_factor >= char_I_GF_High_percentage )
2460 int_O_gradient_factor |= INT_FLAG_ATTENTION;
2461 }
2462 }
2463 else
2464 {
2465 //--- simulated tissues ------------------------------------------------
2466
2467 // compute ceiling for the simulated tissues in bar relative pressure
2468 sim_ceiling = lead_tissue_limit - pres_surface;
2469 } 2837 }
2470 } 2838 }
2471 2839
2472 ////////////////////////////////////////////////////////////////////////////// 2840 //////////////////////////////////////////////////////////////////////////////
2473 // calc_NDL_time 2841 // calc_NDL_time
2474 // 2842 //
2475 // calculates the remaining bottom time 2843 // calculation of the remaining bottom time (NDL: no decompression limit)
2476 // 2844 //
2477 // NOTE: Erik Baker's closed formula works for Nitroxes. Trimix adds a second 2845 // NOTE: Erik Baker's closed formula works for Nitrox. Trimix adds a second
2478 // exponential term to the M-value equation, making it impossible to 2846 // exponential term to the M-value equation, making it impossible to
2479 // invert... So we have to make a fast-simu until we find a better way. 2847 // invert. So we have to solve the problem with an iterative approach.
2480 // 2848 //
2481 // Input: ppN2 2849 // Input: ppN2
2482 // ppHe 2850 // ppHe
2483 // 2851 //
2484 // Output: NDL_time 2852 // Output: NDL_time
2490 2858
2491 2859
2492 // initialize NDL_time to 240 minutes 2860 // initialize NDL_time to 240 minutes
2493 NDL_time = 240; 2861 NDL_time = 240;
2494 2862
2495 for(i=0; i<NUM_COMP; i++) 2863 for( i = 0; i < NUM_COMP; i++ )
2496 { 2864 {
2497 overlay float calc_pres_tissue_N2; 2865 overlay unsigned char period = 10; // start with iterations of 10 minutes
2498 overlay float calc_pres_tissue_He; 2866 overlay unsigned char NDL_tissue; // loop variable
2499 overlay float pres_tissue; 2867 overlay float GF_factor; // gradient factor to be applied
2500 2868 overlay float next_pres_tissue; // auxiliary variable to cache a calculation result
2501 overlay unsigned char NDL_tissue; 2869
2502 overlay unsigned char period = 10; // start with 10 minute periods 2870
2503 2871 // select gradient factor to use
2504 2872 GF_factor = (char_I_deco_model != 0) ? GF_high : 1.0;
2505 // check lead tissue from last NDL computation first 2873
2874 // the fastest way to find out if already being beyond NDL is to start with
2875 // the tissue that was the leading one during the last NDL computation...
2506 ci = i + NDL_lead_tissue; 2876 ci = i + NDL_lead_tissue;
2507 2877
2508 // wrap around after the 16th tissue 2878 // wrap around after the 16th tissue
2509 if( ci >= NUM_COMP ) ci -= NUM_COMP; 2879 if( ci >= NUM_COMP ) ci -= NUM_COMP;
2510 2880
2511 // read Buhlmann a and b coefficients for tissue ci 2881 // read the loading factors for 10 minute iterations
2512 read_Buhlmann_coefficients();
2513
2514 // read the loading factors for 10 minute periods
2515 read_Buhlmann_times(2); 2882 read_Buhlmann_times(2);
2516 2883
2517 // get the tissue pressures for N2 and He 2884 // get the tissue pressures for N2 and He
2518 calc_pres_tissue_N2 = sim_pres_tissue_N2[ci]; 2885 calc_pres_tissue_N2 = sim_pres_tissue_N2[ci];
2519 calc_pres_tissue_He = sim_pres_tissue_He[ci]; 2886 calc_pres_tissue_He = sim_pres_tissue_He[ci];
2520 2887
2521 // calculate the total pressure tissue 2888 // calculate the total pressure tissue
2522 pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He; 2889 pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He;
2523 2890
2524 2891 // Simulate an increasing bottom time and check when we hit the NDL.
2525 // simulate an increasing bottom time and check when we hit the NDL ------------------------ 2892 // It is not needed to simulate for longer than the already found NDL.
2526 for( NDL_tissue = 0; NDL_tissue < NDL_time; ) // not needed to simulate for longer than the already found NDL 2893 for( NDL_tissue = 0; NDL_tissue < NDL_time; )
2527 { 2894 {
2528 overlay float var_a;
2529 overlay float var_b;
2530 overlay float pres_limit; 2895 overlay float pres_limit;
2531 overlay float delta_pres_tissue_N2; 2896 overlay float delta_pres_tissue_N2;
2532 overlay float delta_pres_tissue_He; 2897 overlay float delta_pres_tissue_He;
2533 2898
2534 2899
2900 // read Buhlmann a and b coefficients for tissue ci, they need to be re-read on each
2901 // iteration because adopt_Buhlmann_coefficients() twiddles with the N2 coefficients
2902 read_Buhlmann_coefficients();
2903
2535 // adopt a and b coefficients to current N2/He ratio inside the tissue 2904 // adopt a and b coefficients to current N2/He ratio inside the tissue
2536 var_a = (var_N2_a * calc_pres_tissue_N2 + var_He_a * calc_pres_tissue_He) / pres_tissue; 2905 adopt_Buhlmann_coefficients();
2537 var_b = (var_N2_b * calc_pres_tissue_N2 + var_He_b * calc_pres_tissue_He) / pres_tissue; 2906
2538 2907 // compute the maximum tissue pressure allowed to be exposed to an ambient pressure equaling
2539 // compute pressure limit for tissues under surface pressure conditions 2908 // the surface pressure (this equation [2] is the inverse of equation [1])
2540 pres_limit = (var_a + pres_surface / var_b); 2909 pres_limit = (1.0 - GF_factor + GF_factor / var_N2_b) * pres_surface + GF_factor * var_N2_a;
2541 2910
2542 // adopt pressure limit when using the GF extension 2911 // check if this tissue is already beyond the NDL
2543 if (char_I_deco_model != 0 ) pres_limit = GF_high * (pres_limit - pres_surface) + pres_surface;
2544
2545 //---- Check if this tissue is already beyond the NDL
2546 if( pres_tissue > pres_limit) 2912 if( pres_tissue > pres_limit)
2547 { 2913 {
2548 // NO - finish the outer loop, 2914 // beyond NDL - finish the outer loop, ...
2549 i = NUM_COMP; 2915 i = NUM_COMP;
2550 2916
2551 // and finish the inner loop 2917 // ... and finish the inner loop
2552 break; 2918 break;
2553 } 2919 }
2554 2920
2555 // compute delta to tissue pressures in 10 or 1 minutes of time ahead 2921 // compute tissue pressure deltas for 10 or 1 minute of time ahead
2556 delta_pres_tissue_N2 = (ppN2 - calc_pres_tissue_N2) * var_N2_e; 2922 delta_pres_tissue_N2 = (ppN2 - calc_pres_tissue_N2) * var_N2_e;
2557 delta_pres_tissue_He = (ppHe - calc_pres_tissue_He) * var_He_e; 2923 delta_pres_tissue_He = (ppHe - calc_pres_tissue_He) * var_He_e;
2558 2924
2559 // apply safety factors to the pressure deltas 2925 // apply safety factors to the pressure deltas
2560 // NDL can be computed while ascending, so we have to check if we are saturating or desaturating 2926 // NDL can be computed while ascending, so we have to check if the tissues is saturating or desaturating
2561 if( delta_pres_tissue_N2 > 0.0 ) delta_pres_tissue_N2 *= float_saturation_multiplier; 2927 if( delta_pres_tissue_N2 > 0.0 ) delta_pres_tissue_N2 *= float_saturation_multiplier;
2562 else delta_pres_tissue_N2 *= float_desaturation_multiplier; 2928 else delta_pres_tissue_N2 *= float_desaturation_multiplier;
2563 2929
2564 if( delta_pres_tissue_He > 0.0 ) delta_pres_tissue_He *= float_saturation_multiplier; 2930 if( delta_pres_tissue_He > 0.0 ) delta_pres_tissue_He *= float_saturation_multiplier;
2565 else delta_pres_tissue_He *= float_saturation_multiplier; 2931 else delta_pres_tissue_He *= float_saturation_multiplier;
2566 2932
2567 // Simulate off-gassing while going to surface 2933 // simulate off-gassing while going to surface - well, maybe some day we'll do that...
2568 // TODO !
2569 // delta_pres_tissue_N2 -= exp( ... ascent time ... ppN2...) 2934 // delta_pres_tissue_N2 -= exp( ... ascent time ... ppN2...)
2570 // delta_pres_tissue_He -= exp( ... ascent time ... ppHe...) 2935 // delta_pres_tissue_He -= exp( ... ascent time ... ppHe...)
2571 2936
2572 // within NDL now, but still within in 10 or 1 minutes from now? 2937 // calculate tissue pressure for given time ahead
2573 if( pres_tissue + delta_pres_tissue_N2 + delta_pres_tissue_He <= pres_limit ) 2938 next_pres_tissue = pres_tissue + delta_pres_tissue_N2 + delta_pres_tissue_He;
2939
2940 // within NDL now, but still within NDL in 10 or 1 minute from now?
2941 if( next_pres_tissue <= pres_limit )
2574 { 2942 {
2575 // YES - apply the pressure deltas to tissues 2943 // YES - apply the pressure deltas to the tissues
2576 calc_pres_tissue_N2 += delta_pres_tissue_N2; 2944 calc_pres_tissue_N2 += delta_pres_tissue_N2;
2577 calc_pres_tissue_He += delta_pres_tissue_He; 2945 calc_pres_tissue_He += delta_pres_tissue_He;
2578 2946
2579 // update the overall tissue pressure 2947 // update the overall tissue pressure
2580 pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He; 2948 pres_tissue = next_pres_tissue;
2581 2949
2582 // increment the NDL 2950 // increment the NDL
2583 NDL_tissue += period; 2951 NDL_tissue += period;
2584 2952
2585 // do next loop 2953 // do next iteration
2586 continue; 2954 continue;
2587 } 2955 }
2588 2956
2589 // NO - if delta pressures were for 10 minutes of time ahead, try with 1 minute ahead 2957 // NO - if delta pressures were for 10 minutes of time ahead, continue with trying for 1 minute ahead
2590 if( period == 10 ) 2958 if( period == 10 )
2591 { 2959 {
2592 // reduce period to 1 minute 2960 // reduce period to 1 minute
2593 period = 1; 2961 period = 1;
2594 2962
2595 // read the loading factors for 1 minute periods 2963 // read the loading factors for 1 minute periods
2596 read_Buhlmann_times(1); 2964 read_Buhlmann_times(1);
2597 2965
2598 // do next loop 2966 // do next iteration
2599 continue; 2967 continue;
2600 } 2968 }
2601 2969
2602 // NO - not even within NDL in just one more minute, so make a linear approx for the last minute 2970 // less than a full minute of NDL time left, so finish the inner loop
2603 // (make a meaningful rounding of NDL, but ONLY if positive: negative casted to unsigned is bad)
2604 if( pres_limit > pres_tissue )
2605 NDL_tissue += (unsigned char)(0.5 + (pres_limit - pres_tissue )
2606 / (delta_pres_tissue_N2 + delta_pres_tissue_He) );
2607
2608 // finish the inner loop
2609 break; 2971 break;
2610 } 2972
2611 2973 } // inner for-loop simulating increasing bottom time
2612 // is the current NDL short than the shortest so far? 2974
2975 // is the current NDL shorter than the shortest so far?
2613 if ( NDL_tissue < NDL_time ) 2976 if ( NDL_tissue < NDL_time )
2614 { 2977 {
2615 // keep the current's tissue NDL as the new shortest NDL 2978 // keep the current's tissue NDL as the new shortest NDL
2616 NDL_time = NDL_tissue; 2979 NDL_time = NDL_tissue;
2617 2980
2618 // store the causing tissue 2981 // store the causing tissue
2619 new_NDL_lead_tissue = ci; 2982 new_NDL_lead_tissue = ci;
2620 } 2983 }
2621 2984
2622 // if NDL is > 0 the outer loop will continues with the next tissue 2985 // If NDL is > 0 the outer loop will continues with the next tissue.
2623 // if NDL found to be overrun, outer loop will be terminated through i = NUM_COMP statement 2986 // If NDL found to be overrun, outer loop will be terminated by means of the i = NUM_COMP statement.
2624 } 2987
2988 } // outer for-loop iterating over all tissues
2625 2989
2626 // store the NDL dominating tissue for to start with in the next NDL calculation 2990 // store the NDL dominating tissue for to start with in the next NDL calculation
2627 NDL_lead_tissue = new_NDL_lead_tissue; 2991 NDL_lead_tissue = new_NDL_lead_tissue;
2628 } 2992 }
2629 2993
2994
2630 ////////////////////////////////////////////////////////////////////////////// 2995 //////////////////////////////////////////////////////////////////////////////
2631 // calc_ascenttime 2996 // calc_ascenttime
2632 // 2997 //
2633 // Sum up ascent from bottom to surface at float_ascent_speed, 2998 // Sum up ascent from bottom to surface at float_ascent_speed, slowing down to
2634 // but 1 minute per meter for the final ascent, and all stops. 2999 // 1 minute per meter for the final ascent when in deco, and all stop times.
2635 // 3000 //
2636 // Input: char_I_depth_last_deco 3001 // Input: char_I_depth_last_deco
2637 // pres_respiration 3002 // char_I_ascent_speed
2638 // pres_surface 3003 // char_bottom_depth
2639 // float_ascent_speed
2640 // internal_deco_depth[] 3004 // internal_deco_depth[]
3005 // internal_deco_time[]
2641 // 3006 //
2642 // Output: ascent_time 3007 // Output: ascent_time
2643 // 3008 //
2644 static void calc_ascenttime(void) 3009 static void calc_ascenttime(void)
2645 { 3010 {
2646 overlay unsigned char x; 3011 overlay unsigned char x; // loop counter
2647 3012 overlay unsigned char ascent; // meters to go from bottom to last stop
2648 3013 overlay unsigned char final; // meters to go from last stop to surface
2649 // preset final ascent 3014
2650 overlay float final = (float)char_I_depth_last_deco; 3015
2651 3016 // check if there are stops
2652 // calculate depth 3017 if( internal_deco_depth[0] )
2653 overlay float ascent = (pres_respiration - pres_surface) * BAR_TO_METER; 3018 {
2654 3019 // stops / in deco
2655 // check if we are already in final ascent 3020
2656 if (ascent <= final) 3021 // check if already at last stop depth or shallower
2657 { 3022 if( char_bottom_depth <= char_I_depth_last_deco)
2658 // yes - all ascent is final ascent 3023 {
2659 final = ascent; 3024 // YES
2660 ascent = 0.0; 3025 ascent = 0;
3026 final = char_bottom_depth;
3027 }
3028 else
3029 {
3030 // NO
3031 ascent = char_bottom_depth - char_I_depth_last_deco;
3032 final = char_I_depth_last_deco;
3033 }
2661 } 3034 }
2662 else 3035 else
2663 { 3036 {
2664 // no - subtract final ascent part from overall ascent 3037 // no stops / within NDL
2665 ascent -= final; 3038 ascent = char_bottom_depth;
2666 3039 final = 0;
2667 // compute time for ascent part without final ascent 3040 }
2668 ascent /= float_ascent_speed; 3041
2669 } 3042
2670 3043 // initialize ascent time
2671 // add 1 minute for each meter of final ascent 3044 ascent_time = 0;
2672 ascent += final; 3045
2673 3046 // time for the ascent part (bottom to last stop), if existing
2674 // convert to integer 3047 if( ascent ) ascent_time += ascent / char_I_ascent_speed + 1;
2675 ascent_time = (unsigned short)(ascent + 0.5); 3048
3049 // add time for the final ascent (last stop to surface) at 1 min/m
3050 ascent_time += final;
2676 3051
2677 // add all stop times 3052 // add all stop times
2678 for(x=0; x<NUM_STOPS && internal_deco_depth[x]; x++) 3053 for( x=0; x < NUM_STOPS && internal_deco_depth[x]; x++ )
2679 ascent_time += (unsigned short)internal_deco_time[x]; 3054 ascent_time += internal_deco_time[x];
2680 3055
2681 // limit result to display max. 3056 // limit result to display max.
2682 if( ascent_time > 999) ascent_time = 999; 3057 if( ascent_time > 999) ascent_time = 999;
2683 3058
2684 // tag result as invalid if there is an overflow in the stops table 3059 // tag result as invalid if there is an overflow in the stops table
2692 // 3067 //
2693 static void clear_deco_table(void) 3068 static void clear_deco_table(void)
2694 { 3069 {
2695 overlay unsigned char x; 3070 overlay unsigned char x;
2696 3071
2697 for(x=0; x<NUM_STOPS; ++x) 3072 for( x = 0; x < NUM_STOPS; ++x )
2698 { 3073 {
2699 internal_deco_time [x] = 0; 3074 internal_deco_time [x] = 0;
2700 internal_deco_depth[x] = 0; 3075 internal_deco_depth[x] = 0;
2701 internal_deco_gas[x] = 0; 3076 internal_deco_gas[x] = 0;
2702 } 3077 }
2703 3078
2704 // clear stop table overflow warning 3079 // clear stop table overflow warning
2705 char_O_deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW; 3080 char_O_deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW;
2706 } 3081 }
2710 // 3085 //
2711 // Add time to a stop at sim_depth_limit 3086 // Add time to a stop at sim_depth_limit
2712 // 3087 //
2713 // It is possible to create stops with a duration of 0 minutes, e.g. to 3088 // It is possible to create stops with a duration of 0 minutes, e.g. to
2714 // note a gas change "on the fly" while ascending. Therefore the criteria 3089 // note a gas change "on the fly" while ascending. Therefore the criteria
2715 // to have reached the end of the list needs always to be depth == 0. 3090 // to have reached the end of the list is depth == 0.
2716 // 3091 //
2717 // Input: sim_depth_limit : stop's depth, in meters. 3092 // Input: sim_depth_limit : stop's depth, in meters
2718 // sim_gas_last_used : gas used at stop, as index 1..5 or 0 for gas 6 3093 // sim_gas_current : gas used at stop, as index 1..5 or 0 for gas 6
2719 // PARAMETER time_increment : number of minutes to add to the stop 3094 // time_increment : number of minutes to add to the stop
2720 // 3095 //
2721 // Updated: internal_deco_depth[] : depth (in meters) of each stop 3096 // Updated: internal_deco_depth[] : depth (in meters) of each stop
2722 // internal_deco_time [] : time (in minutes) of each stop 3097 // internal_deco_time [] : time (in minutes) of each stop
2723 // internal_deco_gas [] : gas used (index 1-5) at each stop 3098 // internal_deco_gas [] : gas used (index 1-5) at each stop
2724 // 3099 //
2725 static unsigned char update_deco_table(PARAMETER unsigned char time_increment) 3100 static unsigned char update_deco_table(PARAMETER unsigned char time_increment)
2726 { 3101 {
2727 overlay unsigned char x; 3102 overlay unsigned char x;
2728 3103
2729 assert( sim_depth_limit > 0 ); // No stop at surface... 3104 assert( sim_depth_limit > 0 ); // no stop at surface
2730 3105
2731 // loop through internal deco table 3106 // loop through internal deco table
2732 for(x=0; x<NUM_STOPS; ++x) 3107 for( x = 0; x < NUM_STOPS; ++x )
2733 { 3108 {
2734 // In case the first deco stop is to be placed deeper than previously recorded 3109 // In case the first deco stop is to be placed deeper than previously recorded
2735 // stops for gas changes during the initial ascent (this may happen because the 3110 // stops for gas changes during the initial ascent (this may happen because the
2736 // deco stops are placed at the next deeper multiple of 3 meters instead of the 3111 // deco stops are placed at the next deeper multiple of 3 meters instead of the
2737 // real stop's depth), relocate the deco stop to the depth of the last gas change. 3112 // real stop's depth), relocate the deco stop to the depth of the last gas change.
2738 // The resulting combined stop's duration will be the sum of the configured gas 3113 // The resulting combined stop's duration will be the sum of the configured gas
2739 // change time plus the duration of the deco stop itself. 3114 // change time plus the duration of the deco stop itself.
2740 if( internal_deco_depth[x] && (sim_depth_limit > internal_deco_depth[x]) ) 3115 if( internal_deco_depth[x] && (sim_depth_limit > internal_deco_depth[x]) )
2741 sim_depth_limit = internal_deco_depth[x]; 3116 sim_depth_limit = internal_deco_depth[x];
2742 3117
2743 // Is there already a stop entry for our current depth? 3118 // Is there already a stop entry for our current depth?
2744 if( internal_deco_depth[x] == sim_depth_limit ) 3119 if( internal_deco_depth[x] == sim_depth_limit )
2745 { 3120 {
2746 // Yes - increment stop time if possible 3121 // Yes - increment stop time if possible
2747 // Stop time entries are limited to 99 minutes because of display constraints. 3122 // Stop time entries are limited to 99 minutes because of display constraints.
2748 // Else a limit of 254 would account because of constrains in calc_CNS_planning().
2749 if( internal_deco_time[x] < (100 - time_increment) ) 3123 if( internal_deco_time[x] < (100 - time_increment) )
2750 { 3124 {
2751 internal_deco_time[x] += time_increment; // increment stop time 3125 internal_deco_time[x] += time_increment; // increment stop time
2752 return 1; // return with status 'success' 3126 return 1; // return with status 'success'
2753 } 3127 }
2758 // table entry. 3132 // table entry.
2759 if( internal_deco_depth[x] == 0 ) 3133 if( internal_deco_depth[x] == 0 )
2760 { 3134 {
2761 internal_deco_time[x] = time_increment; // initialize entry with first stop's time, 3135 internal_deco_time[x] = time_increment; // initialize entry with first stop's time,
2762 internal_deco_depth[x] = sim_depth_limit; // ... depth, and 3136 internal_deco_depth[x] = sim_depth_limit; // ... depth, and
2763 internal_deco_gas[x] = sim_gas_last_used; // ... gas 3137 internal_deco_gas[x] = sim_gas_current; // ... gas
2764 return 1; // return with status 'success' 3138 return 1; // return with status 'success'
2765 } 3139 }
2766 } 3140 }
2767 3141
2768 // If program flow passes here, all deco table entries are used up. 3142 // If program flow passes here, all deco table entries are used up.
2776 3150
2777 3151
2778 ////////////////////////////////////////////////////////////////////////////// 3152 //////////////////////////////////////////////////////////////////////////////
2779 // calc_desaturation_time 3153 // calc_desaturation_time
2780 // 3154 //
2781 // Inputs: int_I_pres_surface, ppWater, char_I_desaturation_multiplier
2782 // Outputs: int_O_desaturation_time, int_O_nofly_time
2783 //
2784 // Helper function 3155 // Helper function
2785 // 3156 //
2786 void calc_desaturation_time_helper(void) 3157 static void calc_desaturation_time_helper(void)
2787 { 3158 {
2788 if( pres_actual > pres_target ) // check if actual pressure is higher then target pressure 3159 if( pres_actual > pres_target ) // check if actual pressure is higher then target pressure
2789 { // YES - compute remaining time 3160 { // YES - compute remaining time
2790 overlay float pres_ratio; 3161 overlay float pres_ratio;
2791 3162
2792 pres_ratio = pres_actual / pres_target; 3163 pres_ratio = pres_actual / pres_target;
2793 3164
2794 // Compute desaturation time with result rounded up to multiples of 10 minutes. 3165 // Compute desaturation time with result rounded up to multiples of 10 minutes.
2795 // Main purpose is to avoid confusion, because the times do not clock down in 3166 // Main purpose is to avoid confusion, because the times do not clock down in
2796 // one minute steps any more but get constantly re-computed according to current 3167 // one minute steps any more but get constantly re-computed according to current
2797 // ambient pressure and may therefor make steps of several minutes forwards and 3168 // ambient pressure and may therefor make steps of several minutes forwards and
2798 // backwards as ambient pressure rises and falls. 3169 // backwards as ambient pressure rises/falls and N2/He ratio is being adjusted.
2799 int_time = (unsigned int)( (var_ht * log(pres_ratio) / desat_factor) + 0.9 ); 3170 int_time = (unsigned int)( (var_ht * log(pres_ratio) / desat_factor) + 0.9 );
2800 } 3171 }
2801 else 3172 else
2802 { // NO - desaturation state reached, no remaining time 3173 { // NO - desaturation state reached, no remaining time
2803 int_time = 0; 3174 int_time = 0;
2804 } 3175 }
2805 } 3176 }
2806 3177
2807 ///////////////////////////////////////////////////////////////////////////// 3178 /////////////////////////////////////////////////////////////////////////////
2808 // Main function 3179 // calc_desaturation_time
3180 //
3181 // Inputs: int_I_pres_surface, ppWater, char_I_desaturation_multiplier
3182 // Outputs: int_O_desaturation_time, int_O_nofly_time
3183 //
3184 // Calculate the time needed for the tissues to equilibrate with surface pressure
2809 // 3185 //
2810 void calc_desaturation_time(void) 3186 void calc_desaturation_time(void)
2811 { 3187 {
2812 assert( 800 < int_I_pres_surface && int_I_pres_surface < 1100 ); 3188 assert( 800 < int_I_pres_surface && int_I_pres_surface < 1100 );
2813 assert( 0 < char_I_desaturation_multiplier && char_I_desaturation_multiplier <= 100 ); 3189 assert( 0 < char_I_desaturation_multiplier && char_I_desaturation_multiplier <= 100 );
3190
3191
3192 // safety limit to prevent eventual infinite looping (bricking the OSTC)
3193 if( int_I_pres_surface < 500) int_I_pres_surface = 500;
2814 3194
2815 // fraction of inert gases in respired air 3195 // fraction of inert gases in respired air
2816 N2_ratio = 0.7902; 3196 real_N2_ratio = 0.7902;
2817 He_ratio = 0.0; 3197 real_He_ratio = 0.0;
2818 3198
2819 // surface pressure in bar 3199 // surface pressure in bar
2820 pres_surface = 0.001 * int_I_pres_surface; 3200 pres_surface = 0.001 * int_I_pres_surface;
2821 3201
2822 // partial pressure of N2 in respired air 3202 // partial pressure of N2 in respired air
2823 N2_equilibrium = N2_ratio * (pres_surface - ppWater); 3203 N2_equilibrium = real_N2_ratio * (pres_surface - ppWater);
2824 3204
2825 // pre-computed term for later use: 10 [Min] * 0.01 [%] * 0.6931 [=log(2)] * ... 3205 // pre-computed term for later use: 10 [Min] * 0.01 [%] * 0.6931 [=log(2)] * ...
2826 desat_factor = 0.06931 * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR; 3206 desat_factor = 0.06931 * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR;
2827 3207
2828 // initialize vars 3208 // initialize vars
2829 int_O_desaturation_time = 0; 3209 int_O_desaturation_time = 0;
2830 int_O_nofly_time = 0; 3210 int_O_nofly_time = 0;
2831 3211
2832 3212
2833 for(ci=NUM_COMP; ci>0;) 3213 for( ci = NUM_COMP; ci > 0; )
2834 { 3214 {
2835 overlay float pres_tissue_max; 3215 overlay float pres_tissue_max;
2836 overlay float P_ambient_altitude; 3216 overlay float P_ambient_altitude;
2837 overlay signed char search_direction; 3217 overlay signed char search_direction;
2838 overlay unsigned int nofly_N2 = 0; 3218 overlay unsigned int nofly_N2 = 0;
2870 // Desaturation time 3250 // Desaturation time
2871 // 3251 //
2872 3252
2873 // N2: actual amount of tissue pressure above equilibrium. 3253 // N2: actual amount of tissue pressure above equilibrium.
2874 pres_actual = pres_tissue_N2[ci] - N2_equilibrium; 3254 pres_actual = pres_tissue_N2[ci] - N2_equilibrium;
2875 3255
2876 // N2: half-time of the current tissue 3256 // N2: half-time of the current tissue
2877 var_ht = var_N2_ht; 3257 var_ht = var_N2_ht;
2878 3258
2879 // Calculate desaturation time for N2 in tissue. 3259 // Calculate desaturation time for N2 in tissue.
2880 // Desaturated state is defined as residual tissue pressure <= 1.05 x ppN2 respired 3260 // Desaturated state is defined as residual tissue pressure <= 1.05 x ppN2 respired
2881 3261
2882 pres_target = 0.05 * N2_equilibrium; 3262 pres_target = 0.05 * N2_equilibrium;
2904 3284
2905 // 3285 //
2906 // no-fly time 3286 // no-fly time
2907 // 3287 //
2908 3288
3289 // initialize split_N2_He in case there was a hard reboot / memory clear.
3290 if( split_N2_He[ci] == 0 ) split_N2_He[ci] = 90;
3291
2909 // initialize search direction 3292 // initialize search direction
2910 search_direction = 0; 3293 search_direction = 0;
2911 3294
2912 for(;;) 3295 for(;;)
2913 { 3296 {
2914 // N2: actual amount of tissue pressure above equilibrium. 3297 // N2: actual amount of tissue pressure above equilibrium.
2915 pres_actual = pres_tissue_N2[ci] - N2_equilibrium; 3298 pres_actual = pres_tissue_N2[ci] - N2_equilibrium;
2916 3299
2917 // N2: half-time of the current tissue 3300 // N2: half-time of the current tissue
2918 var_ht = var_N2_ht; 3301 var_ht = var_N2_ht;
2919 3302
2920 // Calculate no-fly time for N2 in the tissue. 3303 // Calculate no-fly time for N2 in the tissue.
2921 // Flying is permitted when the N2 pressure fits into the assigned fraction above equilibrium. 3304 // Flying is permitted when the N2 pressure fits into the assigned fraction above equilibrium.
2922 3305
2923 pres_target = (split_N2_He[ci] * 0.01) * (pres_tissue_max - N2_equilibrium); 3306 pres_target = (split_N2_He[ci] * 0.01) * (pres_tissue_max - N2_equilibrium);
2925 if( pres_target < 0.0 ) // check if desaturation to fly target is possible 3308 if( pres_target < 0.0 ) // check if desaturation to fly target is possible
2926 { 3309 {
2927 int_O_nofly_time = 288; // NO - set no-fly time to 288 * 10 min = 48 h 3310 int_O_nofly_time = 288; // NO - set no-fly time to 288 * 10 min = 48 h
2928 break; // done for this compartment 3311 break; // done for this compartment
2929 } 3312 }
2930 else 3313 else
2931 { 3314 {
2932 calc_desaturation_time_helper(); 3315 calc_desaturation_time_helper();
2933 nofly_N2 = int_time; 3316 nofly_N2 = int_time;
2934 } 3317 }
2935 3318
2964 if( nofly_N2 >= nofly_He ) 3347 if( nofly_N2 >= nofly_He )
2965 { 3348 {
2966 // check if the search direction has changed, which means we are beyond the 3349 // check if the search direction has changed, which means we are beyond the
2967 // optimum now, or if we are at the upper stop limit of split_N2_He 3350 // optimum now, or if we are at the upper stop limit of split_N2_He
2968 if( (search_direction < 0) || (split_N2_He[ci] == 99) ) 3351 if( (search_direction < 0) || (split_N2_He[ci] == 99) )
2969 { 3352 {
2970 // Either the just completed iteration was more close to the optimum or the one before 3353 // Either the just completed iteration was more close to the optimum or the one before
2971 // was, so we take the best (i.e. shortest) time of both as the final no-fly time. 3354 // was, so we take the best (i.e. shortest) time of both as the final no-fly time.
2972 int_O_nofly_time = (nofly_N2 < nofly_last) ? nofly_N2 : nofly_last; 3355 int_O_nofly_time = (nofly_N2 < nofly_last) ? nofly_N2 : nofly_last;
2973 break; 3356 break;
2974 } 3357 }
2995 // store the no-fly time found in this iteration 3378 // store the no-fly time found in this iteration
2996 nofly_last = nofly_He; 3379 nofly_last = nofly_He;
2997 3380
2998 // decrease the N2 fraction of the split and set search direction towards less N2 3381 // decrease the N2 fraction of the split and set search direction towards less N2
2999 split_N2_He[ci] -= 1; 3382 split_N2_He[ci] -= 1;
3000 search_direction = -1; 3383 search_direction = -1;
3001 } 3384 }
3002 3385
3003 } // for(;;) 3386 } // for(;;)
3004 3387
3005 } // for(compartments) 3388 } // for(compartments)
3013 // because of display space constraints and rounding done above. 3396 // because of display space constraints and rounding done above.
3014 if( int_O_desaturation_time > 5999 ) int_O_desaturation_time = 5999; 3397 if( int_O_desaturation_time > 5999 ) int_O_desaturation_time = 5999;
3015 if( int_O_nofly_time > 5999 ) int_O_nofly_time = 5999; 3398 if( int_O_nofly_time > 5999 ) int_O_nofly_time = 5999;
3016 3399
3017 3400
3018 // Clear the microbubbles warning when the current gradient factor is < GF_WARNING_THRESHOLD. 3401 // Clear the microbubbles warning when the current gradient factor is < 100%.
3019 // As the locked warning will stay set, this will cause the warning be be displayed in attention 3402 // The current gradient factor is calculated by calc_interval() while not in diving mode.
3020 // color instead of warning color. 3403 // As the locked warning will stay set, this will cause the warning be be displayed in
3021 if( int_O_gradient_factor < GF_WARNING_THRESHOLD ) 3404 // attention color instead of warning color.
3405 if( int_O_gradient_factor < 100 )
3022 char_O_deco_warnings &= ~DECO_WARNING_MBUBBLES; 3406 char_O_deco_warnings &= ~DECO_WARNING_MBUBBLES;
3023 3407
3024 // clear some warnings when the desaturation time has become zero 3408 // clear some warnings when the desaturation time has become zero
3025 if( int_O_desaturation_time == 0 ) 3409 if( int_O_desaturation_time == 0 )
3026 char_O_deco_warnings &= ~( DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock 3410 char_O_deco_warnings &= ~( DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock
3027 + DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock 3411 + DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock
3028 + DECO_WARNING_OUTSIDE + DECO_WARNING_OUTSIDE_lock ); 3412 + DECO_WARNING_OUTSIDE + DECO_WARNING_OUTSIDE_lock
3413 + DECO_ATTENTION_OUTSIDE );
3029 3414
3030 } 3415 }
3031 3416
3032 ////////////////////////////////////////////////////////////////////////////// 3417 //////////////////////////////////////////////////////////////////////////////
3033 // Calculate desaturation of the real tissues for a given time interval 3418 // Calculate desaturation of the real tissues for a given time interval
3037 // push_tissues_to_vault() / pull_tissues_from_vault() ! 3422 // push_tissues_to_vault() / pull_tissues_from_vault() !
3038 // 3423 //
3039 // Input: int_I_pres_surface : surface pressure in mbar 3424 // Input: int_I_pres_surface : surface pressure in mbar
3040 // time_interval : time interval in minutes, must be limited to 254 at max 3425 // time_interval : time interval in minutes, must be limited to 254 at max
3041 // 3426 //
3042 // Modified: tissue pressures 3427 // Modified: tissue pressures : N2 and He pressures of the tissues
3043 // CNS value 3428 // CNS_fraction : current CNS value
3044 // ceiling and current GF 3429 // ceiling : minimum allowed depth in mbar relative pressure
3430 // lead_supersat : supersaturation of the leading tissue
3431 // int_O_gradient_factor : current GF factor
3045 // 3432 //
3046 static void calc_interval(PARAMETER unsigned char time_interval) 3433 static void calc_interval(PARAMETER unsigned char time_interval)
3047 { 3434 {
3048 overlay unsigned char time; 3435 overlay unsigned char time;
3049 3436
3050
3051 assert( 800 < int_I_pres_surface && int_I_pres_surface < 1100 ); 3437 assert( 800 < int_I_pres_surface && int_I_pres_surface < 1100 );
3052 assert( 100 <= char_I_saturation_multiplier && char_I_saturation_multiplier < 200 ); 3438 assert( 100 <= char_I_saturation_multiplier && char_I_saturation_multiplier < 200 );
3053 assert( 0 < char_I_desaturation_multiplier && char_I_desaturation_multiplier <= 100 ); 3439 assert( 0 < char_I_desaturation_multiplier && char_I_desaturation_multiplier <= 100 );
3054 3440
3441
3442 // safety limit to prevent eventual infinite looping (bricking the OSTC)
3443 if( int_I_pres_surface < 500) int_I_pres_surface = 500; // min. surface pressure = 500 mbar
3055 3444
3056 // setup input data for deco routines 3445 // setup input data for deco routines
3057 pres_respiration = pres_surface = 0.001 * int_I_pres_surface ; 3446 real_pres_respiration = pres_surface = 0.001 * int_I_pres_surface;
3058 3447
3059 N2_ratio = 0.7902; // according to Buhlmann 3448 real_N2_ratio = 0.7902; // according to Buhlmann
3060 N2_equilibrium = N2_ratio * (pres_surface - ppWater); // used for N2 tissue graphics scaling 3449 N2_equilibrium = real_N2_ratio * (pres_surface - ppWater); // used for N2 tissue graphics scaling
3061 ppN2 = N2_ratio * (pres_respiration - ppWater); 3450 ppN2 = real_N2_ratio * (real_pres_respiration - ppWater);
3062 ppHe = 0.0; 3451 ppHe = 0.0;
3063 3452
3064 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR; 3453 float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR;
3065 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier; 3454 float_saturation_multiplier = 0.01 * char_I_saturation_multiplier;
3066 3455
3073 3462
3074 // first chunk for the part exceeding 127 minutes 3463 // first chunk for the part exceeding 127 minutes
3075 if( time > 127) 3464 if( time > 127)
3076 { 3465 {
3077 // do a full 127 minutes on the real tissues 3466 // do a full 127 minutes on the real tissues
3078 tissue_increment = 127 | TISSUE_FLAG; 3467 tissue_increment = TISSUE_FLAG | 127;
3079 calc_tissues(); 3468 calc_tissues();
3080 3469
3081 // determine the remaining part 3470 // determine the remaining part
3082 time -= 127; 3471 time -= 127;
3083 } 3472 }
3084 3473
3085 // program the remaining part (or full part if not exceeding 127 minutes) 3474 // program the remaining part (or full part if not exceeding 127 minutes)
3086 tissue_increment = time | TISSUE_FLAG; 3475 tissue_increment = TISSUE_FLAG | time;
3087 3476
3088 // update the N2 and He pressures in the tissues for the remaining part of the time interval 3477 // update the N2 and He pressures in the tissues
3089 calc_tissues(); 3478 calc_tissues();
3090 3479
3091 3480
3092 // Calculate CNS: 3481 // Calculate CNS:
3093 // To speed up things and because on most invocations of this code char_I_dive_interval 3482 // To speed up things and because on most invocations of this code char_I_dive_interval
3094 // is a multiple of 10 minutes, we loop the loop-counter down using two speeds. 3483 // is a multiple of 10 minutes, we loop the loop-counter down using two speeds.
3095 3484
3096 time = time_interval; 3485 time = time_interval;
3097 3486
3098 while ( time ) 3487 while( time )
3099 { 3488 {
3100 if( time > 9 ) 3489 if( time > 9 )
3101 { 3490 {
3102 CNS_fraction *= 0.925874712; // Half-time = 90min -> 10 min: (1/2)^(1/9) 3491 CNS_fraction *= 0.925874712; // Half-time = 90min -> 10 min: (1/2)^(1/9)
3103 time -= 10; // fast speed looping 3492 time -= 10; // fast speed looping
3110 } 3499 }
3111 3500
3112 // compute integer copy of CNS value 3501 // compute integer copy of CNS value
3113 convert_CNS_for_display(); 3502 convert_CNS_for_display();
3114 3503
3115 3504 // calculate GF value (for a GF high of 100%)
3116 // calculate ceiling (for a GF high of 100%) and gradient factor
3117 calc_limit(1.0); 3505 calc_limit(1.0);
3118 } 3506
3119 3507 // compute integer copy of GF value
3120 3508 convert_GF_for_display();
3121 ////////////////////////////////////////////////////////////////////////////// 3509 }
3122 // calc_CNS_increment 3510
3123 // 3511
3124 // Input: char_ppO2 : current ppO2 [decibars] 3512 //////////////////////////////////////////////////////////////////////////////
3125 // tissue_increment : time increment and tissue selector 3513 // calc_CNS
3126 // 3514 //
3127 // Output: CNS_fraction_inc : increment of the CNS value 3515 // Input: char_ppO2 : current ppO2 [decibars]
3128 // 3516 // tissue_increment : time increment and tissue selector
3129 void calc_CNS_increment(void) 3517 //
3130 { 3518 // Modified: CNS_fraction accumulated CNS (real tissue context)
3131 overlay float time_factor = 1.0; // default is 2sec 3519 // sim_CNS_fraction : accumulated CNS (simulated tissue context)
3520 //
3521 static void calc_CNS(void)
3522 {
3523 overlay float CNS_fraction_inc; // increment of CNS load, 0.01 = 1%
3524 overlay float time_factor; // factor for time increment
3132 3525
3133 assert( char_ppO2 > 15 ); 3526 assert( char_ppO2 > 15 );
3134 3527
3135 // adjust time factor if minute-based stepping is commanded, mask out flag bit 3528 // adjust time factor to 2 seconds (factor = 1.0) or minute-based interval (factor = N * 30.0)
3136 if( tissue_increment & TIME_MASK ) time_factor = 30.0 * (float)(tissue_increment & TIME_MASK); 3529 if( tissue_increment & TIME_MASK ) time_factor = (float)(tissue_increment & TIME_MASK) * 30.0;
3530 else time_factor = 1.0;
3137 3531
3138 //------------------------------------------------------------------------ 3532 //------------------------------------------------------------------------
3139 // Don't increase CNS below 0.5 bar, but keep it steady. 3533 // No CNS increase below 0.5 bar ppO2
3140 if (char_ppO2 < 50) CNS_fraction_inc = 0.0; // no CNS increase below 0.5 bar ppO2 3534 if (char_ppO2 < 50) CNS_fraction_inc = 0.0;
3141 //------------------------------------------------------------------------ 3535 //------------------------------------------------------------------------
3142 // Below (and including) 1.60 bar 3536 // Below (and including) 1.60 bar
3143 else if (char_ppO2 < 61) CNS_fraction_inc = time_factor/(-533.07 * char_ppO2 + 54000.0); 3537 else if (char_ppO2 < 61) CNS_fraction_inc = time_factor/(-533.07 * char_ppO2 + 54000.0);
3144 else if (char_ppO2 < 71) CNS_fraction_inc = time_factor/(-444.22 * char_ppO2 + 48600.0); 3538 else if (char_ppO2 < 71) CNS_fraction_inc = time_factor/(-444.22 * char_ppO2 + 48600.0);
3145 else if (char_ppO2 < 81) CNS_fraction_inc = time_factor/(-355.38 * char_ppO2 + 42300.0); 3539 else if (char_ppO2 < 81) CNS_fraction_inc = time_factor/(-355.38 * char_ppO2 + 42300.0);
3150 //------------------------------------------------------------------------ 3544 //------------------------------------------------------------------------
3151 // Arieli et all.(2002): Modeling pulmonary and CNS O2 toxicity: 3545 // Arieli et all.(2002): Modeling pulmonary and CNS O2 toxicity:
3152 // J Appl Physiol 92: 248--256, 2002, doi:10.1152/japplphysiol.00434.2001 3546 // J Appl Physiol 92: 248--256, 2002, doi:10.1152/japplphysiol.00434.2001
3153 // Formula (A1) based on value for 1.55 and c=20 3547 // Formula (A1) based on value for 1.55 and c=20
3154 // example calculation: Sqrt((1.7/1.55)^20)*0.000404 3548 // example calculation: Sqrt((1.7/1.55)^20)*0.000404
3155 else if (char_ppO2 < 172) CNS_fraction_inc = time_factor*0.00102; 3549 else if (char_ppO2 < 172) CNS_fraction_inc = time_factor * 0.00102;
3156 else if (char_ppO2 < 177) CNS_fraction_inc = time_factor*0.00136; 3550 else if (char_ppO2 < 177) CNS_fraction_inc = time_factor * 0.00136;
3157 else if (char_ppO2 < 182) CNS_fraction_inc = time_factor*0.00180; 3551 else if (char_ppO2 < 182) CNS_fraction_inc = time_factor * 0.00180;
3158 else if (char_ppO2 < 187) CNS_fraction_inc = time_factor*0.00237; 3552 else if (char_ppO2 < 187) CNS_fraction_inc = time_factor * 0.00237;
3159 else if (char_ppO2 < 192) CNS_fraction_inc = time_factor*0.00310; 3553 else if (char_ppO2 < 192) CNS_fraction_inc = time_factor * 0.00310;
3160 else if (char_ppO2 < 198) CNS_fraction_inc = time_factor*0.00401; 3554 else if (char_ppO2 < 198) CNS_fraction_inc = time_factor * 0.00401;
3161 else if (char_ppO2 < 203) CNS_fraction_inc = time_factor*0.00517; 3555 else if (char_ppO2 < 203) CNS_fraction_inc = time_factor * 0.00517;
3162 else if (char_ppO2 < 233) CNS_fraction_inc = time_factor*0.0209; 3556 else if (char_ppO2 < 233) CNS_fraction_inc = time_factor * 0.02090;
3163 else CNS_fraction_inc = time_factor*0.0482; // value for 2.5 bar, used for 2.33 bar and above 3557 else CNS_fraction_inc = time_factor * 0.04820; // value for 2.5 bar, used for 2.33 bar and above
3164 } 3558
3165 3559 // update the CNS accumulator
3166 ////////////////////////////////////////////////////////////////////////////// 3560 if( tissue_increment & TISSUE_FLAG ) CNS_fraction += CNS_fraction_inc; // real tissues
3167 // calc_CNS_planning 3561 else sim_CNS_fraction += CNS_fraction_inc; // simulated tissues
3168 //
3169 // Compute CNS increase during predicted ascent
3170 //
3171 // Input: internal_deco_time[], internal_deco_depth[], internal_deco_gas[]
3172 // Output: sim_CNS_fraction
3173 //
3174 void calc_CNS_planning(void)
3175 {
3176 // null sim_CNS_fraction
3177 sim_CNS_fraction = 0.0;
3178
3179 //---- CCR mode : do the full TTS at once ---------------------------------
3180
3181 if( ((char_O_deco_status & DECO_MODE_MASK) == DECO_MODE_CCR) )
3182 {
3183 overlay unsigned short t; // needs 16 bits here !
3184
3185 // get current ppO2 from sensors or setpoint
3186 char_ppO2 = char_I_const_ppO2;
3187
3188 // calculate CNS% for the period of additional staying at bottom depth (fTTS / delayed ascent)
3189 if( char_O_deco_status & DECO_ASCENT_DELAYED)
3190 {
3191 tissue_increment = char_I_extra_time; // must be limited to 127, is limited by range of char_I_extra_time
3192 calc_CNS_increment(); // calculate the CNS increment
3193 sim_CNS_fraction += CNS_fraction_inc; // sum up
3194 }
3195
3196 // get the ascent time dependent on the current plan +++
3197 t = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? int_O_alternate_ascenttime : int_O_ascenttime;
3198
3199 // start simulating CNS% in chunks of 127 minutes
3200 tissue_increment = 127;
3201
3202 while( t > 127 )
3203 {
3204 t -= 127; // tissue_increment is limited to 127 minutes because of flag in bit 7
3205 calc_CNS_increment(); // calculate CNS in chunks of full 127 minutes
3206 sim_CNS_fraction += CNS_fraction_inc; // sum up
3207 }
3208
3209 tissue_increment = (char)t; // get the remaining minutes <= 127
3210 calc_CNS_increment(); // calculate CNS for the remaining minutes
3211 sim_CNS_fraction += CNS_fraction_inc; // sum up
3212 }
3213 else //---- OC mode and pSCR without sensors: have to follow all gas switches... -----
3214 {
3215 overlay float float_actual_ppO2;
3216 overlay float abs_pres;
3217
3218 overlay unsigned char stop_depth;
3219 overlay unsigned char last_gas;
3220 overlay unsigned char i; // stop table index
3221
3222
3223 // retrieve bottom gas: 1-5 for the configured gases or 0 for the manually set gas
3224 last_gas = sim_gas_last_used = sim_gas_first_used;
3225
3226 // get the calc_N2/He/O2_ratios of the bottom gas
3227 gas_set_ratios();
3228
3229 // calculate absolute pressure
3230 abs_pres = pres_surface + bottom_depth * METER_TO_BAR;
3231
3232 // calculate OC ppO2 (ppWater omitted here on purpose)
3233 float_actual_ppO2 = abs_pres * sim_O2_ratio;
3234
3235 // correct ppO2 in case of pSCR mode by drop
3236 if( char_O_deco_status & DECO_MODE_PSCR ) float_actual_ppO2 -= sim_pSCR_drop;
3237
3238 // convert ppO2 from float to char
3239 if ( float_actual_ppO2 < 0.0 ) char_ppO2 = 0;
3240 else if ( float_actual_ppO2 > 2.545 ) char_ppO2 = 255;
3241 else char_ppO2 = (unsigned char)(100 * float_actual_ppO2 + 0.5);
3242
3243
3244 // simulate extended bottom time (fTTS) / delay before ascent (bailout) if configured
3245 if( char_O_deco_status & DECO_ASCENT_DELAYED )
3246 {
3247 tissue_increment = char_I_extra_time; // must be limited to 127, is limited by range of char_I_extra_time
3248 calc_CNS_increment(); // calculate the CNS increment
3249 sim_CNS_fraction += CNS_fraction_inc; // sum up
3250 }
3251
3252
3253 // For simplicity reason (non-linearity of the relation between ppO2 and CNS increments), the
3254 // whole ascent is calculated with bottom ppO2. This errs, but it does so to the safe side.
3255
3256 // calculate ascent time (integer division and generous round-up)
3257 tissue_increment = bottom_depth / char_I_ascent_speed + 1;
3258
3259 // ** commented out - not needed when char_I_ascent_speed is limited to a minimum
3260 // ** of 2.something, it is indeed limited to a minimum of 5.
3261 //
3262 // // limit tissue_increment to 127 minutes
3263 // if( tissue_increment > 127 ) tissue_increment = 127;
3264
3265 // simulate the CNS increase
3266 calc_CNS_increment(); // calculate the CNS increment
3267 sim_CNS_fraction += CNS_fraction_inc; // sum up
3268
3269
3270 //---- Stops ---------------------------------------------------------
3271
3272 for(i=0; i<NUM_STOPS; ++i)
3273 {
3274 // get the depth of the stop
3275 stop_depth = internal_deco_depth[i];
3276
3277 // did we reach the last entry (depth = 0)? if yes, done
3278 if (stop_depth == 0) break;
3279
3280 // get the duration of the stop and the gas breathed
3281 tissue_increment = internal_deco_time[i];
3282 sim_gas_last_used = internal_deco_gas[i];
3283
3284 // do we have a gas switch?
3285 if( sim_gas_last_used != last_gas )
3286 {
3287 // yes - get new calculation ratios
3288 gas_set_ratios();
3289
3290 // remember new gas as last gas
3291 last_gas = sim_gas_last_used;
3292 }
3293
3294 // calculate absolute pressure at stop depth
3295 abs_pres = pres_surface + stop_depth * METER_TO_BAR;
3296
3297 // calculate OC ppO2 (ppWater omitted here on purpose)
3298 float_actual_ppO2 = abs_pres * sim_O2_ratio;
3299
3300 // correct ppO2 in case of pSCR mode by drop
3301 if( char_O_deco_status & DECO_MODE_PSCR ) float_actual_ppO2 -= sim_pSCR_drop;
3302
3303 // convert ppO2 from float to char
3304 if ( float_actual_ppO2 < 0.0 ) char_ppO2 = 0;
3305 else if ( float_actual_ppO2 > 2.545 ) char_ppO2 = 255;
3306 else char_ppO2 = (unsigned char)(100 * float_actual_ppO2 + 0.5);
3307
3308 // ** Currently, stop times per stop entry are limited to 99 minutes in update_deco_table(),
3309 // ** so the following code block is not needed at times.
3310 //
3311 // // tissue_increment is limited to 127 when fed to calc_CNS_increment(),
3312 // // so if the stop is longer than 127 minutes (but not longer than 254 minutes!)
3313 // // we need to calculate the CNS in two chunks.
3314 // if( tissue_increment > 127)
3315 // {
3316 // tissue_increment -= 127; // subtract full 127 minutes and do the "remaining" minutes first
3317 // calc_CNS_increment(); // calculate the CNS increment
3318 // sim_CNS_fraction += CNS_fraction_inc; // sum up
3319 // tissue_increment = 127; // catch up with the previously subtracted full 127 minutes
3320 // }
3321
3322 // calculate CNS% for the stop
3323 calc_CNS_increment(); // calculate the CNS increment
3324 sim_CNS_fraction += CNS_fraction_inc; // sum up
3325 }
3326 }
3327 } 3562 }
3328 3563
3329 3564
3330 ////////////////////////////////////////////////////////////////////////////// 3565 //////////////////////////////////////////////////////////////////////////////
3331 // gas_volumes 3566 // gas_volumes
3332 // 3567 //
3333 // calculates volumes and required tank fill pressures for each gas. 3568 // calculates volumes and required tank fill pressures for each gas.
3334 // 3569 //
3335 // Input: bottom_depth depth of the bottom segment 3570 // Input: char_bottom_depth depth of the bottom segment
3336 // char_I_bottom_time duration of the bottom segment 3571 // char_I_bottom_time duration of the bottom segment
3337 // char_I_extra_time extra bottom time for fTTS / delayed ascent 3572 // char_I_extra_time extra bottom time for fTTS / delayed ascent
3338 // float_ascent_speed ascent speed, in meters/minute 3573 // float_ascent_speed ascent speed, in meters/minute
3339 // sim_gas_first_used the bottom gas (1-5 for configured gases, 0 for the manual gas)
3340 // internal_deco_depth[] depth of the stops 3574 // internal_deco_depth[] depth of the stops
3341 // internal_deco_time[] duration of the stops 3575 // internal_deco_time[] duration of the stops
3342 // internal_deco_gas[] gas breathed at the stops 3576 // internal_deco_gas[] gas breathed at the stops
3577 // NDL_time remaining NDL time, used to adjust speed of final ascent
3343 // char_I_bottom_usage gas consumption during bottom part and initial ascent, in liters/minute 3578 // char_I_bottom_usage gas consumption during bottom part and initial ascent, in liters/minute
3344 // char_I_deco_usage gas consumption during stops and following ascents, in liters/minute 3579 // char_I_deco_usage gas consumption during stops and following ascents, in liters/minute
3345 // char_I_tank_size[] size of the tanks for gas 1-5, in liters 3580 // char_I_tank_size[] size of the tanks for gas 1-5, in liters
3346 // char_I_tank_pres_fill[] fill pressure of the tanks 3581 // char_I_tank_pres_fill[] fill pressure of the tanks
3347 // 3582 //
3348 // Output: int_O_gas_volumes[] amount of gas needed, in liters 3583 // Output: int_O_ascent_volumes[] amount of gas needed, in liters
3349 // int_O_tank_pres_need[] in bar, + flags for fast evaluation by dive mode warnings: 3584 // int_O_ascent_pres_need[] in bar, + flags for fast evaluation by dive mode warnings:
3350 // 2^15: pres_need >= pres_fill 3585 // 2^15: pres_need >= pres_fill
3351 // 2^14: pres_need >= press_fill * GAS_NEEDS_ATTENTION_THRESHOLD 3586 // 2^14: pres_need >= press_fill * GAS_NEEDS_ATTENTION_THRESHOLD
3352 // 2^11: pres_need == 0 3587 // 2^11: pres_need == 0
3353 // 2^10: pres_need invalid 3588 // 2^10: pres_need is invalid
3354 // 3589 //
3355 void gas_volumes_helper(void) 3590 static void gas_volumes_helper_1(void)
3356 { 3591 {
3357 // Calculate the gas volume needed at a given depth, time and usage (SAC rate). 3592 // Calculate the gas volume needed at a given depth, time and usage (SAC rate).
3358 // We use 1.0 for the surface pressure to have stable results when used through 3593 // We use 1.0 for the surface pressure to have stable results when used through
3359 // the deco calculator (simulation mode). 3594 // the deco calculator (simulation mode).
3360 volume = (float_depth * METER_TO_BAR + 1.0) * float_time * usage; 3595 volume = (float_depth * METER_TO_BAR + 1.0) * float_time * char_usage;
3361 3596
3362 return; 3597 return;
3363 } 3598 }
3364 3599
3365 void gas_volumes(void) 3600 static void gas_volume_helper_2(void)
3601 {
3602 // Convert a gas volume in liters given as a float into an integer number
3603 // and computes the equivalent tank pressure in bar, including all flags.
3604
3605 if( volume >= 65534.5 )
3606 {
3607 int_volume = 65535;
3608 int_pres_need = 999 + INT_FLAG_WARNING; // 999 bar + warning flag for > pres_fill
3609 }
3610 else
3611 {
3612 overlay unsigned short tank_pres_fill = 10.0 * (unsigned short)char_I_tank_pres_fill[gas_num];
3613
3614 // No distinct rounding done here because volumes are not accurate to the single liter anyhow
3615
3616 // convert gas volumes to integers
3617 int_volume = (unsigned short)volume;
3618
3619 // compute how much pressure in the tank will be needed [in bar] (integer-division)
3620 int_pres_need = (unsigned short)(int_volume / char_I_tank_size[gas_num]);
3621
3622 // limit to 999 bar because of display constraints
3623 if( int_pres_need > 999 ) int_pres_need = 999;
3624
3625 // set flags for fast evaluation by divemode check_for_warnings
3626 if ( int_pres_need == 0 ) int_pres_need |= INT_FLAG_ZERO;
3627 else if( int_pres_need >= tank_pres_fill ) int_pres_need |= INT_FLAG_WARNING;
3628 else if( int_pres_need >= GAS_NEEDS_ATTENTION_THRESHOLD * tank_pres_fill ) int_pres_need |= INT_FLAG_ATTENTION;
3629 }
3630
3631 return;
3632 }
3633
3634 static void gas_volumes(void)
3366 { 3635 {
3367 overlay float volumes[NUM_GAS]; 3636 overlay float volumes[NUM_GAS];
3368 3637
3369 overlay unsigned char stop_gas; 3638 overlay unsigned char stop_gas;
3370 overlay unsigned char stop_gas_last; 3639 overlay unsigned char stop_gas_last;
3371 overlay unsigned char stop_time; 3640 overlay unsigned char stop_time;
3372 overlay unsigned char stop_depth; 3641 overlay unsigned char stop_depth;
3373 overlay unsigned char stop_depth_last; 3642 overlay unsigned char stop_depth_last;
3374 overlay unsigned char i; 3643 overlay unsigned char i;
3375 3644
3376
3377 //---- initialization ---------------------------------------------------- 3645 //---- initialization ----------------------------------------------------
3378 3646
3379 // null the volume accumulators 3647 // null the volume accumulators
3380 for(i=0; i<NUM_GAS; ++i) volumes[i] = 0.0; 3648 for( gas_num = 0; gas_num < NUM_GAS; ++gas_num ) volumes[gas_num] = 0.0;
3381 3649
3382 // quit for CCR and pSCR mode 3650 // quit for CCR and pSCR mode
3383 if( char_O_deco_status & DECO_MODE_LOOP ) goto done; 3651 if( char_O_deco_status & DECO_MODE_LOOP ) goto done;
3384 3652
3385 3653
3386 //---- bottom demand ----------------------------------------------------- 3654 //---- bottom demand -----------------------------------------------------
3387 3655
3388 // sim_gas_first_used : gas used during bottom segment (0, 1-5) 3656 // sim_gas_current : gas used during bottom segment (0, 1-5)
3389 // bottom_depth: depth of the bottom segment 3657 // char_bottom_depth: depth of the bottom segment
3390
3391 assert(0 <= sim_gas_first_used && sim_gas_first_used <= NUM_GAS);
3392 3658
3393 // get the gas used during bottom segment 3659 // get the gas used during bottom segment
3394 stop_gas_last = stop_gas = sim_gas_first_used; 3660 gas_find_current();
3661
3662 // initialize variables
3663 stop_gas_last = stop_gas = sim_gas_current;
3395 3664
3396 // set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent 3665 // set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent
3397 usage = char_I_bottom_usage; 3666 char_usage = char_I_bottom_usage;
3398 3667
3399 // volumes are only calculated for gases 1-5, but not the manually configured one 3668 // volumes are only calculated for gases 1-5, but not the manually configured one
3400 if( stop_gas ) 3669 if( stop_gas )
3401 { 3670 {
3402 // set the bottom depth 3671 // set the bottom depth
3403 float_depth = (float)bottom_depth; 3672 float_depth = (float)char_bottom_depth;
3404 3673
3405 // calculate either bottom segment or just the fTTS/bailout delayed part 3674 // calculate either bottom segment or just the fTTS/bailout delayed part
3406 if( char_O_main_status & DECO_BOTTOM_CALCULATE ) 3675 if( char_O_main_status & DECO_BOTTOM_CALCULATE )
3407 { 3676 {
3408 // duration of bottom segment 3677 // duration of bottom segment
3413 // duration of delayed ascent 3682 // duration of delayed ascent
3414 float_time = (float)char_I_extra_time; 3683 float_time = (float)char_I_extra_time;
3415 } 3684 }
3416 3685
3417 // calculate gas demand 3686 // calculate gas demand
3418 gas_volumes_helper(); 3687 gas_volumes_helper_1();
3419 3688
3420 // take result 3689 // take result
3421 volumes[stop_gas-1] = volume; 3690 volumes[stop_gas-1] = volume;
3422 } 3691 }
3423 3692
3425 i = 0; 3694 i = 0;
3426 3695
3427 //---- initial ascent demand --------------------------------------------- 3696 //---- initial ascent demand ---------------------------------------------
3428 3697
3429 // stop_gas : gas from bottom segment 3698 // stop_gas : gas from bottom segment
3430 // bottom_depth : depth of the bottom segment 3699 // char_bottom_depth : depth of the bottom segment
3431 // internal_deco_depth[i=0]: depth of the first stop, may be 0 if no stop exists 3700 // internal_deco_depth[i=0]: depth of the first stop, may be 0 if no stop exists
3432 3701
3433 // get the data of the first stop 3702 // get the data of the first stop
3434 stop_depth = internal_deco_depth[i]; 3703 stop_depth = internal_deco_depth[i];
3435 stop_time = internal_deco_time[i]; 3704 stop_time = internal_deco_time[i];
3436 3705
3437 // volumes are only calculated for gases 1-5, but not the manually configured one 3706 // volumes are only calculated for gases 1-5, but not the manually configured one
3438 if( stop_gas ) 3707 if( stop_gas )
3439 { 3708 {
3440 // compute distance between bottom and first stop 3709 // compute distance between bottom and first stop
3441 float_depth = (float)bottom_depth - (float)stop_depth; 3710 float_depth = (float)(char_bottom_depth - stop_depth);
3442 3711
3443 // initial ascent exists only if ascent distance is > 0 3712 // initial ascent exists only if ascent distance is > 0
3444 if( float_depth > 0.0 ) 3713 if( float_depth > 0.0 )
3445 { 3714 {
3446 // compute ascent time 3715 // compute ascent time
3447 float_time = float_depth / float_ascent_speed; 3716 float_time = float_depth / float_ascent_speed;
3448 3717
3449 // compute average depth between bottom and first stop 3718 // compute average depth between bottom and first stop
3450 float_depth = (float)bottom_depth - float_depth * 0.5; 3719 float_depth = (float)char_bottom_depth - float_depth * 0.5;
3451 3720
3452 // calculate gas demand 3721 // calculate gas demand
3453 gas_volumes_helper(); 3722 gas_volumes_helper_1();
3454 3723
3455 // add result 3724 // add result
3456 volumes[stop_gas-1] += volume; 3725 volumes[stop_gas-1] += volume;
3457 } 3726 }
3458 } 3727 }
3459 3728
3460 // switch the usage (SAC rate) to deco usage rate 3729 // switch the usage (SAC rate) to deco usage rate
3461 // for stops, intermediate and final ascent 3730 // for stops, intermediate and final ascent
3462 usage = char_I_deco_usage; 3731 char_usage = char_I_deco_usage;
3463 3732
3464 // is there a (first) stop? if yes, goto stops processing 3733 // is there a (first) stop? if yes, goto stops processing
3465 if( stop_depth ) goto stops; 3734 if( stop_depth ) goto stops;
3466 3735
3467 // add demand of a 3 minutes safety stop at 5 meters, at least for contingency... 3736 // add demand of a 3 minutes safety stop at 5 meters, at least for contingency...
3468 float_time = 3.0; 3737 float_time = 3.0;
3469 float_depth = 5.0; 3738 float_depth = 5.0;
3470 3739
3471 // calculate gas demand 3740 // calculate gas demand
3472 gas_volumes_helper(); 3741 gas_volumes_helper_1();
3473 3742
3474 // add result 3743 // add result
3475 volumes[stop_gas-1] += volume; 3744 volumes[stop_gas-1] += volume;
3476 3745
3477 // proceed to volume conversion and pressure calculations 3746 // proceed to volume conversion and pressure calculations
3524 3793
3525 // compute average depth between the two stops 3794 // compute average depth between the two stops
3526 float_depth = (float)stop_depth_last - float_depth * 0.5; 3795 float_depth = (float)stop_depth_last - float_depth * 0.5;
3527 3796
3528 // calculate gas demand 3797 // calculate gas demand
3529 gas_volumes_helper(); 3798 gas_volumes_helper_1();
3530 3799
3531 // add result 3800 // add result
3532 volumes[stop_gas_last-1] += volume; 3801 volumes[stop_gas_last-1] += volume;
3533 } 3802 }
3534 3803
3539 // convert depth of the stop 3808 // convert depth of the stop
3540 float_depth = (float)stop_depth; 3809 float_depth = (float)stop_depth;
3541 3810
3542 // get the next gas 3811 // get the next gas
3543 stop_gas = internal_deco_gas[i]; 3812 stop_gas = internal_deco_gas[i];
3544 3813
3545 // in case of end-of-table, keep the last gas 3814 // in case of end-of-table, keep the last gas
3546 if( !stop_gas ) stop_gas = stop_gas_last; 3815 if( !stop_gas ) stop_gas = stop_gas_last;
3547 3816
3548 // do we we have a gas change? 3817 // do we have a gas change?
3549 if( stop_gas_last && (stop_gas != stop_gas_last) ) 3818 if( stop_gas_last && (stop_gas != stop_gas_last) )
3550 { 3819 {
3551 // yes - spend an additional char_I_gas_change_time on the old gas 3820 // yes - spend an additional char_I_gas_change_time on the old gas
3552 float_time = (float)char_I_gas_change_time; 3821 float_time = (float)char_I_gas_change_time;
3553 3822
3554 // calculate gas demand 3823 // calculate gas demand
3555 gas_volumes_helper(); 3824 gas_volumes_helper_1();
3556 3825
3557 // add result 3826 // add result
3558 volumes[stop_gas_last-1] += volume; 3827 volumes[stop_gas_last-1] += volume;
3559 } 3828 }
3560 3829
3563 { 3832 {
3564 // get the duration of the stop 3833 // get the duration of the stop
3565 float_time = (float)stop_time; 3834 float_time = (float)stop_time;
3566 3835
3567 // calculate gas demand 3836 // calculate gas demand
3568 gas_volumes_helper(); 3837 gas_volumes_helper_1();
3569 3838
3570 // add result to last gas 3839 // add result to last gas
3571 volumes[stop_gas-1] += volume; 3840 volumes[stop_gas-1] += volume;
3572 } 3841 }
3573 3842
3579 final_ascent: 3848 final_ascent:
3580 3849
3581 // float_depth: depth of last stop 3850 // float_depth: depth of last stop
3582 // stop_gas : gas from last stop (0 or 1-5) 3851 // stop_gas : gas from last stop (0 or 1-5)
3583 3852
3584 // volumes are only calculated for gases 1-5, but not the manually configured one 3853 // volumes are only calculated for gases 1-5, but not the manually configured one
3585 if( stop_gas ) 3854 if( stop_gas )
3586 { 3855 {
3587 // set ascent time according to an ascent speed of 1 meter per minute 3856 // set ascent time dependent on deco status
3588 float_time = float_depth; 3857 if( NDL_time )
3858 {
3859 // within NDL - ascent with float_ascent_speed
3860 float_time = float_depth / float_ascent_speed;
3861 }
3862 else
3863 {
3864 // in deco - reduce ascent speed to 1 meter per minute
3865 float_time = float_depth;
3866 }
3589 3867
3590 // set half-way depth 3868 // set half-way depth
3591 float_depth *= 0.5; 3869 float_depth *= 0.5;
3592 3870
3593 // calculate gas demand 3871 // calculate gas demand
3594 gas_volumes_helper(); 3872 gas_volumes_helper_1();
3595 3873
3596 // add result 3874 // add result
3597 volumes[stop_gas-1] += volume; 3875 volumes[stop_gas-1] += volume;
3598 } 3876 }
3599 3877
3600 3878
3601 //---- convert results for the assembler interface ----------------------------- 3879 //---- convert results for the assembler interface -----------------------------
3602 done: 3880 done:
3603 3881
3604 for(i=0; i<NUM_GAS; ++i) 3882 #ifdef _rx_functions
3605 { 3883 // only for OSTC TR model with TR functions enabled
3606 if( volumes[i] >= 65534.5 ) 3884 if( char_O_main_status & DECO_TR_FUNCTIONS )
3607 { 3885 {
3608 int_O_gas_volumes[i] = 65535; 3886 // invalidate pressure needs to pressure readings
3609 int_O_tank_pres_need[i] = 999 + INT_FLAG_WARNING; // 999 bar + warning flag for > pres_fill 3887 int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL;
3610 } 3888 int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL;
3611 else 3889 }
3612 { 3890 #endif
3613 overlay unsigned short tank_pres_fill = 10.0 * (unsigned short)char_I_tank_pres_fill[i]; 3891
3614 3892 for( gas_num = 0; gas_num < NUM_GAS; ++gas_num )
3615 // No distinct rounding done here because volumes are not accurate to the single liter anyhow 3893 {
3616 3894 volume = volumes[gas_num];
3617 // convert gas volumes to integers 3895
3618 int_O_gas_volumes[i] = (unsigned short)volumes[i]; 3896 // compute int_volume and int_pres_need from volume and gas_num
3619 3897 gas_volume_helper_2();
3620 // compute how much pressure in the tank will be needed [in bar] (integer-division) 3898
3621 int_O_tank_pres_need[i] = (unsigned short)(int_O_gas_volumes[i] / char_I_tank_size[i]); 3899 // set invalid flag if there is an overflow in the stops table
3622 3900 if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW )
3623 // limit to 999 bar because of display constraints 3901 int_pres_need |= INT_FLAG_INVALID;
3624 if( int_O_tank_pres_need[i] > 999 ) int_O_tank_pres_need[i] = 999; 3902
3625 3903 // copy result data to ASM interface
3626 // set flags for fast evaluation by divemode check for warnings 3904 int_O_ascent_volumes[gas_num] = int_volume;
3627 if ( int_O_tank_pres_need[i] == 0 ) 3905 int_O_ascent_pres_need[gas_num] = int_pres_need;
3906
3907 #ifdef _rx_functions
3908 // only for OSTC TR model with TR functions enabled
3909 if( char_O_main_status & DECO_TR_FUNCTIONS )
3910 {
3911 // char_I_pressure_gas[] uses gas numbers 1-10, gas_num runs from 0 to 4
3912 overlay unsigned char gas = gas_num + 1;
3913
3914 // check if the current gas is configured on pressure reading 1 or 2
3915 if( (gas == char_I_pressure_gas[0]) || (gas == char_I_pressure_gas[1]) )
3628 { 3916 {
3629 // set flag for 0 bar 3917 // strip all flags from int_pres_need
3630 int_O_tank_pres_need[i] |= INT_FLAG_ZERO; 3918 int_pres_need &= 1023;
3919
3920 // limit to 400 bar and multiply by 10 to get result in 0.1 bar
3921 int_pres_need = (int_pres_need > 400) ? (4000 | INT_FLAG_OUT_OF_RANGE) : (10 * int_pres_need);
3922
3923 // tag as not available if there is an overflow in the stops table
3924 if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW )
3925 int_pres_need |= INT_FLAG_NOT_AVAIL;
3926
3927 // copy to result vars (in both readings the same gas could be configured)
3928 if( gas == char_I_pressure_gas[0] ) int_O_pressure_need[0] = int_pres_need;
3929 if( gas == char_I_pressure_gas[1] ) int_O_pressure_need[1] = int_pres_need;
3631 } 3930 }
3632 else if( int_O_tank_pres_need[i] >= tank_pres_fill ) 3931 } // TR functions
3633 { 3932 #endif
3634 // set warning flag 3933
3635 int_O_tank_pres_need[i] |= INT_FLAG_WARNING;
3636
3637 }
3638 else if( int_O_tank_pres_need[i] >= tank_pres_fill * GAS_NEEDS_ATTENTION_THRESHOLD )
3639 {
3640 // set pre-warning flag
3641 int_O_tank_pres_need[i] |= INT_FLAG_ATTENTION;
3642 }
3643
3644 // set invalid flag if there is an overflow in the stops table
3645 if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW )
3646 int_O_tank_pres_need[i] |= INT_FLAG_INVALID;
3647
3648 } // if( volumes[i] )
3649 } // for 3934 } // for
3650 } 3935 }
3651 3936
3652 ////////////////////////////////////////////////////////////////////////////// 3937 //////////////////////////////////////////////////////////////////////////////
3653 3938
3654 void convert_CNS_for_display(void) 3939 static void convert_CNS_for_display(void)
3655 { 3940 {
3656 if ( CNS_fraction < 0.01 ) int_O_CNS_fraction = 0; 3941 if( CNS_fraction < 0.010 ) int_O_CNS_fraction = 0;
3657 else if ( CNS_fraction >= 9.985 ) int_O_CNS_fraction = 999 + INT_FLAG_WARNING; 3942 else if( CNS_fraction >= 9.985 ) int_O_CNS_fraction = 999 + INT_FLAG_WARNING;
3658 else 3943 else
3659 { 3944 {
3660 // convert float to integer 3945 // convert float to integer
3661 int_O_CNS_fraction = (unsigned short)(100 * CNS_fraction + 0.5); 3946 int_O_CNS_fraction = (unsigned short)(100 * CNS_fraction + 0.5);
3662 3947
3663 // set warnings 3948 // set warning & attention flags
3664 if ( int_O_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_O_CNS_fraction |= INT_FLAG_WARNING; 3949 if( int_O_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_O_CNS_fraction |= INT_FLAG_WARNING;
3665 else if ( int_O_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_fraction |= INT_FLAG_ATTENTION; 3950 else if( int_O_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_fraction |= INT_FLAG_ATTENTION;
3666 } 3951 }
3667 } 3952 }
3668 3953
3669 ////////////////////////////////////////////////////////////////////////////// 3954 //////////////////////////////////////////////////////////////////////////////
3670 3955
3671 void convert_sim_CNS_for_display(void) 3956 static void convert_sim_CNS_for_display(void)
3672 { 3957 {
3673 if ( sim_CNS_fraction < 0.01 ) int_sim_CNS_fraction = 0; 3958 if( sim_CNS_fraction < 0.010 ) int_sim_CNS_fraction = 0;
3674 else if ( sim_CNS_fraction >= 9.985 ) int_sim_CNS_fraction = 999 + INT_FLAG_WARNING; 3959 else if( sim_CNS_fraction >= 9.985 ) int_sim_CNS_fraction = 999 + INT_FLAG_WARNING;
3675 else 3960 else
3676 { 3961 {
3677 // convert float to integer 3962 // convert float to integer
3678 int_sim_CNS_fraction = (unsigned short)(100 * sim_CNS_fraction + 0.5); 3963 int_sim_CNS_fraction = (unsigned short)(100 * sim_CNS_fraction + 0.5);
3679 3964
3680 // set warning flag if CNS is >= 100% 3965 // set warning & attention flags
3681 if ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_WARNING; 3966 if ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_WARNING;
3682 else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION; 3967 else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION;
3683 3968 }
3684 // set invalid flag if there is an overflow in the stops table 3969
3685 if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID; 3970 // set invalid flag if there is an overflow in the stops table
3686 } 3971 if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID;
3972 }
3973
3974 //////////////////////////////////////////////////////////////////////////////
3975
3976 static void convert_GF_for_display(void)
3977 {
3978 // convert supersaturation of the leading tissue to int_O_gradient_factor in % (1.0 = 100%)
3979 // limit to 255 because of constraints in ghostwriter code
3980 if( lead_supersat <= 0.000 ) int_O_gradient_factor = 0;
3981 else if( lead_supersat > 2.545 ) int_O_gradient_factor = 255 + INT_FLAG_WARNING;
3982 else
3983 {
3984 int_O_gradient_factor = (unsigned int)(100 * lead_supersat + 0.5);
3985
3986 if( char_I_deco_model != 0 )
3987 {
3988 // GF factors enabled
3989 if( int_O_gradient_factor >= char_I_GF_High_percentage )
3990 {
3991 int_O_gradient_factor |= INT_FLAG_ATTENTION; // make GF factor shown in yellow
3992 char_O_deco_warnings |= DECO_ATTENTION_OUTSIDE; // make depth blink in yellow
3993 }
3994
3995 if( int_O_gradient_factor >= 100 )
3996 int_O_gradient_factor |= INT_FLAG_WARNING; // make GF factor shown in red
3997 }
3998 else
3999 {
4000 // straight Buhlmann
4001 if ( int_O_gradient_factor >= 100 )
4002 int_O_gradient_factor |= INT_FLAG_WARNING; // make GF factor shown in red
4003
4004 else if ( int_O_gradient_factor >= 90 )
4005 {
4006 int_O_gradient_factor |= INT_FLAG_ATTENTION; // make GF factor shown in yellow
4007 char_O_deco_warnings |= DECO_ATTENTION_OUTSIDE; // make depth blink in yellow
4008 }
4009 }
4010 }
4011
4012 // export also the number of the leading tissue
4013 char_O_lead_number = lead_number;
4014 }
4015
4016 //////////////////////////////////////////////////////////////////////////////
4017
4018 static void convert_ceiling_for_display(void)
4019 {
4020 // Convert ceiling to int_O_ceiling in mbar relative pressure.
4021 // Round up to next 10 cm so that the ceiling disappears only
4022 // when the ceiling limit is really zero. This will coincident
4023 // with TTS switching back to NDL time.
4024 if( ceiling <= 0.0 ) int_O_ceiling = 0;
4025 else if( ceiling > 16.0 ) int_O_ceiling = 16000;
4026 else int_O_ceiling = (short)(ceiling * 1000 + 9);
4027
4028 // set/reset ceiling flag
4029 if( int_O_ceiling ) char_O_deco_info |= DECO_CEILING;
4030 else char_O_deco_info &= ~DECO_CEILING;
3687 } 4031 }
3688 4032
3689 ////////////////////////////////////////////////////////////////////////////// 4033 //////////////////////////////////////////////////////////////////////////////
3690 // push_tissues_to_vault & pull_tissues_from_vault 4034 // push_tissues_to_vault & pull_tissues_from_vault
3691 // 4035 //
3692 // ATTENTION: Do not use from inside the deco engine! 4036 // ATTENTION: Do not use from inside the deco engine!
3693 // The vault is exclusively reserved to back-up and restore the real 4037 // The vault is exclusively reserved to back-up and restore the real
3694 // tissues and related data when entering / leaving simulation mode! 4038 // tissues and related data when entering / leaving simulation mode!
3695 // 4039 //
3696 4040
3697 void push_tissues_to_vault(void) 4041 static void push_tissues_to_vault(void)
3698 { 4042 {
3699 overlay unsigned char x; 4043 overlay unsigned char x;
3700 4044
3701 cns_vault_float = CNS_fraction; 4045 cns_vault_float = CNS_fraction;
3702 deco_warnings_vault = char_O_deco_warnings; 4046 deco_warnings_vault = char_O_deco_warnings;
3703 4047
3704 for (x=0;x<NUM_COMP;x++) 4048 for( x = 0; x < NUM_COMP; x++ )
3705 { 4049 {
3706 pres_tissue_N2_vault[x] = pres_tissue_N2[x]; 4050 pres_tissue_N2_vault[x] = pres_tissue_N2[x];
3707 pres_tissue_He_vault[x] = pres_tissue_He[x]; 4051 pres_tissue_He_vault[x] = pres_tissue_He[x];
3708 } 4052 }
3709 } 4053 }
3710 4054
3711 void pull_tissues_from_vault(void) 4055 static void pull_tissues_from_vault(void)
3712 { 4056 {
3713 overlay unsigned char x; 4057 overlay unsigned char x;
3714 4058
3715 CNS_fraction = cns_vault_float; 4059 CNS_fraction = cns_vault_float;
3716 char_O_deco_warnings = deco_warnings_vault; 4060 char_O_deco_warnings = deco_warnings_vault;
3717 4061
3718 convert_CNS_for_display(); 4062 convert_CNS_for_display();
3719 4063
3720 locked_GF_step_norm = GF_delta / low_depth_norm; 4064 for( x = 0; x < NUM_COMP; x++ )
3721 locked_GF_step_alt = GF_delta / low_depth_alt;
3722
3723 for (x=0; x<NUM_COMP; x++)
3724 { 4065 {
3725 pres_tissue_N2[x] = pres_tissue_N2_vault[x]; 4066 pres_tissue_N2[x] = pres_tissue_N2_vault[x];
3726 pres_tissue_He[x] = pres_tissue_He_vault[x]; 4067 pres_tissue_He[x] = pres_tissue_He_vault[x];
3727 } 4068 }
3728 } 4069 }