changeset 696:cc542448fb28

Merge
author heinrichsweikamp
date Fri, 19 Aug 2022 11:30:24 +0200
parents 87bee7cc77b3 (current diff) 49b164022335 (diff)
children d55817a11f4c
files Current build/OSTC4update_210428.bin Discovery/Inc/configuration.h
diffstat 60 files changed, 2739 insertions(+), 811 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Common/Inc/configuration.h	Fri Aug 19 11:30:24 2022 +0200
@@ -0,0 +1,75 @@
+///////////////////////////////////////////////////////////////////////////////
+/// -*- coding: UTF-8 -*-
+///
+/// \file   Discovery/Inc/configuration.h
+/// \brief  Header file for variant specific firmware adaptations at compile time
+/// \author heinrichs weikamp gmbh
+/// \date   29-February-2020
+///
+/// $Id$
+///////////////////////////////////////////////////////////////////////////////
+/// \par Copyright (c) 2014-2020 Heinrichs Weikamp gmbh
+///
+///     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
+///     (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
+///     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/>.
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIGURATION_HEADER
+#define CONFIGURATION_HEADER
+
+/* Enable this to make the simulator write a logbook entry */
+/* #define SIM_WRITES_LOGBOOK 1 */
+
+/* Enable this for support of optical bottle pressure interface */
+/* #define ENABLE_BOTTLE_SENSOR */
+
+/* Enable this to show voltage in parallel to charge state */
+/* #define ALWAYS_SHOW_VOLTAGE */
+
+/* Enable this to skip coplete scan of dive log during startup */
+#define TRUST_LOG_CONSISTENCY
+
+/* Enable this to transfer additional data list last dive ID and last sample index during raw data requests */
+/* define SEND_DATA_DETAILS */
+
+/* Enable to activate a menu item in reset menu which provide sample ring analysis / repair functionality */
+/* #define ENABLE_ANALYSE_SAMPLES */
+
+/* Enable to have access to the debug view options (turn on / off via menu instead of compile switch) */
+/* #define HAVE_DEBUG_VIEW */
+
+/* Enable to have access to the motion control selection menu */
+/* #define ENABLE_MOTION_CONTROL */
+
+/* Enable to have option to hide not needed gases from dive views */
+/* #define ENABLE_UNUSED_GAS_HIDING */
+
+/* Enable to have the new T3 profile view available */
+#define ENABLE_T3_PROFILE_VIEW
+
+/* Enable to have PPO2 adjustments in T3 sensor view during dive simulation */
+/* #define ENABLE_T3_PPO_SIM */
+
+/* Enable to have PSCR functionality available */
+#define ENABLE_PSCR_MODE
+
+/* Enable to have CO2 sensor functionality available */
+/* #define ENABLE_CO2_SUPPORT */
+
+/* Enable to have Sentinel rebreather interface available */
+/* #define ENABLE_SENTINEL_MODE */
+
+/* Enable if you are using sensors with a voltage range 8..16 mV at surface / air level */
+#define ENABLE_ALTERNATIVE_SENSORTYP
+
+#endif
--- a/Common/Inc/data_central.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Common/Inc/data_central.h	Fri Aug 19 11:30:24 2022 +0200
@@ -31,6 +31,7 @@
 
 #include "settings.h"
 #include "stm32f4xx_hal.h"
+#include "configuration.h"
 
 #define BUEHLMANN_STRUCT_MAX_GASES 11
 #define BUEHLMANN_STRUCT_MAX_ASCENDRATES 3
@@ -50,7 +51,8 @@
 	uint8_t setPoint_cbar;
 	uint8_t change_during_ascent_depth_meter_otherwise_zero;
 	uint8_t GasIdInSettings;
-	uint8_t temp1_for16bitalign;
+	uint8_t AppliedDiveMode;
+	float pscr_factor;
 } 	SGas;
 
 typedef struct
@@ -75,6 +77,13 @@
 		uint8_t data[12];
 } 	SDataWireless;
 
+
+typedef struct
+{
+		uint16_t CO2_ppm;
+		uint16_t signalStrength;
+} 	SCO2Sensor;
+
 /* Main structs -------------------------------------------------------------*/
 
 
@@ -187,6 +196,8 @@
 	uint16_t ambient_light_level;
 	SDataWireless wireless_data[4];
 	uint8_t buttonPICdata[4];
+	SCO2Sensor CO2_data;
+
 
 	/* by create DiveSettings() and by setActualGas()
 	 * is send to Small CPU2 for nitrogen calculation
@@ -221,6 +232,9 @@
 	 float ppO2Sensor_bar[3];
 	 float sensorVoltage_mV[3];
 	 float HUD_battery_voltage_V;
+
+/* for PSCR Mode */
+	 float ppo2Simulated_bar;
 } 	SLifeData;
 
 
@@ -323,6 +337,9 @@
 	 */
 	float internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero;
 	uint16_t compassHeading;
+
+	uint8_t pscr_o2_drop;
+	uint8_t pscr_lung_ratio;
  }  SDiveSettings;
 
 enum CHARGE_STATUS{
@@ -454,4 +471,6 @@
 
 _Bool is_ambient_pressure_close_to_surface(SLifeData *lifeData);
 
+uint8_t isLoopMode(uint8_t Mode);
+
 #endif // DATA_CENTRAL_H
--- a/Common/Inc/data_exchange.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Common/Inc/data_exchange.h	Fri Aug 19 11:30:24 2022 +0200
@@ -31,6 +31,21 @@
 #include "settings.h"
 #include "stm32f4xx_hal.h"
 
+/* Command definitions for control of external interface */
+/* 1st nibble binary on/off states */
+/* 2nd nibble UART protocol selection */
+/* 3rd nibble reserve */
+/* 4th nibble command channel */
+#define EXT_INTERFACE_33V_ON		(0x8000u)	/* Bit set to enable 3.3V power interface */
+#define EXT_INTERFACE_ADC_ON		(0x4000u)	/* Bit set to enable ADC conversion */
+#define EXT_INTERFACE_UART_MASK 	(0x0700u)   /* Reserve 3 bits for UART protocol selection */
+#define EXT_INTERFACE_UART_CO2  	(0x0100u)	/* Activate protocol for CO2 sensor */
+#define EXT_INTERFACE_UART_SENTINEL (0x0200u)	/* Activate Sentinel Backup monitor protocol */
+#define EXT_INTERFACE_CO2_CALIB 	(0x0001u)	/* Request calibration of CO2Sensor */
+
+#define DATA_BUFFER_ADC				(0x01u)
+#define DATA_BUFFER_CO2				(0x02u)
+
 enum MODE
 {
 	MODE_SURFACE	= 0,
@@ -80,9 +95,11 @@
 #define CRBUTTON 			(0x01)
 #define CRDATE 				(0x02)
 #define CRTIME 				(0x04)
-#define CRCLEARDECO		(0x08)
-#define CRCOMPASS 		(0x10)
-#define CRDEVICEDATA 	(0x20)
+#define CRCLEARDECO			(0x08)
+#define CRCOMPASS 			(0x10)
+#define CRDEVICEDATA 		(0x20)
+#define CRBATTERY			(0x40)
+#define CRACCIDENT			(0x80)
 
 typedef union{
 confirmbit8_t ub;
@@ -148,7 +165,10 @@
 		uint16_t ambient_light_level;
 		uint16_t SPARE_ALIGN32;
 		float	extADC_voltage[3];
-		uint8_t SPARE_OldWireless[50]; /* 64 - 12 for extADC */
+		uint16_t CO2_ppm;
+		uint16_t CO2_signalStrength;
+		uint16_t externalInterface_CmdAnswer;
+		uint8_t SPARE_OldWireless[44]; /* 64 - 12 for extADC - 6 for CO2 */
 		// PIC data
 		uint8_t button_setting[4]; /* see dependency to SLiveData->buttonPICdata */
 		uint8_t SPARE1;
@@ -166,8 +186,7 @@
 		int8_t offsetPressureSensor_mbar;
 		int8_t offsetTemperatureSensor_centiDegree;
 
-		uint8_t SPARE1;
-		uint8_t SPARE2;
+		uint16_t externalInterface_Cmd;
 
 		float UNUSED1[16-1];//VPM_adjusted_critical_radius_he[16];
 		float UNUSED2[16];//VPM_adjusted_critical_radius_n2[16];
@@ -208,7 +227,7 @@
 	uint8_t chargeStatus;
 	uint8_t boolPICdata;
 	confirmbit8_Type confirmRequest; // confirmbit8_Type
-	uint8_t boolWirelessData;
+	uint8_t boolADCO2Data;
 
 	uint8_t boolPressureData;
 	uint8_t boolCompassData;
--- a/Common/Inc/decom.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Common/Inc/decom.h	Fri Aug 19 11:30:24 2022 +0200
@@ -46,6 +46,8 @@
 void test_decom_CreateGasChangeList(void);
 
 float decom_calc_ppO2(const float ambiant_pressure_bar, const SGas* pGas);
+float decom_calc_SimppO2(float ambiant_pressure_bar, const SGas* pGas);
+float decom_calc_SimppO2_O2based(float ambiant_pressure_bar, uint8_t O2PerCent, float factor);
 void decom_oxygen_calculate_otu(float* oxygen_otu, float pressure_oxygen_real);
 void decom_oxygen_calculate_otu_degrade(float* oxygen_otu, long seconds_since_last_dive);
 void decom_oxygen_calculate_cns_degrade(float* oxygen_cns, long seconds_since_last_dive);
--- a/Common/Inc/settings.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Common/Inc/settings.h	Fri Aug 19 11:30:24 2022 +0200
@@ -36,6 +36,8 @@
 // From Common/Drivers/
 #include "stm32f4xx_hal.h"
 
+#include "configuration.h"
+
 #include <stdint.h>
 
 
@@ -47,11 +49,13 @@
 
 #define CCRMODE_FixedSetpoint 0
 #define CCRMODE_Sensors 1
+#define CCRMODE_Simulation 2
 
 #define DIVEMODE_OC 0
 #define DIVEMODE_CCR 1
 #define DIVEMODE_Gauge 2
 #define DIVEMODE_Apnea 3
+#define DIVEMODE_PSCR 4
 
 #define GF_MODE 1
 #define VPM_MODE 2
@@ -71,13 +75,24 @@
 #define MAX_COMPASS_COMP 		(2u)
 #define MAX_VIEWPORT_MODE 		(0x7F)
 
-#define MAX_SCRUBBER_TIME 		(500u)
+#define MAX_SCRUBBER_TIME 		(999u)
 #define MIN_PPO2_SP_CBAR		(40u)
 
+#define PSCR_MAX_O2_DROP		(15u)
+#define PSCR_MIN_LUNG_RATIO		(5u)
+#define PSCR_MAX_LUNG_RATIO		(20u)
+
+#define UART_MAX_PROTOCOL		(2u)
+
+#define FUTURE_SPARE_SIZE		(28u)		/* Applied for reuse of old, not used, scooter block (was 32 bytes)*/
+
 typedef enum
 {
 	O2_SENSOR_SOURCE_OPTIC = 0,
 	O2_SENSOR_SOURCE_ANALOG,
+#ifdef ENABLE_SENTINEL_MODE
+	O2_SENSOR_SOURCE_SENTINEL,
+#endif
 	O2_SENSOR_SOURCE_MAX
 } SensorSource;
 #define MAX_O2_SENSOR_SOURCE 	(2u)
@@ -202,13 +217,11 @@
 	uint8_t bluetoothActive; /* will be set to zero on each startup at the moment */
 	uint8_t safetystopDepth;
 	uint32_t updateSettingsAllowedFromHeader;
-	uint8_t scooterControl;
-	uint8_t scooterDrag;
-	uint8_t scooterLoad;
-	uint8_t scooterNumberOfBatteries;
-	uint16_t scooterBattSize;
-	uint8_t scooterSPARE1[7];
-	uint8_t scooterSPARE2[19];
+	uint8_t pscr_lung_ratio;									/* redefined in 0xFFFF0020 */
+	uint8_t pscr_o2_drop;										/* redefined in 0xFFFF0020 */
+	uint8_t co2_sensor_active;									/* redefined in 0xFFFF0021 */
+	uint8_t ext_uart_protocol;									/* redefined in 0xFFFF0022 */
+	uint8_t Future_SPARE[FUTURE_SPARE_SIZE];					/* redefined in 0xFFFF0020 (old scooter Block was 32 byte)*/
 	// new in 0xFFFF0006
 	uint8_t ppo2sensors_deactivated;
 	uint8_t tX_colorscheme;
@@ -340,4 +353,7 @@
 uint8_t settingsHelperButtonSens_translate_percentage_to_hwOS_values(uint8_t inputValuePercentage);
 uint8_t settingsHelperButtonSens_translate_hwOS_values_to_percentage(uint8_t inputValuePIC);
 
+void reset_SettingWarning();
+uint8_t isSettingsWarning();
+
 #endif // SETTINGS_H
--- a/Common/Src/decom.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Common/Src/decom.c	Fri Aug 19 11:30:24 2022 +0200
@@ -217,24 +217,34 @@
 	float ppo2_fraction_setpoint;
 	float diluent_divisor;
 
-
 	*fraction_nitrogen = ((float)pGas->nitrogen_percentage) / 100.0f;
 	*fraction_helium = ((float)pGas->helium_percentage) / 100.0f;
 
-	if(!pGas->setPoint_cbar)
-		return;
+	if(pGas->AppliedDiveMode == DIVEMODE_CCR)
+	{
+		// continue with CCR
+		fraction_all_inertgases = *fraction_nitrogen + *fraction_helium;
 
-	// continue with CCR
-	fraction_all_inertgases = *fraction_nitrogen + *fraction_helium;
+		ppo2_fraction_setpoint = (float)pGas->setPoint_cbar/ (100 * ambient_pressure_bar);
+
+		diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases;
+		if(diluent_divisor < 0)
+			diluent_divisor = 0;
 
-	ppo2_fraction_setpoint = (float)pGas->setPoint_cbar/ (100 * ambient_pressure_bar);
+		*fraction_nitrogen *= diluent_divisor;
+		*fraction_helium   *= diluent_divisor;
+	}
+	if(pGas->AppliedDiveMode == DIVEMODE_PSCR)
+	{
+		fraction_all_inertgases = *fraction_nitrogen + *fraction_helium;
+		ppo2_fraction_setpoint =  decom_calc_SimppO2(ambient_pressure_bar, pGas) / ambient_pressure_bar;
+		diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases;
+		if(diluent_divisor < 0)
+			diluent_divisor = 0;
 
-	diluent_divisor = (1.0f - ppo2_fraction_setpoint) / fraction_all_inertgases;
-	if(diluent_divisor < 0)
-		diluent_divisor = 0;
-
-	*fraction_nitrogen *= diluent_divisor;
-	*fraction_helium   *= diluent_divisor;
+		*fraction_nitrogen *= diluent_divisor;
+		*fraction_helium   *= diluent_divisor;
+	}
 }
 
 
@@ -618,79 +628,47 @@
 								pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].helium_percentage;
 								pInput->decogaslist[count].helium_percentage = pInput->gas[i].helium_percentage;
 								pInput->decogaslist[count].GasIdInSettings = i;
-
+								pInput->decogaslist[count].AppliedDiveMode = DIVEMODE_OC;
 						}
 				}
 		}
 		else
 		{
-			//divmode CCR
+			//divmode CCR or PSCR
 				for(i=6; i <= 10; i++)
 				{
-						if(pInput->gas[i].note.ub.active && pInput->gas[i].depth_meter
+						if((pInput->gas[i].note.ub.active) && (pInput->gas[i].depth_meter)
 							 && (pLifeData->actualGas.GasIdInSettings != i)
-							 &&(pInput->gas[i].depth_meter < pLifeData->depth_meter ) )
+							 && (pInput->gas[i].depth_meter < pLifeData->depth_meter ))
 						{
 								count = 1;
 								for(j=6;j<= 10;j++)
 								{
 //                    if(pInput->gas[j].note.ub.active && pInput->gas[j].depth_meter > 0 &&pInput->gas[j].depth_meter > pInput->gas[i].depth_meter)
-										if(			(pInput->gas[j].note.ub.active && pInput->gas[j].depth_meter > 0)
+										if(((pInput->gas[j].note.ub.active) && (pInput->gas[j].depth_meter > 0))
 												&&	(pLifeData->actualGas.GasIdInSettings != j) // new hw 160905
 												&&	(pInput->gas[j].depth_meter > pInput->gas[i].depth_meter))
 												count++;
 								}
 								pInput->decogaslist[count].change_during_ascent_depth_meter_otherwise_zero = pInput->gas[i].depth_meter;
 								pInput->decogaslist[count].nitrogen_percentage = 100;
-								pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].oxygen_percentage;
+								if(pInput->diveMode == DIVEMODE_PSCR)
+								{
+									pInput->decogaslist[count].AppliedDiveMode = DIVEMODE_PSCR;
+									pInput->decogaslist[count].setPoint_cbar = decom_calc_SimppO2_O2based((float)(pInput->gas[i].depth_meter / 10.0 + 1.0), pInput->gas[i].oxygen_percentage, pInput->decogaslist[count].pscr_factor ) * 100;
+									pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].oxygen_percentage;
+								}
+								else
+								{
+									pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].oxygen_percentage;
+									pInput->decogaslist[count].AppliedDiveMode = DIVEMODE_CCR;
+									pInput->decogaslist[count].setPoint_cbar = pInput->decogaslist[0].setPoint_cbar;		/* assume that current setpoint is kept till end of the dive */
+								}
 								pInput->decogaslist[count].nitrogen_percentage -= pInput->gas[i].helium_percentage;
 								pInput->decogaslist[count].helium_percentage = pInput->gas[i].helium_percentage;
 								pInput->decogaslist[count].GasIdInSettings = i;
-
 						}
 				}
-				/* Include Setpoint Changes */
-				for(j=0; j <= count; j++)
-				{
-					uint8_t depth = 0;
-					uint8_t changedepth = 0;
-					char newSetpoint;
-					if(j == 0)
-					{
-						depth = pLifeData->depth_meter;
-					}
-					else
-					{
-						//no setpointchange ?
-						pInput->decogaslist[j].setPoint_cbar =  pInput->decogaslist[j - 1].setPoint_cbar;
-						depth = pInput->decogaslist[j].change_during_ascent_depth_meter_otherwise_zero + 0.1f;
-					}
-					/* Setpoint change at the same depth as gas changes */
-					if(nextSetpointChange(pInput,depth + 1, &changedepth,&newSetpoint) && changedepth == depth)
-					{
-						 pInput->decogaslist[j].setPoint_cbar = newSetpoint;
-					}
-					/* Setpoint changes inbetween gas changes */
-					while(nextSetpointChange(pInput, depth, &changedepth,&newSetpoint)
-							&& (
-										( (j < count) && (changedepth > pInput->decogaslist[j + 1].change_during_ascent_depth_meter_otherwise_zero))
-										|| ((j == count) && (changedepth > 0))
-								 ))
-					{
-						//Include new entry with setpoint change in decogaslist
-						for(int k = count; k > j; k--)
-						{
-								 pInput->decogaslist[k+1] = pInput->decogaslist[k];
-						}
-						pInput->decogaslist[j + 1] =  pInput->decogaslist[j];
-						pInput->decogaslist[j + 1].setPoint_cbar = newSetpoint;
-						j++;
-						count++;
-						depth = changedepth;
-					}
-
-				}
-
 		}
 }
 void test_decom_CreateGasChangeList(void)
@@ -1022,16 +1000,51 @@
 
 float decom_calc_ppO2(const float ambiant_pressure_bar, const SGas* pGas)
 {
-		float percent_N2 = 0;
+	float percent_N2 = 0;
 	float percent_He = 0;
 	float percent_O2 = 0;
-		decom_get_inert_gases(ambiant_pressure_bar, pGas, &percent_N2, &percent_He);
-		percent_O2 = 1 - percent_N2 - percent_He;
 
-		return  (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_O2;
+	decom_get_inert_gases(ambiant_pressure_bar, pGas, &percent_N2, &percent_He);
+	percent_O2 = 1 - percent_N2 - percent_He;
+
+	return  (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * percent_O2;
 }
 
 
+float decom_calc_SimppO2(float ambiant_pressure_bar, const SGas* pGas)
+{
+	float o2Ratio = 0.0;
+	float inertGasRatio = 0.0;
+	float simulatedPSCRppo2 = 0.0;
+
+	o2Ratio = (100.0 - pGas->nitrogen_percentage - pGas->helium_percentage) / 100.0;
+	inertGasRatio = 1.0 - o2Ratio;
+	simulatedPSCRppo2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * o2Ratio;
+	simulatedPSCRppo2 -= (inertGasRatio * pGas->pscr_factor);
+	if(simulatedPSCRppo2 < 0.0)
+	{
+		simulatedPSCRppo2 = 0.0;
+	}
+	return simulatedPSCRppo2;
+}
+
+float decom_calc_SimppO2_O2based(float ambiant_pressure_bar, uint8_t O2PerCent, float factor)
+{
+	float o2Ratio = 0.0;
+	float inertGasRatio = 0.0;
+	float simulatedPSCRppo2 = 0.0;
+
+	o2Ratio = O2PerCent / 100.0;
+	inertGasRatio = 1.0 - o2Ratio;
+	simulatedPSCRppo2 = (ambiant_pressure_bar - WATER_VAPOUR_PRESSURE) * o2Ratio;
+	simulatedPSCRppo2 -= (inertGasRatio * factor);
+	if(simulatedPSCRppo2 < 0.0)
+	{
+		simulatedPSCRppo2 = 0.0;
+	}
+	return simulatedPSCRppo2;
+}
+
 uint8_t decom_get_actual_deco_stop(SDiveState* pDiveState)
 {
 		SDecoinfo* pDecoinfo;
Binary file Current build/OSTC4update_210428.bin has changed
Binary file Current build/OSTC4update_220819.bin has changed
--- a/Discovery/Inc/configuration.h	Mon Nov 01 12:39:34 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////
-/// -*- coding: UTF-8 -*-
-///
-/// \file   Discovery/Inc/configuration.h
-/// \brief  Header file for variant specific firmware adaptations at compile time
-/// \author heinrichs weikamp gmbh
-/// \date   29-February-2020
-///
-/// $Id$
-///////////////////////////////////////////////////////////////////////////////
-/// \par Copyright (c) 2014-2020 Heinrichs Weikamp gmbh
-///
-///     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
-///     (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
-///     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/>.
-//////////////////////////////////////////////////////////////////////////////
-
-
-#ifndef CONFIGURATION_HEADER
-#define CONFIGURATION_HEADER
-
-/* Enable this to make the simulator write a logbook entry */
-/* #define SIM_WRITES_LOGBOOK 1 */
-
-/* Enable this for support of optical bottle pressure interface */
-/* #define ENABLE_BOTTLE_SENSOR */
-
-/* Enable this to show voltage in parallel to charge state */
-/* #define ALWAYS_SHOW_VOLTAGE */
-
-/* Enable this to skip coplete scan of dive log during startup */
-#define TRUST_LOG_CONSISTENCY
-
-/* Enable this to transfer additional data list last dive ID and last sample index during raw data requests */
-/* define SEND_DATA_DETAILS */
-
-/* Enable to activate a menu item in reset menu which provide sample ring analysis / repair functionality */
-/* #define ENABLE_ANALYSE_SAMPLES */
-
-/* Enable to have access to the debug view options (turn on / off via menu instead of compile switch) */
-/* #define HAVE_DEBUG_VIEW */
-
-/* Enable to have access to the motion control selection menu */
-/* #define ENABLE_MOTION_CONTROL */
-
-/* Enable to have option to hide not needed gases from dive views */
-/* #define ENABLE_UNUSED_GAS_HIDING */
-
-/* Enable to have the new T3 profile view available */
-/* #define ENABLE_T3_PROFILE_VIEW */
-
-/* Enable to have PPO2 adjustments in T3 sensor view during dive simulation */
-/* #define ENABLE_T3_PPO_SIM */
-
-#endif
--- a/Discovery/Inc/data_exchange_main.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/data_exchange_main.h	Fri Aug 19 11:30:24 2022 +0200
@@ -45,7 +45,7 @@
 void DataEX_copy_to_LifeData(_Bool *modeChangeFlag);
 void DataEX_copy_to_deco(void);
 void DateEx_copy_to_dataOut(void);
-void DataEX_merge_deviceData(void);
+void DataEX_merge_devicedata(void);
 uint32_t DataEX_lost_connection_count(void);
 void DataEX_control_connection_while_asking_for_sleep(void);
 uint8_t DataEX_check_RTE_version__needs_update(void);
@@ -56,4 +56,6 @@
 
 uint16_t DataEX_debug_data(uint16_t *dataOut20x5);
 
+void DataEX_setExtInterface_Cmd(uint16_t Cmd);
+
 #endif /* DATA_EXCHANGE_MAIN_H */
--- a/Discovery/Inc/t7.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/t7.h	Fri Aug 19 11:30:24 2022 +0200
@@ -49,6 +49,9 @@
 #ifdef ENABLE_BOTTLE_SENSOR
 		LCC_BottleBar,
 #endif
+#ifdef ENABLE_PSCR_MODE
+		LCC_SimPpo2,
+#endif
 		LLC_END
 
 } customview_llc_t;
@@ -70,6 +73,7 @@
 void init_t7_compass(void);
 
 uint8_t t7_GetEnabled_customviews();
+uint8_t t7_customview_disabled(uint8_t view);
 
 /*
 	 void t7c_refresh(uint32_t FramebufferStartAddress);
--- a/Discovery/Inc/tHome.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/tHome.h	Fri Aug 19 11:30:24 2022 +0200
@@ -71,6 +71,7 @@
 		CVIEW_Hello,
 		CVIEW_CompassDebug,
 		CVIEW_SummaryOfLeftCorner,
+		CVIEW_Charger,
 		CVIEW_END,
 		CVIEW_T3_Decostop,
 		CVIEW_T3_TTS,
--- a/Discovery/Inc/tMenuEditXtra.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/tMenuEditXtra.h	Fri Aug 19 11:30:24 2022 +0200
@@ -33,5 +33,6 @@
 
 void openEdit_Xtra(uint8_t line);
 void refresh_CompassHeading(void);
+void refresh_CO2Data(void);
 
 #endif /* TMENU_EDIT_XTRA_H */
--- a/Discovery/Inc/tStructure.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/tStructure.h	Fri Aug 19 11:30:24 2022 +0200
@@ -195,10 +195,13 @@
 #define StMXTRA_CompassHeading	_MB(2,4,2,1,0)
 
  /* SURFACE MODE */
- #define StMXTRA_ScrubTimer_Max_Minutes	_MB(2,4,1,1,0)
- #define StMXTRA_ScrubTimer_Reset		_MB(2,4,2,1,0)
- #define StMXTRA_ScrubTimer_OP_Mode		_MB(2,4,3,1,0)
-
+#define StMXTRA_ScrubTimer_Max_Minutes	_MB(2,4,1,1,0)
+#define StMXTRA_ScrubTimer_Reset		_MB(2,4,2,1,0)
+#define StMXTRA_ScrubTimer_OP_Mode		_MB(2,4,3,1,0)
+#define StMXTRA_PSCR_O2_Drop			_MB(2,4,4,1,0)
+#define StMXTRA_PSCR_LUNG_RATIO			_MB(2,4,5,1,0)
+#define StMXTRA_CO2_Sensor				_MB(2,4,6,1,0)
+#define StMXTRA_CO2_Sensor_Calib		_MB(2,4,6,2,0)
 
 /* PAGE 5 */
 #define StMDECO		_MB(2,5,0,0,0)
@@ -216,12 +219,13 @@
 /* PAGE 5 EDIT FIELD CONTENT */
 #define StMDECO1_OC						_MB(2,5,1,1,0)
 #define StMDECO1_CC						_MB(2,5,1,2,0)
-#define StMDECO1_Apnea				_MB(2,5,1,3,0)
-#define StMDECO1_Gauge				_MB(2,5,1,4,0)
+#define StMDECO1_Apnea					_MB(2,5,1,3,0)
+#define StMDECO1_Gauge					_MB(2,5,1,4,0)
+#define StMDECO1_PSCR					_MB(2,5,1,5,0)
 
 #define StMDECO2_CCRmode			_MB(2,5,2,1,0)
 #define StMDECO3_PPO2Max			_MB(2,5,3,1,0)
-#define StMDECO4_SafetyStop		_MB(2,5,4,1,0)
+#define StMDECO4_SafetyStop			_MB(2,5,4,1,0)
 #define StMDECO5_FUTURE				_MB(2,5,5,1,0)
 #define StMDECO6_SALINITY			_MB(2,5,6,1,0)
 
@@ -310,7 +314,8 @@
 #define StMSYS5_RebootMainCPU	_MB(2,8,5,9,0)
 #define StMSYS5_ScreenTest		_MB(2,8,5,10,0)
 #define StMSYS5_SetFactoryBC	_MB(2,8,5,11,0)
-#define StMSYS5_SetSampleIndx   _MB(2,8,5,12,0)
+#define StMSYS5_ResetBluetooth	_MB(2,8,5,12,0)
+#define StMSYS5_SetSampleIndx   _MB(2,8,5,13,0)
 
  /* PAGE 9 */
 
--- a/Discovery/Inc/text_multilanguage.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Inc/text_multilanguage.h	Fri Aug 19 11:30:24 2022 +0200
@@ -71,10 +71,11 @@
 		TXT_Temperature,
 		TXT_FutureTTS,
 		TXT_Gas,
-		TXT_Time,
+		TXT_ChargeHour,
 		TXT_Date,
 		TXT_Format,
 		TXT_Warning,
+		TXT_Charging,
 		TXT_o2Sensors,
 		TXT_Brightness,
 		TXT_Cave,
@@ -119,6 +120,7 @@
 		TXT_ClosedCircuit,
 		TXT_Apnoe,
 		TXT_Gauge,
+		TXT_PSClosedCircuit,
 		TXT_Sensor,
 		TXT_FixedSP,
 		TXT_Decoparameters,
@@ -141,6 +143,10 @@
 		TXT_ScrubTimeReset,
 		TXT_ScrubTimeMode,
 		TXT_Percent,
+		TXT_PSCRO2Drop,
+		TXT_PSCRLungRatio,
+		TXT_SimPpo2,
+		TXT_CO2Sensor,
 		/* */
 		TXT_END,
 
@@ -308,6 +314,7 @@
 		TXT2BYTE_Maintenance,
 		TXT2BYTE_SetBatteryCharge,
 		TXT2BYTE_SetFactoryDefaults,
+		TXT2BYTE_ResetBluetooth,
 		TXT2BYTE_SetSampleIndex,
 		TXT2BYTE_Reboot,
 		TXT2BYTE_ButtonLeft,
@@ -335,6 +342,8 @@
 		TXT2BYTE_Normal,
 		TXT2BYTE_Maximum,
 
+		TXT2BYTE_CheckSettings,
+
 		TXT2BYTE_END
 };
 
--- a/Discovery/Src/base.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/base.c	Fri Aug 19 11:30:24 2022 +0200
@@ -507,6 +507,7 @@
         {
 	        DoDisplayRefresh = 0;
 
+	        updateSetpointStateUsed();
             if(stateUsed == stateSimGetPointer())
             {
                 simulation_UpdateLifeData(1);
@@ -588,8 +589,6 @@
     case BaseHome:
     case BaseMenu:
     case BaseInfo:
-        updateSetpointStateUsed();
-
         DateEx_copy_to_dataOut();
         DataEX_copy_to_LifeData(&modeChange);
 //foto session :-)  stateRealGetPointerWrite()->lifeData.battery_charge = 99;
@@ -769,17 +768,20 @@
 					}
 				} else if ((status.page == PageDive) && (status.line != 0))
 				{
-					if (pSettings->extraDisplay == EXTRADISPLAY_BIGFONT)
+					if(get_globalState() == StDMENU)
 					{
-						pSettings->design = 3;
-						if(pSettings->MotionDetection == MOTION_DETECT_SECTOR)
+						if (pSettings->extraDisplay == EXTRADISPLAY_BIGFONT)
 						{
-							DefineSectorCount(CUSTOMER_DEFINED_VIEWS);
-							MapCVToSector();
+							pSettings->design = 3;
+							if(pSettings->MotionDetection == MOTION_DETECT_SECTOR)
+							{
+								DefineSectorCount(CUSTOMER_DEFINED_VIEWS);
+								MapCVToSector();
+							}
 						}
+						else if (pSettings->extraDisplay	== EXTRADISPLAY_DECOGAME)
+							pSettings->design = 4;
 					}
-					else if (pSettings->extraDisplay	== EXTRADISPLAY_DECOGAME)
-						pSettings->design = 4;
 					set_globalState(StD);
 				}
 				else
@@ -1151,6 +1153,13 @@
         /* important levelAmbient 300 - 1200 */
         levelAmbient = 10 * pStateReal->lifeData.ambient_light_level;
 
+        if((pStateReal->chargeStatus == CHARGER_running) || (pStateReal->chargeStatus == CHARGER_lostConnection))
+        {
+        	levelMax = 1000;
+        	levelMin = 500;
+        }
+        else
+        {
         switch(	pSettings->brightness + blBoost)
         {
         case 0: /* Cave */
@@ -1192,6 +1201,7 @@
 //			wasLostConnection = 0;
         }
 //	}
+        }
 
     if(levelAmbient > levelActual)
         levelActual += levelUpStep_100ms;
@@ -1203,8 +1213,9 @@
         levelActual = levelMax;
     else
     if(levelActual < levelMin)
+    {
         levelActual = levelMin;
-
+    }
 //	sConfig.Pulse = levelActual / 20;
     sConfig.Pulse = (levelMin + ((levelMax - levelMin)/2)) / 20; // added 170306
 
@@ -1212,8 +1223,8 @@
     if(sConfig.Pulse > 600)
         sConfig.Pulse = 600;
     else
-    if(sConfig.Pulse < 100)
-        sConfig.Pulse = 100;
+    if(sConfig.Pulse < 25)
+        sConfig.Pulse = 25;
 
     HAL_TIM_PWM_ConfigChannel(&TimBacklightHandle, &sConfig, TIM_BACKLIGHT_CHANNEL);
     HAL_TIM_PWM_Start(&TimBacklightHandle, TIM_BACKLIGHT_CHANNEL);
@@ -1716,24 +1727,37 @@
 			switch(status.base)
 			{
 			case BaseHome:
-				// added hw 161027
-				if(!(stateRealGetPointer()->warnings.lowBattery) && (stateRealGetPointer()->lifeData.battery_charge > 9))
+				/* The RTE will mark a charge value as suspect after startup. Main know the update condition and may confirm that the value is most likely valid */
+	//			if(!(stateRealGetPointer()->warnings.lowBattery) && ((stateRealGetPointer()->lifeData.battery_charge > 9) || (wasFirmwareUpdateCheckBattery)))
 				{
-					stateRealGetPointerWrite()->lastKnownBatteryPercentage = stateRealGetPointer()->lifeData.battery_charge;
+					if(stateRealGetPointer()->lifeData.battery_charge < 0.0)
+					{
+						if(fabs(stateRealGetPointerWrite()->lastKnownBatteryPercentage - fabs(stateRealGetPointer()->lifeData.battery_charge)) < 1.0)
+						{
+							setBatteryPercentage(settingsGetPointer()->lastKnownBatteryPercentage);	/* confirm that value provided by RTE is valid (maybe reset happened) */
+						}
+					}
+					else
+					{
+						if(!(stateRealGetPointer()->warnings.lowBattery) && (stateRealGetPointer()->lifeData.battery_charge > 9))
+						{
+							stateRealGetPointerWrite()->lastKnownBatteryPercentage = stateRealGetPointer()->lifeData.battery_charge;
+						}
+					}
 				}
-				else if((wasFirmwareUpdateCheckBattery) && (timeout_in_seconds > 3))
+				if((wasFirmwareUpdateCheckBattery) && (timeout_in_seconds > 3))
 				{
 					wasFirmwareUpdateCheckBattery = 0;
 					setButtonResponsiveness(settingsGetPointer()->ButtonResponsiveness); // added 170306
 					if(	(settingsGetPointer()->lastKnownBatteryPercentage > 0)
-					&& 	(settingsGetPointer()->lastKnownBatteryPercentage <= 100)
+					&& 	(settingsGetPointer()->lastKnownBatteryPercentage <= 101.0)
 					&& 	(stateRealGetPointer()->warnings.lowBattery))
 					{
 						setBatteryPercentage(settingsGetPointer()->lastKnownBatteryPercentage);
 					}
 				}
 				// stuff before and new @161121 CCR-sensor limit 10 minutes
-				if((settingsGetPointer()->dive_mode == DIVEMODE_CCR) && (settingsGetPointer()->CCR_Mode == CCRMODE_Sensors))
+				if(isLoopMode(settingsGetPointer()->dive_mode) && (settingsGetPointer()->CCR_Mode == CCRMODE_Sensors))
 				{
 					timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemodeWithSensors;
 				}
--- a/Discovery/Src/check_warning.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/check_warning.c	Fri Aug 19 11:30:24 2022 +0200
@@ -128,7 +128,7 @@
 /* Private functions ---------------------------------------------------------*/
 static int8_t check_fallback(SDiveState * pDiveState)
 {
-	if(fallback && ((pDiveState->mode != MODE_DIVE) || (pDiveState->diveSettings.diveMode != DIVEMODE_CCR)))
+	if(fallback && ((pDiveState->mode != MODE_DIVE) || (!isLoopMode(pDiveState->diveSettings.diveMode))))
 		fallback = 0;
 	
 	pDiveState->warnings.fallback = fallback;
@@ -181,7 +181,7 @@
 	pDiveState->warnings.sensorOutOfBounds[1] = 0;
 	pDiveState->warnings.sensorOutOfBounds[2] = 0;
 
-	if((pDiveState->diveSettings.diveMode == DIVEMODE_CCR) && (pDiveState->diveSettings.CCR_Mode == CCRMODE_Sensors))
+	if(isLoopMode(pDiveState->diveSettings.diveMode) && (pDiveState->diveSettings.CCR_Mode == CCRMODE_Sensors))
 
 		if(settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_OPTIC)
 		{
@@ -218,7 +218,7 @@
 	betterGasIdLocal = pLifeData->actualGas.GasIdInSettings;
 	bestGasDepth = 255;
 
-	if(pDiveSettings->diveMode == DIVEMODE_CCR)
+	if(isLoopMode(pDiveSettings->diveMode))
 		gasIdOffset = NUM_OFFSET_DILUENT;
 	else
 		gasIdOffset = 0;
@@ -285,33 +285,31 @@
 {
 	pDiveState->warnings.betterSetpoint = 0;
 	betterSetpointId = 0;
-
-	if((stateUsed->mode != MODE_DIVE) || (pDiveState->diveSettings.diveMode != DIVEMODE_CCR) || (pDiveState->diveSettings.CCR_Mode != CCRMODE_FixedSetpoint))
-	{
-		return 0;
-	}
-	
 	uint8_t bestSetpointDepth = 0; // travel the deeper, the better
 	uint8_t betterSetpointIdLocal = 0; // nothing better
 
-	if(!actualLeftMaxDepth(pDiveState)) /* travel gases */
+
+	if((stateUsed->mode == MODE_DIVE) && (pDiveState->diveSettings.diveMode == DIVEMODE_CCR))
 	{
-		for(int i=1; i<=NUM_GASES; i++)
+		if(!actualLeftMaxDepth(pDiveState)) /* travel gases */
 		{
-			if(	 (pDiveState->diveSettings.setpoint[i].note.ub.active)
-				&& (pDiveState->diveSettings.setpoint[i].depth_meter)
-				&& (pDiveState->diveSettings.setpoint[i].depth_meter <= ( pDiveState->lifeData.depth_meter + 0.01f ))
-				&& (pDiveState->diveSettings.setpoint[i].depth_meter >= bestSetpointDepth)
-			)
-				{
-					betterSetpointIdLocal = i;
-					bestSetpointDepth = pDiveState->diveSettings.setpoint[i].depth_meter;
-				}
-		}
-		if((betterSetpointIdLocal) && (pDiveState->diveSettings.setpoint[betterSetpointIdLocal].setpoint_cbar  != pDiveState->lifeData.actualGas.setPoint_cbar))
-		{
-			betterSetpointId = betterSetpointIdLocal;
-			pDiveState->warnings.betterSetpoint = 1;
+			for(int i=1; i<=NUM_GASES; i++)
+			{
+				if(	 (pDiveState->diveSettings.setpoint[i].note.ub.active)
+					&& (pDiveState->diveSettings.setpoint[i].depth_meter)
+					&& (pDiveState->diveSettings.setpoint[i].depth_meter <= ( pDiveState->lifeData.depth_meter + 0.01f ))
+					&& (pDiveState->diveSettings.setpoint[i].depth_meter >= bestSetpointDepth)
+				)
+					{
+						betterSetpointIdLocal = i;
+						bestSetpointDepth = pDiveState->diveSettings.setpoint[i].depth_meter;
+					}
+			}
+			if((betterSetpointIdLocal) && (pDiveState->diveSettings.setpoint[betterSetpointIdLocal].setpoint_cbar  != pDiveState->lifeData.actualGas.setPoint_cbar))
+			{
+				betterSetpointId = betterSetpointIdLocal;
+				pDiveState->warnings.betterSetpoint = 1;
+			}
 		}
 	}
 	return pDiveState->warnings.betterSetpoint;
@@ -350,7 +348,7 @@
 
 static int8_t check_Battery(SDiveState * pDiveState)
 {
-	if(pDiveState->lifeData.battery_charge < 10)
+	if((pDiveState->lifeData.battery_charge > 0) && (pDiveState->lifeData.battery_charge < 10))
 		pDiveState->warnings.lowBattery = 1;
 	else
 		pDiveState->warnings.lowBattery = 0;
--- a/Discovery/Src/data_central.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/data_central.c	Fri Aug 19 11:30:24 2022 +0200
@@ -71,6 +71,7 @@
 #include "ostc.h" // for button adjust on hw testboard 1
 #include "tCCR.h"
 #include "crcmodel.h"
+#include "configuration.h"
 
 static SDiveState stateReal = { 0 };
 SDiveState stateSim = { 0 };
@@ -316,21 +317,29 @@
 
 void createDiveSettings(void)
 {
+	int i;
 	SSettings* pSettings = settingsGetPointer();
 
-	setActualGasFirst(&stateReal.lifeData);
-
 	stateReal.diveSettings.compassHeading = pSettings->compassBearing;
 	stateReal.diveSettings.ascentRate_meterperminute = 10;
 
 	stateReal.diveSettings.diveMode = pSettings->dive_mode;
 	stateReal.diveSettings.CCR_Mode = pSettings->CCR_Mode;
-	if(stateReal.diveSettings.diveMode == DIVEMODE_CCR)
+	if((stateReal.diveSettings.diveMode == DIVEMODE_PSCR) && (stateReal.diveSettings.CCR_Mode == CCRMODE_FixedSetpoint))
+	{
+		/* TODO: update selection of sensor used on/off (currently sensor/fixpoint). As PSCR has no fixed setpoint change to simulated ppo2 if sensors are not active */
+		stateReal.diveSettings.CCR_Mode = CCRMODE_Simulation;
+	}
+
+	if(isLoopMode(stateReal.diveSettings.diveMode))
 		stateReal.diveSettings.ccrOption = 1;
 	else
 		stateReal.diveSettings.ccrOption = 0;
 	memcpy(stateReal.diveSettings.gas, pSettings->gas,sizeof(pSettings->gas));
 	memcpy(stateReal.diveSettings.setpoint, pSettings->setpoint,sizeof(pSettings->setpoint));
+
+	setActualGasFirst(&stateReal.lifeData);
+
 	stateReal.diveSettings.gf_high = pSettings->GF_high;
 	stateReal.diveSettings.gf_low = pSettings->GF_low;
 	stateReal.diveSettings.input_next_stop_increment_depth_bar = ((float)pSettings->stop_increment_depth_meter) / 10.0f;
@@ -341,13 +350,24 @@
 	stateReal.diveSettings.ppo2sensors_deactivated = pSettings->ppo2sensors_deactivated;
 	stateReal.diveSettings.future_TTS_minutes = pSettings->future_TTS;
 	
+	stateReal.diveSettings.pscr_lung_ratio = pSettings->pscr_lung_ratio;
+	stateReal.diveSettings.pscr_o2_drop = pSettings->pscr_o2_drop;
+
+	if(stateReal.diveSettings.diveMode == DIVEMODE_PSCR)
+	{
+		for(i=0; i<5; i++)
+		{
+			stateReal.diveSettings.decogaslist[i].pscr_factor = 1.0 / stateReal.diveSettings.pscr_lung_ratio * stateReal.diveSettings.pscr_o2_drop;
+		}
+	}
+
 	decom_CreateGasChangeList(&stateReal.diveSettings, &stateReal.lifeData); // decogaslist
 	stateReal.diveSettings.internal__pressure_first_stop_ambient_bar_as_upper_limit_for_gf_low_otherwise_zero = 0;
 
 	/* for safety */
 	stateReal.diveSettings.input_second_to_last_stop_depth_bar = stateReal.diveSettings.last_stop_depth_bar + stateReal.diveSettings.input_next_stop_increment_depth_bar;
 	/* and the proper calc */
-	for(int i = 1; i <10; i++)
+	for(i = 1; i <10; i++)
 	{
 		if(stateReal.diveSettings.input_next_stop_increment_depth_bar * i > stateReal.diveSettings.last_stop_depth_bar)
 		{
@@ -389,9 +409,11 @@
 }
 
 
+
+
 void updateSetpointStateUsed(void)
 {
-	if(stateUsed->diveSettings.diveMode != DIVEMODE_CCR)
+	if(!isLoopMode(stateUsed->diveSettings.diveMode))
 	{
 		stateUsedWrite->lifeData.actualGas.setPoint_cbar = 0;
 		stateUsedWrite->lifeData.ppO2 = decom_calc_ppO2(stateUsed->lifeData.pressure_ambient_bar, &stateUsed->lifeData.actualGas);
@@ -402,7 +424,17 @@
 		{
 			stateUsedWrite->lifeData.actualGas.setPoint_cbar = get_ppO2SensorWeightedResult_cbar();
 		}
-
+#ifdef ENABLE_PSCR_MODE
+		if(stateUsed->diveSettings.diveMode == DIVEMODE_PSCR)	/* calculate a ppO2 value based on assumptions ( transfered approach from hwos code) */
+		{
+			stateUsedWrite->lifeData.ppo2Simulated_bar = decom_calc_SimppO2_O2based(stateUsed->lifeData.pressure_ambient_bar, stateReal.diveSettings.gas[stateUsed->lifeData.actualGas.GasIdInSettings].oxygen_percentage, stateUsed->lifeData.actualGas.pscr_factor);
+			if(stateUsed->diveSettings.CCR_Mode == CCRMODE_Simulation)
+			{
+				stateUsedWrite->lifeData.actualGas.setPoint_cbar = stateUsedWrite->lifeData.ppo2Simulated_bar * 100;
+			}
+		}
+#endif
+	/* limit calculated value to the physically possible if needed */
 		if((stateUsed->lifeData.pressure_ambient_bar * 100) < stateUsed->lifeData.actualGas.setPoint_cbar)
 			stateUsedWrite->lifeData.ppO2 = stateUsed->lifeData.pressure_ambient_bar;
 		else
@@ -417,7 +449,7 @@
 	uint8_t gasId = 0;
 	uint8_t setpoint_cbar = 0;
 
-	if(pSettings->dive_mode == DIVEMODE_CCR)
+	if(isLoopMode(pSettings->dive_mode))
 	{
 		setpoint_cbar = pSettings->setpoint[1].setpoint_cbar;
 		start = NUM_OFFSET_DILUENT+1;
@@ -449,6 +481,7 @@
 	lifeData->actualGas.helium_percentage =0;
 	lifeData->actualGas.setPoint_cbar = 0;
 	lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0;
+	lifeData->actualGas.AppliedDiveMode = stateUsed->diveSettings.diveMode;
 }
 
 
@@ -466,8 +499,9 @@
 	lifeData->actualGas.helium_percentage = pSettings->gas[gasId].helium_percentage;
 	lifeData->actualGas.setPoint_cbar = setpoint_cbar;
 	lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0;
-	
-	if((pSettings->dive_mode == DIVEMODE_CCR) && (gasId > NUM_OFFSET_DILUENT))
+	lifeData->actualGas.AppliedDiveMode = stateUsed->diveSettings.diveMode;
+	lifeData->actualGas.pscr_factor = 1.0 / pSettings->pscr_lung_ratio * pSettings->pscr_o2_drop;
+	if(isLoopMode(pSettings->dive_mode) && (gasId > NUM_OFFSET_DILUENT))
 		lifeData->lastDiluent_GasIdInSettings = gasId;
 }
 
@@ -525,7 +559,7 @@
   lifeData->actualGas.helium_percentage = helium;
   lifeData->actualGas.setPoint_cbar = setpoint_cbar;
   lifeData->actualGas.change_during_ascent_depth_meter_otherwise_zero = 0;
-
+  lifeData->actualGas.AppliedDiveMode = stateUsed->diveSettings.diveMode;
 }
 
 void setButtonResponsiveness(uint8_t *ButtonSensitivyList)
@@ -814,3 +848,12 @@
 	return compass_compensated;
 }
 
+uint8_t isLoopMode(uint8_t Mode)
+{
+	uint8_t retVal = 0;
+	if((Mode == DIVEMODE_CCR) || (Mode == DIVEMODE_PSCR))
+	{
+		retVal = 1;
+	}
+	return retVal;
+}
--- a/Discovery/Src/data_exchange_main.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/data_exchange_main.c	Fri Aug 19 11:30:24 2022 +0200
@@ -72,7 +72,7 @@
 #include "buehlmann.h"
 #include "externLogbookFlash.h"
 
-//#define TESTBENCH
+/* #define TESTBENCH */
 
 /* Exported variables --------------------------------------------------------*/
 static uint8_t	wasPowerOn = 0;
@@ -94,6 +94,8 @@
 
 static uint8_t DeviceDataUpdated = 0;
 
+static uint16_t externalInterface_Cmd = 0;
+
 /* Private types -------------------------------------------------------------*/
 #define UNKNOWN_TIME_HOURS		1
 #define UNKNOWN_TIME_MINUTES	0
@@ -181,12 +183,12 @@
 	if(getDeviceDataWasSend)
 	{
 		dataOut.getDeviceDataNow = 0;
-		requestNecessary.ub.devicedata = 1;
 	}
 	getDeviceDataWasSend = 0;
 	if(dataOut.getDeviceDataNow)
 	{
 		getDeviceDataWasSend = 1;
+		requestNecessary.ub.devicedata = 1;
 	}
 	
 	if(setEndDiveWasSend)
@@ -203,40 +205,39 @@
 	if(setAccidentFlagWasSend)
 	{
 		dataOut.setAccidentFlag = 0;
-		requestNecessary.ub.accident = 1;
 	}
 	setAccidentFlagWasSend = 0;
 	if(dataOut.setAccidentFlag)
 	{
 		setAccidentFlagWasSend = 1;
+		requestNecessary.ub.accident = 1;
 	}
 
 	if(setDateWasSend)
 	{
 		dataOut.setDateNow = 0;
-		requestNecessary.ub.date = 1;
 	}
 	setDateWasSend = 0;
 	if(dataOut.setDateNow)
 	{
 		setDateWasSend = 1;
+		requestNecessary.ub.date = 1;
 	}
 
 	if(setTimeWasSend)
 	{
 		dataOut.setTimeNow = 0;
-		requestNecessary.ub.time = 1;
 	}
 	setTimeWasSend = 0;
 	if(dataOut.setTimeNow)
 	{
 		setTimeWasSend = 1;
+		requestNecessary.ub.time = 1;
 	}
 
 	if(calibrateCompassWasSend)
 	{
 		dataOut.calibrateCompassNow = 0;
-		requestNecessary.ub.compass = 1;
 	}
 	calibrateCompassWasSend = 0;
 	if(dataOut.calibrateCompassNow)
@@ -247,22 +248,23 @@
 	if(clearDecoWasSend)
 	{
 		dataOut.clearDecoNow = 0;
-		requestNecessary.ub.clearDeco = 1;
+		requestNecessary.ub.compass = 1;
 	}
 	if(dataOut.clearDecoNow)
 	{
 		clearDecoWasSend = 1;
+		requestNecessary.ub.clearDeco = 1;
 	}
 	
 	if(setButtonSensitivityWasSend)
 	{
 		dataOut.setButtonSensitivityNow = 0;
-		requestNecessary.ub.button = 1;
 	}
 	setButtonSensitivityWasSend = 0;
 	if(dataOut.setButtonSensitivityNow)
 	{
 		setButtonSensitivityWasSend = 1;
+		requestNecessary.ub.button = 1;
 	}
 }
 
@@ -389,6 +391,32 @@
 	dataOut.data.offsetPressureSensor_mbar = settings->offsetPressure_mbar;
 	dataOut.data.offsetTemperatureSensor_centiDegree = settings->offsetTemperature_centigrad;
 
+
+
+	if(settings->ppo2sensors_source == O2_SENSOR_SOURCE_ANALOG)
+	{
+			externalInterface_Cmd |= EXT_INTERFACE_ADC_ON | EXT_INTERFACE_33V_ON;
+	}
+
+#ifdef ENABLE_SENTINEL_MODE
+	if(settings->ppo2sensors_source == O2_SENSOR_SOURCE_SENTINEL)
+	{
+			externalInterface_Cmd |= EXT_INTERFACE_33V_ON | EXT_INTERFACE_UART_SENTINEL;
+			externalInterface_Cmd &= (~EXT_INTERFACE_ADC_ON);
+	}
+#endif
+
+	if(settings->ext_uart_protocol)
+	{
+		externalInterface_Cmd |= (settings->ext_uart_protocol << 8);
+	}
+	if(settings->co2_sensor_active)
+	{
+		externalInterface_Cmd |= EXT_INTERFACE_33V_ON | EXT_INTERFACE_UART_CO2;
+	}
+	dataOut.data.externalInterface_Cmd = externalInterface_Cmd;
+	externalInterface_Cmd = 0;
+
 	if((hardwareDataGetPointer()->primarySerial <= 32) || (((hardwareDataGetPointer()->primarySerial == 72) && (hardwareDataGetPointer()->secondarySerial == 15))))
 	{
 		dataOut.revisionHardware = 0x00;
@@ -773,9 +801,14 @@
 
 void DataEX_copy_to_LifeData(_Bool *modeChangeFlag)
 {
+	static uint16_t getDeviceDataAfterStartOfMainCPU = 20;
+
 	SDiveState *pStateReal = stateRealGetPointerWrite();
-	static uint16_t getDeviceDataAfterStartOfMainCPU = 20;
 	uint8_t idx;
+	float meter = 0;
+	SSettings *pSettings;
+
+
 	
 	// wireless - �ltere daten aufr�umen
 #if 0
@@ -836,23 +869,46 @@
 		}
 	}
 
-	/* new 151207 hw */
-	if(requestNecessary.uw != 0)
+	if((requestNecessary.uw != 0) && (dataIn.confirmRequest.uw != 0))
 	{
 		if(((dataIn.confirmRequest.uw) & CRBUTTON) != 0)
 		{
 			requestNecessary.ub.button = 0;
 		}
+		if(((dataIn.confirmRequest.uw) & CRCLEARDECO) != 0)
+		{
+			requestNecessary.ub.clearDeco = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRDATE) != 0)
+		{
+			requestNecessary.ub.date = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRTIME) != 0)
+		{
+			requestNecessary.ub.time = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRCOMPASS) != 0)
+		{
+			requestNecessary.ub.compass = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRDEVICEDATA) != 0)
+		{
+			requestNecessary.ub.devicedata = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRBATTERY) != 0)
+		{
+			requestNecessary.ub.batterygauge = 0;
+		}
+		if(((dataIn.confirmRequest.uw) & CRACCIDENT) != 0)
+		{
+			requestNecessary.ub.accident = 0;
+		}
 
-		if(requestNecessary.ub.button == 1)
+		if(requestNecessary.ub.button == 1)	/* send button values to RTE */
 		{
 			setButtonResponsiveness(settingsGetPointer()->ButtonResponsiveness);
 		}
 	}
-	requestNecessary.uw = 0; // clear all 
-	
-	float meter = 0;
-	SSettings *pSettings;
 
 	/*	uint8_t IAmStolenPleaseKillMe;
 	 */
@@ -883,7 +939,7 @@
 		{
 			for(idx = 0; idx < 3; idx++)
 			{
-				pStateReal->lifeData.sensorVoltage_mV[idx] = dataIn.data[0].extADC_voltage[idx];
+				pStateReal->lifeData.sensorVoltage_mV[idx] = dataIn.data[(dataIn.boolADCO2Data && DATA_BUFFER_ADC)].extADC_voltage[idx];
 				if(pStateReal->lifeData.sensorVoltage_mV[idx] < IGNORE_O2_VOLTAGE_LEVEL_MV)
 				{
 					pStateReal->lifeData.sensorVoltage_mV[idx] = 0.0;
@@ -909,7 +965,6 @@
 		pStateReal->lifeData.dateBinaryFormat = dataIn.data[dataIn.boolTimeData].localtime_rtc_dr;
 		pStateReal->lifeData.timeBinaryFormat = dataIn.data[dataIn.boolTimeData].localtime_rtc_tr;
 	}
-	dataOut.setAccidentFlag = 0;
 
 	if(pStateReal->data_old__lost_connection_to_slave == 0)
 	{
@@ -971,11 +1026,25 @@
 			  pStateReal->lifeData.max_depth_meter = meter;
 		}
 
-		if(dataIn.accidentFlags & ACCIDENT_DECOSTOP)
-			pStateReal->decoMissed_at_the_end_of_dive = 1;
-		if(dataIn.accidentFlags & ACCIDENT_CNS)
-			pStateReal->cnsHigh_at_the_end_of_dive = 1;
-
+		if(requestNecessary.ub.clearDeco == 0)		/* No "reset deco" is send to RTE ? */
+		{
+			if(dataIn.accidentFlags & ACCIDENT_DECOSTOP)
+			{
+				pStateReal->decoMissed_at_the_end_of_dive = 1;
+			}
+			else
+			{
+				pStateReal->decoMissed_at_the_end_of_dive = 0;
+			}
+			if(dataIn.accidentFlags & ACCIDENT_CNS)
+			{
+				pStateReal->cnsHigh_at_the_end_of_dive = 1;
+			}
+			else
+			{
+				pStateReal->cnsHigh_at_the_end_of_dive = 0;
+			}
+		}
 		pStateReal->lifeData.dive_time_seconds = (int32_t)dataIn.data[dataIn.boolTimeData].divetime_seconds;
 		pStateReal->lifeData.dive_time_seconds_without_surface_time = (int32_t)dataIn.data[dataIn.boolTimeData].dive_time_seconds_without_surface_time;
 		pStateReal->lifeData.counterSecondsShallowDepth = dataIn.data[dataIn.boolTimeData].counterSecondsShallowDepth;
@@ -1030,6 +1099,10 @@
 		/* sensorErrors
 		 */
 		pStateReal->sensorErrorsRTE = dataIn.sensorErrors;
+
+		/* data from CO2 sensor */
+		pStateReal->lifeData.CO2_data.CO2_ppm = dataIn.data[(dataIn.boolADCO2Data && DATA_BUFFER_CO2)].CO2_ppm;
+		pStateReal->lifeData.CO2_data.signalStrength = dataIn.data[(dataIn.boolADCO2Data && DATA_BUFFER_CO2)].CO2_signalStrength;
 	}
 
 	/* apnea specials
@@ -1205,3 +1278,10 @@
 
 	return retval;
 }
+
+void DataEX_setExtInterface_Cmd(uint16_t Cmd)
+{
+	externalInterface_Cmd = Cmd;
+	return;
+}
+
--- a/Discovery/Src/gfx_engine.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/gfx_engine.c	Fri Aug 19 11:30:24 2022 +0200
@@ -2754,7 +2754,14 @@
 	}
 // -----------------------------
 	char_truncated_Height = 0;
-	height_left = hgfx->Image->ImageHeight - (hgfx->WindowY0 + cfg->Ydelta);
+	if(!pSettings->FlipDisplay)
+	{
+		height_left = hgfx->Image->ImageHeight - (hgfx->WindowY0 + cfg->Ydelta);
+	}
+	else
+	{
+		height_left = (hgfx->WindowY1 - cfg->Ydelta);
+	}
 	if(height_left < height)
 	{
 		char_truncated_Height = height - height_left;
--- a/Discovery/Src/logbook.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/logbook.c	Fri Aug 19 11:30:24 2022 +0200
@@ -1002,7 +1002,7 @@
             break;
     }
     firstgasid = i + 1;
-    if(header.diveMode == DIVEMODE_CCR)
+    if(isLoopMode(header.diveMode))
       setPointLast = header.setpoint[0].setpoint_cbar;
     else
       setPointLast = 0;
@@ -1166,6 +1166,10 @@
 						gas.setPoint_cbar = setPointVal;
 						if(gasidVal > 0)
 						{
+							if((gasidVal >= NUM_GASES) && (header.diveMode == DIVEMODE_PSCR))		/* in case gas switches the absolute gas ID is used => map to the 0..NUM_GASES index used in header */
+							{
+								gasidVal -= NUM_GASES;
+							}
 							gas.helium_percentage = header.gasordil[gasidVal - 1].helium_percentage;
 							gas.nitrogen_percentage = 100 -  gas.helium_percentage - header.gasordil[gasidVal - 1].oxygen_percentage;
 						}
@@ -1175,7 +1179,15 @@
 							gas.nitrogen_percentage = 100 -  gas.helium_percentage - manualGasVal.percentageO2;
 						}
 						ambiant_pressure_bar =((float)(depthVal + header.surfacePressure_mbar))/1000;
-						ppO2 = decom_calc_ppO2(ambiant_pressure_bar, &gas );
+
+						if(header.diveMode == DIVEMODE_PSCR)
+						{
+							ppO2 = decom_calc_SimppO2(ambiant_pressure_bar, &gas);
+						}
+						else	/* open circuit calculation */
+						{
+							ppO2 = decom_calc_ppO2(ambiant_pressure_bar, &gas);
+						}
 						ppo2[iNum] = (uint16_t) ( ppO2 * 100);
 					}
 
@@ -1297,7 +1309,14 @@
 		logbook_SetCompartmentDesaturation(pStateReal);
 		logbook_SetLastStop(pStateReal->diveSettings.last_stop_depth_bar);
 		gheader.batteryVoltage = pStateReal->lifeData.battery_voltage * 1000;
-		gheader.batteryCharge = pStateReal->lifeData.battery_charge;
+		if(pStateReal->lifeData.battery_charge > 0.0)
+		{
+			gheader.batteryCharge = pStateReal->lifeData.battery_charge;
+		}
+		else
+		{
+			gheader.batteryCharge = 0.0;
+		}
 		logbook_EndDive();
 		bDiveMode = 0;
 	} else
--- a/Discovery/Src/settings.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/settings.c	Fri Aug 19 11:30:24 2022 +0200
@@ -36,10 +36,12 @@
 #include "t7.h"
 #include "data_central.h"
 
+static uint8_t settingsWarning = 0;		/* Active if setting values have been corrected */
+
 SSettings Settings;
 
 const uint8_t RTErequiredHigh = 2;
-const uint8_t RTErequiredLow = 7;
+const uint8_t RTErequiredLow = 9;
 
 const uint8_t FONTrequiredHigh = 1;
 const uint8_t FONTrequiredLow =	0;
@@ -57,16 +59,16 @@
 const SFirmwareData firmware_FirmwareData __attribute__( (section(".firmware_firmware_data")) ) =
 {
     .versionFirst   = 1,
-    .versionSecond 	= 5,
-    .versionThird   = 8,
-    .versionBeta    = 1,
+    .versionSecond 	= 6,
+    .versionThird   = 0,
+    .versionBeta    = 0,
 
     /* 4 bytes with trailing 0 */
     .signature = "mh",
 
-    .release_year = 21,
-    .release_month = 04,
-    .release_day = 26,
+    .release_year = 22,
+    .release_month = 8,
+    .release_day = 19,
     .release_sub = 0,
 
     /* max 48 with trailing 0 */
@@ -85,10 +87,10 @@
  * There might even be entries with fixed values that have no range
  */
 const SSettings SettingsStandard = {
-    .header = 0xFFFF001F,
+    .header = 0xFFFF0022,
     .warning_blink_dsec = 8 * 2,
     .lastDiveLogId = 0,
-    .logFlashNextSampleStartAddress = 0,
+    .logFlashNextSampleStartAddress = SAMPLESTART,
 
     .gas[0].oxygen_percentage = 21,
     .gas[1].oxygen_percentage = 21,
@@ -219,7 +221,7 @@
     .ppO2_min = 15,
     .CNS_max = 90,
     .ascent_MeterPerMinute_max = 30,
-    .ascent_MeterPerMinute_showGraph = 7,
+    .ascent_MeterPerMinute_showGraph = 30,
     .future_TTS = 5,
     .GF_high = 85,
     .GF_low = 30,
@@ -268,13 +270,9 @@
     .bluetoothActive = 0,
     .safetystopDepth = 5,
     .updateSettingsAllowedFromHeader = 0xFFFF0002,
-    .scooterControl = 0,
-    .scooterDrag = 2,
-    .scooterLoad = 2,
-    .scooterNumberOfBatteries = 1,
-    .scooterBattSize = 760,
-    .scooterSPARE1[0] = 0,
-    .scooterSPARE2[0] = 0,
+	.pscr_lung_ratio = 10,
+	.pscr_o2_drop = 4,
+	.co2_sensor_active = 0,
     .ppo2sensors_deactivated = 0,
     .tX_colorscheme  = 0,
     .tX_userselectedLeftLowerCornerPrimary = LLC_Temperature,
@@ -371,8 +369,6 @@
     SSettings* pSettings = settingsGetPointer();
     const SSettings* pStandard = settingsGetPointerStandard();
 
-    pSettings->scooterControl = 0;
-
     /* Pointing to the old header data => set new data depending on what had been added since last version */
     switch(pSettings->header)
     {
@@ -433,15 +429,7 @@
     case 0xFFFF000F:
         pSettings->compassBearing                   = 0;
         // no break
-    case 0xFFFF0010:
-        pSettings->scooterDrag                      = 2;
-        pSettings->scooterLoad                      = 2;
-        pSettings->scooterSPARE1[0]                 = 0;
-        pSettings->scooterSPARE2[0]                 = 0;
-        // no break
     case 0xFFFF0011:
-        pSettings->scooterNumberOfBatteries         = 1;
-        pSettings->scooterBattSize                  = 760;
         pSettings->lastKnownBatteryPercentage       = 0;
         // no break
     case 0xFFFF0012:
@@ -496,7 +484,24 @@
     	pSettings->ppo2sensors_calibCoeff[0] = 0.0;
     	pSettings->ppo2sensors_calibCoeff[1] = 0.0;
     	pSettings->ppo2sensors_calibCoeff[2] = 0.0;
+    	pSettings->amPMTime = 0;
     	// no break
+    case 0xFFFF001E:
+    	pSettings->autoSetpoint = 0;
+    	pSettings->scrubTimerMax = 0;
+    	pSettings->scrubTimerCur = 0;
+    	pSettings->scrubTimerMode = SCRUB_TIMER_OFF;
+    	// no break
+    case 0xFFFF001F:
+    	pSettings->pscr_lung_ratio = 10;
+    	pSettings->pscr_o2_drop = 4;
+    	// no break
+    case 0xFFFF0020:
+    	pSettings->co2_sensor_active = 0;
+    	// no break;
+    case 0xFFFF0021:
+    	pSettings->ext_uart_protocol = 0;
+    	// no break;
     default:
         pSettings->header = pStandard->header;
         break; // no break before!!
@@ -536,6 +541,9 @@
     uint8_t firstGasFoundOC = 0;
     uint8_t firstGasFoundCCR = 0;
 
+
+    settingsWarning = 0; /* reset warning indicator */
+
 /*	uint32_t header;
  */
 
@@ -564,7 +572,8 @@
     if(	(Settings.dive_mode != DIVEMODE_OC) 		&&
             (Settings.dive_mode != DIVEMODE_CCR)  	&&
             (Settings.dive_mode != DIVEMODE_Gauge)	&&
-            (Settings.dive_mode != DIVEMODE_Apnea)		)
+            (Settings.dive_mode != DIVEMODE_Apnea)	&&
+			(Settings.dive_mode != DIVEMODE_PSCR))
     {
         Settings.dive_mode = DIVEMODE_OC;
         corrections++;
@@ -618,9 +627,9 @@
         }
         if(Settings.gas[i].note.ub.first)
         {
-            if(Settings.setpoint[i].note.ub.active != 1)
+            if(Settings.gas[i].note.ub.active != 1)
             {
-                Settings.setpoint[i].note.ub.active = 1;
+                Settings.gas[i].note.ub.active = 1;
                 corrections++;
             }
             if(Settings.gas[i].note.ub.travel == 1)
@@ -671,6 +680,7 @@
         Settings.gas[1].note.ub.first = 1;
         Settings.gas[1].note.ub.travel = 0;
         Settings.gas[1].note.ub.deco = 0;
+        corrections++;
     }
     if(!firstGasFoundCCR)
     {
@@ -678,6 +688,7 @@
         Settings.gas[1 + NUM_GASES].note.ub.first = 1;
         Settings.gas[1 + NUM_GASES].note.ub.travel = 0;
         Settings.gas[1 + NUM_GASES].note.ub.deco = 0;
+        corrections++;
     }
 /*	SSetpointLine setpoint[1 + NUM_GASES];
  */
@@ -747,6 +758,7 @@
 /*	uint8_t CCR_Mode;
  */
     if(	(Settings.CCR_Mode != CCRMODE_Sensors) &&
+    		(Settings.CCR_Mode != CCRMODE_Simulation) &&
             (Settings.CCR_Mode != CCRMODE_FixedSetpoint))
     {
         Settings.CCR_Mode = CCRMODE_FixedSetpoint;
@@ -1461,10 +1473,41 @@
     	Settings.scrubTimerMode = SCRUB_TIMER_OFF;
     	corrections++;
     }
+
+    if((Settings.pscr_lung_ratio > PSCR_MAX_LUNG_RATIO) || (Settings.pscr_lung_ratio < PSCR_MIN_LUNG_RATIO))
+    {
+    	Settings.pscr_lung_ratio = 10;
+    	corrections++;
+    }
+    if(Settings.pscr_o2_drop > PSCR_MAX_O2_DROP)
+    {
+    	Settings.pscr_o2_drop = 4;
+    	corrections++;
+    }
+
+    if(Settings.co2_sensor_active > 1)
+    {
+    	Settings.co2_sensor_active = 0;
+    	corrections++;
+    }
+    if(Settings.co2_sensor_active > UART_MAX_PROTOCOL)
+    {
+    	Settings.ext_uart_protocol = 0;
+    	corrections++;
+    }
+
+    if(corrections)
+    {
+    	settingsWarning = 1;
+    }
+    else
+
     if(corrections > 255)
-        return 255;
-    else
-        return (uint8_t)corrections;
+    {
+    	corrections = 255;
+    }
+
+    return (uint8_t)corrections;
 }
 
 
@@ -2921,3 +2964,13 @@
         }
     }
 }
+
+void reset_SettingWarning()
+{
+	settingsWarning = 0;
+}
+inline uint8_t isSettingsWarning()
+{
+	return settingsWarning;
+}
+
--- a/Discovery/Src/show_logbook.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/show_logbook.c	Fri Aug 19 11:30:24 2022 +0200
@@ -35,6 +35,7 @@
 #include "unit.h"
 #include "configuration.h"
 #include "logbook_miniLive.h"
+#include "text_multilanguage.h"
 
 #include <stdint.h>
 #include <stdio.h>
@@ -515,16 +516,19 @@
     switch(logbookHeader.diveMode)
     {
     case DIVEMODE_OC:
-            snprintf(text,20,"open circuit");
+            snprintf(text,20,"%c",TXT_OpenCircuit);
             break;
     case DIVEMODE_CCR:
-            snprintf(text,20,"closed circuit");
+            snprintf(text,20,"%c",TXT_ClosedCircuit);
             break;
     case DIVEMODE_Gauge:
-            snprintf(text,20,"Gauge");
+            snprintf(text,20,"%c",TXT_Gauge);
             break;
     case DIVEMODE_Apnea:
-            snprintf(text,20,"Apnea");
+            snprintf(text,20,"%c",TXT_Apnoe);
+            break;
+    case DIVEMODE_PSCR:
+            snprintf(text,20,"%c",TXT_PSClosedCircuit);
             break;
     }
     Gfx_write_label_var(hgfx, 30, 250,60, &FontT42,CLUT_GasSensor4,text);
@@ -886,6 +890,10 @@
 {
     SWindowGimpStyle wintemp;
     SWindowGimpStyle winsmal;
+    uint8_t gasWasUsed[NUM_GASES * 2];
+    int16_t index = 0;
+    uint8_t loopMode = 0;
+
     wintemp.left = 50;
     wintemp.right = 799 - wintemp.left;
     wintemp.top = 50;
@@ -899,6 +907,40 @@
     uint8_t  gasdata[1000];
     dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
 
+    char msg[15];
+    char gas_name[15];
+    int j = 0;
+
+    loopMode = isLoopMode(logbookHeader.diveMode);
+
+    /* check if gas was used, independent from its active state */
+    for(index = 0; index < NUM_GASES * 2; index++)
+    {
+    	gasWasUsed[index] = 0;
+    }
+    for(index = 0; index < dataLength; index++)
+    {
+    	if(loopMode)
+    	{
+    		if(gasdata[index] < NUM_GASES)	/* the log entry starts with a ID in range 1..4 independend if diluent is used at start */
+			{
+				gasdata[index] += NUM_GASES;
+			}
+    		else
+    		{
+    			loopMode = 0;				/* after the first gas change, no matter if diluent or bailout, the correct ID will be stored */
+    		}
+    	}
+    	if(gasdata[index] > 0)
+    	{
+    		gasWasUsed[gasdata[index]-1] = 1;		/* The ID stored in the samples is starting with 1 (array[0] = gasID1) */
+    	}
+    	else
+    	{
+    		gasWasUsed[0] = 1;
+    	}
+    }
+
     //--- print coordinate system & depth graph with gaschanges ---
     show_logbook_draw_depth_graph(hgfx, StepBackwards, &wintemp, 1, dataLength, depthdata, gasdata, NULL);
 
@@ -906,21 +948,38 @@
     winsmal.left = wintemp.right - 190;
     winsmal.right =  winsmal.left + 150;
 
-    char msg[15];
-    char gas_name[15];
-    int j = 0;
-    for(int i = 4;i >= 0;i--)
+    loopMode = isLoopMode(logbookHeader.diveMode);
+    for(index = (2 * NUM_GASES) -1; index >= 0; index--)
     {
-        if(logbookHeader.gasordil[i].note.ub.active > 0)
+    	if(gasWasUsed[index])
         {
             j++;
+            if(j > 5)	/* limit number of gases displayed to 5 */
+            {
+            	break;
+            }
             winsmal.top	= wintemp.bottom - 5 - j * 26 ;
             winsmal.bottom = winsmal.top + 21  ;
-            uint8_t color = get_colour(i);
+            uint8_t color = get_colour(index);
 
-            print_gas_name(gas_name,15,logbookHeader.gasordil[i].oxygen_percentage,logbookHeader.gasordil[i].helium_percentage);
-            snprintf(msg,15,"G%i: %s",i + 1, gas_name);
-            //msg[10] = 0;
+            if(loopMode)
+            {
+            	if(index < NUM_GASES)		/* Switch to Bailout is not covered by log gas list */
+            	{
+            		snprintf(gas_name,15,"Bailout");
+            		snprintf(msg,15,"G%d: %s",index +1, gas_name);
+            	}
+            	else
+            	{
+            		print_gas_name(gas_name,15,logbookHeader.gasordil[index-NUM_GASES].oxygen_percentage,logbookHeader.gasordil[index-NUM_GASES].helium_percentage);
+            		snprintf(msg,15,"D%d: %s",index +1 - NUM_GASES, gas_name);
+            	}
+            }
+            else
+            {
+            	print_gas_name(gas_name,15,logbookHeader.gasordil[index].oxygen_percentage,logbookHeader.gasordil[index].helium_percentage);
+            	snprintf(msg,15,"G%d: %s",index +1, gas_name);
+            }
             Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,msg);
         }
     }
@@ -933,6 +992,26 @@
         */
 }
 
+static uint8_t check_data_array_empty(uint16_t* pdata)
+{
+	uint8_t ret = 0;
+	uint8_t index = 0;
+	uint8_t emptyCnt = 0;
+
+	for (index=0; index < 10; index++)	/* read the first 10 data points. If all are 0 then the array is rated as empty */
+	{
+		if(*(pdata+index) == 0)
+		{
+			emptyCnt++;
+		}
+	}
+	if(emptyCnt == 10)
+	{
+		ret = 1;
+	}
+	return ret;
+}
+
 static void show_logbook_logbook_show_log_page4(GFX_DrawCfgScreen *hgfx, uint8_t StepBackwards)
 { SWindowGimpStyle wintemp;
     SWindowGimpStyle winsmal;
@@ -950,18 +1029,55 @@
     uint16_t ppO2data[1000];
     uint16_t sensor2[1000];
     uint16_t sensor3[1000];
-        uint16_t *setpoint = ppO2data;
-        uint16_t *sensor1 = ppO2data;
+    uint16_t *setpoint = ppO2data;
+    uint16_t *sensor1 = ppO2data;
+    uint8_t  sensorDataAvailable[] = {0,0,0};
 
 
-        if(logbookHeader.diveMode != DIVEMODE_CCR)
+        if(!isLoopMode(logbookHeader.diveMode))
             dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, ppO2data, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
         else
         {
-            if(logbookHeader.CCRmode == CCRMODE_FixedSetpoint)
-                dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata, gasdata, NULL, NULL, setpoint, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-            else
-                dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata, gasdata, NULL, NULL, NULL, sensor1, sensor2, sensor3, NULL, NULL, NULL, NULL, NULL);
+        	switch(logbookHeader.CCRmode)
+        	{
+        		case CCRMODE_FixedSetpoint:
+        		default:				dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata, gasdata, NULL, NULL, setpoint, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        				break;
+        		case CCRMODE_Sensors:	dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata, gasdata, NULL, NULL, NULL, sensor1, sensor2, sensor3, NULL, NULL, NULL, NULL, NULL);
+        								if(!check_data_array_empty(sensor1))
+        								{
+        									sensorDataAvailable[0] = 1;
+        								}
+        								if(!check_data_array_empty(sensor2))
+        								{
+        								    sensorDataAvailable[1] = 1;
+        								}
+        								if(!check_data_array_empty(sensor3))
+        								{
+        								    sensorDataAvailable[2] = 1;
+        								}
+        								if((logbookHeader.diveMode == DIVEMODE_PSCR) && (sensorDataAvailable[0] + sensorDataAvailable[1] + sensorDataAvailable[2] != 3)) /*insert sim data if not all three sensors are in use*/
+        								{
+        									if(sensorDataAvailable[0] == 0)
+        									{
+        										logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, sensor1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        										sensorDataAvailable[0] = 1;
+        									}
+        									else if(sensorDataAvailable[1] == 0)
+        									{
+        										logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, sensor2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        										sensorDataAvailable[1] = 1;
+        									}
+        									else if(sensorDataAvailable[2] == 0)
+        									{
+        										logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, sensor3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        										sensorDataAvailable[2] = 1;
+        									}
+        								}
+        		    	break;
+        		case CCRMODE_Simulation: dataLength = logbook_readSampleData(StepBackwards, 1000, depthdata,gasdata, NULL, ppO2data, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        				break;
+        	}
         }
 
 
@@ -999,14 +1115,25 @@
     winsmal.left = 799 - 67;//wintemp.right -67;
     winsmal.right = winsmal.left;// + 45;
 
-    color = CLUT_LogbookTemperature;//LOGBOOK_GRAPH_DEPTH;
-    if(logbookHeader.diveMode != DIVEMODE_CCR)
+    color = CLUT_LogbookTemperature;
+
+    if(!isLoopMode(logbookHeader.diveMode))
+    {
     	Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002PP O2");
+    }
     else
-    if(logbookHeader.CCRmode != CCRMODE_Sensors)
-    	Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002SETPOINT");
-    else
-    	Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002SENSORS");
+    {
+    	switch(logbookHeader.CCRmode)
+    	{
+    		case CCRMODE_FixedSetpoint:
+    		default:				Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002SETPOINT");
+    				break;
+    		case CCRMODE_Sensors:	Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002SENSORS");
+    		    	break;
+    		case CCRMODE_Simulation: Gfx_write_label_var(hgfx, winsmal.left, winsmal.right,winsmal.top, &FontT24,color,"\002SIM PPO2");
+    				break;
+    	}
+    }
 
     //*** PP O2 ****************************************************
     //calc lines and labels
@@ -1019,7 +1146,7 @@
         if(ppO2data[i]<datamin)
             datamin = ppO2data[i];
     }
-    if((logbookHeader.diveMode == DIVEMODE_CCR) && (logbookHeader.CCRmode == CCRMODE_Sensors))
+    if(isLoopMode(logbookHeader.diveMode) && (logbookHeader.CCRmode == CCRMODE_Sensors))
     {
         for(int i=1;i<dataLength;i++)
         {
@@ -1077,11 +1204,20 @@
     wintemp.top = MaxU32LOG(wintemp.top ,0);
     if(wintemp.top < wintemp.bottom)
     {
-        if((logbookHeader.diveMode == DIVEMODE_CCR) && (logbookHeader.CCRmode == CCRMODE_Sensors))
+    	if(isLoopMode(logbookHeader.diveMode) && (logbookHeader.CCRmode == CCRMODE_Sensors))
         {
-            GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, ppO2data,dataLength,CLUT_LogbookTemperature, NULL);
-            GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, sensor2,dataLength,CLUT_LogbookTemperature, NULL);
-            GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, sensor3,dataLength,CLUT_LogbookTemperature, NULL);
+            if(sensorDataAvailable[0])
+            {
+            	GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, ppO2data,dataLength,CLUT_GasSensor2, NULL);
+            }
+            if(sensorDataAvailable[1])
+            {
+            	GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, sensor2,dataLength,CLUT_GasSensor3, NULL);
+            }
+            if(sensorDataAvailable[2])
+            {
+            	GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, sensor3,dataLength,CLUT_GasSensor4, NULL);
+            }
         }
         else
             GFX_graph_print(hgfx,&wintemp,0,1,datamax,datamin, ppO2data,dataLength,CLUT_LogbookTemperature, NULL);
--- a/Discovery/Src/simulation.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/simulation.c	Fri Aug 19 11:30:24 2022 +0200
@@ -391,6 +391,9 @@
 {
     uint8_t ptrGasChangeList = 0; // new hw 160704
 
+    for (int i = 0; i < 40; i++)
+    	gasChangeListDepthGas20x2[i] = 0;
+
     SDiveState * pDiveState = &stateSim;
     copyDiveSettingsToSim();
     vpm_init(&pDiveState->vpm,  pDiveState->diveSettings.vpm_conservatism, 0, 0);
--- a/Discovery/Src/t3.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/t3.c	Fri Aug 19 11:30:24 2022 +0200
@@ -947,6 +947,9 @@
     SDivetime Stopwatch = {0,0,0,0};
     float fAverageDepth, fAverageDepthAbsolute;
 
+#ifdef ENABLE_PSCR_MODE
+    uint8_t showSimPPO2 = 1;
+#endif
     uint16_t tempWinX0;
     uint16_t tempWinX1;
     uint16_t tempWinY0;
@@ -1264,11 +1267,22 @@
 
             if((stateUsed->diveSettings.ppo2sensors_deactivated & (1<<i)) || (stateUsed->lifeData.ppO2Sensor_bar[i] == 0.0))
             {
-                text[textpointer++] = '\031';
-                text[textpointer++] = ' ';
-                text[textpointer++] = '-';
-                text[textpointer++] = ' ';
-                text[textpointer++] = 0;
+#ifdef ENABLE_PSCR_MODE
+            	if((stateUsed->diveSettings.diveMode == DIVEMODE_PSCR) && (showSimPPO2) && (stateUsed->mode == MODE_DIVE))	/* display ppo2 sim in blue letters in case a slot is not used in the ppo2 custom view */
+            	{
+            		text[textpointer++] = '\023';
+            		textpointer += snprintf(&text[textpointer],TEXTSIZE,"%.2f",stateUsed->lifeData.ppo2Simulated_bar);
+            		showSimPPO2 = 0;
+            	}
+            	else
+#endif
+            	{
+					text[textpointer++] = '\031';
+					text[textpointer++] = ' ';
+					text[textpointer++] = '-';
+					text[textpointer++] = ' ';
+					text[textpointer++] = 0;
+            	}
             }
             else
             {
@@ -1279,7 +1293,7 @@
             GFX_write_string(&FontT105,tXc1,text,0);
 
 
-            if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (pSettings->dive_mode == DIVEMODE_CCR))
+            if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && isLoopMode(pSettings->dive_mode))
             {
                  snprintf(text,TEXTSIZE,"\032\002\f%c",TXT_ScrubTime);
                  GFX_write_string(&FontT42,tXc1,text,0);
--- a/Discovery/Src/t7.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/t7.c	Fri Aug 19 11:30:24 2022 +0200
@@ -35,6 +35,7 @@
 #include "gfx_fonts.h"
 #include "logbook_miniLive.h"
 #include "math.h"
+#include "tComm.h"
 #include "tHome.h"
 #include "simulation.h"
 #include "timer.h"
@@ -61,6 +62,7 @@
 
 void t7_miniLiveLogProfile(void);
 void t7_logo_OSTC(void);
+void t7_ChargerView(void);
 static void t7_colorscheme_mod(char *text);
 
 uint8_t t7_test_customview_warnings(void);
@@ -136,7 +138,7 @@
     CVIEW_Compass,
     CVIEW_Tissues,
     CVIEW_sensors_mV,
-    CVIEW_END,
+	CVIEW_Charger,
     CVIEW_END
 };
 
@@ -685,6 +687,7 @@
 void t7_refresh_surface(void)
 {
 	static float debounceAmbientPressure = 0;
+	static uint8_t lastChargeStatus = 0;
     char text[256];
     char timeSuffix;
     uint8_t hours;
@@ -743,8 +746,9 @@
     }
     else
 */
-    if(DataEX_was_power_on())
+    if(DataEX_was_power_on()) {
         GFX_write_string_color(&FontT42,&t7surfaceR,"cold start",4,CLUT_WarningRed);
+    }
 
     /* time and date */
     translateDate(stateUsed->lifeData.dateBinaryFormat, &Sdate);
@@ -1015,7 +1019,7 @@
     else
     {
     	textIdx = 0;
-        if(stateUsed->diveSettings.diveMode == DIVEMODE_CCR)
+        if(isLoopMode(stateUsed->diveSettings.diveMode))
             gasOffset = NUM_OFFSET_DILUENT;
         else
             gasOffset = 0;
@@ -1090,6 +1094,9 @@
 	case DIVEMODE_CCR:
 		GFX_write_string(&FontT24, &t7c1, "\f\002" "CCR", 0);
 		break;
+	case DIVEMODE_PSCR:
+		GFX_write_string(&FontT24, &t7c1, "\f\002" "PSCR", 0);
+		break;
 	case DIVEMODE_OC:
 		GFX_write_string(&FontT24, &t7c1, "\f\002" "OC", 0);
 		break;
@@ -1180,6 +1187,11 @@
     }
     else
     {
+        if(lastChargeStatus == CHARGER_off)
+        {
+        	t7_select_customview(CVIEW_Charger);
+        }
+
         GFX_write_string_color(&Batt24,&t7batt,text,0,CLUT_BatteryCharging);
 
         switch(stateUsed->chargeStatus)
@@ -1200,6 +1212,7 @@
         GFX_write_string_color(&Batt24,&t7charge,text,0,color);
     }
 
+    lastChargeStatus = stateUsed->chargeStatus;
 
 
     customview_warnings = t7_test_customview_warnings_surface_mode();
@@ -1604,13 +1617,21 @@
     {
       	cv_disabled = 1;
     }
+
+    if ((view == CVIEW_Charger) && (stateUsed->chargeStatus != CHARGER_running) && (stateUsed->chargeStatus != CHARGER_lostConnection))
+    {
+       	cv_disabled = 1;
+    }
+
+
     return cv_disabled;
 }
 
 uint8_t t7_change_customview(uint8_t action)
 {
     uint8_t *pViews;
-    uint8_t *pStartView,*pCurView, *pLastView;
+    uint8_t *pStartView,*pLastView;
+    uint8_t *pCurView = NULL;
     _Bool cv_disabled = 0;
 
     if(stateUsed->mode == MODE_DIVE)
@@ -1694,6 +1715,9 @@
     char text[256];
 	char timeSuffix;
 	uint8_t hoursToDisplay;
+#ifdef ENABLE_PSCR_MODE
+	uint8_t showSimPPO2 = 1;
+#endif
     uint16_t textpointer = 0;
     uint16_t heading = 0;
     int16_t start;
@@ -1730,6 +1754,13 @@
         }
         break;
 
+    case CVIEW_Charger:
+             snprintf(text,100,"\032\f\001%c",TXT_Charging);
+            GFX_write_string(&FontT42,&t7cH,text,0);
+            t7_ChargerView();
+
+        break;
+
     case CVIEW_SummaryOfLeftCorner:
         snprintf(text,100,"\032\f\001%c%c",TXT_2BYTE,TXT2BYTE_Summary);
         GFX_write_string(&FontT42,&t7cH,text,0);
@@ -1790,6 +1821,24 @@
             }
             t7cC.WindowNumberOfTextLines = 3;
         }
+        else if(isSettingsWarning())
+		{
+            if(warning_count_high_time)
+            {
+                shiftWindowY0 += 20;
+                t7cC.WindowY0 -= shiftWindowY0;
+                textpointer = 0;
+                text[textpointer++] = '\001';
+                text[textpointer++] = TXT_2BYTE;
+                text[textpointer++] = TXT2BYTE_CheckSettings;
+                text[textpointer++] = '\n';
+                text[textpointer++] = '\r';
+                text[textpointer++] = 0;
+                GFX_write_string_color(&FontT42,&t7cC,text,1, CLUT_WarningRed);
+                t7cC.WindowY0 += shiftWindowY0;
+            }
+            t7cC.WindowNumberOfTextLines = 1;
+		}
         else // customtext
         {
             lineCountCustomtext = t7_customtextPrepare(text);
@@ -1993,13 +2042,24 @@
         {
             if((stateUsed->diveSettings.ppo2sensors_deactivated & (1<<i)) || (stateUsed->lifeData.ppO2Sensor_bar[i] == 0.0))
             {
-                text[textpointer++] = '\031'; // labelcolor
-                text[textpointer++] = '\001';
-                text[textpointer++] = '-';
-                text[textpointer++] = '\n';
-                text[textpointer++] = '\r';
-                text[textpointer++] = '\030'; // main color
-                text[textpointer] = 0;
+#ifdef ENABLE_PSCR_MODE
+            	if((stateUsed->diveSettings.diveMode == DIVEMODE_PSCR) && (showSimPPO2) && (stateUsed->mode == MODE_DIVE))	/* display ppo2 sim in blue letters in case a slot is not used in the ppo2 custom view */
+            	{
+            		text[textpointer++] = '\023';
+            		textpointer += snprintf(&text[textpointer],100,"\001%01.2f\n\r\030",stateUsed->lifeData.ppo2Simulated_bar);
+            		showSimPPO2 = 0;
+            	}
+            	else
+#endif
+            	{
+					text[textpointer++] = '\031'; // labelcolor
+					text[textpointer++] = '\001';
+					text[textpointer++] = '-';
+					text[textpointer++] = '\n';
+					text[textpointer++] = '\r';
+					text[textpointer++] = '\030'; // main color
+					text[textpointer] = 0;
+            	}
             }
             else
             {
@@ -2412,7 +2472,7 @@
         TextR1[textPointer++] = '\a';
         TextR1[textPointer++] = '\001';
         TextR1[textPointer++] = ' ';
-        textPointer += snprintf(&TextR1[textPointer],TEXTSIZE,"%f01.2",((float)(stateUsed->diveSettings.setpoint[actualBetterSetpointId()].setpoint_cbar))/100);
+        textPointer += snprintf(&TextR1[textPointer],TEXTSIZE,"%01.2f",(float)(stateUsed->diveSettings.setpoint[actualBetterSetpointId()].setpoint_cbar) / 100.0);
         TextR1[textPointer++] = '?';
         TextR1[textPointer++] = ' ';
         TextR1[textPointer++] = 0;
@@ -2515,9 +2575,10 @@
 
         if(stateUsed->diveSettings.ccrOption)
         {
-            if(stateUsed->diveSettings.diveMode == DIVEMODE_CCR)
+        	if(isLoopMode(stateUsed->diveSettings.diveMode))
             {
                 snprintf(TextC2,TEXTSIZE,"\020%01.2f",stateUsed->lifeData.ppO2);
+
                 if(stateUsed->warnings.betterSetpoint && warning_count_high_time && (stateUsed->diveSettings.diveMode == DIVEMODE_CCR))
                 {
                     TextC2[0] = '\a'; // inverse instead of color \020
@@ -2547,7 +2608,7 @@
         TextC2[1] = TXT_2BYTE;
         TextC2[2] = TXT2BYTE_WarnCnsHigh;
         TextC2[3] = 0;
-        GFX_write_string_color(&FontT48,&t7c1,TextC2,0,CLUT_WarningRed);
+        GFX_write_string_color(&FontT42,&t7c1,TextC2,0,CLUT_WarningRed);
     }
     else
     {
@@ -2568,6 +2629,9 @@
             GFX_write_string(&FontT24,&t7c1,"\027\f\002" "CCR",0);
         //  GFX_write_string(&FontT24,&t7c1,"\f\177\177\x80" "CCR",0);
         else
+        if(stateUsed->diveSettings.diveMode == DIVEMODE_PSCR)
+                GFX_write_string(&FontT24,&t7c1,"\027\f\002" "PSCR",0);
+        else
         if(stateUsed->diveSettings.ccrOption)
             GFX_write_string(&FontT24,&t7c1,"\f\002\024" "Bailout",0);
         //  GFX_write_string(&FontT24,&t7c1,"\f\177\177\x80\024" "Bailout",0);
@@ -2661,11 +2725,16 @@
     {
     	selection_custom_field++;
     }
-    if((selection_custom_field == LLC_ScrubberTime) && ((settingsGetPointer()->scrubTimerMode == SCRUB_TIMER_OFF) || (settingsGetPointer()->dive_mode != DIVEMODE_CCR)))
+    if((selection_custom_field == LLC_ScrubberTime) && ((settingsGetPointer()->scrubTimerMode == SCRUB_TIMER_OFF) || (!isLoopMode(settingsGetPointer()->dive_mode))))
     {
     	selection_custom_field++;
     }
-
+#ifdef ENABLE_PSCR_MODE
+    if((selection_custom_field == LCC_SimPpo2) && (settingsGetPointer()->dive_mode != DIVEMODE_PSCR))
+    {
+    	selection_custom_field++;
+    }
+#endif
     if(selection_custom_field >= LLC_END)
     {
         selection_custom_field = LLC_Empty;
@@ -2803,6 +2872,12 @@
         	snprintf(text,TEXTSIZE,"\020%u\016\016%%\017", (settingsGetPointer()->scrubTimerCur * 100 / settingsGetPointer()->scrubTimerMax));
         }
 		break;
+#ifdef ENABLE_PSCR_MODE
+    case LCC_SimPpo2:
+        headerText[2] = TXT_SimPpo2;
+        snprintf(text,TEXTSIZE,"\020%.2f\016\016Bar\017",stateUsed->lifeData.ppo2Simulated_bar);
+        break;
+#endif
 
 #ifdef ENABLE_BOTTLE_SENSOR
     case LCC_BottleBar:
@@ -3380,7 +3455,7 @@
     text[textpointer++] = TXT_FutureTTS;
     text[textpointer++] = '\n';
     text[textpointer++] = '\r';
-    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (pSettings->dive_mode == DIVEMODE_CCR))
+    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (isLoopMode(pSettings->dive_mode)))
     {
 		text[textpointer++] = TXT_ScrubTime;
 
@@ -3429,7 +3504,7 @@
     else
     	textpointer += snprintf(&text[textpointer],10,"\020%ih", (pDecoinfoFuture->output_time_to_surface_seconds + 59) / 3600);
 
-    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (pSettings->dive_mode == DIVEMODE_CCR))
+    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (isLoopMode(pSettings->dive_mode)))
     {
         text[textpointer++] = '\n';
         text[textpointer++] = '\r';
@@ -3779,3 +3854,212 @@
     windowGimp.top = 40 + 32;
     GFX_draw_image_monochrome(&t7screen, windowGimp, &ImgOSTC, 0);
 }
+
+static uint16_t ChargerLog[60] = {10,10,10,10,10,10,10,10,10,10,
+								  10,10,10,10,10,10,10,10,10,10,
+								  10,10,10,10,10,10,10,10,10,10,
+								  10,10,10,10,10,10,10,10,10,10,
+								  10,10,10,10,10,10,10,10,10,10,
+								  10,10,10,10,10,10,10,10,10,10};
+
+uint16_t LogDeltaCharge(float charge)
+{
+	static uint8_t curIndex = 0;
+	static float averageSpeed = 0.0;
+	uint16_t level = 0;
+	uint16_t completeSec = 0;
+
+	if(charge > 0.003)
+	{
+		level = 2;
+	}
+	else if(charge > 0.0025)
+	{
+			level = 3;
+	}
+	else if(charge > 0.002)
+	{
+			level = 4;
+	}
+	else if(charge > 0.0015)
+	{
+			level = 5;
+	}
+	else if(charge > 0.001)
+	{
+			level = 6;
+	}
+	else if(charge > 0.0005)
+	{
+			level = 7;
+	}
+	else if(charge > 0.00)
+	{
+			level = 8;
+	}
+	else
+	{
+		level = 10;
+	}
+	if(curIndex < 59)
+	{
+		ChargerLog[curIndex++] = level;
+	}
+	else
+	{
+		memcpy (&ChargerLog[0],&ChargerLog[1],sizeof(ChargerLog) - 1);
+		ChargerLog[curIndex] = level;
+	}
+	if(curIndex > 1)
+	{
+		averageSpeed = ((averageSpeed * (curIndex-1)) + charge) / curIndex;
+		completeSec = (100.0 - stateUsed->lifeData.battery_charge) / averageSpeed;
+	}
+	else
+	{
+		completeSec = 0xffff;
+	}
+	return completeSec;
+}
+
+uint16_t* getChargeLog()
+{
+	return ChargerLog;
+}
+
+void t7_ChargerView(void)
+{
+	static float lastCharge = 0.0;
+	float localCharge = 0.0;
+	static uint32_t lastTick = 0;
+	uint32_t curTick = 0;
+	static float speed = 0.0;
+	float deltatime = 0.0;
+
+    char text[256+50];
+    uint8_t textpointer = 0;
+    static uint16_t remainingSec = 0;
+    uint16_t hoursto100 = 0;
+    char indicator = '~';
+
+    point_t start, stop;
+
+    SWindowGimpStyle wintemp;
+	SSettings* pSettings;
+	pSettings = settingsGetPointer();
+
+    t7cY0free.WindowLineSpacing = 28 + 48 + 14;
+    t7cY0free.WindowY0 = t7cH.WindowY0 - 5 - 2 * t7cY0free.WindowLineSpacing;
+    t7cY0free.WindowNumberOfTextLines = 3;
+
+
+    if(pSettings->FlipDisplay)
+    {
+       	t7cY0free.WindowY0 = t7cH.WindowY0 + 15;
+        t7cY0free.WindowY1 = t7cY0free.WindowY0 + 250;
+    }
+
+    localCharge = stateUsed->lifeData.battery_charge;
+    if(localCharge < 0.0)
+    {
+    	localCharge *= -1.0;
+    }
+
+    if(stateUsed->chargeStatus != CHARGER_off)
+    {
+		if(lastCharge != localCharge)
+		{
+			curTick = HAL_GetTick();
+			deltatime = (curTick - lastTick);
+			lastTick = curTick;
+			if(lastCharge < localCharge)
+			{
+				speed = (localCharge - lastCharge) * 1000.0 / deltatime;
+			}
+
+			if(localCharge > 100.0)
+			{
+				localCharge = 100.0;
+			}
+
+			lastCharge = localCharge;
+		}
+
+
+		if(deltatime > 1000)
+		{
+			deltatime = 0;
+			remainingSec = LogDeltaCharge(speed);
+			speed = 0;
+		}
+    }
+    textpointer += snprintf(&text[textpointer],50,"\n\r");
+    textpointer += snprintf(&text[textpointer],50,"\001%c\n\r",TXT_ChargeHour);
+
+    GFX_write_string(&FontT24, &t7cY0free, text, 1);
+
+    hoursto100 = remainingSec / 3600;		/* reduce to hours */
+    if(hoursto100 < 1)
+    {
+    	indicator = '<';
+    	hoursto100 = 1;
+    }
+
+    if(!pSettings->FlipDisplay)
+    {
+    	t7cY0free.WindowY0 -= 52;
+    }
+    else
+    {
+        	t7cY0free.WindowY1 += 52;
+    }
+
+    if((stateUsed->lifeData.battery_charge > 0) && (stateUsed->chargeStatus != CHARGER_off))
+    {
+		snprintf(text,60,
+			"\001%0.2f\016\016%%\017\n\r"
+			"\001%c%d\n\r"
+			,stateUsed->lifeData.battery_charge
+			,indicator
+			,hoursto100);
+    }
+    else
+    {
+		snprintf(text,60,
+			"\001---\n\r"
+			"\001---\n\r");
+    }
+    GFX_write_string(&FontT42, &t7cY0free, text, 1);
+
+    wintemp.left = CUSTOMBOX_LINE_LEFT + CUSTOMBOX_INSIDE_OFFSET + 50;
+    wintemp.right = wintemp.left + CUSTOMBOX_SPACE_INSIDE - 100;
+
+
+    if(!pSettings->FlipDisplay)
+    {
+    	wintemp.top = 480 - t7l1.WindowY0 + 115;
+    	wintemp.bottom = wintemp.top + 100;
+    }
+    else
+    {
+    	wintemp.top = t7l1.WindowY1 + 102;
+    	wintemp.bottom = wintemp.top + 100;
+    }
+
+    start.x =  wintemp.left-5;
+    start.y =  90;
+
+    stop.x = wintemp.right + 5 - start.x;
+    stop.y = 100;
+    GFX_draw_box(&t7screen, start, stop,1, CLUT_Font020);
+
+    if(stateUsed->chargeStatus != CHARGER_off)
+    {
+    	GFX_graph_print(&t7screen, &wintemp, 1,1,0, 10, getChargeLog(), 60, CLUT_Font030, NULL);
+    }
+    else
+    {
+        	GFX_graph_print(&t7screen, &wintemp, 1,1,0, 10, getChargeLog(), 60, CLUT_Font031, NULL);
+    }
+
+}
--- a/Discovery/Src/tCCR.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tCCR.c	Fri Aug 19 11:30:24 2022 +0200
@@ -65,6 +65,13 @@
 #define BOTTLE_SENSOR_TIMEOUT		(6000u)     /* signal pressure budget as not received after 10 minutes (6000 * 100ms) */
 
 #define MAX_SENSOR_COMPARE_DEVIATION (0.15f)	/* max deviation between two sensors allowed before their results are rated as suspect */
+#define MAX_SENSOR_VOLTAGE_MV		(250u)		/* max allowed voltage value for a sensor measurement */
+
+#ifdef ENABLE_ALTERNATIVE_SENSORTYP
+#define MIN_SENSOR_VOLTAGE_MV		(3u)		/* min allowed voltage value for a sensor measurement (Inspiration, Submatix, Sentinel Typ) */
+#else
+#define MIN_SENSOR_VOLTAGE_MV		(8u)		/* min allowed voltage value for a sensor measurement (legacy OSTC TYP)  */
+#endif
 
 /* Private variables ---------------------------------------------------------*/
 static SIrLink receiveHUD[2];
@@ -173,8 +180,8 @@
 
         if(sensorActive[i])
         {
-            if(	(stateUsed->lifeData.sensorVoltage_mV[i] < 8) ||
-                    (stateUsed->lifeData.sensorVoltage_mV[i] > 250))
+            if(	(stateUsed->lifeData.sensorVoltage_mV[i] < MIN_SENSOR_VOLTAGE_MV) ||
+                    (stateUsed->lifeData.sensorVoltage_mV[i] > MAX_SENSOR_VOLTAGE_MV))
             {
                 sensorActive[i] = 0;
                 switch(i)
@@ -330,7 +337,7 @@
 	}
 
 	/* decrease scrubber timer only in real dive mode */
-    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (pSettings->dive_mode == DIVEMODE_CCR) && (stateUsed->mode == MODE_DIVE) && (stateUsed == stateRealGetPointer()))
+    if((pSettings->scrubTimerMode != SCRUB_TIMER_OFF) && (isLoopMode(pSettings->dive_mode)) && (stateUsed->mode == MODE_DIVE) && (stateUsed == stateRealGetPointer()))
     {
     	ScrubberTimeoutCount++;
     	if(ScrubberTimeoutCount >= 600)		/* resolution is minutes */
@@ -444,18 +451,25 @@
 static uint8_t tCCR_fallbackToFixedSetpoint(void)
 {
 	uint8_t retVal = 0;
-    if((stateUsed->mode == MODE_DIVE) && (stateUsed->diveSettings.diveMode == DIVEMODE_CCR) && (stateUsed->diveSettings.CCR_Mode == CCRMODE_Sensors) && (stateUsed->diveSettings.fallbackOption))
-    {
-        uint8_t setpointCbar, actualGasID;
+	uint8_t setpointCbar, actualGasID;
 
-        setpointCbar = stateUsed->diveSettings.setpoint[1].setpoint_cbar;
-        stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_FixedSetpoint;
+    if((stateUsed->mode == MODE_DIVE) && (stateUsed->diveSettings.CCR_Mode == CCRMODE_Sensors) && (stateUsed->diveSettings.fallbackOption))
+    {
+    	if(stateUsed->diveSettings.diveMode == DIVEMODE_CCR)
+    	{
+			setpointCbar = stateUsed->diveSettings.setpoint[1].setpoint_cbar;
+			stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_FixedSetpoint;
+    	}
+    	else
+    	{
+    		setpointCbar = stateUsed->lifeData.ppo2Simulated_bar * 100;
+    		stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_Simulation;
+    	}
+    	actualGasID = stateUsed->lifeData.actualGas.GasIdInSettings;
+    	setActualGas_DM(&stateUsedWrite->lifeData,actualGasID,setpointCbar);
 
-        actualGasID = stateUsed->lifeData.actualGas.GasIdInSettings;
-        setActualGas_DM(&stateUsedWrite->lifeData,actualGasID,setpointCbar);
-
-        set_warning_fallback();
-        retVal = stateUsed->diveSettings.setpoint[1].setpoint_cbar;
+    	set_warning_fallback();
+    	retVal = setpointCbar;
     }
     return retVal;
 }
--- a/Discovery/Src/tComm.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tComm.c	Fri Aug 19 11:30:24 2022 +0200
@@ -2001,7 +2001,8 @@
     char aRxBuffer[UART_CMD_BUF_SIZE];
     uint8_t sizeAnswer = sizeof(answerOkay) -1;
 	uint8_t result = HAL_OK;
-	uint8_t index = 0;
+	uint8_t indexRef = 0;
+	uint8_t indexBuf = 0;
 	uint8_t answer;
 
 	memset(aRxBuffer,0,UART_CMD_BUF_SIZE);
@@ -2009,25 +2010,46 @@
 	{
 		do
 		{
-			if(answerOkay[index] != aRxBuffer[index])
+			if(answerOkay[indexRef] == aRxBuffer[indexBuf])
 			{
-				index = sizeAnswer;
-				result = HAL_ERROR;		/* unexpected answer => there might be characters left in RX que => read and discard all rx bytes */
-				do
-				{
-					answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxBuffer[index], 1, 10);
-					if (index < UART_CMD_BUF_SIZE) 
-					{
-						index++;
-					}
-				}while(answer == HAL_OK);
-				index = sizeAnswer;
+				indexRef++;
 			}
 			else
 			{
-				index++;
+				if(indexRef != 0)
+				{
+					indexRef = 0;
+				}
 			}
-		}while(index < sizeAnswer);
+			indexBuf++;
+		}while(indexBuf < sizeAnswer);
+
+		if(indexRef != sizeAnswer)		/* unexpected answer => there might be characters left in RX que => read and check all rx bytes */
+		{
+			do
+			{
+				answer = HAL_UART_Receive(&UartHandle, (uint8_t*)&aRxBuffer[indexBuf], 1, 10);
+				if (indexBuf < UART_CMD_BUF_SIZE)
+				{
+					if(answerOkay[indexRef] == aRxBuffer[indexBuf])
+					{
+						indexRef++;
+					}
+					else
+					{
+						if(indexRef != 0)
+						{
+							indexRef = 0;
+						}
+					}
+					indexBuf++;
+				}
+			}while(answer == HAL_OK);
+			if(indexRef != sizeAnswer)
+			{
+				result = HAL_ERROR;
+			}
+		}
 	}
 	else
 	{
@@ -2175,14 +2197,8 @@
 		CmdSize = strlen(TxBuffer);
 		if(HAL_UART_Transmit(&UartHandle, (uint8_t*)TxBuffer,CmdSize, 2000) == HAL_OK)
 		{
-			if(BmTmpConfig == BM_CONFIG_ECHO)	/* echo is not yet turned off => read and discard echo */
-			{
-				HAL_UART_Receive(&UartHandle, (uint8_t*)TxBuffer, CmdSize, UART_OPERATION_TIMEOUT);
-			}
-
 			result = tComm_CheckAnswerOK();
 
-
 			if((BmTmpConfig == BM_CONFIG_BAUD) && (result == HAL_OK) && (UartHandle.Init.BaudRate != 460800)) /* is com already switched to fast speed? */
 			{
 				HAL_UART_DeInit(&UartHandle);
@@ -2190,6 +2206,19 @@
 				UartHandle.Init.BaudRate   = 460800;
 				HAL_UART_Init(&UartHandle);
 			}
+			if((BmTmpConfig == BM_CONFIG_BAUD) && (result == HAL_OK) && (UartHandle.Init.BaudRate == 460800)) /* This shut not happen because default speed is 115200 => update module configuration */
+			{
+				sprintf(TxBuffer,"AT%%B8\r");	/* set default baudrate */
+				CmdSize = strlen(TxBuffer);
+				HAL_UART_Transmit(&UartHandle, (uint8_t*)TxBuffer,CmdSize, 2000);
+				HAL_UART_DeInit(&UartHandle);
+				HAL_Delay(10);
+				UartHandle.Init.BaudRate   = 115200;
+				HAL_UART_Init(&UartHandle);
+				sprintf(TxBuffer,"AT&W\r");		/* write configuration */
+				CmdSize = strlen(TxBuffer);
+				HAL_UART_Transmit(&UartHandle, (uint8_t*)TxBuffer,CmdSize, 2000);
+			}
 			if(result == HAL_OK)
 			{
 				BmTmpConfig++;
@@ -2197,6 +2226,7 @@
 			if(BmTmpConfig == BM_CONFIG_DONE)
 			{
 				ConfigRetryCnt = 0;
+				RestartModule = 1;
 			}
 		}
 	}
@@ -2210,6 +2240,14 @@
 			{
 				RestartModule = 0;      /* only one try */
 				ConfigRetryCnt = 200;	/* used for delay to startup module again */
+
+				if(BmTmpConfig == BM_CONFIG_ECHO)	/* the module did not answer even once => try again with alternative baud rate */
+				{
+					HAL_UART_DeInit(&UartHandle);
+					HAL_Delay(1);
+					UartHandle.Init.BaudRate   = 460800;
+					HAL_UART_Init(&UartHandle);
+				}
 				BmTmpConfig = BM_CONFIG_RETRY;
 			}
 			else						/* even restarting module failed => switch bluetooth off */
--- a/Discovery/Src/tHome.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tHome.c	Fri Aug 19 11:30:24 2022 +0200
@@ -590,7 +590,7 @@
         }
     }
 
-    if((stateUsed->mode == MODE_SURFACE) && (stateUsed->diveSettings.ppo2sensors_deactivated != 0x07) && (stateUsed->diveSettings.ccrOption != 0))
+    if((stateUsed->mode == MODE_SURFACE) && (stateUsed->diveSettings.ppo2sensors_deactivated != 0x07) && (stateUsed->diveSettings.ccrOption != 0) && (!t7_customview_disabled(CVIEW_sensors)))
     {
     	tHome_tick_count_o2sens++;
     	if(tHome_tick_count_o2sens > AUTORETURN_O2SENS)
--- a/Discovery/Src/tMenu.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenu.c	Fri Aug 19 11:30:24 2022 +0200
@@ -58,6 +58,8 @@
 #define MENU_WDW_HIGH	390
 #define KEY_LABEL_HIGH	25	/* Height of the label used for the the user keys */
 
+#define SLOW_UPDATE_CNT	10	/* Some content shall not be update in short intervals => add prescalar */
+
 typedef struct
 {
     uint32_t	StartAddressForPage[MAXPAGES+1];
@@ -530,7 +532,7 @@
         tM_add(StMDECOP);
 //	}
 
-    if((pSettings->dive_mode == DIVEMODE_CCR) || (stateUsed->diveSettings.ccrOption == 1))
+    if((isLoopMode(pSettings->dive_mode)) || (stateUsed->diveSettings.ccrOption == 1))
     {
         tM_add(StMCG);
         tM_add(StMSP);
@@ -586,23 +588,45 @@
 
 void tM_refresh_live_content(void)
 {
+	static uint8_t slowUpdate = SLOW_UPDATE_CNT;
     uint8_t page = 0;
     char text[MAX_PAGE_TEXTSIZE];
     char subtext[MAX_PAGE_TEXTSIZE];
     uint16_t tabPosition;
 
-    if((get_globalState() == StMSYS) && (actual_menu_content == MENU_SURFACE))
+    uint32_t globalState = get_globalState();
+
+    slowUpdate--;
+    page = menu.pageMemoryForNavigation;
+    switch(globalState)
     {
-        page = menu.pageMemoryForNavigation;
-        tMSystem_refresh(0, text, &tabPosition, subtext);
-        update_content_with_new_frame(page, text, tabPosition, subtext);
+    	case StMSYS: 	if(actual_menu_content == MENU_SURFACE)
+    					{
+    						tMSystem_refresh(0, text, &tabPosition, subtext);
+    						update_content_with_new_frame(page, text, tabPosition, subtext);
+    					}
+    		break;
+    	case StMHARD:	tMHardware_refresh(0, text, &tabPosition, subtext);
+        				update_content_with_new_frame(page, text, tabPosition, subtext);
+        	break;
+    	case StMOG:		if((actual_menu_content != MENU_SURFACE) && (slowUpdate == 0))
+    					{
+    						tMOG_refresh(0, text, &tabPosition, subtext);
+    						update_content_with_new_frame(page, text, tabPosition, subtext);
+    					}
+    		break;
+        case StMCG:		if((actual_menu_content != MENU_SURFACE) && (slowUpdate == 0))
+        				{
+        					tMCG_refresh(0, text, &tabPosition, subtext);
+        					update_content_with_new_frame(page, text, tabPosition, subtext);
+        				}
+    		break;
+    	default:
+    		break;
     }
-    else
-    if(get_globalState() == StMHARD)
+    if(slowUpdate == 0)
     {
-        page = menu.pageMemoryForNavigation;
-        tMHardware_refresh(0, text, &tabPosition, subtext);
-        update_content_with_new_frame(page, text, tabPosition, subtext);
+    	slowUpdate = SLOW_UPDATE_CNT;
     }
 
     tMscreen.FBStartAdress = menu.StartAddressForPage[page];
--- a/Discovery/Src/tMenuDeco.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuDeco.c	Fri Aug 19 11:30:24 2022 +0200
@@ -67,6 +67,9 @@
         case DIVEMODE_Apnea:
             divemode = TXT_Apnoe;
             break;
+        case DIVEMODE_PSCR:
+            divemode = TXT_PSClosedCircuit;
+        break;
         default :
         	divemode = TXT_OpenCircuit;
         	break;
@@ -81,14 +84,22 @@
     strcpy(&text[textPointer],"\n\r");
     textPointer += 2;
 
-    if(data->dive_mode == DIVEMODE_CCR)
+    if(isLoopMode(data->dive_mode))
     {
         if((line == 0) || (line == 2))
         {
-            if(data->CCR_Mode == CCRMODE_Sensors)
-                CcrModusTxtId = TXT_Sensor;
-            else
-                CcrModusTxtId = TXT_FixedSP;
+        	switch(data->CCR_Mode)
+        	{
+        		case CCRMODE_Sensors: CcrModusTxtId = TXT_Sensor;
+        			break;
+        		case CCRMODE_FixedSetpoint: CcrModusTxtId = TXT_FixedSP;
+        			break;
+        		case CCRMODE_Simulation: CcrModusTxtId = TXT_SimPpo2;
+        			break;
+        		default:	CcrModusTxtId = 'X';
+        			break;
+        	}
+
 
             textPointer += snprintf(&text[textPointer], 60,\
                 "%c"
--- a/Discovery/Src/tMenuEdit.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEdit.c	Fri Aug 19 11:30:24 2022 +0200
@@ -213,6 +213,13 @@
 	 	 	 break;
 	 	 case (StMXTRA_CompassHeading & MaskFieldDigit):  refreshFct = refresh_CompassHeading;
 	 	 	 break;
+	 	 case (StMXTRA_PSCR_O2_Drop & MaskFieldDigit): if(settingsGetPointer()->dive_mode != DIVEMODE_PSCR)	/* workaround because PSCR mode is set dynamic */
+	 	 	 	 	 	 	 	 	 	 	 	 	 	 {
+	 		 	 	 	 	 	 	 	 	 	 	 	 	 refreshFct = refresh_CO2Data;
+	 	 	 	 	 	 	 	 	 	 	 	 	 	 }
+	 	 	 break;
+	 	 case (StMXTRA_CO2_Sensor & MaskFieldDigit):  refreshFct = refresh_CO2Data;
+	 	 	 break;
 	 	 case (StMSYS4_Info & MaskFieldDigit): refreshFct = &refresh_InformationPage;
 	 	 	 break;
 	 	 case (StMPLAN5_ExitResult & MaskFieldDigit): refreshFct = refresh_PlanResult;
@@ -256,6 +263,7 @@
 {
     if(WriteSettings)
     {
+    	reset_SettingWarning();
         GFX_logoAutoOff();
         ext_flash_write_settings(0);
         WriteSettings = 0;
--- a/Discovery/Src/tMenuEditCustom.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditCustom.c	Fri Aug 19 11:30:24 2022 +0200
@@ -169,6 +169,12 @@
     	text[4] = TXT_AtemGasVorrat;
     	    	break;
 #endif
+
+#ifdef ENABLE_PSCR_MODE
+    case LCC_SimPpo2:
+    	text[4] = TXT_SimPpo2;
+    	    	break;
+#endif
     /* none */
     case LLC_Empty:
         text[4] = '-';
@@ -713,7 +719,7 @@
 uint8_t OnAction_CViewPortLayout(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
 {
 	SSettings* pSettings = settingsGetPointer();
-	if((pSettings->viewPortMode >> 4) & 0x10 != 0)
+	if(((pSettings->viewPortMode >> 4) & 0x10) != 0)
 	{
 		pSettings->viewPortMode &= 0xEF;	/* 1110 1111 */
 	}
--- a/Discovery/Src/tMenuEditDeco.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditDeco.c	Fri Aug 19 11:30:24 2022 +0200
@@ -32,6 +32,7 @@
 #include "gfx_fonts.h"
 #include "tMenuEdit.h"
 #include "unit.h"
+#include "configuration.h"
 
 /* Private variables ---------------------------------------------------------*/
 static uint8_t lineSelected = 0;
@@ -46,11 +47,7 @@
 static void openEdit_Salinity(void);
 
 /* Announced function prototypes -----------------------------------------------*/
-
-static uint8_t OnAction_OC			(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
-static uint8_t OnAction_CC			(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
-static uint8_t OnAction_Apnea		(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
-static uint8_t OnAction_Gauge		(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+static uint8_t OnAction_setMode (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 static uint8_t OnAction_FutureTTS	(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 static uint8_t OnAction_ppO2Max	(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 static uint8_t OnAction_SafetyStop (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
@@ -66,7 +63,7 @@
 
     lineSelected = line;
 
-    if((data->dive_mode != DIVEMODE_CCR )&&  (line > 1))
+    if((!isLoopMode(data->dive_mode)) &&  (line > 1))
         line += 1;
 
     switch(line)
@@ -101,6 +98,7 @@
 #define APNEAANDGAUGE
 
     char text[32];
+    uint8_t lineOffset = 0;
     uint8_t actualDiveMode, active;
     SSettings *pSettings = settingsGetPointer();
     actualDiveMode = pSettings->dive_mode;
@@ -113,6 +111,10 @@
     text[1] = 0;
 
 
+#ifdef ENABLE_PSCR_MODE
+    lineOffset = ME_Y_LINE_STEP;
+#endif
+
     text[0] = TXT_OpenCircuit;
     if(actualDiveMode == DIVEMODE_OC)
         active = 1;
@@ -127,89 +129,81 @@
         active = 0;
     write_field_on_off(StMDECO1_CC,			 30, 500, ME_Y_LINE2,  &FontT48, text, active);
 
-    #ifdef APNEAANDGAUGE
+#ifdef ENABLE_PSCR_MODE
+    text[0] = TXT_PSClosedCircuit;
+    if(actualDiveMode == DIVEMODE_PSCR)
+        active = 1;
+    else
+        active = 0;
+    write_field_on_off(StMDECO1_PSCR,		 30, 500, ME_Y_LINE3,  &FontT48, text, active);
+#endif
+#ifdef APNEAANDGAUGE
     text[0] = TXT_Apnoe;
     if(actualDiveMode == DIVEMODE_Apnea)
         active = 1;
     else
         active = 0;
-    write_field_on_off(StMDECO1_Apnea,	 30, 500, ME_Y_LINE3,  &FontT48, text, active);
+    write_field_on_off(StMDECO1_Apnea,	 30, 500, ME_Y_LINE3 + lineOffset,  &FontT48, text, active);
 
     text[0] = TXT_Gauge;
     if(actualDiveMode == DIVEMODE_Gauge)
         active = 1;
     else
         active = 0;
-    write_field_on_off(StMDECO1_Gauge,	 30, 500, ME_Y_LINE4,  &FontT48, text, active);
-    #endif
+    write_field_on_off(StMDECO1_Gauge,	 30, 500, ME_Y_LINE4 + lineOffset,  &FontT48, text, active);
+#endif
 
-    setEvent(StMDECO1_OC, 			(uint32_t)OnAction_OC);
-    setEvent(StMDECO1_CC, 			(uint32_t)OnAction_CC);
-    #ifdef APNEAANDGAUGE
-    setEvent(StMDECO1_Apnea, 		(uint32_t)OnAction_Apnea);
-    setEvent(StMDECO1_Gauge, 		(uint32_t)OnAction_Gauge);
-    #endif
+    setEvent(StMDECO1_OC, 			(uint32_t)OnAction_setMode);
+    setEvent(StMDECO1_CC, 			(uint32_t)OnAction_setMode);
+#ifdef ENABLE_PSCR_MODE
+    setEvent(StMDECO1_PSCR,			(uint32_t)OnAction_setMode);
+#endif
+
+#ifdef APNEAANDGAUGE
+    setEvent(StMDECO1_Apnea, 		(uint32_t)OnAction_setMode);
+    setEvent(StMDECO1_Gauge, 		(uint32_t)OnAction_setMode);
+#endif
 
     write_buttonTextline(TXT2BYTE_ButtonBack,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonNext);
 }
 
-static uint8_t OnAction_OC						(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+
+static uint8_t OnAction_setMode (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action) //(uint32_t newMode)
 {
-    SSettings *pSettings = settingsGetPointer();
-    if(pSettings->dive_mode == DIVEMODE_OC)
-        return EXIT_TO_MENU;
-    pSettings->dive_mode = DIVEMODE_OC;
-    setActualGasFirst(&stateRealGetPointerWrite()->lifeData);
-    tMenuEdit_set_on_off(editId, 1);
-    tMenuEdit_set_on_off(StMDECO1_CC, 0);
-    tMenuEdit_set_on_off(StMDECO1_Apnea, 0);
-    tMenuEdit_set_on_off(StMDECO1_Gauge, 0);
-    return UPDATE_DIVESETTINGS;
-}
+	uint32_t modeArray[] = {StMDECO1_OC, StMDECO1_CC, StMDECO1_Gauge, StMDECO1_Apnea  /* definition needs to follow order of DIVEMODE (settings.h) */
+#ifdef ENABLE_PSCR_MODE
+			, StMDECO1_PSCR
+#endif
+	};
+
+	uint8_t index = 0;
+	SSettings *pSettings = settingsGetPointer();
+	uint8_t retVal = EXIT_TO_MENU;
+	uint8_t lastMode = pSettings->dive_mode;
 
 
-static uint8_t OnAction_CC						(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
-{
-    SSettings *pSettings = settingsGetPointer();
-    if(pSettings->dive_mode == DIVEMODE_CCR)
-        return EXIT_TO_MENU;
-    pSettings->dive_mode = DIVEMODE_CCR;
-    setActualGasFirst(&stateRealGetPointerWrite()->lifeData);
-    tMenuEdit_set_on_off(editId, 1);
-    tMenuEdit_set_on_off(StMDECO1_OC, 0);
-    tMenuEdit_set_on_off(StMDECO1_Apnea, 0);
-    tMenuEdit_set_on_off(StMDECO1_Gauge, 0);
-    return UPDATE_DIVESETTINGS;
-}
-
-
-static uint8_t OnAction_Apnea				(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
-{
-    SSettings *pSettings = settingsGetPointer();
-    if(pSettings->dive_mode == DIVEMODE_Apnea)
-        return EXIT_TO_MENU;
-    pSettings->dive_mode = DIVEMODE_Apnea;
-    setActualGasFirst(&stateRealGetPointerWrite()->lifeData);
-    tMenuEdit_set_on_off(editId, 1);
-    tMenuEdit_set_on_off(StMDECO1_CC, 0);
-    tMenuEdit_set_on_off(StMDECO1_OC, 0);
-    tMenuEdit_set_on_off(StMDECO1_Gauge, 0);
-    return UPDATE_DIVESETTINGS;
-}
-
-
-static uint8_t OnAction_Gauge				(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
-{
-    SSettings *pSettings = settingsGetPointer();
-    if(pSettings->dive_mode == DIVEMODE_Gauge)
-        return EXIT_TO_MENU;
-    pSettings->dive_mode = DIVEMODE_Gauge;
-    setActualGasFirst(&stateRealGetPointerWrite()->lifeData);
-    tMenuEdit_set_on_off(editId, 1);
-    tMenuEdit_set_on_off(StMDECO1_CC, 0);
-    tMenuEdit_set_on_off(StMDECO1_Apnea, 0);
-    tMenuEdit_set_on_off(StMDECO1_OC, 0);
-    return UPDATE_DIVESETTINGS;
+	setActualGasFirst(&stateRealGetPointerWrite()->lifeData);
+	while(index < sizeof(modeArray) / 4)	/* calculate number of items out of array size (bytes) */
+	{
+		if(editId == modeArray[index])
+		{
+			if(pSettings->dive_mode != index)
+			{
+				tMenuEdit_set_on_off(modeArray[index], 1);
+				pSettings->dive_mode = index;
+				retVal = UPDATE_DIVESETTINGS;
+			}
+		}
+		else
+		{
+			if(lastMode == index)		/* reset state of previous mode selection */
+			{
+				tMenuEdit_set_on_off(modeArray[index], 0);
+			}
+		}
+		index++;
+	}
+	return retVal;
 }
 
 
--- a/Discovery/Src/tMenuEditGasOC.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditGasOC.c	Fri Aug 19 11:30:24 2022 +0200
@@ -92,7 +92,7 @@
     {
 		if(line == 6)
 		{
-			if((settingsGetPointer()->dive_mode == DIVEMODE_CCR) || (stateUsed->diveSettings.ccrOption == 1))
+			if(isLoopMode(settingsGetPointer()->dive_mode) || (stateUsed->diveSettings.ccrOption == 1))
 			{
 				selectPage(StMOG);
 			}
@@ -122,7 +122,7 @@
     {
 		if(line == 6)
 		{
-			if((settingsGetPointer()->dive_mode == DIVEMODE_CCR) || (stateUsed->diveSettings.ccrOption == 1))
+			if(isLoopMode(settingsGetPointer()->dive_mode) || (stateUsed->diveSettings.ccrOption == 1))
 			{
 				selectPage(StMCG);
 			}
@@ -167,9 +167,12 @@
 /* select gas in divemode */
 void openEdit_DiveGasSelect(uint8_t line, uint8_t ccr)
 {
-    openEdit_DiveGasSelect_Subroutine(line, ccr);
-    if(!ccr)
-        tMEGas_check_switch_to_bailout();
+	if(!ccr)
+	{
+		tMEGas_check_switch_to_bailout();
+	}
+	openEdit_DiveGasSelect_Subroutine(line, ccr);
+
     exitMenuEdit_to_Home_with_Menu_Update();
 }
 
@@ -367,7 +370,7 @@
 
 void tMEGas_check_switch_to_bailout(void)
 {
-    if(stateUsed->diveSettings.diveMode == DIVEMODE_CCR)
+    if(isLoopMode(stateUsed->diveSettings.diveMode))
     {
     	stateUsedWrite->diveSettings.diveMode = DIVEMODE_OC;
         block_diluent_page();
--- a/Discovery/Src/tMenuEditHardware.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditHardware.c	Fri Aug 19 11:30:24 2022 +0200
@@ -336,11 +336,18 @@
 		switch(settingsGetPointer()->ppo2sensors_source)
 		{
 			default:
-			case O2_SENSOR_SOURCE_OPTIC: text[1] = TXT2BYTE_O2IFOptic;
+			case O2_SENSOR_SOURCE_OPTIC: 	text[1] = TXT2BYTE_O2IFOptic;
+											text[2] = 0;
+				break;
+			case O2_SENSOR_SOURCE_ANALOG: 	text[1] = TXT2BYTE_O2IFAnalog;
+											text[2] = 0;
 				break;
-			case O2_SENSOR_SOURCE_ANALOG: text[1] = TXT2BYTE_O2IFAnalog;
+#ifdef ENABLE_SENTINEL_MODE
+			case O2_SENSOR_SOURCE_SENTINEL: snprintf(text, 10,"Sentinel");
+				break;
+#endif
 		}
-		text[2] = 0;
+
 		write_label_var(  400, 800, ME_Y_LINE6, &FontT48, text);
     }
     tMenuEdit_refresh_field(StMHARD3_O2_Sensor1);
@@ -378,12 +385,16 @@
     write_field_on_off(StMHARD3_O2_Sensor2,	 30, 95, ME_Y_LINE2,  &FontT48, "", sensorActive[1]);
     write_field_on_off(StMHARD3_O2_Sensor3,	 30, 95, ME_Y_LINE3,  &FontT48, "", sensorActive[2]);
 
-    if(settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_ANALOG)
+    if((settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_ANALOG)
+#ifdef ENABLE_SENTINEL_MODE
+    		|| (settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_SENTINEL)
+#endif
+	)
     {
         write_label_fix(   30, 800, ME_Y_LINE4, &FontT48, TXT2BYTE_O2Calib);
         write_label_var(  400, 800, ME_Y_LINE4, &FontT48, "\016\016 %\017");
 
-        write_field_toggle(StMHARD3_O2_Calibrate,	400, 800, ME_Y_LINE4, &FontT48, "", 21, 100);
+        write_field_toggle(StMHARD3_O2_Calibrate,	400, 800, ME_Y_LINE4, &FontT48, "", 21, 98);
     }
 
     text[0] = TXT_Fallback;
@@ -399,7 +410,11 @@
     setEvent(StMHARD3_O2_Sensor1, (uint32_t)OnAction_Sensor1);
     setEvent(StMHARD3_O2_Sensor2, (uint32_t)OnAction_Sensor2);
     setEvent(StMHARD3_O2_Sensor3, (uint32_t)OnAction_Sensor3);
-    if(settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_ANALOG)
+    if((settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_ANALOG)
+#ifdef ENABLE_SENTINEL_MODE
+    		|| (settingsGetPointer()->ppo2sensors_source == O2_SENSOR_SOURCE_SENTINEL)
+#endif
+	)
     {
     	setEvent(StMHARD3_O2_Calibrate, (uint32_t)OnAction_O2_Calibrate);
     }
@@ -517,7 +532,7 @@
     {
 		if(O2_calib_gas == 21)
 		{
-			O2_calib_gas = 100;
+			O2_calib_gas = 98;
 		}
 		else
 		{
@@ -537,11 +552,8 @@
 {
     uint8_t source = settingsGetPointer()->ppo2sensors_source;
 
-    if(source == O2_SENSOR_SOURCE_OPTIC)
-    {
-    	source = O2_SENSOR_SOURCE_ANALOG;
-    }
-    else
+    source++;
+    if(source == O2_SENSOR_SOURCE_MAX)
     {
     	source = O2_SENSOR_SOURCE_OPTIC;
     }
--- a/Discovery/Src/tMenuEditPlanner.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditPlanner.c	Fri Aug 19 11:30:24 2022 +0200
@@ -307,7 +307,7 @@
     strncpy(text,
         "  "
         "\016\016"
-        "  l\\min"
+        "  l/min"
         "\017"
         "  "
         "\016\016"
@@ -315,36 +315,18 @@
         "\017"
         "   "
         "\016\016"
-        "   l\\min"
+        "   l/min"
         "\017",
         40
     );
     write_label_var(  400, 800, y_line, &FontT48, text);
 
     write_field_udigit(StMPLAN4_Settings,		400, 800, y_line, &FontT48, "##            ##", (uint32_t)travel_lbar, (uint32_t)deco_lbar, 0, 0);
-//	write_field_udigit(StMPLAN4_Settings,		400, 800, y_line, &FontT48, "##\016\016 l\\min\017  \016\016deco\017 ##\016\016 l\\min\017", (uint32_t)travel_lbar, (uint32_t)deco_lbar, 0, 0);
     // note : text max is 32 byte! -> ok and it does not like small fonts in between -> problem
     write_buttonTextline(TXT2BYTE_ButtonMinus,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonPlus);
 
     setEvent(StMPLAN4_Settings,			(uint32_t)OnAction_PlanSettings);
     startEdit();
-
-/*
-    text[textPointer++] = TXT_2BYTE;
-    text[textPointer++] = TXT2BYTE_SimConsumption;
-    text[textPointer++] = '\t';
-    textPointer += snprintf(&text[textPointer],30,
-        "%u"
-        "\016\016 l\\min\017"
-        ,tMplan_gasConsumTravel);
-    text[textPointer++] = ' ';
-    text[textPointer++] = ' ';
-    textPointer += snprintf(&text[textPointer],30,
-        "\016\016deco\017"
-        " %u"
-        "\016\016 l\\min\017"
-        ,tMplan_gasConsumDeco);
-*/
 }
 
 
@@ -622,14 +604,14 @@
             switch(j)
             {
             case 0: // descent
-                textpointer = snprintf(&text[textpointer],20,"-%u\016\016 m\\min\017",tMplan_Summary.descentRateMeterPerMinute);
+                textpointer = snprintf(&text[textpointer],20,"-%u\016\016 m/min\017",tMplan_Summary.descentRateMeterPerMinute);
                 break;
             case 1: // level
                 textpointer = snprintf(&text[textpointer],20,"%1.2f\016\016 %c\017",tMplan_Summary.ppO2AtBottom, TXT_ppO2);
                 break;
             case 2: // first stop
             case 3: // surface
-                textpointer = snprintf(&text[textpointer],20,"%u\016\016 m\\min\017",tMplan_Summary.ascentRateMeterPerMinute);
+                textpointer = snprintf(&text[textpointer],20,"%u\016\016 m/min\017",tMplan_Summary.ascentRateMeterPerMinute);
                 break;
             default:
                 break;
@@ -689,7 +671,7 @@
                     textpointer += snprintf(&text[textpointer],20,"GF %u/%u", stateUsed->diveSettings.gf_low, stateUsed->diveSettings.gf_high);
                 break;
             case 1:
-                if(settingsGetPointer()->dive_mode == DIVEMODE_CCR)
+                if(isLoopMode(settingsGetPointer()->dive_mode))
                     text[textpointer++] = 'C';
                 else
                     text[textpointer++] = 'O';
--- a/Discovery/Src/tMenuEditSetpoint.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditSetpoint.c	Fri Aug 19 11:30:24 2022 +0200
@@ -58,6 +58,8 @@
 void openEdit_Setpoint(uint8_t line)
 {
     uint8_t useSensorSubMenu = 0;
+    char text[20];
+    uint8_t sensorActive[3];
 
     /* dive mode */
     if(actual_menu_content != MENU_SURFACE)
@@ -66,7 +68,7 @@
         setpointCbar = 100;
 
         // actualGasID
-        if(stateUsedWrite->diveSettings.diveMode != DIVEMODE_CCR)
+        if(!isLoopMode(stateUsedWrite->diveSettings.diveMode))
         {
             actualGasID = stateUsedWrite->lifeData.lastDiluent_GasIdInSettings;
             if((actualGasID <= NUM_OFFSET_DILUENT) || (actualGasID > NUM_GASES + NUM_OFFSET_DILUENT))
@@ -76,7 +78,7 @@
             actualGasID = stateUsedWrite->lifeData.actualGas.GasIdInSettings;
 
         // setpointCbar, CCR_Mode and sensor menu
-        if(line < 6)
+        if((line < 6) && (stateUsedWrite->diveSettings.diveMode != DIVEMODE_PSCR))		/* setpoints inactive in PSCR mode */
         {
             setpointCbar = stateUsedWrite->diveSettings.setpoint[line].setpoint_cbar;
             stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_FixedSetpoint;
@@ -96,25 +98,32 @@
                 stateUsedWrite->diveSettings.setpoint[line].note.ub.first = 1;
             }
         }
-        else
+        else	/* menu item not pointing to setpoint selection => use sensor or ppo2 simulation */
         {
-            if(stateUsedWrite->diveSettings.CCR_Mode != CCRMODE_Sensors)
-            {
-                /* setpoint_cbar will be written by updateSetpointStateUsed() in main.c loop */
-                setpointCbar = 255;
-                stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_Sensors;
-            }
-            else
-            {
-                useSensorSubMenu = 1;
-            }
+        	if((stateUsedWrite->diveSettings.diveMode == DIVEMODE_PSCR) && (line == 2))
+			{
+        		stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_Simulation;
+			}
+			else	/* => use sensor */
+			{
+				if(stateUsedWrite->diveSettings.CCR_Mode != CCRMODE_Sensors)
+				{
+					/* setpoint_cbar will be written by updateSetpointStateUsed() in main.c loop */
+					setpointCbar = 255;
+					stateUsedWrite->diveSettings.CCR_Mode = CCRMODE_Sensors;
+				}
+				else
+				{
+					useSensorSubMenu = 1;
+				}
+			}
         }
 
         setActualGas_DM(&stateUsedWrite->lifeData,actualGasID,setpointCbar);
 
-        if(stateUsedWrite->diveSettings.diveMode != DIVEMODE_CCR)
+        if(!isLoopMode(stateUsedWrite->diveSettings.diveMode))
         {
-        	stateUsedWrite->diveSettings.diveMode = DIVEMODE_CCR;
+        	stateUsedWrite->diveSettings.diveMode = settingsGetPointer()->dive_mode;
             unblock_diluent_page();
         }
 
@@ -129,9 +138,6 @@
             set_globalState_Menu_Line(line);
             resetMenuEdit(CLUT_MenuPageGasSP);
 
-            char text[20];
-            uint8_t sensorActive[3];
-
             text[0] = '\001';
             text[1] = TXT_o2Sensors;
             text[2] = 0;
@@ -145,6 +151,7 @@
             else
             {
             	snprintf (text,20,"Sensor 1    (%01.2f)", stateUsed->lifeData.ppO2Sensor_bar[0] );
+            	sensorActive[0] = 1;
             }
             write_label_var(  96, 600, ME_Y_LINE1, &FontT48, text);
             if(stateUsedWrite->diveSettings.ppo2sensors_deactivated & 2)
@@ -155,6 +162,7 @@
             else
             {
                	snprintf (text,20,"Sensor 2    (%01.2f)", stateUsed->lifeData.ppO2Sensor_bar[1] );
+               	sensorActive[1] = 1;
             }
             write_label_var(  96, 600, ME_Y_LINE2, &FontT48, text);
             if(stateUsedWrite->diveSettings.ppo2sensors_deactivated & 4)
@@ -165,13 +173,10 @@
             else
             {
               	snprintf (text,20,"Sensor 3    (%01.2f)", stateUsed->lifeData.ppO2Sensor_bar[2] );
+              	sensorActive[2] = 1;
             }
             write_label_var(  96, 600, ME_Y_LINE3, &FontT48, text);
 
-            sensorActive[0] = 1;
-            sensorActive[1] = 1;
-            sensorActive[2] = 1;
-
             write_field_on_off(StMSP_Sensor1,	 30, 95, ME_Y_LINE1,  &FontT48, "", sensorActive[0]);
             write_field_on_off(StMSP_Sensor2,	 30, 95, ME_Y_LINE2,  &FontT48, "", sensorActive[1]);
             write_field_on_off(StMSP_Sensor3,	 30, 95, ME_Y_LINE3,  &FontT48, "", sensorActive[2]);
@@ -329,23 +334,26 @@
     uint8_t spId;
     uint8_t depth;
 
-    spId = actualBetterSetpointId();
-
-    depth = stateUsedWrite->diveSettings.setpoint[spId].depth_meter;
-
-    // BetterSetpoint warning only once -> clear active
-    for(int i=0; i<=NUM_GASES; i++)
+    if(stateUsedWrite->diveSettings.diveMode != DIVEMODE_PSCR)		/* no setpoints in PSCR mode */
     {
-    	stateUsedWrite->diveSettings.setpoint[i].note.ub.first = 0;
-        if(stateUsedWrite->diveSettings.setpoint[i].depth_meter <= depth)
-        	stateUsedWrite->diveSettings.setpoint[i].note.ub.active = 0;
-    }
+		spId = actualBetterSetpointId();
+
+		depth = stateUsedWrite->diveSettings.setpoint[spId].depth_meter;
 
-    // new setpoint
-    stateUsedWrite->diveSettings.setpoint[spId].note.ub.first = 1;
+		// BetterSetpoint warning only once -> clear active
+		for(int i=0; i<=NUM_GASES; i++)
+		{
+			stateUsedWrite->diveSettings.setpoint[i].note.ub.first = 0;
+			if(stateUsedWrite->diveSettings.setpoint[i].depth_meter <= depth)
+				stateUsedWrite->diveSettings.setpoint[i].note.ub.active = 0;
+		}
 
-    // change in lifeData
-    setActualGas_DM(&stateUsedWrite->lifeData, stateUsedWrite->lifeData.actualGas.GasIdInSettings, stateUsedWrite->diveSettings.setpoint[spId].setpoint_cbar);
+		// new setpoint
+		stateUsedWrite->diveSettings.setpoint[spId].note.ub.first = 1;
+
+		// change in lifeData
+		setActualGas_DM(&stateUsedWrite->lifeData, stateUsedWrite->lifeData.actualGas.GasIdInSettings, stateUsedWrite->diveSettings.setpoint[spId].setpoint_cbar);
+    }
 }
 
 static uint8_t OnAction_SP_DM_Sensor1	(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
--- a/Discovery/Src/tMenuEditSystem.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditSystem.c	Fri Aug 19 11:30:24 2022 +0200
@@ -1081,7 +1081,7 @@
 #endif
 
 
-        if(stateRealGetPointer()->lifeData.battery_charge == 0)
+        if(stateRealGetPointer()->lifeData.battery_charge <= 0)
         {
             text[0] = TXT_2BYTE;
             text[1] = TXT2BYTE_SetBatteryCharge;
--- a/Discovery/Src/tMenuEditXtra.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuEditXtra.c	Fri Aug 19 11:30:24 2022 +0200
@@ -35,6 +35,7 @@
 #include "tMenuEdit.h"
 #include "data_exchange_main.h"
 #include "motion.h"
+#include "configuration.h"
 
 
 /* Private function prototypes -----------------------------------------------*/
@@ -47,10 +48,26 @@
 static void openEdit_ScrubberTimer(uint8_t line);
 static void openEdit_ScrubberReset(void);
 static void openEdit_ScrubberTimerMode(void);
+#ifdef ENABLE_PSCR_MODE
+static void openEdit_PSCRO2Drop(uint8_t line);
+static void openEdit_PSCRLungRatio(uint8_t line);
+#endif
+#ifdef ENABLE_CO2_SUPPORT
+static void openEdit_CO2Sensor(void);
+#endif
 
 /* Announced function prototypes -----------------------------------------------*/
 uint8_t OnAction_CompassHeading	(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 static uint8_t OnAction_ScrubberTimer(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+#ifdef ENABLE_PSCR_MODE
+static uint8_t OnAction_PSCRO2Drop(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+static uint8_t OnAction_PSCRLungRation(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+#endif
+
+#ifdef ENABLE_CO2_SUPPORT
+static uint8_t OnAction_CO2OnOff(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+static uint8_t OnAction_CO2Calib(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+#endif
 
 /* Exported functions --------------------------------------------------------*/
 
@@ -91,6 +108,11 @@
     }
     else /* surface mode */
     {
+    	if((settingsGetPointer()->dive_mode != DIVEMODE_PSCR) && (line > 3))		/* PSCR items are only optional */
+		{
+			line = 6;
+		}
+
 		switch(line)
 		{
 			case 1:	openEdit_ScrubberTimer(line);
@@ -99,6 +121,16 @@
 				break;
 			case 3:	openEdit_ScrubberTimerMode();
 				break;
+#ifdef ENABLE_PSCR_MODE
+			case 4: openEdit_PSCRO2Drop(line);
+				break;
+			case 5: openEdit_PSCRLungRatio(line);
+							break;
+#endif
+#ifdef ENABLE_CO2_SUPPORT
+			case 6: openEdit_CO2Sensor();
+				break;
+#endif
 			default:
 				break;
 		}
@@ -191,6 +223,103 @@
      exitMenuEdit_to_Menu_with_Menu_Update();
 }
 
+#ifdef ENABLE_PSCR_MODE
+static void openEdit_PSCRO2Drop(uint8_t line)
+{
+    uint8_t localO2Drop;
+    uint16_t y_line;
+
+    char text[32];
+    SSettings *pSettings = settingsGetPointer();
+    localO2Drop = pSettings->pscr_o2_drop;
+
+    y_line = ME_Y_LINE_BASE + (line * ME_Y_LINE_STEP);
+
+    text[0] = '\001';
+    text[1] = TXT_PSCRO2Drop;
+    text[2] = 0;
+    write_topline(text);
+
+    text[0] = '\002';
+    text[1] = '\016';
+    text[2] = '\016';
+    text[3] = '%';
+    text[4] = 0;
+    write_label_fix(   20, 800, y_line, &FontT48, TXT_PSCRO2Drop);
+    write_label_var(  435, 780, y_line, &FontT48, text);
+    write_field_udigit(StMXTRA_PSCR_O2_Drop, 710, 779, y_line, &FontT48, "##", (uint32_t)localO2Drop, 0, 0, 0);
+
+    write_buttonTextline(TXT2BYTE_ButtonMinus,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonPlus);
+
+    setEvent(StMXTRA_PSCR_O2_Drop,	(uint32_t)OnAction_PSCRO2Drop);
+    startEdit();
+}
+
+static void openEdit_PSCRLungRatio(uint8_t line)
+{
+    uint8_t localLungRatio;
+    uint16_t y_line;
+
+    char text[32];
+    SSettings *pSettings = settingsGetPointer();
+    localLungRatio = pSettings->pscr_lung_ratio;
+
+    y_line = ME_Y_LINE_BASE + (line * ME_Y_LINE_STEP);
+
+    text[0] = '\001';
+    text[1] = TXT_PSCRO2Drop;
+    text[2] = 0;
+    write_topline(text);
+
+    text[0] = '\002';
+    text[1] = '1';
+    text[2] = '/';
+    text[3] = 0;
+
+    write_label_fix(   20, 800, y_line, &FontT48, TXT_PSCRLungRatio);
+    write_label_var(  435, 710, y_line, &FontT48, text);
+    write_field_udigit(StMXTRA_PSCR_LUNG_RATIO, 710, 779, y_line, &FontT48, "##", (uint32_t)localLungRatio, 0, 0, 0);
+
+    write_buttonTextline(TXT2BYTE_ButtonMinus,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonPlus);
+
+    setEvent(StMXTRA_PSCR_LUNG_RATIO,	(uint32_t)OnAction_PSCRLungRation);
+    startEdit();
+}
+#endif
+
+#ifdef ENABLE_CO2_SUPPORT
+static void openEdit_CO2Sensor()
+{
+    char text[32];
+    snprintf(text,32,"\001%c",TXT_CO2Sensor);
+    write_topline(text);
+
+    refresh_CO2Data();
+    if(settingsGetPointer()->co2_sensor_active)
+    {
+    	text[0] = '\005';
+    }
+    else
+    {
+        text[0] = '\006';
+    }
+    text[0] = TXT_CO2Sensor;
+    text[1] = 0;
+
+    write_field_on_off(StMXTRA_CO2_Sensor,	 30, 95, ME_Y_LINE3,  &FontT48, text, settingsGetPointer()->co2_sensor_active);
+
+   	text[0] = TXT_2BYTE;
+    text[1] = TXT2BYTE_O2Calib;
+    text[2] = 0;
+    write_field_button(StMXTRA_CO2_Sensor_Calib,30, 800, ME_Y_LINE4,  &FontT48, text);
+
+    setEvent(StMXTRA_CO2_Sensor,	(uint32_t)OnAction_CO2OnOff);
+    setEvent(StMXTRA_CO2_Sensor_Calib,	(uint32_t)OnAction_CO2Calib);
+
+    write_buttonTextline(TXT2BYTE_ButtonBack,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonNext);
+}
+#endif
+
 void refresh_CompassHeading(void)
 {
     uint16_t heading;
@@ -209,6 +338,23 @@
     tMenuEdit_refresh_field(StMXTRA_CompassHeading);
 }
 
+void refresh_CO2Data(void)
+{
+    char text[32];
+
+    snprintf(text,32,"\001%c",TXT_CO2Sensor);
+    write_topline(text);
+
+    snprintf(text,32,"CO2: %d ppm",stateUsed->lifeData.CO2_data.CO2_ppm);
+    write_label_var(   30, 800, ME_Y_LINE1, &FontT48, text);
+
+    snprintf(text,32,"Signal: %d",stateUsed->lifeData.CO2_data.signalStrength);
+    write_label_var(   30, 800, ME_Y_LINE2, &FontT48, text);
+
+    tMenuEdit_refresh_field(StMXTRA_CO2_Sensor);
+    tMenuEdit_refresh_field(StMXTRA_CO2_Sensor_Calib);
+}
+
 void openEdit_CompassHeading(void)
 {
 
@@ -267,4 +413,107 @@
     }
     return digitContentNew;
 }
+#ifdef ENABLE_PSCR_MODE
+static uint8_t OnAction_PSCRO2Drop(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+    SSettings *pSettings;
+    uint8_t digitContentNew = EXIT_TO_MENU;
+    uint32_t newO2Drop;
 
+    if(action == ACTION_BUTTON_ENTER)
+    {
+        return digitContent;
+    }
+    if(action == ACTION_BUTTON_ENTER_FINAL)
+    {
+        evaluateNewString(editId, &newO2Drop, 0, 0, 0);
+
+        if(newO2Drop > PSCR_MAX_O2_DROP)
+        	newO2Drop = PSCR_MAX_O2_DROP;
+
+        pSettings = settingsGetPointer();
+        pSettings->pscr_o2_drop = newO2Drop;
+
+        tMenuEdit_newInput(editId, newO2Drop, 0, 0, 0);
+        digitContentNew = UPDATE_AND_EXIT_TO_MENU;
+    }
+    if(action == ACTION_BUTTON_NEXT)
+    {
+        digitContentNew = digitContent + 1;
+        if(digitContentNew > '9')
+            digitContentNew = '0';
+    }
+    if(action == ACTION_BUTTON_BACK)
+    {
+        digitContentNew = digitContent - 1;
+        if(digitContentNew < '0')
+            digitContentNew = '9';
+    }
+    return digitContentNew;
+}
+
+static uint8_t OnAction_PSCRLungRation(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+    SSettings *pSettings;
+    uint8_t digitContentNew = EXIT_TO_MENU;
+    uint32_t newLungRatio;
+
+    if(action == ACTION_BUTTON_ENTER)
+    {
+        return digitContent;
+    }
+    if(action == ACTION_BUTTON_ENTER_FINAL)
+    {
+        evaluateNewString(editId, &newLungRatio, 0, 0, 0);
+
+        if(newLungRatio > PSCR_MAX_LUNG_RATIO)
+        	newLungRatio = PSCR_MAX_LUNG_RATIO;
+
+        if(newLungRatio < PSCR_MIN_LUNG_RATIO)
+        	newLungRatio = PSCR_MIN_LUNG_RATIO;
+
+        pSettings = settingsGetPointer();
+        pSettings->pscr_lung_ratio = newLungRatio;
+
+        tMenuEdit_newInput(editId, newLungRatio, 0, 0, 0);
+        digitContentNew = UPDATE_AND_EXIT_TO_MENU;
+    }
+    if(action == ACTION_BUTTON_NEXT)
+    {
+        digitContentNew = digitContent + 1;
+        if(digitContentNew > '9')
+            digitContentNew = '0';
+    }
+    if(action == ACTION_BUTTON_BACK)
+    {
+        digitContentNew = digitContent - 1;
+        if(digitContentNew < '0')
+            digitContentNew = '9';
+    }
+    return digitContentNew;
+}
+#endif
+
+#ifdef ENABLE_CO2_SUPPORT
+static uint8_t OnAction_CO2OnOff(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+	SSettings *pSettings = settingsGetPointer();
+	if(pSettings->co2_sensor_active)
+	{
+		pSettings->co2_sensor_active = 0;
+		tMenuEdit_set_on_off(StMXTRA_CO2_Sensor,0);
+	}
+	else
+	{
+		pSettings->co2_sensor_active = 1;
+		tMenuEdit_set_on_off(StMXTRA_CO2_Sensor,1);
+	}
+	return UPDATE_DIVESETTINGS;
+}
+
+static uint8_t OnAction_CO2Calib(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+	DataEX_setExtInterface_Cmd(EXT_INTERFACE_CO2_CALIB);
+	return UPDATE_DIVESETTINGS;
+}
+#endif
--- a/Discovery/Src/tMenuGas.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuGas.c	Fri Aug 19 11:30:24 2022 +0200
@@ -55,7 +55,7 @@
     }
     else
     {
-        if (stateUsed->diveSettings.diveMode == DIVEMODE_CCR)
+        if (isLoopMode(stateUsed->diveSettings.diveMode))
             gas_mode = OCGAS_BAILOUT_INACTIVE;
         else
             gas_mode = OCGAS_BAILOUT_ACTIVE;
@@ -328,7 +328,7 @@
 			text[textPointer++] = 0;
     	}
     	else	/* switch to bailout selection in surface mode */
-    	if((settingsGetPointer()->dive_mode == DIVEMODE_CCR) || (stateUsed->diveSettings.ccrOption == 1))
+    	if((isLoopMode(settingsGetPointer()->dive_mode)) || (stateUsed->diveSettings.ccrOption == 1))
     	{
 			text[textPointer++] = '\024';
 			if(gasMode == CCGAS_STANDARD)
--- a/Discovery/Src/tMenuPlanner.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuPlanner.c	Fri Aug 19 11:30:24 2022 +0200
@@ -130,14 +130,14 @@
         text[textPointer++] = '\t';
         textPointer += snprintf(&text[textPointer],30,
             "%u"
-            "\016\016 l\\min\017",
+            "\016\016 l/min\017",
             tMplan_gasConsumTravel);
         text[textPointer++] = ' ';
         text[textPointer++] = ' ';
         textPointer += snprintf(&text[textPointer],30,
             "\016\016deco\017"
             " %u"
-            "\016\016 l\\min\017",
+            "\016\016 l/min\017",
             tMplan_gasConsumDeco);
     }
     strcpy(&text[textPointer],"\n\r");
--- a/Discovery/Src/tMenuSetpoint.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuSetpoint.c	Fri Aug 19 11:30:24 2022 +0200
@@ -53,76 +53,79 @@
     *tab = 130;
     *subtext = 0;
 
-    for(int spId=1;spId<=NUM_GASES;spId++)
+    if((actual_menu_content == MENU_SURFACE) || (stateUsed->diveSettings.diveMode != DIVEMODE_PSCR))	/* do not show setpoints in PSCR mode */
     {
-        if(line && (line != spId))
-        {
-                first = pSetpointLine[spId].note.ub.first;
-                if(first == 0)
-                {
-                    strcpy(&text[textPointer],
-                        "\t"
-                        "\177"
-                        "*"
-                        "\n\r"
-                    );
-                    textPointer += 5;
-                }
-                else
-                {
-                    strcpy(&text[textPointer],"\n\r");
-                    textPointer += 2;
-                }
-        }
-        else
-        {
-            setpoint_cbar = pSetpointLine[spId].setpoint_cbar;
-            depthUp = pSetpointLine[spId].depth_meter;
-            //active = pSetpointLine[spId].note.ub.active;
-            first = pSetpointLine[spId].note.ub.first;
+		for(int spId=1;spId<=NUM_GASES;spId++)
+		{
+			if(line && (line != spId))
+			{
+					first = pSetpointLine[spId].note.ub.first;
+					if(first == 0)
+					{
+						strcpy(&text[textPointer],
+							"\t"
+							"\177"
+							"*"
+							"\n\r"
+						);
+						textPointer += 5;
+					}
+					else
+					{
+						strcpy(&text[textPointer],"\n\r");
+						textPointer += 2;
+					}
+			}
+			else
+			{
+				setpoint_cbar = pSetpointLine[spId].setpoint_cbar;
+				depthUp = pSetpointLine[spId].depth_meter;
+				//active = pSetpointLine[spId].note.ub.active;
+				first = pSetpointLine[spId].note.ub.first;
 
-            strcpy(&text[textPointer],"\020"); // if(active) always active
-            textPointer += 1;
+				strcpy(&text[textPointer],"\020"); // if(active) always active
+				textPointer += 1;
 
-            sp_high = setpoint_cbar / 100;
+				sp_high = setpoint_cbar / 100;
 
-            text[textPointer++] = 'S';
-            text[textPointer++] = 'P';
-            text[textPointer++] = '0' + spId;
-            text[textPointer++] = '\t';
+				text[textPointer++] = 'S';
+				text[textPointer++] = 'P';
+				text[textPointer++] = '0' + spId;
+				text[textPointer++] = '\t';
 
-            if((first == 0) || (actual_menu_content != MENU_SURFACE))
-                strcpy(&text[textPointer++],"\177");
+				if((first == 0) || (actual_menu_content != MENU_SURFACE))
+					strcpy(&text[textPointer++],"\177");
 
-            char color = '\031';
-            if(depthUp)
-                color = '\020';
+				char color = '\031';
+				if(depthUp)
+					color = '\020';
 
-            textPointer += snprintf(&text[textPointer], 57,
-                "* "
-                "%u.%02u"
-                "\016\016"
-                " bar"
-                "\017"
-                "\034"
-                "   "
-                "\016\016"
-                " "
-                "\017"
-                "%c"
-                "%3u"
-                "\016\016"
-                " %c%c"
-                "\017"
-                "\035"
-                "\n\r",
-                sp_high, setpoint_cbar - (100 * sp_high),
-                color,
-                unit_depth_integer(depthUp),
-                unit_depth_char1(),
-                unit_depth_char2()
-            );
-        }
+				textPointer += snprintf(&text[textPointer], 57,
+					"* "
+					"%u.%02u"
+					"\016\016"
+					" bar"
+					"\017"
+					"\034"
+					"   "
+					"\016\016"
+					" "
+					"\017"
+					"%c"
+					"%3u"
+					"\016\016"
+					" %c%c"
+					"\017"
+					"\035"
+					"\n\r",
+					sp_high, setpoint_cbar - (100 * sp_high),
+					color,
+					unit_depth_integer(depthUp),
+					unit_depth_char1(),
+					unit_depth_char2()
+				);
+			}
+		}
     }
     if((actual_menu_content != MENU_SURFACE) /*&& (line == 0)*/)
     {
@@ -131,6 +134,12 @@
         text[textPointer++] = TXT2BYTE_UseSensor;
         text[textPointer++] = '\n';
         text[textPointer++] = '\r';
+
+
+        if(stateUsed->diveSettings.diveMode == DIVEMODE_PSCR)
+        {
+        	textPointer += snprintf(&text[textPointer], 20,"\020%c", TXT_SimPpo2);
+        }
         text[textPointer++] = 0;
     }
     else
--- a/Discovery/Src/tMenuXtra.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/tMenuXtra.c	Fri Aug 19 11:30:24 2022 +0200
@@ -47,6 +47,8 @@
     *tab = 500;
     *subtext = 0;
 
+    SSettings *pSettings = settingsGetPointer();
+
     /* DIVE MODE */
     if(actual_menu_content != MENU_SURFACE)
     {
@@ -133,7 +135,7 @@
                 "\017"
                 ,TXT_ScrubTime
 				,TXT_Maximum
-                ,settingsGetPointer()->scrubTimerMax
+                ,pSettings->scrubTimerMax
                 ,TXT_Minutes
             );
         }
@@ -144,14 +146,14 @@
             textPointer += snprintf(&text[textPointer], 60,\
                         "%c\002%03u\016\016 %c\017"
                         ,TXT_ScrubTimeReset
-                        ,settingsGetPointer()->scrubTimerCur
+                        ,pSettings->scrubTimerCur
                         ,TXT_Minutes);
         }
         strcpy(&text[textPointer],"\n\r");
         textPointer += 2;
         if((line == 0) || (line == 3))
         {
-        	switch(settingsGetPointer()->scrubTimerMode)
+        	switch(pSettings->scrubTimerMode)
         	{
         		case SCRUB_TIMER_OFF:
         		default: 	textPointer += snprintf(&text[textPointer], 60,"%c\002%c%c",TXT_ScrubTimeMode, TXT_2BYTE, TXT2BYTE_MoCtrlNone );
@@ -165,6 +167,35 @@
         strcpy(&text[textPointer],"\n\r");
         textPointer += 2;
 
+#ifdef ENABLE_PSCR_MODE
+        if(pSettings->dive_mode == DIVEMODE_PSCR)
+        {
+            if((line == 0) || (line == 4))
+             {
+                 textPointer += snprintf(&text[textPointer], 60,\
+                             "%c\002%02u\016\016%%\017"
+                             ,TXT_PSCRO2Drop
+                             ,pSettings->pscr_o2_drop);
+             }
+             strcpy(&text[textPointer],"\n\r");
+             textPointer += 2;
+             if((line == 0) || (line == 5))
+              {
+                  textPointer += snprintf(&text[textPointer], 60,\
+                              "%c\002 1/%02u"
+                              ,TXT_PSCRLungRatio
+                              ,pSettings->pscr_lung_ratio);
+              }
+              strcpy(&text[textPointer],"\n\r");
+              textPointer += 2;
+        }
+#endif
+#ifdef ENABLE_CO2_SUPPORT
+        if((line == 0) || (line == 6))
+         {
+             textPointer += snprintf(&text[textPointer], 60, "%c", TXT_CO2Sensor);
+         }
+#endif
     }
     return StMXTRA;
 }
--- a/Discovery/Src/text_multilanguage.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Discovery/Src/text_multilanguage.c	Fri Aug 19 11:30:24 2022 +0200
@@ -453,11 +453,17 @@
 static uint8_t text_IT_ClosedCircuit[] = "Ciurcuito chiuso";
 static uint8_t text_ES_ClosedCircuit[] = "Circuito cerrado";
 
-static uint8_t text_EN_Time[] = "Time";
-static uint8_t text_DE_Time[] = "Uhrzeit";
-static uint8_t text_FR_Time[] = "Heure";
-static uint8_t text_IT_Time[] = "Ora";
-static uint8_t text_ES_Time[] = "Hora";
+static uint8_t text_EN_PSClosedCircuit[] = "PSC circuit";
+static uint8_t text_DE_PSClosedCircuit[] = "PSC Kreislauf";
+static uint8_t text_FR_PSClosedCircuit[] = "PSC circuit";
+static uint8_t text_IT_PSClosedCircuit[] = "PSC circuit";
+static uint8_t text_ES_PSClosedCircuit[] = "PSC circuit";
+
+static uint8_t text_EN_ChargeHour[] = "Hour(s) till 100%";
+static uint8_t text_DE_ChargeHour[] = "Stunde(n) bis 100%";
+static uint8_t text_FR_ChargeHour[] = "";
+static uint8_t text_IT_ChargeHour[] = "";
+static uint8_t text_ES_ChargeHour[] = "";
 
 static uint8_t text_EN_Date[] = "Date";
 static uint8_t text_DE_Date[] = "Datum";
@@ -1134,6 +1140,13 @@
 static uint8_t text_IT_Warning[] = "Pericolo";
 static uint8_t text_ES_Warning[] = "Peligro";
 
+// Customview Header
+static uint8_t text_EN_Charging[] = "Charging";
+static uint8_t text_DE_Charging[] = "Ladezyklus";
+static uint8_t text_FR_Charging[] = "";
+static uint8_t text_IT_Charging[] = "";
+static uint8_t text_ES_Charging[] = "";
+
 // Menu SYS2 sub Information
 static uint8_t text_EN_Usage_Battery[] = "Battery life";
 static uint8_t text_DE_Usage_Battery[] = "Batterie-Nutzung";
@@ -1704,6 +1717,37 @@
 static uint8_t text_IT_Percent[] = "Percent";
 static uint8_t text_ES_Percent[] = "Percent";
 
+static uint8_t text_EN_PSCRO2Drop[] = "PSCR O2 drop";
+static uint8_t text_DE_PSCRO2Drop[] = "PSCR O2 Abfall";
+static uint8_t text_FR_PSCRO2Drop[] = "PSCR O2 drop";
+static uint8_t text_IT_PSCRO2Drop[] = "PSCR O2 drop";
+static uint8_t text_ES_PSCRO2Drop[] = "PSCR O2 drop";
+
+static uint8_t text_EN_LungRatio[] = "PSCR lung ratio";
+static uint8_t text_DE_LungRatio[] = "PSCR Lungen Faktor";
+static uint8_t text_FR_LungRatio[] = "PSCR lung ratio";
+static uint8_t text_IT_LungRatio[] = "PSCR lung ratio";
+static uint8_t text_ES_LungRatio[] = "PSCR lung ratio";
+
+static uint8_t text_EN_CheckSettings[] = "Check settings";
+static uint8_t text_DE_CheckSettings[] = "Prüfe Optionen";
+static uint8_t text_FR_CheckSettings[] = "Check settings";
+static uint8_t text_IT_CheckSettings[] = "Check settings";
+static uint8_t text_ES_CheckSettings[] = "Check settings";
+
+static uint8_t text_EN_SimPpo2[] = "Sim ppO2";
+static uint8_t text_DE_SimPpo2[] = "Sim ppO2";
+static uint8_t text_FR_SimPpo2[] = "Sim ppO2";
+static uint8_t text_IT_SimPpo2[] = "Sim ppO2";
+static uint8_t text_ES_SimPpo2[] = "Sim ppO2";
+
+static uint8_t text_EN_CO2Sensor[] = "CO2 Sensor";
+static uint8_t text_DE_CO2Sensor[] = "CO2 Sensor";
+static uint8_t text_FR_CO2Sensor[] = "CO2 Sensor";
+static uint8_t text_IT_CO2Sensor[] = "CO2 Sensor";
+static uint8_t text_ES_CO2Sensor[] = "CO2 Sensor";
+
+
 /* Lookup Table -------------------------------------------------------------*/
 
 const tText text_array[] =
@@ -1725,10 +1769,11 @@
     {(uint8_t)TXT_ActualGradient,   {text_EN_ActualGradient, text_DE_ActualGradient, text_FR_ActualGradient, text_IT_ActualGradient, text_ES_ActualGradient}},
     {(uint8_t)TXT_Stopwatch, 		{text_EN_Stopwatch, text_DE_Stopwatch, text_FR_Stopwatch, text_IT_Stopwatch, text_ES_Stopwatch}},
     {(uint8_t)TXT_Gas, 				{text_EN_Gas, text_DE_Gas, text_FR_Gas, text_IT_Gas, text_ES_Gas}},
-    {(uint8_t)TXT_Time, 			{text_EN_Time, text_DE_Time, text_FR_Time, text_IT_Time, text_ES_Time}},
+    {(uint8_t)TXT_ChargeHour,		{text_EN_ChargeHour, text_DE_ChargeHour, text_FR_ChargeHour, text_IT_ChargeHour, text_ES_ChargeHour}},
     {(uint8_t)TXT_Date, 			{text_EN_Date, text_DE_Date, text_FR_Date, text_IT_Date, text_ES_Date}},
     {(uint8_t)TXT_Format, 			{text_EN_Format, text_DE_Format, text_FR_Format, text_IT_Format, text_ES_Format}},
     {(uint8_t)TXT_Warning, 			{text_EN_Warning, text_DE_Warning, text_FR_Warning, text_IT_Warning, text_ES_Warning}},
+    {(uint8_t)TXT_Charging, 		{text_EN_Charging, text_DE_Charging, text_FR_Charging, text_IT_Charging, text_ES_Charging}},
     {(uint8_t)TXT_o2Sensors, 		{text_EN_o2Sensors, text_DE_o2Sensors, text_FR_o2Sensors, text_IT_o2Sensors, text_ES_o2Sensors}},
     {(uint8_t)TXT_Brightness, 		{text_EN_Brightness, text_DE_Brightness, text_FR_Brightness, text_IT_Brightness, text_ES_Brightness}},
     {(uint8_t)TXT_Cave, 			{text_EN_Cave, text_DE_Cave, text_FR_Cave, text_IT_Cave, text_ES_Cave}},
@@ -1770,7 +1815,8 @@
     {(uint8_t)TXT_ClosedCircuit,	{text_EN_ClosedCircuit, text_DE_ClosedCircuit, text_FR_ClosedCircuit, text_IT_ClosedCircuit, text_ES_ClosedCircuit}},
     {(uint8_t)TXT_Apnoe,	 		{text_EN_Apnoe, text_DE_Apnoe, text_FR_Apnoe, text_IT_Apnoe, text_ES_Apnoe}},
     {(uint8_t)TXT_Gauge,	 		{text_EN_Gauge, text_DE_Gauge, text_FR_Gauge, text_IT_Gauge, text_ES_Gauge}},
-    {(uint8_t)TXT_Sensor,			{text_EN_Sensor, text_DE_Sensor, text_FR_Sensor, text_IT_Sensor, text_ES_Sensor}},
+    {(uint8_t)TXT_PSClosedCircuit,  {text_EN_PSClosedCircuit, text_DE_PSClosedCircuit, text_FR_PSClosedCircuit, text_IT_PSClosedCircuit, text_ES_PSClosedCircuit}},
+	{(uint8_t)TXT_Sensor,			{text_EN_Sensor, text_DE_Sensor, text_FR_Sensor, text_IT_Sensor, text_ES_Sensor}},
     {(uint8_t)TXT_FixedSP,			{text_EN_FixedSP, text_DE_FixedSP, text_FR_FixedSP, text_IT_FixedSP, text_ES_FixedSP}},
     {(uint8_t)TXT_Decoparameters,	{text_EN_Decoparameters, text_DE_Decoparameters, text_FR_Decoparameters, text_IT_Decoparameters, text_ES_Decoparameters}},
     {(uint8_t)TXT_LastDecostop,		{text_EN_LastDecostop, text_DE_LastDecostop, text_FR_LastDecostop, text_IT_LastDecostop, text_ES_LastDecostop}},
@@ -1787,7 +1833,10 @@
 	{(uint8_t)TXT_ScrubTimeReset,	{text_EN_ScrubTimeReset, text_DE_ScrubTimeReset, text_FR_ScrubTimeReset, text_IT_ScrubTimeReset, text_ES_ScrubTimeReset}},
 	{(uint8_t)TXT_ScrubTimeMode,	{text_EN_ScrubTimeMode, text_DE_ScrubTimeMode, text_FR_ScrubTimeMode, text_IT_ScrubTimeMode, text_ES_ScrubTimeMode}},
 	{(uint8_t)TXT_Percent,	    	{text_EN_Percent, text_DE_Percent, text_FR_Percent, text_IT_Percent, text_ES_Percent}},
-
+	{(uint8_t)TXT_PSCRO2Drop,	    {text_EN_PSCRO2Drop, text_DE_PSCRO2Drop, text_FR_PSCRO2Drop, text_IT_PSCRO2Drop, text_ES_PSCRO2Drop}},
+	{(uint8_t)TXT_PSCRLungRatio,	{text_EN_LungRatio, text_DE_LungRatio, text_FR_LungRatio, text_IT_LungRatio, text_ES_LungRatio}},
+	{(uint8_t)TXT_SimPpo2,			{text_EN_SimPpo2, text_DE_SimPpo2, text_FR_SimPpo2, text_IT_SimPpo2, text_ES_SimPpo2}},
+	{(uint8_t)TXT_CO2Sensor,		{text_EN_CO2Sensor, text_DE_CO2Sensor, text_FR_CO2Sensor, text_IT_CO2Sensor, text_ES_CO2Sensor}},
 };
 
 const tText text_array2[] =
@@ -1955,4 +2004,8 @@
 	{(uint8_t)TXT2BYTE_Minimum, 		{text_EN_Minimum, text_DE_Minimum, text_FR_Minimum, text_IT_Minimum, text_ES_Minimum}},
 	{(uint8_t)TXT2BYTE_Normal, 			{text_EN_Normal, text_DE_Normal, text_FR_Normal, text_IT_Normal, text_ES_Normal}},
 	{(uint8_t)TXT2BYTE_Maximum, 		{text_EN_Maximum, text_DE_Maximum, text_FR_Maximum, text_IT_Maximum, text_ES_Maximum}},
+
+	{(uint8_t)TXT2BYTE_CheckSettings, 	{text_EN_CheckSettings, text_DE_CheckSettings, text_FR_CheckSettings, text_IT_CheckSettings, text_ES_CheckSettings}},
+
+
 };
--- a/Small_CPU/Inc/batteryCharger.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Inc/batteryCharger.h	Fri Aug 19 11:30:24 2022 +0200
@@ -31,9 +31,30 @@
 /* Includes ------------------------------------------------------------------*/
 #include <stdint.h>
 
-uint8_t get_charge_status(void);
+#define CHARGE_IN_PIN				GPIO_PIN_2
+#define CHARGE_IN_GPIO_PORT			GPIOC
+#define CHARGE_IN_GPIO_ENABLE()		__GPIOC_CLK_ENABLE()
+
+#define CHARGE_OUT_PIN				GPIO_PIN_1
+#define CHARGE_OUT_GPIO_PORT		GPIOC
+#define CHARGE_OUT_GPIO_ENABLE()	__GPIOC_CLK_ENABLE()
 
+ typedef enum
+ {
+ 	Charger_NotConnected = 0,		/* This is identified reading CHARGE_IN_PIN == HIGH */
+ 	Charger_WarmUp,					/* Charging started but counter did not yet reach a certain limit (used to debounce connect / disconnect events to avoid multiple increases of statistic charging cycle counter) */
+ 	Charger_Active,					/* Charging identified by  CHARGE_IN_PIN == LOW for a certain time */
+ 	Charger_Finished,
+ 	Charger_LostConnection,			/* Intermediate state to debounce disconnecting events (including charging error state like over temperature) */
+ 	Charger_ColdStart,				/* Cold start condition => check if an loaded battery has been inserted */
+ 	Charger_END
+ } chargerState_t;
+
+
+uint8_t get_charge_status(void);
 void init_battery_charger_status(void);
+void set_charge_state(chargerState_t newState);
+uint8_t get_charge_state(void);
 void ReInit_battery_charger_status_pins(void);
 void DeInit_battery_charger_status_pins(void);
 void battery_charger_get_status_and_contral_battery_gas_gauge(uint8_t cycleTimeBase);
--- a/Small_CPU/Inc/batteryGasGauge.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Inc/batteryGasGauge.h	Fri Aug 19 11:30:24 2022 +0200
@@ -31,6 +31,12 @@
 
 #include <stdint.h>
 
+#define BATTERY_DEFAULT_VOLTAGE					(6.0f)
+#define BATTERY_ENDOF_CHARGE_VOLTAGE			(4.05f)
+#define BATTERY_CHARGER_CONNECTED_VOLTAGE		(4.2f)
+
+#define BATTERY_CHARGE_UNKNOWN					(-1.0f)
+
 void init_battery_gas_gauge(void);
 
 float get_voltage(void);
@@ -41,6 +47,10 @@
 void battery_gas_gauge_set(float percentage);
 uint8_t battery_gas_gauge_CheckConfigOK(void);
 
+uint8_t battery_gas_gauge_isChargeValueValid(void);
+void battery_gas_gauge_setChargeValueValid(void);
+
+
 #ifdef __cplusplus
 }
 #endif
--- a/Small_CPU/Inc/externalInterface.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Inc/externalInterface.h	Fri Aug 19 11:30:24 2022 +0200
@@ -32,10 +32,27 @@
 #define MAX_ADC_CHANNEL		(3u)		/* number of channels to be read */
 #define EXTERNAL_ADC_NO_DATA	0xFF
 
+#define EXT33V_CONTROL_PIN				GPIO_PIN_7	/* PortC */
+
 void externalInterface_Init(void);
+void externalInterface_InitPower33(void);
 uint8_t externalInterface_StartConversion(uint8_t channel);
 uint8_t externalInterface_ReadAndSwitch();
 float externalInterface_CalculateADCValue(uint8_t channel);
 float getExternalInterfaceChannel(uint8_t channel);
+uint8_t setExternalInterfaceChannel(uint8_t channel, float value);
+void externalInterface_SwitchPower33(uint8_t state);
+void externalInterface_SwitchADC(uint8_t state);
+uint8_t externalInterface_isEnabledPower33(void);
+uint8_t externalInterface_isEnabledADC(void);
+
+void externalInterface_SetCO2Value(uint16_t CO2_ppm);
+void externalInterface_SetCO2SignalStrength(uint16_t LED_qa);
+uint16_t externalInterface_GetCO2Value(void);
+uint16_t externalInterface_GetCO2SignalStrength(void);
+void externalInterface_SetCO2State(uint16_t state);
+uint16_t externalInterface_GetCO2State(void);
+
+void externalInterface_ExecuteCmd(uint16_t Cmd);
 
 #endif /* EXTERNAL_INTERFACE_H */
--- a/Small_CPU/Inc/uart.h	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Inc/uart.h	Fri Aug 19 11:30:24 2022 +0200
@@ -24,11 +24,39 @@
 
 #include "stm32f4xx_hal.h"
 
-void MX_USART2_UART_Init(void);
-void MX_USART2_UART_DeInit(void);
-uint8_t UART_ButtonAdjust(uint8_t *array);
+
+ typedef enum
+ {
+ 	RX_Ready= 0,					/* Initial state */
+	RX_DetectStart,					/* validate start byte */
+	RX_SelectData,					/* Data contained in this frame */
+ 	RX_Data0,						/* Process incoming data */
+	RX_Data1,
+	RX_Data2,
+	RX_Data3,
+	RX_Data4,
+	RX_Data5,
+	RX_Data6,
+	RX_Data7,
+	RX_Data8,
+	RX_Data9,
+	RX_Data10,
+	RX_Data11,
+	RX_Data12,
+	RX_DataComplete
+ } receiveState_t;
 
 
+void MX_USART1_UART_Init(void);
+void MX_USART1_UART_DeInit(void);
+void MX_USART1_DMA_Init(void);
+uint8_t UART_ButtonAdjust(uint8_t *array);
+#ifdef ENABLE_CO2_SUPPORT
+void HandleUARTCO2Data(void);
+#endif
+#ifdef ENABLE_SENTINEL_MODE
+void HandleUARTSentinelData(void);
+#endif
 #ifdef __cplusplus
 }
 #endif
--- a/Small_CPU/Src/baseCPU2.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/baseCPU2.c	Fri Aug 19 11:30:24 2022 +0200
@@ -142,6 +142,7 @@
 #include "scheduler.h"
 #include "tm_stm32f4_otp.h"
 #include "externalInterface.h"
+#include "uart.h"
 
 // From Common/Inc:
 #include "calc_crush.h"
@@ -165,16 +166,16 @@
 // See CPU2-RTE.ld
 const SFirmwareData cpu2_FirmwareData __attribute__(( section(".firmware_data") ))= {
 		.versionFirst = 2,
-		.versionSecond = 7,
+		.versionSecond = 9,
 		.versionThird = 0,
 		.versionBeta = 0,
 
 /* 4 bytes with trailing 0 */
 		.signature = "mh",
 
-		.release_year = 21,
-		.release_month = 4,
-		.release_day = 26,
+		.release_year = 22,
+		.release_month = 8,
+		.release_day = 19,
 		.release_sub = 0,
 
 		/* max 48 with trailing 0 */
@@ -230,6 +231,10 @@
 #define WIRELSS_POWER_GPIO_PORT     	GPIOB
 #define WIRELSS_POWER_HAL_RCC_GPIO_CLK_ENABLE()		 __HAL_RCC_GPIOB_CLK_ENABLE()
 
+
+#define LED_CONTROL_PIN          		GPIO_PIN_3		/* PortC */
+#define MAINCPU_CONTROL_PIN				GPIO_PIN_0		/* PortC */
+
 /* Private macro -------------------------------------------------------------*/
 
 /* Private variables ---------------------------------------------------------*/
@@ -353,12 +358,18 @@
 	HAL_Delay(10);
 	battery_gas_gauge_get_data();
 
+	global.lifeData.battery_voltage = get_voltage();
+	global.lifeData.battery_charge = get_charge();
+	copyBatteryData();
+
 	MX_SPI3_Init();
 
 	if(coldstart != 0xA5)	/* Not reading a 0xA5 means the memory cells has not been initialized before => cold start */
 	{
 		coldstart = 0xA5;
-		battery_gas_gauge_set(0);
+
+		set_charge_state(Charger_ColdStart);
+
 		global.dataSendToMaster.power_on_reset = 1;
 		global.deviceDataSendToMaster.power_on_reset = 1;
 
@@ -373,13 +384,16 @@
 			}
 		}
 	}
-
-	global.lifeData.battery_voltage = get_voltage();
-	global.lifeData.battery_charge = get_charge();
-	copyBatteryData();
+	else
+	{
+		set_charge_state(Charger_NotConnected);
+	}
 
 	ADCx_Init();
 	GPIO_Power_MainCPU_Init();
+
+	externalInterface_InitPower33();
+
 	global.mode = MODE_POWERUP;
 #else
 	init_pressure();
@@ -408,6 +422,7 @@
 			SPI_synchronize_with_Master();
 			MX_DMA_Init();
 			MX_SPI1_Init();
+			MX_USART1_UART_Init();
 			SPI_Start_single_TxRx_with_Master(); /* be prepared for the first data exchange */
 			Scheduler_Request_sync_with_SPI(SPI_SYNC_METHOD_HARD);
 			EXTI_Test_Button_Init();
@@ -478,7 +493,9 @@
 			 EXTI_Wakeup_Button_Init();
 			 NOT_USED_AT_THE_MOMENT_scheduleSleepMode();
 			 */
+
 			EXTI_Test_Button_DeInit();
+			externalInterface_SwitchPower33(false);
 			if (hasExternalClock())
 				SystemClock_Config_HSI();
 			sleep_prepare();
@@ -500,6 +517,11 @@
 			MX_SPI1_Init();
 			SPI_Start_single_TxRx_with_Master();
 
+			if(externalInterface_isEnabledPower33())
+			{
+				externalInterface_SwitchPower33(true);
+			}
+
 			// EXTILine0_Button_DeInit(); not now, later after testing
 			break;
 		}
@@ -793,7 +815,7 @@
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	__GPIOC_CLK_ENABLE();
-	GPIO_InitStructure.Pin = GPIO_PIN_3;
+	GPIO_InitStructure.Pin = LED_CONTROL_PIN;
 	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
 	GPIO_InitStructure.Pull = GPIO_PULLUP;
 	GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
@@ -805,7 +827,7 @@
 	GPIO_InitTypeDef GPIO_InitStructure;
 
 	__GPIOC_CLK_ENABLE();
-	GPIO_InitStructure.Pin = GPIO_PIN_3;
+	GPIO_InitStructure.Pin = LED_CONTROL_PIN;
 	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
 	GPIO_InitStructure.Pull = GPIO_PULLUP;
 	GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
@@ -815,33 +837,33 @@
 
 void GPIO_new_DEBUG_LOW(void) {
 #ifdef DEBUG_PIN_ACTIVE
-	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_RESET);
+	HAL_GPIO_WritePin(GPIOC,LED_CONTROL_PIN,GPIO_PIN_RESET);
 #endif
 }
 
 void GPIO_new_DEBUG_HIGH(void) {
 #ifdef DEBUG_PIN_ACTIVE
-	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_3,GPIO_PIN_SET);
+	HAL_GPIO_WritePin(GPIOC,LED_CONTROL_PIN,GPIO_PIN_SET);
 #endif
 }
 
 static void GPIO_Power_MainCPU_Init(void) {
 	GPIO_InitTypeDef GPIO_InitStructure;
 	__GPIOC_CLK_ENABLE();
-	GPIO_InitStructure.Pin = GPIO_PIN_0;
+	GPIO_InitStructure.Pin = MAINCPU_CONTROL_PIN;
 	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
 	GPIO_InitStructure.Pull = GPIO_PULLUP;
 	GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
 	HAL_GPIO_Init( GPIOC, &GPIO_InitStructure);
-	HAL_GPIO_WritePin( GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
+	HAL_GPIO_WritePin( GPIOC, MAINCPU_CONTROL_PIN, GPIO_PIN_RESET);
 }
 
 static void GPIO_Power_MainCPU_ON(void) {
-	HAL_GPIO_WritePin( GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
+	HAL_GPIO_WritePin( GPIOC, MAINCPU_CONTROL_PIN, GPIO_PIN_RESET);
 }
 
 static void GPIO_Power_MainCPU_OFF(void) {
-	HAL_GPIO_WritePin( GPIOC, GPIO_PIN_0, GPIO_PIN_SET);
+	HAL_GPIO_WritePin( GPIOC, MAINCPU_CONTROL_PIN, GPIO_PIN_SET);
 }
 
 /**
@@ -938,11 +960,7 @@
 
 void sleep_prepare(void) {
 	EXTI_Wakeup_Button_Init();
-	/*
-	 GPIO_InitStruct.Pull = GPIO_PULLUP;
-	 GPIO_InitStruct.Pin =  GPIO_PIN_0;
-	 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
-	 */
+
 	compass_sleep();
 	HAL_Delay(100);
 	accelerator_sleep();
@@ -972,8 +990,8 @@
 
 	GPIO_InitStruct.Pin =
 			GPIO_PIN_All
-					^ ( GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_14
-							| GPIO_PIN_15); /* power off & charger in & charge out & OSC32*/
+					^ ( MAINCPU_CONTROL_PIN | CHARGE_OUT_PIN | CHARGE_IN_PIN | EXT33V_CONTROL_PIN | LED_CONTROL_PIN); /* power off & charger in & charge out & OSC32 & ext33Volt */
+
 	HAL_GPIO_Init( GPIOC, &GPIO_InitStruct);
 
 	GPIO_InitStruct.Pin = GPIO_PIN_All ^ ( GPIO_PIN_0);
--- a/Small_CPU/Src/batteryCharger.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/batteryCharger.c	Fri Aug 19 11:30:24 2022 +0200
@@ -37,29 +37,12 @@
 /* Use This compile switch to select the new charger status control implementation */
 #define ENABLE_CHARGER_STATUS_V2
 
-#define CHARGE_IN_PIN							GPIO_PIN_2
-#define CHARGE_IN_GPIO_PORT				GPIOC
-#define CHARGE_IN_GPIO_ENABLE()		__GPIOC_CLK_ENABLE()
+#define CHARGER_DEBOUNCE_SECONDS	(6u)		/* 6 seconds used to avoid problems with charger interrupts / disconnections */
 
-#define CHARGE_OUT_PIN						GPIO_PIN_1
-#define CHARGE_OUT_GPIO_PORT			GPIOC
-#define CHARGE_OUT_GPIO_ENABLE()	__GPIOC_CLK_ENABLE()
-
-#define CHARGER_DEBOUNCE_SECONDS	(5u)		/* 5 seconds used to avoid problems with charger interrupts / disconnections */
-
-uint8_t battery_i_charge_status = 0;
-uint16_t battery_charger_counter = 0;
+static uint8_t battery_i_charge_status = 0;
+static uint16_t battery_charger_counter = 0;
 
 #ifdef ENABLE_CHARGER_STATUS_V2
-typedef enum
-{
-	Charger_NotConnected = 0,		/* This is identified reading CHARGE_IN_PIN == HIGH */
-	Charger_WarmUp,					/* Charging started but counter did not yet reach a certain limit (used to debounce connect / disconnect events to avoid multiple increases of statistic charging cycle counter) */
-	Charger_Active,					/* Charging identified by  CHARGE_IN_PIN == LOW for a certain time */
-	Charger_Finished,
-	Charger_LostConnection			/* Intermediate state to debounce disconnecting events (including charging error state like over temperature) */
-} chargerState_t;
-
 static chargerState_t batteryChargerState = Charger_NotConnected;
 #endif
 
@@ -73,6 +56,21 @@
 	return battery_i_charge_status;
 }
 
+void set_charge_state(uint8_t newState)
+{
+#ifdef ENABLE_CHARGER_STATUS_V2
+	if(newState < Charger_END)
+	{
+		batteryChargerState = newState;
+	}
+#endif
+}
+
+uint8_t get_charge_state(void)
+{
+	return batteryChargerState;
+}
+
 void init_battery_charger_status(void)
 {
 	#ifdef OSTC_ON_DISCOVERY_HARDWARE
@@ -150,115 +148,140 @@
 	#endif
 	
 #ifdef ENABLE_CHARGER_STATUS_V2
-	/* on disconnection or while disconnected */
-	if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))
+
+	if(batteryChargerState == Charger_ColdStart)	/* wait for the first valid voltage meassurement */
 	{
-		switch(batteryChargerState)
+		if((global.lifeData.battery_voltage != BATTERY_DEFAULT_VOLTAGE) && (global.lifeData.battery_voltage < BATTERY_CHARGER_CONNECTED_VOLTAGE))
 		{
-			case Charger_Active:				global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
-												global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
-												batteryChargerState = Charger_LostConnection;
-												battery_charger_counter = CHARGER_DEBOUNCE_SECONDS;
-
-												if(get_voltage() >= 4.1f)			/* the charger stops charging when charge current is 1/10. */
-												{									/*  Basically it is OK to rate a charging as complete if a defined voltage is reached */
-													batteryChargerState = Charger_Finished;
-													global.dataSendToMaster.chargeStatus = CHARGER_complete;
-													global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
-													battery_charger_counter = 15;
-													notifyChargeComplete = 1;
-												}
-										break;
-			case Charger_WarmUp:
-			case Charger_Finished:
-			case Charger_LostConnection:		if(battery_charger_counter >= cycleTimeBase)
-												{
-													battery_charger_counter -= cycleTimeBase;
-													global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
-													global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
-													batteryChargerState = Charger_LostConnection;
-												}
-												else
-												{
-													battery_charger_counter = 0;
-													battery_i_charge_status = 0;
-													global.dataSendToMaster.chargeStatus = CHARGER_off;
-													global.deviceDataSendToMaster.chargeStatus = CHARGER_off;
-
-													if(notifyChargeComplete)
-													{
-														battery_gas_gauge_set_charge_full();
-														scheduleUpdateDeviceDataChargerFull();
-														notifyChargeComplete = 0;
-													}
-													batteryChargerState = Charger_NotConnected;
-												}
-										break;
-			default: break;
+			if(global.lifeData.battery_voltage > BATTERY_ENDOF_CHARGE_VOLTAGE) 						/* Voltage close to full state => maybe new battery inserted 	*/
+			{
+				battery_gas_gauge_set_charge_full();
+			}
+			batteryChargerState = Charger_NotConnected;
 		}
 	}
 	else
-	{
-		/* connected */
-		/* wait for disconnection to write and reset */
-		switch(batteryChargerState)
+	{	/* on disconnection or while disconnected */
+		if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))
 		{
-				case Charger_NotConnected:		battery_i_charge_status = 1;
-												battery_charger_counter = 0;
-												batteryChargerState = Charger_WarmUp;
-										break;
-				case Charger_LostConnection:		batteryChargerState = Charger_Active;
-										break;
-				case Charger_WarmUp:			battery_charger_counter += cycleTimeBase;
-												if(battery_charger_counter >= CHARGER_DEBOUNCE_SECONDS )
-												{
-													battery_i_charge_status = 2;
-													scheduleUpdateDeviceDataChargerCharging();
-													batteryChargerState = Charger_Active;
-												}
-						/* no break */
-				case Charger_Finished:
-				case Charger_Active:			global.dataSendToMaster.chargeStatus = CHARGER_running;
-												global.deviceDataSendToMaster.chargeStatus = CHARGER_running;
-
-												/* drive the output pin high to determine the state of the charger */
-												GPIO_InitTypeDef   GPIO_InitStructure;
-												GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
-												GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
-												GPIO_InitStructure.Pull = GPIO_NOPULL;
-												GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
-												HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
-												HAL_GPIO_WritePin(CHARGE_OUT_GPIO_PORT, CHARGE_OUT_PIN,GPIO_PIN_SET);
-												HAL_Delay(1);
-
-												if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))		/* high => charger stopped charging */
-												{
-													batteryChargerState = Charger_Finished;
-													global.dataSendToMaster.chargeStatus = CHARGER_complete;
-													global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
-													battery_charger_counter = 30;
-													notifyChargeComplete = 1;
-												}
-												else
-												{
-													if(batteryChargerState == Charger_Finished)				/* voltage dropped below the hysteresis again => charging restarted */
+			switch(batteryChargerState)
+			{
+				case Charger_WarmUp:
+				case Charger_Active:				global.dataSendToMaster.chargeStatus = CHARGER_lostConnection;
+													global.deviceDataSendToMaster.chargeStatus = CHARGER_lostConnection;
+													batteryChargerState = Charger_LostConnection;
+													if(cycleTimeBase > CHARGER_DEBOUNCE_SECONDS)	/* adapt connection lost detection to sleep mode */
+													{
+														battery_charger_counter = cycleTimeBase + 1;
+													}
+													else
 													{
-														batteryChargerState = Charger_Active;
+														battery_charger_counter = CHARGER_DEBOUNCE_SECONDS;
+													}
+											break;
+				case Charger_Finished:				battery_charger_counter = 0;
+													batteryChargerState = Charger_LostConnection;
+					/* no break */
+				case Charger_LostConnection:		/* the charger stops charging when charge current is 1/10 	*/
+													/* Basically it is OK to rate a charging as complete if a defined voltage is reached */
+													if(((battery_gas_gauge_isChargeValueValid() == 0) || (global.lifeData.battery_charge < 90)) && (get_voltage() >= BATTERY_ENDOF_CHARGE_VOLTAGE) && (get_voltage() < BATTERY_CHARGER_CONNECTED_VOLTAGE))
+													{
+														notifyChargeComplete = 1;
+													}
+													else
+													{
 														notifyChargeComplete = 0;
 													}
-												}
+													if(battery_charger_counter >= cycleTimeBase)
+													{
+														battery_charger_counter -= cycleTimeBase;
+													}
+													else
+													{
+														battery_charger_counter = 0;
+														battery_i_charge_status = 0;
+														global.dataSendToMaster.chargeStatus = CHARGER_off;
+														global.deviceDataSendToMaster.chargeStatus = CHARGER_off;
 
-												/* restore high impedance to be able to detect disconnection */
-												GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
-												GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
-												GPIO_InitStructure.Pull = GPIO_NOPULL;
-												GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
-												HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
-												HAL_Delay(1);
-										break;
+														if(notifyChargeComplete)
+														{
+															battery_gas_gauge_set_charge_full();
+															scheduleUpdateDeviceDataChargerFull();
+															notifyChargeComplete = 0;
+														}
+														batteryChargerState = Charger_NotConnected;
+													}
+											break;
+				default: break;
+			}
+		}
+		else
+		{
+			/* connected */
+			/* wait for disconnection to write and reset */
+			switch(batteryChargerState)
+			{
+					case Charger_NotConnected:		battery_i_charge_status = 1;
+													battery_charger_counter = 0;
+													batteryChargerState = Charger_WarmUp;
+											break;
+					case Charger_LostConnection:		batteryChargerState = Charger_Active;
+											break;
+					case Charger_WarmUp:			battery_charger_counter += cycleTimeBase;
+													if(battery_charger_counter >= CHARGER_DEBOUNCE_SECONDS )
+													{
+														battery_i_charge_status = 2;
+														scheduleUpdateDeviceDataChargerCharging();
+														batteryChargerState = Charger_Active;
+													}
+							/* no break */
+					case Charger_Finished:
+					case Charger_Active:			global.dataSendToMaster.chargeStatus = CHARGER_running;
+													global.deviceDataSendToMaster.chargeStatus = CHARGER_running;
 
-				default:						/* wait for disconnection */
-					break;
+													/* drive the output pin high to determine the state of the charger */
+													GPIO_InitTypeDef   GPIO_InitStructure;
+													GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+													GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+													GPIO_InitStructure.Pull = GPIO_NOPULL;
+													GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+													HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+													HAL_GPIO_WritePin(CHARGE_OUT_GPIO_PORT, CHARGE_OUT_PIN,GPIO_PIN_SET);
+													HAL_Delay(1);
+
+													if(HAL_GPIO_ReadPin(CHARGE_IN_GPIO_PORT,CHARGE_IN_PIN))		/* high => charger stopped charging */
+													{
+														batteryChargerState = Charger_Finished;
+														global.dataSendToMaster.chargeStatus = CHARGER_complete;
+														global.deviceDataSendToMaster.chargeStatus = CHARGER_complete;
+														battery_charger_counter = 30;
+														notifyChargeComplete = 1;
+													}
+													else
+													{
+														if(global.lifeData.battery_charge > 100.0)				/* still charging but indicator is set to full => decrease to 99% to keep count increasing */
+														{
+															battery_gas_gauge_set(99.0);
+														}
+														if(batteryChargerState == Charger_Finished)				/* voltage dropped below the hysteresis again => charging restarted */
+														{
+															batteryChargerState = Charger_Active;
+															notifyChargeComplete = 0;
+														}
+													}
+
+													/* restore high impedance to be able to detect disconnection */
+													GPIO_InitStructure.Pin = CHARGE_OUT_PIN;
+													GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;
+													GPIO_InitStructure.Pull = GPIO_NOPULL;
+													GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+													HAL_GPIO_Init(CHARGE_OUT_GPIO_PORT, &GPIO_InitStructure);
+													HAL_Delay(1);
+											break;
+
+					default:						/* wait for disconnection */
+						break;
+			}
 		}
 	}
 #else
--- a/Small_CPU/Src/batteryGasGauge.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/batteryGasGauge.c	Fri Aug 19 11:30:24 2022 +0200
@@ -28,8 +28,10 @@
 #include "stm32f4xx_hal.h"
 #include "i2c.h"
 
-static float battery_f_voltage = 6.0;		/* max assumed voltage */
+static float battery_f_voltage = BATTERY_DEFAULT_VOLTAGE;		/* max assumed voltage */
 static float battery_f_charge_percent = 0;
+static uint8_t chargeValueKnown = 0;							/* indicator if the charge of the battery is known (for example after a full charge cycle) */
+
 
 #define BGG_BATTERY_OFFSET          (26123)  //; 65536-(3,35Ah/0,085mAh)
 #define BGG_BATTERY_DIVIDER         (394)    //; 3,35Ah/0,085mAh/100 [%]
@@ -66,7 +68,7 @@
 	// F8 = 11111000:
 	// ADC auto mode (11)
 	// Prescale M = 128 (111)
-	// AL/CC pin disable (0)
+	// AL/CC pin disable (00)
 	// Shutdown (0)
 	buffer[1] = 0xF8;
 	I2C_Master_Transmit(DEVICE_BATTERYGAUGE, buffer, 2);
@@ -152,6 +154,7 @@
 	bufferSend[2] = 0xFF;
 	I2C_Master_Transmit(  DEVICE_BATTERYGAUGE, bufferSend, 3);
 	init_battery_gas_gauge();
+	chargeValueKnown = 1;
 }
 
 
@@ -177,7 +180,17 @@
 	bufferSend[2] = (uint8_t)(mAhSend & 0xFF);
 	I2C_Master_Transmit(  DEVICE_BATTERYGAUGE, bufferSend, 3);
 	init_battery_gas_gauge();
+	chargeValueKnown = 1;
 }
 
+uint8_t battery_gas_gauge_isChargeValueValid(void)
+{
+	return chargeValueKnown;
+}
+
+void battery_gas_gauge_setChargeValueValid(void)
+{
+	chargeValueKnown = 1;
+}
 
 /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/
--- a/Small_CPU/Src/dma.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/dma.c	Fri Aug 19 11:30:24 2022 +0200
@@ -34,6 +34,7 @@
   */
 /* Includes ------------------------------------------------------------------*/
 #include "dma.h"
+#include "uart.h"
 
 /* USER CODE BEGIN 0 */
 
@@ -55,6 +56,7 @@
   /* DMA controller clock enable */
   __DMA2_CLK_ENABLE();
 
+  MX_USART1_DMA_Init();
   /* DMA interrupt init */
 
 }
--- a/Small_CPU/Src/externalInterface.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/externalInterface.c	Fri Aug 19 11:30:24 2022 +0200
@@ -27,8 +27,11 @@
 #include "i2c.h"
 #include "externalInterface.h"
 #include "scheduler.h"
+#include "uart.h"
+#include "data_exchange.h"
 
 extern SGlobal global;
+extern UART_HandleTypeDef huart1;
 
 #define ADC_ANSWER_LENGTH	(5u)		/* 3424 will provide addr + 4 data bytes */
 #define ADC_TIMEOUT			(10u)		/* conversion stuck for unknown reason => restart */
@@ -52,6 +55,11 @@
 static uint8_t externalInterfacePresent = 0;
 
 float externalChannel_mV[MAX_ADC_CHANNEL];
+static uint8_t  externalV33_On = 0;
+static uint8_t  externalADC_On = 0;
+static uint16_t externalCO2Value;
+static uint16_t externalCO2SignalStrength;
+static uint16_t  externalCO2Status = 0;
 
 
 void externalInterface_Init(void)
@@ -65,6 +73,12 @@
 		global.deviceDataSendToMaster.hw_Info.extADC = 1;
 	}
 	global.deviceDataSendToMaster.hw_Info.checkADC = 1;
+
+/* init data values */
+	externalV33_On = 0;
+	externalCO2Value = 0;
+	externalCO2SignalStrength = 0;
+	externalCO2Status = 0;
 }
 
 
@@ -168,3 +182,122 @@
 	}
 	return retval;
 }
+
+uint8_t setExternalInterfaceChannel(uint8_t channel, float value)
+{
+	uint8_t retval = 0;
+
+	if(channel < MAX_ADC_CHANNEL)
+	{
+		externalChannel_mV[channel] = value;
+		retval = 1;
+	}
+	return retval;
+}
+
+void externalInterface_InitPower33(void)
+{
+	GPIO_InitTypeDef   GPIO_InitStructure;
+
+	GPIO_InitStructure.Pin = GPIO_PIN_7;
+	GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+	GPIO_InitStructure.Pull = GPIO_PULLUP;
+	GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+	HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
+	HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
+}
+
+
+uint8_t externalInterface_isEnabledPower33()
+{
+	return externalV33_On;
+}
+
+uint8_t externalInterface_isEnabledADC()
+{
+	return externalADC_On;
+}
+
+void externalInterface_SwitchPower33(uint8_t state)
+{
+	if(state != externalV33_On)
+	{
+		if(state)
+		{
+			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET);
+			externalV33_On = 1;
+			MX_USART1_UART_Init();
+		}
+		else
+		{
+			HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET);
+			externalV33_On = 0;
+			externalInterface_SetCO2Value(0);
+			externalInterface_SetCO2SignalStrength(0);
+			MX_USART1_UART_DeInit();
+		}
+	}
+}
+void externalInterface_SwitchADC(uint8_t state)
+{
+	if((state) && (externalInterfacePresent))
+	{
+		externalInterface_StartConversion(activeChannel);
+		externalADC_On = 1;
+	}
+	else
+	{
+		externalADC_On = 0;
+	}
+}
+
+void externalInterface_SetCO2Value(uint16_t CO2_ppm)
+{
+	externalCO2Value = CO2_ppm;
+}
+
+void externalInterface_SetCO2SignalStrength(uint16_t LED_qa)
+{
+	externalCO2SignalStrength = LED_qa;
+}
+
+uint16_t externalInterface_GetCO2Value(void)
+{
+	return externalCO2Value;
+}
+
+uint16_t externalInterface_GetCO2SignalStrength(void)
+{
+	return externalCO2SignalStrength;
+}
+
+
+void externalInterface_SetCO2State(uint16_t state)
+{
+	externalCO2Status = state;
+}
+
+uint16_t externalInterface_GetCO2State(void)
+{
+	return externalCO2Status;
+}
+
+void externalInterface_ExecuteCmd(uint16_t Cmd)
+{
+	char cmdString[10];
+	uint8_t cmdLength = 0;
+
+	switch(Cmd & 0x00FF)		/* lower byte is reserved for commands */
+	{
+		case EXT_INTERFACE_CO2_CALIB:	cmdLength = snprintf(cmdString, 10, "G\r\n");
+			break;
+		default:
+			break;
+	}
+	if(cmdLength != 0)
+	{
+		HAL_UART_Transmit(&huart1,(uint8_t*)cmdString,cmdLength,10);
+	}
+	return;
+}
+
--- a/Small_CPU/Src/pressure.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/pressure.c	Fri Aug 19 11:30:24 2022 +0200
@@ -49,8 +49,12 @@
 /* remove comment to use a predefined profile for pressure changes instead of real world data */
 /* #define SIMULATE_PRESSURE */
 
+
 #define PRESSURE_SURFACE_MAX_MBAR			(1060.0f)		/* It is unlikely that pressure at surface is greater than this value => clip to it */
 
+#define PRESSURE_MINIMUM					(0.0f)
+#define TEMPERATURE_MINIMUM					(-100.0f)
+
 #define PRESSURE_SURFACE_QUE					(30u)			/* history buffer [minutes] for past pressure measurements */
 #define PRESSURE_SURFACE_EVA_WINDOW				(15u)			/* Number of entries evaluated during instability test. Used to avoid detection while dive enters water */
 #define PRESSURE_SURFACE_STABLE_LIMIT			(10u)			/* Define pressure as stable if delta (mBar) is below this value */
@@ -664,6 +668,11 @@
 	ambient_temperature = ((float)local_Tx100) / 100;
 	ambient_temperature	+= temperature_offset;
 
+	if(ambient_temperature < TEMPERATURE_MINIMUM)
+	{
+		ambient_temperature = 20.0;
+	}
+
 	calc_pressure = ((float)local_Px10) / 10;
 	calc_pressure += pressure_offset;
 
@@ -673,6 +682,11 @@
 		avgCnt++;		/* by the measurement range of the sensor which is focused on under water pressure measurement */
 	}
 	ambient_pressure_mbar = runningAvg;
+
+	if(ambient_pressure_mbar < PRESSURE_MINIMUM)
+	{
+		ambient_pressure_mbar = 1000.0;
+	}
 }
 
 
--- a/Small_CPU/Src/scheduler.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/scheduler.c	Fri Aug 19 11:30:24 2022 +0200
@@ -42,6 +42,7 @@
 #include "decom.h"
 #include "tm_stm32f4_otp.h"
 #include "externalInterface.h"
+#include "uart.h"
 
 /* uncomment to enable restoting of last known date in case of a power loss (RTC looses timing data) */
 /* #define RESTORE_LAST_KNOWN_DATE */
@@ -90,6 +91,7 @@
 void copyDeviceData(void);
 void copyPICdata(void);
 void copyExtADCdata();
+void copyExtCO2data();
 static void schedule_update_timer_helper(int8_t thisSeconds);
 uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow);
 
@@ -125,6 +127,8 @@
 
 	global.I2C_SystemStatus = HAL_ERROR; // 0x00 would be everything working
 	
+	global.lifeData.battery_voltage = BATTERY_DEFAULT_VOLTAGE;
+
 	global.lifeData.pressure_ambient_bar = INVALID_PREASURE_VALUE;
 	global.lifeData.pressure_surface_bar = INVALID_PREASURE_VALUE;
 	decom_reset_with_1000mbar(&global.lifeData);
@@ -301,6 +305,26 @@
 	memcpy(&DeviceDataFlash, &global.dataSendToSlave.data.DeviceData, sizeof(SDevice));
 	deviceDataFlashValid = 1;
 
+
+	/* handle external interface requests */
+
+	if((global.dataSendToSlave.data.externalInterface_Cmd && EXT_INTERFACE_33V_ON) != externalInterface_isEnabledPower33())
+	{
+		externalInterface_SwitchPower33(global.dataSendToSlave.data.externalInterface_Cmd && EXT_INTERFACE_33V_ON);
+	}
+
+	if(((global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_ADC_ON) != 0) != externalInterface_isEnabledADC())
+	{
+		externalInterface_SwitchADC(global.dataSendToSlave.data.externalInterface_Cmd && EXT_INTERFACE_ADC_ON);
+	}
+
+
+	if(global.dataSendToSlave.data.externalInterface_Cmd & 0x00FF)	/* lowest nibble for commands */
+	{
+		externalInterface_ExecuteCmd(global.dataSendToSlave.data.externalInterface_Cmd);
+	}
+
+
 #if 0
 	//TODO: Temporary placed here. Duration ~210 ms.
 	if (global.I2C_SystemStatus != HAL_OK) {
@@ -487,6 +511,20 @@
 		lasttick = HAL_GetTick();
 		ticksdiff = time_elapsed_ms(Scheduler.tickstart,lasttick);
 
+#ifdef ENABLE_CO2_SUPPORT
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_SENTINEL)
+		{
+			HandleUARTCO2Data();
+		}
+#endif
+#ifdef ENABLE_SENTINEL_MODE
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_SENTINEL)
+		{
+			HandleUARTSentinelData();
+		}
+#endif
+
+
 		if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
 		{
 			if(SPI_Evaluate_RX_Data()!=0) /* did we receive something ? */
@@ -495,12 +533,16 @@
 			}
 			schedule_check_resync();
 
-			extAdcChannel = externalInterface_ReadAndSwitch();
-			if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
+			if(externalInterface_isEnabledADC())
 			{
-				externalInterface_CalculateADCValue(extAdcChannel);
-				copyExtADCdata();
+				extAdcChannel = externalInterface_ReadAndSwitch();
+				if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
+				{
+					externalInterface_CalculateADCValue(extAdcChannel);
+				}
 			}
+			copyExtADCdata();
+			copyExtCO2data();
 		}
 
 		//Evaluate pressure at 20 ms, 120 ms, 220 ms,....
@@ -761,10 +803,11 @@
 
 void scheduleSurfaceMode(void)
 {
-
 	uint32_t ticksdiff = 0; 
 	uint32_t lasttick = 0;
 	uint8_t extAdcChannel = 0;
+	uint8_t batteryToggle = 0;		/* ADC is operating in automatic 2 second cycles => consider for battery charge function call */
+
 	Scheduler.tickstart = HAL_GetTick();
 	Scheduler.counterSPIdata100msec = 0;
 	Scheduler.counterCompass100msec = 0;
@@ -786,7 +829,20 @@
 			if(scheduleSetButtonResponsiveness())
 				setButtonsNow = 0;
 		}
-		
+
+#ifdef ENABLE_CO2_SUPPORT
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_SENTINEL)
+		{
+			HandleUARTCO2Data();
+		}
+#endif
+#ifdef ENABLE_SENTINEL_MODE
+		if(global.dataSendToSlave.data.externalInterface_Cmd & EXT_INTERFACE_UART_SENTINEL)
+		{
+			HandleUARTSentinelData();
+		}
+#endif
+
 		/* Evaluate received data at 10 ms, 110 ms, 210 ms,... duration ~<1ms */
 		if(ticksdiff >= Scheduler.counterSPIdata100msec * 100 + 10)
 		{
@@ -795,12 +851,17 @@
 				Scheduler.counterSPIdata100msec++;
 			}
 			schedule_check_resync();
-			extAdcChannel = externalInterface_ReadAndSwitch();
-			if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
+			if(externalInterface_isEnabledADC())
 			{
-				externalInterface_CalculateADCValue(extAdcChannel);
-				copyExtADCdata();
+				extAdcChannel = externalInterface_ReadAndSwitch();
+				if(extAdcChannel != EXTERNAL_ADC_NO_DATA)
+				{
+					externalInterface_CalculateADCValue(extAdcChannel);
+
+				}
 			}
+			copyExtADCdata();
+			copyExtCO2data();
 		}
 
 		/* Evaluate pressure at 20 ms, 120 ms, 220 ms,... duration ~22ms] */
@@ -886,14 +947,24 @@
 			{
 				global.lifeData.desaturation_time_minutes = 0;
 			}
-			battery_gas_gauge_get_data();
-			battery_charger_get_status_and_contral_battery_gas_gauge(1);
+
+			if(!batteryToggle)
+			{
+				battery_gas_gauge_get_data();
+				battery_charger_get_status_and_contral_battery_gas_gauge(2);
+				batteryToggle = 1;
+			}
+			else
+			{
+				batteryToggle = 0;
+			}
 
 			copyCnsAndOtuData();
 			copyTimeData();
 			copyBatteryData();
 			copyDeviceData();
 
+
 /* check if I2C is not up an running and try to reactivate if necessary. Also do initialization if problem occured during startup */
 			if(global.I2C_SystemStatus != HAL_OK)
 			{
@@ -1034,6 +1105,7 @@
 {
 	global.dataSendToMaster.mode = 0;
 	global.deviceDataSendToMaster.mode = 0;
+	secondsCount = 0;
 	
 	/* prevent button wake up problem while in sleep_prepare
 	 * sleep prepare does I2C_DeInit()
@@ -1056,6 +1128,7 @@
 		if(global.mode == MODE_SLEEP)
 			secondsCount += 2;
 
+		externalInterface_InitPower33();
 		MX_I2C1_Init();
 		pressure_sensor_get_pressure_raw();
 
@@ -1069,19 +1142,18 @@
 			MX_I2C1_Init();
 			HAL_Delay(100);
 
-
 			if((global.I2C_SystemStatus == HAL_OK) && (!is_init_pressure_done()))
 			{
 				init_pressure();
 			}
 		}
 
-		if(secondsCount >= 30)
+		if((secondsCount >= 30) || (global.mode != MODE_SLEEP)) /* Service battery charge state in case sleep is left */
 		{
 			pressure_sensor_get_temperature_raw();
 			battery_gas_gauge_get_data();
-//			ReInit_battery_charger_status_pins();
-			battery_charger_get_status_and_contral_battery_gas_gauge(30);
+			ReInit_battery_charger_status_pins();
+			battery_charger_get_status_and_contral_battery_gas_gauge(secondsCount);
 //			DeInit_battery_charger_status_pins();
 			secondsCount = 0;
 		}
@@ -1120,6 +1192,7 @@
 	clearDecoNow = 0;
 	setButtonsNow = 0;
 	reinitGlobals();
+	ReInit_battery_charger_status_pins();
 }
 
 
@@ -1363,7 +1436,7 @@
 			}
 			break;
 
-		case	MODE_SLEEP:
+		case MODE_SLEEP:
 		case MODE_SHUTDOWN:
 			break;
 	}
@@ -1549,8 +1622,17 @@
 void copyBatteryData(void)
 {
 	uint8_t boolBatteryData = !global.dataSendToMaster.boolBatteryData;
+	global.lifeData.battery_charge = get_charge();
 	global.dataSendToMaster.data[boolBatteryData].battery_voltage = get_voltage();
-	global.dataSendToMaster.data[boolBatteryData].battery_charge= get_charge();
+
+	if(battery_gas_gauge_isChargeValueValid())
+	{
+		global.dataSendToMaster.data[boolBatteryData].battery_charge= global.lifeData.battery_charge;
+	}
+	else
+	{
+		global.dataSendToMaster.data[boolBatteryData].battery_charge = global.lifeData.battery_charge * -1.0;	/* negate value to show that this is just an assumption */
+	}
 	global.dataSendToMaster.boolBatteryData = boolBatteryData;
 }
 
@@ -1629,13 +1711,44 @@
 
 	uint8_t channel = 0;
 
+	uint8_t boolADCBuffer =  ~(global.dataSendToMaster.boolADCO2Data & DATA_BUFFER_ADC);
+
+	boolADCBuffer &= DATA_BUFFER_ADC;
+	global.dataSendToMaster.boolADCO2Data &= ~DATA_BUFFER_ADC;
+
 	for(channel = 0; channel < MAX_ADC_CHANNEL; channel++)
 	{
 		value = getExternalInterfaceChannel(channel);
-		global.dataSendToMaster.data[0].extADC_voltage[channel] = value;
+		global.dataSendToMaster.data[boolADCBuffer && DATA_BUFFER_ADC].extADC_voltage[channel] = value;
 	}
+	global.dataSendToMaster.boolADCO2Data |= boolADCBuffer;
 }
 
+void copyExtCO2data()
+{
+	uint16_t value;
+	uint8_t boolCO2Buffer =  ~(global.dataSendToMaster.boolADCO2Data & DATA_BUFFER_CO2);
+
+	global.dataSendToMaster.boolADCO2Data &= ~DATA_BUFFER_CO2;
+	boolCO2Buffer &= DATA_BUFFER_CO2;
+
+	if(externalInterface_GetCO2State())
+	{
+		value = externalInterface_GetCO2Value();
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].CO2_ppm = value;
+		value = externalInterface_GetCO2SignalStrength();
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].CO2_signalStrength = value;
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].externalInterface_CmdAnswer = externalInterface_GetCO2State();
+		externalInterface_SetCO2State(EXT_INTERFACE_33V_ON); 	/* clear command responses */
+	}
+	else
+	{
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].CO2_ppm = 0;
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].CO2_signalStrength = 0;
+		global.dataSendToMaster.data[(boolCO2Buffer && DATA_BUFFER_CO2)].externalInterface_CmdAnswer = 0;
+	}
+	global.dataSendToMaster.boolADCO2Data |= boolCO2Buffer;
+}
 
 typedef enum 
 {
--- a/Small_CPU/Src/spi.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/spi.c	Fri Aug 19 11:30:24 2022 +0200
@@ -350,7 +350,6 @@
 
 		/* stop data exchange? */
 		if (global.mode == MODE_SHUTDOWN) {
-			global.mode = MODE_SLEEP;
 			global.dataSendToSlavePending = 0;
 			global.dataSendToSlaveIsValid = 1;
 			global.dataSendToSlaveIsNotValidCount = 0;
--- a/Small_CPU/Src/stm32f4xx_hal_msp_v3.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/stm32f4xx_hal_msp_v3.c	Fri Aug 19 11:30:24 2022 +0200
@@ -229,14 +229,18 @@
 {
 
   GPIO_InitTypeDef GPIO_InitStruct;
-  if(huart->Instance==USART2)
+  if(huart->Instance==USART1)
   {
-    __USART2_CLK_ENABLE();
-    GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
+	  __GPIOA_CLK_ENABLE();
+    __USART1_CLK_ENABLE();
+    GPIO_InitStruct.Pin = GPIO_PIN_9;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_PULLUP;
-    GPIO_InitStruct.Speed = GPIO_SPEED_LOW;
-    GPIO_InitStruct.Alternate = GPIO_AF7_USART2;
+    GPIO_InitStruct.Speed = GPIO_SPEED_FAST; //GPIO_SPEED_LOW;
+    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
+    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
+
+    GPIO_InitStruct.Pin = GPIO_PIN_10;
     HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
   }
 }
@@ -244,10 +248,11 @@
 
 void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
 {
-  if(huart->Instance==USART2)
+  if(huart->Instance==USART1)
   {
-    __USART2_CLK_DISABLE();
-    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
+      HAL_NVIC_DisableIRQ(USART1_IRQn);
+    __USART1_CLK_DISABLE();
+    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
   }
 }
 
--- a/Small_CPU/Src/stm32f4xx_it_v3.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/stm32f4xx_it_v3.c	Fri Aug 19 11:30:24 2022 +0200
@@ -58,6 +58,9 @@
 extern RTC_HandleTypeDef RTCHandle;
 extern ADC_HandleTypeDef    AdcHandle;
 
+extern UART_HandleTypeDef huart1;
+extern DMA_HandleTypeDef  hdma_usart1_rx;
+
 /* Private function prototypes -----------------------------------------------*/
 /* Private functions ---------------------------------------------------------*/
 
@@ -233,6 +236,11 @@
   * @retval None
   */
 
+void DMA2_Stream5_IRQHandler(void)
+{
+  HAL_DMA_IRQHandler(&hdma_usart1_rx);
+}
+
 
 /******************************************************************************/
 /*                 STM32F4xx Peripherals Interrupt Handlers                   */
@@ -295,6 +303,12 @@
   HAL_ADC_IRQHandler(&AdcHandle);
 }
 
+
+void USART1_IRQHandler(void)
+{
+  HAL_UART_IRQHandler(&huart1);
+}
+
 /**
   * @brief  This function handles PPP interrupt request.
   * @param  None
--- a/Small_CPU/Src/uart.c	Mon Nov 01 12:39:34 2021 +0100
+++ b/Small_CPU/Src/uart.c	Fri Aug 19 11:30:24 2022 +0200
@@ -20,57 +20,370 @@
   */ 
 /* Includes ------------------------------------------------------------------*/
 #include "uart.h"
+#include "externalInterface.h"
+#include "data_exchange.h"
 
 /* Private variables ---------------------------------------------------------*/
 
-UART_HandleTypeDef huart2;
+#define CHUNK_SIZE			(20u)		/* the DMA will handle chunk size transfers */
+#define CHUNKS_PER_BUFFER	(3u)
+UART_HandleTypeDef huart1;
+
+DMA_HandleTypeDef  hdma_usart1_rx;
 
+uint8_t rxBuffer[CHUNK_SIZE * CHUNKS_PER_BUFFER];		/* The complete buffer has a X * chunk size to allow fariations in buffer read time */
+static uint8_t rxWriteIndex;					/* Index of the data item which is analysed */
+static uint8_t rxReadIndex;						/* Index at which new data is stared */
+static uint8_t lastCmdIndex;					/* Index of last command which has not been completly received */
+static uint8_t dmaActive;						/* Indicator if DMA receiption needs to be started */
 
+float LED_Level = 0.0;							/* Normalized LED value which may be used as indication for the health status of the sensor */
+float LED_ZeroOffset = 0.0;
+float pCO2 = 0.0;
 /* Exported functions --------------------------------------------------------*/
 
-void MX_USART2_UART_Init(void)
+void MX_USART1_UART_Init(void)
 {
-/* pullup special */
-  GPIO_InitTypeDef   GPIO_InitStructure;
-  __GPIOA_CLK_ENABLE();
-  GPIO_InitStructure.Pin = GPIO_PIN_2;
-  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
-  GPIO_InitStructure.Pull = GPIO_PULLUP;
-  GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
-  HAL_GPIO_Init(GPIOA, &GPIO_InitStructure); 
+/* regular init */	
+
+  huart1.Instance = USART1;
+  huart1.Init.BaudRate = 9600;
+  huart1.Init.WordLength = UART_WORDLENGTH_8B;
+  huart1.Init.StopBits = UART_STOPBITS_1;
+  huart1.Init.Parity = UART_PARITY_NONE;
+  huart1.Init.Mode = UART_MODE_TX_RX;
+  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
+
+  HAL_UART_Init(&huart1);
+
+  rxReadIndex = 0;
+  lastCmdIndex = 0;
+  rxWriteIndex = 0;
+  dmaActive = 0;
+}
+
+void MX_USART1_UART_DeInit(void)
+{
+	HAL_DMA_DeInit(&hdma_usart1_rx);
+	HAL_UART_DeInit(&huart1);
+}
+
+void  MX_USART1_DMA_Init()
+{
+  /* DMA controller clock enable */
+  __DMA2_CLK_ENABLE();
 
-/* regular init */	
-  huart2.Instance = USART2;
-  huart2.Init.BaudRate = 1200;
-  huart2.Init.WordLength = UART_WORDLENGTH_8B;
-  huart2.Init.StopBits = UART_STOPBITS_1;
-  huart2.Init.Parity = UART_PARITY_NONE;
-  huart2.Init.Mode = UART_MODE_TX_RX;
-  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
-  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
-  HAL_UART_Init(&huart2);
+  /* Peripheral DMA init*/
+  hdma_usart1_rx.Instance = DMA2_Stream5;
+  hdma_usart1_rx.Init.Channel = DMA_CHANNEL_4;
+  hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; //DMA_MEMORY_TO_PERIPH;
+  hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
+  hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;
+  hdma_usart1_rx.Init.PeriphDataAlignment = DMA_MDATAALIGN_BYTE;
+  hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
+  hdma_usart1_rx.Init.Mode = DMA_NORMAL;
+  hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;
+  hdma_usart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+  HAL_DMA_Init(&hdma_usart1_rx);
+
+  __HAL_LINKDMA(&huart1,hdmarx,hdma_usart1_rx);
+
+  /* DMA interrupt init */
+  HAL_NVIC_SetPriority(DMA2_Stream5_IRQn, 0, 0);
+  HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn);
+}
+
+void ConvertByteToHexString(uint8_t byte, char* str)
+{
+	uint8_t worker = 0;
+	uint8_t digit = 0;
+	uint8_t digitCnt = 1;
+
+	worker = byte;
+	while((worker!=0) && (digitCnt != 255))
+	{
+		digit = worker % 16;
+		if( digit < 10)
+		{
+			digit += '0';
+		}
+		else
+		{
+			digit += 'A' - 10;
+		}
+		str[digitCnt--]= digit;
+		worker = worker / 16;
+	}
 }
 
 
-uint8_t UART_ButtonAdjust(uint8_t *array)
+#ifdef ENABLE_CO2_SUPPORT
+void HandleUARTCO2Data(void)
+{
+	uint8_t localRX = rxReadIndex;
+	uint8_t dataType = 0;
+	uint32_t dataValue = 0;
+	static receiveState_t rxState = RX_Ready;
+	static uint32_t lastReceiveTick = 0;
+
+	while(localRX != rxWriteIndex)
+	{
+		lastReceiveTick = HAL_GetTick();
+		if(rxState == RX_Ready)		/* identify data content */
+		{
+			switch(rxBuffer[localRX])
+			{
+				case 'l':
+				case 'D':
+				case 'Z':
+									dataType = rxBuffer[localRX];
+									rxState = RX_Data0;
+									dataValue = 0;
+					break;
+
+				default:			/* unknown or corrupted => ignore */
+					break;
+			}
+		}
+		else if((rxState >= RX_Data0) && (rxState <= RX_Data4))
+		{
+			if((rxBuffer[localRX] >= '0') && (rxBuffer[localRX] <= '9'))
+			{
+				dataValue = dataValue * 10 + (rxBuffer[localRX] - '0');
+				rxState++;
+			}
+		}
+		if((rxBuffer[localRX] == ' ') || (rxBuffer[localRX] == '\n'))	/* Abort data detection */
+		{
+			if(rxState == RX_DataComplete)
+			{
+				if(externalInterface_GetCO2State() == 0)
+				{
+					externalInterface_SetCO2State(EXT_INTERFACE_33V_ON);
+				}
+				switch(dataType)
+				{
+					case 'D':			externalInterface_SetCO2SignalStrength(dataValue);
+						break;
+					case 'l':			LED_ZeroOffset = dataValue;
+						break;
+					case 'Z':			externalInterface_SetCO2Value(dataValue);
+						break;
+					default: break;
+				}
+			}
+			if(rxState != RX_Data0)	/* reset state machine because message in wrong format */
+			{
+				rxState = RX_Ready;
+			}
+		}
+
+		localRX++;
+		rxReadIndex++;
+		if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER)
+		{
+			localRX = 0;
+			rxReadIndex = 0;
+		}
+	}
+
+	if(time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 2000)	/* check for communication timeout */
+	{
+		externalInterface_SetCO2State(0);
+	}
+
+	if((dmaActive == 0)	&& (externalInterface_isEnabledPower33()))	/* Should never happen in normal operation => restart in case of communication error */
+	{
+		if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
+		{
+			dmaActive = 1;
+		}
+	}
+}
+#endif
+
+#ifdef ENABLE_SENTINEL_MODE
+void HandleUARTSentinelData(void)
 {
-	uint8_t answer[4];
-	
-	HAL_UART_Transmit(&huart2,array,4,1000);
-	HAL_UART_Receive(&huart2,answer,4,2000);
-	if(	(answer[0] == array[0])
-		&&(answer[1] == array[1])
-		&&(answer[2] == array[2])
-		&&(answer[3] == array[3]))
-	return 1;
-	else
-	return 0;
+	uint8_t localRX = rxReadIndex;
+	static uint8_t dataType = 0;
+	static uint32_t dataValue[3];
+	static uint8_t dataValueIdx = 0;
+	static receiveState_t rxState = RX_Ready;
+	static uint32_t lastReceiveTick = 0;
+	static uint8_t lastAlive = 0;
+	static uint8_t curAlive = 0;
+	static uint8_t checksum = 0;
+	char checksum_str[]="00";
+
+	while(localRX != rxWriteIndex)
+	{
+		lastReceiveTick = HAL_GetTick();
+
+		switch(rxState)
+		{
+			case RX_Ready:	if((rxBuffer[localRX] >= 'a') && (rxBuffer[localRX] <= 'z'))
+							{
+								rxState = RX_DetectStart;
+								curAlive = rxBuffer[localRX];
+								checksum = 0;
+							}
+					break;
+
+			case RX_DetectStart: 	checksum += rxBuffer[localRX];
+									if(rxBuffer[localRX] == '1')
+								 	{
+								 		rxState = RX_SelectData;
+								 		dataType = 0xFF;
+
+								 	}
+									else
+									{
+										rxState = RX_Ready;
+									}
+					break;
+
+			case RX_SelectData:		checksum += rxBuffer[localRX];
+									switch(rxBuffer[localRX])
+									{
+										case 'T':	dataType = rxBuffer[localRX];
+											break;
+										case '0': 	if(dataType != 0xff)
+													{
+														rxState = RX_Data0;
+														dataValueIdx = 0;
+														dataValue[0] = 0;
+
+													}
+													else
+													{
+														rxState = RX_Ready;
+													}
+											break;
+										default:	rxState = RX_Ready;
+									}
+					break;
+
+			case RX_Data0:
+			case RX_Data1:
+			case RX_Data2:
+			case RX_Data4:
+			case RX_Data5:
+			case RX_Data6:
+			case RX_Data8:
+			case RX_Data9:
+			case RX_Data10: checksum += rxBuffer[localRX];
+							if((rxBuffer[localRX] >= '0') && (rxBuffer[localRX] <= '9'))
+							{
+								dataValue[dataValueIdx] = dataValue[dataValueIdx] * 10 + (rxBuffer[localRX] - '0');
+								rxState++;
+							}
+							else
+							{
+								rxState = RX_Ready;
+							}
+					break;
+
+			case RX_Data3:
+			case RX_Data7:	checksum += rxBuffer[localRX];
+							if(rxBuffer[localRX] == '0')
+							{
+								rxState++;
+								dataValueIdx++;
+								dataValue[dataValueIdx] = 0;
+							}
+							else
+							{
+								rxState = RX_Ready;
+							}
+					break;
+			case RX_Data11: rxState = RX_DataComplete;
+							ConvertByteToHexString(checksum,checksum_str);
+							if(rxBuffer[localRX] == checksum_str[0])
+							{
+								rxState = RX_DataComplete;
+							}
+							else
+							{
+								rxState = RX_Ready;
+							}
+
+				break;
+
+			case RX_DataComplete:	if(rxBuffer[localRX] == checksum_str[1])
+									{
+										setExternalInterfaceChannel(0,(float)(dataValue[0] / 10.0));
+										setExternalInterfaceChannel(1,(float)(dataValue[1] / 10.0));
+										setExternalInterfaceChannel(2,(float)(dataValue[2] / 10.0));
+									}
+									rxState = RX_Ready;
+				break;
+
+
+			default:				rxState = RX_Ready;
+				break;
+
+		}
+
+		localRX++;
+		rxReadIndex++;
+		if(rxReadIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER)
+		{
+			localRX = 0;
+			rxReadIndex = 0;
+		}
+	}
+
+	if(time_elapsed_ms(lastReceiveTick,HAL_GetTick()) > 4000)	/* check for communication timeout */
+	{
+		if(curAlive == lastAlive)
+		{
+			setExternalInterfaceChannel(0,0.0);
+			setExternalInterfaceChannel(1,0.0);
+			setExternalInterfaceChannel(2,0.0);
+		}
+		lastAlive = curAlive;
+	}
+
+	if((dmaActive == 0)	&& (externalInterface_isEnabledPower33()))	/* Should never happen in normal operation => restart in case of communication error */
+	{
+		if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
+		{
+			dmaActive = 1;
+		}
+	}
 }
+#endif
 
-void MX_USART2_UART_DeInit(void)
+void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
 {
-	HAL_UART_DeInit(&huart2);
+    if(huart == &huart1)
+    {
+    	dmaActive = 0;
+    	rxWriteIndex+=CHUNK_SIZE;
+    	if(rxWriteIndex >= CHUNK_SIZE * CHUNKS_PER_BUFFER)
+    	{
+    		rxWriteIndex = 0;
+    	}
+    	if((rxWriteIndex / CHUNK_SIZE) != (rxReadIndex / CHUNK_SIZE))	/* start next transfer if we did not catch up with read index */
+    	{
+    		if(externalInterface_isEnabledPower33())
+    		{
+				if(HAL_OK == HAL_UART_Receive_DMA (&huart1, &rxBuffer[rxWriteIndex], CHUNK_SIZE))
+				{
+					dmaActive = 1;
+				}
+    		}
+    	}
+    }
 }
 
 
+
+
+
+
+
+
 /************************ (C) COPYRIGHT heinrichs weikamp *****END OF FILE****/