changeset 430:30580cf5ee77

Merged in Ideenmodellierer/ostc4/ImprovmentNVM_2 (pull request #39) ImprovmentNVM 2
author heinrichsweikamp <bitbucket@heinrichsweikamp.com>
date Tue, 18 Feb 2020 07:20:29 +0000
parents c2264ce139cb (current diff) 7f351c25608a (diff)
children 49c3c5f0d0cb
files
diffstat 10 files changed, 500 insertions(+), 206 deletions(-) [+]
line wrap: on
line diff
--- a/Discovery/Inc/externLogbookFlash.h	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Inc/externLogbookFlash.h	Tue Feb 18 07:20:29 2020 +0000
@@ -59,18 +59,18 @@
  */
 #define SETTINGSSTART	0x00010000
 #define SETTINGSSTOP 	0x0001FFFF
-#define VPMSTART			0x00020000
-#define VPMSTOP				0x0002FFFF
+#define VPMSTART		0x00020000
+#define VPMSTOP			0x0002FFFF
 #define unused3START	0x00030000
 #define unused3STOP		0x0007FFFF
 #define HEADERSTART		0x00080000
 #define HEADERSTOP		0x000FFFFF
 #define SAMPLESTART		0x00100000
 #define SAMPLESTOP		0x00CFFFFF
-#define FWSTART				0x00D00000
-#define FWSTOP				0x00DFFFFF
-#define FWSTART2			0x00E00000
-#define FWSTOP2				0x00FFFFFF
+#define FWSTART			0x00D00000
+#define FWSTOP			0x00DFFFFF
+#define FWSTART2		0x00E00000
+#define FWSTOP2			0x00FFFFFF
 /* 16 MB with 4 Byte addressing */
 #define unused4START	0x01000000
 #define unused4STOP		0x01FFFFFF
@@ -78,6 +78,12 @@
 #define HEADERSIZE sizeof(SLogbookHeader)
 #define HEADERSIZEOSTC3 sizeof(SLogbookHeaderOSTC3)
 
+/* Sample ring buffer sector states derived from the usage at begin and end of a sector */
+#define SECTOR_CLOSED		(0)
+#define SECTOR_NOTUSED		(1)
+#define SECTOR_INUSE		(4)
+#define SECTOR_EMPTY		(5)
+
 /* Exported types ------------------------------------------------------------*/
 typedef struct{
 uint8_t byteLow;
@@ -102,10 +108,10 @@
 } convert16_Type;
 
 /* Exported functions --------------------------------------------------------*/
-void ext_flash_write_settings(void);
+void ext_flash_write_settings(uint8_t resetRing);
 uint8_t ext_flash_read_settings(void);
 
-void ext_flash_write_devicedata(void);
+void ext_flash_write_devicedata(uint8_t resetRing);
 uint16_t ext_flash_read_devicedata(uint8_t *buffer, uint16_t max_length);
 void ext_flash_read_fixed_16_devicedata_blocks_formated_128byte_total(uint8_t *buffer);
 
@@ -157,4 +163,7 @@
 
 uint16_t ext_flash_repair_SPECIAL_dive_numbers_starting_count_with(uint16_t startCount);
 
+uint32_t ext_flash_AnalyseSampleBuffer(char *pstrResult);
+void ext_flash_CloseSector(void);
+
 #endif /* EXTERN_LOGBOOK_FLASH_H */
--- a/Discovery/Inc/tStructure.h	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Inc/tStructure.h	Tue Feb 18 07:20:29 2020 +0000
@@ -290,19 +290,19 @@
 #define StMSYS5_Info		_MB(2,8,5,1,0)
 
 
-#define StMSYS6_Exit					_MB(2,8,6,1,0)
+#define StMSYS6_Exit			_MB(2,8,6,1,0)
 #define StMSYS6_LogbookOffset	_MB(2,8,6,7,0)
-#define StMSYS6_ResetAll			_MB(2,8,6,2,0)
-#define StMSYS6_ResetDeco			_MB(2,8,6,3,0)
-#define StMSYS6_Reboot				_MB(2,8,6,4,0)
+#define StMSYS6_ResetAll		_MB(2,8,6,2,0)
+#define StMSYS6_ResetDeco		_MB(2,8,6,3,0)
+#define StMSYS6_Reboot			_MB(2,8,6,4,0)
 #define StMSYS6_Maintenance		_MB(2,8,6,5,0)
 #define StMSYS6_ResetLogbook	_MB(2,8,6,6,0)
 #define StMSYS6_SetBattCharge	_MB(2,8,6,7,0)
-#define StMSYS6_RebootRTE			_MB(2,8,6,8,0)
+#define StMSYS6_RebootRTE		_MB(2,8,6,8,0)
 #define StMSYS6_RebootMainCPU	_MB(2,8,6,9,0)
 #define StMSYS6_ScreenTest		_MB(2,8,6,10,0)
 #define StMSYS6_SetFactoryBC	_MB(2,8,6,11,0)
-
+#define StMSYS6_SetSampleIndx   _MB(2,8,6,12,0)
 
 /* PAGE 9 */
 #define StMPLAN		_MB(2,9,0,0,0)
--- a/Discovery/Inc/text_multilanguage.h	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Inc/text_multilanguage.h	Tue Feb 18 07:20:29 2020 +0000
@@ -288,6 +288,7 @@
 		TXT2BYTE_Maintenance,
 		TXT2BYTE_SetBatteryCharge,
 		TXT2BYTE_SetFactoryDefaults,
+		TXT2BYTE_SetSampleIndex,
 		TXT2BYTE_Reboot,
 		TXT2BYTE_ButtonLeft,
 		TXT2BYTE_ButtonMitte,
--- a/Discovery/Src/base.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/base.c	Tue Feb 18 07:20:29 2020 +0000
@@ -230,6 +230,7 @@
 #include "test_vpm.h"
 #include "tDebug.h"
 #include "motion.h"
+#include "data_exchange_main.h"
 
 #ifdef DEMOMODE
 #include "demo.h"
@@ -262,6 +263,8 @@
 TIM_HandleTypeDef   TimDemoHandle; /* used in stm32f4xx_it.c too */
 #endif
 
+static uint8_t RequestModeChange = 0;
+
 static uint8_t LastButtonPressed;
 static uint32_t LastButtonPressedTick;
 static uint32_t BaseTick100ms;			/* Tick at last 100ms cycle */
@@ -300,6 +303,8 @@
 static void TriggerButtonAction(void);
 static void EvaluateButton(void);
 static void RefreshDisplay(void);
+static void TimeoutControlRequestModechange(void);
+static void TimeoutControl(void);
 
 /* ITM Trace-------- ---------------------------------------------------------*/
 /*
@@ -450,7 +455,7 @@
     if( settingsGetPointer()->debugModeOnStart )
     {
         settingsGetPointer()->debugModeOnStart = 0;
-        ext_flash_write_settings();
+        ext_flash_write_settings(0);
         setDebugMode();
         openInfo( StIDEBUG );
     }
@@ -476,14 +481,14 @@
         {
             createDiveSettings();
             updateMenu();
-            ext_flash_write_settings();
+            ext_flash_write_settings(0);
         }
 
         /* check if tasks depending on global state are pending */
         get_globalStateList(&status);
         if(status.base == BaseHome)
         {
-            tMenuEdit_writeSettingsToFlash(); // takes 900 ms!!
+            tMenuEdit_writeSettingsToFlash();
         }
 
         DataEX_merge_devicedata(); 	/* data is exchanged at startup and every 10 minutes => check if something changed */
@@ -495,6 +500,8 @@
 	        DoDisplayRefresh = 0;
         	RefreshDisplay();
 
+        	TimeoutControl();								/* exit menus if needed */
+
         	if(stateUsed->mode == MODE_DIVE)			/* handle motion events in divemode only */
         	{
 				switch(settingsGetPointer()->MotionDetection)
@@ -583,23 +590,11 @@
         return;
     }
 #endif
-    static uint8_t last_base;
-
     SStateList status;
-    uint32_t timeout_in_seconds;
-    uint32_t timeout_limit_Surface_in_seconds;
-
+    _Bool modeChange = 0;
 
     BaseTick100ms = HAL_GetTick();	/* store start of 100ms cycle */
 
-    _Bool InDiveMode = 0;
-    _Bool modeChange = 0; // to exit from menu and logbook
-
-    if(stateUsed->mode == MODE_DIVE)
-        InDiveMode = 1;
-    else
-        InDiveMode = 0;
-
     EvaluateButton();
 
     if(returnFromCommCleanUpRequest)
@@ -652,132 +647,11 @@
         break;
     }
 
-    /* timeout control */
-    if(modeChange) ///< from RTE, set in data_exchange_main.c
-        time_without_button_pressed_deciseconds = (settingsGetPointer()->timeoutSurfacemode / 4) * 3;
-    if(status.base != last_base)
-        time_without_button_pressed_deciseconds = 0;
-    last_base = status.base;
-    timeout_in_seconds = time_without_button_pressed_deciseconds / 10;
-    time_without_button_pressed_deciseconds += 1;
-    if(modeChange || (timeout_in_seconds != time_without_button_pressed_deciseconds / 10))
+    get_globalStateList(&status);
+    if(modeChange)
     {
-#ifdef NO_TIMEOUT
-        timeout_in_seconds = 0;
-#else
-        timeout_in_seconds += 1;
-#endif
-
-        if(InDiveMode)
-        {
-            switch(status.base)
-            {
-            case BaseHome:
-                if((status.line != 0) && (timeout_in_seconds  >= settingsGetPointer()->timeoutEnterButtonSelectDive))
-                {
-                    set_globalState(StD);
-                    timeout_in_seconds = 0;
-                }
-            break;
-
-            case BaseMenu:
-                if((status.line == 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuDive) || modeChange))
-                {
-                    exitMenu();
-                    timeout_in_seconds = 0;
-                }
-                if((status.line != 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuEdit) || modeChange))
-                {
-                    exitMenuEdit_to_Home();
-                    timeout_in_seconds = 0;
-                }
-            break;
-            default:
-                break;
-            }
-        }
-        else /* surface mode */
-        {
-            switch(status.base)
-            {
-            case BaseHome:
-                // added hw 161027
-                if(!(stateRealGetPointer()->warnings.lowBattery) && (stateRealGetPointer()->lifeData.battery_charge > 9))
-                {
-                    stateRealGetPointerWrite()->lastKnownBatteryPercentage = stateRealGetPointer()->lifeData.battery_charge;
-                }
-                else if((wasFirmwareUpdateCheckBattery) && (timeout_in_seconds > 3))
-                {
-                    wasFirmwareUpdateCheckBattery = 0;
-                    setButtonResponsiveness(settingsGetPointer()->ButtonResponsiveness); // added 170306
-                    if(	(settingsGetPointer()->lastKnownBatteryPercentage > 0)
-                    && 	(settingsGetPointer()->lastKnownBatteryPercentage <= 100)
-                    && 	(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))
-                {
-                    timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemodeWithSensors;
-                }
-                else
-                {
-                    timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemode;
-                }
-                if(timeout_in_seconds  >= timeout_limit_Surface_in_seconds)
-                {
-                    gotoSleep();
-                }
-                break;
-            case BaseMenu:
-                if((status.line == 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuSurface) || modeChange))
-                {
-                    exitMenu();
-                    timeout_in_seconds = 0;
-                }
-                if((status.line != 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuEdit) || modeChange))
-                {
-                    if((status.page != (uint8_t)((StMPLAN >> 24) & 0x0F)) || (timeout_in_seconds  >= 10*(settingsGetPointer()->timeoutMenuEdit)))
-                    {
-                        exitMenuEdit_to_Home();
-                        timeout_in_seconds = 0;
-                    }
-                }
-                break;
-
-            case BaseInfo:
-                if((timeout_in_seconds  >= settingsGetPointer()->timeoutInfo) || modeChange)
-                {
-                    if(status.page == InfoPageLogList)
-                    {
-                        exitLog();
-                        timeout_in_seconds = 0;
-                    }
-                    else
-                    if(status.page == InfoPageLogShow)
-                    {
-                        show_logbook_exit();
-                        exitLog();
-                        timeout_in_seconds = 0;
-                    }
-                    else
-                    if(status.page != InfoPageCompass)
-                    {
-                        exitInfo();
-                        timeout_in_seconds = 0;
-                    }
-                }
-                break;
-            default:
-                break;
-            }
-        }
+    	TimeoutControlRequestModechange();
     }
-
-    get_globalStateList(&status);
-
     if(status.base == BaseComm) /* main loop not serviced in com mode */
     {
     	tComm_refresh();
@@ -1045,6 +919,8 @@
     /* not at the moment of testing */
 //	ext_flash_erase_firmware_if_not_empty();
     GFX_logoAutoOff();
+    ext_flash_write_devicedata(true);	/* write data at default position */
+    ext_flash_write_settings(true);		/* write data at default position */
     set_globalState(StStop);
 }
 
@@ -1754,6 +1630,155 @@
     HAL_NVIC_SystemReset();
 }
 
+static void TimeoutControlRequestModechange(void)
+{
+	RequestModeChange = 1;
+}
+
+static void TimeoutControl(void)
+{
+    static uint8_t last_base;
+
+    SStateList status;
+    uint32_t timeout_in_seconds;
+    uint32_t timeout_limit_Surface_in_seconds;
+    _Bool InDiveMode = 0;
+
+    get_globalStateList(&status);
+
+    if(stateUsed->mode == MODE_DIVE)
+    {
+        InDiveMode = 1;
+    }
+    else
+    {
+        InDiveMode = 0;
+    }
+	/* timeout control */
+	if(RequestModeChange) ///< from RTE, set in data_exchange_main.c
+		time_without_button_pressed_deciseconds = (settingsGetPointer()->timeoutSurfacemode / 4) * 3;
+	if(status.base != last_base)
+		time_without_button_pressed_deciseconds = 0;
+	last_base = status.base;
+	timeout_in_seconds = time_without_button_pressed_deciseconds / 10;
+	time_without_button_pressed_deciseconds += 1;
+	if(RequestModeChange || (timeout_in_seconds != time_without_button_pressed_deciseconds / 10))
+	{
+	#ifdef NO_TIMEOUT
+		timeout_in_seconds = 0;
+	#else
+		timeout_in_seconds += 1;
+	#endif
+
+		if(InDiveMode)
+		{
+			switch(status.base)
+			{
+			case BaseHome:
+				if((status.line != 0) && (timeout_in_seconds  >= settingsGetPointer()->timeoutEnterButtonSelectDive))
+				{
+					set_globalState(StD);
+					timeout_in_seconds = 0;
+				}
+			break;
+
+			case BaseMenu:
+				if((status.line == 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuDive) || RequestModeChange))
+				{
+					exitMenu();
+					timeout_in_seconds = 0;
+				}
+				if((status.line != 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuEdit) || RequestModeChange))
+				{
+					exitMenuEdit_to_Home();
+					timeout_in_seconds = 0;
+				}
+			break;
+			default:
+				break;
+			}
+		}
+		else /* surface mode */
+		{
+			switch(status.base)
+			{
+			case BaseHome:
+				// added hw 161027
+				if(!(stateRealGetPointer()->warnings.lowBattery) && (stateRealGetPointer()->lifeData.battery_charge > 9))
+				{
+					stateRealGetPointerWrite()->lastKnownBatteryPercentage = stateRealGetPointer()->lifeData.battery_charge;
+				}
+				else if((wasFirmwareUpdateCheckBattery) && (timeout_in_seconds > 3))
+				{
+					wasFirmwareUpdateCheckBattery = 0;
+					setButtonResponsiveness(settingsGetPointer()->ButtonResponsiveness); // added 170306
+					if(	(settingsGetPointer()->lastKnownBatteryPercentage > 0)
+					&& 	(settingsGetPointer()->lastKnownBatteryPercentage <= 100)
+					&& 	(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))
+				{
+					timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemodeWithSensors;
+				}
+				else
+				{
+					timeout_limit_Surface_in_seconds = settingsGetPointer()->timeoutSurfacemode;
+				}
+				if(timeout_in_seconds  >= timeout_limit_Surface_in_seconds)
+				{
+					gotoSleep();
+				}
+				break;
+			case BaseMenu:
+				if((status.line == 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuSurface) || RequestModeChange))
+				{
+					exitMenu();
+					timeout_in_seconds = 0;
+				}
+				if((status.line != 0) && ((timeout_in_seconds  >= settingsGetPointer()->timeoutMenuEdit) || RequestModeChange))
+				{
+					if((status.page != (uint8_t)((StMPLAN >> 24) & 0x0F)) || (timeout_in_seconds  >= 10*(settingsGetPointer()->timeoutMenuEdit)))
+					{
+						exitMenuEdit_to_Home();
+						timeout_in_seconds = 0;
+					}
+				}
+				break;
+
+			case BaseInfo:
+				if((timeout_in_seconds  >= settingsGetPointer()->timeoutInfo) || RequestModeChange)
+				{
+					if(status.page == InfoPageLogList)
+					{
+						exitLog();
+						timeout_in_seconds = 0;
+					}
+					else
+					if(status.page == InfoPageLogShow)
+					{
+						show_logbook_exit();
+						exitLog();
+						timeout_in_seconds = 0;
+					}
+					else
+					if(status.page != InfoPageCompass)
+					{
+						exitInfo();
+						timeout_in_seconds = 0;
+					}
+				}
+				break;
+			default:
+				break;
+			}
+		}
+	}
+	RequestModeChange = 0;
+}
 // debugging by https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
 
 /*
--- a/Discovery/Src/data_exchange_main.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/data_exchange_main.c	Tue Feb 18 07:20:29 2020 +0000
@@ -640,7 +640,7 @@
 
 	if(dataLengthRead == 0)
 	{
-		ext_flash_write_devicedata();
+		ext_flash_write_devicedata(false);
 		return;
 	}
 
@@ -682,7 +682,7 @@
 	}
 	
 	DataEX_check_DeviceData	();
-	ext_flash_write_devicedata();
+	ext_flash_write_devicedata(false);
 }
 
 
--- a/Discovery/Src/externLogbookFlash.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/externLogbookFlash.c	Tue Feb 18 07:20:29 2020 +0000
@@ -116,14 +116,17 @@
 
 /* Private variables ---------------------------------------------------------*/
 static uint32_t	actualAddress = 0;
+static uint32_t	preparedPageAddress = 0;
+static uint32_t closeSectorAddress = 0;
 static uint32_t	entryPoint = 0;
 
 static uint32_t	actualPointerHeader = 0;
 static uint32_t	actualPointerSample = 0;
 static uint32_t	LengthLeftSampleRead = 0;
-static uint32_t	actualPointerDevicedata = 0;
+static uint32_t	actualPointerDevicedata = DDSTART;
+static uint32_t	actualPointerDevicedata_Read = DDSTART;
 static uint32_t	actualPointerVPM = 0;
-static uint32_t	actualPointerSettings = 0;
+static uint32_t	actualPointerSettings = SETTINGSSTART;
 static uint32_t	actualPointerFirmware = 0;
 static uint32_t	actualPointerFirmware2 = 0;
 
@@ -392,18 +395,24 @@
 
 #ifndef BOOTLOADER_STANDALONE
 
-void ext_flash_write_devicedata(void)
+void ext_flash_write_devicedata(uint8_t resetRing)
 {
 	uint8_t *pData;
 	const uint16_t length = sizeof(SDevice);
 	uint8_t length_lo, length_hi;
 	uint8_t dataLength[2] = { 0 };
+	uint32_t tmpBlockStart;
 
 	ext_flash_disable_protection();
 
 	pData = (uint8_t *)stateDeviceGetPointer();
 
-	actualPointerDevicedata = DDSTART;
+	/* Reset the Ring to the start address if requested (e.g. because we write the default block during shutdown) */
+	if((resetRing) || ((actualPointerDevicedata + length) >= DDSTOP))
+	{
+		actualPointerDevicedata = DDSTART;
+	}
+	tmpBlockStart = actualPointerDevicedata;
 
 	length_lo = (uint8_t)(length & 0xFF);
 	length_hi = (uint8_t)(length >> 8);
@@ -412,6 +421,9 @@
 
 	ef_write_block(dataLength,2, EF_DEVICEDATA, 0);
 	ef_write_block(pData,length, EF_DEVICEDATA, 0);
+
+	actualPointerDevicedata_Read = tmpBlockStart;
+
 }
 
 
@@ -420,20 +432,37 @@
 	uint16_t length;
 	uint8_t length_lo, length_hi;
 
-	actualAddress = DDSTART;
+	actualAddress = actualPointerDevicedata_Read; 
 
+	length = 0;
+	length_lo = 0;
+	length_hi = 0;
 	ext_flash_read_block_start();
+
+
 	ext_flash_read_block(&length_lo, EF_DEVICEDATA);
 	ext_flash_read_block(&length_hi, EF_DEVICEDATA);
 	
-	length = (length_hi * 256) + length_lo;
-	
-	if(length > max_length)
-		return 0;
-	
-	ext_flash_read_block_multi(buffer,length,EF_DEVICEDATA);
+	while ((length_lo != 0xFF) && (length_hi != 0xFF))
+	{
+		length = (length_hi * 256) + length_lo;
+
+		if(length > max_length)
+			return 0;
+
+		ext_flash_read_block_multi(buffer,length,EF_DEVICEDATA);
+
+		ext_flash_read_block(&length_lo, EF_DEVICEDATA);	/* check if another devicedata set is available */
+		ext_flash_read_block(&length_hi, EF_DEVICEDATA);	/* length will be 0xFFFF if a empty memory is read */
+	}
+	ext_flash_decf_address_ring(EF_DEVICEDATA);				/* set pointer back to empty address */
+	ext_flash_decf_address_ring(EF_DEVICEDATA);
 	ext_flash_read_block_stop();
-	
+
+	if(actualAddress > actualPointerDevicedata)				/* the write pointer has not yet been set up probably */
+	{
+		actualPointerDevicedata = actualAddress;
+	}
 	return length;
 }
 
@@ -493,7 +522,7 @@
 	return;
 }
 #else
-void ext_flash_write_settings(void)
+void ext_flash_write_settings(uint8_t resetRing)
 {
 	uint8_t *pData;
 	const uint16_t length = sizeof(SSettings);
@@ -511,7 +540,11 @@
 
 	pData = (uint8_t *)settingsGetPointer();
 
-	actualPointerSettings = SETTINGSSTART;
+	/* Reset the Ring to the start address if requested (e.g. because we write the default block during shutdown) */
+	if((resetRing) || ((actualPointerSettings + length) >= SETTINGSSTOP))
+	{
+		actualPointerSettings = SETTINGSSTART;
+	}
 
 	length_lo = (uint8_t)(length & 0xFF);
 	length_hi = (uint8_t)(length >> 8);
@@ -548,23 +581,36 @@
 	ext_flash_read_block(&length_lo, EF_SETTINGS);
 	ext_flash_read_block(&length_hi, EF_SETTINGS);
 	
-	lengthOnEEPROM = length_hi * 256;
-	lengthOnEEPROM += length_lo;
-	if(lengthOnEEPROM <= lengthStandardNow)
+	while ((length_lo != 0xFF) && (length_hi != 0xFF))		/* get the latest stored setting block */
 	{
-		ext_flash_read_block_multi(&header, 4, EF_SETTINGS);
-		if((header <= pSettings->header) && (header >= pSettings->updateSettingsAllowedFromHeader))
+		lengthOnEEPROM = length_hi * 256;
+		lengthOnEEPROM += length_lo;
+		if(lengthOnEEPROM <= lengthStandardNow)
 		{
-			returnValue = HAL_OK;
-			pSettings->header = header;
-			pData = (uint8_t *)pSettings + 4; /* header */
-			for(uint16_t i = 0; i < (lengthOnEEPROM-4); i++)
-				ext_flash_read_block(&pData[i], EF_SETTINGS);
+			ext_flash_read_block_multi(&header, 4, EF_SETTINGS);
+			if((header <= pSettings->header) && (header >= pSettings->updateSettingsAllowedFromHeader))
+			{
+				returnValue = HAL_OK;
+				pSettings->header = header;
+				pData = (uint8_t *)pSettings + 4; /* header */
+				for(uint16_t i = 0; i < (lengthOnEEPROM-4); i++)
+					ext_flash_read_block(&pData[i], EF_SETTINGS);
+			}
+			else
+			{
+				returnValue = HAL_ERROR;
+			}
 		}
-		else
-		{
-			returnValue = HAL_ERROR;
-		}
+		ext_flash_read_block(&length_lo, EF_SETTINGS);
+		ext_flash_read_block(&length_hi, EF_SETTINGS);
+	}
+	ext_flash_decf_address_ring(EF_SETTINGS);				/* set pointer back to empty address */
+	ext_flash_decf_address_ring(EF_SETTINGS);
+	ext_flash_read_block_stop();
+
+	if(actualAddress > actualPointerSettings)				/* the write pointer has not yet been set up probably */
+	{
+		actualPointerSettings = actualAddress;
 	}
 	ext_flash_read_block_stop();
 	return returnValue;
@@ -614,7 +660,7 @@
 void ext_flash_create_new_dive_log(uint8_t *pHeaderPreDive)
 {
 	SSettings *settings;
-	uint8_t id, id_next;
+	uint8_t id;
 	uint8_t  header1, header2;
 
 	settings = settingsGetPointer();
@@ -622,10 +668,12 @@
 
 	actualAddress = HEADERSTART + (0x800 * id);
 	ext_flash_read_block_start();
-	ext_flash_read_block(&header1, EF_SAMPLE);
-	ext_flash_read_block(&header2, EF_SAMPLE);
+	ext_flash_read_block(&header1, EF_SAMPLE); /* the sample ring is increased instead of header... not sure if that is planned intention */
+	ext_flash_read_block(&header2, EF_SAMPLE); /* does not matter because actual address is reset in write_block call */
 	ext_flash_read_block_stop();
 
+	/* TODO Cleanup_Ref_2: The code below should not be necessary in case of a proper shutdown and startup */
+	/* the implementation fixes an issue which might happen at Cleanup_Ref_1 (in case of more then 254 dives) */
 	if((header1 == 0xFA) && (header2 == 0xFA))
 	{
 		id += 1; /* 0-255, auto rollover */
@@ -645,11 +693,6 @@
 		id = 0;
 	}
 
-	/* delete next header */
-	id_next = id + 1;
-	actualPointerHeader = HEADERSTART + (0x800 * id_next);
-	ef_write_block(0,0, EF_HEADER, 0);
-
 	settings->lastDiveLogId = id;
 	actualPointerHeader = HEADERSTART + (0x800 * id);
 
@@ -726,10 +769,28 @@
 
 void ext_flash_write_sample(uint8_t *pSample, uint16_t length)
 {
+	uint32_t actualAdressBackup = 0;
+
 	ef_write_block(pSample,length, EF_SAMPLE, 0);
 
 	SSettings *settings = settingsGetPointer();
 	settings->logFlashNextSampleStartAddress = actualPointerSample;
+
+	if(0xFFFF - (actualAddress & 0x0000FFFF) < 255)								/* are we close to a sector border? */
+	{
+		if (((actualAddress & 0x0000FFFF) != 0) && (preparedPageAddress == 0))		/* only prepare if not already at start of sector */
+		{
+			actualAdressBackup = actualAddress;
+			actualAddress = (actualAddress & 0xFFFF0000) + 0x00010000;	/* Set to start of next 64k sector */
+			if(actualAddress >= SAMPLESTOP)
+			{
+				actualAddress = SAMPLESTART;
+			}
+			preparedPageAddress = actualAddress;
+			ext_flash_erase64kB();
+			actualAddress = actualAdressBackup;
+		}
+	}
 }
 
 static void ext_flash_overwrite_sample_without_erase(uint8_t *pSample, uint16_t length)
@@ -1316,16 +1377,16 @@
     ext_flash_read_block(&dataStart.u8bit.byteMidLow, EF_HEADER);
     ext_flash_read_block(&dataStart.u8bit.byteMidHigh, EF_HEADER);
     ext_flash_read_block_stop();
-    if((header1 == 0xFA) && (header2 == 0xFA))
+    if((header1 == 0xFA) && (header2 == 0xFA))						/* Header is indicating the start of a dive */
     {
       actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET;
       ext_flash_read_block_start();
       ext_flash_read_block(&header1, EF_HEADER);
       ext_flash_read_block(&header2, EF_HEADER);
       ext_flash_read_block_stop();
-      if((header1 != 0xFA) || (header2 != 0xFA))
+      if((header1 != 0xFA) || (header2 != 0xFA))					/* Secondary header was not written at the end of a dive */
       {
-        actualPointerSample = dataStart.u32bit;
+        actualPointerSample = dataStart.u32bit;						/* Set datapointer to position stored in header written at beginning of dive */
         actualAddress = actualPointerSample;
         logbook_recover_brokenlog(id);
         SSettings *settings = settingsGetPointer();
@@ -1343,6 +1404,9 @@
 	uint8_t  header1, header2;
   convert_Type dataStart, dataEnd;
 
+  /* TODO Cleanup_Ref_1: cleanup logFlashNextSampleStartAddress and lastDiveLogId */
+  /* The implementation below would cause problems in case more then 254 dives would be done. */
+  /* This is avoided by Cleanup_Ref2 */
   for(id = 0; id < 255;id++)
   {
     actualAddress = HEADERSTART + (0x800 * id) + HEADER2OFFSET;
@@ -1578,7 +1642,7 @@
 			ext_flash_erase4kB();
 			return 1;
 		}
-	}		
+	}
 	else
 	if(actualAddress < 0x00010000)
 	{
@@ -1588,16 +1652,25 @@
 			ext_flash_erase32kB();
 			return 1;
 		}
-	}		
+	}
 	else
 	{
 		/* 64K Byte is 0x10000 */
 		if((actualAddress & 0xFFFF) == 0)
 		{
-			ext_flash_erase64kB();
+			if(preparedPageAddress == actualAddress)	/* has page already been prepared before? (at the moment for samples only) */
+			{
+				preparedPageAddress = 0;
+
+			}
+			else
+			{
+				ext_flash_erase64kB();
+			}
 			return 1;
 		}
-	}		
+	}
+
 	return 0;
 }
 
@@ -1633,7 +1706,8 @@
 static void ef_write_block(uint8_t * sendByte, uint32_t length, uint8_t type, uint8_t do_not_erase)
 {
 	uint32_t remaining_page_size, remaining_length, remaining_space_to_ring_end;
-	
+	uint32_t i=0;
+
 	if(!length)
 		return;
 
@@ -1688,7 +1762,7 @@
 	if(do_not_erase == 0)
 		ext_flash_erase_if_on_page_start();
 	
-	for(uint32_t i=0;i<length;i++)
+	while( i<length)
 	{
 		ef_hw_rough_delay_us(5);
 		wait_chip_not_busy();
@@ -1697,12 +1771,24 @@
 		write_address(HOLDCS);
 		
 		remaining_length = length - i;
-		remaining_page_size = actualAddress & 0xFF;
+		remaining_page_size = 0xFF - (uint8_t)(actualAddress & 0xFF) +1;
 		remaining_space_to_ring_end = ringStop - actualAddress;
 		
-		if((remaining_page_size == 0) && (remaining_length >= 256) && (remaining_space_to_ring_end >= 256))
+		if(remaining_length >= 256)
+		{
+			remaining_length = 255;	/* up to 256 bytes may be written in one burst. Last byte is written with release */
+		}
+		else
 		{
-			for(int j=0; j<255; j++)
+			remaining_length--;		/* last byte needed for release */
+		}
+		if(remaining_length >= (remaining_page_size) ) /* use 256 byte page and calculate number of bytes left */
+		{
+			remaining_length = remaining_page_size - 1;
+		}
+		if( (remaining_space_to_ring_end >= 256)) 
+		{
+			for(int j=0; j<remaining_length; j++)
 			{
 				write_spi(sendByte[i],HOLDCS);/* write data */
 				actualAddress++;
@@ -1712,8 +1798,11 @@
 		/* byte with RELEASE */
 		write_spi(sendByte[i],RELEASE);/* write data */
 		actualAddress++;
+		i++;
+
 		if(actualAddress > ringStop)
 			actualAddress = ringStart;
+
 		if(do_not_erase == 0)
 			ext_flash_erase_if_on_page_start();
 	}
@@ -2026,6 +2115,131 @@
   {
   }
 }
+
+void ext_flash_CloseSector(void)
+{
+	uint32_t actualAddressBackup = actualAddress;
+	int i=0;
+
+	if(closeSectorAddress != 0)
+	{
+	/* write some dummy bytes to the sector which is currently used for storing samples. This is done to "hide" problem if function is calles again */
+		actualAddress = closeSectorAddress;
+
+		wait_chip_not_busy();
+		write_spi(0x06,RELEASE);		/* WREN */
+		write_spi(0x02,HOLDCS);			/* write cmd */
+		write_address(HOLDCS);
+		for(i = 0; i<8; i++)
+		{
+			write_spi(0xA5,HOLDCS);/* write data */
+			actualAddress++;
+		}
+		/* byte with RELEASE */
+		write_spi(0xA5,RELEASE);/* write data */
+		actualAddress = actualAddressBackup;
+		closeSectorAddress = 0;
+	}
+}
+
+uint32_t ext_flash_AnalyseSampleBuffer(char *pstrResult)
+{
+	uint8_t sectorState[16];	/* samples are stored in 16 sector / 64k each */
+	uint32_t curAddress = SAMPLESTART;
+	uint8_t curSector = 0;
+	uint8_t samplebuffer[10];
+	uint32_t actualAddressBackup = actualAddress;
+	uint8_t emptyCellCnt = 0;
+	uint32_t i = 0;
+	uint8_t startedSectors = 0;
+	uint8_t	lastSectorInuse = 0;
+
+/* check if a sector is used till its end */
+	for(curSector = 0; curSector < 16; curSector++)
+	{
+		sectorState[curSector] = 0;
+		emptyCellCnt = 0;
+		curAddress = SAMPLESTART + (curSector * 0x10000);	/* set address to begin of sector and check if it is used */
+		actualAddress = curAddress;
+		ext_flash_read_block_start();
+		for(uint32_t i=0;i<10;i++)
+		{
+			samplebuffer[i] = read_spi(HOLDCS);/* read data */
+			if(samplebuffer[i] == 0xFF)
+			{
+				emptyCellCnt++;
+			}
+		}
+		ext_flash_read_block_stop();
+		if(emptyCellCnt == 10)
+		{
+			sectorState[curSector] = SECTOR_NOTUSED;
+		}
+		emptyCellCnt = 0;
+		curAddress = SAMPLESTART + (curSector * 0x10000) + 0xFFF5;	/* set address to end of sector and check if it is used */
+		actualAddress = curAddress;
+		ext_flash_read_block_start();
+		for(i=0;i<10;i++)
+		{
+			samplebuffer[i] = read_spi(HOLDCS);/* read data */
+			if(samplebuffer[i] == 0xFF)
+			{
+				emptyCellCnt++;
+			}
+		}
+		ext_flash_read_block_stop();
+		if(emptyCellCnt == 10)
+		{
+			sectorState[curSector] |= SECTOR_INUSE;		/* will become SECTOR_EMPTY if start is NOTUSED */
+		}
+	}
+
+	for(i=0;i<16;i++)
+	{
+		if( sectorState[i] == SECTOR_INUSE)
+		{
+			startedSectors++;
+			lastSectorInuse = i;
+		}
+		*(pstrResult+i) = sectorState[i] + 48;
+	}
+
+	if(startedSectors > 1)	/* more than one sector is in used => ring buffer corrupted */
+	{
+		if(startedSectors == 2)			/* only fix issue if only two sectors are in used. Otherwise fixing will cause more worries than help */
+		{
+		/* the logic behind healing of the problem is that the larger address is the oldest one => restore the largest address */
+			curAddress = SAMPLESTART + (lastSectorInuse * 0x10000);
+			emptyCellCnt = 0;
+			actualAddress = curAddress;
+			ext_flash_read_block_start();
+			while((emptyCellCnt < 10) && (actualAddress < curAddress + 0x10000))
+			{
+				samplebuffer[0] = read_spi(HOLDCS);/* read data */
+				if(samplebuffer[0] == 0xFF)
+				{
+					emptyCellCnt++;
+				}
+				else
+				{
+					emptyCellCnt = 0;
+				}
+				actualAddress++;
+			}
+			ext_flash_read_block_stop();
+			actualAddress -= 10;	/* step 10 bytes back to the start of free bytes */
+			actualPointerSample = actualAddress;
+
+			closeSectorAddress = settingsGetPointer()->logFlashNextSampleStartAddress & 0xFFFF0000;
+			closeSectorAddress += 0xFFF5; /* to be used once next time a dive is logged. Needed because NextSampleID is derived at every startup */
+			settingsGetPointer()->logFlashNextSampleStartAddress = actualPointerSample;	/* store new position to be used for next dive */
+		}
+	}
+	actualAddress = actualAddressBackup;
+	*(pstrResult+i) = 0;
+	return startedSectors;
+}
+
 /*
 uint8_t ext_flash_erase_firmware_if_not_empty(void)
 {
--- a/Discovery/Src/logbook.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/logbook.c	Tue Feb 18 07:20:29 2020 +0000
@@ -1187,8 +1187,10 @@
 				{
 					pSettings->logbookOffset++;
 				}
-				ext_flash_write_settings();
+				ext_flash_write_settings(0);
 				ext_flash_disable_protection_for_logbook();
+
+				ext_flash_CloseSector();	/* this is just a repair function which invalidates a not used sector in case a log maintenance was called before dive */
 				bDiveMode = 3;
 			}
 			if(bDiveMode == 3)
--- a/Discovery/Src/tMenuEdit.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/tMenuEdit.c	Tue Feb 18 07:20:29 2020 +0000
@@ -272,7 +272,7 @@
     if(WriteSettings)
     {
         GFX_logoAutoOff();
-        ext_flash_write_settings();
+        ext_flash_write_settings(0);
         WriteSettings = 0;
     }
 }
--- a/Discovery/Src/tMenuEditSystem.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/tMenuEditSystem.c	Tue Feb 18 07:20:29 2020 +0000
@@ -41,6 +41,8 @@
 #include "motion.h"
 #include "t7.h"
 
+/* Uncomment to activate a menu item in reset menu which provide sample ring analysis / repair functionality */
+#define ENABLE_ANALYSE_SAMPLES
 
 #define CV_SUBPAGE_MAX		(2u)	/* max number of customer view selection pages */
 /*#define HAVE_DEBUG_VIEW */
@@ -95,6 +97,7 @@
 uint8_t OnAction_LogbookOffset(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 uint8_t OnAction_SetFactoryDefaults(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 uint8_t OnAction_SetBatteryCharge(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+uint8_t OnAction_RecoverSampleIdx(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 #ifdef SCREENTEST
 uint8_t OnAction_ScreenTest		(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 #endif
@@ -1470,27 +1473,46 @@
 
     case StMSYS6_Maintenance:
     case StMSYS6_SetBattCharge:
+    case StMSYS6_SetSampleIndx:
         text[0] = TXT_2BYTE;
         text[1] = TXT2BYTE_SetFactoryDefaults;
         text[2] = 0;
         write_field_button(StMSYS6_SetFactoryBC,			30, 800, ME_Y_LINE2,  &FontT48, text);
 
+#ifdef ENABLE_ANALYSE_SAMPLES
+        text[0] = TXT_2BYTE;
+        text[1] = TXT2BYTE_SetSampleIndex;
+        text[2] = 0;
+        write_field_button(StMSYS6_SetSampleIndx,			30, 800, ME_Y_LINE3,  &FontT48, text);
+#endif
+
+
         if(stateRealGetPointer()->lifeData.battery_charge == 0)
         {
             text[0] = TXT_2BYTE;
             text[1] = TXT2BYTE_SetBatteryCharge;
             text[2] = 0;
             snprintf(&text[2],10,": %u%%",settingsGetPointer()->lastKnownBatteryPercentage);
+#ifdef ENABLE_ANALYSE_SAMPLES
+            write_field_button(StMSYS6_SetBattCharge,			30, 800, ME_Y_LINE4,  &FontT48, text);
+#else
             write_field_button(StMSYS6_SetBattCharge,			30, 800, ME_Y_LINE3,  &FontT48, text);
+#endif
 
             setEvent(StMSYS6_Exit, (uint32_t)OnAction_Exit);
             setEvent(StMSYS6_SetFactoryBC, (uint32_t)OnAction_SetFactoryDefaults);
+#ifdef ENABLE_ANALYSE_SAMPLES
+            setEvent(StMSYS6_SetSampleIndx, (uint32_t)OnAction_RecoverSampleIdx);
+#endif
             setEvent(StMSYS6_SetBattCharge, (uint32_t)OnAction_SetBatteryCharge);
         }
         else
         {
             setEvent(StMSYS6_Exit, (uint32_t)OnAction_Exit);
             setEvent(StMSYS6_SetFactoryBC, (uint32_t)OnAction_SetFactoryDefaults);
+#ifdef ENABLE_ANALYSE_SAMPLES
+            setEvent(StMSYS6_SetSampleIndx, (uint32_t)OnAction_RecoverSampleIdx);
+#endif
         }
 //		write_field_button(StMSYS6_ScreenTest,			30, 800, ME_Y_LINE3,  &FontT48, "Screen Test");
 //		setEvent(StMSYS6_ScreenTest, (uint32_t)OnAction_ScreenTest);
@@ -1609,6 +1631,18 @@
 }
 
 
+uint8_t OnAction_RecoverSampleIdx(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+	char text[32];
+	char strResult[20];
+
+
+	ext_flash_AnalyseSampleBuffer(strResult);
+    snprintf(&text[0],30,"Ring: %s",strResult); //"Code: %X",settingsGetPointer()->logFlashNextSampleStartAddress); //getLicence());
+    write_label_var(  30, 800, ME_Y_LINE6, &FontT42, text);
+    return UNSPECIFIC_RETURN;
+}
+
 uint8_t OnAction_SetBatteryCharge(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
 {
     setBatteryPercentage(settingsGetPointer()->lastKnownBatteryPercentage);
--- a/Discovery/Src/text_multilanguage.c	Mon Feb 10 08:23:15 2020 +0000
+++ b/Discovery/Src/text_multilanguage.c	Tue Feb 18 07:20:29 2020 +0000
@@ -618,6 +618,14 @@
 static uint8_t text_ES_SetFactoryDefaults[] = "Restablecer ajustes de fábrica";
 
 // Menu SYS2 sub
+static uint8_t text_EN_SetSampleIndex[] = "Analyse log memory";
+static uint8_t text_DE_SetSampleIndex[] = "Prüfe Logbuchspeicher";
+static uint8_t text_FR_SetSampleIndex[] = "Maintain log memory";
+static uint8_t text_IT_SetSampleIndex[] = "Maintain log memory";
+static uint8_t text_ES_SetSampleIndex[] = "Maintain log memory";
+
+
+// Menu SYS2 sub
 static uint8_t text_EN_Reboot[] = "Reboot";
 static uint8_t text_DE_Reboot[] = "Neustart";
 static uint8_t text_FR_Reboot[] = "Redémarrage";
@@ -1761,6 +1769,7 @@
     {(uint8_t)TXT2BYTE_Maintenance,		{text_EN_Maintenance, text_DE_Maintenance, text_FR_Maintenance, text_IT_Maintenance, text_ES_Maintenance}},
     {(uint8_t)TXT2BYTE_SetBatteryCharge,{text_EN_SetBatteryCharge, text_DE_SetBatteryCharge, text_FR_SetBatteryCharge, text_IT_SetBatteryCharge, text_ES_SetBatteryCharge}},
     {(uint8_t)TXT2BYTE_SetFactoryDefaults,{text_EN_SetFactoryDefaults, text_DE_SetFactoryDefaults, text_FR_SetFactoryDefaults, text_IT_SetFactoryDefaults, text_ES_SetFactoryDefaults}},
+	{(uint8_t)TXT2BYTE_SetSampleIndex,  {text_EN_SetSampleIndex, text_DE_SetSampleIndex, text_FR_SetSampleIndex, text_IT_SetSampleIndex, text_ES_SetSampleIndex}},
 
     {(uint8_t)TXT2BYTE_Reboot,			{text_EN_Reboot, text_DE_Reboot, text_FR_Reboot, text_IT_Reboot, text_ES_Reboot}},
     {(uint8_t)TXT2BYTE_ButtonLeft,		{text_EN_ButtonLeft, text_DE_ButtonLeft, text_FR_ButtonLeft, text_IT_ButtonLeft, text_ES_ButtonLeft}},