diff src/p2_deco.c @ 623:c40025d8e750

3.03 beta released
author heinrichsweikamp
date Mon, 03 Jun 2019 14:01:48 +0200
parents 7b3903536213
children cd58f7fc86db
line wrap: on
line diff
--- a/src/p2_deco.c	Wed Apr 10 10:51:07 2019 +0200
+++ b/src/p2_deco.c	Mon Jun 03 14:01:48 2019 +0200
@@ -1,5 +1,5 @@
 // ***************************************************************************
-// p2_deco.c                                         REFACTORED VERSION V2.99f
+// p2_deco.c                                  combined next generation V3.03.4
 //
 //  Created on: 12.05.2009
 //  Author: heinrichs weikamp, contributions by Ralph Lembcke and others
@@ -12,42 +12,42 @@
 //
 //    This program is free software: you can redistribute it and/or modify
 //    it under the terms of the GNU General Public License as published by
-//    the Free Software Foundation, either version 3 of the License, or
+//    the Free Software Foundation, either version 3 of  the  License,  or
 //    (at your option) any later version.
 //
 //    This program is distributed in the hope that it will be useful,
 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
-//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//    MERCHANTABILITY  or  FITNESS FOR A PARTICULAR PURPOSE. See the
 //    GNU General Public License for more details.
 //
 //    You should have received a copy of the GNU General Public License
-//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//    along with this program. If not, see <http://www.gnu.org/licenses/>.
 //
 //////////////////////////////////////////////////////////////////////////////
 
-// history:
+// History:
 // 01/03/08 v100: first release candidate
 // 03/13/08 v101: start of programming ppO2 code
 // 03/13/25 v101a: backup of interim version with ppO2 calculation
 // 03/13/25 v101: open circuit gas change during deco
-// 03/13/25 v101: CNS_fraction calculation
+// 03/13/25 v101: CNS_fraction_real calculation
 // 03/13/26 v101: optimization of tissue calc routines
-// 07/xx/08 v102a: debug of bottom time routine
-// 09/xx/08 v102d: Gradient Factor Model implementation
-// 10/10/08 v104: renamed to build v103 for v118 stable
-// 10/14/08 v104: integration of char_I_depth_last_deco for Gradient Model
-// 03/31/09 v107: integration of FONT Incon24
-// 05/23/10 v109: 5 gas changes & 1 min timer
-// 07/13/10 v110: cns vault added
-// 12/25/10 v110: split in three files (deco.c, main.c, definitions.h)
+// 07/xx/2008 v102a: debug of bottom time routine
+// 09/xx/2008 v102d: Gradient Factor Model implementation
+// 10/10/2008 v104: renamed to build v103 for v118 stable
+// 10/14/2008 v104: integration of char_I_depth_last_deco for Gradient Model
+// 03/31/2009 v107: integration of FONT Incon24
+// 05/23/2010 v109: 5 gas changes & 1 min timer
+// 07/13/2010 v110: cns vault added
+// 12/25/2010 v110: split in three files (deco.c, main.c, definitions.h)
 // 2011/01/20: [jDG] Create a common file included in ASM and C code.
-// 2011/01/24: [jDG] Make ascenttime an short. No more overflow!
+// 2011/01/24: [jDG] Make ascent time an short. No more overflow!
 // 2011/01/25: [jDG] Fusion deco array for both models.
 // 2011/01/25: [jDG] Use CF(54) to reverse deco order.
 // 2011/02/11: [jDG] Reworked gradient-factor implementation.
 // 2011/02/15: [jDG] Fixed inconsistencies introduced by gas switch delays.
 // 2011/03/21: [jDG] Added gas consumption (CF56 & CF57) evaluation for OCR mode.
-// 2011/04/15: [jDG] Store low_depth in 32bits (w/o rounding), for a better stability.
+// 2011/04/15: [jDG] Store GF_low_depth in 32 bits (w/o rounding), for a better stability.
 // 2011/04/25: [jDG] Added 1mn mode for CNS calculation, to allow it for deco planning.
 // 2011/04/27: [jDG] Fixed char_O_gradient_factor calculation when model uses gradient-factor.
 // 2011/05/02: [jDG] Added "Future TTS" function (CF58).
@@ -58,8 +58,8 @@
 // 2012/02/24: [jDG] Remove missed stop bug.
 // 2012/02/25: [jDG] Looking for a more stable LOW grad factor reference.
 // 2012/09/10: [mH]  Fill char_O_deco_time_for_log for logbook write
-// 2012/10/05: [jDG] Better gas_volumes accuracy (average depth, switch between stop).
-// 2013/03/05: [jDG] Should vault low_depth too.
+// 2012/10/05: [jDG] Better calc_gas_needs_ascent accuracy (average depth, switch between stop).
+// 2013/03/05: [jDG] Should vault GF_low_depth too.
 // 2013/03/05: [jDG] Wrobell remark: ascent_to_first_stop works better with finer steps (2sec).
 // 2013/05/08: [jDG] A. Salm remark: NOAA tables for CNS are in ATA, not bar.
 // 2013/12/21: [jDG] Fix CNS calculation in deco plan w/o marked gas switch
@@ -87,10 +87,12 @@
 //
 // *********************************************************************************************************************************
 
+
 #include	<math.h>
 #include	"p2_definitions.h"
 #define		TEST_MAIN
 #include	"shared_definitions.h"
+#include	"configuration.inc"
 
 
 // *********************************************************************************************************************************
@@ -99,10 +101,11 @@
 //
 // *********************************************************************************************************************************
 
-// conditional compiles
-#define		_rx_functions						// if defined, compile transmitter functions   (default:     included *)
-//#define	_cave_mode							// if defined, compile cave mode into firmware (default: not included *)   ## OPTION IS UNDER CONSTRUCTION ##
-												// * option needs to be included / excluded in hwos.inc, too!
+
+// deco engine scheduling
+#define INVOKES_PER_SECOND				2		// number of invocations of the deco engine per second (use powers of 2 only: 1, 2, 4, ...)
+#define BUDGET_PER_SECOND				640		// [ms] total time budget per second for the deco engine, each invocation will preempt after BUDGET_PER_SECOND / INVOKES_PER_SECOND
+
 
 // ambient pressure at different mountain heights
 #define P_ambient_1000m					0.880	// [bar]  based on 990 hPa and 20°C at sea level, 15°C at altitude
@@ -122,7 +125,6 @@
 #define SURFACE_DESAT_FACTOR			0.70420	// surface desaturation safety factor
 #define HYST							1.0E-06	// threshold for tissue graphics on-gassing / off-gassing visualization
 
-
 // thresholds
 #define CNS_WARNING_THRESHOLD			100		// threshold for CNS  warning
 #define CNS_ATTENTION_THRESHOLD			 70		// threshold for CNS  attention
@@ -131,39 +133,47 @@
 #define PRESSURE_LIMIT_WARNING			200		// threshold for pressure reading warning  : 20.0 bar
 #define PRESSURE_LIMIT_ATTENTION		500		// threshold for pressure reading attention: 50.0 bar
 #define O2_CONSUMPTION_LIMIT_ATTENTION	 20		// threshold for O2 "SAC"         attention:  2.0 l/min
-
-// deco engine states and modes - char_O_main_status: controls current tissue and deco status calculation (as-is situation)
-#define DECO_COMPLETED_NORM				0x01	// the calculation of a normal       deco plan has just been completed
-#define DECO_COMPLETED_ALT				0x02	// the calculation of an alternative deco plan has just been completed
-//#define DECO_MODE_MASK				0x0C	// mask for mode selection ==> current diving mode
-//#define DECO_MODE_LOOP				0x04	// see below
-//#define DECO_MODE_CCR					0x04	// see below
-//#define DECO_MODE_PSCR				0x08	// see below
-
-#define DECO_USE_Z_FACTOR				0x10	// =1: figure in Z factor when converting gas volumes <-> pressures
-#define DECO_CAVE_MODE					0x20	// =1: activate ascent gas needs calculation under cave constraints
-#define DECO_BOTTOM_CALCULATE			0x40	// =1: switch to deco calculator interface
-#define DECO_TR_FUNCTIONS				0x80	// =1: activate TR functions (pressure reading) processing
-
-// deco engine states and modes - char_O_deco_status: controls deco plan calculation (to-be scenario)
-#define DECO_STATUS_MASK				0x03	// bit mask for values below
-#define DECO_STATUS_START				0x00	// value commands the start of a new deco calculation cycle
-#define DECO_STATUS_FINISHED			0x00	// value indicates completion of deco calculation
-#define DECO_STATUS_STOPS				0x01	// value indicated calculation is ongoing, currently calculating the stops
-#define DECO_STATUS_RESULTS				0x02	// value indicates calculation is ongoing, currently calculating the results
-#define DECO_STATUS_INIT				0x03	// value to be set once for the first invocation at the begin of a new dive
-
-#define DECO_MODE_MASK					0x0C	// mask for mode selection ==> diving mode during ascent
-#define DECO_MODE_LOOP					0x04	// =1: CCR (DECO_MODE_PSCR needs to be cleared) or pSCR mode
-#define DECO_MODE_CCR					0x04	// to be used with == operator in combination with DECO_MODE_MASK only!
-#define DECO_MODE_PSCR					0x08	// =1: pSCR mode (DECO_MODE_LOOP needs to be set, too)
-
-#define DECO_PLAN_ALTERNATE				0x10	// =1: calculate the 2nd (alternative) deco plan
-#define DECO_BAILOUT_MODE				0x20	// =1: do a bailout calculation, i.e. allow gas switches before first deco stop
-#define DECO_VOLUME_CALCULATE			0x40	// =1: calculate ascent gas needs
-#define DECO_ASCENT_DELAYED				0x80	// =1: calculate a delayed ascent (fTTS)
-
-// deco engine warnings - char_O_deco_warnings
+#define ppO2_MARGIN_ON_MAX				  3		// [cbar] margin on ppO2 max to compensate for surface pressures > 1.000 mbar
+
+// deco engine states and modes - (char_O_)main_status: controls current tissue and deco status calculation (as-is situation)
+#define CALC_VOLUME						0x01	// =1: calculate gas needs
+#define CALCULATE_BOTTOM				0x02	// =1: calculate gas needs in deco calculator mode, =0: in dive mode
+#define CAVE_MODE						0x04	// =1: calculate ascent and gas needs using backtracking data
+#define USE_Z_FACTOR					0x08	// =1: calculate with Z factor when converting gas volumes <-> pressures
+
+#define TR_FUNCTIONS					0x10	// =1: calculate TR functions (pressure reading) processing
+#define EXTENDED_STOPS					0x20	// =1: allow placement of gas switches below the depth of the 1st stop
+
+#define MODE_MASK						0xC0	// mask for real tissues mode selection
+#define MODE_LOOP						0x40	// =1: CCR (MODE_PSCR needs to be cleared) or pSCR mode
+#define MODE_CCR						0x40	// to be used with == operator in combination with MODE_MASK only!
+#define MODE_PSCR						0x80	// =1: pSCR mode (MODE_LOOP needs to be set, too)
+
+// deco engine states and modes - (char_O_)deco_status: controls deco plan calculation (to-be scenario)
+#define PLAN_MASK						0x03	// bit mask covering normal & alternative plan flag
+#define COMMAND_MASK					0x07	// bit mask covering all command flags
+#define CALCULATING						0x00	// calculations are ongoing
+#define START_NORM						0x01	// input:    start calculation of a  normal      deco plan
+#define CALC_NORM						0x01	// internal: calculating          a  normal      deco plan
+#define COMPLETED_NORM					0x01	// output:   calculation       of a  normal      deco plan has completed
+#define START_ALT						0x02	// input:    start calculation of an alternative deco plan
+#define CALC_ALT						0x02	// internal: calculating          an alternative deco plan
+#define COMPLETED_ALT					0x02	// output:   calculation of       an alternative deco plan has completed
+#define INITIALIZE						0x04	// input:    initialize deco engine
+#define INITIALIZE_START_NORM			0x05	// input:    initialize deco engine and start calculation of a normal       deco plan
+#define INITIALIZE_START_ALT			0x06	// input:    initialize deco engine and start calculation of an alternative deco plan
+//										0x08	// unused - reserved for further deco engine commands
+
+#define BAILOUT_MODE					0x10	// =1: allow gas switches before first deco stop
+#define DELAYED_ASCENT					0x20	// =1: figure in a delayed ascent (fTTS)
+
+//      MODE_MASK						0xC0	// mask for simulated tissues mode selection
+//      MODE_LOOP						0x40	// =1: CCR (MODE_PSCR needs to be cleared) or pSCR mode
+//      MODE_CCR						0x40	// to be used with == operator in combination with MODE_MASK only!
+//      MODE_PSCR						0x80	// =1: pSCR mode (MODE_LOOP needs to be set, too)
+
+
+// deco engine warnings - (char_O_)deco_warnings
 #define DECO_WARNING_IBCD				0x01	// IBCD occurring now
 #define DECO_WARNING_IBCD_lock			0x02	// IBCD has occurred during the dive
 #define DECO_WARNING_MBUBBLES			0x04	// micro bubbles likely to develop now
@@ -173,21 +183,53 @@
 #define DECO_ATTENTION_OUTSIDE			0x40	// tissue pressures are very close to the Buhlmann limit
 #define DECO_WARNING_STOPTABLE_OVERFLOW	0x80	// internal error: no more space in the deco stops table
 
-// deco engine status (char_O_deco_info)
+// deco engine status (char_O_)deco_info
 #define DECO_FLAG						0x01	// =1: deco ppO2 levels are permitted
 #define IND_DOUBLE_SWITCH_FLAG			0x02	// =1: switch to other tank advice active
-#define DECO_STEADY						0x04	// =1: fTTS = TTS (not updated when in bailout mode)
-#define DECO_DECREASING					0x08	// =1: fTTS < TTS (not updated when in bailout mode)
+//										0x04	// --- unused
+#define DECO_ZONE						0x08	// =1: fTTS < TTS (not updated when in bailout mode)
 #define DECO_CEILING					0x10	// =1: ceiling depth > 0
-#define GAS_NEEDS_CAVE					0x20	// =1: indicated gas needs are calculated in cave mode
+#define DECO_STOPS						0x20	// =1: deco stops found
+#define GAS_NEEDS_CAVE					0x40	// =1: indicated gas needs are calculated in cave mode
+//										0x80	// --- unused
+
 
 // deco engine control - tissue_increment
-#define TIME_MASK						0x7F	// (127 decimal, bits 0-6 set)
-#define TISSUE_FLAG						0x80	// (128 decimal, bit   7  set)
+#define TIME_MASK						0x7F	// =0: time increment is 2 seconds, 1..127: time increments is 1..127 minutes
+#define TISSUE_SELECTOR					0x80	// =1: calculate on real tissues, =0: calculate on simulated tissues
+
+
+// deco engine control - next_planning_phase
+#define PHASE_00_DONE					0x00	// calculation cycle finished
+#define PHASE_10_DIVE_INIT				0x10	// once-per-dive    initialization of the deco engine
+#define PHASE_11_CYCLIC_INIT			0x11	// once-every-cycle initialization of the deco engine
+#define PHASE_20_EXTENDED_BOTTOM_TIME	0x20	// calculate extended bottom time
+#define PHASE_30_NDL_TIME				0x30	// calculate NDL time
+#define PHASE_40_CAVE_ASCENT			0x40	// calculate cave mode return/ascent
+#define PHASE_60_DECO_ASCENT			0x60	// calculate open water deco ascent
+#define PHASE_70_RESULTS				0x70	// results - initialization
+#define PHASE_71_RESULTS_STOPS_TABLE	0x71	// results - publish stops table
+#define PHASE_72_RESULTS_NDL			0x72	// results - publish data / within NDL
+#define PHASE_73_RESULTS_DECO			0x73	// results - publish data / in deco
+#define PHASE_80_GAS_NEEDS_SWITCHES		0x80	// calculate gas needs - find gas switches in NDL bailout mode
+#define PHASE_81_GAS_NEEDS_ASCENT		0x81	// calculate gas needs - needs of bottom segment and ascent
+#define PHASE_82_GAS_NEEDS_PRESSURES	0x82	// calculate gas needs - conversion from volumes to pressures
+#define PHASE_90_FINISH					0x90	// finish calculation cycle
+
+
+// gas needs calculation - gas_needs_next_phase
+#define GAS_NEEDS_INIT					0x00	// initialization
+#define GAS_NEEDS_BOTTOM_SEGMENT		0x10	// demand during bottom segment
+#define GAS_NEEDS_INITIAL_ASCENT		0x20	// demand of initial ascent
+#define GAS_NEEDS_STOP					0x30	// demand on a stop
+#define GAS_NEEDS_INTERMEDIATE_ASCENT	0x40	// demand on ascent between two stops
+#define GAS_NEEDS_FINAL_ASCENT			0x50	// demand during final ascent
+#define GAS_NEEDS_DONE					0x60	// calculation finished
 
 
 // flags used with integer numbers
 #define INT_FLAG_INVALID				0x0400	// =1: value not valid
+#define INT_FLAG_NOT_COMPUTED_YET		0x0800	// =1: value not computed yet
 #define INT_FLAG_ZERO					0x0800	// =1: value is zero
 #define INT_FLAG_LOW					0x1000	// =1: value is below a lower warning threshold
 #define INT_FLAG_NOT_AVAIL				0x1000	// =1: value is not available (not computed)
@@ -207,19 +249,20 @@
 //
 // *********************************************************************************************************************************
 
-// Functions used in surface mode
+// Functions used in Surface Mode
 static void			 calc_interval(PARAMETER unsigned char time_increment);
 														// Calculates the tissue off-gassing under surface conditions.
 static void			 calc_desaturation_time(void);		// Calculates the desaturation and no-fly times.
 static void			 clear_tissue(void);				// Resets all tissues to surface pressure equilibrium state.
-
-// Main entry point in dive mode
+static void			 init_output_vars(void);			// Initializes all deco engine output variables to defaults
+
+// Main entry point in Dive Mode
 static void			 calc_hauptroutine(void);			// Sequences all calculations for the real tissues and the deco calculation.
 
-// Functions dedicated to the real tissues
+// Functions dedicated to the real Tissues
 static void			 calc_hauptroutine_data_input(void);// Initializes environment data and sets gas ratios for the real tissues.
 
-// Functions combined for real tissues & deco calculations
+// Functions combined for real Tissues & Deco Calculations
 static void			 calc_alveolar_pressures(void);		// Computes the partial pressures from the gas ratios and many more parameters,
 														// needs either calc_hauptroutine_data_input() be called beforehand or
 														// gas_find_current()/gas_find_better() and gas_set_ratios().
@@ -228,41 +271,50 @@
 static void			 calc_limit(PARAMETER float GF_current);
 														// Calculates ceiling, current GF (supersaturation) and some more data.
 
-// Functions dedicated to deco calculations
+// Functions for TR
+#ifdef _rx_functions
+static void			 calc_TR_functions(void);			// Calculates SAC etc.
+#endif
+
+// Functions dedicated to Deco Calculations
 static void			 clear_deco_table(void);			// Clears the deco stops table, invoked at the start of each calculation cycle.
 static void			 gas_find_current(void);			// Sets the first gas used for deco calculation, invoked at start of cycle, too.
 static unsigned char gas_find_better(void);				// Checks for, and eventually switches to, a better gas.
 static void			 gas_set_ratios(void);				// Sets the gas ratios for use in deco calculation (simulated tissues),
 														// needs to be called after each gas change (gas_find_current/_better).
-static void			 calc_NDL_time(void);				// Calculates remaining NDL time.
-static void			 find_NDL_gas_changes(void);		// Finds the gas changes in an OC bailout ascent that is within NDL
-static void			 calc_ascent_to_first_stop(void);	// Calculates ascent to the first deco stop.
-static void			 calc_hauptroutine_calc_deco(void);	// Calculates the subsequent ascent until reaching surface.
-static unsigned char calc_nextdecodepth(void);			// Calculates the depth of the next required deco stop.
+static void			 calc_NDL_time_tissue(void);		// Calculates the remaining NDL time for a given tissue.
+static void			 find_NDL_gas_changes(void);		// Finds the gas changes in an OC bailout ascent that is within NDL.
+static unsigned char find_next_stop(void);				// Finds the next stop when in a deco ascent.
 static unsigned char update_deco_table(PARAMETER unsigned char time_increment);
 														// Enters a new stop or extends an existing stop in the deco stops table.
 static void			 calc_ascenttime(void);				// Calculates the ascent time from current depth and deco stop times.
-static void			 gas_volumes(void);					// Calculates required gas volumes and pressures from the data in stops table.
-
-// Functions for results reporting
+static void			 calc_gas_needs_ascent(void);		// Calculates required gas volumes and pressures from the data in stops table.
+static void			 calc_due_by_depth_time_sac(void);	// Calculates gas volume required for a given depth, time and usage (SAC rate).
+static void			 convert_gas_needs_to_press(void);	// Converts gas volumes into pressures and sets respective flags.
+
+// Functions for Results Reporting
 static void			 publish_deco_table(void);			// Copies the internal deco stops table to the export interface.
-static void			 convert_CNS_for_display(void);		// Converts the current     CNS value from float to integer.
+static void			 convert_cur_CNS_for_display(void);	// Converts the current     CNS value from float to integer.
 static void			 convert_sim_CNS_for_display(void);	// Converts the end-of-dive CNS value from float to integer.
-static void			 convert_GF_for_display(void);		// Converts leading tissue supersaturation value from float to integer, 1.0 = 100%.
+static void			 convert_sat_for_display(void);		// Converts leading tissue saturation value from float to integer, 1.0 = 100%.
 static void			 convert_ceiling_for_display(void);	// Converts ceiling from float to integer in mbar relative pressure.
 
 
-// internal helper functions
-static unsigned short tmr5(void);						// Reads a hardware timer which is used for preemptive scheduling.
-static void			 read_Buhlmann_coefficients(void);	// Reads the a and b coefficients from a ROM table.
+// internal helper Functions
+static void			 load_tmr5(void);					// Loads  a hardware timer which is used for preemptive scheduling.
+static void 		 read_tmr5(void);					// Reads  a hardware timer which is used for preemptive scheduling.
+static void			 read_CNS_ab_coefficient(void);		// Reads the CNS      a and b coefficients from a ROM table.
+static void			 read_CNS_c_coefficient(void);		// Reads the CNS      c       coefficient  from a ROM table.
+static void			 read_Buhlmann_coefficients(void);	// Reads the Buhlmann a and b coefficients from a ROM table.
 static void			 read_Buhlmann_times(PARAMETER char period);
 														// Reads pre-computed tissue increment factors from a ROM table.
 static void			 read_Buhlmann_ht(void);			// Reads the half-times from a ROM table.
 static void			 adopt_Buhlmann_coefficients(void);	// Computes average a and b coefficient by the N2/He tissue ratio.
-static void			 temp_tissue_safety(void);			// Applies safety margins to the tissue increments.
 static void			 push_tissues_to_vault(void);		// Stores the state of the real tissues during simulator runs.
 static void			 pull_tissues_from_vault(void);		// Restores the state of the real tissues after a simulator run.
-
+static void			 calc_N2_equilibrium(void);			// Calculate partial pressure of N2 in respired air at surface pressure
+static void			 get_saturation_factors(void);		// Get, safeguard and convert the saturation and desaturation factors
+static void			 apply_saturation_factors(void);	// Applies saturation and desaturation factors
 
 
 // *********************************************************************************************************************************
@@ -276,110 +328,15 @@
 #   pragma udata bank5=0x500
 #endif
 
-// general deco parameters
-
-static float			GF_low;							// initialized from deco parameters
-static float			GF_high;						// initialized from deco parameters
-static float			GF_delta;						// initialized from deco parameters
-
-static float			locked_GF_step_norm;			// GF_delta / low_depth_norm in normal plan
-static float			locked_GF_step_alt;				// GF_delta / low_depth_alt  in alternative plan
-
-static float			low_depth_norm;					// depth of deepest stop in normal plan
-static float			low_depth_alt;					// depth of deepest stop in alternative plan
-
-static float			float_ascent_speed;				// ascent speed from options_table (5.0 .. 10.0 m/min)
-static float			float_deco_distance;			// additional depth below stop depth for tissue, CNS and gas volume calculation
-static float			float_saturation_multiplier;	// safety factor for on-gassing rates
-static float			float_desaturation_multiplier;	// safety factor for off-gassing rates
-
-static unsigned char	split_N2_He[NUM_COMP];			// used for calculating the desaturation time
-
-// real context: what we are doing now
-
-static float			CNS_fraction;					// current CNS (1.00 = 100%)
-
-static unsigned short	deco_tissue_vector;				// 16 bit vector to memorize all tissues that are in decompression
-static unsigned short	IBCD_tissue_vector;				// 16 bit vector to memorize all tissues that experience IBCD
-
-static float			pres_respiration_sac;			// current depth in absolute pressure, used in SAC calculation
-static float			float_sac;						// used in SAC calculation
-static unsigned int		max_sac_rate;					// used in SAC calculation to determine SAC rate attention
-
-
-// simulation context: used to predict ascent
-
-static float			sim_CNS_fraction;				// CNS after predicted ascent, 0.01 = 1%, as float
-
-static unsigned int		int_sim_CNS_fraction;			// CNS after predicted ascent,    1 = 1%, as integer
-
-static unsigned char	sim_depth_limit;				// depth of next stop in meters, used in deco calculations
-static unsigned char	NDL_lead_tissue_norm;				// used to cache the tissue to start with when calculating the NDL
-static unsigned char	NDL_lead_tissue_alt;				// used to cache the tissue to start with when calculating the NDL
-
-
-// result values from calculation functions
-
-static float			ceiling;						// minimum tolerated relative pressure (i.e. without surface pressure)
-static float			lead_supersat;					// supersaturation of the leading tissue, 1.0 = 100%
-static unsigned char	lead_number;					// number of the leading tissue
-
-// stops table
-
-static unsigned char	internal_deco_depth[NUM_STOPS];	// depths of the stops
-static unsigned char	internal_deco_time[NUM_STOPS];	// durations of the stops
-static unsigned char	internal_deco_gas[NUM_STOPS];	// gases used on the stops
-
-
-// transfer variables between calc_desaturation_time() and calc_desaturation_time_helper()
-
-static float			desat_factor;					// used to cache a pre-computed factor
-static float			var_ht;							// buffer for a half-time factor
-static float			pres_target;					// target pressure for a compartment
-static float			pres_actual;					// current pressure of the compartment
-static unsigned int		int_time;						// time it takes for the compartment to reach the target pressure
-
-
-// transfer variables between gas_volumes() and gas_volumes_helper_1/_2()
-
-static float			float_depth;					// depth of the stop or half-way point
-static float			float_time;						// duration of the stop or ascent phase
-static unsigned char	char_usage;						// gas usage in l/min
-static unsigned char	gas_num;						// number of the gas/tank
-static float			volume;							// computed volume of gas
-static unsigned int		int_volume;						// required gas volume in liter
-static unsigned int		int_pres_need;					// required gas volume in bar
-
-
-// auxiliary variables for data buffering
-
-static float			N2_equilibrium;					// used for N2 tissue graphics scaling
-static float			temp_tissue;					// auxiliary variable to buffer tissue pressures
-static float			float_pSCR_factor;				// pre-computed factor for pSCR ppO2 drop calculation
-static float			calc_pres_tissue_N2;			// auxiliary variable to buffer tissue N2 pressure
-static float			calc_pres_tissue_He;			// auxiliary variable to buffer tissue He pressure
-static float 			pres_tissue;					// auxiliary variable to buffer total tissue pressure
-
-// 10 byte free space left in this bank (4 bytes per float, 2 bytes per int/short, 1 byte per char)
-
-
-//---- Bank 6 parameters -----------------------------------------------------
-#ifndef UNIX
-#   pragma udata bank6=0x600
-#endif
-
-// indexing and sequencing
-
-static unsigned char	ci;								// used as index to the Buhlmann tables
-static unsigned char	twosectimer = 0;				// used for timing the tissue updating
-static unsigned char	tissue_increment;				// selector for real/simulated tissues and time increment
-
-
-// environmental and gas data
+// Environmental and Gas Data (52 byte)
 
 static float			pres_surface;					// absolute pressure at the surface
 
-static unsigned char	char_bottom_depth;				// bottom depth in meters, used by ascent time and gas needs calculation
+static float			float_depth_real;				// current real      depth in meters, float
+static unsigned char	char_depth_real;				// current real      depth in meters, integer
+static unsigned char	char_depth_sim;					// current simulated depth in meters, integer
+static unsigned char	char_depth_last;				// last    simulated depth in meters, integer
+static unsigned char	char_depth_bottom;				// bottom            depth in meters, integer
 
 static float			real_pres_respiration;			// current real depth in absolute pressure
 static float			real_O2_ratio;					// real breathed gas oxygen ratio
@@ -394,7 +351,153 @@
 static float			sim_pSCR_drop;					// simulated ppO2 drop in pSCR loop
 
 
-// result values from calculation functions
+// general Deco Parameters (57 byte)
+
+static float			GF_low;							// gradient factor to determine 1st stop
+static float			GF_high;						// gradient factor to determine surfacing
+
+static unsigned char	GF_low_last;					// last GF low,  used to detect changes
+static unsigned char	GF_high_last;					// last GF high, used to detect changes
+
+static unsigned char	GF_low_depth;					// GF low reference depth in current calculation cycle
+static unsigned char	GF_low_depth_norm;				// GF low reference depth in normal plan
+static unsigned char	GF_low_depth_alt;				// GF low reference depth in alternative plan
+
+static float			GF_slope;						// (GF_high - GF_low) / GF_low_depth      in current calculation cycle
+static float			GF_slope_norm;					// (GF_high - GF_low) / GF_low_depth_norm in normal plan
+static float			GF_slope_alt;					// (GF_high - GF_low) / GF_low_depth_alt  in alternative plan
+
+static float			float_ascent_speed;				// ascent speed from options_table (5.0 .. 10.0 m/min)
+static float			float_deco_distance;			// additional depth below stop depth for tissue, CNS and gas volume calculation
+static float			float_saturation_multiplier;	// safety factor for  on-gassing rates
+static float			float_desaturation_multiplier;	// safety factor for off-gassing rates
+
+static unsigned char	split_N2_He[NUM_COMP];			// used for calculating the desaturation time
+
+
+// real Context: what we are doing now (16 byte)
+
+static float			CNS_fraction_real;				// current real CNS (1.00 = 100%)
+static unsigned short	IBCD_tissue_vector;				// 16 bit vector to memorize all tissues that experience IBCD
+
+static float			pres_respiration_sac;			// used in SAC calculation: current depth in absolute pressure
+static float			float_sac;						// used in SAC calculation: SAC value in float
+static unsigned short	max_sac_rate;					// used in SAC calculation: threshold for SAC rate attention
+
+
+// simulated Context: used to calculate Ascent (11 byte)
+
+static float			CNS_fraction_sim;				// CNS after predicted ascent, 0.01 = 1%, as float
+static unsigned short	int_sim_CNS_fraction;			// CNS after predicted ascent,    1 = 1%, as integer
+static unsigned char	NDL_tissue_start_norm;			// tissue to start with when calculating the normal      NDL time
+static unsigned char	NDL_tissue_start_alt;			// tissue to start with when calculating the alternative NDL time
+static unsigned char	NDL_tissue_start;				// tissue to start with                    in current cycle
+static unsigned char	NDL_tissue_lead;				// tissue with the shortest NDL time found in current cycle
+static unsigned char	NDL_tissue;						// tissue for which the NDL is calculated right now
+
+// Result Values from Calculation Functions (9 byte)
+
+static float			ceiling;						// minimum tolerated relative pressure (i.e. without surface pressure)
+static float			lead_supersat;					// supersaturation of the leading tissue, 1.0 = 100%
+static unsigned char	lead_tissue;					// number of the leading tissue
+
+
+// Transfer Variables between calc_desaturation_time() and calc_desaturation_time_helper() (18 byte)
+
+static float			desat_factor;					// used to cache a pre-computed factor
+static float			var_ht;							// buffer for a half-time factor
+static float			pres_target;					// target pressure for a compartment
+static float			pres_actual;					// current pressure of the compartment
+static unsigned short	int_time;						// time it takes for the compartment to reach the target pressure
+
+
+// Gas in Use and Gas Needs (30 byte)
+
+static unsigned char	sim_gas_current_num;			// number       of the currently used gas
+static unsigned char	sim_gas_current_depth;			// change depth of the currently used gas
+
+static unsigned char	gas_needs_stop_time;			// duration of the stop in minutes
+static unsigned char	gas_needs_stop_gas;				// gas used now    (1-5 or 0)
+static unsigned char	gas_needs_stop_gas_last;		// gas used before (1-5 or 0)
+static unsigned char	gas_needs_stop_depth;			// depth of the stop      in meters
+static unsigned char	gas_needs_stop_depth_last;		// depth of the last stop in meters
+static unsigned char	gas_needs_stop_index;			// index to the stop table
+static unsigned char	gas_needs_gas_index;			// index to the gas and tank data arrays
+static unsigned char	gas_needs_next_phase;			// next phase within the ascent gas needs calculation
+
+static float			gas_volume_need[NUM_GAS];		// gas volumes required for return/ascent in liters
+
+
+// Transfer Variables between calc_gas_needs_ascent() and calc_due_by_depth_time_sac() (13 byte)
+
+static float			gas_needs_float_depth;			// depth of the stop or half-way point
+static float			gas_needs_float_time;			// duration of the stop or ascent phase
+static unsigned char	gas_needs_stop_usage;			// gas usage in l/min
+static float			gas_needs_volume_due;			// computed due of gas volume required
+
+
+// CNS Coefficients (10 byte)
+
+static float			var_cns_a;						// two coefficients approximation, gain
+static float			var_cns_b;						// two coefficients approximation, offset
+static unsigned short	var_cns_c;						// one coefficient  approximation, value
+
+
+// Transfer values for convert_float_int and convert_float_to_char() (7 byte)
+
+static float			float_value;					// input value,   float
+static unsigned short	int_value;						// output value, 16 bit
+static unsigned char	char_value;						// output value,  8 bit
+
+
+// Auxiliary Variables for Data Buffering (28 byte)
+
+static float			N2_equilibrium;					// used for N2 tissue graphics scaling
+static float			temp_tissue;					// auxiliary variable to buffer tissue pressures
+static float			float_pSCR_factor;				// pre-computed factor for pSCR ppO2 drop calculation
+static float			calc_pres_tissue_N2;			// auxiliary variable to buffer tissue N2 pressure
+static float			calc_pres_tissue_He;			// auxiliary variable to buffer tissue He pressure
+static float			pres_tissue;					// auxiliary variable to buffer total tissue pressure
+static float			old_pres_respiration;			// auxiliary variable to buffer sim_pres_respiration
+
+
+// Performance Profiling (4 byte)
+
+static unsigned short	profiling_runtime;				// performance measurement: runtime of current invocation
+static unsigned char	profiling_runs;					// performance measurement: invocations per deco calculation cycle
+static unsigned char	profiling_phase;				// performance measurement: current calculation phase
+
+
+// 255 byte used, 1 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
+
+
+//---- Bank 6 parameters -----------------------------------------------------
+#ifndef UNIX
+#   pragma udata bank6=0x600
+#endif
+
+// Timer5 Interface (3 byte) - Attention: keep order and keep at beginning of bank 6, i.e. at address 0x600 !
+
+static volatile unsigned short	tmr5_value;				// timer 5 value buffer		MUST be at address 0x600
+static volatile unsigned char	tmr5_overflow;			// timer 5 overflow flag	MUST be at address 0x602
+
+
+// Modes, Sequencing and Indexing (11 byte)
+
+static unsigned char	main_status;					// shadow register for char_O_main_status
+static unsigned char	deco_status;					// shadow register for char_O_deco_status
+static unsigned char	deco_info;						// shadow register for char_O_deco_info
+static unsigned char	deco_warnings;					// shadow register for char_O_deco_warnings
+static unsigned char	next_planning_phase;			// next calculation phase to be executed
+static unsigned char	tissue_increment;				// selector for real/simulated tissues and time increment
+static unsigned char	sequence_timer;					// timer to sequence deco engine tasks
+static unsigned char	ci;								// index to the Buhlmann tables (compartment index)
+static unsigned char	cns_i;							// index to the CNS      tables (ppO2 range  index)
+static unsigned char	i;								// general purpose loop counter and index
+static unsigned char	fast;							// selects 1 minute or 2 second ascent steps
+
+
+// Result Values from Calculation Functions (28 byte)
 
 static float			O2_ppO2;						// ppO2 - calculated for pure oxygen at current depth
 static float			OC_ppO2;						// ppO2 - calculated for breathing in OC   mode
@@ -406,36 +509,52 @@
 
 static unsigned char	char_ppO2;						// partial pressure of breathed oxygen, as integer 100 = 1.00 bar
 static unsigned char	NDL_time;						// time in minutes until reaching NDL
-static unsigned int		ascent_time;					// time in minutes needed for the ascent
-
-
-// Buhlmann model parameters
+static unsigned short	ascent_time;					// time in minutes needed for the ascent
+
+
+// Buhlmann Model Parameters (40 byte)
 
 static float			var_N2_a;						// Buhlmann a, for current N2 tissue
 static float			var_N2_b;						// Buhlmann b, for current N2 tissue
 static float			var_He_a;						// Buhlmann a, for current He tissue
 static float			var_He_b;						// Buhlmann b, for current He tissue
+static float			var_a;							// Buhlmann a, adopted to current N2/He ratio
+static float			var_b;							// Buhlmann b, adopted to current N2/He ratio
 static float			var_N2_e;						// exposition, for current N2 tissue
 static float			var_He_e;						// exposition, for current He tissue
 static float			var_N2_ht;						// half-time,  for current N2 tissue
 static float			var_He_ht;						// half-time,  for current He tissue
 
 
-// gas in use
-
-static unsigned char	sim_gas_current;				// number       of the currently used gas
-static unsigned char	sim_gas_current_depth;			// change depth of the currently used gas
-
-
-// vault to back-up & restore tissue data
-
-static float			pres_tissue_N2_vault[NUM_COMP];	// stores the nitrogen tissue pressures
-static float			pres_tissue_He_vault[NUM_COMP];	// stores the helium tissue pressures
-static float			cns_vault_float;				// stores current CNS (float representation)
-static unsigned char	deco_warnings_vault;			// stores warnings status
-
-
-// 8 byte free space left in this bank (4 bytes per float, 2 bytes per int/short, 1 byte per char)
+// Vault to back-up & restore Tissue related Data (134 byte)
+
+static float			vault_pres_tissue_N2[NUM_COMP];	// stores the nitrogen tissue pressures
+static float			vault_pres_tissue_He[NUM_COMP];	// stores the helium tissue pressures
+static float			vault_CNS_fraction_real;		// stores current CNS (float representation)
+static unsigned char	vault_deco_warnings;			// stores warnings status
+static unsigned char	vault_deco_info;				// stores info status
+
+
+// 7 byte occupied by compiler-placed vars
+
+
+// 223 byte used, 33 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
+
+
+
+//---- Bank 12 parameters -----------------------------------------------------
+#ifndef UNIX
+#   pragma udata bank12=0xc00
+#endif
+
+// stops table (96 byte)
+
+static unsigned char	internal_deco_depth[NUM_STOPS];	// depths     of the stops in meters
+static unsigned char	internal_deco_time[NUM_STOPS];	// durations  of the stops in minutes
+static unsigned char	internal_deco_gas[NUM_STOPS];	// gases used on the stops (0 / 1-5)
+
+
+// 96 byte used, 160 byte left in this bank (4 bytes per float, 2 bytes per short, 1 byte per char)
 
 
 //---- Bank 7 parameters -----------------------------------------------------
@@ -443,15 +562,15 @@
 #   pragma udata bank7=0x700
 #endif
 
-// Keep order and position of the variables in bank 7 as they are backed-up to & restored from EEPROM 
-
-float					pres_tissue_N2[NUM_COMP];		// 16 floats = 64 bytes
-float					pres_tissue_He[NUM_COMP];		// 16 floats = 64 bytes
-
-float					sim_pres_tissue_N2[NUM_COMP];	// 16 floats = 64 bytes
-float					sim_pres_tissue_He[NUM_COMP];	// 16 floats = 64 bytes
-
-// bank is full!
+// Keep order and position of the variables in bank 7 as they are backed-up to & restored from EEPROM
+
+static float			real_pres_tissue_N2[NUM_COMP];		// 16 floats = 64 bytes
+static float			real_pres_tissue_He[NUM_COMP];		// 16 floats = 64 bytes
+
+static float			sim_pres_tissue_N2[NUM_COMP];		// 16 floats = 64 bytes
+static float			sim_pres_tissue_He[NUM_COMP];		// 16 floats = 64 bytes
+
+// 256 byte used, bank is full
 
 
 //---- Bank 8 parameters -----------------------------------------------------
@@ -478,6 +597,52 @@
 // *********************************************************************************************************************************
 
 #ifndef UNIX
+#   pragma romdata CNS_tables = 0x1DC80  // needs to be in the UPPER bank
+#endif
+
+rom const float CNS_ab[2*11] = {
+// CNS increment per 2sec = 1 / (a*ppO2 + b) with ppO2 in [cbar]
+//   a          b       for ppO2 cbar range
+	-533.07,    54000,	//  51 -  60   (index  0)
+	-444.22,    48600,	//  61 -  70   (index  1)
+	-355.38,    42300,	//  71 -  80   (index  2)
+	-266.53,    35100,	//  81 -  90   (index  3)
+	-177.69,    27000,	//  91 - 100   (index  4)
+	-177.69,    27000,	// 101 - 110   (index  5)
+	 -88.84,    17100,	// 111 - 120   (index  6)
+	 -88.84,    17100,	// 121 - 130   (index  7)
+	 -88.84,    17100,	// 131 - 140   (index  8)
+	 -88.84,    17100,	// 141 - 150   (index  9)
+	-222.11,    37350	// 151 - 160   (index 10)
+};
+
+rom const unsigned short CNS_c[1*20] = {
+//  CNS increment per 2sec = c / 100000.0
+//   c in [1/100000]   for ppO2 cbar range
+	  75,				// 161 - 165   (index  0)
+	 102,				// 166 - 170   (index  1)
+	 136,				// 171 - 175   (index  2)
+	 180,				// 176 - 180   (index  3)
+	 237,				// 181 - 185   (index  4)
+	 310,				// 186 - 190   (index  5)
+	 401,				// 191 - 195   (index  6)
+	 517,				// 196 - 200   (index  7)
+	 760,				// 201 - 205   (index  8)
+	1100,				// 206 - 210   (index  9)
+	1500,				// 211 - 215   (index 10)
+	2090,				// 216 - 220   (index 11)
+	2900,				// 221 - 225   (index 12)
+	3900,				// 226 - 230   (index 13)
+	4820,				// 231 - 235   (index 14)
+	4820,				// 236 - 240   (index 15)
+	4820,				// 241 - 245   (index 16)
+	4820,				// 246 - 250   (index 17)
+	4820,				// 251 - 255   (index 18)
+	   0				// not used, just to fill up the memory block
+};
+
+
+#ifndef UNIX
 #   pragma romdata Buhlmann_tables = 0x1DD00  // needs to be in the UPPER bank
 #endif
 
@@ -526,7 +691,7 @@
 rom const float e2secs[2*16] = {
 // result of  1 - 2^(-1/(2sec*HT))
 //---- N2 ------------- He ------------
-	5.75958E-03,    1.51848E-02,  
+	5.75958E-03,    1.51848E-02,
 	2.88395E-03,    7.62144E-03,
 	1.84669E-03,    4.88315E-03,
 	1.24813E-03,    3.29997E-03,
@@ -607,7 +772,7 @@
 
 //////////////////////////////////////////////////////////////////////////////
 // Bump to blue-screen when an assert is wrong
-#ifdef __DEBUG
+#ifdef _DEBUG
 void assert_failed(PARAMETER short int line)
 {
 }
@@ -616,12 +781,12 @@
 
 //////////////////////////////////////////////////////////////////////////////
 // When calling C code from ASM context, the data stack pointer and
-// frames should be reset. Bank8 is used by stack
+// frames should be reset. Bank 8 is used by stack.
 
 #ifdef CROSS_COMPILE
 #	define RESET_C_STACK
 #else
-#	ifdef __DEBUG
+#	ifdef _DEBUG
 #		define RESET_C_STACK fillDataStack();
 		void fillDataStack(void)
 		{
@@ -647,23 +812,101 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// Fast subroutine to read timer 5
-// Note: result is in 1/32 of milliseconds (30.51757813 us/bit to be precise)
-static unsigned short tmr5(void)
+// Reset timer 5
+//
+// Note: TMR5 is configured in 16 bit mode: a value written to TMR5H is buffered
+//       and will be written to TMR5 together with a successive write to TMR5L.
+//       As we don't know in which bank the code will be executed, we use either
+//       the bank-save "movff" command, or address mapping via access bank (",0").
+//
+static void load_tmr5(void)
 {
 #ifndef CROSS_COMPILE
 	_asm
-		movff	0xf7c,PRODL		// TMR5L
-		movff	0xf7d,PRODH		// TMR5H
-	_endasm						// result in PRODH:PRODL
+		movff	0x601,0xF7D		// bank-safe load TMR5H from C variable tmr5_value first
+		movff	0x600,0xF7C		// bank-safe load TMR5L from c variable tmr5_value thereafter
+		bcf		0xFBA,1,0		// clear timer 5 overrun flag (0xFBA = PIR5, bit 1 = TMR5IF)
+	_endasm
 #else
-	return 0;
+	return;
+#endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Read timer 5
+//
+// Note: TMR5 reads in multiples of 1/32 ms, 30.51757813 us/bit to be precise.
+//       TMR5 is configured in 16 bit mode: on reading of TMR5L the contents of
+//       TMR5H is latched and can be read afterwards without potential rollover.
+//       As we don't know in which bank the code will be executed, we use either
+//       the bank-save "movff" command, or address mapping via access bank (",0").
+//
+static void read_tmr5(void)
+{
+#ifndef CROSS_COMPILE
+	_asm
+		movff	0xF7C,0x600		// copy TMR5L to C variable tmr5_value, low  byte first
+		movff	0xF7D,0x601		// copy TMR5H to C variable tmr5_value, high byte thereafter
+		clrf	WREG,0			// clear WREG to 0x00 = no overrun by default
+		btfsc	0xFBA,1,0		// did timer 5 overrun? (0xFBA = PIR5, bit 1 = TMR5IF)
+		setf	WREG,0			// YES - set WREG to 0xff = overrun detected
+		movff	WREG,0x602		// copy WREG to C variable tmr5_overflow
+	_endasm
+#else
+	return;
 #endif
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// read Buhlmann coefficients a and b for compartment ci
+// Read CNS coefficients a and b
+//
+static void read_CNS_ab_coefficient(void)
+{
+#ifndef CROSS_COMPILE
+	// Note: We don't use far ROM pointer, because handling
+	//       24 bit is to complex, hence we have to set the
+	//       UPPER page ourself...
+	//       -> set to zero if tables are moved to lower pages!
+	_asm
+		movlw	1
+		movwf	TBLPTRU,0
+	_endasm
+#endif
+
+	{
+		overlay rom const float* ptr = &CNS_ab[2*cns_i];
+		var_cns_a = *ptr++;
+		var_cns_b = *ptr++;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Read CNS coefficient c
+//
+static void read_CNS_c_coefficient(void)
+{
+#ifndef CROSS_COMPILE
+	// Note: We don't use far ROM pointer, because handling
+	//       24 bit is to complex, hence we have to set the
+	//       UPPER page ourself...
+	//       -> set to zero if tables are moved to lower pages!
+	_asm
+		movlw	1
+		movwf	TBLPTRU,0
+	_endasm
+#endif
+
+	{
+		overlay rom const unsigned short* ptr = &CNS_c[cns_i];
+		var_cns_c = *ptr++;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Read Buhlmann coefficients a and b for compartment ci
 //
 static void read_Buhlmann_coefficients(void)
 {
@@ -692,7 +935,7 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// read Buhlmann increments for compartment ci
+// Read Buhlmann increments for compartment ci
 // If period == 0 :  2 sec interval
 //              1 :  1 min interval
 //              2 : 10 min interval
@@ -711,7 +954,7 @@
 
 	assert( ci < NUM_COMP );
 
-	// Integration intervals
+	// Integration Intervals
 	switch(period)
 	{
 	case 0: //---- 2 sec -----------------------------------------------------
@@ -736,16 +979,16 @@
 			var_N2_e = *ptr++;
 			var_He_e = *ptr++;
 		}
-	break;
+		break;
 
 	default:
-		assert(0);  // Never go there...
+		assert(0);	// code execution shall never pass along here!
 	}
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// read Buhlmann half-times for compartment ci
+// Read Buhlmann half-times for compartment ci
 //
 static void read_Buhlmann_ht(void)
 {
@@ -774,13 +1017,112 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// compute adopted Buhlmann coefficients
+// Calculate adopted Buhlmann coefficients
+//
+// Input:  var_N2_a, var_N2_b       coefficients for N2
+//         var_He_a, var_He_b       coefficients for He
+//         calc_pres_tissue_N2      partial pressure of N2 in tissue
+//         calc_pres_tissue_He      partial pressure of He in tissue
+//         pres_tissue              total pressure in tissue
+//
+// Output: var_a, var_b             coefficients adopted by N2/He ratio
 //
 static void adopt_Buhlmann_coefficients(void)
 {
 	// adopt a and b coefficients to current N2/He ratio inside the tissue
-	var_N2_a = (var_N2_a * calc_pres_tissue_N2 + var_He_a * calc_pres_tissue_He) / pres_tissue;
-	var_N2_b = (var_N2_b * calc_pres_tissue_N2 + var_He_b * calc_pres_tissue_He) / pres_tissue;
+
+#ifdef _helium
+
+	var_a = (var_N2_a * calc_pres_tissue_N2 + var_He_a * calc_pres_tissue_He) / pres_tissue;
+	var_b = (var_N2_b * calc_pres_tissue_N2 + var_He_b * calc_pres_tissue_He) / pres_tissue;
+
+#else
+
+	var_a = var_N2_a;
+	var_b = var_N2_b;
+
+#endif
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Calculate partial pressure of N2 in respired air at surface pressure
+//
+// Input:  pres_surface     surface pressure
+//
+// Output: N2_equilibrium   partial pressure of N2 in surface air
+//
+static void calc_N2_equilibrium(void)
+{
+	N2_equilibrium = 0.7902 * (pres_surface - ppWater);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Get, safeguard and convert the saturation and desaturation factors
+//
+// Input:  char_I_saturation_multiplier     saturation   factor (integer)
+//         char_I_desaturation_multiplier   desaturation factor (integer)
+//
+// Output: float_saturation_multiplier      saturation   factor (float)
+//         float_desaturation_multiplier    desaturation factor (float)
+//
+static void get_saturation_factors(void)
+{
+	// safeguard input parameters that are constant during the course of the dive
+	if( char_I_saturation_multiplier   < 100 ) char_I_saturation_multiplier   = 100;
+	if( char_I_saturation_multiplier   > 140 ) char_I_saturation_multiplier   = 140;
+
+	if( char_I_desaturation_multiplier <  60 ) char_I_desaturation_multiplier =  60;
+	if( char_I_desaturation_multiplier > 100 ) char_I_desaturation_multiplier = 100;
+
+	// convert input parameters to float numbers
+	float_saturation_multiplier   = 0.01 * char_I_saturation_multiplier;
+	float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// apply_saturation_factors
+//
+// Apply safety factors for both ZH-L16 models.
+//
+// Modified:  temp_tissue  safeguarded tissue increment/decrement
+//
+static void apply_saturation_factors(void)
+{
+	assert( 0.0 <  float_desaturation_multiplier && float_desaturation_multiplier <= 1.0 );
+	assert( 1.0 <= float_saturation_multiplier   && float_saturation_multiplier   <= 2.0 );
+
+	if   ( temp_tissue < 0.0 ) temp_tissue *= float_desaturation_multiplier;
+	else                       temp_tissue *= float_saturation_multiplier;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// convert_float_to_int
+//
+// Converts a float within range 0.0 - 9.99 into 16 bit integer scaled in 1/100.
+//
+static void convert_float_to_int(void)
+{
+		if      ( float_value <  0.005 ) int_value =   0;
+		else if ( float_value >= 9.985 ) int_value = 999;
+		else                             int_value = (unsigned short)(100 * float_value + 0.5);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// convert_float_to_char
+//
+// Converts a float within range 0.0 - 255 into 8 bit integer
+//
+static void convert_float_to_char(void)
+{
+		if      (float_value <    0.0) char_value = 0;
+		else if (float_value >= 254.5) char_value = 255;
+		else                           char_value = (unsigned char)(float_value + 0.5);
 }
 
 
@@ -810,6 +1152,20 @@
 	calc_hauptroutine();
 }
 
+
+//////////////////////////////////////////////////////////////////////////////
+// deco_init_output_vars
+//
+// called from divemode.asm
+//
+// Initializes all output variables to their default values.
+//
+void deco_init_output_vars(void)
+{
+	RESET_C_STACK
+	init_output_vars();
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // deco_clear_tissue
 //
@@ -826,6 +1182,7 @@
 	clear_tissue();
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // deco_calc_dive_interval
 //
@@ -841,6 +1198,7 @@
 	calc_interval(char_I_dive_interval);
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // deco_calc_dive_interval_1min
 //
@@ -893,6 +1251,7 @@
 	calc_desaturation_time();
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // deco_push_tissues_to_vault
 //
@@ -906,6 +1265,7 @@
 	push_tissues_to_vault();
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // deco_pull_tissues_from_vault
 //
@@ -929,202 +1289,190 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// calc_nextdecodepth
-//
-// INPUT, changing during dive:
-//        sim_pres_respiration     : current depth in absolute pressure
+// find_next_stop
 //
 // INPUT, fixed during dive:
-//        pres_surface
-//        GF_delta
-//        GF_high
-//        GF_low
-//        char_I_depth_last_deco
-//
-// MODIFIED
-//        locked_GF_step_norm/_alt : used for GF model
-//        low_depth_norm/_alt      : used for GF model
+//        pres_surface             : surface pressure (as absolute pressure)
+//        char_I_depth_last_deco   : depth of the last deco stop
+//
+// INPUT, changing during dive:
+//        float_depth_real         : current real depth in meters (float)
+//        char_depth_real          : current real depth in meters (integer)
+//        GF_high                  : GF high factor
+//        GF_low                   : GF low  factor
+//
+// INPUT & OUTPUT
+//        char_depth_sim           : simulated depth in meters
+//        GF_low_depth             : GF low  depth in current calculation cycle
+//        GF_slope                 : GF slope      in current calculation cycle
+//        GF_low_depth_norm/_alt   : frozen GF low depth reference
+//        GF_slope_norm/_alt       : frozen GF slope
 //
 // OUTPUT
-//        sim_depth_limit          : depth of next stop in meters     (if RETURN == true )
-//                                   next possible depth without stop (if RETURN == false)
-//
-// RETURN TRUE if a stop is needed, else false
-//
-static unsigned char calc_nextdecodepth(void)
+//        char_depth_last          : depth we came from
+//        sim_pres_respiration     : simulated depth in absolute pressure
+//
+// RETURN
+//        TRUE: a stop is needed, FALSE: no stop needed
+//
+static unsigned char find_next_stop(void)
 {
+	overlay unsigned char depth_1min;
+	overlay unsigned char depth_limit;
+	overlay unsigned char first_stop;
 	overlay unsigned char need_stop;
 
-	// compute current depth in meters
-	overlay float depth = (sim_pres_respiration - pres_surface) * BAR_TO_METER;
-
-	// compute depth in meters after 1 minute of ascent at float_ascent_speed (5..10 m/min)
-	overlay float min_depth = (depth > float_ascent_speed) ? (depth - float_ascent_speed) : 0.0;
-
-
-	// target the simulated tissues
-	tissue_increment = 0;
-
-	//---- check if a stop is needed for deco reasons ----------------------------
-
-	// switch on deco model
-	if( char_I_deco_model != 0 )
+
+	// -----------------------------------------------------------------------
+	// we start with the assumption that a stop is not required
+	// -----------------------------------------------------------------------
+
+	need_stop = 0;
+
+	// remember the depth we came from
+	char_depth_last = char_depth_sim;
+
+	// calculate the limit for the current depth
+	     if( char_I_deco_model == 0            ) calc_limit(1.0);											// straight Buhlmann
+	else if( char_depth_sim    >= GF_low_depth ) calc_limit(GF_low);										// with GF, below low depth reference
+	else                                         calc_limit(GF_high - GF_slope * (float)char_depth_sim);	// with GF, above low depth reference
+
+	// check if we can surface directly
+	if( ceiling <= 0.0 )
 	{
-		//---- ZH-L16 + GRADIENT FACTOR Model ------------------------------------
-
-		overlay float locked_GF_step;
-		overlay float low_depth;
-		overlay float limit_depth;
-
-		overlay unsigned char first_stop = 0;
-
-
-		// calculate minimum depth we can ascent to in bar relative pressure
-		calc_limit(GF_low);
-
-		// check if we can surface directly
-		if( ceiling <= 0.0 )
+		// YES - ascent to surface is allowed
+		char_depth_sim = 0;
+
+		//     - done
+		goto done;
+	}
+
+	// -----------------------------------------------------------------------
+	// a stop is required, but maybe not yet within the running minute
+	// -----------------------------------------------------------------------
+
+	// convert the depth we can ascent to from relative pressure to meters,
+	// rounded up (i.e. made deeper) to next full meter.
+	depth_limit = (unsigned char)(ceiling * BAR_TO_METER + 0.99);
+
+	// calculate the stop depth, i.e. round up to the next multiple of 3 meters
+	// using integer arithmetics
+	first_stop = 3 * ( (depth_limit + 2) / 3 );
+
+	// apply correction for the shallowest stop
+	if( first_stop == 3 ) first_stop = char_I_depth_last_deco;
+
+	// compute depth in meters that will be reached in 1 minute of ascent
+	// at a speed of char_I_ascent_speed (5..10 m/min)
+	if( char_depth_sim > char_I_ascent_speed )
+	{
+		depth_1min = char_depth_sim - char_I_ascent_speed;
+	}
+	else
+	{
+		depth_1min = 0;
+	}
+
+	// is the stop shallower than the depth that can be reached within 1 minute?
+	if( depth_1min > first_stop )
+	{
+		// YES - report the depth that will be reached within 1 minute of ascent
+		char_depth_sim = depth_1min;
+
+		//     - done
+		goto done;
+	}
+
+	// -----------------------------------------------------------------------
+	// we need to make a stop now
+	// -----------------------------------------------------------------------
+
+	// set stop data
+	need_stop      = 1;
+	char_depth_sim = first_stop;
+
+	// done so far if using straight Buhlmann
+	if( char_I_deco_model == 0 ) goto done;
+
+	// -----------------------------------------------------------------------
+	// we need to make a stop now and we are using the GF extension
+	// -----------------------------------------------------------------------
+
+	// is the depth limit deeper than the GF low depth reference used up to now?
+	if( depth_limit > GF_low_depth )
+	{
+		// YES - update the reference
+		GF_low_depth = depth_limit;
+		GF_slope     = (GF_high - GF_low) / (float)GF_low_depth;
+
+		// store for use in next cycles
+		if( deco_status & CALC_NORM )
 		{
-			min_depth = 0.0;		// set minimum depth to 0 meters = surface
-			goto no_deco_stop;		// done
-		}
-
-		// convert minimum depth we can ascent to from relative pressure to depth in meters
-		limit_depth = ceiling * BAR_TO_METER;
-
-		// recall low_depth dependent on current plan
-		low_depth = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? low_depth_alt : low_depth_norm;
-
-		// Store the deepest point needing a deco stop as the LOW reference for GF.
-		// NOTE: following stops will be validated using this LOW-HIGH GF scale,
-		//       so if we want to keep coherency, we should not validate this stop
-		//       yet, but apply the search to it, as for all the following stops afterward.
-		if( limit_depth > low_depth )
-		{
-			// update GF parameters
-			low_depth      = limit_depth;
-			locked_GF_step = GF_delta / low_depth;
-
-			// store updated GF parameters dependent on current plan
-			if( char_O_deco_status & DECO_PLAN_ALTERNATE )
-			{
-				low_depth_alt       = low_depth;
-				locked_GF_step_alt  = locked_GF_step;
-			}
-			else
-			{
-				low_depth_norm      = low_depth;
-				locked_GF_step_norm = locked_GF_step;
-			}
+			GF_low_depth_norm = GF_low_depth;
+			GF_slope_norm     = GF_slope;
 		}
 		else
 		{
-			// recall locked_GF_step dependent of current plan
-			locked_GF_step = (char_O_deco_status & DECO_PLAN_ALTERNATE) ? locked_GF_step_alt : locked_GF_step_norm;
+			GF_low_depth_alt = GF_low_depth;
+			GF_slope_alt     = GF_slope;
 		}
-
-		// invalidate this stop if we can ascent for 1 minute without going above minimum required deco depth
-		if( limit_depth < min_depth ) goto no_deco_stop;
-
-
-		//---- if program execution passes here, we need a deco stop --------------------------------
-
-		// round to multiple of 3 meters (limit depth is in meters of depth)
-		first_stop = 3 * (unsigned char)(0.4999 + limit_depth * 0.333333);
-
-		// check a constraint
-		assert( first_stop < 128 );
-
-		// apply correction for the shallowest stop, use char_I_depth_last_deco (3..6 m) instead
-		if( first_stop == 3 ) first_stop = char_I_depth_last_deco;
-
-		// We have a stop candidate.
-		// But maybe ascending to the next stop will diminish the constraint,
-		// because the GF might decrease more than the pressure gradient...
-		while( first_stop > 0 )
+	}
+
+	// keep the stop as it is when it is the first stop
+	// (i.e. there are no stops in the stops table yet)
+	if( internal_deco_depth[0] == 0  ) goto done;
+
+	// keep the stop as it is when extended stops are activated
+	if( main_status & EXTENDED_STOPS ) goto done;
+
+	// We have a (first) stop. But with a steep GF slope, the stop(s) after this
+	// first stop may be allowed to ascent to, too. This is because the gradient
+	// factor that will be used at the next depth(s) will allow more tissue super-
+	// saturation, maybe so much more that the next stop(s) will be allowed to
+	// ascent to. So we have to probe the next stops that are within the reach of
+	// 1 minute of ascent as well.
+
+	// no need to probe for a stop that is beyond 1 minute of ascent
+	while( first_stop >= (depth_1min + 3) )
+	{
+		overlay unsigned char next_stop;
+
+		// compute the depth of the next stop
+		if      ( first_stop <= char_I_depth_last_deco ) next_stop = 0;
+		else if ( first_stop == 6                      ) next_stop = char_I_depth_last_deco;
+		else                                             next_stop = first_stop - 3;
+
+		// compute the depth limit at the next stop depth
+		calc_limit(GF_high - GF_slope * (float)next_stop);
+
+		// check if ascent to the next stop is allowed
+		if( next_stop < (unsigned char)(ceiling * BAR_TO_METER + 0.99) )
 		{
-			// next depth
-			overlay unsigned char next_stop;
-
-			// invalidate this stop if we can ascent one more minute without going above minimum required deco depth
-			if( first_stop <= (unsigned char)min_depth ) goto no_deco_stop;
-
-			// compute depth of next stop
-			if      ( first_stop <= char_I_depth_last_deco ) next_stop = 0;
-			else if ( first_stop == 6                      ) next_stop = char_I_depth_last_deco;
-			else                                             next_stop = first_stop - 3;
-
-			// compute limit with the GF of the new stop candidate
-			if( (low_depth == 0.0) || (next_stop > low_depth) ) calc_limit(GF_low);
-			else                                                calc_limit(GF_high - next_stop * locked_GF_step);
-
-			// check if ascent to the next stop candidate is possible
-			if( ceiling * BAR_TO_METER >= next_stop )
-				goto deco_stop_found;					// no - ascent to next_stop forbidden
-
-			// else, validate that stop and loop...
-			first_stop = next_stop;
-		}
-
-no_deco_stop:
-		need_stop       = 0;							// set flag for stop needed to 'no'
-		sim_depth_limit = (unsigned char)min_depth;		// report depth we can ascent to without stop
-		goto done;
-
-deco_stop_found:
-		need_stop       = 1;							// set flag for stop needed to 'yes'
-		sim_depth_limit = (unsigned char)first_stop;	// stop depth, in meters
-
-done:
-		;
-	}
-	else
-	{
-		//---- ZH-L16 model -------------------------------------------------
-
-		overlay float limit_depth;
-
-
-		// calculate minimum depth we can ascent to in bar relative pressure
-		calc_limit(1.0);
-
-		// check if we can surface directly
-		if( ceiling >= 0 )
-		{
-			// no - set flag for stop needed to 'yes'
-			need_stop = 1;
-
-			// convert stop depth in relative pressure to stop index
-			limit_depth = ceiling * BAR_TO_METER / 3.0;
-
-			// convert stop index to depth in meters, rounded to multiple of 3 meters
-			sim_depth_limit = 3 * (short)(limit_depth + 0.99);
-
-			// correct last stop to 4m/5m/6m
-			if( sim_depth_limit == 3 ) sim_depth_limit = char_I_depth_last_deco;
+			// NO - the next stop would be too shallow
+			break;
 		}
 		else
 		{
-			// yes - set flag for stop needed to 'no'
-			need_stop       = 0;
-
-			// set depth we can ascent to as 0 = surface
-			sim_depth_limit = 0;
+			// YES - the next stop is allowed
+			char_depth_sim = next_stop;
+
+			//     - ascent to next stop
+			first_stop = next_stop;
+
+			//     - loop to probe the stop following next
+			continue;
 		}
 	}
 
-	// ---- After the first deco stop, gas changes are only done at deco stops now! -----------------------
-
-	// check if a stop is found and there is a better gas to switch to
-	if( need_stop         )
-	if( gas_find_better() )
-	{
-		// set the new calculation ratios for N2, He and O2
-		gas_set_ratios();
-
-		// prime the deco stop with the gas change time
-		update_deco_table(char_I_gas_change_time);
-	}
+
+	// -----------------------------------------------------------------------
+	// common end for straight Buhlmann and Buhlmann with GF extension
+	// -----------------------------------------------------------------------
+
+done:
+
+	// calculate absolute pressure at the depth found
+	sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface;
 
 	return need_stop;
 }
@@ -1133,83 +1481,70 @@
 //////////////////////////////////////////////////////////////////////////////
 // publish_deco_table
 //
-// Buffer the stops, once computed, so we can continue to display them
-// while computing the next set.
+// Input:  internal_deco_depth[]      depth in internal stops table
+//         internal_deco_time[]       times ...
+//         internal_deco_gas[]        gases ...
+//
+// Output: char_O_deco_depth[]        depth in the external stops table
+//         char_O_deco_time[]         times ...
+//         char_O_deco_gas[]          gases ...
+//         char_O_deco_time_for_log   times in reverse order
 //
 static void publish_deco_table(void)
 {
-	overlay unsigned char x, y;
-
-
-	// Copy depth of the first (deepest) stop, because when reversing
-	// order, it will be hard to find...
-	char_O_first_deco_depth = internal_deco_depth[0];
-	char_O_first_deco_time  = internal_deco_time [0];
-
-	for( x = 0; x < NUM_STOPS; x++ )
+	overlay unsigned char x = 0;
+	overlay unsigned char y;
+
+
+	// copy all entries from internal to external stops table
+	for( y = 0; y < NUM_STOPS; y++ )
 	{
-		char_O_deco_depth[x] = internal_deco_depth[x];
-		char_O_deco_time [x] = internal_deco_time [x];
-		char_O_deco_gas  [x] = internal_deco_gas  [x];
+		// remember index of last entry with a non-null depth
+		if( internal_deco_depth[y] > 0 ) x = y;
+
+		// copy depth, time and gas
+		char_O_deco_depth[y] = internal_deco_depth[y];
+		char_O_deco_time [y] = internal_deco_time [y];
+		char_O_deco_gas  [y] = internal_deco_gas  [y];
 	}
 
-	// Now fill the char_O_deco_time_for_log array
-	// ---- First: search the first non-null depth
-	for( x = (NUM_STOPS-1); x != 0; --x )
-		if( internal_deco_depth[x] != 0 ) break;
-
-	//---- Second: copy to output table (in reverse order)
-	for( y = 0; y < NUM_STOPS; y++, --x )
+
+	// copy times of shallowest stops to logging table
+	for( y = 0; y < NUM_STOPS_LOG; y++, --x )
 	{
 		char_O_deco_time_for_log[y] = internal_deco_time [x];
 
-		// Stop when the last transfer is done.
+		// stop when all entries are copied
 		if( x == 0 ) break;
 	}
 
-	//---- Third: fill table with null until end
-	for( y++; y < NUM_STOPS; y++ )
+	// fill the remainder of the logging table with null
+	// if it is not completely filled already
+	for( y++; y < NUM_STOPS_LOG; y++ )
 		char_O_deco_time_for_log[y] = 0;
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// temp_tissue_safety
-//
-// outsourced in v.102
-//
-// Apply safety factors for both ZH-L16 models.
-//
-static void temp_tissue_safety(void)
-{
-	assert( 0.0 <  float_desaturation_multiplier && float_desaturation_multiplier <= 1.0 );
-	assert( 1.0 <= float_saturation_multiplier   && float_saturation_multiplier   <= 2.0 );
-
-	if( temp_tissue < 0.0 ) temp_tissue *= float_desaturation_multiplier;
-	else                    temp_tissue *= float_saturation_multiplier;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
 // Find current gas in the list (if any) and get its change depth
 //
-// Input:  char_I_current_gas    : 1..5 or 6
-//
-// Output: sim_gas_current       : 1..6 or 0 for the manually configured gas/dil
-//         sim_gas_current_depth : change depth (MOD) of the gas/dil in meters
+// Input:  char_I_current_gas_num   number of current gas (1..5 or 6)
+//
+// Output: sim_gas_current_num      1..6 or 0 for the manually configured gas/dil
+//         sim_gas_current_depth    change depth (MOD) of the gas/dil in meters
 //
 static void gas_find_current(void)
 {
-	assert( 1 <= char_I_current_gas && char_I_current_gas <= 6 );
-
-	if( char_I_current_gas <= NUM_GAS )			// gas/diluent 1-5
+	assert( 1 <= char_I_current_gas_num && char_I_current_gas_num <= 6 );
+
+	if( char_I_current_gas_num <= NUM_GAS )			// gas/diluent 1-5
 	{
-		sim_gas_current       = char_I_current_gas;
-		sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current-1];
+		sim_gas_current_num   = char_I_current_gas_num;
+		sim_gas_current_depth = char_I_deco_gas_change[sim_gas_current_num-1];
 	}
 	else
 	{
-		sim_gas_current       = 0;
+		sim_gas_current_num   = 0;
 		sim_gas_current_depth = char_I_gas6_depth;
 	}
 }
@@ -1218,16 +1553,16 @@
 //////////////////////////////////////////////////////////////////////////////
 // Find the deco gas with the shallowest change depth below or at the current depth
 //
-// INPUT    sim_depth_limit          : current depth in meters
-//          sim_gas_current          : number of the currently used gas/dil
-//          sim_gas_current_depth    : change depth of the currently used gas/dil
-//          char_I_deco_gas_type[]   : types         of the gases/dils
-//          char_I_deco_gas_change[] : change depths of the gases/dils
-//
-// MODIFIED sim_gas_current          : index of the gas (1..5) - only if return value is true
-//          sim_gas_current_depth    : switch depth            - only if return value is true
-//
-// RETURNS TRUE if a better gas is available
+// Input:    char_depth_sim             simulated depth in meters
+//           sim_gas_current_num        number of the currently used gas/dil
+//           sim_gas_current_depth      change depth of the currently used gas/dil
+//           char_I_deco_gas_type[]     types         of the gases/dils
+//           char_I_deco_gas_change[]   change depths of the gases/dils
+//
+// Modified: sim_gas_current_num        index of the gas (1..5) - only if return value is true
+//           sim_gas_current_depth      switch depth            - only if return value is true
+//
+// Return value is TRUE if a better gas is available
 //
 static unsigned char gas_find_better(void)
 {
@@ -1235,27 +1570,21 @@
 	overlay unsigned char switch_gas   =   0;
 	overlay unsigned char j;
 
-	// no automatic gas changes in CCR mode
-	if( (char_O_deco_status & DECO_MODE_MASK) == DECO_MODE_CCR ) return 0;
+	//	// no automatic gas changes in CCR mode
+	//	if( (deco_status & MODE_MASK) == MODE_CCR ) return 0;
 
 	// loop over all deco gases to find the shallowest one below or at current depth
 	for( j = 0; j < NUM_GAS; ++j )
 	{
 		// Is this gas not the one we are already breathing?
-		if( j+1 != sim_gas_current )
-
-		// Is this -                      an (active) deco gas,
-		//         - or if in deco phase, any gas but disabled
-		//         - or if in bailout,    any gas but disabled,
-		//         - or if in pSCR mode,  any gas but disabled?
-		if(   (                                               ( char_I_deco_gas_type[j] == 3 ) )
-		   || ( ( char_O_deco_info   & DECO_FLAG         ) && ( char_I_deco_gas_type[j] != 0 ) )
-		   || ( ( char_O_deco_status & DECO_BAILOUT_MODE ) && ( char_I_deco_gas_type[j] != 0 ) )
-		   || ( ( char_O_main_status & DECO_MODE_PSCR    ) && ( char_I_deco_gas_type[j] != 0 ) ) )
+		if( j+1 != sim_gas_current_num )
+
+		// Is this gas available?
+		if( char_I_deco_gas_type[j] > 0 )
 
 		// Is the change depth of the this gas deeper than or
 		// at least equal to the current depth?
-		if( char_I_deco_gas_change[j] >= sim_depth_limit )
+		if( char_I_deco_gas_change[j] >= char_depth_sim )
 
 		// Is the change depth of this gas shallower than the
 		// change depth of the gas we are currently on?
@@ -1278,7 +1607,7 @@
 	if( switch_gas )
 	{
 		// YES - set the better gas as the new gas
-		sim_gas_current       = switch_gas;
+		sim_gas_current_num   = switch_gas;
 
 		// set its change depth as the last used change depth
 		sim_gas_current_depth = switch_depth;
@@ -1297,32 +1626,33 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// Set calc_N2/He/O2_ratios by sim_gas_current
-//
-// Input:  sim_gas_current              : index of gas to use
-//         real_O2_ratio, real_He_ratio : if gas =    0 (the manually set gas)
-//         char_I_deco_O2/He_ratio[]    : if gas = 1..5 (the configured gases)
-//
-// Output: sim_N2_ratio, sim_He_ratio   : ratios of the inert gases
-//         sim_pSCR_drop                : ppO2 drop in pSCR loop
+// Set calc_N2/He/O2_ratios by sim_gas_current_num
+//
+// Input:  sim_gas_current_num           index of gas to use
+//         real_O2_ratio, real_He_ratio  if gas =    0 (the manually set gas)
+//         char_I_deco_O2/He_ratio[]     if gas = 1..5 (the configured gases)
+//
+// Output: sim_N2_ratio, sim_He_ratio    ratios of the inert gases
+//         sim_pSCR_drop                 ppO2 drop in pSCR loop
 //
 static void gas_set_ratios(void)
 {
 	overlay float sim_IG_ratio;
 
-	assert( 0 <= sim_gas_current <= NUM_GAS );
-
-
+	assert( 0 <= sim_gas_current_num <= NUM_GAS );
+
+
+#ifdef _helium
 	// get gas ratios
-	if( sim_gas_current == 0 )
+	if( sim_gas_current_num == 0 )
 	{
 		sim_O2_ratio = real_O2_ratio;
 		sim_He_ratio = real_He_ratio;
 	}
 	else
 	{
-		sim_O2_ratio = 0.01 * char_I_deco_O2_ratio[sim_gas_current-1];
-		sim_He_ratio = 0.01 * char_I_deco_He_ratio[sim_gas_current-1];
+		sim_O2_ratio = 0.01 * char_I_deco_O2_ratio[sim_gas_current_num-1];
+		sim_He_ratio = 0.01 * char_I_deco_He_ratio[sim_gas_current_num-1];
 	}
 
 	// inert gas ratio (local helper variable)
@@ -1330,9 +1660,24 @@
 
 	// N2 ratio
 	sim_N2_ratio  = sim_IG_ratio - sim_He_ratio;
-
+#else
+	// get O2 ratio
+	sim_O2_ratio = ( sim_gas_current_num == 0 ) ? real_O2_ratio : 0.01 * char_I_deco_O2_ratio[sim_gas_current_num-1];
+
+	// set H2 ratio to zero
+	sim_He_ratio = 0.0;
+
+	// inert gas ratio (local helper variable)
+	sim_IG_ratio  = 1.00 - sim_O2_ratio;
+
+	// N2 ratio
+	sim_N2_ratio  = sim_IG_ratio;
+#endif
+
+#ifdef _ccr_pscr
 	// ppO2 drop in pSCR loop
 	sim_pSCR_drop = sim_IG_ratio * float_pSCR_factor;
+#endif
 
 
 	assert( 0.0 <=  sim_N2_ratio && sim_N2_ratio  <= 0.95 );
@@ -1345,8 +1690,8 @@
 // Compute respired ppO2, ppN2 and ppHe
 //
 // Input:  tissue_increment           : selector for targeting simulated or real tissues
-//         char_O_main_status         : breathing mode for real      tissues
-//         char_O_deco_status         : breathing mode for simulated tissues
+//         main_status                : breathing mode for real      tissues
+//         deco_status                : breathing mode for simulated tissues
 //         sim_/real_O2_ratio         : (simulated) O2 ratio breathed
 //         sim_/real_N2_ratio         : (simulated) N2 ratio breathed
 //         sim_/real_He_ratio         : (simulated) He ratio breathed
@@ -1359,52 +1704,72 @@
 //
 // Output: ppN2                       : respired N2 partial pressure
 //         ppHe                       : respired He partial pressure
-//         char_ppO2                  : breathed ppO2 in %, used in CNS calculation
+//         char_ppO2                  : breathed ppO2 in %, used for CNS calculation
 //
 void calc_alveolar_pressures(void)
 {
 	overlay float calc_pres_respiration;
 	overlay float calc_O2_ratio;
 	overlay float calc_N2_ratio;
+
+#ifdef _helium
 	overlay float calc_He_ratio;
+#endif
+
+#ifdef _ccr_pscr
 	overlay float calc_pSCR_drop;
+#endif
 
 	overlay unsigned char status;
 
 
-	assert( 0.00 <= real_N2_ratio && real_N2_ratio <= 1.00 );
-	assert( 0.00 <= real_He_ratio && real_He_ratio <= 1.00 );
-	assert(        (real_N2_ratio + real_He_ratio) <= 1.00 );
+	assert( 0.00 <= real_N2_ratio && real_N2_ratio  <= 1.00 );
+	assert( 0.00 <= real_He_ratio && real_He_ratio  <= 1.00 );
+	assert(        (real_N2_ratio +  real_He_ratio) <= 1.00 );
 	assert( 0.800 < real_pres_respiration && real_pres_respiration < 14.0 );
 
-	assert( 0.00 <= sim_N2_ratio && real_N2_ratio <= 1.00 );
-	assert( 0.00 <= sim_He_ratio && real_He_ratio <= 1.00 );
-	assert(         (sim_N2_ratio + sim_He_ratio) <= 1.00 );
+	assert( 0.00 <= sim_N2_ratio && real_N2_ratio  <= 1.00 );
+	assert( 0.00 <= sim_He_ratio && real_He_ratio  <= 1.00 );
+	assert(         (sim_N2_ratio +  sim_He_ratio) <= 1.00 );
 	assert( 0.800 < sim_pres_respiration && sim_pres_respiration < 14.0 );
 
 
 	// get input data according to context
-	if( tissue_increment & TISSUE_FLAG )
+	if( tissue_increment & TISSUE_SELECTOR )
 	{
 		//---- real tissues -----------------------------------------------------------
-		status                = char_O_main_status;
 		calc_pres_respiration = real_pres_respiration;
-		calc_pSCR_drop        = real_pSCR_drop;
-
+
+		status                = main_status;
 		calc_O2_ratio         = real_O2_ratio;
 		calc_N2_ratio         = real_N2_ratio;
+
+#ifdef _helium
 		calc_He_ratio         = real_He_ratio;
+#endif
+
+#ifdef _ccr_pscr
+		calc_pSCR_drop        = real_pSCR_drop;
+#endif
 	}
 	else
 	{
 		//---- simulated tissues ------------------------------------------------------
-		status                = char_O_deco_status;
-		calc_pres_respiration = sim_pres_respiration;
-		calc_pSCR_drop        = sim_pSCR_drop;
-
+
+		// correct sim_pres_respiration if shallower than calculated stop depth
+		calc_pres_respiration = ( real_pres_respiration < sim_pres_respiration ) ? real_pres_respiration : sim_pres_respiration;
+
+		status                = deco_status;
 		calc_O2_ratio         = sim_O2_ratio;
 		calc_N2_ratio         = sim_N2_ratio;
+
+#ifdef _helium
 		calc_He_ratio         = sim_He_ratio;
+#endif
+
+#ifdef _ccr_pscr
+		calc_pSCR_drop        = sim_pSCR_drop;
+#endif
 	}
 
 	//---- OC, CCR and Bailout Mode Gas Calculations -----------------------------------
@@ -1418,6 +1783,8 @@
 	// calculate ppO2 of the pure gas (OC, diluent)
 	OC_ppO2 = O2_ppO2 * calc_O2_ratio;
 
+#ifdef _ccr_pscr
+
 	// calculate pSCR ppO2
 	pSCR_ppO2 = OC_ppO2 - calc_pSCR_drop;
 
@@ -1426,7 +1793,7 @@
 
 
 	//---- Loop modes : adjust ppN2 and ppHe for change in ppO2 due to setpoint (CCR) or drop (pSCR) ---
-	if( status & DECO_MODE_LOOP )
+	if( status & MODE_LOOP )
 	{
 		overlay float const_ppO2;
 		overlay float   max_ppO2;
@@ -1437,21 +1804,21 @@
 		// Limit the setpoint to the maximum physically possible ppO2. This prevents for
 		// example calculating with a setpoint of 1.3 bar in only 2 meters of depth.
 		// Additionally, the ppO2 can be further reduced to account for exhaled inert gases
-		// accumulating in the loop by the user-adjustable setting char_I_cc_max_frac_o2.
+		// accumulating in the loop by the user-adjustable setting char_I_CC_max_frac_O2.
 		// (ppWater is neglected here)
-		max_ppO2 = 0.01 * char_I_cc_max_frac_o2 * calc_pres_respiration;
+		max_ppO2 = 0.01 * char_I_CC_max_frac_O2 * calc_pres_respiration;
 
 		if( const_ppO2 > max_ppO2 ) const_ppO2 = max_ppO2;
 
 		// check which kind of loop we are on
-		if( status & DECO_MODE_PSCR )
+		if( status & MODE_PSCR )
 		{
 			//---- pSCR Mode --------------------------------------------------------------------------
 
 			// Use the sensor value if available, but only in real tissue context!
 			// In all other cases use calculated ppO2.
-			if( char_I_const_ppO2 && (tissue_increment & TISSUE_FLAG)) ppO2 = const_ppO2;
-			else                                                       ppO2 = pSCR_ppO2;
+			if   ( char_I_const_ppO2 && (tissue_increment & TISSUE_SELECTOR)) ppO2 = const_ppO2;
+			else                                                              ppO2 = pSCR_ppO2;
 		}
 		else
 		{
@@ -1464,7 +1831,7 @@
 		// adjust overall gas pressure for change in ppO2 due to setpoint (CCR) or drop (pSCR),
 		// capture potential failure conditions first:
 		if(    ( calc_pres_respiration <  ppO2 )     // sensor reading or selected setpoint is higher than ambient pressure
-		    || ( calc_O2_ratio         > 0.995 ) )   // diluent is pure O2, i.e. calc_N2_ratio + calc_He_ratio = 0 yielding a div/0
+		    || ( calc_O2_ratio         > 0.995 ) )   // diluent is pure O2, i.e. calc_N2_ratio + calc_He_ratio = 0 would give a div/0
 		{
 			// failure condition present, set predetermined result
 			calc_pres_respiration = 0.0;
@@ -1473,10 +1840,15 @@
 		{
 			// no failure conditions present, equation can be executed
 			calc_pres_respiration -= ppO2;
+#ifdef _helium
 			calc_pres_respiration /= calc_N2_ratio + calc_He_ratio;
+#else
+			calc_pres_respiration /= calc_N2_ratio;
+#endif
 		}
 	}
 	else
+#endif	// _ccr_pscr
 	{
 		//---- OC mode ---------------------------------------------------------------------------------
 
@@ -1495,7 +1867,7 @@
 	//---- calculate ppN2 and ppHe ---------------------------------------------------------------------
 
 	// add deco safety distance when working on simulated tissues
-	if( !(tissue_increment & TISSUE_FLAG) ) calc_pres_respiration += float_deco_distance;
+	if( !(tissue_increment & TISSUE_SELECTOR) ) calc_pres_respiration += float_deco_distance;
 
 	// compute ppN2 and ppHe, capture potential failure conditions first:
 	if( calc_pres_respiration > ppWater )
@@ -1505,7 +1877,13 @@
 
 		// calculate partial pressures
 		ppN2 = calc_N2_ratio * calc_pres_respiration;
+
+#ifdef _helium
 		ppHe = calc_He_ratio * calc_pres_respiration;
+#else
+		ppHe = 0.0;
+#endif
+
 	}
 	else
 	{
@@ -1517,109 +1895,291 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
+// init_output_vars
+//
+// Initializes all output variables to their default values
+//
+static void init_output_vars(void)
+{
+	// clear the internal stops table from remains lasting from the previous dive or deco calculator run
+	clear_deco_table();
+
+	// publish the cleared stops table to the display functions
+	publish_deco_table();
+
+	// clear the published gas needs in volume and pressure
+	for( i = 0; i < NUM_GAS; ++i )
+	{
+		int_O_gas_need_vol[i]  = 0;
+		int_O_gas_need_pres[i] = 0 + INT_FLAG_ZERO + INT_FLAG_INVALID;
+	}
+
+	// values initially to be set to zero
+	int_O_ceiling           = 0;						// ceiling depth in mbar
+	char_O_deco_info        = 0;						// clear all deco information flags
+	char_O_deco_warnings    = 0;						// clear all deco warning     flags
+
+	// default desaturation time to 24 hours (it will not be computed during a dive)
+	int_O_desaturation_time = 1440;
+
+	// initialize CNS values
+	int_O_CNS_norm          = 0 + INT_FLAG_INVALID;
+	int_O_CNS_alt           = 0 + INT_FLAG_INVALID;
+
+	// initialize NDL times
+	char_O_NDL_norm         = 240;
+	char_O_NDL_alt          = 240;
+
+	// initialize ascent times
+	int_O_TTS_norm          = 0;
+	int_O_TTS_alt           = 0 + INT_FLAG_INVALID + INT_FLAG_NOT_COMPUTED_YET;
+
+#ifdef _rx_functions
+	// clear TR values
+	int_O_SAC_measured      = 0 + INT_FLAG_NOT_AVAIL;	// SAC rate
+	int_O_pressure_need[0]  = 0 + INT_FLAG_NOT_AVAIL;	// pressure need to reading 1
+	int_O_pressure_need[1]  = 0 + INT_FLAG_NOT_AVAIL;	// pressure need to reading 2
+#endif
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
 // clear_tissue
 //
-// optimized in v.101 (var_N2_a)
-//
-// Reset all tissues to surface pressure equilibrium state.
+// Reset all tissues to surface pressure equilibrium state
+//
+// Input:  int_I_pres_surface             current surface pressure in hPa (mbar)
+//
+// Output: real_pres_tissue_N2[]          partial pressure of N2 in real tissues
+//         real_pres_tissue_He[]          partial pressure of He in real tissues
+//         char_O_tissue_pres_N2[]        partial pressure of N2 for tissue graphics
+//         char_O_tissue_pres_He[]        partial pressure of He for tissue graphics
+//         char_O_tissue_pressure[]       total   pressure       for tissue graphics
+//         CNS_fraction_real              internal CNS value
+//         int_O_CNS_current              current CNS value
+//         int_O_CNS_norm                 CNS value at end of normal      dive plan
+//         int_O_CNS_alt                  CNS value at end of alternative dive plan
+//         char_O_deco_warnings           deco warnings vector
+//         char_O_NDL_norm                remaining NDL time in normal      dive plan
+//         char_O_NDL_alt                 remaining NDL time in alternative dive plan
+//         int_O_TTS_norm                 ascent time (TTS)  in normal      dive plan
+//         int_O_TTS_alt                  ascent time (TTS)  in alternative dive plan
+//         int_O_lead_supersat            supersaturation of the leading tissue
 //
 static void clear_tissue(void)
 {
-	// safety limit to prevent improper initialization values
-	if( int_I_pres_respiration < 500) int_I_pres_respiration = 500;		// min. respiration pressure = 500 mbar
-
-	real_pres_respiration = 0.001  * int_I_pres_respiration;
-	N2_equilibrium        = 0.7902 * (real_pres_respiration - ppWater);
-
+	// safeguard and convert the surface pressure (mbar -> bar) (*)
+	if( int_I_pres_surface < 500 ) pres_surface = 0.500;
+	else                           pres_surface = 0.001 * int_I_pres_surface;
+
+	// calculate partial pressure of N2 in respired air at surface pressure
+	calc_N2_equilibrium();
+
+	// cycle through the 16 Buhlmann tissues
 	for( ci = 0; ci < NUM_COMP; ci++ )
 	{
-		// cycle through the 16 Buhlmann N2 tissues
-		pres_tissue_N2[ci]              = N2_equilibrium;	// initialize data for "real" tissue
-		char_O_tissue_N2_saturation[ci] = 11;				// initialize data for tissue graphics
-
-		// cycle through the 16 Buhlmann He tissues
-		pres_tissue_He[ci]              = 0.0;				// initialize data for "real" tissue
-		char_O_tissue_He_saturation[ci] = 0;				// initialize data for tissue graphics
+		// reset tissue pressures
+		real_pres_tissue_He[ci]    = 0.0;				// He
+		real_pres_tissue_N2[ci]    = N2_equilibrium;	// N2
+
+		// reset tissue pressures for scaled for tissue graphics
+		char_O_tissue_pres_He[ci]  = 0;					// He
+		char_O_tissue_pres_N2[ci]  = 10;				// N2
+		char_O_tissue_pressure[ci] = 10;				// combined
 	}
 
 	// reset CNS values
-	CNS_fraction = 0.0;
-	int_O_CNS_fraction = int_O_normal_CNS_fraction = int_O_alternate_CNS_fraction = 0;
-
-
-	// reset any warnings and status data
-	char_O_deco_warnings		= 0;
-	char_O_deco_status			= 0;
+	CNS_fraction_real = 0.0;
+	int_O_CNS_current = int_O_CNS_norm = int_O_CNS_alt = 0;
 
 	// reset some more vars to their defaults
-	char_O_nullzeit				= 240;
-	int_O_ascenttime			= 0;
-	int_O_alternate_ascenttime	= 0;
-	int_O_gradient_factor		= 0;
+	char_O_NDL_norm       = 240;
+	char_O_NDL_alt        = 240;
+	int_O_TTS_norm        = 0;
+	int_O_TTS_alt         = 0;
+	int_O_lead_supersat   = 0;
+
+	// reset all warning and info flags
+	char_O_deco_warnings  = 0;
+	char_O_deco_info      = 0;
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 // calc_hauptroutine
 //
-// this is the major code in dive mode calculates:
-//      the tissues,
-//      the bottom time,
-//      and simulates the ascend with all deco stops.
+// This is the major code in dive mode, it calculates the tissue pressures,
+// the bottom time, and it calculates the ascend with all deco stops, etc.
+//
+// Input:    char_O_main_status              deco engine control and real      tissues mode
+//           char_O_deco_status              deco engine control and simulated tissues mode
+//           char_I_sim_advance_time         mailbox for bottom time incrementing
+//
+//           char_I_SAC_work                 gas usage rate during working    phase in l/min
+//           char_I_SAC_deco                 gas usage rate during deco stops phase in l/min
+//
+//           char_I_deco_model               selector for GF extension
+//           char_I_ascent_speed             ascent speed
+//           char_I_deco_distance            safety distance between stop depth and calculated depth
+//           char_I_saturation_multiplier    safety factor for tissue saturation
+//           char_I_desaturation_multiplier  safety factor for tissue desaturation
+//
+//           char_I_pressure_gas[]           amount of gas available for ascent in bar
+//           int_I_pressure_drop[]           pressure drop used to calculate SAC rate
+//           char_I_gas_avail_size[]         size of the tanks in liters
+//
+// Output:   int_O_O2_ppO2                   partial pressure of pure O2 at current depth
+//           int_O_pure_ppO2                 partial pressure of O2 in gas at current depth
+//           int_O_pSCR_ppO2                 partial pressure of O2 in gas at current depth, corrected for pSCR mode
+//           int_O_breathed_ppO2             partial pressure of O2 currently breathed
+//
+//           char_O_deco_status              deco engine computations status
+//           char_O_deco_info                deco engine information vector
+//           char_O_deco_warnings            deco engine warnings    vector
+//
+//           char_O_NDL_norm                 remaining NDL time in normal      dive plan
+//           char_O_NDL_alt                  remaining NDL time in alternative dive plan
+//           int_O_TTS_norm                  ascent time (TTS)  in normal      dive plan
+//           int_O_TTS_alt                   ascent time (TTS)  in alternative dive plan
+//           int_O_CNS_norm                  CNS value at end   of normal      dive plan
+//           int_O_CNS_alt                   CNS value at end   of alternative dive plan
+//
+//           int_O_gas_need_vol              calculated gas volumes   needed for ascent
+//           int_O_gas_need_pres             calculated gas pressures needed for ascent
+//
+//           int_O_SAC_measured              measured surface air consumption (SAC) rate in l/min
+// 
+// Modified: int_IO_pressure_value[]         warning flags added to pressure reading 1 & 2
+//           int_IO_pressure_need[]          pressure needs      to pressure reading 1 & 2
 //
 static void calc_hauptroutine(void)
 {
-	overlay unsigned int int_ppO2_min;
-	overlay unsigned int int_ppO2_max;
-	overlay unsigned int int_ppO2_max_dil;
-	overlay unsigned int int_ppO2_max_max;
-	overlay float        EAD;
-	overlay float        END;
-
-
-	//--- Set-up Part --------------------------------------------------------------------------------
-
-	// clear flags indicating a calculation has been completed
-	char_O_main_status &= ~( DECO_COMPLETED_NORM + DECO_COMPLETED_ALT );
-
-	// twosectimer:
-	// calc_hauptroutine is now invoked every second to speed up the deco planning.
-	// Because the tissue and CNS calculations are based on a two seconds period, a
-	// toggle-timer is used to skip every 2nd invocation.
-	twosectimer = (twosectimer) ? 0 : 1;
-
-	// do initializations that need to be done only once at the beginning of a dive
-	if( (char_O_deco_status & DECO_STATUS_MASK) == DECO_STATUS_INIT )
+	overlay unsigned short int_ppO2_min;
+	overlay unsigned short int_ppO2_max;
+	overlay unsigned short int_ppO2_max_dil;
+	overlay unsigned short int_ppO2_max_max;
+	overlay float          EAD;
+	overlay float          END;
+
+	//=============================================================================================
+
+	//
+	//--- Setup Part ---------------------------------------------------------------------------------
+	//
+
+	// set time limit for preempting deco calculations, timer is 16 bit and increments every 1/32 ms
+	tmr5_value = 65535 - (32 * BUDGET_PER_SECOND / INVOKES_PER_SECOND);
+
+	// load timer
+	load_tmr5();
+
+	// read command flags and set up what to do
+	switch( char_O_deco_status & COMMAND_MASK )
 	{
-		// compute a factor that will be used later on in pSCR calculations
-		float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio;
+
+	case INITIALIZE:
+	case INITIALIZE_START_NORM:
+	case INITIALIZE_START_ALT:
+
+		// copy master modes to shadow registers
+		main_status = char_O_main_status;
+		deco_status = char_O_deco_status;
+
+		// clear all command flags on the master mode to signal that the command is read
+		char_O_deco_status &= ~COMMAND_MASK;
+
+		// clear the initialization flag on the shadow copy
+		deco_status &= ~INITIALIZE;
+
+		// initialize the sequence timer
+		sequence_timer = 0;
+
+		// set the calculation phase to start with to doing the once-per-dive initialization
+		next_planning_phase = PHASE_10_DIVE_INIT;
+
+		break;
+
+
+	case START_NORM:
+	case START_ALT:
+
+		// copy master modes to shadow registers
+		main_status = char_O_main_status;
+		deco_status = char_O_deco_status;
+
+		// clear all command flags on the master mode to signal that the command is read
+		char_O_deco_status &= ~COMMAND_MASK;
+
+		// set the calculation phase to start with to doing the cyclic initialization
+		next_planning_phase = PHASE_11_CYCLIC_INIT;
+
+		// continue in CALCULATING
+
+
+	case CALCULATING:
+
+		// keep current calculation phase
+
+		// step the sequence timer
+		sequence_timer = (sequence_timer < INVOKES_PER_SECOND * 2 - 1) ? sequence_timer + 1 : 0;
+
+		break;
 	}
 
 
-	//---- Calculations Part ----------------------------------------------------------------------
-
-	// acquire current environment data
-	calc_hauptroutine_data_input();
+	//
+	//--- End of Setup Part -----------------------------------------------------------------------
+	//
+
+	//=============================================================================================
+
+	//
+	//---- Calculations Part (real Tissues) -------------------------------------------------------
+	//
+
 
 	// target the real tissues with 2 second increments by default
-	tissue_increment = TISSUE_FLAG | 0;
-
-	// calculate ppO2, ppN2 and ppHe
-	calc_alveolar_pressures();
-
-	// All deco code is invoked every second. But as the tissue and CNS updates are based
-	// on 2 seconds periods, each update is done only on each 2nd second. In case a "fast
-	// forward" of the tissues is commanded, the 2-seconds rule is over-raided.
-	if( twosectimer || char_I_sim_advance_time )
+	tissue_increment = TISSUE_SELECTOR | 0;
+
+
+	// Tasks every second, if more than 1 invocation per second: on the first section of the second.
+	// Requests for tissue "fast forward" are executed immediately.
+#if (INVOKES_PER_SECOND > 1)
+	if(    ( sequence_timer          == 0                  )
+	    || ( sequence_timer          == INVOKES_PER_SECOND )
+	    || ( char_I_sim_advance_time  > 0                  )
+	)
+#endif
 	{
+		// acquire current environmental data
+		calc_hauptroutine_data_input();
+
+		// calculate ppO2, ppN2 and ppHe
+		calc_alveolar_pressures();
+
+		// add decent calculation here and include trigger in above if-statement
+		// TODO
+
+	} // tasks every second, on the first section of the second
+
+
+	// Tasks every 2 seconds, on the first section of the respective second.
+	// Requests for tissue "fast forward" are executed immediately.
+	if(    ( sequence_timer           == 0 )
+	    || ( char_I_sim_advance_time   > 0 )
+	)
+	{
+		// Tissue and CNS updates are based on 2 seconds periods!
+
 		// Set up normal tissue updating or "fast forward" updating for simulator
 		// sim+5' function and deco calculator bottom time calculation.
 		if( char_I_sim_advance_time > 0 )
 		{
 			// configure "fast forward" tissue updating
-			tissue_increment = TISSUE_FLAG | char_I_sim_advance_time;
-
-			// clear the "mailbox"
+			tissue_increment = TISSUE_SELECTOR | char_I_sim_advance_time;
+
+			// clear the request
 			char_I_sim_advance_time = 0;
 		}
 
@@ -1630,753 +2190,498 @@
 		calc_CNS();
 
 		// calculate ceiling (at GF_high or 100%) and leading tissue supersaturation
-		if( char_I_deco_model ) calc_limit(GF_high);		// GF factors enabled
-		else                    calc_limit(  1.0  );		// classic Buhlmann
-
-		// convert ceiling from float to integer for export [mbar relative pressure]
+		if   ( char_I_deco_model ) calc_limit(GF_high);		// GF factors enabled
+		else                       calc_limit(  1.0  );		// classic Buhlmann
+
+		// convert the ceiling value to integer
 		convert_ceiling_for_display();
 
-		// convert leading tissue supersaturation value from float to integer for export [%]
-		convert_GF_for_display();
-
-		// convert CNS value from float to integer for export
-		convert_CNS_for_display();
-	}
-
-	//---- Calculate and Export EAD and END ------------------------------------------------------
-
-	// calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air
-	EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER;
-
-	// calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too
-	// Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott,
-	//               4th edition, 1993, W.B.Saunders Company Ltd, London.
-	END = (real_pres_respiration - ppHe - pres_surface) * BAR_TO_METER;
-
-	// export EAD
-	if( (EAD < 0.0) || (EAD > 245.5) ) char_O_EAD = 0;
-	else                               char_O_EAD = (unsigned char)(EAD + 0.5);
-
-	// export END
-	if( (END < 0.0) || (END > 245.5) ) char_O_END = 0;
-	else                               char_O_END = (unsigned char)(END + 0.5);
-
-
-	//---- Compute ppO2 Values in [cbar] ---------------------------------------------------------
-
-	// pure oxygen ppO2
-	     if ( O2_ppO2       <  0.01  ) int_O_O2_ppO2       =   0;
-	else if ( O2_ppO2       >= 9.995 ) int_O_O2_ppO2       = 999;
-	else                               int_O_O2_ppO2       = (unsigned int)(100 *   O2_ppO2 + 0.5);
-
-	// pure gas ppO2
-	     if ( OC_ppO2       <  0.01  ) int_O_pure_ppO2     =   0;
-	else if ( OC_ppO2       >= 9.995 ) int_O_pure_ppO2     = 999;
-	else                               int_O_pure_ppO2     = (unsigned int)(100 *   OC_ppO2 + 0.5);
-
-	// calculated pSCR ppO2
-	     if ( pSCR_ppO2     <  0.01  ) int_O_pSCR_ppO2     =   0;
-	else if ( pSCR_ppO2     >= 9.995 ) int_O_pSCR_ppO2     = 999;
-	else                               int_O_pSCR_ppO2     = (unsigned int)(100 * pSCR_ppO2 + 0.5);
-
-	// breathed ppO2
-	     if ( ppO2          <  0.01  ) int_O_breathed_ppO2 =   0;
-	else if ( ppO2          >= 9.995 ) int_O_breathed_ppO2 = 999;
-	else                               int_O_breathed_ppO2 = (unsigned int)(100 *      ppO2 + 0.5);
-
-
-	//---- Set/Reset Deco Mode --------------------------------------------------------------------
-
-	// Set the deco mode flag if:
-	// - breathing an OC deco gas (gas type 3), or
-	// - breathing a gas or diluent that officially is disabled (type 0), or
-	// - if nearby or above the deepest deco stop (nearby means 1 meter below, the additional 0.9 serves rounding effects)
-	if  (    ( char_I_current_gas_type == 3                                                                           )
-	      || ( char_I_current_gas_type == 0                                                                           )
-	      || ( (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER - 1.9) < char_O_first_deco_depth )
-		)
-			char_O_deco_info |=  DECO_FLAG;
-	else
-			char_O_deco_info &= ~DECO_FLAG;
-
-
-	//---- Compute ppO2 Warnings ------------------------------------------------------------------
-
-	// compute conditional min/max values
-	int_ppO2_min = (char_O_main_status & DECO_MODE_LOOP) ? (unsigned int)char_I_ppO2_min_loop : (unsigned int)char_I_ppO2_min;
-	int_ppO2_max = (char_O_deco_info   & DECO_FLAG     ) ? (unsigned int)char_I_ppO2_max_deco : (unsigned int)char_I_ppO2_max;
-
-	// get biggest of char_I_ppO2_max / char_I_ppO2_max_deco
-	int_ppO2_max_max = ( char_I_ppO2_max_deco > char_I_ppO2_max ) ? char_I_ppO2_max_deco : char_I_ppO2_max;
-
-	// default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold
-	int_ppO2_max_dil = int_ppO2_max;
-
-	// when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
-	if( (char_O_main_status & DECO_MODE_MASK) == DECO_MODE_CCR )
+		// convert the saturation value of the leading tissue to integer
+		convert_sat_for_display();
+
+		// convert the CNS value to integer
+		convert_cur_CNS_for_display();
+
+	} // tasks every 2 seconds
+
+
+	// Tasks every second, if more than 1 invocation per second: on the first section of the second.
+#if (INVOKES_PER_SECOND > 1)
+	if(    ( sequence_timer == 0                  )
+	    || ( sequence_timer == INVOKES_PER_SECOND )
+	)
+#endif
 	{
-		overlay unsigned int max_dil;
-
-		//  The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
-		// (the condition protects from negative numbers which would cause a wrap-around in unsigned integers)
-		max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned int)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
-
-		// ...but never above int_ppO2_max.
-		if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil;
-
-		// We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
-		// against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
-	}
-
-	// check for safe range of pure oxygen
-	     if ( int_O_O2_ppO2       >=               int_ppO2_max     ) int_O_O2_ppO2       |= INT_FLAG_WARNING + INT_FLAG_HIGH;
-
-	// check for safe range of breathed gas
-	     if ( int_O_breathed_ppO2 <=               int_ppO2_min     ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
-	else if ( int_O_breathed_ppO2 >=               int_ppO2_max_max ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
-	else if ( char_O_deco_info    &                DECO_FLAG        ) ; // no attention generated in deco mode
-	else if ( char_O_main_status  &                DECO_MODE_LOOP   ) ; // no attention generated in loop modes
-	else if ( int_O_breathed_ppO2 >= (unsigned int)char_I_ppO2_max  ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
-
-	// check for safe range of pure diluent
-	     if ( int_O_pure_ppO2     <= (unsigned int)char_I_ppO2_min  ) int_O_pure_ppO2     |= INT_FLAG_WARNING + INT_FLAG_LOW;
-	else if ( int_O_pure_ppO2     >=               int_ppO2_max     ) int_O_pure_ppO2     |= INT_FLAG_WARNING + INT_FLAG_HIGH;
-	else if ( int_O_pure_ppO2     >=               int_ppO2_max_dil ) int_O_pure_ppO2     |= INT_FLAG_ATTENTION;
-
-	// check for safe range of calculated pSCR loop gas
-	     if ( int_O_pSCR_ppO2     <=               int_ppO2_min     ) int_O_pSCR_ppO2     |= INT_FLAG_WARNING + INT_FLAG_LOW;
-	else if ( int_O_pSCR_ppO2     >=               int_ppO2_max     ) int_O_pSCR_ppO2     |= INT_FLAG_WARNING + INT_FLAG_HIGH;
+		//---- Calculate and Export EAD and END ------------------------------------------------------
+
+		// calculate EAD (Equivalent Air Depth): equivalent depth for the same N2 level with plain air
+		EAD = (ppN2 / 0.7902 + ppWater - pres_surface) * BAR_TO_METER;
+
+		// calculate END (Equivalent Narcotic Depth): here O2 is treated as narcotic, too
+		// Source cited: The Physiology and Medicine of Diving by Peter Bennett and David Elliott,
+		//               4th edition, 1993, W.B.Saunders Company Ltd, London.
+		END = (real_pres_respiration - ppHe - pres_surface) * BAR_TO_METER;
+
+		// export EAD
+		float_value = EAD; convert_float_to_char(); char_O_EAD = char_value;
+
+		// export END
+		float_value = END; convert_float_to_char(); char_O_END = char_value;
+
+
+		//---- Compute ppO2 Values in [cbar] ---------------------------------------------------------
+
+		float_value = ppO2;      convert_float_to_int(); int_O_breathed_ppO2 = int_value;	// breathed gas
+#ifdef _ccr_pscr
+		float_value = O2_ppO2;   convert_float_to_int(); int_O_O2_ppO2       = int_value;	// pure oxygen
+		float_value = OC_ppO2;   convert_float_to_int(); int_O_pure_ppO2     = int_value;	// pure gas
+		float_value = pSCR_ppO2; convert_float_to_int(); int_O_pSCR_ppO2     = int_value;	// pSCR calculated
+#endif
+
+
+		//---- Set/Reset Deco Mode --------------------------------------------------------------------
+
+		// Set the deco mode flag if:
+		//     deco mode is not set
+		// AND     breathing an OC deco gas (gas type 3)
+		//     OR  breathing a gas or diluent that officially is disabled (type 0)
+		//     OR  there is a deco stop and we are less deep than 1 meter below the deepest deco stop
+		if (    ( deco_info & DECO_FLAG ) == 0                                                      )
+		if (    ( char_I_current_gas_type == 3                                                      )
+		     || ( char_I_current_gas_type == 0                                                      )
+		     || ( ( char_O_deco_depth[0]   > 0 ) && ( char_depth_real <= char_O_deco_depth[0] + 1 ) )
+		   )
+				deco_info |=  DECO_FLAG;
+
+		// Clear the deco mode flag if:
+		//      deco mode is set
+		// AND  deeper than 7 meters below deepest deco stop (7 meters = 2 stop depth intervals plus 1 meter below stop)
+		if (    ( deco_info   & DECO_FLAG      )  > 0                                               )
+		if (    ( char_depth_real                 > char_O_deco_depth[0] + 7                        )
+		   )
+				deco_info &= ~DECO_FLAG;
+
+
+		//---- Compute ppO2 Warnings ------------------------------------------------------------------
+
+		// compute conditional min values
+#ifdef _ccr_pscr
+		int_ppO2_min = ( main_status & MODE_LOOP ) ? (unsigned short)char_I_ppO2_min_loop : (unsigned short)char_I_ppO2_min;
+#else
+		int_ppO2_min = (unsigned short)char_I_ppO2_min;
+#endif
+
+		// compute conditional max values
+		int_ppO2_max = ( deco_info   & DECO_FLAG ) ? (unsigned short)char_I_ppO2_max_deco : (unsigned short)char_I_ppO2_max_work;
+
+		// add some margin on ppO2 max to compensate for surface pressures > 1.000 mbar
+		int_ppO2_max += ppO2_MARGIN_ON_MAX;
+
+		// get biggest of char_I_ppO2_max_work / char_I_ppO2_max_deco
+		int_ppO2_max_max = ( char_I_ppO2_max_deco > char_I_ppO2_max_work ) ? char_I_ppO2_max_deco : char_I_ppO2_max_work;
+
+#ifdef _ccr_pscr
+		// default value for the upper diluent ppO2 warning threshold is the normal upper warning threshold
+		int_ppO2_max_dil = int_ppO2_max;
+
+		// when in CCR mode, the upper diluent warning threshold gets adjust according to the current setpoint
+		if( (main_status & MODE_MASK) == MODE_CCR )
+		{
+			overlay unsigned short max_dil;
+
+			//  The upper diluent ppO2 threshold is ppO2_GAP_TO_SETPOINT below the setpoint...
+			// (the condition protects from negative numbers which would cause a wrap-around in unsigned integers)
+			max_dil = (char_I_const_ppO2 > ppO2_GAP_TO_SETPOINT) ? (unsigned short)(char_I_const_ppO2 - ppO2_GAP_TO_SETPOINT) : 0;
+
+			// ...but never above int_ppO2_max.
+			if( max_dil < int_ppO2_max ) int_ppO2_max_dil = max_dil;
+
+			// We do not need to guard int_ppO2_max_dil against becoming lower than char_I_ppO2_min because the check
+			// against char_I_ppO2_min is done first and will then raise a low warning and inhibit further checks.
+		}
+#endif
+
+		// check for safe range of breathed gas
+		if      ( int_O_breathed_ppO2 <=                 int_ppO2_min         ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_LOW;
+		else if ( int_O_breathed_ppO2 >=                 int_ppO2_max_max     ) int_O_breathed_ppO2 |= INT_FLAG_WARNING + INT_FLAG_HIGH;
+		else if ( deco_info           &                  DECO_FLAG            ) ; // no attention generated in deco mode
+		else if ( main_status         &                  MODE_LOOP            ) ; // no attention generated in loop modes
+		else if ( int_O_breathed_ppO2 >= (unsigned short)char_I_ppO2_max_work ) int_O_breathed_ppO2 |= INT_FLAG_ATTENTION;
+
+#ifdef _ccr_pscr
+		// check for safe range of pure oxygen
+		if      ( int_O_O2_ppO2       >=                 int_ppO2_max         ) int_O_O2_ppO2       |= INT_FLAG_WARNING + INT_FLAG_HIGH;
+
+		// check for safe range of pure diluent
+		if      ( int_O_pure_ppO2     <= (unsigned short)char_I_ppO2_min      ) int_O_pure_ppO2     |= INT_FLAG_WARNING + INT_FLAG_LOW;
+		else if ( int_O_pure_ppO2     >=                 int_ppO2_max         ) int_O_pure_ppO2     |= INT_FLAG_WARNING + INT_FLAG_HIGH;
+		else if ( int_O_pure_ppO2     >=                 int_ppO2_max_dil     ) int_O_pure_ppO2     |= INT_FLAG_ATTENTION;
+
+		// check for safe range of calculated pSCR loop gas
+		if      ( int_O_pSCR_ppO2     <=                 int_ppO2_min         ) int_O_pSCR_ppO2     |= INT_FLAG_WARNING + INT_FLAG_LOW;
+		else if ( int_O_pSCR_ppO2     >=                 int_ppO2_max         ) int_O_pSCR_ppO2     |= INT_FLAG_WARNING + INT_FLAG_HIGH;
+#endif
+
+	} // tasks every second / on the first section of the second
 
 
 #ifdef _rx_functions
 
-	//---- Process Pressure Readings (OSTC TR only) -----------------------------------------------
-
-	// only for OSTC TR model with TR functions enabled
-	if( char_O_main_status & DECO_TR_FUNCTIONS )
+	// only when TR functions are enabled
+	if( main_status & TR_FUNCTIONS )
+
+	// Tasks every second, if more than 1 invocation per second: on the second section of the second.
+#if (INVOKES_PER_SECOND > 1)
+	if(    ( sequence_timer == 1                      )
+	    || ( sequence_timer == INVOKES_PER_SECOND + 1 )
+	)
+#endif
 	{
-		// pressure warnings for reading 1, but only if enabled and pressure value available
-		if( (char_I_pressure_gas[0] > 0) && !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
-		{
-			overlay unsigned int pressure_value = int_IO_pressure_value[0] & ~INT_FLAG_OUTDATED;
-
-			if( (char_I_pressure_gas[0] < 6 ) && !(int_O_pressure_need[0] & INT_FLAG_NOT_AVAIL) )
-			{
-				// not a dil and need available: warning & attention by need
-				     if( pressure_value <= int_O_pressure_need[0])
-				         int_IO_pressure_value[0] |= INT_FLAG_WARNING;
-				else if( pressure_value <= int_O_pressure_need[0] + int_O_pressure_need[0] / 2 )
-				         int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
-			}
-			else
-			{
-				// a dil or need not available: warning & attention by fixed thresholds
-				if     ( pressure_value <= PRESSURE_LIMIT_WARNING   ) int_IO_pressure_value[0] |= INT_FLAG_WARNING;
-				else if( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
-			}
-		}
-
-		// pressure warnings for reading 2, but only if enabled and pressure value available
-		if( (char_I_pressure_gas[1] > 0) && !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
-		{
-			overlay unsigned int pressure_value = int_IO_pressure_value[1] & ~INT_FLAG_OUTDATED;
-
-			if( (char_I_pressure_gas[1] < 6 ) && !(int_O_pressure_need[1] & INT_FLAG_NOT_AVAIL) )
-			{
-				// not a dil and need available: warning & attention by need
-				     if( pressure_value <= int_O_pressure_need[1])
-				         int_IO_pressure_value[1] |= INT_FLAG_WARNING;
-				else if( pressure_value <= int_O_pressure_need[1] + int_O_pressure_need[1] / 2 )
-				         int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
-			}
-			else
-			{
-				// a dil or need not available: warning & attention by fixed thresholds
-				     if( pressure_value <= PRESSURE_LIMIT_WARNING   ) int_IO_pressure_value[1] |= INT_FLAG_WARNING;
-				else if( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
-			}
-		}
-
-		//--- SAC Calculation ---------------------------------------------------------------------
-		//
-		// char_I_SAC_mode =0: disabled
-		//                 =1: SAC from 1st reading
-		//                 =2: SAC from 2nd reading
-		//                 =3: SAC from higher one of both pressure drops (independent double mode)
-		//                 =4: SAC (O2 usage) from 2nd reading without real_pres_respiration term
-
-		// set SAC rate to not available by default
-		int_O_sac_rate = 0 + INT_FLAG_NOT_AVAIL;
-
-		// get a copy of the current absolute pressure
-		pres_respiration_sac = real_pres_respiration;
-
-		// set threshold for SAC rate attention
-		max_sac_rate = (char_O_deco_info & DECO_FLAG) ? char_I_deco_usage : char_I_bottom_usage;
-
-		// char_I_deco_usage / char_I_bottom_usage are in l/min, max_sac_rate is in 0.1 l/min
-		max_sac_rate *= 10;
-
-
-		// pre-process SAC mode 3 (independent double)
-		if( char_I_SAC_mode == 3 )
-		{
-			overlay unsigned char  reading1_gas;
-			overlay unsigned char  reading2_gas;
-			overlay unsigned char  reading1_tanksize;
-			overlay unsigned char  reading2_tanksize;
-			overlay unsigned short reading1_press;
-			overlay unsigned short reading2_press;
-			overlay unsigned short reading1_drop;
-			overlay unsigned short reading2_drop;
-
-			// get gas numbers (1-10) of both readings
-			reading1_gas = char_I_pressure_gas[0];
-			reading2_gas = char_I_pressure_gas[1];
-
-			// default to no SAC calculation
-			char_I_SAC_mode = 0;
-
-			// clear switch advice by default
-			char_O_deco_info &= ~IND_DOUBLE_SWITCH_FLAG;
-
-			// check if both readings are configured and available
-			if(  reading1_gas                                    )
-			if(  reading2_gas                                    )
-			if( !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
-			if( !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
-			if( !(int_I_pressure_drop[0]   & INT_FLAG_NOT_AVAIL) )
-			if( !(int_I_pressure_drop[1]   & INT_FLAG_NOT_AVAIL) )
-			{
-				// get tank pressures, stripping flags
-				reading1_press = int_IO_pressure_value[0] & 0x0FFF;			// in 0.1 bar
-				reading2_press = int_IO_pressure_value[1] & 0x0FFF;			// in 0.1 bar
-
-				// get pressure drops as integers, stripping flags and shifting right
-				// to avoid an overflow when multiplying with the tank size later on
-				reading1_drop = (int_I_pressure_drop[0] & 0x0FFF) >> 2;
-				reading2_drop = (int_I_pressure_drop[1] & 0x0FFF) >> 2;
-
-				// get tank sizes
-				reading1_tanksize = char_I_tank_size[reading1_gas-1];
-				reading2_tanksize = char_I_tank_size[reading2_gas-1];
-
-				// set mode to calculate SAC on the reading with the higher absolute drop
-				char_I_SAC_mode = (reading1_drop * reading1_tanksize > reading2_drop * reading2_tanksize) ? 1 : 2;
-
-				// compute switch advice if pressure (in 0.1 bar) of tank breathed from is
-				// more than char_I_max_pres_diff (in bar) below pressure of the other tank.
-				if( char_I_SAC_mode == 1 )
-				{
-					// breathing from reading 1, switch advice if pressure on reading 1 lower than on 2
-					if( (reading1_press + 10*char_I_max_pres_diff) <= reading2_press )
-						char_O_deco_info |= IND_DOUBLE_SWITCH_FLAG;
-				}
-				else
-				{
-					// breathing from reading 2, switch advice if pressure on reading 2 lower than on 1
-					if( (reading2_press + 10*char_I_max_pres_diff) <= reading1_press )
-						char_O_deco_info |= IND_DOUBLE_SWITCH_FLAG;
-				}
-			}
-		}
-
-
-		// pre-process SAC mode 4 (O2 usage by reading 2)
-		if( char_I_SAC_mode == 4 )
-		{
-			// O2 usage on CCR is independent from absolute pressure
-			pres_respiration_sac = 1.0;
-
-			// O2 pressure drop is measured via reading 2
-			char_I_SAC_mode = 2;
-
-			// reconfigure max SAC rate to O2 consumption attention threshold
-			max_sac_rate = O2_CONSUMPTION_LIMIT_ATTENTION;
-		}
-
-
-		// calculate SAC - modes 1 & 2
-		if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) )
-		{
-			overlay unsigned char reading_index;
-			overlay unsigned char reading_gas;
-			overlay unsigned char reading_tanksize;
-			overlay float         reading_drop;
-
-			// set index: char_I_SAC_mode = 1 -> reading one, index 0
-			//                            = 2 ->         two,       1
-			reading_index = char_I_SAC_mode - 1;
-
-			// get gas number (1-10)
-			reading_gas = char_I_pressure_gas[reading_index];
-
-			// check if reading is configured and available
-			if(  reading_gas                                               )
-			if( !(int_I_pressure_drop[reading_index] & INT_FLAG_NOT_AVAIL) )
-			{
-				// get tank size (in liter)
-				reading_tanksize = char_I_tank_size[reading_gas-1];
-
-				// get pressure drop as float, stripping flags (in 1/5120 bar/sec)
-				reading_drop = (float)(int_I_pressure_drop[reading_index] & 0x0FFF);
-
-				// check if pressure drop is within range
-				if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUT_OF_RANGE) )
-				{
-					// calculate SAC,   10 is factor to have result in 0.1 liter/min
-					//                  60 is factor for 60 seconds per 1 minute,
-					//                5120 accounts for reading_drop being in 1/5120 bar/sec
-					//                10*60/5120 = 60/512 = 15/128
-					float_sac = reading_drop * 15/128 * reading_tanksize / pres_respiration_sac;
-
-					// limit result to 999 (99.9 liter/min)
-					if ( float_sac >= 998.5 )
-					{
-						int_O_sac_rate = 999 + INT_FLAG_ATTENTION;
-					}
-					else
-					{
-						// convert float to integer
-						int_O_sac_rate = (unsigned short)(float_sac + 0.5);
-
-						// set attention flag if exceeding SAC threshold, but only if pressure drop is not outdated
-						if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED) )
-						if( int_O_sac_rate >= max_sac_rate )
-						{
-							int_O_sac_rate |= INT_FLAG_ATTENTION;
-						}
-					}
-				}
-				else
-				{
-					// pressure drop is out of range, so SAC will be set out of range, too
-					int_O_sac_rate = 999 + INT_FLAG_ATTENTION;
-				}
-
-				// copy outdated flag from int_I_pressure_drop to int_O_sac_rate
-				if( int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED )
-				{
-					int_O_sac_rate |= INT_FLAG_OUTDATED;
-				}
-			}
-		}
-	} // TR functions
-
-#endif
-
-
+		calc_TR_functions();
+	}
+
+#endif // _rx_functions
+
+
+	//
 	//---- End of Computations for the real Tissues -----------------------------------------------
 	//
+
 	//=============================================================================================
+
 	//
-	//---- Begin of Computations for Ascent and Decompression -------------------------------------
-
-	// branch to the code for the current phase the deco calculations are in, i.e.
-	// toggle between calculating NDL (remaining bottom time), deco stops, and results
-	switch( char_O_deco_status & DECO_STATUS_MASK )
+	//---- Begin of Computations for Ascent and Decompression (simulated Tissues) -----------------
+	//
+
+	// Dispatcher: select what to do based on the current calculation phase
+	do
 	{
-		overlay unsigned char i;
-
-	default:
-
-	case DECO_STATUS_INIT: //---- At surface: Start a new dive ---------------------
-
-		// clear the internal stops table from remains lasting from the previous dive or deco calculator run
-		clear_deco_table();
-
-		// publish the cleared stops table to the display functions
-		publish_deco_table();
-
-		// clear the gas needs table
-		for( i = 0; i < NUM_GAS; ++i )
+
+#ifdef _profiling
+		profiling_phase = next_planning_phase;
+#endif
+
+		switch( next_planning_phase )
 		{
-			int_O_ascent_volumes[i]   = 0;
-			int_O_ascent_pres_need[i] = 0 + INT_FLAG_ZERO;
-		}
-
-		// safety limits to prevent eventual infinite looping (bricking the OSTC)
-		if( char_I_ascent_speed            <  5 ) char_I_ascent_speed            =  5;	// min.  5 m/min
-		if( char_I_deco_distance           > 20 ) char_I_deco_distance           = 20;	// max. 20 dm (= 2 m)
-		if( char_I_desaturation_multiplier < 50 ) char_I_desaturation_multiplier = 50;	// min. 50 %
-
-		// initialize values that are constant during the course of the dive
-		float_ascent_speed            = 1.00 * char_I_ascent_speed;						// in meter/minute
-		float_deco_distance           = 0.01 * char_I_deco_distance;					// in bar
-		float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier;			// as factor, 1.0 = 100%
-		float_saturation_multiplier   = 0.01 * char_I_saturation_multiplier;			// as factor, 1.0 = 100%
+
+		//
+		//---- once-per-dive Initialization of the Deco Engine ------------------------------------
+		//
+		case PHASE_10_DIVE_INIT:
+
+		// initialize all output variables to defaults
+		init_output_vars();
+
+		// safeguard input parameters that are constant during the course of the dive
+		if( char_I_deco_distance >  20 ) char_I_deco_distance =  20;
+		if( char_I_ascent_speed  <   5 ) char_I_ascent_speed  =   5;
+		if( char_I_ascent_speed  >  10 ) char_I_ascent_speed  =  10;
+
+		// convert input parameters to float numbers
+		float_deco_distance = 0.01 * char_I_deco_distance;
+		float_ascent_speed  = 1.00 * char_I_ascent_speed;
 
 		// initialize values that will be recalculated later on periodically
-		char_O_nullzeit               = 0;		// reset NDL time for the normal plan
-		char_O_alternate_nullzeit     = 0;		// reset NDL time for the alternative plan
-		int_O_ascenttime              = 0;		// reset ascent time for the normal plan
-		int_O_alternate_ascenttime    = 0;		// reset ascent time for the alternative plan
-		char_O_deco_warnings          = 0;		// reset all deco warnings
-		char_O_deco_info              = 0;		// reset all deco infos
-		deco_tissue_vector            = 0;		// reset tissue deco vector
-		IBCD_tissue_vector            = 0;		// reset tissue IBCD vector
-		NDL_lead_tissue_norm          = 0;		// reset first tissue to look at during NDL calculation
-		NDL_lead_tissue_alt           = 0;		// reset first tissue to look at during NDL calculation
-
-		// tag desaturation time as invalid (it will not be computed during a dive)
-		int_O_desaturation_time       = 65535;
-
-		// initialize values for first stop depth and GF slope
-		low_depth_norm                = 0.0;	// reset depth of first stop in normal      plan
-		locked_GF_step_norm           = 0.0;	// reset GF slope            in normal      plan
-		low_depth_alt                 = 0.0;	// reset depth of first stop in alternative plan
-		locked_GF_step_alt            = 0.0;	// reset GF slope            in alternative plan
-
-		// initialize CNS values
-		int_O_normal_CNS_fraction     = int_O_alternate_CNS_fraction = int_O_CNS_fraction;
+		deco_warnings            = 0;		// reset all deco warnings
+		deco_info                = 0;		// reset all deco infos
+		IBCD_tissue_vector       = 0;		// reset tissue IBCD vector
+		NDL_tissue_start_norm    = 0;		// initialize the tissue to start with when calculating normal      NDL time
+		NDL_tissue_start_alt     = 0;		// initialize the tissue to start with when calculating alternative NDL time
+
+		// enforce initialization of GF data on first cyclic initialization
+		GF_high_last             = 0;
+		GF_low_last              = 0;
+
+
+#ifdef _cave_mode
+		char_I_backtrack_time    = 0;		//clear backtracking time (index to char_I_backtrack_depth)
+		char_I_backtrack_depth   = 0;		//prime first entry with a depth of 0 meter
+#endif
+
+#ifdef _profiling
+		int_O_profiling_overrun_max = 0;
+		char_O_profiling_runs_norm  = 0;
+		char_O_profiling_runs_alt   = 0;
+#endif
+
+
+		// the next calculation phase will do the cyclic initialization of the deco engine if a
+		// normal or alternative plan shall be calculated, else the calculation cycle is done.
+		if( deco_status & PLAN_MASK ) next_planning_phase = PHASE_11_CYCLIC_INIT;
+		else                          next_planning_phase = PHASE_00_DONE;
+
+		break;
+
 
 		//
-		// --> code execution continues in state DECO_STATUS_START
+		//---- once-per-cycle Initialization of the Deco Engine------------------------------------
 		//
-
-	case DECO_STATUS_START: //---- Start a new deco calculation cycle --------------
-
-		// clear the internal(!) stops table
+		case PHASE_11_CYCLIC_INIT:
+
+		// target the simulated tissues (flag bit 7 = 0)
+		tissue_increment = 0;
+
+		// clear the internal stops table
 		clear_deco_table();
 
 		// initialize the simulated tissues with the current state of the real tissues
 		for( i = 0; i < NUM_COMP; i++ )
 		{
-			sim_pres_tissue_N2[i] = pres_tissue_N2[i];
-			sim_pres_tissue_He[i] = pres_tissue_He[i];
-		}
-
-		// initialize the simulated CNS value with the current CNS of the real tissues
-		sim_CNS_fraction = CNS_fraction;
-
-		// initialize the simulated depth with the current depth (in absolute pressure)
-		sim_pres_respiration = real_pres_respiration;
-
-		// Lookup the current gas and store it also as the first gas used.
-		// This gas will be used until gas_find_better() is invoked and finds
-		// a better gas to switch to.
-		gas_find_current();
-
-		// Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio).
-		// These ratios will be used and remain valid to use until a gas switch
-		// is done. Thus, if a call to gas_find_better() has found a better gas,
-		// gas_set_ratios() needs to be called again.
-		gas_set_ratios();
-
-		// Calculate the effect of extended bottom time due to delayed ascent,
-		// if requested.
-		if( char_O_deco_status & DECO_ASCENT_DELAYED )
-		{
-			// program interval on simulated tissues (flag bit 7 = 0)
-			tissue_increment = char_I_extra_time;
-
-			// calculate ppO2, ppN2 and ppHe from sim_N2/real_He_ratio
-			calc_alveolar_pressures();
-
-			// update the tissues
-			calc_tissues();
-
-			// update the CNS value
-			calc_CNS();
-		}
-
-		// Calculate the remaining no decompression limit (NDL) time. calc_NDL_time()
-		// is very fast in detecting if being beyond NDL, so there is enough time left
-		// in this phase to do the initial ascent calculation if found to be outside NDL.
-		calc_NDL_time();
-
-		if( NDL_time == 0 )
-		{
-			// calculate ascent to first stop using the set ascent rate,
-			// re-calculating the tissues and limits every minute along the ascent.
-			calc_ascent_to_first_stop();
-
-			// continue in next cycle(s) with calculating the initial ascent and stops
-			char_O_deco_status &= ~DECO_STATUS_MASK;
-			char_O_deco_status |=  DECO_STATUS_STOPS;
-		}
-		else
-		{
-			// within NDL - continue in next cycle with gathering all results
-			char_O_deco_status &= ~DECO_STATUS_MASK;
-			char_O_deco_status |=  DECO_STATUS_RESULTS;
+			sim_pres_tissue_N2[i] = real_pres_tissue_N2[i];
+			sim_pres_tissue_He[i] = real_pres_tissue_He[i];
 		}
 
-		break;
-
-
-	case DECO_STATUS_STOPS: //---- Calculate Stops ---------------------------------
-
-		// calculate the stops
-		calc_hauptroutine_calc_deco();
-
-		// calc_hauptroutine_calc_deco() iterates in this phase as long as it is
-		// calculating the stops. Once done, it will set the status to doing the
-		// results gathering.
-
-		break;
-
-
-	case DECO_STATUS_RESULTS: //--- Gather Results ---------------------------------
-
-		// if in normal plan, publish the stops table
-		if( !(char_O_deco_status & DECO_PLAN_ALTERNATE) )
+		// initialize GF parameters if using GF model
+		if( char_I_deco_model != 0 )
 		{
-			// publish the stops table to the display functions
-			publish_deco_table();
-
-			// When entering deco and the ceiling depth becomes > 0 but the
-			// deco calculation reveals no distinct deco stop yet because
-			// the deco obligation will vanish during the ascent, create an
-			// artificial stop to signal that expedite surfacing ("popping
-			// up") is not allowed anymore.
-			if( char_O_first_deco_depth == 0 )		// simulation  reveals no stop required
-			if( int_O_ceiling           >  0 )		// real status reveals a ceiling
+			// update GF parameters (GFs may have been switched between GF and aGF)
+			if( (char_I_GF_High_percentage != GF_high_last) || (char_I_GF_Low_percentage != GF_low_last) )
 			{
-				// set a pro forma stop at 3 meters
-				char_O_first_deco_depth = 3;
-
-				// set a stop time of 0 minute, this will be displayed as "..'"
-				char_O_first_deco_time  = 0;
+				// store new values in integer format
+				GF_high_last = char_I_GF_High_percentage;
+				GF_low_last  = char_I_GF_Low_percentage;
+
+				// store new values in float format
+				GF_high  = 0.01 * char_I_GF_High_percentage;
+				GF_low   = 0.01 * char_I_GF_Low_percentage;
+
+				// reset low depth references and slopes
+				GF_low_depth_norm = 0;
+				GF_low_depth_alt  = 0;
+				GF_slope_norm     = 0.0;
+				GF_slope_alt      = 0.0;
 			}
-		}
-
-		// The current depth is needed by calc_ascenttime() and gas_volumes(). As we
-		// don't want it to be calculated multiple times, it's done here on stockpile.
-		char_bottom_depth = (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER + 0.5);
-
-		// results to publish depend whether within NDL or in deco
-		if( NDL_time )
-		{
-			//---- within NDL ----------------------------------------------
-
-			// check which plan we are on
-			if( char_O_deco_status & DECO_PLAN_ALTERNATE )
+
+			// retrieve GF parameters for current calculation cycle
+			if( deco_status & CALC_NORM )
 			{
-				//---- alternate dive plan ---------------------------------
-
-				// output NDL time
-				char_O_alternate_nullzeit  = NDL_time;
-
-				// clear ascent time
-				int_O_alternate_ascenttime = 0;
-
-				// As we are in no stop, CNS at end of dive is more or less
-				// the same CNS as we have right now.
-				int_O_alternate_CNS_fraction = int_O_CNS_fraction;
+				GF_low_depth = GF_low_depth_norm;
+				GF_slope     = GF_slope_norm;
 			}
 			else
 			{
-				//---- normal dive plan ------------------------------------
-
-				// output NDL time
-				char_O_nullzeit = NDL_time;
-
-				// clear ascent time
-				int_O_ascenttime = 0;
-
-				// As we are in no stop, CNS at end of dive is more or less
-				// the same CNS as we have right now.
-				int_O_normal_CNS_fraction = int_O_CNS_fraction;
+				GF_low_depth = GF_low_depth_alt;
+				GF_slope     = GF_slope_alt;
 			}
-		} // NDL
-		else
-		{
-			//---- in DECO -------------------------------------------------
-
-			// calculate the ascent time
-			calc_ascenttime();
-
-			// check which plan we are on
-			if( char_O_deco_status & DECO_PLAN_ALTERNATE )
-			{
-				//---- alternative plan ----------------------------------------------------
-
-				// clear the NDL time
-				char_O_alternate_nullzeit = 0;
-
-				// export the ascent time
-				int_O_alternate_ascenttime = ascent_time;
-
-				// convert the CNS value to integer for export
-				convert_sim_CNS_for_display();
-
-				// export the integer CNS value
-				int_O_alternate_CNS_fraction = int_sim_CNS_fraction;
-
-			} // alternative plan
-			else
-			{
-				//---- normal plan ---------------------------------------------------------
-
-				// clear the NDL time
-				char_O_nullzeit  = 0;
-
-				// export the ascent time
-				int_O_ascenttime = ascent_time;
-
-				// convert the CNS value to integer for export
-				convert_sim_CNS_for_display();
-
-				// export the integer CNS value
-				int_O_normal_CNS_fraction = int_sim_CNS_fraction;
-
-			} // normal plan
-		} // NDL / DECO
-
-
-		// Check if deco obligation is steady or decreasing. This works only when an alternative plan is enabled and
-		// if it is not a bailout plan, thus DECO_BAILOUT_MODE must not be set while doing the DECO_PLAN_ALTERNATE.
-		if( (char_O_deco_status & DECO_PLAN_ALTERNATE) && !(char_O_deco_status & DECO_BAILOUT_MODE) )
-		{
-			// Set DECO_DECREASING flag when fTTS < TTS and DECO_STEADY flag when fTTS = TTS.
-			     if ( int_O_alternate_ascenttime <  int_O_ascenttime ) char_O_deco_info |= DECO_DECREASING;
-			else if ( int_O_alternate_ascenttime == int_O_ascenttime ) char_O_deco_info |= DECO_STEADY;
 		}
 
-		// Clear DECO_DECREASING flag when fTTS >= TTS and DECO_STEADY flag when fTTS > TTS.
-		// This works in any planning mode combination.
-		     if ( int_O_alternate_ascenttime >  int_O_ascenttime ) char_O_deco_info &= ~(DECO_DECREASING + DECO_STEADY);
-		else if ( int_O_alternate_ascenttime == int_O_ascenttime ) char_O_deco_info &= ~(DECO_DECREASING              );
-
-		// If requested, calculate the required gas volumes and tank pressures at the end of the dive.
-		if( char_O_deco_status & DECO_VOLUME_CALCULATE )
-		{
-			// When in bailout mode and within NDL, find the gas changes along the ascent and put
-			// them into the stops table for use by gas_volumes(). The stops table can be "polluted"
-			// by now because the table has already been published in "clean" state before.
-			if( (NDL_time) && ( char_O_deco_status & DECO_BAILOUT_MODE ) )
-			{
-				// find the gas changes and put them into the stops table
-				find_NDL_gas_changes();
-			}
-
-			// calculate the required gas volumes and tank pressures
-			gas_volumes();
-		}
-
-		// set the computation cycle to finished
-		char_O_deco_status &= ~DECO_STATUS_MASK;
-
-		// set flag indicating that deco calculation has been completed
-		if( char_O_deco_status & DECO_PLAN_ALTERNATE ) char_O_main_status |= DECO_COMPLETED_ALT;
-		else                                           char_O_main_status |= DECO_COMPLETED_NORM;
-
+		// initialize the simulated CNS value with the current CNS value of the real tissues
+		CNS_fraction_sim = CNS_fraction_real;
+
+		// initialize the simulated depth with the current depth (in absolute pressure)
+		sim_pres_respiration = real_pres_respiration;
+
+		// compute the depth in meters where we are now
+		float_depth_real = (sim_pres_respiration - pres_surface) * BAR_TO_METER;
+
+		// convert to integer and round up to next full meter
+		char_depth_real = (unsigned char)(float_depth_real + 0.99);
+
+		// initialize depth for deco ascent calculation
+		char_depth_sim = char_depth_real;
+
+		// Lookup the gas that is currently breathed with the real tissues and set it as
+		// the gas to be used with the simulated tissues, too. This gas will be used until
+		// gas_find_better() is invoked and finds a better gas to switch to.
+		gas_find_current();
+
+		// Setup the calculation ratio's for N2, He and O2 (sim_N2/He/_O2_ratio). These ratios
+		// can be kept until a gas switch is done. Thus, if a call to gas_find_better() has
+		// found a better gas and initiated a switch, gas_set_ratios() needs to be called again.
+		gas_set_ratios();
+
+		// compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration
+		calc_alveolar_pressures();
+
+		// initialize the no decompression limit (NDL) time to 240 minutes
+		NDL_time = 240;
+
+		// retrieve the tissue that had the shortest NDL time during last calculation
+		NDL_tissue_start = ( deco_status & CALC_NORM ) ? NDL_tissue_start_norm : NDL_tissue_start_alt;
+
+		// start calculating NDL time with the tissue that had the shortest NDL last time
+		NDL_tissue      = NDL_tissue_start;
+		NDL_tissue_lead = NDL_tissue_start;
+
+		// initialization for calculating the initial ascent
+		// start with 1 minute ascent steps when calculating the initial ascent
+		fast = 1;
+
+		// initialization for calc_gas_needs_ascent()
+		gas_needs_next_phase = GAS_NEEDS_INIT;
+
+		// initialization for convert_gas_needs_to_press()
+		gas_needs_gas_index  = 0;
+
+
+#ifdef _profiling
+		profiling_runs = 0;
+#endif
+
+		// The next calculation phase will
+		// - calculate the bottom segment if extended bottom time is configured (fTTS),
+		// - proceed with calculating the NDL time else.
+		if   ( deco_status & DELAYED_ASCENT ) next_planning_phase = PHASE_20_EXTENDED_BOTTOM_TIME;
+		else                                  next_planning_phase = PHASE_30_NDL_TIME;
+
+		break;
+
+
+		//
+		//---- extended Bottom Time ---------------------------------------------------------------
+		//
+		case PHASE_20_EXTENDED_BOTTOM_TIME:
+
+		// program interval on simulated tissues (flag bit 7 = 0)
+		tissue_increment = char_I_extra_time;
+
+		// calculate ppO2, ppN2 and ppHe
+		calc_alveolar_pressures();
+
+		// update the tissues
+		calc_tissues();
+
+		// update the CNS value
+		calc_CNS();
+
+		// the next calculation phase will calculate the NDL time
+		next_planning_phase = PHASE_30_NDL_TIME;
 
 		break;
 
-	} // switch
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// calc_hauptroutine_data_input
-//
-// Set all C-code dive parameters from their ASM-code values.
-// Detect gas change condition.
-//
-void calc_hauptroutine_data_input(void)
-{
-	overlay float IG_ratio;
-
-	// safety limits to prevent eventual infinite looping (bricking the OSTC)
-	if( int_I_pres_surface     < 500) int_I_pres_surface     = 500;		// min. surface     pressure = 500 mbar
-	if( int_I_pres_respiration < 500) int_I_pres_respiration = 500;		// min. respiration pressure = 500 mbar
-
-	// safe-guard further parameters to protect the tissue-flag
-	if( char_I_sim_advance_time > 127 ) char_I_sim_advance_time = 127;
-	if( char_I_extra_time       > 127 ) char_I_extra_time       = 127;
-	if( char_I_gas_change_time  >  99 ) char_I_gas_change_time  =  99;
-
-	// get the current pressures
-	pres_surface          = 0.001  * int_I_pres_surface;
-	real_pres_respiration = 0.001  * int_I_pres_respiration;
-
-	// N2 tissue pressure at surface equilibrium, used for tissue graphics scaling
-	N2_equilibrium   = 0.7902 * (pres_surface - ppWater);
-
-	// read the GF settings (they may have been switch between GF/aGF)
-	GF_high  = 0.01 * char_I_GF_High_percentage;
-	GF_low   = 0.01 * char_I_GF_Low_percentage;
-	GF_delta = GF_high - GF_low;
-
-	// get the currently breathed gas mixture
-	real_O2_ratio = 0.01 * char_I_O2_ratio;
-	real_He_ratio = 0.01 * char_I_He_ratio;
-
-	// inert gas ratio (local helper variable)
-	IG_ratio = 1.00 - real_O2_ratio;
-
-	// N2 ratio
-	real_N2_ratio  = IG_ratio - real_He_ratio;
-
-	// compute values for ppO2 drop in pSCR loop
-	real_pSCR_drop = IG_ratio * float_pSCR_factor;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-// Compute stops
-//
-// Note: because this can be very long, break on 16 iterations, or after
-//       512 ms, whichever comes first. Set state to DECO_STATUS_RESULTS
-//       when finished, or keep DECO_STATUS_STOPS when needing to continue.
-//
-void calc_hauptroutine_calc_deco(void)
-{
-	overlay unsigned char loop;
-
-	for( loop = 0; loop < 16; ++loop )
-	{
-		// limit execution time to 512 ms using timer 5
-		if( tmr5() & (512*32) ) break;
-
-		// calc_nextdecodepth()
+
+		//
+		//---- NDL Time ---------------------------------------------------------------------------
+		//
+		case PHASE_30_NDL_TIME:
+
+		// Calculate the remaining no decompression limit (NDL) time for the tissue NDL_tissue.
+		// NDL_time will be updated if the NDL time found is shorter than the current NDL_time.
+		//
+		// In the initialization phase of the calculation cycle:
+		// - NDL_time      had been initialized to 240 (minutes),
+		// - NDL_tissue    had been initialized to the tissue with
+		//                 the shortest NDL time in the last cycle.
+		//
+		calc_NDL_time_tissue();
+
+		// advance to next tissue, wrapping around after last tissue
+		NDL_tissue = (NDL_tissue + 1) & (NUM_COMP - 1);
+
+		// did we run out of NDL time or did we have probed all tissues?
+		if( (NDL_time == 0) || (NDL_tissue == NDL_tissue_start) )
+		{
+			// YES
+
+			// set the tissue with the shortest NDL time found as
+			// the one to start with in the next calculation cycle
+			if( deco_status & CALC_NORM ) NDL_tissue_start_norm = NDL_tissue_lead;
+			else                          NDL_tissue_start_alt  = NDL_tissue_lead;
+
+			// done with calculating NDL time, set next calculation phase:
+			// - calculate return and ascent in cave mode if configured, else
+			// - proceed with gathering the results if within NDL time, or
+			// - proceed with the initial ascent    if beyond NDL time.
+#ifdef _cave_mode
+			if   ( main_status & CAVE_MODE ) next_planning_phase = PHASE_40_CAVE_ASCENT;
+			else
+#endif
+			if   ( NDL_time                ) next_planning_phase = PHASE_70_RESULTS;
+			else                             next_planning_phase = PHASE_60_DECO_ASCENT;
+		}
+
+		break;
+
+
+#ifdef _cave_mode
+		//
+		//---- Cave Mode Return/Ascent ------------------------------------------------------------
 		//
-		// INPUT  sim_pres_respiration : current depth in absolute pressure
-		// OUTPUT sim_depth_limit      : depth of next stop in meters      (if RETURN = true)
-		//                               next depth without need of a stop (if RETURN = false)
-		// RETURN true if a stop is needed, else false
+		case PHASE_40_CAVE_ASCENT:
+
+		// TODO
+
+		// the next calculation phase will gather all results
+		next_planning_phase = PHASE_70_RESULTS;
+
+		break;
+#endif
+
+
 		//
-		// The function manages gas changes by itself, including priming
-		// the deco stop with the configured gas change time.
+		//---- Open Water Ascent with Deco Stops --------------------------------------------------
 		//
-		if( calc_nextdecodepth() )
+		case PHASE_60_DECO_ASCENT:
+
+		// program 1 minute interval on simulated tissues
+		tissue_increment = 1;
+
+		// ascent to the next stop depth or the depth that is reachable within one minute of ascent
+		// and decide if a stop is required (return value = 1/true) or not (return value = 0/false)
+		if( find_next_stop() )
 		{
-			// this check should not be needed as in this case the RETURN value will be false
-			if( sim_depth_limit == 0 ) goto Surface;
-
-			//---- stop required at sim_depth_limit ----------------------
-
-			// convert stop depth in meters to absolute pressure
-			sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface;
-
-			// Add one minute to the current stop, or add a new stop,
-			// or abort deco calculation if the deco table is full.
-			if( !update_deco_table(1) ) goto Surface;
+			//---- stop required --------------------
+
+			// check if there is a better gas to switch to
+			if( gas_find_better() )
+			{
+				// set the new calculation ratios for N2, He and O2
+				gas_set_ratios();
+
+				// doing extended stops?
+				if( main_status & EXTENDED_STOPS )
+				{
+					// YES - set char_depth_sim to the gas change depth
+					char_depth_sim = sim_gas_current_depth;
+
+					//     - adjust absolute pressure down to the change depth
+					sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface;
+				}
+
+				// prime the deco stop with the gas change time
+				update_deco_table(char_I_gas_change_time);
+			}
+
+			// add one minute to an existing stop or add a new stop at char_depth_sim,
+			// or abort stops calculation if the deco table is full
+			if( !update_deco_table(1) ) next_planning_phase = PHASE_70_RESULTS;
 		}
 		else
 		{
-			//---- no stop required --------------------------------------
-
-			// convert next depth (without stop requirement) to absolute pressure
-			sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface;
-
-			// finish deco calculation if surface is reached
-			if( sim_pres_respiration <= pres_surface )
+			//---- no stop required -----------------
+
+			// check if there is a better gas to switch to, but only:
+			//
+			//     if extended stops are activated,
+			// OR  if in bailout mode.
+			//
+			// Attention: do not use a && formula over both 'if' terms, the extended stops / bailout
+			//            condition must be checked before a call to gas_find_better() is made!
+			//
+			if( (main_status & EXTENDED_STOPS) || (deco_status & BAILOUT_MODE) )
+			if( gas_find_better() )
 			{
-Surface:
-				// continue with gathering all results in the next calculation phase
-				char_O_deco_status &= ~DECO_STATUS_MASK;
-				char_O_deco_status |=  DECO_STATUS_RESULTS;
-
-				return;
+				// set the new calculation values for N2, He and O2
+				gas_set_ratios();
+
+				// stop duration is the gas change time, a change time of 0 minutes
+				// will set a tissue calculation interval of 2 seconds
+				tissue_increment += char_I_gas_change_time;
+
+				// set char_depth_sim to the gas change depth, but not deeper than
+				// the depth we came from.
+				// (char_depth_last holds the depth from before the ascent step)
+				char_depth_sim = (sim_gas_current_depth < char_depth_last) ? sim_gas_current_depth : char_depth_last;
+
+				// adjust sim_pres_respiration to the adjusted value of char_depth_sim
+				sim_pres_respiration = char_depth_sim * METER_TO_BAR + pres_surface;
+
+				// create a stop for the gas change in the stops table
+				update_deco_table(char_I_gas_change_time);
 			}
 		}
 
-		//---- as one minute as passed now, update the tissues -----------
-
-		// program 1 minute interval on simulated tissues
-		tissue_increment = 1;
+		//---- one minute has passed by now, update the tissues ----------------
 
 		// compute current ppO2, ppN2 and ppHe
 		calc_alveolar_pressures();
@@ -2386,23 +2691,360 @@
 
 		// update the CNS value
 		calc_CNS();
+
+		// finish stops calculation if the surface is reached
+		if( char_depth_sim == 0 ) next_planning_phase = PHASE_70_RESULTS;
+
+		break;
+
+
+		///
+		//--- Results - Initialization ------------------------------------------------------------
+		//
+		case PHASE_70_RESULTS:
+
+		// The current depth is needed by calc_ascenttime(), find_NDL_gas_changes() and
+		// calc_gas_needs_ascent(). As we don't want it to be calculated multiple times,
+		// it is done here on stockpile.
+		char_depth_bottom = (unsigned char)((real_pres_respiration - pres_surface) * BAR_TO_METER + 0.5);
+
+		// The next calculation phase will
+		// - publish the stops table if in normal plan mode,
+		// - proceed with remaining results dependent on if within NDL, or
+		// - in deco
+		if      ( deco_status & CALC_NORM ) next_planning_phase = PHASE_71_RESULTS_STOPS_TABLE;
+		else if ( NDL_time                ) next_planning_phase = PHASE_72_RESULTS_NDL;
+		else                                next_planning_phase = PHASE_73_RESULTS_DECO;
+
+		break;
+
+
+		///
+		//--- Publish Stops Table -----------------------------------------------------------------
+		//
+		case PHASE_71_RESULTS_STOPS_TABLE:
+
+		// publish the stops table to the display functions
+		publish_deco_table();
+
+		// When entering deco and the ceiling depth becomes > 0 but the
+		// deco calculation reveals no distinct deco stop yet because
+		// the deco obligation will vanish during the ascent, create an
+		// artificial stop to signal that expedite surfacing ("popping
+		// up") is not allowed anymore.
+		if( char_O_deco_depth[0] == 0 )	// simulated ascent reveals no required stops
+		if( int_O_ceiling        >  0 )	// real tissues have a ceiling
+		{
+			// set a pro forma stop at the configured last stop depth
+			char_O_deco_depth[0] = char_I_depth_last_deco;
+
+			// set a stop time of 0 minutes, this will be displayed as "..'"
+			char_O_deco_time[0]  = 0;
+		}
+
+		// update deco info vector
+		if( char_O_deco_depth[0] ) deco_info |=  DECO_STOPS;		// set flag for deco stops found
+		else                       deco_info &= ~DECO_STOPS;		// clear flag for deco stops found
+
+		// The next calculation phase will publish the main results dependent on being
+		// - within NDL,
+		// - in deco.
+		if   ( NDL_time ) next_planning_phase = PHASE_72_RESULTS_NDL;
+		else              next_planning_phase = PHASE_73_RESULTS_DECO;
+
+		break;
+
+
+		///
+		//--- Results - within NDL ----------------------------------------------------------------
+		//
+		case PHASE_72_RESULTS_NDL:
+
+		// results to publish depend on normal or alternative plan
+		if( deco_status & CALC_NORM )
+		{
+			// output the NDL time
+			char_O_NDL_norm = NDL_time;
+
+			// clear the normal ascent time
+			int_O_TTS_norm  = 0;
+
+			// as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now
+			int_O_CNS_norm  = int_O_CNS_current;
+		}
+		else
+		{
+			// output the NDL time
+			char_O_NDL_alt = NDL_time;
+
+			// clear the alternative ascent time
+			int_O_TTS_alt  = 0;
+
+			// as we are in no stop, CNS at end of dive is more or less the same CNS as we have right now
+			int_O_CNS_alt  = int_O_CNS_current;
+		}
+
+		// The next calculation phase will
+		// - finish the calculation cycle if no gas needs calculation configured, else
+		// - find gas switches when in bailout mode (we are in NDL), or
+		// - calculate the gas needs along the ascent
+		if      ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH;
+		else if (  (deco_status & BAILOUT_MODE) ) next_planning_phase = PHASE_80_GAS_NEEDS_SWITCHES;
+		else                                      next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT;
+
+		break;
+
+
+		///
+		//--- Results - in Deco -------------------------------------------------------------------
+		//
+		case PHASE_73_RESULTS_DECO:
+
+		// calculate the ascent time
+		calc_ascenttime();
+
+		// convert the CNS value to integer
+		convert_sim_CNS_for_display();
+
+		// results to publish depend on normal or alternative plan
+		if( deco_status & CALC_NORM )
+		{
+			// clear the normal NDL time
+			char_O_NDL_norm = 0;
+
+			// export the ascent time
+			int_O_TTS_norm  = ascent_time;
+
+			// export the integer CNS value
+			int_O_CNS_norm  = int_sim_CNS_fraction;
+		}
+		else
+		{
+			// clear the alternative NDL time
+			char_O_NDL_alt  = 0;
+
+			// export the ascent time
+			int_O_TTS_alt   = ascent_time;
+
+			// export the integer CNS value
+			int_O_CNS_alt   = int_sim_CNS_fraction;
+		}
+
+		// The next calculation phase will
+		// - finish the calculation cycle if no gas needs calculation configured, else
+		// - calculate the gas needs along the ascent
+		if      ( !(main_status & CALC_VOLUME ) ) next_planning_phase = PHASE_90_FINISH;
+		else                                      next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT;
+
+		break;
+
+
+		//
+		//--- Gas Needs - Switches ----------------------------------------------------------------
+		//
+		case PHASE_80_GAS_NEEDS_SWITCHES:
+
+		// When in bailout mode and within NDL, find the gas switches along the ascent and put
+		// them into the stops table. The stops table can be "polluted" by now because the table
+		// has already been published in "clean" state before.
+		find_NDL_gas_changes();
+
+		// the next calculation phase will calculate the gas needs along the ascent
+		next_planning_phase = PHASE_81_GAS_NEEDS_ASCENT;
+
+		break;
+
+
+		//
+		//--- Gas Needs - calculate Ascent Needs using Data from Stop Table -----------------------
+		//
+		case PHASE_81_GAS_NEEDS_ASCENT:
+
+		// calculate the gas needs along the ascent
+		calc_gas_needs_ascent();
+
+		// if calculation has finished, advance to next calculation phase
+		if( gas_needs_next_phase == GAS_NEEDS_DONE ) next_planning_phase = PHASE_82_GAS_NEEDS_PRESSURES;
+
+		break;
+
+
+		//
+		//--- Gas Needs - convert Volumes to Pressures --------------------------------------------
+		//
+		case PHASE_82_GAS_NEEDS_PRESSURES:
+
+		// convert required volume of the gas pointed to by gas_needs_gas_index
+		// into the respective pressure and set the flags
+		convert_gas_needs_to_press();
+
+		// increment index to address next gas
+		gas_needs_gas_index++;
+
+		// if all gases have been converted, advance to next calculation phase
+		if( gas_needs_gas_index == NUM_GAS ) next_planning_phase = PHASE_90_FINISH;
+
+		break;
+
+
+		//
+		//--- finish Calculation Cycle ------------------------------------------------------------
+		//
+		case PHASE_90_FINISH:
+
+		// Check if deco obligation is steady state or decreasing.
+		// This works only when an alternative plan is enabled and if it is not a bailout plan,
+		// thus BAILOUT_MODE must not be set while doing the alternative plan.
+		if( (deco_status & CALC_ALT) && !(deco_status & BAILOUT_MODE) )
+		{
+			if   ( int_O_TTS_alt <= int_O_TTS_norm ) deco_info |=  DECO_ZONE;
+			else                                     deco_info &= ~DECO_ZONE;
+		}
+
+		// export updated deco infos and warnings
+		char_O_deco_info     = deco_info;
+		char_O_deco_warnings = deco_warnings;
+
+		// restore command flag to indicate that deco calculation cycle has finished
+		char_O_deco_status   = deco_status;
+
+		// signal end of deco calculation
+		next_planning_phase = PHASE_00_DONE;
+
+		break;
+
+		} // switch
+
+		// read timer 5, result will be stored in tmr5_value (in 1/32 ms) and tmr5_overflow
+		read_tmr5();
+
+	} // sequence calculation phases while not timed out and calculation cycle is not finished
+	while( (tmr5_overflow == 0) && ( next_planning_phase != PHASE_00_DONE ) );
+
+	// report where we are in terms of depth reached, used in deco calculator to show deco calculation progress
+	char_O_depth_sim = char_depth_sim;
+
+
+#ifdef _profiling
+
+	//---- Performance Measurement -------------------------------------------
+
+	// convert timer 5 readout into ms
+	profiling_runtime = tmr5_value / 32;
+
+	// actual runtime longer than target runtime?
+	if( tmr5_overflow )
+	{
+		// YES - report excess
+		int_O_profiling_overrun = profiling_runtime;
+
+		//     - excess > max we had so far?
+		if( int_O_profiling_overrun > int_O_profiling_overrun_max )
+		{
+			// YES - update max
+			int_O_profiling_overrun_max    = int_O_profiling_overrun;
+
+			//     - store the causing phase
+			char_O_profiling_overrun_phase = profiling_phase;
+		}
 	}
+	else
+	{
+		// NO - calculate unused budget and flag it to be under-run time
+		int_O_profiling_overrun = (2048 - profiling_runtime) | 0x8000;
+	}
+
+	// increment number of runs in current cycle
+	profiling_runs += 1;
+
+	// planning cycle completed?
+	if( next_planning_phase == PHASE_00_DONE )
+	{
+		// YES - export number of runs it took
+		if( deco_status & COMPLETED_NORM ) char_O_profiling_runs_norm = profiling_runs;
+		else                               char_O_profiling_runs_alt  = profiling_runs;
+	}
+
+#endif
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// calc_hauptroutine_data_input
+//
+// Set all C-code dive parameters from their ASM-code values.
+//
+void calc_hauptroutine_data_input(void)
+{
+	overlay float IG_ratio;
+
+	// safeguard and convert the surface pressure (mbar -> bar) (*)
+	if( int_I_pres_surface     < 500 ) pres_surface          = 0.500;
+	else                               pres_surface          = 0.001 * int_I_pres_surface;
+
+	// safeguard and convert the current real pressure
+	if( int_I_pres_respiration < 500 ) real_pres_respiration = 0.500;
+	else                               real_pres_respiration = 0.001 * int_I_pres_respiration;
+
+	// safeguard further parameters to protect the tissue-flag and the stop table
+	if( char_I_sim_advance_time > 127 ) char_I_sim_advance_time = 127;
+	if( char_I_extra_time       > 127 ) char_I_extra_time       = 127;
+	if( char_I_gas_change_time  >  99 ) char_I_gas_change_time  =  99;
+
+	// calculate partial pressure of N2 in respired air at surface pressure
+	calc_N2_equilibrium();
+
+	// get, safeguard and convert the saturation and desaturation factors
+	get_saturation_factors();
+
+#ifdef _ccr_pscr
+	// compute a factor that will be used later on for pSCR ppO2 drop calculation (*)
+	float_pSCR_factor = 0.01 * char_I_PSCR_drop * char_I_PSCR_lungratio;
+#endif
+
+#ifdef _helium
+	// get the currently breathed gas ratios
+	real_O2_ratio = 0.01 * char_I_O2_ratio;
+	real_He_ratio = 0.01 * char_I_He_ratio;
+
+	// calculate the inert gas ratio (local helper variable)
+	IG_ratio = 1.00 - real_O2_ratio;
+
+	// calculate the N2 ratio
+	real_N2_ratio  = IG_ratio - real_He_ratio;
+#else
+	// get the currently breathed O2 ratio
+	real_O2_ratio = 0.01 * char_I_O2_ratio;
+
+	// set the He ratio to zero
+	real_He_ratio = 0.0;
+
+	// calculate the N2 / inert gas ratio
+	real_N2_ratio = IG_ratio = 1.00 - real_O2_ratio;
+#endif	// _helium
+
+#ifdef _ccr_pscr
+	// calculate ppO2 drop in pSCR loop for real tissues
+	real_pSCR_drop = IG_ratio * float_pSCR_factor;
+#endif
+
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 // Find gas changes on an NDL ascent
 //
-// This function is a variant of calc_ascent_to_first_stop() to be used solely
-// for finding the gas changes in an OC bailout ascent that is within NDL.
-//
-// Input    : char_bottom_depth : depth at which the ascent starts, in meters
-//
-// Output   : gas change stops put into stops table
-//
-// Destroyed: sim_depth_limit
-//            sim_gas_current
-//            sim_gas_current_depth
+// This function is used for finding the gas changes in an OC bailout ascent
+// that is within NDL.
+//
+// Input:     char_depth_bottom       depth at which the ascent starts, in meters
+//
+// Output:    gas change stops put into stops table
+//
+// Destroyed: char_depth_sim
+//            sim_gas_current_num     number of current gas
+//            sim_gas_current_depth   change depth of current gas
 //
 void find_NDL_gas_changes(void)
 {
@@ -2412,20 +3054,20 @@
 	gas_find_current();
 
 	// loop in ascending until reaching a depth of 3 meters, no gas switches considered thereafter
-	for( sim_depth_limit = char_bottom_depth; sim_depth_limit >= 3; )
+	for( char_depth_sim = char_depth_bottom; char_depth_sim >= 3; )
 	{
 		// memorize the depth we came from
-		old_depth_limit = sim_depth_limit;
+		old_depth_limit = char_depth_sim;
 
 		// ascent - initially in steps of 10 m, then slowing down to 1 m steps to not miss a O2 gas
-		if( sim_depth_limit > 10 ) sim_depth_limit -= 10;
-		else                       sim_depth_limit -=  1;
+		if   ( char_depth_sim > 10 ) char_depth_sim -= 10;
+		else                         char_depth_sim -=  1;
 
 		// check if there is a better gas to switch to
 		if( gas_find_better() )
 		{
-			// adjust sim_depth_limit to the gas change depth, but not deeper than the depth we came from
-			sim_depth_limit = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
+			// adjust char_depth_sim to the gas change depth, but not deeper than the depth we came from
+			char_depth_sim = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
 
 			// create a stop for the gas change in the stops table
 			update_deco_table(char_I_gas_change_time);
@@ -2435,139 +3077,29 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// Calculate ascent to first deco stop
-//
-// Modified : sim_pres_respiration : current depth in ascent and deco simulation, in bar absolute pressure
-//
-// Output   : sim_depth_limit      : depth in meters of the 1st stop, if a stop is found
-//
-// Destroyed: tissue_increment     : tissue and update period selector
-//
-void calc_ascent_to_first_stop(void)
-{
-	overlay float         old_pres_respiration;
-	overlay unsigned char fast = 1;					// 0: 2 seconds step, 1: 1 minute step
-
-	// target the simulated tissues
-	tissue_increment = 0;
-
-	// loop until first deco stop or the surface is reached
-	for(;;)
-	{
-		// memorize depth in absolute pressure we came from
-		old_pres_respiration = sim_pres_respiration;
-
-		// try ascending 1 full minute (fast) or 2 seconds (!fast)
-		if( fast ) sim_pres_respiration -=          float_ascent_speed * METER_TO_BAR;	// 1 min at float_ascent_speed ( 5 .. 10  m)
-		else       sim_pres_respiration -= 0.0333 * float_ascent_speed * METER_TO_BAR;	// 2 sec at float_ascent_speed (17 .. 33 cm)
-
-		// but don't go over surface
-		if( sim_pres_respiration < pres_surface ) sim_pres_respiration = pres_surface;
-
-		// compute ceiling of the simulated tissues
-		if( char_I_deco_model != 0 ) calc_limit(GF_low);
-		else                         calc_limit(1.0);
-
-		// did we overshoot the ceiling?
-		if( sim_pres_respiration < (ceiling + pres_surface) )
-		{
-			// YES - back to memorized depth
-			sim_pres_respiration = old_pres_respiration;
-
-			// switch to 2 seconds ascent if not yet in, else done
-			if( fast )
-			{
-				fast = 0;		// ascent with 2 seconds ascent steps
-				continue;
-			}
-			else
-			{
-				break;			// done, stop required
-			}
-		}
-
-		// if code execution passes along here, we did not overshoot the ceiling
-
-		// did we reach the surface? If yes, deco has vanished, no stop required, done.
-		if( sim_pres_respiration == pres_surface ) break;
-
-		// depth in meters where we are now (no round-up)
-		sim_depth_limit = (unsigned char)((sim_pres_respiration - pres_surface) * BAR_TO_METER);
-
-		// program interval on simulated tissues:
-		// fast = 1 -> 1 minute,
-		// fast = 0 -> 2 seconds
-		tissue_increment = fast;
-
-		// Check if there is a better gas to switch to, but only if bailout mode is enabled.
-		// If yes, introduce a stop for the gas change.
-		if( char_O_deco_status & DECO_BAILOUT_MODE )
-		if( gas_find_better() )
-		{
-			overlay unsigned char old_depth_limit;
-
-			// set the new calculation values for N2, He and O2
-			gas_set_ratios();
-
-			// add gas change time: a gas change time of
-			//    0 minutes will keep the 1 minute / 2 seconds interval selection,
-			// >= 1 minute  will add the the 1 minute interval but overrule a 2 seconds interval.
-			tissue_increment += char_I_gas_change_time;
-
-			// depth in meters we came from
-			old_depth_limit = (unsigned char)((old_pres_respiration - pres_surface) * BAR_TO_METER);
-
-			// adjust sim_depth_limit to the gas change depth, but not deeper than the depth we came from
-			sim_depth_limit = (sim_gas_current_depth < old_depth_limit) ? sim_gas_current_depth : old_depth_limit;
-
-			// Adjust the depth for the tissue update to the current depth. In case of fast mode,
-			// this imposes that the ascent from the 'old_pres_respiration' depth to this depth
-			// took one minute although we might have only ascended one or two meters...
-			sim_pres_respiration = sim_depth_limit * METER_TO_BAR + pres_surface;
-
-			// create a stop for the gas change in the stops table
-			update_deco_table(char_I_gas_change_time);
-		}
-
-		// omit the 2 seconds interval updates (do only updates for >= 1 minute)
-		// It's a trade-off between computational effort and accuracy...
-		if( tissue_increment )
-		{
-			// compute ppO2, ppN2 and ppHe for current depth from sim_pres_respiration
-			calc_alveolar_pressures();
-
-			// update the tissues
-			calc_tissues();
-
-			// update the CNS value
-			calc_CNS();
-		}
-
-	} // for()
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
 // calc_tissues
 //
-// INPUT:    ppN2                          : partial pressure of inspired N2
-//           ppHe                          : partial pressure of inspired He
-//           tissue_increment              : integration time and tissue selector (real or simulated)
-//
-// MODIFIED: pres_tissue_N2[]              : tissue N2 pressures (in real tissues context)
-//           pres_tissue_He[]              : tissue He pressures (in real tissues context)
-//           sim_pres_tissue_N2[]          : tissue N2 pressures (in simulated tissues context)
-//           sim_pres_tissue_He[]          : tissue He pressures (in simulated tissues context)
-//
-// OUTPUT:   char_O_tissue_N2_saturation[] : tissue N2 pressures scaled for display purpose (in real tissues context)
-//           char_O_tissue_He_saturation[] : tissue He pressures scaled for display purpose (in real tissues context)
+// INPUT:    ppN2                       partial pressure of inspired N2
+//           ppHe                       partial pressure of inspired He
+//           tissue_increment           integration time and tissue selector (real or simulated)
+//
+// MODIFIED: real_pres_tissue_N2[]      tissue N2 pressures (in real tissues context)
+//           real_pres_tissue_He[]      tissue He pressures (in real tissues context)
+//           sim_pres_tissue_N2[]       tissue N2 pressures (in simulated tissues context)
+//           sim_pres_tissue_He[]       tissue He pressures (in simulated tissues context)
+//
+// OUTPUT:   char_O_tissue_pres_N2[]    tissue N2 pressures scaled for display purpose (in real tissues context)
+//           char_O_tissue_pres_He[]    tissue He pressures scaled for display purpose (in real tissues context)
+//           char_O_tissue_pressure[]   combined tissue pressures scaled for display purpose (in real tissue context)
 //
 static void calc_tissues()
 {
+	overlay unsigned char	period;
 	overlay float			temp_tissue_N2;
+
+#ifdef _helium
 	overlay float			temp_tissue_He;
-	overlay unsigned char	period;
-	overlay unsigned char	i;
+#endif
 
 
 	assert( 0.00 <= ppN2 && ppN2 < 11.2 );  // 80% N2 at 130m
@@ -2581,59 +3113,62 @@
 
 		if( i == 0 )						// check if we shall do one 2-seconds period
 		{
-			read_Buhlmann_times(0);			// YES, program coefficients for a 2 seconds period
-			period = 1;						//      set period length (in cycles)
-			i      = 1;						//      and one cycle to do
+			read_Buhlmann_times(0);			// YES - program coefficients for a 2 seconds period
+			period = 1;						//     - set period length (in cycles)
+			i      = 1;						//     - and one cycle to do
 		}
 		else if( i > 9 )					// check if we can start with 10 minutes periods
 		{
-			read_Buhlmann_times(2);			// YES, program coefficients for 10 minutes periods
-			period = 10;					//      set period length (in cycles) to ten
+			read_Buhlmann_times(2);			// YES - program coefficients for 10 minutes periods
+			period = 10;					//       set period length (in cycles) to ten
 		}
-		else								// we shall do 1 to 9 minutes
+		else								// last but not lease, do 1 to 9 minutes
 		{
-			read_Buhlmann_times(1);			//      program coefficients for 1 minute periods
-			period = 1;						//      set period length (in cycles) to one
+			read_Buhlmann_times(1);			// NO  - program coefficients for 1 minute periods
+			period = 1;						//     - set period length (in cycles) to one
 		}
 
 		do
 		{
-			//---- N2 -------------------------------------------------------------------------------
-
-			temp_tissue = (tissue_increment & TISSUE_FLAG) ? pres_tissue_N2[ci] : sim_pres_tissue_N2[ci];
+			//---- N2 --------------------------------------------------------
+
+			temp_tissue = (tissue_increment & TISSUE_SELECTOR) ? real_pres_tissue_N2[ci] : sim_pres_tissue_N2[ci];
 
 			temp_tissue = (ppN2 - temp_tissue) * var_N2_e;
 
-			temp_tissue_safety();
-
-			if( tissue_increment & TISSUE_FLAG )
+			apply_saturation_factors();
+
+			if( tissue_increment & TISSUE_SELECTOR )
 			{
-				temp_tissue_N2      = temp_tissue;
-				pres_tissue_N2[ci] += temp_tissue;
+				temp_tissue_N2           = temp_tissue;
+				real_pres_tissue_N2[ci] += temp_tissue;
 			}
 			else
 			{
-				sim_pres_tissue_N2[ci] += temp_tissue;
+				sim_pres_tissue_N2[ci]  += temp_tissue;
 			}
 
-
-			//---- He -------------------------------------------------------------------------------
-
-			temp_tissue = (tissue_increment & TISSUE_FLAG) ? pres_tissue_He[ci] : sim_pres_tissue_He[ci];
+#ifdef _helium
+			//---- He --------------------------------------------------------
+
+			temp_tissue = (tissue_increment & TISSUE_SELECTOR) ? real_pres_tissue_He[ci] : sim_pres_tissue_He[ci];
 
 			temp_tissue = (ppHe - temp_tissue) * var_He_e;
 
-			temp_tissue_safety();
-
-			if( tissue_increment & TISSUE_FLAG )
+			apply_saturation_factors();
+
+			if( tissue_increment & TISSUE_SELECTOR )
 			{
-				temp_tissue_He      = temp_tissue;
-				pres_tissue_He[ci] += temp_tissue;
+				temp_tissue_He           = temp_tissue;
+				real_pres_tissue_He[ci] += temp_tissue;
 			}
 			else
 			{
-				sim_pres_tissue_He[ci] += temp_tissue;
+				sim_pres_tissue_He[ci]  += temp_tissue;
 			}
+#endif
+
+			//---- decrement loop counter and adjust step size ---------------
 
 			// decrement loop counter
 			i -= period;
@@ -2649,116 +3184,169 @@
 
 
 		// have the computations been done for the "real" tissues?
-		if( tissue_increment & TISSUE_FLAG )
+		if( tissue_increment & TISSUE_SELECTOR )
 		{
+
+#ifdef _helium
+
 			// net tissue balance
 			temp_tissue = temp_tissue_N2 + temp_tissue_He;
 
+
 			// check tissue on-/off-gassing and IBCD with applying a threshold of +/-HYST
 			//
 			if      ( temp_tissue < -HYST )				// check if the tissue is off-gassing
 			{
-				deco_tissue_vector |=  (1 << ci);		// tag tissue as being in decompression
-				IBCD_tissue_vector &= ~(1 << ci);		// tag tissue as not experiencing mentionable IBCD
+				// tag tissue as not experiencing mentionable IBCD
+				IBCD_tissue_vector &= ~(1 << ci);
 			}
 			else if ( temp_tissue > +HYST )				// check if the tissue in on-gassing
 			{
-				deco_tissue_vector &= ~(1 << ci);		// tag tissue as not being in decompression
-
-				if(    ((temp_tissue_N2 > 0.0) && (temp_tissue_He < 0.0))		// check for counter diffusion
+				// check for counter diffusion
+				if(    ((temp_tissue_N2 > 0.0) && (temp_tissue_He < 0.0))
 				    || ((temp_tissue_N2 < 0.0) && (temp_tissue_He > 0.0)) )
 				{
-					IBCD_tissue_vector |= (1 << ci);	// tag tissue as experiencing mentionable IBCD
+					// tag tissue as experiencing mentionable IBCD
+					IBCD_tissue_vector |= (1 << ci);
 				}
 			}
 
-
-			// keep the saturating / desaturating flags from last invocation
-			char_O_tissue_N2_saturation[ci] &= 128;
-			char_O_tissue_He_saturation[ci] &= 128;
-
-			// flip the flags applying a hysteresis of HYST (actual value: see #define of HYST)
-				 if( temp_tissue_N2 > +HYST ) char_O_tissue_N2_saturation[ci] = 128; // set flag for tissue pressure is increasing
-			else if( temp_tissue_N2 < -HYST ) char_O_tissue_N2_saturation[ci] =   0; // clear flag (-> tissue pressure is decreasing)
-
-				 if( temp_tissue_He > +HYST ) char_O_tissue_He_saturation[ci] = 128; // set flag for tissue pressure is increasing
-			else if( temp_tissue_He < -HYST ) char_O_tissue_He_saturation[ci] =   0; // clear flag (-> tissue pressure is decreasing)
-
-
-			// For N2 tissue display purpose:
-			// Scale tissue press so that saturation in 70m on AIR gives a value of approx. 80.
-			// The surface steady-state tissue loading of [0.7902 * (real_pres_respiration - ppWater)] bar
-			// gives then a 10. If N2 is completely washed out of the tissue, result will be 0.
-			// This scaling is adapted to the capabilities of the tissue graphics in the custom views.
-			temp_tissue = (pres_tissue_N2[ci] / N2_equilibrium) * 10;
-
-			// limit to 127 to leave space for sat/desat flag
+#endif
+
+			// For N2 tissue pressure display purpose:
+
+			// basically keep the on-gassing / off-gassing flag from last invocation, but flip
+			// it in case the rate exceeds a set hysteresis (actual value: see #define of HYST)
+			char_O_tissue_pres_N2[ci]  &= 128;
+			if      ( temp_tissue_N2 > +HYST ) char_O_tissue_pres_N2[ci]  = 128; // set flag for tissue pressure is increasing
+			else if ( temp_tissue_N2 < -HYST ) char_O_tissue_pres_N2[ci]  =   0; // clear flag (-> tissue pressure is decreasing)
+
+			// scale N2 tissue pressure such that the surface steady-state tissue loading
+			// of [0.7902 * (1013 hPa - ppWater)] bar will give a 8, which aligns with
+			// the 2nd scale line.
+			temp_tissue_N2 = (8 / (0.7902 * (1.013 - ppWater))) * real_pres_tissue_N2[ci];
+
+			// limit to 127 to protect the uppermost bit which holds the sat/desat flag
+			if (temp_tissue_N2 > 127) temp_tissue_N2 = 127;
+
+			// convert to integer and combine with sat/desat flag
+			char_O_tissue_pres_N2[ci] += (unsigned char)temp_tissue_N2;
+
+#ifdef _helium
+
+			// For He tissue pressure display purpose:
+
+			// basically keep the on-gassing / off-gassing flag from last invocation, but flip
+			// it in case the rate exceeds a set hysteresis (actual value: see #define of HYST)
+			char_O_tissue_pres_He[ci]  &= 128;
+			if      ( temp_tissue_He > +HYST ) char_O_tissue_pres_He[ci]  = 128; // set flag for tissue pressure is increasing
+			else if ( temp_tissue_He < -HYST ) char_O_tissue_pres_He[ci]  =   0; // clear flag (-> tissue pressure is decreasing)
+
+			// scale He tissue pressure alike it is done for N2.
+			// With no He in a tissue, the result will be 0.
+			temp_tissue_He = (8 / (0.7902 * (1.013 - ppWater))) * real_pres_tissue_He[ci];
+
+			// limit to 127 to protect the uppermost bit which holds the sat/desat flag
+			if (temp_tissue_He > 127) temp_tissue_He = 127;
+
+			// convert to integer and combine with sat/desat flag
+			char_O_tissue_pres_He[ci] += (unsigned char)temp_tissue_He;
+
+
+			// For combined tissue pressure display purpose:
+
+			// basically keep the on-gassing / off-gassing flag from last invocation, but flip
+			// it in case the rate exceeds a set hysteresis (actual value: see #define of HYST)
+			char_O_tissue_pressure[ci] &= 128;
+			if      ( temp_tissue    > +HYST ) char_O_tissue_pressure[ci] = 128; // set flag for tissue pressure is increasing
+			else if ( temp_tissue    < -HYST ) char_O_tissue_pressure[ci] =   0; // clear flag (-> tissue pressure is decreasing)
+
+			// add the two scaled pressures.
+			temp_tissue = temp_tissue_N2 + temp_tissue_He;
+
+			// limit to 127 to protect the uppermost bit which holds the sat/desat flag
 			if (temp_tissue > 127) temp_tissue = 127;
 
-			// export as integer
-			char_O_tissue_N2_saturation[ci] += (unsigned char)temp_tissue;
-
-
-			// For H2 tissue display purpose:
-			// Scale tissue press so that saturation in 120m on TMX 10/70 gives a value of approx. 70.
-			// With no He in a tissue, result will be 0.
-			// This scaling is adapted to the capabilities of the tissue graphics in the custom views.
-			temp_tissue = pres_tissue_He[ci] * 7.7;
-
-			// limit to 127 to leave space for sat/desat flag
-			if (temp_tissue > 127) temp_tissue = 127;
-
-			// export as integer
-			char_O_tissue_He_saturation[ci] += (unsigned char)temp_tissue;
+			// convert to integer and combine with sat/desat flag
+			char_O_tissue_pressure[ci] += (unsigned char)temp_tissue;
+
+#else
+
+			// He tissue pressure is zero
+			char_O_tissue_pres_He[ci] = 0;
+
+			// combined tissue pressure equals N2 tissue pressure
+			char_O_tissue_pressure[ci] = char_O_tissue_pres_N2[ci];
+
+#endif
+
 		} //if
 
 	} // for
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // calc_limit
 //
-// Input:  GF_parameter             gradient factor to be used, negative values activate surface mode
-//         tissue_increment         selector for context: real or simulated tissues
-//         sim_pres_tissue_N2/_He   tissue pressures (used in simulated tissues context)
-//         pres_tissue_N2/_He       tissue pressures (used in real      tissues context)
-//
-// Output: lead_supersat            highest supersaturation found among all tissues, 1.0 = 100%
-//         lead_tissue              number of the leading tissue (0-15)
-//         ceiling                  ceiling in bar relative pressure
-//
-// Modified:
-//         char_O_deco_warnings     for IBCD, microbubbles and outside warning (only in real tissues context)
+// Input:    GF_parameter             gradient factor to be used, negative values activate surface mode
+//           tissue_increment         selector for context: real or simulated tissues
+//           sim_pres_tissue_N2/_He   tissue pressures (used in simulated tissues context)
+//           real_pres_tissue_N2/_He  tissue pressures (used in real      tissues context)
+//
+// Output:   lead_supersat            highest supersaturation found among all tissues, 1.0 = 100%
+//           lead_tissue              number of the leading tissue (0-15)
+//           ceiling                  ceiling in bar relative pressure
+//
+// Modified: deco_warnings            for IBCD, micro bubbles and outside warning (only in real tissues context)
 //
 static void calc_limit(PARAMETER float GF_parameter)
 {
-	overlay float lead_tissue_limit = 0.0;
-
-
-	// set leading tissue number to not yet computed
-	lead_number = 0;
+	overlay float         pres_respiration_min_total = 0.0;
+	overlay unsigned char surface_mode               = 0;		// 0: off, 1: on
+
+
+	// check mode
+	if( GF_parameter < 0 )
+	{
+		// activate surface mode
+		surface_mode = 1;
+
+		// normalize parameter
+		GF_parameter = -GF_parameter;
+	}
+
+	// set leading tissue number to tissue 1 (it has the index 0)
+	lead_tissue   = 0;
 
 	// initialize leading tissue supersaturation value to null
-	lead_supersat  = 0.0;
-
-	// check context
-	if( tissue_increment & TISSUE_FLAG )
+	lead_supersat = 0.0;
+
+	// next code section is relevant only when invoked on the real tissues
+	if( tissue_increment & TISSUE_SELECTOR )
 	{
-		// clear IBCD, micro bubbles and outside warning flags (locked warnings will be preserved)
-		char_O_deco_warnings &= ~(DECO_WARNING_IBCD + DECO_WARNING_MBUBBLES + DECO_WARNING_OUTSIDE + DECO_ATTENTION_OUTSIDE );
+		// clear IBCD, micro-bubbles and outside warning flags (locked warnings will be preserved)
+		deco_warnings &= ~( DECO_WARNING_IBCD + DECO_WARNING_MBUBBLES + DECO_WARNING_OUTSIDE + DECO_ATTENTION_OUTSIDE );
 	}
 
 	// loop over all tissues
 	for( ci = 0; ci < NUM_COMP; ci++ )
 	{
-		overlay float pres_min;
+		overlay float pres_respiration_min_tissue;
+
+
+		// get the coefficients for tissue ci
+		read_Buhlmann_coefficients();
+
+#ifdef _helium
 
 		// get the tissue pressures
-		if( tissue_increment & TISSUE_FLAG )
+		// adopt_Buhlmann_coefficients needs calc_pres_tissue_N2/He when compiled for helium
+		if( tissue_increment & TISSUE_SELECTOR )
 		{
 			// context is real tissues
-			calc_pres_tissue_N2 = pres_tissue_N2[ci];
-			calc_pres_tissue_He = pres_tissue_He[ci];
+			calc_pres_tissue_N2 = real_pres_tissue_N2[ci];
+			calc_pres_tissue_He = real_pres_tissue_He[ci];
 		}
 		else
 		{
@@ -2770,29 +3358,38 @@
 		// overall tissue pressure
 		pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He;
 
-		// get the coefficients for tissue ci
-		read_Buhlmann_coefficients();
+#else
+
+		// get the tissue pressure
+		pres_tissue = ( tissue_increment & TISSUE_SELECTOR ) ? real_pres_tissue_N2[ci] : sim_pres_tissue_N2[ci];
+
+#endif
 
 		// adopt a and b coefficients to current N2/He ratio inside the tissue
 		adopt_Buhlmann_coefficients();
 
 		// next calculations are only relevant when invoked on the real tissues
-		if( tissue_increment & TISSUE_FLAG )
+		if( tissue_increment & TISSUE_SELECTOR )
 		{
 			overlay float pres_tissue_max;
 			overlay float supersat;
 			overlay float baseline_threshold;
 
+
 			// check if tissue is in supersaturation
 			if( pres_tissue > real_pres_respiration )
 			{
 				// calculate maximum allowed tissue pressure at current ambient pressure
-				pres_tissue_max = real_pres_respiration / var_N2_b + var_N2_a;
+				pres_tissue_max = real_pres_respiration / var_b + var_a;
 
 				// calculate current supersaturation value (1.0 = 100%) of this tissue according to straight Buhlmann
 				supersat =    ( pres_tissue     - real_pres_respiration )
 				            / ( pres_tissue_max - real_pres_respiration );
 
+				// calculate supersaturation value for display purpose: 1.35 = 135% = 86 pixel
+				if( supersat <= 1.35 ) char_O_tissue_saturation[ci] = (unsigned char)(supersat * 64);
+				else                   char_O_tissue_saturation[ci] = 86;
+
 				// memorize highest supersaturation found
 				if( supersat > lead_supersat ) lead_supersat = supersat;
 
@@ -2801,218 +3398,300 @@
 
 				// micro bubbles warning: supersaturation > baseline threshold
 				if( supersat > baseline_threshold )
-					char_O_deco_warnings |= (DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock);
+					deco_warnings |= (DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock);
 
 				// outside warning: supersaturation > baseline threshold + additional 5% margin
-				if( supersat > baseline_threshold + 0.05 )
-					char_O_deco_warnings |= (DECO_WARNING_OUTSIDE  + DECO_WARNING_OUTSIDE_lock );
+				if( supersat > (baseline_threshold + 0.05) )
+					deco_warnings |= (DECO_WARNING_OUTSIDE  + DECO_WARNING_OUTSIDE_lock );
+			}
+			else
+			{
+				// supersaturation is defined as zero while tissue pressure <= ambient pressure
+				supersat                     = 0.0;
+				char_O_tissue_saturation[ci] = 0;
 			}
-		}
+
+			// next only when in surface mode
+			if( surface_mode )
+			{
+				// tag tissue whether it is beyond the M-line limit or not
+				if( supersat > 1.0 )
+				{
+					char_O_tissue_pres_N2[ci]  |=  128;
+#ifdef _helium
+					char_O_tissue_pres_He[ci]  |=  128;
+#endif
+					char_O_tissue_pressure[ci] |=  128;
+				}
+				else
+				{
+					char_O_tissue_pres_N2[ci]  &= ~128;
+#ifdef _helium
+					char_O_tissue_pres_He[ci]  &= ~128;
+#endif
+					char_O_tissue_pressure[ci] &= ~128;
+				}
+			}
+		} // real tissues
 
 		// calculate the minimum ambient pressure that the tissue can withstand
 		if( char_I_deco_model == 0 )
 		{
 			// straight Buhlmann
-			pres_min = (pres_tissue - var_N2_a) * var_N2_b;
+			pres_respiration_min_tissue = (pres_tissue - var_a) * var_b;
 		}
 		else
 		{
 			// Buhlmann with Eric Baker's varying gradient factor correction
 			// note: this equation [1] is the inverse of equation [2]
-			pres_min =   ( pres_tissue        - (var_N2_a     * GF_parameter) )
-			           / ( 1.0 - GF_parameter + (GF_parameter / var_N2_b      ) );
+			pres_respiration_min_tissue =   ( pres_tissue        - (var_a        * GF_parameter) )
+			                              / ( 1.0 - GF_parameter + (GF_parameter / var_b       ) );
 		}
 
 		// check if this tissue requires a higher ambient pressure than was found to be needed up to now
-		if( pres_min > lead_tissue_limit )
+		if( pres_respiration_min_tissue > pres_respiration_min_total )
 		{
-			lead_tissue_limit = pres_min;
-			lead_number       = ci;
+			pres_respiration_min_total = pres_respiration_min_tissue;
+			lead_tissue                = ci;
 		}
 	} // for
 
-
 	// compute ceiling for the real tissues in bar relative pressure
-	ceiling = lead_tissue_limit - pres_surface;
-
-
-	// next in real tissue context only
-	if( tissue_increment & TISSUE_FLAG )
+	ceiling = pres_respiration_min_total - pres_surface;
+
+#ifdef _helium
+	// IBCD is checked for real tissues only
+	if( tissue_increment & TISSUE_SELECTOR )
 	{
 		// check if the leading tissue is in IBCD condition
-		if(    (IBCD_tissue_vector & (1 << lead_number))
-		    && ((pres_tissue_N2[lead_number] + pres_tissue_He[lead_number]) > real_pres_respiration) )
+		if(    (IBCD_tissue_vector & (1 << lead_tissue))
+		    && ((real_pres_tissue_N2[lead_tissue] + real_pres_tissue_He[lead_tissue]) > real_pres_respiration) )
 		{
-			// leading tissue is in IBCD condition and in super-saturation, so issue a warning
-			char_O_deco_warnings |= (DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock);
+			// leading tissue is in IBCD condition and in super-saturation, so issue a warning.
+			deco_warnings |= (DECO_WARNING_IBCD + DECO_WARNING_IBCD_lock);
 		}
 	}
+#endif
+
 }
+
+
 //////////////////////////////////////////////////////////////////////////////
-// calc_NDL_time
-//
-// calculation of the remaining bottom time (NDL: no decompression limit)
+// calc_NDL_time_tissue
+//
+// calculation of the remaining no decompression limit (NDL) time for a tissue
 //
 // NOTE: Erik Baker's closed formula works for Nitrox. Trimix adds a second
 //       exponential term to the M-value equation, making it impossible to
-//       invert. So we have to solve the problem with an iterative approach.
-//
-// Input:  ppN2
-//         ppHe
-//
-// Output: NDL_time
-//
-static void calc_NDL_time(void)
+//       invert. So we have to solve the problem with a search approach.
+//
+// Input:    NDL_tissue       tissue for which to calculate remaining NDL time
+//           GF_high          gradient factor used when GF factors are enabled
+//           ppN2, ppHe       partial pressures of N2 and He breathed
+//
+// Modified: NDL_time         shortest NDL time found so far
+//           NDL_tissue_lead  leading tissue, i.e. tissue with the shortest NDL
+//
+static void calc_NDL_time_tissue(void)
 {
-	overlay unsigned char new_NDL_lead_tissue = 0;
-	overlay unsigned char i;
-
-
-	// initialize NDL_time to 240 minutes
-	NDL_time = 240;
-
-	for( i = 0; i < NUM_COMP; i++ )
+	overlay unsigned char NDL_time_tissue	=  0;	// NDL time of this tissue, starting with  0 minutes
+	overlay unsigned char step_size			= 10;	// step size in searching,  starting with 10 minutes
+	overlay float         pres_limit;				// max. tissue pressure allowed
+
+#ifdef _helium
+	overlay float         last_pres_tissue_N2;		// last tissue pressure for N2
+	overlay float         last_pres_tissue_He;		// last tissue pressure for He
+#else
+	overlay float         last_pres_tissue;			// last tissue pressure
+#endif
+
+
+	// set the compartment index ci for reading the Buhlmann increments and coefficients
+	ci = NDL_tissue;
+
+	// read the tissue increments for a step size of 10 minutes
+	read_Buhlmann_times(2);
+
+	// read Buhlmann a and b coefficients for tissue ci
+	read_Buhlmann_coefficients();
+
+#ifdef _helium
+
+	// get the current simulated tissue pressures
+	calc_pres_tissue_N2 = last_pres_tissue_N2 = sim_pres_tissue_N2[ci];
+	calc_pres_tissue_He = last_pres_tissue_He = sim_pres_tissue_He[ci];
+
+#else
+
+	// get the current simulated tissue pressure
+	pres_tissue = last_pres_tissue = sim_pres_tissue_N2[ci];
+
+	// set the a and b coefficients
+	adopt_Buhlmann_coefficients();
+
+#endif
+
+	// simulate an increasing bottom time and check when the NDL is hit
+	for(;;)
 	{
-		overlay unsigned char period		= 10;		// start with iterations of 10 minutes
-		overlay unsigned char NDL_tissue;				// loop variable
-		overlay float         GF_factor;				// gradient factor to be applied
-		overlay float         next_pres_tissue;			// auxiliary variable to cache a calculation result
-
-
-		// select gradient factor to use
-		GF_factor = (char_I_deco_model != 0) ? GF_high : 1.0;
-
-		// the fastest way to find out if already being beyond NDL is to start with
-		// the tissue that was the leading one during the last NDL computation...
-		ci =  (char_O_deco_status & DECO_PLAN_ALTERNATE) ? (NDL_lead_tissue_alt + i) : (NDL_lead_tissue_norm + i);
-
-		// wrap around after the 16th tissue
-		if( ci >= NUM_COMP ) ci -= NUM_COMP;
-
-		// read the loading factors for 10 minute iterations
-		read_Buhlmann_times(2);
-
-		// get the tissue pressures for N2 and He
-		calc_pres_tissue_N2 = sim_pres_tissue_N2[ci];
-		calc_pres_tissue_He = sim_pres_tissue_He[ci];
-
-		// calculate the total pressure tissue
+
+#ifdef _helium
+
+		// calculate the total tissue pressure
 		pres_tissue = calc_pres_tissue_N2 + calc_pres_tissue_He;
 
-		// Simulate an increasing bottom time and check when we hit the NDL.
-		// It is not needed to simulate for longer than the already found NDL.
-		for( NDL_tissue = 0; NDL_tissue < NDL_time; )
+		// adopt a and b coefficients to current N2/He ratio inside the tissue
+		adopt_Buhlmann_coefficients();
+
+#endif
+
+		// compute the maximum tissue pressure allowed to be exposed to an
+		// ambient pressure equaling the surface pressure
+		if( char_I_deco_model != 0 )
+		{
+			// GF model enabled, this equation [2] is the inverse of equation [1]
+			pres_limit = (1.0 - GF_high + GF_high / var_b) * pres_surface + GF_high * var_a;
+		}
+		else
 		{
-			overlay float pres_limit;
-			overlay float delta_pres_tissue_N2;
-			overlay float delta_pres_tissue_He;
-
-
-			// read Buhlmann a and b coefficients for tissue ci, they need to be re-read on each
-			// iteration because adopt_Buhlmann_coefficients() twiddles with the N2 coefficients
-			read_Buhlmann_coefficients();
-
-			// adopt a and b coefficients to current N2/He ratio inside the tissue
-			adopt_Buhlmann_coefficients();
-
-			// compute the maximum tissue pressure allowed to be exposed to an ambient pressure equaling
-			// the surface pressure                   (this equation [2] is the inverse of equation [1])
-			pres_limit = (1.0 - GF_factor + GF_factor / var_N2_b) * pres_surface + GF_factor * var_N2_a;
-
-			// check if this tissue is already beyond the NDL
-			if( pres_tissue > pres_limit)
+			// straight Buhlmann
+			pres_limit = pres_surface / var_b + var_a;
+		}
+
+		// is the tissue pressure higher than the maximum tissue pressure allowed?
+		if( pres_tissue > pres_limit)
+		{
+			// YES - tissue is outside NDL
+
+			// was the tissue outside NDL right from the start?
+			if( NDL_time_tissue == 0 )
 			{
-				// beyond NDL - finish the outer loop, ...
-				i = NUM_COMP;
-
-				// ... and finish the inner loop
+				// YES - search can be aborted
+
+				// at least one tissue is outside NDL, so overall NDL time is zero
+				NDL_time = 0;
+
+				// store the number of this tissue as being the leading one
+				NDL_tissue_lead = NDL_tissue;
+
+				// done
 				break;
 			}
 
-			// compute tissue pressure deltas for 10 or 1 minute of time ahead
-			delta_pres_tissue_N2 = (ppN2 - calc_pres_tissue_N2) * var_N2_e;
-			delta_pres_tissue_He = (ppHe - calc_pres_tissue_He) * var_He_e;
-
-			// apply safety factors to the pressure deltas
-			// NDL can be computed while ascending, so we have to check if the tissues is saturating or desaturating
-			if( delta_pres_tissue_N2 > 0.0 ) delta_pres_tissue_N2 *= float_saturation_multiplier;
-			else                             delta_pres_tissue_N2 *= float_desaturation_multiplier;
-
-			if( delta_pres_tissue_He > 0.0 ) delta_pres_tissue_He *= float_saturation_multiplier;
-			else                             delta_pres_tissue_He *= float_saturation_multiplier;
-
-			// simulate off-gassing while going to surface - well, maybe some day we'll do that...
-			// delta_pres_tissue_N2 -= exp( ... ascent time ... ppN2...)
-			// delta_pres_tissue_He -= exp( ... ascent time ... ppHe...)
-
-			// calculate tissue pressure for given time ahead
-			next_pres_tissue = pres_tissue + delta_pres_tissue_N2 + delta_pres_tissue_He;
-
-			// within NDL now, but still within NDL in 10 or 1 minute from now?
-			if( next_pres_tissue <= pres_limit )
+			// when code execution passes here, the tissue has become
+			// being outside NDL after doing one or more search steps
+
+			// still searching with a step size of 10 minutes?
+			if( step_size == 10 )
 			{
-				// YES - apply the pressure deltas to the tissues
-				calc_pres_tissue_N2 += delta_pres_tissue_N2;
-				calc_pres_tissue_He += delta_pres_tissue_He;
-
-				// update the overall tissue pressure
-				pres_tissue = next_pres_tissue;
-
-				// increment the NDL
-				NDL_tissue += period;
-
-				// do next iteration
+				// YES - retry with smaller step size
+
+				// go back to last NDL time
+				NDL_time_tissue -= 10;
+
+#ifdef _helium
+
+				// go back to last pressures
+				calc_pres_tissue_N2 = last_pres_tissue_N2;
+				calc_pres_tissue_He = last_pres_tissue_He;
+
+#else
+
+				// go back to last pressure
+				pres_tissue = last_pres_tissue;
+
+#endif
+
+				// reduce step size to 1 minute
+				step_size = 1;
+
+				// read the tissue increments for a step size of 1 minute
+				read_Buhlmann_times(1);
+
+				// redo search from last pressure & time within NDL with smaller step size
 				continue;
 			}
-
-			// NO - if delta pressures were for 10 minutes of time ahead, continue with trying for 1 minute ahead
-			if( period == 10 )
+			else
 			{
-				// reduce period to 1 minute
-				period = 1;
-
-				// read the loading factors for 1 minute periods
-				read_Buhlmann_times(1);
-
-				// do next iteration
-				continue;
+				// NO - already tried with a step size of 1 minute
+
+				// go back to last NDL time that was within NDL
+				NDL_time_tissue -= 1;
+
+				// is the NDL time of this tissue shorter than the overall NDL time found so far?
+				if( NDL_time_tissue < NDL_time )
+				{
+					// YES - set this tissue's NDL time as the new overall NDL time
+					NDL_time = NDL_time_tissue;
+
+					//     - store the number of this tissue as being the leading one
+					NDL_tissue_lead = NDL_tissue;
+				}
+
+				// done
+				break;
 			}
-
-			// less than a full minute of NDL time left, so finish the inner loop
-			break;
-
-		} // inner for-loop simulating increasing bottom time
-
-		// is the current NDL shorter than the shortest so far?
-		if ( NDL_tissue < NDL_time )
+		}
+		else
 		{
-			// keep the current's tissue NDL as the new shortest NDL
-			NDL_time = NDL_tissue;
-
-			// store the causing tissue
-			new_NDL_lead_tissue = ci;
+			// NO - tissue is still within NDL
+
+			// The search can be terminated when the NDL time of this tissue
+			// exceeds the overall NDL time, thus when a shorter NDL time has
+			// already been found with another tissue.
+			if( NDL_time_tissue >= NDL_time ) break;
+
+#ifdef _helium
+
+			// back-up current tissue pressures
+			last_pres_tissue_N2 = calc_pres_tissue_N2;
+			last_pres_tissue_He = calc_pres_tissue_He;
+
+#else
+
+			// back-up current tissue pressure
+			last_pres_tissue    = pres_tissue;
+
+#endif
+
+			// step forward NDL time of current tissue
+			NDL_time_tissue += step_size;
+
+#ifdef _helium
+
+			// step forward tissue pressure - N2
+			temp_tissue          = (ppN2 - calc_pres_tissue_N2) * var_N2_e;		// pressure delta breathed - tissue
+			apply_saturation_factors();											// apply safety factor
+			calc_pres_tissue_N2 += temp_tissue;									// add pressure delta to tissue
+
+			// step forward tissue pressure - He
+			temp_tissue          = (ppHe - calc_pres_tissue_He) * var_He_e;		// pressure delta breathed - tissue
+			apply_saturation_factors();											// apply safety factor
+			calc_pres_tissue_He += temp_tissue;									// add pressure delta to tissue
+
+#else
+
+			// step forward tissue pressure
+			temp_tissue          = (ppN2 - pres_tissue        ) * var_N2_e;		// pressure delta breathed - tissue
+			apply_saturation_factors();											// apply safety factor
+			pres_tissue         += temp_tissue;									// add pressure delta to tissue
+
+#endif
+
 		}
-		
-		// If NDL is > 0 the outer loop will continues with the next tissue.
-		// If NDL found to be overrun, outer loop will be terminated by means of the i = NUM_COMP statement.
-
-	} // outer for-loop iterating over all tissues
-
-	// store the NDL dominating tissue for to start with in the next NDL calculation
-	if( char_O_deco_status & DECO_PLAN_ALTERNATE ) NDL_lead_tissue_alt  = new_NDL_lead_tissue;
-	else                                           NDL_lead_tissue_norm = new_NDL_lead_tissue;
+	}
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 // calc_ascenttime
 //
-// Sum up ascent from bottom to surface at float_ascent_speed, slowing down to
-// 1 minute per meter for the final ascent when in deco, and all stop times.
+// Sum up ascent from bottom to surface at char_I_ascent_speed, slowing down
+// to 1 minute per meter for the final ascent when in deco, and all stop times.
 //
 // Input:  char_I_depth_last_deco
 //         char_I_ascent_speed
-//         char_bottom_depth
+//         char_depth_bottom
 //         internal_deco_depth[]
 //         internal_deco_time[]
 //
@@ -3020,100 +3699,87 @@
 //
 static void calc_ascenttime(void)
 {
-	overlay unsigned char x;		// loop counter
-	overlay unsigned char ascent;	// meters to go from bottom to last stop
-	overlay unsigned char final;	// meters to go from last stop to surface
-
-
 	// check if there are stops
 	if( internal_deco_depth[0] )
 	{
-		// stops / in deco
+		// YES - stops / in deco
 
 		// check if already at last stop depth or shallower
-		if( char_bottom_depth <= char_I_depth_last_deco)
+		if( char_depth_bottom <= char_I_depth_last_deco)
 		{
-			// YES
-			ascent = 0;
-			final  = char_bottom_depth;
+			// YES - final ascent part only
+			ascent_time = char_depth_bottom;
 		}
 		else
 		{
-			// NO
-			ascent = char_bottom_depth - char_I_depth_last_deco;
-			final  = char_I_depth_last_deco;
+			// NO  - ascent part from bottom to last stop
+			ascent_time = (char_depth_bottom - char_I_depth_last_deco) / char_I_ascent_speed + 1;
+
+			//     - ascent part from last stop to surface at 1 meter per minute
+			ascent_time += char_I_depth_last_deco;
 		}
+
+		// add all stop times
+		for( i=0; i < NUM_STOPS && internal_deco_depth[i]; i++ )
+			ascent_time += internal_deco_time[i];
+
+		// limit result to display max.
+		if( ascent_time > 999) ascent_time = 999;
+
+		// tag result as invalid if there is an overflow in the stops table
+		if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) ascent_time |= INT_FLAG_INVALID;
 	}
 	else
 	{
-		// no stops / within NDL
-		ascent = char_bottom_depth;
-		final  = 0;
+		// NO - no stops / within NDL
+		ascent_time = char_depth_bottom / char_I_ascent_speed + 1;
 	}
-
-
-	// initialize ascent time
-	ascent_time = 0;
-
-	// time for the ascent part (bottom to last stop), if existing
-	if( ascent ) ascent_time += ascent / char_I_ascent_speed + 1;
-
-	// add time for the final ascent (last stop to surface) at 1 min/m
-	ascent_time += final;
-
-	// add all stop times
-	for( x=0; x < NUM_STOPS && internal_deco_depth[x]; x++ )
-		ascent_time += internal_deco_time[x];
-
-	// limit result to display max.
-	if( ascent_time > 999) ascent_time = 999;
-
-	// tag result as invalid if there is an overflow in the stops table
-	if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) ascent_time |= INT_FLAG_INVALID;
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 // clear_deco_table
 //
+// Modified: internal_deco_time[]    stop durations
+//           internal_deco_depth[]   stop depths
+//           internal_deco_gas[]     gases used at stops
 //
 static void clear_deco_table(void)
 {
-	overlay unsigned char x;
-
-	for( x = 0; x < NUM_STOPS; ++x )
+	for( i = 0; i < NUM_STOPS; ++i )
 	{
-		internal_deco_time [x] = 0;
-		internal_deco_depth[x] = 0;
-		internal_deco_gas[x]   = 0;
+		internal_deco_time [i] = 0;
+		internal_deco_depth[i] = 0;
+		internal_deco_gas[i]   = 0;
 	}
 
 	// clear stop table overflow warning
-	char_O_deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW;
+	deco_warnings &= ~DECO_WARNING_STOPTABLE_OVERFLOW;
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // update_deco_table
 //
-// Add time to a stop at sim_depth_limit
+// Add time to a stop at char_depth_sim
 //
 // It is possible to create stops with a duration of 0 minutes, e.g. to
 // note a gas change "on the fly" while ascending. Therefore the criteria
 // to have reached the end of the list is depth == 0.
 //
-// Input:   sim_depth_limit       : stop's depth, in meters
-//          sim_gas_current       : gas used at stop, as index 1..5 or 0 for gas 6
-//          time_increment        : number of minutes to add to the stop
-//
-// Updated: internal_deco_depth[] : depth    (in meters)  of each stop
-//          internal_deco_time [] : time     (in minutes) of each stop
-//          internal_deco_gas  [] : gas used (index 1-5)  at each stop
+// Input:   char_depth_sim         stop's depth, in meters
+//          sim_gas_current_num    gas used at stop, as index 1..5 or 0 for gas 6
+//          time_increment         number of minutes to add to the stop
+//
+// Updated: internal_deco_depth[]  depth    (in meters)  of each stop
+//          internal_deco_time []  time     (in minutes) of each stop
+//          internal_deco_gas  []  gas used (index 1-5)  at each stop
 //
 static unsigned char update_deco_table(PARAMETER unsigned char time_increment)
 {
 	overlay unsigned char x;
 
-	assert( sim_depth_limit > 0 );		// no stop at surface
+	assert( char_depth_sim > 0 );		// no stop at surface
 
 	// loop through internal deco table
 	for( x = 0; x < NUM_STOPS; ++x )
@@ -3124,11 +3790,11 @@
 		// real stop's depth), relocate the deco stop to the depth of the last gas change.
 		// The resulting combined stop's duration will be the sum of the configured gas
 		// change time plus the duration of the deco stop itself.
-		if( internal_deco_depth[x] && (sim_depth_limit > internal_deco_depth[x]) )
-			sim_depth_limit = internal_deco_depth[x];
+		if( internal_deco_depth[x] && (char_depth_sim > internal_deco_depth[x]) )
+			char_depth_sim = internal_deco_depth[x];
 
 		// Is there already a stop entry for our current depth?
-		if( internal_deco_depth[x] == sim_depth_limit )
+		if( internal_deco_depth[x] == char_depth_sim )
 		{
 			// Yes - increment stop time if possible
 			// Stop time entries are limited to 99 minutes because of display constraints.
@@ -3145,8 +3811,8 @@
 		if( internal_deco_depth[x] == 0 )
 		{
 			internal_deco_time[x]  = time_increment;		// initialize entry with first stop's time,
-			internal_deco_depth[x] = sim_depth_limit;		// ... depth, and
-			internal_deco_gas[x]   = sim_gas_current;		// ... gas
+			internal_deco_depth[x] = char_depth_sim;		// ... depth, and
+			internal_deco_gas[x]   = sim_gas_current_num;	// ... gas
 			return 1;										// return with status 'success'
 		}
 	}
@@ -3154,7 +3820,7 @@
 	// If program flow passes here, all deco table entries are used up.
 
 	// set overflow warning
-	char_O_deco_warnings |= DECO_WARNING_STOPTABLE_OVERFLOW;
+	deco_warnings |= DECO_WARNING_STOPTABLE_OVERFLOW;
 
 	// return with status 'failed'.
 	return 0;
@@ -3162,16 +3828,27 @@
 
 
 //////////////////////////////////////////////////////////////////////////////
-// calc_desaturation_time
+// calc_desaturation_time_helper
 //
 // Helper function
 //
+// Input:  pres_actual      current tissue pressure
+//         pres_target      target  tissue pressure
+//         var_ht           half-time of the tissue
+//         desat_factor     desaturation factor
+//
+// Output: int_time         time needed by tissue to reach target pressure
+//
 static void calc_desaturation_time_helper(void)
 {
-	if( pres_actual > pres_target )		// check if actual pressure is higher then target pressure
-	{									// YES - compute remaining time
+	// check if actual pressure is higher then target pressure
+	if( pres_actual > pres_target )
+	{
+		// YES - compute remaining time
+
 		overlay float pres_ratio;
 
+		// compute pressure ratio to archive
 		pres_ratio = pres_actual / pres_target;
 
 		// Compute desaturation time with result rounded up to multiples of 10 minutes.
@@ -3179,72 +3856,131 @@
 		// one minute steps any more but get constantly re-computed according to current
 		// ambient pressure and may therefor make steps of several minutes forwards and
 		// backwards as ambient pressure rises/falls and N2/He ratio is being adjusted.
-		int_time = (unsigned int)( (var_ht * log(pres_ratio) / desat_factor) + 0.9 );
+		int_time = (unsigned short)( (var_ht * log(pres_ratio) / desat_factor) + 0.9 );
 	}
 	else
-	{									// NO  - desaturation state reached, no remaining time
+	{
+		// NO  - desaturation state reached, no remaining time
 		int_time = 0;
 	}
 }
 
+
 /////////////////////////////////////////////////////////////////////////////
 // calc_desaturation_time
 //
-// Inputs:  int_I_pres_surface, ppWater, char_I_desaturation_multiplier
-// Outputs: int_O_desaturation_time, int_O_nofly_time
-//
-// Calculate the time needed for the tissues to equilibrate with surface pressure
+// Calculates the time needed for the tissues to equilibrate with
+// surface pressure and the no-fly / no-altitude time.
+//
+// Input:   int_I_pres_surface
+//          char_I_desaturation_multiplier
+//
+// Output:  int_O_desaturation_time
+//          int_O_nofly_time
 //
 void calc_desaturation_time(void)
 {
+	overlay float P_ambient_altitude;
+
 	assert( 800 < int_I_pres_surface             && int_I_pres_surface             <  1100 );
 	assert( 0   < char_I_desaturation_multiplier && char_I_desaturation_multiplier <=  100 );
 
 
-	// safety limit to prevent eventual infinite looping (bricking the OSTC)
-	if( int_I_pres_surface < 500) int_I_pres_surface = 500;
-
-	// fraction of inert gases in respired air
-	real_N2_ratio  = 0.7902;
-	real_He_ratio  = 0.0;
-
-	// surface pressure in bar
-	pres_surface   = 0.001    * int_I_pres_surface;
-
-	// partial pressure of N2 in respired air
-	N2_equilibrium = real_N2_ratio * (pres_surface - ppWater);
-
-	// pre-computed term for later use: 10 [Min] * 0.01 [%] * 0.6931 [=log(2)] * ...
-	desat_factor   = 0.06931  * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR;
+	// safeguard and convert surface pressure
+	if( int_I_pres_surface < 500) pres_surface = 0.5;
+	else                          pres_surface = 0.001 * int_I_pres_surface;
+
+	// calculate partial pressure of N2 in respired air at surface pressure
+	calc_N2_equilibrium();
+
+	// get, safeguard and convert the saturation and desaturation factors
+	get_saturation_factors();
+
+	// pre-computed term for later use: 10 [Min] * 0.6931 [=log(2)] * 1 [Desat Factor] * ...
+	desat_factor = (6.931 * SURFACE_DESAT_FACTOR) * float_desaturation_multiplier;
 
 	// initialize vars
 	int_O_desaturation_time = 0;
 	int_O_nofly_time        = 0;
 
-
+	// get selected target altitude
+	switch( char_I_altitude_wait )
+	{
+		case 1:  P_ambient_altitude = P_ambient_1000m;	break;
+		case 2:  P_ambient_altitude = P_ambient_2000m;	break;
+		case 3:  P_ambient_altitude = P_ambient_3000m;	break;
+		default: P_ambient_altitude = P_ambient_fly;	break;
+	}
+
+	// loop over all compartments in order slowest to fastest
 	for( ci = NUM_COMP; ci > 0; )
 	{
-		overlay float        pres_tissue_max;
-		overlay float        P_ambient_altitude;
-		overlay signed char  search_direction;
-		overlay unsigned int nofly_N2   =  0;
-		overlay unsigned int nofly_He   =  0;
-		overlay unsigned int nofly_last = ~0;
-
-
+		overlay float          pres_tissue_max;
+		overlay unsigned short nofly_last = ~0;
+		overlay unsigned short nofly_N2   =  0;
+
+#ifdef _helium
+		overlay signed char    search_direction;
+		overlay unsigned short nofly_He   =  0;
+#endif
+
+
+		// decrement compartment index
 		ci -= 1;
 
+		// get the Buhlmann halftimes and coefficients
 		read_Buhlmann_ht();
 		read_Buhlmann_coefficients();
 
-		// get selected target altitude
-		switch( char_I_altitude_wait )
-		{
-			case 1:  P_ambient_altitude = P_ambient_1000m;	break;
-			case 2:  P_ambient_altitude = P_ambient_2000m;	break;
-			case 3:  P_ambient_altitude = P_ambient_3000m;	break;
-			default: P_ambient_altitude = P_ambient_fly;	break;
-		}
+
+		//
+		// Desaturation time
+		//
+
+		// calculate desaturation time for N2 in tissue,
+		// desaturated state is defined as residual tissue pressure <= 1.05 x ppN2 respired
+
+		// current tissue pressure above equilibrium pressure
+		pres_actual = real_pres_tissue_N2[ci] - N2_equilibrium;
+
+		// target pressure above equilibrium pressure
+		pres_target = 0.05 * N2_equilibrium;
+
+		// half-time of the current tissue
+		var_ht = var_N2_ht;
+
+		// calculate desaturation time
+		calc_desaturation_time_helper();
+
+		// store desaturation time if it is longer than longest found so far
+		if( int_time > int_O_desaturation_time) int_O_desaturation_time = int_time;
+
+
+#ifdef _helium
+
+		// calculate desaturation time for He in the tissue,
+		// desaturated state is defined as residual tissue pressure <= 0.05 x ppN2 respired
+
+		// actual tissue pressure above equilibrium: equilibrium for He is 0 bar
+		pres_actual = real_pres_tissue_He[ci];
+
+		// target pressure above equilibrium pressure: use same target pressure as for N2
+		pres_target = 0.05 * N2_equilibrium;
+
+		// half-time of the current tissue
+		var_ht      = var_He_ht;
+
+		// calculate desaturation time
+		calc_desaturation_time_helper();
+
+		// store desaturation time if it is longer than longest found so far
+		if( int_time > int_O_desaturation_time) int_O_desaturation_time = int_time;
+
+#endif
+
+		//
+		// no-fly time
+		//
 
 		// Target pressure for the tissue is the Buhlmann limit. We use the Buhlmann
 		// coefficients for N2 also for He because it is easier to calculate and the
@@ -3252,53 +3988,18 @@
 		// safe side, too.
 		pres_tissue_max = (P_ambient_altitude/var_N2_b + var_N2_a);
 
-		// Adjust target pressure in case the GF model is in use by GF-high
-		if( char_I_deco_model != 0 )
-			pres_tissue_max = P_ambient_altitude +
-			                  0.01 * char_I_GF_High_percentage * (pres_tissue_max - P_ambient_altitude);
-
-
-		//
-		// Desaturation time
-		//
-
-		// N2: actual amount of tissue pressure above equilibrium.
-		pres_actual = pres_tissue_N2[ci] - N2_equilibrium;
-
-		// N2: half-time of the current tissue
-		var_ht = var_N2_ht;
-
-		// Calculate desaturation time for N2 in tissue.
-		// Desaturated state is defined as residual tissue pressure <= 1.05 x ppN2 respired
-
-		pres_target = 0.05 * N2_equilibrium;
-
-		calc_desaturation_time_helper();
-
-		if( int_time > int_O_desaturation_time) int_O_desaturation_time = int_time;
-
-
-		// He: actual amount of tissue pressure above equilibrium: equilibrium for He is 0 bar
-		pres_actual = pres_tissue_He[ci];
-
-		// He: half-time of the current tissue
-		var_ht      = var_He_ht;
-
-		// Calculate desaturation time for He in the tissue.
-		// Desaturated state is defined as residual tissue pressure <= 0.05 x ppN2 respired
-
-		pres_target = 0.05 * N2_equilibrium;
-
-		calc_desaturation_time_helper();
-
-		if( int_time > int_O_desaturation_time) int_O_desaturation_time = int_time;
-
-
-		//
-		// no-fly time
-		//
-
-		// initialize split_N2_He in case there was a hard reboot / memory clear.
+		// adjust target pressure by GF-high in case the GF model is in use, but not
+		// for the no-fly time as it's target pressure is hard to reach anyhow
+		if( char_I_deco_model && char_I_altitude_wait )
+		    pres_tissue_max = P_ambient_altitude +
+		                      0.01 * char_I_GF_High_percentage * (pres_tissue_max - P_ambient_altitude);
+
+
+#ifdef _helium
+
+		//---- Variant with Helium -------------------------------------------
+
+		// initialize split_N2_He in case there was a hard reboot / memory clear
 		if( split_N2_He[ci] == 0 ) split_N2_He[ci] = 90;
 
 		// initialize search direction
@@ -3306,46 +4007,56 @@
 
 		for(;;)
 		{
-			// N2: actual amount of tissue pressure above equilibrium.
-			pres_actual = pres_tissue_N2[ci] - N2_equilibrium;
-
-			// N2: half-time of the current tissue
-			var_ht = var_N2_ht;
-
 			// Calculate no-fly time for N2 in the tissue.
 			// Flying is permitted when the N2 pressure fits into the assigned fraction above equilibrium.
 
+			// current tissue pressure above equilibrium
+			pres_actual = real_pres_tissue_N2[ci] - N2_equilibrium;
+
+			// target pressure above equilibrium pressure, weighted by N2/He split
 			pres_target = (split_N2_He[ci] * 0.01) * (pres_tissue_max - N2_equilibrium);
 
-			if( pres_target < 0.0 )						// check if desaturation to fly target is possible
+			// half-time of the current tissue
+			var_ht = var_N2_ht;
+
+			// check if desaturation to target pressure is possible at all
+			if( pres_target < 0.0 )
 			{
-				int_O_nofly_time = 288;					// NO  - set no-fly time to 288 * 10 min = 48 h
-				break;									// done for this compartment
+				// NO  - set no-fly time to 288 * 10 min = 48 h
+				int_O_nofly_time = 288;
+				break;
 			}
 			else
 			{
+				// YES - calculate desaturation time
 				calc_desaturation_time_helper();
+
+				// store time found
 				nofly_N2 = int_time;
 			}
 
-			// He: actual amount of tissue pressure above equilibrium - equilibrium for He is 0 bar.
-			pres_actual = pres_tissue_He[ci];
-
-			// He: half-time of the current tissue
+			// calculate no-fly time for He in the tissue,
+			// flying is permitted when the He pressure fits into the assigned fraction
+
+			// current tissue pressure above equilibrium: equilibrium for He is 0 bar
+			pres_actual = real_pres_tissue_He[ci];
+
+			// target pressure above equilibrium pressure, weighted by N2/He split
+			pres_target = ((100 - split_N2_He[ci]) * 0.01) * (pres_tissue_max - N2_equilibrium);
+
+			// half-time of the current tissue
 			var_ht      = var_He_ht;
 
-			// Calculate no-fly time for He in the tissue.
-			// Flying is permitted when the He pressure fits into the assigned fraction.
-
-			pres_target = (0.01 * (100 - split_N2_He[ci])) * (pres_tissue_max - N2_equilibrium);
-
+			// calculate desaturation time
 			calc_desaturation_time_helper();
+
+			// store time found
 			nofly_He = int_time;
 
 
 			// Because the sum of N2 and He tissue pressures needs to fit into the Buhlmann limit for
 			// no-fly time calculation, each gas gets assigned a fraction of the available total pressure
-			// limit. The optimum split between the two gases can not be computed by a single formular,
+			// limit. The optimum split between the two gases can not be computed by a single formula,
 			// because this would require the inversion of a function with two exponential terms, which is
 			// not possible. We do not want to do a computational complex simulation here like it is done
 			// in the deco calculation code (although we tackle the same base problem here), so we just let
@@ -3362,17 +4073,21 @@
 				// optimum now, or if we are at the upper stop limit of split_N2_He
 				if( (search_direction < 0) || (split_N2_He[ci] == 99) )
 				{
-					// Either the just completed iteration was more close to the optimum or the one before
-					// was, so we take the best (i.e. shortest) time of both as the final no-fly time.
+					// either the just completed iteration was more close to the optimum or the one before
+					// was, so we take the best (i.e. shortest) time of both as the final no-fly time
 					int_O_nofly_time = (nofly_N2 < nofly_last) ? nofly_N2 : nofly_last;
+
+					// done
 					break;
 				}
 
 				// store the no-fly time found in this iteration
 				nofly_last = nofly_N2;
 
-				// increase the N2 fraction of the split and set search direction towards more N2
+				// increase the N2 fraction of the split
 				split_N2_He[ci]  +=  1;
+
+				// set search direction towards more N2
 				search_direction  = +1;
 			}
 			else
@@ -3381,51 +4096,86 @@
 				// optimum now, or if we are at the lower stop limit of split_N2_He
 				if( (search_direction > 0) || (split_N2_He[ci] == 1) )
 				{
-					// Either the just completed iteration was more close to the optimum or the one before
-					// was, so we take the best (i.e. shortest) time of both as the final no-fly time.
+					// either the just completed iteration was more close to the optimum or the one before
+					// was, so we take the best (i.e. shortest) time of both as the final no-fly time
 					int_O_nofly_time = (nofly_He < nofly_last) ? nofly_He : nofly_last;
+
+					// done
 					break;
 				}
 
 				// store the no-fly time found in this iteration
 				nofly_last = nofly_He;
 
-				// decrease the N2 fraction of the split and set search direction towards less N2
+				// decrease the N2 fraction of the split
 				split_N2_He[ci]  -=  1;
+
+				// set search direction towards less N2
 				search_direction  = -1;
 			}
 
 		} // for(;;)
 
+#else
+
+		//---- Variant without Helium ----------------------------------------
+
+		// current tissue pressure above equilibrium
+		pres_actual = real_pres_tissue_N2[ci] - N2_equilibrium;
+
+		// target pressure above equilibrium pressure
+		pres_target = pres_tissue_max - N2_equilibrium;
+
+		// half-time of the current tissue
+		var_ht = var_N2_ht;
+
+		// check if desaturation to target pressure is possible at all
+		if( pres_target < 0.0 )
+		{
+			// NO  - set no-fly time to 288 * 10 min = 48 h
+			int_O_nofly_time = 288;
+		}
+		else
+		{
+			// YES - calculate desaturation time
+			calc_desaturation_time_helper();
+
+			//     - extend desaturation time if this tissue needs
+			//       more time than already found to be needed
+			if( int_time > int_O_nofly_time ) int_O_nofly_time = int_time;
+		}
+
+#endif
+
 	} // for(compartments)
 
 
-	// Rescale int_O_desaturation_time and int_O_nofly_time to full minutes for display purpose
+	// rescale int_O_desaturation_time and int_O_nofly_time to full minutes for display purpose
 	int_O_desaturation_time *= 10;
 	int_O_nofly_time		*= 10;
 
-	// Limit int_O_desaturation_time and int_O_nofly_time to 5999 = 99 hours + 59 minutes
-	// because of display space constraints and rounding done above.
+	// limit int_O_desaturation_time and int_O_nofly_time to 5999 = 99 hours + 59 minutes
+	// because of display space constraints and rounding done above
 	if( int_O_desaturation_time > 5999 ) int_O_desaturation_time = 5999;
 	if( int_O_nofly_time        > 5999 ) int_O_nofly_time        = 5999;
 
 
-	// Clear the microbubbles warning when the current gradient factor is < 100%.
+	// Clear the micro bubbles warning when the current gradient factor is < 100%.
 	// The current gradient factor is calculated by calc_interval() while not in diving mode.
 	// As the locked warning will stay set, this will cause the warning be be displayed in
 	// attention color instead of warning color.
-	if( int_O_gradient_factor < 100 )
-		char_O_deco_warnings &= ~DECO_WARNING_MBUBBLES;
+	if( int_O_lead_supersat < 100 )
+		deco_warnings &= ~DECO_WARNING_MBUBBLES;
 
 	// clear some warnings when the desaturation time has become zero
 	if( int_O_desaturation_time == 0 )
-	    char_O_deco_warnings &= ~(   DECO_WARNING_IBCD     + DECO_WARNING_IBCD_lock
-	                               + DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock
-	                               + DECO_WARNING_OUTSIDE  + DECO_WARNING_OUTSIDE_lock
-	                               + DECO_ATTENTION_OUTSIDE                             );
-
+	    deco_warnings &= ~(   DECO_WARNING_IBCD     + DECO_WARNING_IBCD_lock
+	                        + DECO_WARNING_MBUBBLES + DECO_WARNING_MBUBBLES_lock
+	                        + DECO_WARNING_OUTSIDE  + DECO_WARNING_OUTSIDE_lock
+	                        + DECO_ATTENTION_OUTSIDE                             );
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // Calculate desaturation of the real tissues for a given time interval
 //
@@ -3433,14 +4183,14 @@
 //          If in doubt, use this function only inside a context surrounded with
 //          push_tissues_to_vault() / pull_tissues_from_vault() !
 //
-// Input:    int_I_pres_surface : surface pressure in mbar
-//           time_interval      : time interval in minutes, must be limited to 254 at max
-//
-// Modified: tissue pressures   : N2 and He pressures of the tissues
-//           CNS_fraction       : current CNS value
-//           ceiling            : minimum allowed depth in mbar relative pressure
-//           lead_supersat      : supersaturation of the leading tissue
-//           int_O_gradient_factor : current GF factor
+// Input:    int_I_pres_surface     surface pressure in mbar
+//           time_interval          time interval in minutes, must be limited to 254 at max
+//
+// Modified: tissue pressures       N2 and He pressures of the tissues
+//           CNS_fraction_real      current real CNS value
+//           ceiling                minimum allowed depth in mbar relative pressure
+//           lead_supersat          supersaturation of the leading tissue (float)
+//           int_O_lead_supersat    supersaturation of the leading tissue (integer)
 //
 static void calc_interval(PARAMETER unsigned char time_interval)
 {
@@ -3451,20 +4201,25 @@
 	assert(   0 <  char_I_desaturation_multiplier && char_I_desaturation_multiplier <=  100 );
 
 
-	// safety limit to prevent eventual infinite looping (bricking the OSTC)
-	if( int_I_pres_surface < 500) int_I_pres_surface = 500;		// min. surface pressure = 500 mbar
-
-	// setup input data for deco routines
-	real_pres_respiration = pres_surface = 0.001 * int_I_pres_surface;
-
-	real_N2_ratio  = 0.7902;											// according to Buhlmann
-	N2_equilibrium = real_N2_ratio * (pres_surface          - ppWater);	// used for N2 tissue graphics scaling
-	ppN2           = real_N2_ratio * (real_pres_respiration - ppWater);
-	ppHe           = 0.0;
-
-	float_desaturation_multiplier = 0.01 * char_I_desaturation_multiplier * SURFACE_DESAT_FACTOR;
-	float_saturation_multiplier   = 0.01 * char_I_saturation_multiplier;
-
+	// safeguard and convert surface pressure
+	if( int_I_pres_surface < 500) pres_surface = 0.500;
+	else                          pres_surface = 0.001 * int_I_pres_surface;
+
+	// set breathed pressure to surface pressure
+	real_pres_respiration = pres_surface;
+
+	// calculate partial pressure of N2 in respired air at surface pressure
+	calc_N2_equilibrium();
+
+	// calculate partial pressures (0.7902 is fraction of N2 in atmosphere as of Buhlmann)
+	ppN2 = N2_equilibrium;
+	ppHe = 0.0;
+
+	// get, safeguard and convert the saturation and desaturation factors
+	get_saturation_factors();
+
+	// adjust desaturation factor to surface mode
+	float_desaturation_multiplier *= SURFACE_DESAT_FACTOR;
 
 	// Calculate the tissues:
 	// Because calc_tissues() can calculate for 127 minutes at max,
@@ -3476,15 +4231,15 @@
 	if( time > 127)
 	{
 		// do a full 127 minutes on the real tissues
-		tissue_increment = TISSUE_FLAG | 127;
+		tissue_increment = TISSUE_SELECTOR | 127;
 		calc_tissues();
 
-		// determine the remaining part
+		// determine the remaining time
 		time -= 127;
 	}
 
-	// program the remaining part (or full part if not exceeding 127 minutes)
-	tissue_increment = TISSUE_FLAG | time;
+	// program the remaining time (or full time if not exceeding 127 minutes) on the real tissues
+	tissue_increment = TISSUE_SELECTOR | time;
 
 	// update the N2 and He pressures in the tissues
 	calc_tissues();
@@ -3500,549 +4255,831 @@
 	{
 		if( time > 9 )
 		{
-			CNS_fraction *= 0.925874712;	// Half-time = 90min -> 10 min: (1/2)^(1/9)
-			time         -= 10;				// fast speed looping
+			CNS_fraction_real *= 0.925874712;	// half-time = 90 min -> 10 min: (1/2)^(1/9)
+			time              -= 10;			// fast speed looping
 		}
 		else
 		{
-			CNS_fraction *= 0.992327946;	// Half-time = 90min ->  1 min: (1/2)^(1/90)
-			time         -= 1;				// slow speed looping
+			CNS_fraction_real *= 0.992327946;	// half-time = 90 min ->  1 min: (1/2)^(1/90)
+			time              -= 1;				// slow speed looping
 		}
 	}
 
-	// compute integer copy of CNS value
-	convert_CNS_for_display();
-
-	// calculate GF value (for a GF high of 100%)
-	calc_limit(1.0);
-
-	// compute integer copy of GF value
-	convert_GF_for_display();
+	// convert the CNS value to integer
+	convert_cur_CNS_for_display();
+
+	// calculate the supersaturation of the leading tissue, the
+	// negative argument puts calc_limit() into surface mode
+	// Attention: do not pass char_I_GF_High_percentage as an argument
+	//            here because it is not configured outside dive mode
+	calc_limit(-1.0);
+
+	// convert the saturation value of the leading tissue to integer
+	convert_sat_for_display();
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
 // calc_CNS
 //
-// Input:    char_ppO2        : current ppO2 [decibars]
-//           tissue_increment : time increment and tissue selector
-//
-// Modified:     CNS_fraction   accumulated CNS (real      tissue context)
-//           sim_CNS_fraction : accumulated CNS (simulated tissue context)
+// Input:    char_ppO2          current ppO2 [in 0.1 bars]
+//           tissue_increment   time increment and tissue selector
+//
+// Modified: CNS_fraction_real  accumulated CNS (real      tissue context)
+//           CNS_fraction_sim   accumulated CNS (simulated tissue context)
 //
 static void calc_CNS(void)
 {
 	overlay float CNS_fraction_inc;			// increment of CNS load, 0.01 = 1%
-	overlay float time_factor;				// factor for time increment
-
-	assert( char_ppO2 > 15 );
-
-	// adjust time factor to 2 seconds (factor = 1.0) or minute-based interval (factor = N * 30.0)
-	if( tissue_increment & TIME_MASK ) time_factor = (float)(tissue_increment & TIME_MASK) * 30.0;
-	else                               time_factor =                                          1.0;
-
-	//------------------------------------------------------------------------
-	// No CNS increase below 0.5 bar ppO2
-	     if (char_ppO2 <  50) CNS_fraction_inc = 0.0;
-	//------------------------------------------------------------------------
-	// Below (and including) 1.60 bar
-	else if (char_ppO2 <  61) CNS_fraction_inc = time_factor/(-533.07 * char_ppO2 + 54000.0);
-	else if (char_ppO2 <  71) CNS_fraction_inc = time_factor/(-444.22 * char_ppO2 + 48600.0);
-	else if (char_ppO2 <  81) CNS_fraction_inc = time_factor/(-355.38 * char_ppO2 + 42300.0);
-	else if (char_ppO2 <  91) CNS_fraction_inc = time_factor/(-266.53 * char_ppO2 + 35100.0);
-	else if (char_ppO2 < 111) CNS_fraction_inc = time_factor/(-177.69 * char_ppO2 + 27000.0);
-	else if (char_ppO2 < 152) CNS_fraction_inc = time_factor/( -88.84 * char_ppO2 + 17100.0);
-	else if (char_ppO2 < 167) CNS_fraction_inc = time_factor/(-222.11 * char_ppO2 + 37350.0);
-	//------------------------------------------------------------------------
-	// Arieli et all.(2002): Modeling pulmonary and CNS O2 toxicity:
-	// J Appl Physiol 92: 248--256, 2002, doi:10.1152/japplphysiol.00434.2001
-	// Formula (A1) based on value for 1.55 and c=20
-	// example calculation: Sqrt((1.7/1.55)^20)*0.000404
-	else if (char_ppO2 < 172) CNS_fraction_inc = time_factor * 0.00102;
-	else if (char_ppO2 < 177) CNS_fraction_inc = time_factor * 0.00136;
-	else if (char_ppO2 < 182) CNS_fraction_inc = time_factor * 0.00180;
-	else if (char_ppO2 < 187) CNS_fraction_inc = time_factor * 0.00237;
-	else if (char_ppO2 < 192) CNS_fraction_inc = time_factor * 0.00310;
-	else if (char_ppO2 < 198) CNS_fraction_inc = time_factor * 0.00401;
-	else if (char_ppO2 < 203) CNS_fraction_inc = time_factor * 0.00517;
-	else if (char_ppO2 < 233) CNS_fraction_inc = time_factor * 0.02090;
-	else                      CNS_fraction_inc = time_factor * 0.04820; // value for 2.5 bar, used for 2.33 bar and above
+
+
+	// calculate CNS increment for 2 seconds interval
+	if( char_ppO2 > 160 )
+	{
+		// step-wise CNS increment
+
+		// calculate index for increment look-up
+		cns_i = (char_ppO2 - 161) / 5;	// integer division
+
+		// read coefficient (increment)
+		read_CNS_c_coefficient();
+
+		// re-scale coefficient from storage format in [1/100000] to productive value
+		CNS_fraction_inc = (float)var_cns_c / 100000.0;
+	}
+	else if( char_ppO2 > 50 )
+	{
+		// range wise CNS increment approximation
+
+		// calculate index for approximation coefficients look-up
+		cns_i = (char_ppO2 - 51) / 10;	// integer division
+
+		// read coefficients
+		read_CNS_ab_coefficient();
+
+		// calculate the CNS increment
+		CNS_fraction_inc = 1.0 / (var_cns_a * char_ppO2 + var_cns_b );
+	}
+	else
+	{	// no increment up to 0.5 bar ppO2
+		CNS_fraction_inc = 0.0;
+	}
+
+	// apply a time factor in case of minute-based interval (factor = N * 30.0)
+	if( tissue_increment & TIME_MASK )
+	{
+		CNS_fraction_inc *= (float)(tissue_increment & TIME_MASK) * 30.0;
+	}
 
 	// update the CNS accumulator
-	if( tissue_increment & TISSUE_FLAG )     CNS_fraction += CNS_fraction_inc;	// real tissues
-	else                                 sim_CNS_fraction += CNS_fraction_inc;	// simulated tissues
+	if   ( tissue_increment & TISSUE_SELECTOR ) CNS_fraction_real += CNS_fraction_inc;	// real tissues
+	else                                        CNS_fraction_sim  += CNS_fraction_inc;	// simulated tissues
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// calc_due_by_depth_time_sac       (Helper Function saving Code Space)
+//
+// Calculates the gas volume required for a given depth, time and usage (SAC)
+// rate. It uses a fixed surface pressure of 1.0 bar to deliver stable results
+// when used through the deco calculator.
+//
+// Input:  gas_needs_float_depth   depth     in meters
+//         gas_needs_float_time    time      in minutes
+//         gas_needs_stop_usage    gas usage in liters per minute at surface pressure
+//
+// Output: gas_needs_volume_due    required gas volume in liters
+//
+static void calc_due_by_depth_time_sac(void)
+{
+	gas_needs_volume_due = (gas_needs_float_depth * METER_TO_BAR + 1.0) * gas_needs_float_time * gas_needs_stop_usage;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// calc_gas_needs_ascent
+//
+// calculates the gas needs along the ascent
+//
+// Input:  char_depth_bottom         depth of the bottom segment
+//         char_I_bottom_time        duration of the bottom segment
+//         char_I_extra_time         extra bottom time for fTTS / delayed ascent
+//         float_ascent_speed        ascent speed, in meters/minute
+//         internal_deco_depth[]     depth of the stops
+//         internal_deco_time[]      duration of the stops
+//         internal_deco_gas[]       gas breathed at the stops
+//         NDL_time                  remaining NDL time, used to adjust speed of final ascent
+//         char_I_SAC_work           gas consumption during bottom part and initial ascent, in liters/minute
+//         char_I_SAC_deco           gas consumption during stops and following ascents, in liters/minute
+//         char_I_gas_avail_size[]   size of the tanks for gas 1-5, in liters
+//         char_I_gas_avail_pres[]   fill pressure of the tanks
+//
+// Output: gas_volume_need[]         amount of gas needed, in liters
+//
+static void calc_gas_needs_ascent(void)
+{
+	switch (gas_needs_next_phase)
+	{
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_INIT:
+
+		// set index to the first stop table entry
+		gas_needs_stop_index = 0;
+
+		// clear the gas volume needs
+		for( i = 0; i < NUM_GAS; ++i ) gas_volume_need[i] = 0.0;
+
+#ifdef _rx_functions
+		// only for OSTC TR model with TR functions enabled
+		if( main_status & TR_FUNCTIONS )
+		{
+			// invalidate pressure needs to pressure readings
+			int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL;
+			int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL;
+		}
+#endif
+
+		// terminate if in loop mode (CCR, pSCR) as there are no gas needs to calculate,
+		// else continue with the gas needs of the bottom segment
+		if   ( deco_status & MODE_LOOP ) gas_needs_next_phase = GAS_NEEDS_DONE;
+		else                             gas_needs_next_phase = GAS_NEEDS_BOTTOM_SEGMENT;
+
+		break;
+
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_BOTTOM_SEGMENT:
+
+		// sim_gas_current_num   gas used during bottom segment (0, 1-5)
+		// char_depth_bottom     depth of the bottom segment
+
+		// get the gas used during bottom segment
+		gas_find_current();
+
+		// initialize variables
+		gas_needs_stop_gas_last = gas_needs_stop_gas = sim_gas_current_num;
+
+		// set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent
+		gas_needs_stop_usage = char_I_SAC_work;
+
+		// volumes are only calculated for gases 1-5, but not the manually configured one
+		if( gas_needs_stop_gas )
+		{
+			// set the bottom depth
+			gas_needs_float_depth = (float)char_depth_bottom;
+
+			// calculate either whole bottom time or just the fTTS/bailout extra time
+			gas_needs_float_time = ( main_status & CALCULATE_BOTTOM ) ? (float)char_I_bottom_time : (float)char_I_extra_time;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// take result
+			gas_volume_need[gas_needs_stop_gas-1] = gas_needs_volume_due;
+		}
+
+		// continue with initial ascent demand
+		gas_needs_next_phase = GAS_NEEDS_INITIAL_ASCENT;
+
+		break;
+
+
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_INITIAL_ASCENT:
+
+		// gas_needs_stop_gas    : gas from bottom segment
+		// char_depth_bottom     : depth of the bottom segment
+		// internal_deco_depth[0]: depth of the first stop, may be 0 if no stop exists
+
+		// get the data of the first stop
+		gas_needs_stop_depth = internal_deco_depth[0];
+		gas_needs_stop_time  = internal_deco_time[0];
+
+		// volumes are only calculated for gases 1-5, but not the manually configured one
+		if( gas_needs_stop_gas )
+		{
+			// compute distance between bottom and first stop
+			gas_needs_float_depth = (float)char_depth_bottom - (float)gas_needs_stop_depth;
+
+			// initial ascent exists only if ascent distance is > 0
+			if( gas_needs_float_depth > 0.0 )
+			{
+				// compute ascent time
+				gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
+
+				// compute average depth between bottom and first stop
+				gas_needs_float_depth = (float)char_depth_bottom - gas_needs_float_depth * 0.5;
+
+				// calculate gas demand
+				calc_due_by_depth_time_sac();
+
+				// add to overall demand
+				gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
+			}
+		}
+
+		// switch the usage (SAC rate) to deco usage rate
+		// for stops, intermediate and final ascent
+		gas_needs_stop_usage = char_I_SAC_deco;
+
+		// is there a (first) stop?
+		if( gas_needs_stop_depth )
+		{
+			// YES - continue with stop demand
+			gas_needs_next_phase = GAS_NEEDS_STOP;
+
+			break;
+		}
+		else
+		{
+			// NO - add demand of a 3 minutes safety stop at 5 meters, at least for contingency...
+			gas_needs_float_time  = 3.0;
+			gas_needs_float_depth = 5.0;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// add to overall demand
+			gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
+
+			// calculation finished
+			gas_needs_next_phase = GAS_NEEDS_DONE;
+
+			break;
+		}
+
+
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_STOP:
+
+		// correct stop depth if shallower than calculated stop depth and convert to float
+		gas_needs_float_depth = ( char_depth_bottom < gas_needs_stop_depth ) ? (float)char_depth_bottom : (float)gas_needs_stop_depth;
+
+		// get the gas on this stop
+		gas_needs_stop_gas = internal_deco_gas[gas_needs_stop_index];
+
+		// do we have a gas change?
+		if( gas_needs_stop_gas_last && (gas_needs_stop_gas != gas_needs_stop_gas_last) )
+		{
+			// YES - spend an additional char_I_gas_change_time on the old gas
+			gas_needs_float_time = (float)char_I_gas_change_time;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// add to overall demand
+			gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due;
+		}
+
+		// calculate demand of (new) gas for the full stop duration
+		if( gas_needs_stop_gas )
+		{
+			// get the duration of the stop
+			gas_needs_float_time = (float)gas_needs_stop_time;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// add to overall demand
+			gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
+		}
+
+		// Continue with the demand of the intermediate ascent to the next stop.
+		// If there is no further stop, it will divert by itself to final ascent.
+		gas_needs_next_phase = GAS_NEEDS_INTERMEDIATE_ASCENT;
+
+		break;
+
+
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_INTERMEDIATE_ASCENT:
+
+		// store last stop depth and last gas
+		gas_needs_stop_depth_last = gas_needs_stop_depth;
+		gas_needs_stop_gas_last   = gas_needs_stop_gas;
+
+		// check if end of stop table is reached
+		if( gas_needs_stop_index < NUM_STOPS-1 )
+		{
+			// NO - check if there is another stop entry
+			if( internal_deco_depth[gas_needs_stop_index+1] == 0 )
+			{
+				// NO - continue with final ascent demand
+				gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT;
+
+				break;
+			}
+			else
+			{
+				// YES - goto next stop entry
+				gas_needs_stop_index++;
+
+				// get the depth of the next stop entry
+				gas_needs_stop_depth = internal_deco_depth[gas_needs_stop_index];
+
+				// get the duration of the next stop
+				gas_needs_stop_time  = internal_deco_time[gas_needs_stop_index];
+			}
+		}
+		else
+		{
+			// YES - end of stop table reached
+			// We are stranded at some stop depth and do not know how many more
+			// stops there may be in front of us and how long they may be. So as
+			// as last resort to calculate at least something, we assume that the
+			// rest of the ascent will be done in deco final ascent pace, i.e. at
+			// 1 meter per minute. Because of the stop table overflow, the result
+			// will be flagged as being invalid later on.
+			//
+			gas_needs_next_phase = GAS_NEEDS_FINAL_ASCENT;
+
+			break;
+		}
+
+		// volumes are only calculated for gases 1-5, but not the manually configured one
+		if( gas_needs_stop_gas_last )
+		{
+			// compute distance between the two stops
+			gas_needs_float_depth = (float)(gas_needs_stop_depth_last - gas_needs_stop_depth);
+
+			// compute ascent time
+			gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
+
+			// compute average depth between the two stops
+			gas_needs_float_depth = (float)gas_needs_stop_depth_last - gas_needs_float_depth * 0.5;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// add to overall demand
+			gas_volume_need[gas_needs_stop_gas_last-1] += gas_needs_volume_due;
+		}
+
+		// continue with calculation stop demand
+		gas_needs_next_phase = GAS_NEEDS_STOP;
+
+		break;
+
+
+		//---------------------------------------------------------------------
+
+		case GAS_NEEDS_FINAL_ASCENT:
+
+		// gas_needs_float_depth: still holds depth of the last stop
+		// gas_needs_stop_gas   : still holds gas from last stop (0 or 1-5)
+
+		// volumes are only calculated for gases 1-5, but not the manually configured one
+		if( gas_needs_stop_gas )
+		{
+			// set ascent time dependent on deco status
+			if( NDL_time )
+			{
+				// within NDL - ascent with float_ascent_speed
+				//
+				// Remark: When calculating a bailout ascent, there may be stops
+				//         for gas changes although the dive is still within NDL
+				//         and final ascent thus does not need to be slowed down.
+				gas_needs_float_time = gas_needs_float_depth / float_ascent_speed;
+			}
+			else
+			{
+				// in deco - reduce ascent speed to 1 meter per minute
+				gas_needs_float_time = gas_needs_float_depth;
+			}
+
+			// set half-way depth
+			gas_needs_float_depth *= 0.5;
+
+			// calculate gas demand
+			calc_due_by_depth_time_sac();
+
+			// add to overall demand
+			gas_volume_need[gas_needs_stop_gas-1] += gas_needs_volume_due;
+		}
+
+		// calculation finished
+		gas_needs_next_phase = GAS_NEEDS_DONE;
+
+		break;
+
+	} // switch
 }
 
 
 //////////////////////////////////////////////////////////////////////////////
-// gas_volumes
-//
-// calculates volumes and required tank fill pressures for each gas.
-//
-// Input:	char_bottom_depth		depth of the bottom segment
-//			char_I_bottom_time		duration of the bottom segment
-//			char_I_extra_time		extra bottom time for fTTS / delayed ascent
-//			float_ascent_speed		ascent speed, in meters/minute
-//			internal_deco_depth[]	depth of the stops
-//			internal_deco_time[]	duration of the stops
-//			internal_deco_gas[]		gas breathed at the stops
-//			NDL_time				remaining NDL time, used to adjust speed of final ascent
-//			char_I_bottom_usage		gas consumption during bottom part and initial ascent, in liters/minute
-//			char_I_deco_usage		gas consumption during stops and following ascents, in liters/minute
-//			char_I_tank_size[]		size of the tanks for gas 1-5, in liters
-//			char_I_tank_pres_fill[]	fill pressure of the tanks
-//
-// Output:	int_O_ascent_volumes[]	 amount of gas needed, in liters
-//			int_O_ascent_pres_need[] in bar, + flags for fast evaluation by dive mode warnings:
-//											  2^15: pres_need >= pres_fill
-//											  2^14: pres_need >= press_fill * GAS_NEEDS_ATTENTION_THRESHOLD
-//											  2^11: pres_need == 0
-//											  2^10: pres_need is invalid
-//
-static void gas_volumes_helper_1(void)
+// calc_TR_functions
+//
+// Process Pressure Readings (OSTC TR only)
+//
+// Input:  todo
+//
+// Output: todo
+//
+#ifdef _rx_functions
+static void calc_TR_functions(void)
 {
-	// Calculate the gas volume needed at a given depth, time and usage (SAC rate).
-	// We use 1.0 for the surface pressure to have stable results when used through
-	// the deco calculator (simulation mode).
-	volume = (float_depth * METER_TO_BAR + 1.0) * float_time * char_usage;
-
-	return;
-}
-
-static void gas_volume_helper_2(void)
-{
-	// Convert a gas volume in liters given as a float into an integer number
-	// and computes the equivalent tank pressure in bar, including all flags.
-
-	if( volume >= 65534.5 )
-	{
-		int_volume    = 65535;
-		int_pres_need = 999 + INT_FLAG_WARNING; // 999 bar + warning flag for > pres_fill
-	}
-	else
+	// pressure warnings for reading 1, but only if enabled and pressure value available
+	if( (char_I_pressure_gas[0] > 0) && !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
 	{
-		overlay unsigned short tank_pres_fill = 10.0 * (unsigned short)char_I_tank_pres_fill[gas_num];
-
-		// No distinct rounding done here because volumes are not accurate to the single liter anyhow
-
-		// convert gas volumes to integers
-		int_volume    = (unsigned short)volume;
-
-		// compute how much pressure in the tank will be needed [in bar]  (integer-division)
-		int_pres_need = (unsigned short)(int_volume / char_I_tank_size[gas_num]);
-
-		// limit to 999 bar because of display constraints
-		if( int_pres_need > 999 ) int_pres_need = 999;
-
-		// set flags for fast evaluation by divemode check_for_warnings
-		if     ( int_pres_need ==                                              0 ) int_pres_need |= INT_FLAG_ZERO;
-		else if( int_pres_need >=                                 tank_pres_fill ) int_pres_need |= INT_FLAG_WARNING;
-		else if( int_pres_need >= GAS_NEEDS_ATTENTION_THRESHOLD * tank_pres_fill ) int_pres_need |= INT_FLAG_ATTENTION;
+		overlay unsigned short pressure_value = int_IO_pressure_value[0] & ~INT_FLAG_OUTDATED;
+
+		if( (char_I_pressure_gas[0] < 6 ) && !(int_O_pressure_need[0] & INT_FLAG_NOT_AVAIL) )
+		{
+			// not a diluent and need available: warning & attention by need
+			if     ( pressure_value <= int_O_pressure_need[0])
+			       int_IO_pressure_value[0] |= INT_FLAG_WARNING;
+			else if( pressure_value <= int_O_pressure_need[0] + int_O_pressure_need[0] / 2 )
+			       int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
+		}
+		else
+		{
+			// a diluent or need not available: warning & attention by fixed thresholds
+			if      ( pressure_value <= PRESSURE_LIMIT_WARNING   ) int_IO_pressure_value[0] |= INT_FLAG_WARNING;
+			else if ( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[0] |= INT_FLAG_ATTENTION;
+		}
 	}
 
-	return;
-}
-
-static void gas_volumes(void)
-{
-	overlay float volumes[NUM_GAS];
-
-	overlay unsigned char stop_gas;
-	overlay unsigned char stop_gas_last;
-	overlay unsigned char stop_time;
-	overlay unsigned char stop_depth;
-	overlay unsigned char stop_depth_last;
-	overlay unsigned char i;
-
-	//---- initialization ----------------------------------------------------
-
-	// null the volume accumulators
-	for( gas_num = 0; gas_num < NUM_GAS; ++gas_num ) volumes[gas_num] = 0.0;
-
-	// quit for CCR and pSCR mode
-	if( char_O_deco_status & DECO_MODE_LOOP ) goto done;
-
-
-	//---- bottom demand -----------------------------------------------------
-
-	// sim_gas_current  : gas used during bottom segment (0, 1-5)
-	// char_bottom_depth: depth of the bottom segment
-
-	// get the gas used during bottom segment
-	gas_find_current();
-
-	// initialize variables
-	stop_gas_last = stop_gas = sim_gas_current;
-
-	// set the usage (SAC rate) to bottom usage rate for bottom part and initial ascent
-	char_usage = char_I_bottom_usage;
-
-	// volumes are only calculated for gases 1-5, but not the manually configured one
-	if( stop_gas )
+	// pressure warnings for reading 2, but only if enabled and pressure value available
+	if( (char_I_pressure_gas[1] > 0) && !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
 	{
-		// set the bottom depth
-		float_depth = (float)char_bottom_depth;
-
-		// calculate either bottom segment or just the fTTS/bailout delayed part
-		if( char_O_main_status & DECO_BOTTOM_CALCULATE )
+		overlay unsigned short pressure_value = int_IO_pressure_value[1] & ~INT_FLAG_OUTDATED;
+
+		if( (char_I_pressure_gas[1] < 6 ) && !(int_O_pressure_need[1] & INT_FLAG_NOT_AVAIL) )
 		{
-			// duration of bottom segment
-			float_time = (float)char_I_bottom_time;
+			// not a diluent and need available: warning & attention by need
+			if      ( pressure_value <= int_O_pressure_need[1])
+			        int_IO_pressure_value[1] |= INT_FLAG_WARNING;
+			else if ( pressure_value <= int_O_pressure_need[1] + int_O_pressure_need[1] / 2 )
+			        int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
 		}
 		else
 		{
-			// duration of delayed ascent
-			float_time = (float)char_I_extra_time;
+			// a diluent or need not available: warning & attention by fixed thresholds
+			if      ( pressure_value <= PRESSURE_LIMIT_WARNING   ) int_IO_pressure_value[1] |= INT_FLAG_WARNING;
+			else if ( pressure_value <= PRESSURE_LIMIT_ATTENTION ) int_IO_pressure_value[1] |= INT_FLAG_ATTENTION;
 		}
-
-		// calculate gas demand
-		gas_volumes_helper_1();
-
-		// take result
-		volumes[stop_gas-1] = volume;
 	}
 
-	// initialize stop index with first stop
-	i = 0;
-
-	//---- initial ascent demand ---------------------------------------------
-
-	// stop_gas                : gas from bottom segment
-	// char_bottom_depth       : depth of the bottom segment
-	// internal_deco_depth[i=0]: depth of the first stop, may be 0 if no stop exists
-
-	// get the data of the first stop
-	stop_depth = internal_deco_depth[i];
-	stop_time  = internal_deco_time[i];
-
-	// volumes are only calculated for gases 1-5, but not the manually configured one
-	if( stop_gas )
+	//--- SAC Calculation ---------------------------------------------------------------------
+	//
+	// char_I_SAC_mode =0: disabled
+	//                 =1: SAC from 1st reading
+	//                 =2: SAC from 2nd reading
+	//                 =3: SAC from higher one of both pressure drops (independent double mode)
+	//                 =4: SAC (O2 usage) from 2nd reading without real_pres_respiration term
+
+	// set SAC rate to not available by default
+	int_O_SAC_measured   = 0 + INT_FLAG_NOT_AVAIL;
+
+	// get a copy of the current absolute pressure
+	pres_respiration_sac = real_pres_respiration;
+
+	// set threshold for SAC rate attention
+	max_sac_rate = (deco_info & DECO_FLAG) ? char_I_SAC_deco : char_I_SAC_work;
+
+	// char_I_SAC_deco / char_I_SAC_work are in l/min, max_sac_rate is in 0.1 l/min
+	max_sac_rate *= 10;
+
+
+	// pre-process SAC mode 3 (independent double)
+	if( char_I_SAC_mode == 3 )
 	{
-		// compute distance between bottom and first stop
-		float_depth = (float)char_bottom_depth - (float)stop_depth;
-
-		// initial ascent exists only if ascent distance is > 0
-		if( float_depth > 0.0 )
+		overlay unsigned char  reading1_gas;
+		overlay unsigned char  reading2_gas;
+		overlay unsigned char  reading1_tanksize;
+		overlay unsigned char  reading2_tanksize;
+		overlay unsigned short reading1_press;
+		overlay unsigned short reading2_press;
+		overlay unsigned short reading1_drop;
+		overlay unsigned short reading2_drop;
+
+		// get gas numbers (1-10) of both readings
+		reading1_gas = char_I_pressure_gas[0];
+		reading2_gas = char_I_pressure_gas[1];
+
+		// default to no SAC calculation
+		char_I_SAC_mode = 0;
+
+		// clear switch advice by default
+		deco_info &= ~IND_DOUBLE_SWITCH_FLAG;
+
+		// check if both readings are configured and available
+		if(  reading1_gas                                    )
+		if(  reading2_gas                                    )
+		if( !(int_IO_pressure_value[0] & INT_FLAG_NOT_AVAIL) )
+		if( !(int_IO_pressure_value[1] & INT_FLAG_NOT_AVAIL) )
+		if( !(int_I_pressure_drop[0]   & INT_FLAG_NOT_AVAIL) )
+		if( !(int_I_pressure_drop[1]   & INT_FLAG_NOT_AVAIL) )
 		{
-			// compute ascent time
-			float_time = float_depth / float_ascent_speed;
-
-			// compute average depth between bottom and first stop
-			float_depth = (float)char_bottom_depth - float_depth * 0.5;
-
-			// calculate gas demand
-			gas_volumes_helper_1();
-
-			// add result
-			volumes[stop_gas-1] += volume;
+			// get tank pressures, stripping flags
+			reading1_press = int_IO_pressure_value[0] & 0x0FFF;			// in 0.1 bar
+			reading2_press = int_IO_pressure_value[1] & 0x0FFF;			// in 0.1 bar
+
+			// get pressure drops as integers, stripping flags and shifting right
+			// to avoid an overflow when multiplying with the tank size later on
+			reading1_drop = (int_I_pressure_drop[0] & 0x0FFF) >> 2;
+			reading2_drop = (int_I_pressure_drop[1] & 0x0FFF) >> 2;
+
+			// get tank sizes
+			reading1_tanksize = char_I_gas_avail_size[reading1_gas-1];
+			reading2_tanksize = char_I_gas_avail_size[reading2_gas-1];
+
+			// set mode to calculate SAC on the reading with the higher absolute drop
+			char_I_SAC_mode = (reading1_drop * reading1_tanksize > reading2_drop * reading2_tanksize) ? 1 : 2;
+
+			// compute switch advice if pressure (in 0.1 bar) of tank breathed from is
+			// more than char_I_max_pres_diff (in bar) below pressure of the other tank.
+			if( char_I_SAC_mode == 1 )
+			{
+				// breathing from reading 1, switch advice if pressure on reading 1 lower than on 2
+				if( (reading1_press + 10*char_I_max_pres_diff) <= reading2_press )
+					deco_info |= IND_DOUBLE_SWITCH_FLAG;
+			}
+			else
+			{
+				// breathing from reading 2, switch advice if pressure on reading 2 lower than on 1
+				if( (reading2_press + 10*char_I_max_pres_diff) <= reading1_press )
+					deco_info |= IND_DOUBLE_SWITCH_FLAG;
+			}
 		}
 	}
 
-	// switch the usage (SAC rate) to deco usage rate
-	// for stops, intermediate and final ascent
-	char_usage = char_I_deco_usage;
-
-	// is there a (first) stop? if yes, goto stops processing
-	if( stop_depth ) goto stops;
-
-	// add demand of a 3 minutes safety stop at 5 meters, at least for contingency...
-	float_time  = 3.0;
-	float_depth = 5.0;
-
-	// calculate gas demand
-	gas_volumes_helper_1();
-
-	// add result
-	volumes[stop_gas-1] += volume;
-
-	// proceed to volume conversion and pressure calculations
-	goto done;
-
-
-	//---- intermediate ascent demand ---------------------------------------
-inter_ascents:
-
-	// store last stop depth and gas
-	stop_depth_last = stop_depth;
-	stop_gas_last   = stop_gas;
-
-	// check if we are at the end of the stops table
-	if( i < NUM_STOPS-1 )
+
+	// pre-process SAC mode 4 (O2 usage by reading 2)
+	if( char_I_SAC_mode == 4 )
+	{
+		// O2 usage on CCR is independent from absolute pressure
+		pres_respiration_sac = 1.0;
+
+		// O2 pressure drop is measured via reading 2
+		char_I_SAC_mode = 2;
+
+		// reconfigure max SAC rate to O2 consumption attention threshold
+		max_sac_rate = O2_CONSUMPTION_LIMIT_ATTENTION;
+	}
+
+
+	// calculate SAC - modes 1 & 2
+	if( (char_I_SAC_mode == 1) || (char_I_SAC_mode == 2) )
 	{
-		// there are more entries - get the next stop data
-		i++;
-
-		// get the next stop depth
-		stop_depth = internal_deco_depth[i];
-
-		// check if there is indeed another stop,
-		// if not (depth = 0) treat as end of table
-		if( stop_depth == 0 ) goto end_of_table;
-
-		// get the next stop duration
-		stop_time = internal_deco_time[i];
+		overlay unsigned char reading_index;
+		overlay unsigned char reading_gas;
+		overlay unsigned char reading_tanksize;
+		overlay float         reading_drop;
+
+		// set index: char_I_SAC_mode = 1 -> reading one, index 0
+		//                            = 2 ->         two,       1
+		reading_index = char_I_SAC_mode - 1;
+
+		// get gas number (1-10)
+		reading_gas = char_I_pressure_gas[reading_index];
+
+		// check if reading is configured and available
+		if(  reading_gas                                               )
+		if( !(int_I_pressure_drop[reading_index] & INT_FLAG_NOT_AVAIL) )
+		{
+			// get tank size (in liter)
+			reading_tanksize = char_I_gas_avail_size[reading_gas-1];
+
+			// get pressure drop as float, stripping flags (in 1/5120 bar/sec)
+			reading_drop = (float)(int_I_pressure_drop[reading_index] & 0x0FFF);
+
+			// check if pressure drop is within range
+			if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUT_OF_RANGE) )
+			{
+				// calculate SAC,   10 is factor to have result in 0.1 liter/min
+				//                  60 is factor for 60 seconds per 1 minute,
+				//                5120 accounts for reading_drop being in 1/5120 bar/sec
+				//                10*60/5120 = 60/512 = 15/128
+				float_sac = reading_drop * 15/128 * reading_tanksize / pres_respiration_sac;
+
+				// limit result to 999 (99.9 liter/min)
+				if ( float_sac >= 998.5 )
+				{
+					int_O_SAC_measured = 999 + INT_FLAG_ATTENTION;
+				}
+				else
+				{
+					// convert float to integer
+					int_O_SAC_measured = (unsigned short)(float_sac + 0.5);
+
+					// set attention flag if exceeding SAC threshold, but only if pressure drop is not outdated
+					if( !(int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED) )
+					if( int_O_SAC_measured >= max_sac_rate )
+					{
+						int_O_SAC_measured |= INT_FLAG_ATTENTION;
+					}
+				}
+			}
+			else
+			{
+				// pressure drop is out of range, so SAC will be set out of range, too
+				int_O_SAC_measured = 999 + INT_FLAG_ATTENTION;
+			}
+
+			// copy outdated flag from int_I_pressure_drop to int_O_SAC_measured
+			if( int_I_pressure_drop[reading_index] & INT_FLAG_OUTDATED )
+			{
+				int_O_SAC_measured |= INT_FLAG_OUTDATED;
+			}
+		}
+	}
+}
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+// convert_gas_needs_to_press
+//
+// Converts gas volumes into pressures and sets respective flags
+//
+// Input:  gas_needs_gas_index       index of the gas to convert (0-4)
+//         gas_volume_need[]         needed gas volume in liters
+//         char_I_gas_avail_pres[]   available gas volume in bar
+//         char_I_gas_avail_size[]   size of the tanks in liters
+//         char_I_pressure_gas[]     gas configured on reading 1/2 (TR only)
+//
+// Output: int_O_gas_need_vol[]      required gas amount in liters, including flags
+//         int_O_gas_need_pres[]     required gas amount in bar,    including flags
+//         int_O_pressure_need[]     required gas amount for reading 1/2 (TR only)
+//
+static void convert_gas_needs_to_press(void)
+{
+
+	// just to make the code more readable...
+	i = gas_needs_gas_index;
+
+	if( gas_volume_need[i] >= 65534.5 )
+	{
+		int_O_gas_need_vol[i]  = 65535;										// clip at 65535 liters
+		int_O_gas_need_pres[i] =   999 | INT_FLAG_WARNING | INT_FLAG_HIGH;	// 999 bar + warning flag + >999 flag
 	}
 	else
 	{
-end_of_table:
-
-		// End of the stops table reached or no more stops: Split the remaining
-		// ascent into an intermediate ascent and a final ascent by creating a
-		// dummy stop at the usual last deco stop depth. Stop gas doesn't change.
-		stop_time  = 0;
-		stop_depth = char_I_depth_last_deco;
-	}
-
-	// volumes are only calculated for gases 1-5, but not the manually configured one
-	if( stop_gas_last )
-	{
-		// compute distance between the two stops:
-		// last stop will always be deeper than current stop
-		float_depth = (float)(stop_depth_last - stop_depth);
-
-		// compute ascent time
-		float_time = float_depth / float_ascent_speed;
-
-		// compute average depth between the two stops
-		float_depth = (float)stop_depth_last - float_depth * 0.5;
-
-		// calculate gas demand
-		gas_volumes_helper_1();
-
-		// add result
-		volumes[stop_gas_last-1] += volume;
+		overlay unsigned short int_pres_warn;
+		overlay unsigned short int_pres_attn;
+
+		// set warning and attention thresholds
+		int_pres_warn = 10.0 * (unsigned short)char_I_gas_avail_pres[i];
+		int_pres_attn = GAS_NEEDS_ATTENTION_THRESHOLD * int_pres_warn;
+
+		// convert ascent gas volume need from float to integer [in liter]
+		int_O_gas_need_vol[i]  = (unsigned short)gas_volume_need[i];
+
+		// compute how much pressure in the tank will be needed [in bar]
+		int_O_gas_need_pres[i] = (unsigned short)( gas_volume_need[i] / char_I_gas_avail_size[i] + 0.999 );
+
+		// limit result to 999 bar because of display constraints
+		if( int_O_gas_need_pres[i] > 999 ) int_O_gas_need_pres[i] = 999 | INT_FLAG_HIGH;
+
+		// set flags for fast evaluation by dive mode
+		if      ( int_O_gas_need_pres[i] ==             0 ) int_O_gas_need_pres[i] |= INT_FLAG_ZERO;
+		else if ( int_O_gas_need_pres[i] >= int_pres_warn ) int_O_gas_need_pres[i] |= INT_FLAG_WARNING;
+		else if ( int_O_gas_need_pres[i] >= int_pres_attn ) int_O_gas_need_pres[i] |= INT_FLAG_ATTENTION;
 	}
 
-
-	//---- next stop demand -------------------------------------------------
-stops:
-
-	// convert depth of the stop
-	float_depth = (float)stop_depth;
-
-	// get the next gas
-	stop_gas = internal_deco_gas[i];
-
-	// in case of end-of-table, keep the last gas
-	if( !stop_gas ) stop_gas = stop_gas_last;
-
-	// do we have a gas change?
-	if( stop_gas_last && (stop_gas != stop_gas_last) )
-	{
-		// yes - spend an additional char_I_gas_change_time on the old gas
-		float_time = (float)char_I_gas_change_time;
-
-		// calculate gas demand
-		gas_volumes_helper_1();
-
-		// add result
-		volumes[stop_gas_last-1] += volume;
-	}
-
-	// calculate and add demand on new gas for the full stop duration
-	if( stop_gas )
-	{
-		// get the duration of the stop
-		float_time = (float)stop_time;
-
-		// calculate gas demand
-		gas_volumes_helper_1();
-
-		// add result to last gas
-		volumes[stop_gas-1] += volume;
-	}
-
-	// continue with the next intermediate ascent if this was not the last stop
-	if( stop_depth > char_I_depth_last_deco ) goto inter_ascents;
-
-
-	//---- final ascent demand -----------------------------------------------
-final_ascent:
-
-	// float_depth: depth of last stop
-	// stop_gas   : gas from last stop (0 or 1-5)
-
-	// volumes are only calculated for gases 1-5, but not the manually configured one
-	if( stop_gas )
-	{
-		// set ascent time dependent on deco status
-		if( NDL_time )
-		{
-			// within NDL - ascent with float_ascent_speed
-			float_time = float_depth / float_ascent_speed;
-		}
-		else
-		{
-			// in deco - reduce ascent speed to 1 meter per minute
-			float_time = float_depth;
-		}
-
-		// set half-way depth
-		float_depth *= 0.5;
-
-		// calculate gas demand
-		gas_volumes_helper_1();
-
-		// add result
-		volumes[stop_gas-1] += volume;
-	}
-
-
-	//---- convert results for the assembler interface -----------------------------
-done:
+	// set invalid flag if there is an overflow in the stops table
+	if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_O_gas_need_pres[i] |= INT_FLAG_INVALID;
 
 #ifdef _rx_functions
 	// only for OSTC TR model with TR functions enabled
-	if( char_O_main_status & DECO_TR_FUNCTIONS )
-	{
-		// invalidate pressure needs to pressure readings
-		int_O_pressure_need[0] = 0 + INT_FLAG_NOT_AVAIL;
-		int_O_pressure_need[1] = 0 + INT_FLAG_NOT_AVAIL;
-	}
-#endif
-
-	for( gas_num = 0; gas_num < NUM_GAS; ++gas_num )
+	if( main_status & TR_FUNCTIONS )
 	{
-		volume = volumes[gas_num];
-
-		// compute int_volume and int_pres_need from volume and gas_num
-		gas_volume_helper_2();
-
-		// set invalid flag if there is an overflow in the stops table
-		if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW )
-			int_pres_need |= INT_FLAG_INVALID;
-
-		// copy result data to ASM interface
-		int_O_ascent_volumes[gas_num]   = int_volume;
-		int_O_ascent_pres_need[gas_num] = int_pres_need;
-
-#ifdef _rx_functions
-		// only for OSTC TR model with TR functions enabled
-		if( char_O_main_status & DECO_TR_FUNCTIONS )
+		// char_I_pressure_gas[] uses gas indexes from 1-10, loop variable i runs from 0 to 4
+		overlay unsigned char j = i+1;
+
+		// check if the current gas is configured on pressure reading 1 or 2
+		if( (char_I_pressure_gas[0] == j) || (char_I_pressure_gas[1] == j) )
 		{
-			// char_I_pressure_gas[] uses gas numbers 1-10, gas_num runs from 0 to 4
-			overlay unsigned char gas = gas_num + 1;
-
-			// check if the current gas is configured on pressure reading 1 or 2
-			if( (gas == char_I_pressure_gas[0]) || (gas == char_I_pressure_gas[1]) )
-			{
-				// strip all flags from int_pres_need
-				int_pres_need &= 1023;
-
-				// limit to 400 bar and multiply by 10 to get result in 0.1 bar
-				int_pres_need = (int_pres_need > 400) ? (4000 | INT_FLAG_OUT_OF_RANGE) : (10 * int_pres_need);
-
-				// tag as not available if there is an overflow in the stops table
-				if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW )
-					int_pres_need |= INT_FLAG_NOT_AVAIL;
-
-				// copy to result vars (in both readings the same gas could be configured)
-				if( gas == char_I_pressure_gas[0] ) int_O_pressure_need[0] = int_pres_need;
-				if( gas == char_I_pressure_gas[1] ) int_O_pressure_need[1] = int_pres_need;
-			}
-		} // TR functions
+			// get a copy of the required pressure in full bar
+			overlay unsigned short int_pres_need = int_O_gas_need_pres[i];
+
+			// strip all flags
+			int_pres_need &= 1023;
+
+			// limit to 400 bar and multiply by 10 to get required pressure in 0.1 bar
+			int_pres_need = (int_pres_need > 400) ? 4000 | INT_FLAG_OUT_OF_RANGE : 10 * int_pres_need;
+
+			// tag as not available if there is an overflow in the stops table
+			if( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_pres_need |= INT_FLAG_NOT_AVAIL;
+
+			// copy to reading data (in both readings the same gas could be configured)
+			if( char_I_pressure_gas[0] == j ) int_O_pressure_need[0] = int_pres_need;
+			if( char_I_pressure_gas[1] == j ) int_O_pressure_need[1] = int_pres_need;
+		}
+	} // TR functions
 #endif
-
-	} // for
 }
 
+
+//////////////////////////////////////////////////////////////////////////////
+// convert the real CNS value to integer
+//
+// Input  CNS_fraction_real     current CNS value as float
+//
+// Output: int_O_CNS_current    current CNS value as integer including flags
+//
+static void convert_cur_CNS_for_display(void)
+{
+	// convert to integer
+	float_value = CNS_fraction_real; convert_float_to_int(); int_O_CNS_current = int_value;
+
+	// set warning & attention flags
+	if      ( int_O_CNS_current    >= CNS_WARNING_THRESHOLD   ) int_O_CNS_current |= INT_FLAG_WARNING;
+	else if ( int_O_CNS_current    >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_current |= INT_FLAG_ATTENTION;
+}
+
+
 //////////////////////////////////////////////////////////////////////////////
-
-static void convert_CNS_for_display(void)
-{
-	     if( CNS_fraction <  0.010 ) int_O_CNS_fraction = 0;
-	else if( CNS_fraction >= 9.985 ) int_O_CNS_fraction = 999 + INT_FLAG_WARNING;
-	else
-	{
-		// convert float to integer
-		int_O_CNS_fraction = (unsigned short)(100 * CNS_fraction + 0.5);
-
-		// set warning & attention flags
-		     if( int_O_CNS_fraction >= CNS_WARNING_THRESHOLD   ) int_O_CNS_fraction |= INT_FLAG_WARNING;
-		else if( int_O_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_O_CNS_fraction |= INT_FLAG_ATTENTION;
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
+// convert the simulated CNS value to integer
+//
+// Input:  CNS_fraction_sim       CNS value after predicted ascent in float
+//
+// Output: int_sim_CNS_fraction   CNS value after predicted ascent in integer
+//                                including flags, will be routed to
+//                                int_O_{normal,alternative}_CNS_fraction
+//
 static void convert_sim_CNS_for_display(void)
 {
-	     if( sim_CNS_fraction <  0.010 ) int_sim_CNS_fraction = 0;
-	else if( sim_CNS_fraction >= 9.985 ) int_sim_CNS_fraction = 999 + INT_FLAG_WARNING;
-	else
-	{
-		// convert float to integer
-		int_sim_CNS_fraction = (unsigned short)(100 * sim_CNS_fraction + 0.5);
-
-		// set warning & attention flags
-		if      ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD    ) int_sim_CNS_fraction |= INT_FLAG_WARNING;
-		else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD  ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION;
-	}
+	// convert to integer
+	float_value = CNS_fraction_sim; convert_float_to_int(); int_sim_CNS_fraction = int_value;
+
+	// set warning & attention flags
+	if      ( int_sim_CNS_fraction >= CNS_WARNING_THRESHOLD   ) int_sim_CNS_fraction |= INT_FLAG_WARNING;
+	else if ( int_sim_CNS_fraction >= CNS_ATTENTION_THRESHOLD ) int_sim_CNS_fraction |= INT_FLAG_ATTENTION;
 
 	// set invalid flag if there is an overflow in the stops table
-	if( char_O_deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID;
+	if      ( deco_warnings & DECO_WARNING_STOPTABLE_OVERFLOW ) int_sim_CNS_fraction |= INT_FLAG_INVALID;
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
-
-static void convert_GF_for_display(void)
+// convert the saturation value of the leading tissue to integer
+//
+// Input     lead_supersat              saturation of the leading tissue
+//           lead_tissue                number of the     leading tissue
+//           char_I_GF_High_percentage  GF high factor
+//
+// Output:   int_O_lead_supersat        saturation of the leading tissue
+//           char_O_lead_tissue         number of the     leading tissue
+//
+// Modified: deco_warnings              deco engine warnings vector
+//
+static void convert_sat_for_display(void)
 {
-	// convert supersaturation of the leading tissue to int_O_gradient_factor in % (1.0 = 100%)
+	// convert supersaturation of the leading tissue to int_O_lead_supersat in % (1.0 = 100%)
 	// limit to 255 because of constraints in ghostwriter code
-	     if( lead_supersat <= 0.000 ) int_O_gradient_factor = 0;
-	else if( lead_supersat >  2.545 ) int_O_gradient_factor = 255 + INT_FLAG_WARNING;
-	else
+	     if ( lead_supersat <= 0.000 ) int_O_lead_supersat = 0;
+	else if ( lead_supersat >  2.545 ) int_O_lead_supersat = 255;
+	else                               int_O_lead_supersat = (unsigned short)(100 * lead_supersat + 0.5);
+
+	// set warning & attention flags
+	if( int_O_lead_supersat > 100 )
 	{
-		int_O_gradient_factor = (unsigned int)(100 * lead_supersat + 0.5);
-
-		if( char_I_deco_model != 0 )
-		{
-			// GF factors enabled
-			if     ( int_O_gradient_factor > 99 )
-			{
-				int_O_gradient_factor |= INT_FLAG_WARNING;			// make GF factor shown in red
-			}
-			else if( int_O_gradient_factor > char_I_GF_High_percentage )
-			{
-				int_O_gradient_factor |= INT_FLAG_ATTENTION;		// make GF factor shown in yellow
-				char_O_deco_warnings  |= DECO_ATTENTION_OUTSIDE;	// make depth blink     in yellow
-			}
-		}
-		else
-		{
-			// straight Buhlmann
-			if      ( int_O_gradient_factor > 100 )
-				int_O_gradient_factor |= INT_FLAG_WARNING;			// make GF factor shown in red
-
-			else if ( int_O_gradient_factor >  99 )
-			{
-				int_O_gradient_factor |= INT_FLAG_ATTENTION;		// make GF factor shown in yellow
-				char_O_deco_warnings  |= DECO_ATTENTION_OUTSIDE;	// make depth blink     in yellow
-			}
-		}
+		int_O_lead_supersat |= INT_FLAG_WARNING;			// make GF factor shown in red
+		deco_warnings       |= DECO_WARNING_OUTSIDE;		// make depth     shown in red
+	}
+	else if(    (char_I_deco_model != 0) && (int_O_lead_supersat > char_I_GF_High_percentage)
+	         || (char_I_deco_model == 0) && (int_O_lead_supersat > 99                       ) )
+	{
+		int_O_lead_supersat |= INT_FLAG_ATTENTION;			// make GF factor shown in yellow
+		deco_warnings       |= DECO_ATTENTION_OUTSIDE;		// make depth     shown in yellow
 	}
 
 	// export also the number of the leading tissue
-	char_O_lead_number = lead_number;
+	char_O_lead_tissue = lead_tissue;
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
-
+// convert the ceiling value to integer
+//
+// Input:    ceiling         minimum depth permitted in float
+//
+// Output:   int_O_ceiling   minimum depth permitted in mbar
+//
+// Modified: deco_info       deco engine information vector
+//
 static void convert_ceiling_for_display(void)
 {
 	// Convert ceiling to int_O_ceiling in mbar relative pressure.
 	// Round up to next 10 cm so that the ceiling disappears only
 	// when the ceiling limit is really zero. This will coincident
 	// with TTS switching back to NDL time.
-	     if( ceiling <=  0.0 ) int_O_ceiling = 0;
-	else if( ceiling >  16.0 ) int_O_ceiling = 16000;
-	else                       int_O_ceiling = (short)(ceiling * 1000 + 9);
+	if      ( ceiling <=  0.0 ) int_O_ceiling = 0;
+	else if ( ceiling >  16.0 ) int_O_ceiling = 16000;
+	else                        int_O_ceiling = (unsigned short)(ceiling * 1000 + 9);
 
 	// set/reset ceiling flag
-	if( int_O_ceiling ) char_O_deco_info |=  DECO_CEILING;
-	else                char_O_deco_info &= ~DECO_CEILING;
+	if      ( int_O_ceiling   ) deco_info |=  DECO_CEILING;
+	else                        deco_info &= ~DECO_CEILING;
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 // push_tissues_to_vault & pull_tissues_from_vault
 //
@@ -4050,37 +5087,55 @@
 //            The vault is exclusively reserved to back-up and restore the real
 //            tissues and related data when entering / leaving simulation mode!
 //
-
+// Input/Output: CNS_fraction_real       current real CNS value
+//               char_O_deco_warnings    deco engine warnings vector
+//               real_pres_tissue_N2[]   partial pressure of N2 in real tissues
+//               real_pres_tissue_He[]   partial pressure of He in real tissues
+//
+// Output:       int_O_CNS_current      current CNS value as integer including flags
+//
 static void push_tissues_to_vault(void)
 {
-	overlay unsigned char x;
-
-	cns_vault_float      = CNS_fraction;
-	deco_warnings_vault  = char_O_deco_warnings;
-
-	for( x = 0; x < NUM_COMP; x++ )
+	// store the current CNS value and deco warnings
+	vault_CNS_fraction_real = CNS_fraction_real;
+	vault_deco_warnings     = char_O_deco_warnings;
+	vault_deco_info         = char_O_deco_info;
+
+	// store the tissue pressures
+	for( i = 0; i < NUM_COMP; i++ )
 	{
-		pres_tissue_N2_vault[x] = pres_tissue_N2[x];
-		pres_tissue_He_vault[x] = pres_tissue_He[x];
+		vault_pres_tissue_N2[i] = real_pres_tissue_N2[i];
+#ifdef _helium
+		vault_pres_tissue_He[i] = real_pres_tissue_He[i];
+#else
+		vault_pres_tissue_He[i] = 0;
+#endif
 	}
 }
 
 static void pull_tissues_from_vault(void)
 {
-	overlay unsigned char x;
-
-	CNS_fraction         = cns_vault_float;
-	char_O_deco_warnings = deco_warnings_vault;
-
-	convert_CNS_for_display();
-
-	for( x = 0; x < NUM_COMP; x++ )
+	// restore the CNS value and deco warnings
+	CNS_fraction_real    = vault_CNS_fraction_real;
+	char_O_deco_warnings = vault_deco_warnings;
+	char_O_deco_info     = vault_deco_info;
+
+	// convert the CNS value to integer
+	convert_cur_CNS_for_display();
+
+	// restore the tissue pressures
+	for( i = 0; i < NUM_COMP; i++ )
 	{
-		pres_tissue_N2[x] = pres_tissue_N2_vault[x];
-		pres_tissue_He[x] = pres_tissue_He_vault[x];
+		real_pres_tissue_N2[i] = vault_pres_tissue_N2[i];
+#ifdef _helium
+		real_pres_tissue_He[i] = vault_pres_tissue_He[i];
+#else
+		real_pres_tissue_He[i] = 0;
+#endif
 	}
 }
 
+
 //////////////////////////////////////////////////////////////////////////////
 //
 #ifndef CROSS_COMPILE