changeset 416:bcf447646e07

Merged in Ideenmodellierer/ostc4/Improment_NVM (pull request #37) Improment NVM
author heinrichsweikamp <bitbucket@heinrichsweikamp.com>
date Wed, 15 Jan 2020 10:53:15 +0000
parents 6f30f2011667 (current diff) e0907c7d8038 (diff)
children 54a480c43e97
files
diffstat 13 files changed, 639 insertions(+), 267 deletions(-) [+]
line wrap: on
line diff
--- a/Discovery/Inc/data_exchange_main.h	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Inc/data_exchange_main.h	Wed Jan 15 10:53:15 2020 +0000
@@ -45,6 +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);
 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);
--- a/Discovery/Src/base.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/base.c	Wed Jan 15 10:53:15 2020 +0000
@@ -351,6 +351,7 @@
     uint8_t lastsecond = 0xFF;
 #endif
 
+	SStateList status;
     detectionState_t pitchstate;
     set_globalState( StBoot0 );
     LastButtonPressed = 0;
@@ -477,6 +478,16 @@
             updateMenu();
             ext_flash_write_settings();
         }
+
+        /* check if tasks depending on global state are pending */
+        get_globalStateList(&status);
+        if(status.base == BaseHome)
+        {
+            tMenuEdit_writeSettingsToFlash(); // takes 900 ms!!
+        }
+
+        DataEX_merge_devicedata(); 	/* data is exchanged at startup and every 10 minutes => check if something changed */
+
         deco_loop();
         TriggerButtonAction();
         if(DoDisplayRefresh)							/* set every 100ms by timer interrupt */
@@ -624,8 +635,6 @@
         base_tempLightLevel = TIM_BACKLIGHT_adjust();
         tCCR_tick();
         tHome_tick();
-        if(status.base == BaseHome)
-            tMenuEdit_writeSettingsToFlash(); // takes 900 ms!!
         break;
     case BaseStop:
         DateEx_copy_to_dataOut();
@@ -1671,7 +1680,7 @@
 
     static CALC_WHAT what = CALC_INVALID;
     static int counter = 0;
-    if((stateUsed->mode != MODE_DIVE) || (stateUsed->diveSettings.diveMode == DIVEMODE_Apnea) || (decoLock != DECO_CALC_ready ))
+    if((stateUsed->mode != MODE_DIVE) || (stateUsed->diveSettings.diveMode == DIVEMODE_Apnea) || (stateUsed->diveSettings.diveMode == DIVEMODE_Gauge) || (decoLock != DECO_CALC_ready ))
         return;
 
     decoLock = DECO_CALC_running;
--- a/Discovery/Src/data_exchange_main.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/data_exchange_main.c	Wed Jan 15 10:53:15 2020 +0000
@@ -90,7 +90,15 @@
 static uint8_t data_old__lost_connection_to_slave_counter_retry = 0;
 static uint32_t data_old__lost_connection_to_slave_counter_total = 0;
 
+static uint8_t DeviceDataUpdated = 0;
+
 /* Private types -------------------------------------------------------------*/
+#define UNKNOWN_TIME_HOURS		1
+#define UNKNOWN_TIME_MINUTES	0
+#define UNKNOWN_TIME_SECOND		0
+#define UNKNOWN_DATE_DAY		1
+#define UNKNOWN_DATE_MONTH		1
+#define UNKNOWN_DATE_YEAR		16
 
 /* Private function prototypes -----------------------------------------------*/
 static uint8_t DataEX_check_header_and_footer_ok(void);
@@ -99,7 +107,6 @@
 static void DataEX_check_DeviceData(void);
 
 /* Exported functions --------------------------------------------------------*/
-
 uint8_t DataEX_was_power_on(void)
 {
 	return wasPowerOn;
@@ -141,6 +148,7 @@
 	pStateReal->data_old__lost_connection_to_slave = 0; //initial value
 	data_old__lost_connection_to_slave_counter_temp = 0;
 	data_old__lost_connection_to_slave_counter_total = 0;
+	DeviceDataUpdated = 0;
 
 	memset((void *)&dataOut, 0, sizeof(SDataReceiveFromMaster));
 
@@ -517,19 +525,18 @@
 }
 
 
-
 static void DataEX_helper_set_Unknown_Date_deviceData(SDeviceLine *lineWrite)
 {	
 	RTC_DateTypeDef sdatestructure;
 	RTC_TimeTypeDef stimestructure;
 
-	stimestructure.Hours = 1;
-	stimestructure.Minutes = 0;
-	stimestructure.Seconds = 0;
+	stimestructure.Hours = UNKNOWN_TIME_HOURS;
+	stimestructure.Minutes = UNKNOWN_TIME_MINUTES;
+	stimestructure.Seconds = UNKNOWN_TIME_SECOND;
 
-	sdatestructure.Date = 1;
-	sdatestructure.Month = 1;
-	sdatestructure.Year = 16;
+	sdatestructure.Date = UNKNOWN_DATE_DAY;
+	sdatestructure.Month = UNKNOWN_DATE_MONTH;
+	sdatestructure.Year = UNKNOWN_DATE_YEAR;
 	setWeekday(&sdatestructure);
 
 	DataEX_helper_SetTime(stimestructure, &lineWrite->time_rtc_tr);
@@ -539,36 +546,63 @@
 
 static uint8_t DataEX_helper_Check_And_Correct_Date_deviceData(SDeviceLine *lineWrite)
 {
+	uint8_t retval = 0;
 	RTC_DateTypeDef sdatestructure;
 	RTC_TimeTypeDef stimestructure;
 
 	// from lineWrite to structure
 	translateDate(lineWrite->date_rtc_dr, &sdatestructure);
 	translateTime(lineWrite->time_rtc_tr, &stimestructure);
-	
-	if(		(sdatestructure.Year >= 15)
+
+	/* Check if date is out of range */
+	if(!(	(sdatestructure.Year >= 15)
 			&& (sdatestructure.Year <= 30)
-			&& (sdatestructure.Month <= 12))
-		return 0;
-
-
-	DataEX_helper_set_Unknown_Date_deviceData(lineWrite);
-	return 1;
+			&& (sdatestructure.Month <= 12)))
+	{
+		DataEX_helper_set_Unknown_Date_deviceData(lineWrite);
+		retval = 1;
+	}
+	return retval;
 }
 
 
-static uint8_t DataEX_helper_Check_And_Correct_Value_deviceData(SDeviceLine *lineWrite, int32_t from, int32_t to)
+static uint8_t DataEX_helper_Check_And_Correct_Value_deviceData(SDeviceLine *lineWrite, int32_t from, int32_t to, uint8_t defaulttofrom)
 {
-	if(lineWrite->value_int32 >= from && lineWrite->value_int32 <= to)
-		return 0;
+	uint8_t retval = 0;
+	RTC_DateTypeDef sdatestructure;
+
+	/* Is value out of valid range? */
+	if(!(lineWrite->value_int32 >= from && lineWrite->value_int32 <= to))
+	{
+		if(defaulttofrom)
+		{
+			lineWrite->value_int32 = from;
+		}
+		else
+		{
+			lineWrite->value_int32 = to;
+		}
+		DataEX_helper_set_Unknown_Date_deviceData(lineWrite);
+	}
 
-	if(lineWrite->value_int32 < from)
-		lineWrite->value_int32 = from;
-	else
-		lineWrite->value_int32 = to;
-		
-	DataEX_helper_set_Unknown_Date_deviceData(lineWrite);
-	return 0;
+	/* This is just a repair function to restore metric if a corruption occurred in an older fw version */
+	if(((lineWrite->value_int32 == to) && defaulttofrom )
+		|| ((lineWrite->value_int32 == from) && !defaulttofrom ))
+	{
+		translateDate(lineWrite->date_rtc_dr, &sdatestructure);
+		if(sdatestructure.Year == UNKNOWN_DATE_YEAR)
+		{
+			if(defaulttofrom)
+			{
+				lineWrite->value_int32 = from;
+			}
+			else
+			{
+				lineWrite->value_int32 = to;
+			}
+		}
+	}
+	return retval;
 }
 
 
@@ -585,14 +619,14 @@
 	DataEX_helper_Check_And_Correct_Date_deviceData(&DeviceData->temperatureMinimum);
 	DataEX_helper_Check_And_Correct_Date_deviceData(&DeviceData->voltageMinimum);
 
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->batteryChargeCompleteCycles, 0, 10000);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->batteryChargeCycles, 0, 20000);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->depthMaximum, 0, (500*100)+1000);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->diveCycles, 0, 20000);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->hoursOfOperation, 0, 1000000);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->temperatureMaximum, -30*100, 150*100);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->temperatureMinimum, -30*100, 150*100);
-	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->voltageMinimum, -1*1000, 6*1000);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->batteryChargeCompleteCycles, 0, 10000,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->batteryChargeCycles, 0, 20000,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->depthMaximum, 0, (500*100)+1000,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->diveCycles, 0, 20000,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->hoursOfOperation, 0, 1000000,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->temperatureMaximum, -30*100, 150*100,1);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->temperatureMinimum, -30*100, 150*100,0);
+	DataEX_helper_Check_And_Correct_Value_deviceData(&DeviceData->voltageMinimum, 2*1000, 6*1000,0);
 }
 
 
@@ -631,20 +665,21 @@
 	{
 		DataEX_helper_copy_deviceData(&DeviceData->diveCycles, &DeviceDataFlash.diveCycles);
 	}
+	if(DeviceData->hoursOfOperation.value_int32 < DeviceDataFlash.hoursOfOperation.value_int32)
+	{
+		DataEX_helper_copy_deviceData(&DeviceData->hoursOfOperation, &DeviceDataFlash.hoursOfOperation);
+	}
 	
+
 	/* min values */
 	if(DeviceData->temperatureMinimum.value_int32 > DeviceDataFlash.temperatureMinimum.value_int32)
 	{
 		DataEX_helper_copy_deviceData(&DeviceData->temperatureMinimum, &DeviceDataFlash.temperatureMinimum);
 	}
-	// Voltage minimum, keep limit to 2.0 Volt; hw 09.09.2015
 	if(DeviceData->voltageMinimum.value_int32 > DeviceDataFlash.voltageMinimum.value_int32)
 	{
-		if(DeviceDataFlash.voltageMinimum.value_int32 > 2000) // do not copy back 2000 and below
 			DataEX_helper_copy_deviceData(&DeviceData->voltageMinimum, &DeviceDataFlash.voltageMinimum);
 	}
-	if(DeviceData->voltageMinimum.value_int32 < 2000)
-		DeviceData->voltageMinimum.value_int32 = 2000;
 	
 	DataEX_check_DeviceData	();
 	ext_flash_write_devicedata();
@@ -657,6 +692,7 @@
 	SDevice * pDeviceState = stateDeviceGetPointerWrite();
 
 	memcpy(pDeviceState, &dataInDevice->DeviceData[dataInDevice->boolDeviceData], sizeof(SDevice));
+	DeviceDataUpdated = 1;	/* indicate new data to be written to flash by background task (at last op hour count will be updated) */
 }
 
 
@@ -755,7 +791,6 @@
 		if(DataEX_check_header_and_footer_devicedata())
 		{
 			DataEX_copy_to_DeviceData();
-			DataEX_merge_DeviceData_and_store();
 			DataEX_copy_to_VpmRepetitiveData();
 			data_old__lost_connection_to_slave_counter_temp = 0;
 			data_old__lost_connection_to_slave_counter_retry = 0;
@@ -1109,3 +1144,13 @@
 
 	return 1;
 }
+
+void DataEX_merge_devicedata(void)
+{
+	if(DeviceDataUpdated)
+	{
+		DeviceDataUpdated = 0;
+		DataEX_merge_DeviceData_and_store();
+	}
+}
+
--- a/Discovery/Src/logbook.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/logbook.c	Wed Jan 15 10:53:15 2020 +0000
@@ -64,6 +64,8 @@
 #define LOGBOOK_VERSION (0x30)
 #define LOGBOOK_VERSION_OSTC3 (0x24)
 
+#define DEFAULT_SAMPLES	(100)	/* Number of sample data bytes in case of an broken header information */
+
 typedef struct /* don't forget to adjust void clear_divisor(void) */
 {
 	uint8_t temperature;
@@ -78,7 +80,7 @@
 /* Exported variables --------------------------------------------------------*/
 
 /* Private variables ---------------------------------------------------------*/
-static  SLogbookHeader  header;
+static SLogbookHeader  gheader;
 static SLogbookHeaderOSTC3	headerOSTC3;
 static SLogbookHeaderOSTC3compact headerOSTC3compact;
 static SSmallHeader smallHeader;
@@ -99,7 +101,7 @@
 
 void logbook_EndDive(void)
 {
-	ext_flash_close_new_dive_log((uint8_t*) &header);
+	ext_flash_close_new_dive_log((uint8_t*) &gheader);
 }
 
 
@@ -136,7 +138,7 @@
 */
 SLogbookHeader* logbook_getCurrentHeader(void)
 {
-    return &header;
+    return &gheader;
 }
 
 /**
@@ -198,78 +200,78 @@
 
 	for(int i = 0; i < sizeof(SLogbookHeader); i++)
 	{
-		((uint8_t*)(&header))[i] = 0;
+		((uint8_t*)(&gheader))[i] = 0;
 	}
-	header.diveHeaderStart = 0xFAFA;
-	header.diveHeaderEnd = 0xFBFB;
-	header.samplingRate = 2;
+	gheader.diveHeaderStart = 0xFAFA;
+	gheader.diveHeaderEnd = 0xFBFB;
+	gheader.samplingRate = 2;
 	if(pInfo->diveSettings.diveMode == DIVEMODE_OC)
   {
     for(int i = 0; i < 5; i++)
     {
-      header.gasordil[i].oxygen_percentage = pSettings->gas[i+1].oxygen_percentage;
-      header.gasordil[i].helium_percentage = pSettings->gas[i+1].helium_percentage;
-      header.gasordil[i].note.uw = pSettings->gas[i+1].note.uw;
-      header.gasordil[i].depth_meter = pSettings->gas[i+1].depth_meter;
+      gheader.gasordil[i].oxygen_percentage = pSettings->gas[i+1].oxygen_percentage;
+      gheader.gasordil[i].helium_percentage = pSettings->gas[i+1].helium_percentage;
+      gheader.gasordil[i].note.uw = pSettings->gas[i+1].note.uw;
+      gheader.gasordil[i].depth_meter = pSettings->gas[i+1].depth_meter;
     }
   }
   else
   {
     for(int i = 0; i < 5; i++)
     {
-      header.gasordil[i].oxygen_percentage = pSettings->gas[i+6].oxygen_percentage;
-      header.gasordil[i].helium_percentage = pSettings->gas[i+6].helium_percentage;
-      header.gasordil[i].note.uw = pSettings->gas[i+6].note.uw;
-      header.gasordil[i].depth_meter = pSettings->gas[i+6].depth_meter;
+      gheader.gasordil[i].oxygen_percentage = pSettings->gas[i+6].oxygen_percentage;
+      gheader.gasordil[i].helium_percentage = pSettings->gas[i+6].helium_percentage;
+      gheader.gasordil[i].note.uw = pSettings->gas[i+6].note.uw;
+      gheader.gasordil[i].depth_meter = pSettings->gas[i+6].depth_meter;
     }
 
     for(int i = 0; i < 5; i++)
     {
-      header.setpoint[i].setpoint_cbar = pSettings->setpoint[i+1].setpoint_cbar;
-      header.setpoint[i].depth_meter = pSettings->setpoint[i+1].depth_meter;
+      gheader.setpoint[i].setpoint_cbar = pSettings->setpoint[i+1].setpoint_cbar;
+      gheader.setpoint[i].depth_meter = pSettings->setpoint[i+1].depth_meter;
     }
   }
 //	header.gasordil[pInfo->lifeData.actualGas.GasIdInSettings].depth_meter = 0;
 
 	translateDate(pInfo->lifeData.dateBinaryFormat, &Sdate);
 	translateTime(pInfo->lifeData.timeBinaryFormat, &Stime);
-	header.dateYear = Sdate.Year;
-	header.dateMonth = Sdate.Month;
-	header.dateDay = Sdate.Date;
-	header.timeHour = Stime.Hours;
-	header.timeMinute = Stime.Minutes;
-	header.cnsAtBeginning = (uint16_t)pInfo->lifeData.cns;
-	header.surfacePressure_mbar = (uint16_t)(pInfo->lifeData.pressure_surface_bar * 1000);
-	header.firmwareVersionHigh = firmwareVersion_16bit_high();
-	header.firmwareVersionLow = firmwareVersion_16bit_low();
-	header.logbookProfileVersion = LOGBOOK_VERSION;
-	header.salinity = pSettings->salinity;
-	header.diveNumber = pSettings->totalDiveCounter;
-	header.personalDiveCount = pSettings->personalDiveCount;
+	gheader.dateYear = Sdate.Year;
+	gheader.dateMonth = Sdate.Month;
+	gheader.dateDay = Sdate.Date;
+	gheader.timeHour = Stime.Hours;
+	gheader.timeMinute = Stime.Minutes;
+	gheader.cnsAtBeginning = (uint16_t)pInfo->lifeData.cns;
+	gheader.surfacePressure_mbar = (uint16_t)(pInfo->lifeData.pressure_surface_bar * 1000);
+	gheader.firmwareVersionHigh = firmwareVersion_16bit_high();
+	gheader.firmwareVersionLow = firmwareVersion_16bit_low();
+	gheader.logbookProfileVersion = LOGBOOK_VERSION;
+	gheader.salinity = pSettings->salinity;
+	gheader.diveNumber = pSettings->totalDiveCounter;
+	gheader.personalDiveCount = pSettings->personalDiveCount;
 
-	header.diveMode = pInfo->diveSettings.diveMode;
-	header.CCRmode = pInfo->diveSettings.CCR_Mode;
-	header.lastDecostop_m = pSettings->last_stop_depth_meter;
+	gheader.diveMode = pInfo->diveSettings.diveMode;
+	gheader.CCRmode = pInfo->diveSettings.CCR_Mode;
+	gheader.lastDecostop_m = pSettings->last_stop_depth_meter;
 
 	if(pInfo->diveSettings.deco_type.ub.standard == GF_MODE)
 	{
-		header.decoModel = 1;
-		header.gfLow_or_Vpm_conservatism = pInfo->diveSettings.gf_low;
-		header.gfHigh = pInfo->diveSettings.gf_high;
+		gheader.decoModel = 1;
+		gheader.gfLow_or_Vpm_conservatism = pInfo->diveSettings.gf_low;
+		gheader.gfHigh = pInfo->diveSettings.gf_high;
 	}
 	else
 	{
-		header.decoModel = 2;
-		header.gfLow_or_Vpm_conservatism = pInfo->diveSettings.vpm_conservatism;
-		header.gfHigh = 0;
+		gheader.decoModel = 2;
+		gheader.gfLow_or_Vpm_conservatism = pInfo->diveSettings.vpm_conservatism;
+		gheader.gfHigh = 0;
 	}
 
-	memcpy(header.n2Compartments, pInfo->lifeData.tissue_nitrogen_bar, 64);
-	memcpy(header.heCompartments, pInfo->lifeData.tissue_helium_bar, 64);
+	memcpy(gheader.n2Compartments, pInfo->lifeData.tissue_nitrogen_bar, 64);
+	memcpy(gheader.heCompartments, pInfo->lifeData.tissue_helium_bar, 64);
 
 	logbook_SetCompartmentDesaturation(pInfo);
 
-	ext_flash_start_new_dive_log_and_set_actualPointerSample((uint8_t*)&header);
+	ext_flash_start_new_dive_log_and_set_actualPointerSample((uint8_t*)&gheader);
 
 	smallHeader.profileLength[0] = 0xFF;
 	smallHeader.profileLength[1] = 0xFF;
@@ -1176,7 +1178,7 @@
 			tickstart = lasttick;
 			if((bDiveMode == 1) && (pStateReal->lifeData.dive_time_seconds >= pSettings->divetimeToCreateLogbook))
 			{
-				ext_flash_create_new_dive_log((uint8_t*)&header);
+				ext_flash_create_new_dive_log((uint8_t*)&gheader);
 				/** save settings
 					* with new lastDiveLogId and time and day
 					*/
@@ -1201,7 +1203,7 @@
 		logbook_SetMaxCNS(pStateReal->lifeData.cns);
 		logbook_SetCompartmentDesaturation(pStateReal);
 		logbook_SetLastStop(pStateReal->diveSettings.last_stop_depth_bar);
-		header.batteryVoltage = pStateReal->lifeData.battery_voltage * 1000;
+		gheader.batteryVoltage = pStateReal->lifeData.battery_voltage * 1000;
 		logbook_EndDive();
 		bDiveMode = 0;
 	} else
@@ -1242,49 +1244,49 @@
 	header.timeMinute = Stime.Minutes;
 	*/
 	/// 160315 Quick fix for empty date problem
-	if((!(header.dateYear)) || (!(header.dateMonth)) || (!(header.dateDay)))
+	if((!(gheader.dateYear)) || (!(gheader.dateMonth)) || (!(gheader.dateDay)))
 	{
 		translateDate(pStateReal->lifeData.dateBinaryFormat, &Sdate);
 		translateTime(pStateReal->lifeData.timeBinaryFormat, &Stime);
 
-		header.dateYear = Sdate.Year;
-		header.dateMonth = Sdate.Month;
-		header.dateDay = Sdate.Date;
+		gheader.dateYear = Sdate.Year;
+		gheader.dateMonth = Sdate.Month;
+		gheader.dateDay = Sdate.Date;
 		
-		time1_u32 = (uint32_t)header.timeMinute + (uint32_t)(header.timeHour * 60);
+		time1_u32 = (uint32_t)gheader.timeMinute + (uint32_t)(gheader.timeHour * 60);
 		time2_u32 = (uint32_t)Stime.Minutes + (uint32_t)(Stime.Hours * 60);
 		if(time2_u32 < time1_u32)
 		{
-			if(header.dateDay > 1)
+			if(gheader.dateDay > 1)
 			{
-				header.dateDay -= 1;
+				gheader.dateDay -= 1;
 			}
 			else
 			{
-				header.dateMonth --;
-				if(!header.dateMonth)
+				gheader.dateMonth --;
+				if(!gheader.dateMonth)
 				{
-					header.dateYear--;
-					header.dateMonth = 12;
-					header.dateDay = 31;
+					gheader.dateYear--;
+					gheader.dateMonth = 12;
+					gheader.dateDay = 31;
 				}
 				else
 				{
-					if(header.dateMonth == 2)
-						header.dateDay = 28;
+					if(gheader.dateMonth == 2)
+						gheader.dateDay = 28;
 					else
-					if((header.dateMonth == 4) || (header.dateMonth == 6) || (header.dateMonth == 9) || (header.dateMonth == 11))
-						header.dateDay = 30;
+					if((gheader.dateMonth == 4) || (gheader.dateMonth == 6) || (gheader.dateMonth == 9) || (gheader.dateMonth == 11))
+						gheader.dateDay = 30;
 					else
-						header.dateDay = 31;
+						gheader.dateDay = 31;
 				}
 			}
 		}
 	}
 	
 	/* duration */
-	header.total_diveTime_seconds = pStateReal->lifeData.dive_time_seconds;
-	header.maxDepth = pStateReal->lifeData.max_depth_meter * 100;
+	gheader.total_diveTime_seconds = pStateReal->lifeData.dive_time_seconds;
+	gheader.maxDepth = pStateReal->lifeData.max_depth_meter * 100;
 
 	/* old:
 	
@@ -1295,49 +1297,49 @@
 	header.diveTimeSeconds = header.total_diveTime_seconds - secondsAtShallow - (header.diveTimeMinutes * 60);
 	*/
 	divetimeHelper = pStateReal->lifeData.dive_time_seconds_without_surface_time;
-	header.diveTimeMinutes = (uint16_t)(divetimeHelper/60);
-	divetimeHelper -= 60 * (uint32_t)header.diveTimeMinutes;
-	header.diveTimeSeconds = (uint16_t)divetimeHelper;
+	gheader.diveTimeMinutes = (uint16_t)(divetimeHelper/60);
+	divetimeHelper -= 60 * (uint32_t)gheader.diveTimeMinutes;
+	gheader.diveTimeSeconds = (uint16_t)divetimeHelper;
 	
 	/* deco algorithm (final) */
 	if(pStateReal->diveSettings.deco_type.ub.standard == GF_MODE)
 	{
-		header.decoModel = 1;
-		header.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.gf_low;
-		header.gfHigh = pStateReal->diveSettings.gf_high;
+		gheader.decoModel = 1;
+		gheader.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.gf_low;
+		gheader.gfHigh = pStateReal->diveSettings.gf_high;
 	}
 	else
 	{
-		header.decoModel = 2;
-		header.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.vpm_conservatism;
-		header.gfHigh = 0;
+		gheader.decoModel = 2;
+		gheader.gfLow_or_Vpm_conservatism = pStateReal->diveSettings.vpm_conservatism;
+		gheader.gfHigh = 0;
 	}
 
 	/* tissue load */
-	memcpy(header.n2Compartments, pStateReal->lifeData.tissue_nitrogen_bar, 64);
-	memcpy(header.heCompartments, pStateReal->lifeData.tissue_helium_bar, 64);
+	memcpy(gheader.n2Compartments, pStateReal->lifeData.tissue_nitrogen_bar, 64);
+	memcpy(gheader.heCompartments, pStateReal->lifeData.tissue_helium_bar, 64);
 
 }
 
 
 static void logbook_SetAverageDepth(float average_depth_meter)
 {
-		header.averageDepth_mbar = (uint16_t)(average_depth_meter * 100);
+		gheader.averageDepth_mbar = (uint16_t)(average_depth_meter * 100);
 }
 
 
 static void logbook_SetMinTemperature(float min_temperature_celsius)
 {
-		header.minTemp = (int16_t)((min_temperature_celsius * 10.0f) + 0.5f);
+		gheader.minTemp = (int16_t)((min_temperature_celsius * 10.0f) + 0.5f);
 }
 
 
 static void logbook_SetMaxCNS(float max_cns_percentage)
 {
 	if(max_cns_percentage < 9999)
-		header.maxCNS = (uint16_t)(max_cns_percentage);
+		gheader.maxCNS = (uint16_t)(max_cns_percentage);
 	else
-		header.maxCNS = 9999;
+		gheader.maxCNS = 9999;
 }
 
 
@@ -1349,19 +1351,19 @@
 	for(int i=0;i<16;i++)
 	{
 		if(secondaryInformation.tissue_nitrogen_desaturation_time_minutes[i] <= (15 * 255))
-			header.n2CompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_nitrogen_desaturation_time_minutes[i] + 14) / 15);
+			gheader.n2CompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_nitrogen_desaturation_time_minutes[i] + 14) / 15);
 		else
-			header.n2CompartDesatTime_min[i] = 255;
+			gheader.n2CompartDesatTime_min[i] = 255;
 		if(secondaryInformation.tissue_helium_desaturation_time_minutes[i] <= (15 * 255))
-			header.heCompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_helium_desaturation_time_minutes[i] + 14 )/ 15);
+			gheader.heCompartDesatTime_min[i] = (uint8_t)((secondaryInformation.tissue_helium_desaturation_time_minutes[i] + 14 )/ 15);
 		else
-			header.heCompartDesatTime_min[i] = 255;
+			gheader.heCompartDesatTime_min[i] = 255;
 	}
 }
 
 static void logbook_SetLastStop(float last_stop_depth_bar)
 {
-	header.lastDecostop_m = (uint8_t)(last_stop_depth_bar / 10.0f);
+	gheader.lastDecostop_m = (uint8_t)(last_stop_depth_bar / 10.0f);
 }
 
 static void logbook_writedata(void * data, int length_byte)
@@ -1369,7 +1371,6 @@
     ext_flash_write_sample(data, length_byte);
 }
 
-
 /********************************************************************************
 	* @brief   logbook_build_ostc3header. /
   * @author  heinrichs weikamp gmbh
@@ -1378,17 +1379,40 @@
 *********************************************************************************/
 SLogbookHeaderOSTC3 * logbook_build_ostc3header(SLogbookHeader* pHead)
 {
-	convert_Type data;
+	convert_Type data,data2;
 
 	memcpy(headerOSTC3.diveHeaderStart,			&pHead->diveHeaderStart,					2);
 	memcpy(headerOSTC3.pBeginProfileData,		&pHead->pBeginProfileData,				3);
 	memcpy(headerOSTC3.pEndProfileData,			&pHead->pEndProfileData,					3);
 
+
 	data.u8bit.byteHigh = 0;
-	data.u8bit.byteLow 			= pHead->profileLength[0];
-	data.u8bit.byteMidLow 	= pHead->profileLength[1];
-	data.u8bit.byteMidHigh 	= pHead->profileLength[2];
+	data.u8bit.byteLow 			= pHead->pBeginProfileData[0];
+	data.u8bit.byteMidLow 	= pHead->pBeginProfileData[1];
+	data.u8bit.byteMidHigh 	= pHead->pBeginProfileData[2];
+
+	data2.u8bit.byteHigh = 0;
+	data2.u8bit.byteLow 			= pHead->pEndProfileData[0];
+	data2.u8bit.byteMidLow 	= pHead->pEndProfileData[1];
+	data2.u8bit.byteMidHigh 	= pHead->pEndProfileData[2];
 
+	/* check if sample address information are corrupted by address range. */
+	/* TODO: Workaround. Better solution would be to check end of ring for 0xFF pattern */
+	if((data.u32bit > data2.u32bit) && (data.u32bit < (SAMPLESTOP - 0x9000)))
+	{
+		data2.u32bit = data.u32bit + DEFAULT_SAMPLES;
+		pHead->pEndProfileData[0] = data2.u8bit.byteLow;
+		pHead->pEndProfileData[1] = data2.u8bit.byteMidLow;
+		pHead->pEndProfileData[2] = data2.u8bit.byteMidHigh;
+		data.u32bit = DEFAULT_SAMPLES;
+	}
+	else
+	{
+		data.u8bit.byteHigh = 0;
+		data.u8bit.byteLow 			= pHead->profileLength[0];
+		data.u8bit.byteMidLow 	= pHead->profileLength[1];
+		data.u8bit.byteMidHigh 	= pHead->profileLength[2];
+	}
 	if(data.u32bit != 0xFFFFFF)
 		data.u32bit += 3;
 
@@ -1502,12 +1526,36 @@
 *********************************************************************************/
 SLogbookHeaderOSTC3compact * logbook_build_ostc3header_compact(SLogbookHeader* pHead)
 {
-	convert_Type data;
+	convert_Type data, data2;
+
 
 	data.u8bit.byteHigh = 0;
-	data.u8bit.byteLow 			= pHead->profileLength[0];
-	data.u8bit.byteMidLow 	= pHead->profileLength[1];
-	data.u8bit.byteMidHigh 	= pHead->profileLength[2];
+	data.u8bit.byteLow 			= pHead->pBeginProfileData[0];
+	data.u8bit.byteMidLow 	= pHead->pBeginProfileData[1];
+	data.u8bit.byteMidHigh 	= pHead->pBeginProfileData[2];
+
+	data2.u8bit.byteHigh = 0;
+	data2.u8bit.byteLow 			= pHead->pEndProfileData[0];
+	data2.u8bit.byteMidLow 	= pHead->pEndProfileData[1];
+	data2.u8bit.byteMidHigh 	= pHead->pEndProfileData[2];
+
+	/* check if sample address information are corrupted by address range. */
+	/* TODO: Workaround. Better solution would be to check end of ring for 0xFF pattern */
+	if((data.u32bit > data2.u32bit) && (data.u32bit < (SAMPLESTOP - 0x9000)))
+	{
+		data2.u32bit = data.u32bit + DEFAULT_SAMPLES;
+		pHead->pEndProfileData[0] = data2.u8bit.byteLow;
+		pHead->pEndProfileData[1] = data2.u8bit.byteMidLow;
+		pHead->pEndProfileData[2] = data2.u8bit.byteMidHigh;
+		data.u32bit = DEFAULT_SAMPLES;
+	}
+	else
+	{
+		data.u8bit.byteHigh = 0;
+		data.u8bit.byteLow 			= pHead->profileLength[0];
+		data.u8bit.byteMidLow 	= pHead->profileLength[1];
+		data.u8bit.byteMidHigh 	= pHead->profileLength[2];
+	}
 
 	if(data.u32bit != 0xFFFFFF)
 	{
--- a/Discovery/Src/t3.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/t3.c	Wed Jan 15 10:53:15 2020 +0000
@@ -259,13 +259,28 @@
             else
                 depthChangeRate = 200;
         }
-        start.y = tXl1->WindowY0 - 1;
+
+        if(!pSettings->FlipDisplay)
+        {
+        	start.y = tXl1->WindowY0 - 1;
+        }
+        else
+        {
+        	start.y = tXl1->WindowY1 + 1;
+        }
         startZeroLine.y = start.y;
         for(int i = 0; i<5;i++)
         {
             start.y += 40;
             stop.y = start.y;
-            start.x = tXl1->WindowX1 - 1;
+            if(!pSettings->FlipDisplay)
+            {
+            	start.x = tXl1->WindowX1 - 1;
+            }
+            else
+            {
+            	start.x = tXr1->WindowX1 - 1;
+            }
             stop.x = start.x - 17;
 
             if(depthChangeRate <= 6)
@@ -290,7 +305,6 @@
         if((stateUsed->lifeData.ascent_rate_meter_per_min > 4) || (stateUsed->lifeData.ascent_rate_meter_per_min < -4))
         {
             start.y = startZeroLine.y;
-
             if(depthChangeAscent)
             {
                 color = CLUT_EverythingOkayGreen;
@@ -307,7 +321,16 @@
                 if(stop.y <= tXl1->WindowY0)
                     stop.y = tXl1->WindowY0 + 1;
             }
-            stop.x = start.x = tXl1->WindowX1 - 8;
+            if(!pSettings->FlipDisplay)
+            {
+            	start.x = tXl1->WindowX1 - 3 - 5;
+            }
+            else
+            {
+            	start.x = tXr1->WindowX1 - 3 - 5;
+            }
+
+            stop.x = start.x;
             GFX_draw_thick_line(12,tXscreen, start, stop, color);
         }
     }
@@ -501,15 +524,21 @@
 
     // CVIEW_T3_Temperature
     float temperature;
+	SSettings* pSettings;
+	pSettings = settingsGetPointer();
 
     SDivetime TotalDivetime = {0,0,0,0};
     SDivetime LastDivetime = {0,0,0,0};
 
     uint16_t tempWinX0;
+    uint16_t tempWinX1;
     uint16_t tempWinY0;
+    uint16_t tempWinY1;
 
     tempWinX0 = tXc1->WindowX0;
+    tempWinX1 = tXc1->WindowX1;
     tempWinY0 = tXc1->WindowY0;
+    tempWinY1 = tXc1->WindowY1;
 
     tXc1->WindowX0 = 440; // rechte Seite
 
@@ -542,27 +571,54 @@
         LastDivetime.Minutes = LastDivetime.Total / 60;
         LastDivetime.Seconds = LastDivetime.Total - ( LastDivetime.Minutes * 60 );
 
-        tXc1->WindowY0 = 100; // obere Zeile
+   //     tXc1->WindowY0 = 100; // obere Zeile
+        if(!pSettings->FlipDisplay)
+        {
+        	tXc1->WindowY0 = 100;
+        }
+        else
+        {
+        	tXc1->WindowY1 -= 100; /* jump to upper of two lines */
+        }
 
         snprintf(text,TEXTSIZE,"\020\016%u:%02u",LastDivetime.Minutes, LastDivetime.Seconds);
         t3_basics_colorscheme_mod(text);
         GFX_write_string(&FontT105,tXc1,text,0);
 
+        if(pSettings->FlipDisplay)
+        {
+            tXc1->WindowX0 = 0;
+
+        }
         snprintf(text,TEXTSIZE,"\032\002%c%c",TXT_2BYTE, TXT2BYTE_ApneaLast);
         GFX_write_string(&FontT42,tXc1,text,0);
 
-        tXc1->WindowY0 = tempWinY0; // wieder unten
+        if(!pSettings->FlipDisplay)
+        {
+        	tXc1->WindowY0 = tempWinY0;
+        }
+        else
+        {
+            tXc1->WindowX1 = tempWinX1;
+        	tXc1->WindowY1 = tempWinY1; /* jump to upper of two lines */
+        }
 
         snprintf(text,TEXTSIZE,"\020\016%u:%02u",TotalDivetime.Minutes, TotalDivetime.Seconds);
         t3_basics_colorscheme_mod(text);
         GFX_write_string(&FontT105,tXc1,text,0);
 
         snprintf(text,TEXTSIZE,"\032\002%c%c",TXT_2BYTE, TXT2BYTE_ApneaTotal);
+        if(pSettings->FlipDisplay)
+        {
+            tXc1->WindowX0 = 0;
+
+        }
         GFX_write_string(&FontT42,tXc1,text,0);
         break;
     }
 
     tXc1->WindowX0 = tempWinX0;
+    tXc1->WindowX1 = tempWinX1;
     tXc1->WindowY0 = tempWinY0;
 
 }
@@ -609,30 +665,61 @@
     uint16_t tempWinY0;
     uint16_t tempWinY1;
     uint16_t tempWinC2X0;
+    uint16_t tempWinC2Y0;
+    uint16_t tempWinC2X1;
+    uint16_t tempWinC2Y1;
     uint16_t tempWinC2Tab;
 
     tempWinX0 = tXc1->WindowX0;
     tempWinY0 = tXc1->WindowY0;
+
     tempWinC2X0  = tXc2->WindowX0;
+    tempWinC2Y0 = tXc2->WindowY0;
+    tempWinC2X1  = tXc2->WindowX1;
+    tempWinC2Y1 = tXc2->WindowY1;
     tempWinC2Tab = tXc2->WindowTab;
 
     switch(tX_selection_customview)
     {
     case CVIEW_T3_ApnoeSurfaceInfo:
         snprintf(text,TEXTSIZE,"\032\f%c",TXT_MaxDepth);
-        GFX_write_string(&FontT42,tXc1,text,0);
 
-        tXc1->WindowY0 = 100; // obere Zeile
+        if(!pSettings->FlipDisplay)
+        {
+	        GFX_write_string(&FontT42,tXc1,text,0);
+        	tXc1->WindowY0 = 100;
+        }
+        else
+        {
+	        GFX_write_string(&FontT42,tXc2,text,0);
+        	tXc2->WindowY1 -= 100; /* jump to upper of two lines */
+        }
 
         snprintf(text,TEXTSIZE,"\020\016%01.1f",unit_depth_float(stateUsed->lifeData.apnea_last_max_depth_meter));
         t3_basics_colorscheme_mod(text);
-        GFX_write_string(&FontT105,tXc1,text,0);
+        
+        if(!pSettings->FlipDisplay)
+        {
+	        GFX_write_string(&FontT105,tXc1,text,0);
+        	tXc1->WindowY0 = tempWinY0;
+        }
+        else
+        {
+	        GFX_write_string(&FontT105,tXc2,text,0);
+        	tXc2->WindowY1 = tempWinC2Y1; /* jump to upper of two lines */
+        }
 
-        tXc1->WindowY0 = tempWinY0; // wieder unten
 
         snprintf(text,TEXTSIZE,"\020\016%01.1f",unit_depth_float(stateUsed->lifeData.apnea_total_max_depth_meter));
         t3_basics_colorscheme_mod(text);
-        GFX_write_string(&FontT105,tXc1,text,0);
+        if(!pSettings->FlipDisplay)
+        {
+		    GFX_write_string(&FontT105,tXc1,text,0);
+        }
+        else
+        {
+	        GFX_write_string(&FontT105,tXc2,text,0);
+        }
         break;
 
     case CVIEW_T3_StopWatch:
@@ -695,10 +782,14 @@
         textpointer = 0;
         tempWinC2X0 = tXc2->WindowX0;
         tempWinC2Tab = tXc2->WindowTab;
-
         tXc2->WindowX0 = 0;
         tXc2->WindowTab = 800/2;
 
+        if(pSettings->FlipDisplay)
+        {
+        	tXc2->WindowY1 = 0;
+        }
+
         pGasLine = settingsGetPointer()->gas;
         if(actualLeftMaxDepth(stateUsed))
             fPpO2limitHigh = (float)(settingsGetPointer()->ppO2_max_deco) / 100;
@@ -839,10 +930,38 @@
 
     case CVIEW_T3_MaxDepth:
         snprintf(text,TEXTSIZE,"\032\f%c",TXT_MaxDepth);
-        GFX_write_string(&FontT42,tXc1,text,0);
+        if(pSettings->FlipDisplay)
+        {
+        	if(mode == DIVEMODE_Apnea)
+        	{
+        		GFX_write_string(&FontT42,tXc2,text,0);
+        	}
+        	else
+        	{
+        		GFX_write_string(&FontT42,tXc1,text,0);
+        	}
+        }
+        else
+        {
+        	GFX_write_string(&FontT42,tXc1,text,0);
+        }
         snprintf(text,TEXTSIZE,"\020\003\016%01.1f",unit_depth_float(stateUsed->lifeData.max_depth_meter));
         t3_basics_colorscheme_mod(text);
-        GFX_write_string(&FontT105,tXc1,text,1);
+        if(pSettings->FlipDisplay)
+        {
+        	if(mode == DIVEMODE_Apnea)
+        	{
+        		GFX_write_string(&FontT105,tXc2,text,0);
+        	}
+        	else
+        	{
+        		GFX_write_string(&FontT105,tXc1,text,0);
+        	}
+        }
+        else
+        {
+        	GFX_write_string(&FontT105,tXc1,text,1);
+        }
         break;
 
     case CVIEW_T3_TTS:
@@ -881,7 +1000,11 @@
     }
     tXc1->WindowX0 = tempWinX0;
     tXc1->WindowY0 = tempWinY0;
+
     tXc2->WindowX0 = tempWinC2X0;
+    tXc2->WindowY0 = tempWinC2Y0;
+    tXc2->WindowX1 = tempWinC2X1;
+    tXc2->WindowY1 = tempWinC2Y1;
     tXc2->WindowTab = tempWinC2Tab;
 }
 
--- a/Discovery/Src/t5_gauge.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/t5_gauge.c	Wed Jan 15 10:53:15 2020 +0000
@@ -95,6 +95,9 @@
 
 void t5_init(void)
 {
+	SSettings* pSettings;
+	pSettings = settingsGetPointer();
+
     t5_selection_customview = t5_customviewsStandard[0];
 
     t5screen.FBStartAdress = 0;
@@ -105,18 +108,36 @@
     t5l1.Image = &t5screen;
     t5l1.WindowNumberOfTextLines = 2;
     t5l1.WindowLineSpacing = 19; // Abstand von Y0
-    t5l1.WindowTab = 100;
-    t5l1.WindowX0 = 0;
-    t5l1.WindowX1 = BigFontSeperationLeftRight - 5;
-    t5l1.WindowY0 = BigFontSeperationTopBottom + 5;
-    t5l1.WindowY1 = 479;
+	t5l1.WindowTab = 100;
+    if(!pSettings->FlipDisplay)
+    {
+		t5l1.WindowX0 = 0;
+		t5l1.WindowX1 = BigFontSeperationLeftRight - 5;
+		t5l1.WindowY0 = BigFontSeperationTopBottom + 5;
+		t5l1.WindowY1 = 479;
+    }
+    else
+    {
+		t5l1.WindowX0 = 800 - BigFontSeperationLeftRight + 5;
+		t5l1.WindowX1 = 799;
+		t5l1.WindowY0 = 0;
+		t5l1.WindowY1 = 479 - BigFontSeperationTopBottom + 5 ;
+    }
 
     t5r1.Image = &t5screen;
     t5r1.WindowNumberOfTextLines = t5l1.WindowNumberOfTextLines;
     t5r1.WindowLineSpacing = t5l1.WindowLineSpacing;
     t5r1.WindowTab = t5l1.WindowTab;
-    t5r1.WindowX0 = BigFontSeperationLeftRight + 5;
-    t5r1.WindowX1 = 799;
+    if(!pSettings->FlipDisplay)
+    {
+		t5r1.WindowX0 = BigFontSeperationLeftRight + 5;
+		t5r1.WindowX1 = 799;
+    }
+    else
+    {
+		t5r1.WindowX0 = 0;
+		t5r1.WindowX1 = BigFontSeperationLeftRight - 5;
+    }
     t5r1.WindowY0 = t5l1.WindowY0;
     t5r1.WindowY1 = t5l1.WindowY1;
 
@@ -125,8 +146,16 @@
     t5c1.WindowLineSpacing = t5l1.WindowLineSpacing;
     t5c1.WindowX0 = 0;
     t5c1.WindowX1 = 799;
-    t5c1.WindowY0 = 0;
-    t5c1.WindowY1 = BigFontSeperationTopBottom - 5;
+    if(!pSettings->FlipDisplay)
+    {
+    	t5c1.WindowY0 = 0;
+    	t5c1.WindowY1 = BigFontSeperationTopBottom - 5;
+    }
+	else
+	{
+		t5c1.WindowY0 = 480 - BigFontSeperationTopBottom + 5;
+		t5c1.WindowY1 = 479;
+	}
 
     t5c2.Image = &t5screen;
     t5c2.WindowNumberOfTextLines = 3;
@@ -143,8 +172,16 @@
     t5c3.WindowTab = 100;
     t5c3.WindowX0 = CUSTOMBOX_LINE_LEFT + CUSTOMBOX_INSIDE_OFFSET;
     t5c3.WindowX1 = CUSTOMBOX_LINE_RIGHT - CUSTOMBOX_INSIDE_OFFSET;
-    t5c3.WindowY0 = 0;
-    t5c3.WindowY1 = 69;
+    if(!pSettings->FlipDisplay)
+    {
+    	t5c3.WindowY0 = 0;
+    	t5c3.WindowY1 = 69;
+    }
+    else
+    {
+    	t5c3.WindowY0 = 480 - 69;
+    	t5c3.WindowY1 = 479;
+    }
 }
 
 
--- a/Discovery/Src/t6_apnea.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/t6_apnea.c	Wed Jan 15 10:53:15 2020 +0000
@@ -88,6 +88,8 @@
 
 void t6_init(void)
 {
+	SSettings* pSettings;
+	pSettings = settingsGetPointer();
     t6_selection_customview = t6_customviewsStandard[0];
 
     t6screen.FBStartAdress = 0;
@@ -99,17 +101,35 @@
     t6l1.WindowNumberOfTextLines = 2;
     t6l1.WindowLineSpacing = 19; // Abstand von Y0
     t6l1.WindowTab = 100;
-    t6l1.WindowX0 = 0;
-    t6l1.WindowX1 = BigFontSeperationLeftRight - 5;
-    t6l1.WindowY0 = BigFontSeperationTopBottom + 5;
-    t6l1.WindowY1 = 479;
+    if(!pSettings->FlipDisplay)
+    {
+    	t6l1.WindowX0 = 0;
+    	t6l1.WindowX1 = BigFontSeperationLeftRight - 5;
+    	t6l1.WindowY0 = BigFontSeperationTopBottom + 5;
+    	t6l1.WindowY1 = 479;
+    }
+    else
+    {
+    	t6l1.WindowX0 = 800 - BigFontSeperationLeftRight + 5;
+    	t6l1.WindowX1 = 799;
+    	t6l1.WindowY0 = 0;
+    	t6l1.WindowY1 = 479 - BigFontSeperationTopBottom + 5 ;
+    }
 
     t6r1.Image = &t6screen;
     t6r1.WindowNumberOfTextLines = t6l1.WindowNumberOfTextLines;
     t6r1.WindowLineSpacing = t6l1.WindowLineSpacing;
     t6r1.WindowTab = t6l1.WindowTab;
-    t6r1.WindowX0 = BigFontSeperationLeftRight + 5;
-    t6r1.WindowX1 = 799;
+    if(!pSettings->FlipDisplay)
+    {
+    	t6r1.WindowX0 = BigFontSeperationLeftRight + 5;
+    	t6r1.WindowX1 = 799;
+    }
+    else
+    {
+    	t6r1.WindowX0 = 0;
+    	t6r1.WindowX1 = BigFontSeperationLeftRight - 5;
+    }
     t6r1.WindowY0 = t6l1.WindowY0;
     t6r1.WindowY1 = t6l1.WindowY1;
 
@@ -118,16 +138,36 @@
     t6c1.WindowLineSpacing = t6l1.WindowLineSpacing;
     t6c1.WindowX0 = 0;
     t6c1.WindowX1 = 799;
-    t6c1.WindowY0 = 0;
-    t6c1.WindowY1 = BigFontSeperationTopBottom - 5;
+    if(!pSettings->FlipDisplay)
+    {
+    	t6c1.WindowY0 = 0;
+    	t6c1.WindowY1 = BigFontSeperationTopBottom - 5;
+    }
+	else
+	{
+		t6c1.WindowY0 = 480 - BigFontSeperationTopBottom + 5;
+		t6c1.WindowY1 = 479;
+	   	t6c1.WindowX0 = 0;
+	    t6c1.WindowX1 = BigFontSeperationLeftRight - 5;
+	}
 
     t6c2.Image = &t6screen;
     t6c2.WindowNumberOfTextLines = 3;
     t6c2.WindowLineSpacing = 58;
     t6c2.WindowX0 = 370;
     t6c2.WindowX1 = 799;
-    t6c2.WindowY0 = 0;
-    t6c2.WindowY1 = BigFontSeperationTopBottom - 5;
+
+    if(!pSettings->FlipDisplay)
+    {
+    	t6c2.WindowY0 = 0;
+    	t6c2.WindowY1 = BigFontSeperationTopBottom - 5;
+    }
+	else
+	{
+		t6c2.WindowY0 = 480 - BigFontSeperationTopBottom + 5;
+		t6c2.WindowY1 = 479;
+	}
+
     t6c2.WindowTab = 600;
 
     t6c3.Image = &t6screen;
@@ -136,8 +176,16 @@
     t6c3.WindowTab = 100;
     t6c3.WindowX0 = CUSTOMBOX_LINE_LEFT + CUSTOMBOX_INSIDE_OFFSET;
     t6c3.WindowX1 = CUSTOMBOX_LINE_RIGHT - CUSTOMBOX_INSIDE_OFFSET;
-    t6c3.WindowY0 = 0;
-    t6c3.WindowY1 = 69;
+    if(!pSettings->FlipDisplay)
+    {
+    	t6c3.WindowY0 = 0;
+    	t6c3.WindowY1 = 69;
+    }
+    else
+    {
+    	t6c3.WindowY0 = 480 - 69;
+    	t6c3.WindowY1 = 479;
+    }
 }
 
 
--- a/Discovery/Src/t7.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/t7.c	Wed Jan 15 10:53:15 2020 +0000
@@ -48,6 +48,7 @@
 void t7_refresh_sleep_design_fun(void);
 void t7_refresh_divemode_userselected_left_lower_corner(void);
 void t7_refresh_customview(void);
+uint8_t t7_customview_disabled(uint8_t view);
 
 void draw_frame(_Bool PluginBoxHeader, _Bool LinesOnTheSides, uint8_t colorBox, uint8_t colorLinesOnTheSide);
 
@@ -1491,9 +1492,31 @@
     return enabledViewCnt;
 }
 
+uint8_t t7_customview_disabled(uint8_t view)
+{
+	uint8_t i = 0;
+	uint8_t cv_disabled = 0;
+
+   	while(cv_changelist[i] != CVIEW_END)
+    {
+         if((view == cv_changelist[i]) && !CHECK_BIT_THOME(settingsGetPointer()->cv_configuration, cv_changelist[i]))
+         {
+        	 cv_disabled = 1;
+               break;
+         }
+         i++;
+    }
+
+    if (((view == CVIEW_sensors) || (view == CVIEW_sensors_mV)) &&
+       	((stateUsed->diveSettings.ppo2sensors_deactivated) || (stateUsed->diveSettings.ccrOption == 0)))
+    {
+      	cv_disabled = 1;
+    }
+    return cv_disabled;
+}
+
 void t7_change_customview(uint8_t action)
 {
-	int8_t i;
     uint8_t *pViews;
     uint8_t *pStartView,*pCurView, *pLastView;
     _Bool cv_disabled = 0;
@@ -1540,24 +1563,7 @@
 
     do
     {
-        cv_disabled = 0;
-        i=0;
-       	while(cv_changelist[i] != CVIEW_END)
-        {
-             if((*pViews == cv_changelist[i]) && !CHECK_BIT_THOME(settingsGetPointer()->cv_configuration, cv_changelist[i]))
-             {
-            	 cv_disabled = 1;
-                   break;
-             }
-             i++;
-        }
-
-        if (((*pViews == CVIEW_sensors) || (*pViews == CVIEW_sensors_mV)) &&
-           	((stateUsed->diveSettings.ppo2sensors_deactivated) || (stateUsed->diveSettings.ccrOption == 0)))
-        {
-	      	cv_disabled = 1;
-        }
-
+    	cv_disabled = t7_customview_disabled(*pViews);
         if(cv_disabled)		/* view is disabled => jump to next view */
         {
           	if((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_POS))
@@ -1598,6 +1604,7 @@
 
 void t7_refresh_customview(void)
 {
+	static uint8_t last_customview = CVIEW_END;
 
     char text[256];
     uint16_t textpointer = 0;
@@ -1614,13 +1621,13 @@
 	SSettings* pSettings;
 	pSettings = settingsGetPointer();
 
-    if((selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview(ACTION_BUTTON_ENTER);
-    if((selection_customview == CVIEW_sensors_mV) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview(ACTION_BUTTON_ENTER);
-    if((selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview(ACTION_BUTTON_ENTER);
-
+	if(last_customview != selection_customview)		/* check if current selection is disabled and should be skipped */
+	{
+		if(t7_customview_disabled(selection_customview))
+		{
+			t7_change_customview(ACTION_BUTTON_ENTER);
+		}
+	}
     switch(selection_customview)
     {
     case CVIEW_noneOrDebug:
--- a/Discovery/Src/tMenuEditSystem.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Discovery/Src/tMenuEditSystem.c	Wed Jan 15 10:53:15 2020 +0000
@@ -1258,6 +1258,7 @@
         text_content[2] = 0;
         write_label_var(  20, 800, ME_Y_LINE4, &FontT42, text_content);
 
+        translateDate(stateDeviceGetPointer()->voltageMinimum.date_rtc_dr, &Sdate);
         voltage = ((float)stateDeviceGetPointer()->voltageMinimum.value_int32) / 1000;
         snprintf(text_content,80,"%0.3fV (%u.%u.20%02u)",voltage, Sdate.Date,Sdate.Month,Sdate.Year);
         write_label_var(  20, 800, ME_Y_LINE5, &FontT42, text_content);
--- a/Small_CPU/Src/batteryGasGauge.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Small_CPU/Src/batteryGasGauge.c	Wed Jan 15 10:53:15 2020 +0000
@@ -28,7 +28,7 @@
 #include "stm32f4xx_hal.h"
 #include "i2c.h"
 
-static float battery_f_voltage = 0;
+static float battery_f_voltage = 6.0;		/* max assumed voltage */
 static float battery_f_charge_percent = 0;
 
 #define BGG_BATTERY_OFFSET          (26123)  //; 65536-(3,35Ah/0,085mAh)
@@ -117,23 +117,25 @@
 	float battery_f_charge_percent_local;
 	
 	uint8_t bufferReceive[10];
-	I2C_Master_Receive(		DEVICE_BATTERYGAUGE, bufferReceive, 10);
-
-	battery_f_voltage_local =  (float)(bufferReceive[8] * 256);
-	battery_f_voltage_local += (float)(bufferReceive[9]);
-	battery_f_voltage_local *= (float)6 / (float)0xFFFF;
+	
+	if(I2C_Master_Receive(DEVICE_BATTERYGAUGE, bufferReceive, 10) == HAL_OK)
+	{
+		battery_f_voltage_local =  (float)(bufferReceive[8] * 256);
+		battery_f_voltage_local += (float)(bufferReceive[9]);
+		battery_f_voltage_local *= (float)6 / (float)0xFFFF;
+	
+		// max/full: 0.085 mAh * 1 * 65535 = 5570 mAh
+		battery_f_charge_percent_local =  (float)(bufferReceive[2] * 256);
+		battery_f_charge_percent_local += (float)(bufferReceive[3]);
+		battery_f_charge_percent_local -= BGG_BATTERY_OFFSET;
+		battery_f_charge_percent_local /= BGG_BATTERY_DIVIDER;
 
-	// max/full: 0.085 mAh * 1 * 65535 = 5570 mAh
-	battery_f_charge_percent_local =  (float)(bufferReceive[2] * 256);
-	battery_f_charge_percent_local += (float)(bufferReceive[3]);
-	battery_f_charge_percent_local -= BGG_BATTERY_OFFSET;
-	battery_f_charge_percent_local /= BGG_BATTERY_DIVIDER;
-	
-	if(battery_f_charge_percent_local < 0)
-		battery_f_charge_percent_local = 0;
-	
-	battery_f_voltage = battery_f_voltage_local;
-	battery_f_charge_percent = battery_f_charge_percent_local;
+		if(battery_f_charge_percent_local < 0)
+			battery_f_charge_percent_local = 0;
+
+		battery_f_voltage = battery_f_voltage_local;
+		battery_f_charge_percent = battery_f_charge_percent_local;
+	}
 }
 
 
--- a/Small_CPU/Src/compass.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Small_CPU/Src/compass.c	Wed Jan 15 10:53:15 2020 +0000
@@ -39,6 +39,8 @@
 
 #include "stm32f4xx_hal.h"
 
+extern uint32_t time_elapsed_ms(uint32_t ticksstart,uint32_t ticksnow);
+
 /// split byte to bits
 typedef struct{ 
 uint8_t bit0:1; ///< split byte to bits
@@ -1353,61 +1355,51 @@
 //  ===============================================================================
 int compass_calib_common(void)
 {
-		SCompassCalib g;
+	SCompassCalib g;
 
     // Starts with no calibration at all:
-		compass_reset_calibration(&g);
-	
-		int64_t tickstart = 0;
-		uint32_t ticks = 0; 
-		uint32_t lasttick = 0;
-		tickstart = HAL_GetTick();
-    // Eine Minute kalibrieren
-    while((ticks) < 60 * 1000)
+	compass_reset_calibration(&g);
+	uint32_t tickstart = 0;
+	tickstart = HAL_GetTick();
+    /* run calibration for one minute */
+ 	while(time_elapsed_ms(tickstart,HAL_GetTick()) < 60000)
     {
-				compass_read();
-				acceleration_read();
-				compass_calc_roll_pitch_only();
+		while((SPI_Evaluate_RX_Data() == 0) && (time_elapsed_ms(tickstart,HAL_GetTick()) < 60000))
+		{
+			HAL_Delay(1);
+		}
+		compass_read();
+		acceleration_read();
+		compass_calc_roll_pitch_only();
 			
-				if((hardwareCompass == compass_generation1 )		//HMC5883L)
+		if((hardwareCompass == compass_generation1 )		//HMC5883L)
 				&&((compass_DX_f == -4096) ||
-					 (compass_DY_f == -4096) ||
-					 (compass_DZ_f == -4096) ))
-				{
-					if(compass_gain == 0)
-						return -1;
-					compass_gain--;
-				
-					compass_init(1, compass_gain);
-					compass_reset_calibration(&g);
-					//tickstart = HAL_GetTick();
-					continue;
-				}
+				 (compass_DY_f == -4096) ||
+				 (compass_DZ_f == -4096) ))
+		{
+			if(compass_gain == 0)
+				return -1;
+			compass_gain--;
+			compass_init(1, compass_gain);
+			compass_reset_calibration(&g);
+			continue;
+		}
 
-				copyCompassDataDuringCalibration(compass_DX_f,compass_DY_f,compass_DZ_f);
-				compass_add_calibration(&g);
-				HAL_Delay(1);
-				lasttick = HAL_GetTick();
-				if(lasttick == 0)
-				{
-					 tickstart = -ticks;
-				}	
-				HAL_Delay(1);
-				ticks = lasttick - tickstart;
-				SPI_Evaluate_RX_Data();
+		copyCompassDataDuringCalibration(compass_DX_f,compass_DY_f,compass_DZ_f);
+		compass_add_calibration(&g);
     }
         
     compass_solve_calibration(&g);
 		
-		tfull32 dataBlock[4];
-		dataBlock[0].Word16.low16 = compass_CX_f;
-		dataBlock[0].Word16.hi16 = compass_CY_f;
-		dataBlock[1].Word16.low16 = compass_CZ_f;
-		dataBlock[1].Word16.hi16 = 0xFFFF;
-		dataBlock[2].Full32 = 0x7FFFFFFF;
-		dataBlock[3].Full32 = 0x7FFFFFFF;
-		BFA_writeDataBlock((uint32_t *)dataBlock);
+	tfull32 dataBlock[4];
+	dataBlock[0].Word16.low16 = compass_CX_f;
+	dataBlock[0].Word16.hi16 = compass_CY_f;
+	dataBlock[1].Word16.low16 = compass_CZ_f;
+	dataBlock[1].Word16.hi16 = 0xFFFF;
+	dataBlock[2].Full32 = 0x7FFFFFFF;
+	dataBlock[3].Full32 = 0x7FFFFFFF;
+	BFA_writeDataBlock((uint32_t *)dataBlock);
 	
-		return 0;
+	return 0;
 }
 
--- a/Small_CPU/Src/scheduler.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Small_CPU/Src/scheduler.c	Wed Jan 15 10:53:15 2020 +0000
@@ -42,6 +42,8 @@
 #include "decom.h"
 #include "tm_stm32f4_otp.h"
 
+/* uncomment to enable restoting of last known date in case of a power loss (RTC looses timing data) */
+/* #define RESTORE_LAST_KNOWN_DATE */
 
 #define INVALID_PREASURE_VALUE 			(100.0f)
 #define START_DIVE_MOUNTAIN_MODE_BAR	(0.88f)
@@ -1200,6 +1202,41 @@
 }
 
 
+void scheduletranslateDate(uint32_t datetmpreg, RTC_DateTypeDef *sDate)
+{
+  datetmpreg = (uint32_t)(datetmpreg & RTC_DR_RESERVED_MASK);
+
+  /* Fill the structure fields with the read parameters */
+  sDate->Year = (uint8_t)((datetmpreg & (RTC_DR_YT | RTC_DR_YU)) >> 16);
+  sDate->Month = (uint8_t)((datetmpreg & (RTC_DR_MT | RTC_DR_MU)) >> 8);
+  sDate->Date = (uint8_t)(datetmpreg & (RTC_DR_DT | RTC_DR_DU));
+  sDate->WeekDay = (uint8_t)((datetmpreg & (RTC_DR_WDU)) >> 13);
+
+	/* Convert the date structure parameters to Binary format */
+	sDate->Year = (uint8_t)RTC_Bcd2ToByte(sDate->Year);
+	sDate->Month = (uint8_t)RTC_Bcd2ToByte(sDate->Month);
+	sDate->Date = (uint8_t)RTC_Bcd2ToByte(sDate->Date);
+}
+
+void scheduleCheckDate(void)
+{
+	uint32_t localdate;
+	RTC_DateTypeDef sDate;
+	localdate =	(uint32_t)(RTCHandle.Instance->DR & RTC_DR_RESERVED_MASK);
+	scheduletranslateDate(localdate, &sDate);
+
+	/* RTC start in year 2000 in case of a power loss. Use the operation counter time stamp to bring at last date to a more realistic value */
+	if(sDate.Year < 15)
+	{
+		scheduletranslateDate(DeviceDataFlash.hoursOfOperation.date_rtc_dr, &sDate);
+		if(sDate.Year > 16)
+		{
+			RTC_SetDate(sDate);
+		}
+	}
+
+}
+
 void scheduleUpdateDeviceData(void)
 {
 	/* first step, main CPU */
@@ -1207,6 +1244,13 @@
 	if(deviceDataFlashValid)
 	{
 		/* max values */
+		if(global.deviceData.hoursOfOperation.value_int32 < DeviceDataFlash.hoursOfOperation.value_int32)
+		{
+			scheduleCopyDeviceData(&global.deviceData.hoursOfOperation, &DeviceDataFlash.hoursOfOperation);
+#ifdef RESTORE_LAST_KNOWN_DATE
+			scheduleCheckDate();
+#endif
+		}
 		if(global.deviceData.batteryChargeCompleteCycles.value_int32 < DeviceDataFlash.batteryChargeCompleteCycles.value_int32)
 		{
 			scheduleCopyDeviceData(&global.deviceData.batteryChargeCompleteCycles, &DeviceDataFlash.batteryChargeCompleteCycles);
@@ -1227,10 +1271,6 @@
 		{
 			scheduleCopyDeviceData(&global.deviceData.diveCycles, &DeviceDataFlash.diveCycles);
 		}
-		if(global.deviceData.hoursOfOperation.value_int32 < DeviceDataFlash.hoursOfOperation.value_int32)
-		{
-			scheduleCopyDeviceData(&global.deviceData.hoursOfOperation, &DeviceDataFlash.hoursOfOperation);
-		}
 		
 		/* min values */
 		if(global.deviceData.temperatureMinimum.value_int32 > DeviceDataFlash.temperatureMinimum.value_int32)
@@ -1286,6 +1326,7 @@
 			{
 				deviceDataSubSeconds = 0;
 				global.deviceData.hoursOfOperation.value_int32++;
+				scheduleSetDate(&global.deviceData.hoursOfOperation);
 			}
 			break;
 
--- a/Small_CPU/Src/spi.c	Wed Jan 08 15:35:15 2020 +0100
+++ b/Small_CPU/Src/spi.c	Wed Jan 15 10:53:15 2020 +0000
@@ -24,6 +24,8 @@
 #include "global_constants.h"
 #include "spi.h"
 #include "dma.h"
+#include "batteryGasGauge.h"
+#include "pressure.h"
 
 //#include "gpio.h"
 
@@ -298,13 +300,29 @@
 }
 
 void SPI_Start_single_TxRx_with_Master(void) {
+	static uint8_t DevicedataDelayCnt = 10;
+	static uint8_t DeviceDataPending = 0;
 	uint8_t * pOutput;
 	HAL_StatusTypeDef retval;
 
-	if (global.dataSendToSlave.getDeviceDataNow) {
-		global.dataSendToSlave.getDeviceDataNow = 0;
-		pOutput = (uint8_t*) &(global.deviceDataSendToMaster);
-	} else {
+	if ((global.dataSendToSlave.getDeviceDataNow) || (DeviceDataPending))
+	{
+		if(((DevicedataDelayCnt == 0) || (((get_voltage() != 6.0) && (get_temperature() != 0.0)))))			/* devicedata complete? */
+		{
+			global.dataSendToSlave.getDeviceDataNow = 0;
+			DeviceDataPending = 0;
+			pOutput = (uint8_t*) &(global.deviceDataSendToMaster);
+		}
+		else
+		{
+			DeviceDataPending = 1;
+			DevicedataDelayCnt--;
+			pOutput = (uint8_t*) &(global.dataSendToMaster);
+		}
+
+	}
+	else
+	{
 		pOutput = (uint8_t*) &(global.dataSendToMaster);
 	}
 	retval = HAL_SPI_TransmitReceive_DMA(&hspi1, pOutput,(uint8_t*) &(global.dataSendToSlave), EXCHANGE_BUFFERSIZE);