changeset 387:0dbb74be972f

Merged in Ideenmodellierer/ostc4/MotionDetection (pull request #34) MotionDetection
author heinrichsweikamp <bitbucket@heinrichsweikamp.com>
date Sun, 24 Nov 2019 15:46:58 +0000
parents c6a084d1433f (current diff) 39c147e47c1c (diff)
children a848e22bc527 cad6f8dfacab 27c56f1b1856
files
diffstat 24 files changed, 877 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/Common/Inc/settings.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Common/Inc/settings.h	Sun Nov 24 15:46:58 2019 +0000
@@ -218,6 +218,8 @@
 	uint8_t FlipDisplay;
 	/* new in 0xFFFF0019 */
 	uint32_t cv_configuration;
+	/* new in 0xFFFF001A */
+	uint8_t MotionDetection;
 
 } SSettings;
 
--- a/Discovery/Inc/base.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/base.h	Sun Nov 24 15:46:58 2019 +0000
@@ -86,6 +86,8 @@
 	ACTION_BUTTON_NEXT,
 	ACTION_BUTTON_ENTER,
 	ACTION_BUTTON_ENTER_FINAL,
+	ACTION_PITCH_POS,
+	ACTION_PITCH_NEG,
 	ACTION_END
 } SAction;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Discovery/Inc/motion.h	Sun Nov 24 15:46:58 2019 +0000
@@ -0,0 +1,63 @@
+/*
+ * motion.h
+ *
+ *  Created on: 20.05.2019
+ *      Author: Thorsten Sonntag
+ */
+
+#ifndef INC_MOTION_H_
+#define INC_MOTION_H_
+
+
+/* exported data types */
+#define CUSTOMER_DEFINED_VIEWS	(100u)	/* value will cause the function to detect the number of selected views */
+#define CUSTOMER_KEEP_LAST_SECTORS	(200u)	/* do not update number of sectors, just define the new center position */
+
+typedef enum
+{
+		MOTION_DETECT_OFF = 0,
+		MOTION_DETECT_SECTOR,
+		MOTION_DETECT_MOVE,
+		MOTION_DETECT_SCROLL,
+		MOTION_DETECT_END
+} MotionDetectMethod_t;
+
+typedef enum
+{
+		DETECT_START = 0,
+		DETECT_POS_MOVE,
+		DETECT_MAXIMA,
+		DETECT_FALLBACK,
+		DETECT_POS_PITCH,
+		DETECT_NEG_MOVE,
+		DETECT_MINIMA,
+		DETECT_RISEBACK,
+		DETECT_NEG_PITCH,
+		DETECT_NOTHING
+} detectionState_t;
+
+typedef struct
+{
+    float upperborder;			/* current sector is changed if pitch exceeds these borders */
+    float lowerborder;
+
+    uint8_t current;			/* number of the current visible sector */
+    uint8_t target;				/* used for sector switch => number of the sector which shall be finnaly displayed */
+
+    float offset;				/* offset to adjust minimum pitch value used for detection to zero */
+    float size;					/* delta of upper and lower boarder defining the sector in degree */
+    float window;				/* defines which range of pitch values are used for detection */
+    float center;				/* defines the offset from pitch to middle of active sector (avoid center position is close to the calculated borders) */
+    uint8_t count;				/* number of sectors used for detection */
+} SSector;
+
+
+
+
+void InitMotionDetection(void);
+void DefinePitchSectors(float centerAngle, uint8_t numOfSectors);
+detectionState_t detectPitch(float currentPitch);
+detectionState_t detectSectorButtonEvent(float curPitch);
+detectionState_t detectScrollButtonEvent(float curPitch);
+
+#endif /* INC_MOTION_H_ */
--- a/Discovery/Inc/t3.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/t3.h	Sun Nov 24 15:46:58 2019 +0000
@@ -35,6 +35,7 @@
 /* Exported functions --------------------------------------------------------*/
 void t3_init(void);
 void t3_refresh(void);
-void t3_change_customview(void);
+void t3_change_customview(uint8_t action);
+uint8_t t3_GetEnabled_customviews();
 
 #endif /* T3_H */
--- a/Discovery/Inc/t5_gauge.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/t5_gauge.h	Sun Nov 24 15:46:58 2019 +0000
@@ -35,7 +35,7 @@
 /* Exported functions --------------------------------------------------------*/
 void t5_init(void);
 void t5_refresh(void);
-void t5_change_customview(void);
+void t5_change_customview(uint8_t action);
 uint8_t t5_getCustomView(void);
 
 #endif /* T5_H */
--- a/Discovery/Inc/t6_apnea.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/t6_apnea.h	Sun Nov 24 15:46:58 2019 +0000
@@ -35,6 +35,6 @@
 /* Exported functions --------------------------------------------------------*/
 void t6_init(void);
 void t6_refresh(void);
-void t6_change_customview(void);
+void t6_change_customview(uint8_t action);
 
 #endif /* T6_H */
--- a/Discovery/Inc/t7.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/t7.h	Sun Nov 24 15:46:58 2019 +0000
@@ -40,13 +40,15 @@
 void t7_refresh_customview_old(void);
 
 void t7_change_field(void);
-void t7_change_customview(void);
+void t7_change_customview(uint8_t action);
 
 void t7_set_field_to_primary(void);
 void t7_set_customview_to_primary(void);
 
 void init_t7_compass(void);
 
+uint8_t t7_GetEnabled_customviews();
+
 /*
 	 void t7c_refresh(uint32_t FramebufferStartAddress);
 */
--- a/Discovery/Inc/tHome.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/tHome.h	Sun Nov 24 15:46:58 2019 +0000
@@ -83,7 +83,7 @@
 };
 
 // for custom view switch on/off 161122 hw
-extern const uint8_t cv_changelist[6];
+extern const uint8_t cv_changelist[];
 #define CHECK_BIT_THOME(var,pos) (((var)>>(pos)) & 1)
 
 typedef struct
@@ -116,7 +116,7 @@
 void tHome_sleepmode_fun(void);
 void set_globalState_tHome(void);
 void tHome_change_field_button_pressed(void);
-void tHome_change_customview_button_pressed(void);
+void tHome_change_customview_button_pressed(uint8_t action);
 
 void tHome_findNextStop(const uint16_t *list, uint8_t *depthOut, uint16_t *lengthOut);
 void tHomeDiveMenuControl(uint8_t sendAction);
@@ -134,7 +134,7 @@
 void t3_basics_refresh_apnoeRight(float depth, uint8_t tX_selection_customview, GFX_DrawCfgScreen *tXscreen, GFX_DrawCfgWindow* tXc1, GFX_DrawCfgWindow* tXc2, uint8_t mode);
 //void _findNextStop(const uint16_t *list, uint8_t *depthOut, uint16_t *lengthOut);
 void t3_basics_colorscheme_mod(char *text);
-void t3_basics_change_customview(uint8_t *tX_selection_customview, const uint8_t *tX_customviews);
+void t3_basics_change_customview(uint8_t *tX_selection_customview, const uint8_t *tX_customviews, uint8_t action);
 
 uint8_t tHome_show_lost_connection_count(GFX_DrawCfgScreen *ScreenToWriteOn);
 
--- a/Discovery/Inc/tMenu.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/tMenu.h	Sun Nov 24 15:46:58 2019 +0000
@@ -78,6 +78,7 @@
 void tM_rebuild_menu_after_tComm(void);
 
 void tM_refresh(char *text, uint8_t *textPointer, uint8_t line, const char content[6]);
+void tM_build_page(uint32_t id, char *text, uint16_t tab, char *subtext);
 
 void block_diluent_page(void);
 void unblock_diluent_page(void);
--- a/Discovery/Inc/tMenuSystem.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/tMenuSystem.h	Sun Nov 24 15:46:58 2019 +0000
@@ -36,6 +36,8 @@
 	* @{
 	*/
 
+void set_CustomsviewsSubpage(uint8_t page);
+
 /* Exported variables --------------------------------------------------------*/
 
 
--- a/Discovery/Inc/tStructure.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/tStructure.h	Sun Nov 24 15:46:58 2019 +0000
@@ -283,8 +283,9 @@
 #define StMSYS4_CViewTimeout		_MB(2,8,4,1,0)
 #define StMSYS4_CViewStandard		_MB(2,8,4,2,0)
 #define StMSYS4_CornerTimeout		_MB(2,8,4,3,0)
-#define StMSYS4_CornerStandard	_MB(2,8,4,4,0)
+#define StMSYS4_CornerStandard		_MB(2,8,4,4,0)
 #define StMSYS4_ExtraDisplay		_MB(2,8,4,5,0)
+#define StMSYS4_MotionCtrl			_MB(2,8,4,6,0)
 
 #define StMSYS5_Info		_MB(2,8,5,1,0)
 
--- a/Discovery/Inc/text_multilanguage.h	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Inc/text_multilanguage.h	Sun Nov 24 15:46:58 2019 +0000
@@ -273,6 +273,12 @@
 		TXT2BYTE_ExtraDecoGame,
 		TXT2BYTE_ExtraNone,
 		/* */
+		TXT2BYTE_MotionCtrl,
+		TXT2BYTE_MoCtrlNone,
+		TXT2BYTE_MoCtrlPitch,
+		TXT2BYTE_MoCtrlSector,
+		TXT2BYTE_MoCtrlScroll,
+		/* */
 		TXT2BYTE_DecoDataLost,
 		TXT2BYTE_Info,
 		TXT2BYTE_Korrekturwerte,
@@ -288,6 +294,7 @@
 		TXT2BYTE_ButtonRight,
 		/* */
 		TXT2BYTE_Summary,
+		TXT2BYTE_DispNoneDbg,
 		TXT2BYTE_ApneaLast,
 		TXT2BYTE_ApneaTotal,
 		TXT2BYTE_ApneaSurface,
--- a/Discovery/Src/base.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/base.c	Sun Nov 24 15:46:58 2019 +0000
@@ -229,12 +229,14 @@
 #include "logbook_miniLive.h"
 #include "test_vpm.h"
 #include "tDebug.h"
+#include "motion.h"
 
 #ifdef DEMOMODE
 #include "demo.h"
 static void TIM_DEMO_init(void);
 #endif
 
+
 //#include "lodepng.h"
 //#include <stdlib.h> // for malloc and free
 
@@ -325,6 +327,14 @@
 #define MEASURECNT 60	/* number of measuremets to be stored */
 static uint32_t loopcnt[MEASURECNT];
 #endif
+
+static uint8_t ButtonAction = ACTION_END;
+
+static void StoreButtonAction(uint8_t action)
+{
+	ButtonAction = action;
+}
+
 //  ===============================================================================
 //	main
 /// @brief	This function makes initializations and has the nonIRQ endless loop
@@ -341,6 +351,7 @@
     uint8_t lastsecond = 0xFF;
 #endif
 
+    detectionState_t pitchstate;
     set_globalState( StBoot0 );
     LastButtonPressed = 0;
 
@@ -446,6 +457,7 @@
         setDebugMode();
         openInfo( StIDEBUG );
     }
+    InitMotionDetection();
 
     TIM_init();		/* start cylic 100ms task */
 
@@ -476,6 +488,31 @@
 	        DoDisplayRefresh = 0;
         	RefreshDisplay();
 
+        	if(stateUsed->mode == MODE_DIVE)			/* handle motion events in divemode only */
+        	{
+				switch(settingsGetPointer()->MotionDetection)
+				{
+					case MOTION_DETECT_MOVE: pitchstate = detectPitch(stateRealGetPointer()->lifeData.compass_pitch);
+						break;
+					case MOTION_DETECT_SECTOR: pitchstate = detectSectorButtonEvent(stateRealGetPointer()->lifeData.compass_pitch);
+						break;
+					case MOTION_DETECT_SCROLL: pitchstate = detectScrollButtonEvent(stateRealGetPointer()->lifeData.compass_pitch);
+						 break;
+					default:
+						pitchstate = DETECT_NOTHING;
+						break;
+				}
+				if(DETECT_NEG_PITCH == pitchstate)
+	           	{
+	            	StoreButtonAction((uint8_t)ACTION_PITCH_NEG);
+	           	}
+	            if(DETECT_POS_PITCH == pitchstate)
+	           	{
+	            	StoreButtonAction((uint8_t)ACTION_PITCH_POS);
+	           	}
+        	}
+
+
 // Enable this to make the simulator write a logbook entry
 // #define SIM_WRITES_LOGBOOK 1
 
@@ -510,6 +547,9 @@
     }
 }
 
+
+
+
 //  ===============================================================================
 //	timer IRQ
 /// @brief	this is called periodically
@@ -819,12 +859,7 @@
 		break;
 	}
 }
-static uint8_t ButtonAction = ACTION_END;
 
-static void StoreButtonAction(uint8_t action)
-{
-	ButtonAction = action;
-}
 
 static void TriggerButtonAction()
 {
@@ -860,7 +895,13 @@
 					settingsGetPointer()->design = 7; // auto switch to 9 if necessary
 				} else if ((status.page == PageDive) && (status.line != 0)) {
 					if (settingsGetPointer()->extraDisplay == EXTRADISPLAY_BIGFONT)
+					{
 						settingsGetPointer()->design = 3;
+						if(settingsGetPointer()->MotionDetection == MOTION_DETECT_SECTOR)
+						{
+							DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch,CUSTOMER_DEFINED_VIEWS);
+						}
+					}
 					else if (settingsGetPointer()->extraDisplay
 							== EXTRADISPLAY_DECOGAME)
 						settingsGetPointer()->design = 4;
@@ -868,14 +909,22 @@
 					set_globalState(StD);
 				} else
 					tHome_change_field_button_pressed();
-			} else if (action == ACTION_BUTTON_ENTER) {
-				if ((status.page == PageDive) && (status.line == 0))
-					tHome_change_customview_button_pressed();
-				else if (status.page == PageSurface)
-					tHome_change_customview_button_pressed();
-				else
-					tHomeDiveMenuControl(action);
-			}
+			} else if ((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_NEG) || (action == ACTION_PITCH_POS))
+					{
+
+						if ((status.page == PageDive) && (status.line == 0))
+						{
+							tHome_change_customview_button_pressed(action);
+							if((settingsGetPointer()->MotionDetection != MOTION_DETECT_OFF) && (action == ACTION_BUTTON_ENTER))  /* Button pressed while motion detection is active => calibrate to current pitch value */
+							{
+								DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch,CUSTOMER_KEEP_LAST_SECTORS);
+							}
+						}
+						else if (status.page == PageSurface)
+							tHome_change_customview_button_pressed(action);
+						else
+							tHomeDiveMenuControl(action);
+					}
 			break;
 
 		case BaseMenu:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Discovery/Src/motion.c	Sun Nov 24 15:46:58 2019 +0000
@@ -0,0 +1,297 @@
+/*
+ * motion.c
+ *
+ *  Created on: 20.05.2019
+ *      Author: Thorsten Sonntag
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "motion.h"
+#include "data_central.h"
+#include "t7.h"
+#include "t3.h"
+#include "settings.h"
+
+#define	STABLE_STATE_COUNT			2	/* number of count to declare a state as stable (at the moment based on 100ms) */
+#define STABLE_STATE_TIMEOUT		5	/* Detection shall be aborted if a movement state is stable for more than 500ms */
+
+#define SECTOR_WINDOW				80.0  	/* Pitch window which is used for custom view projection */
+#define SECTOR_WINDOW_MAX			120.0  	/* Pitch window which will be greater than the divers field of view */
+#define SECTOR_HYSTERY				2		/* Additional offset to avoid fast changing displays */
+#define SECTOR_BORDER				400.0	/* Define a value which is out of limit to avoid not wanted key events */
+#define SECTOR_FILTER				10		/* Define speed for calculated angle to follow real value */
+
+#define SECTOR_MAX					24		/* maximum number of sectors */
+#define SECTOR_SCROLL				7		/* number of sectors used for scroll detection */
+
+detectionState_t detectionState = DETECT_NOTHING;
+SSector sectorDetection;
+
+
+uint8_t GetSectorForPitch(float pitch)
+{
+	static uint8_t lastsector = 0;
+	float newPitch;
+	uint8_t sector = 0;
+
+	newPitch = pitch + sectorDetection.offset + sectorDetection.center;		/* do not use negative values and consider offset to center position */
+	if (newPitch < 0.0)							/* clip value */
+	{
+		newPitch = 0.0;
+	}
+	if (newPitch > sectorDetection.window)							/* clip value */
+	{
+		newPitch = sectorDetection.window;
+	}
+
+	/* switch to other sector? */
+	if((newPitch > sectorDetection.upperborder) || (newPitch <= sectorDetection.lowerborder))
+	{
+		sector = (uint16_t) newPitch / sectorDetection.size;
+		sectorDetection.lowerborder = sector * sectorDetection.size - SECTOR_HYSTERY;
+		sectorDetection.upperborder = (sector + 1) * sectorDetection.size + SECTOR_HYSTERY;
+		lastsector = sector;
+	}
+
+	return lastsector;
+}
+
+void DefinePitchSectors(float centerPitch,uint8_t numOfSectors)
+{
+	if(numOfSectors == CUSTOMER_DEFINED_VIEWS)
+	{
+		if(settingsGetPointer()->design == 3)		/* Big font view ? */
+		{
+			sectorDetection.count =  t3_GetEnabled_customviews();
+		}
+		else
+		{
+			sectorDetection.count =  t7_GetEnabled_customviews();
+		}
+		if(sectorDetection.count > 7)
+		{
+			sectorDetection.count = 7;	/* more views are hard to manually control */
+		}
+	}
+	else
+	if(numOfSectors != CUSTOMER_KEEP_LAST_SECTORS)
+	{
+		sectorDetection.count = numOfSectors;
+	}
+
+	if(sectorDetection.count == SECTOR_MAX)
+	{
+		sectorDetection.window = SECTOR_WINDOW_MAX;
+	}
+	else
+	{
+		sectorDetection.window = SECTOR_WINDOW;
+	}
+
+	sectorDetection.offset = (centerPitch - (sectorDetection.window / 2)) * -1.0;
+	sectorDetection.size = sectorDetection.window / sectorDetection.count;
+	sectorDetection.center = 0;
+
+/* reset border values */
+	sectorDetection.lowerborder = SECTOR_BORDER;
+	sectorDetection.upperborder = SECTOR_BORDER * -1.0;
+/* get the current sector */
+	sectorDetection.current = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
+	sectorDetection.target = sectorDetection.current;
+/* do a small adjustment to center pitch to make sure the actual pitch is in the center of the current sector */
+	sectorDetection.center = (sectorDetection.upperborder) - ((sectorDetection.size + 2 *SECTOR_HYSTERY) / 2.0) - (centerPitch + sectorDetection.offset);
+
+}
+
+void InitMotionDetection(void)
+{
+	sectorDetection.target = 0;
+	sectorDetection.current = 0;
+	sectorDetection.size = 0;
+	sectorDetection.count = 0;
+
+	switch(settingsGetPointer()->MotionDetection)
+	{
+		case MOTION_DETECT_SECTOR: DefinePitchSectors(0,CUSTOMER_DEFINED_VIEWS);
+			break;
+		case MOTION_DETECT_MOVE: DefinePitchSectors(0,SECTOR_MAX);
+			break;
+		case MOTION_DETECT_SCROLL: DefinePitchSectors(0,SECTOR_SCROLL);
+			break;
+		default:
+			break;
+	}
+
+}
+
+/* Map the current pitch value to a sector and create button event in case the sector is left */
+detectionState_t detectSectorButtonEvent(float curPitch)
+{
+	static uint8_t lastTargetSector = 0;
+	uint8_t newTargetSector;
+	uint8_t PitchEvent = DETECT_NOTHING;
+
+/* only change sector if reading is stable */
+	newTargetSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
+	if(lastTargetSector == newTargetSector)
+	{
+		sectorDetection.target = newTargetSector;
+	}
+	lastTargetSector = newTargetSector;
+	if(sectorDetection.target != sectorDetection.current)
+	{
+		 if(sectorDetection.target > sectorDetection.current)
+		 {
+			 sectorDetection.current++;
+			PitchEvent = DETECT_POS_PITCH;
+		 }
+		 else
+		 {
+			 sectorDetection.current--;
+			 PitchEvent = DETECT_NEG_PITCH;
+		 }
+	}
+	return PitchEvent;
+}
+
+/* Check if pitch is not in center position and trigger a button action if needed */
+detectionState_t detectScrollButtonEvent(float curPitch)
+{
+	static uint8_t	delayscroll = 0;		/* slow down the number of scroll events */
+
+	uint8_t PitchEvent = DETECT_NOTHING;
+	uint8_t newSector;
+
+	if(delayscroll == 0)
+	{
+		newSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
+		/* for scroll detection the motion windoe is split into 6 sectors => set event accoring to the sector number*/
+		switch(newSector)
+		{
+			case 0:
+			case 1:	PitchEvent = DETECT_POS_PITCH;
+				break;
+			case 5:
+			case 6:	PitchEvent = DETECT_NEG_PITCH;
+				break;
+			default:
+				break;
+		}
+		if(PitchEvent != DETECT_NOTHING)
+		{
+			delayscroll = 5;
+		}
+	}
+	else
+	{
+		delayscroll--;
+	}
+	return PitchEvent;
+}
+
+
+/* Detect if user is generating an pitch including return to starting position */
+/* This is done by feeding the past movements value per value into a state machine */
+detectionState_t detectPitch(float currentPitch)
+{
+	static uint8_t lastSector = 0;
+	static uint8_t startSector = 0;
+	static uint8_t stableCnt = 0;
+
+	uint8_t curSector;
+
+	if((detectionState == DETECT_NEG_PITCH) || (detectionState == DETECT_POS_PITCH))	/* discard last detection */
+	{
+		detectionState = DETECT_NOTHING;
+	}
+
+	curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
+
+	/* feed value into state machine */
+	switch (detectionState)
+	{
+			case DETECT_NOTHING: 	if(curSector != lastSector)	/* detect a stable condition before evaluating for the next move */
+									{
+										stableCnt=0;
+									}
+
+									if(stableCnt > STABLE_STATE_COUNT)
+									{
+										detectionState = DETECT_START;
+										stableCnt = 0;
+										startSector = lastSector;
+									}
+				break;
+			case DETECT_START:		if(curSector != lastSector)
+									{
+										if(abs(curSector - startSector) > 1)
+										{
+											if(curSector > lastSector)
+											{
+												detectionState = DETECT_POS_MOVE;
+											}
+											else
+											{
+												detectionState = DETECT_NEG_MOVE;
+											}
+											stableCnt = 0;
+											startSector = lastSector;
+										}
+									}
+				break;
+			case DETECT_NEG_MOVE:
+			case DETECT_POS_MOVE:	if(curSector == lastSector)		/* Moved to a max? */
+									{
+										if(abs(startSector - curSector) > 2)
+										{
+											detectionState++;
+											stableCnt = 0;
+										}
+										if(stableCnt > 2)
+										{
+											detectionState = DETECT_NOTHING;
+											stableCnt = 0;
+										}
+									}
+				break;
+			case DETECT_MAXIMA:
+			case DETECT_MINIMA:		if(curSector != lastSector)		/* reset timeout detection */
+									{
+										detectionState++;
+										stableCnt = 0;
+									}
+				break;
+			case DETECT_RISEBACK:
+			case DETECT_FALLBACK:
+									if(curSector == lastSector)		/* check if we are back at start position at end of movement */
+									{
+										if(abs(startSector - curSector) <= 1)
+										{
+											if(stableCnt > 2)
+											{
+												detectionState++;
+												stableCnt = 0;
+											}
+										}
+									}
+								break;
+			default:
+				detectionState = DETECT_NOTHING;
+				break;
+	}
+	if(detectionState != DETECT_START)
+	{
+		stableCnt++;
+	}
+	lastSector = curSector;
+	if(stableCnt > STABLE_STATE_TIMEOUT)
+	{
+		detectionState = DETECT_NOTHING;
+		stableCnt = 0;
+	}
+
+	return detectionState;
+}
--- a/Discovery/Src/settings.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/settings.c	Sun Nov 24 15:46:58 2019 +0000
@@ -32,6 +32,7 @@
 #include "externLogbookFlash.h" // for SAMPLESTART and SAMPLESTOP
 #include "text_multilanguage.h" // for LANGUAGE_END
 #include "tHome.h" // for CVIEW_END
+#include "Motion.h"
 
 SSettings Settings;
 
@@ -82,7 +83,7 @@
  * There might even be entries with fixed values that have no range
  */
 const SSettings SettingsStandard = {
-    .header = 0xFFFF0019,
+    .header = 0xFFFF001A,
     .warning_blink_dsec = 8 * 2,
     .lastDiveLogId = 0,
     .logFlashNextSampleStartAddress = 0,
@@ -307,6 +308,7 @@
     .FactoryButtonBalance[2] = 3,
 	.FlipDisplay = 0,
 	.cv_configuration = 0xFFFFFFFF,
+	.MotionDetection = MOTION_DETECT_OFF,
 };
 
 /* Private function prototypes -----------------------------------------------*/
@@ -353,6 +355,7 @@
 
     pSettings->scooterControl = 0;
 
+    /* Pointing to the old header data => set new data depending on what had been added since last version */
     switch(pSettings->header)
     {
     case 0xFFFF0000:
@@ -450,6 +453,9 @@
     case 0xFFFF0018:
     	pSettings->cv_configuration = 0xFFFFFFFF;
     	// no break
+    case 0xFFFF0019:
+    	pSettings->MotionDetection = MOTION_DETECT_OFF;
+    	// no break
     default:
         pSettings->header = pStandard->header;
         break; // no break before!!
@@ -1347,6 +1353,11 @@
     	Settings.FlipDisplay = 0;
 	    corrections++;
    	}
+    if(Settings.MotionDetection >= MOTION_DETECT_END)
+   	{
+    	Settings.MotionDetection = MOTION_DETECT_OFF;
+	    corrections++;
+   	}
 
     if(corrections > 255)
         return 255;
@@ -1399,7 +1410,7 @@
     return ((firmware_FirmwareData.versionSecond & 0x03)  << 6)	+ ((firmware_FirmwareData.versionThird & 0x1F) << 1) + (firmware_FirmwareData.versionBeta & 0x01);
 }
 
-SSettings* settingsGetPointer(void)
+inline SSettings* settingsGetPointer(void)
 {
     return &Settings;
 }
--- a/Discovery/Src/t3.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/t3.c	Sun Nov 24 15:46:58 2019 +0000
@@ -58,6 +58,7 @@
 
 /* Private types -------------------------------------------------------------*/
 #define TEXTSIZE 16
+#define NUMBER_OF_VIEWS 7	/* number of views defined in the array below */
 
 const uint8_t t3_customviewsStandard[] =
 {
@@ -259,6 +260,7 @@
                 depthChangeRate = 200;
         }
         start.y = tXl1->WindowY0 - 1;
+        startZeroLine.y = start.y;
         for(int i = 0; i<5;i++)
         {
             start.y += 40;
@@ -484,9 +486,10 @@
 
 void t3_refresh_customview(float depth)
 {
+#if 0
     if((t3_selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
         t3_change_customview();
-
+#endif
     t3_basics_refresh_customview(depth, t3_selection_customview, &t3screen, &t3c1, &t3c2, stateUsedWrite->diveSettings.diveMode);
 }
 
@@ -1059,13 +1062,13 @@
 }
 
 
-void t3_change_customview(void)
+void t3_change_customview(uint8_t action)
 {
-    t3_basics_change_customview(&t3_selection_customview, t3_customviews);
+    t3_basics_change_customview(&t3_selection_customview, t3_customviews, action);
 }
 
 
-void t3_basics_change_customview(uint8_t *tX_selection_customview, const uint8_t *tX_customviews)
+void t3_basics_change_customview(uint8_t *tX_selection_customview, const uint8_t *tX_customviews, uint8_t action)
 {
     const SDecoinfo * pDecoinfo;
     if(stateUsed->diveSettings.deco_type.ub.standard == GF_MODE)
@@ -1073,24 +1076,60 @@
     else
         pDecoinfo = &stateUsed->decolistVPM;
 
-    const uint8_t *pViews;
+    uint8_t *pViews;
     pViews = tX_customviews;
 
-    while((*pViews != CVIEW_T3_END) && (*pViews != *tX_selection_customview))
-        {pViews++;}
+    uint8_t *pStartView,*pCurView, *pLastView;
+    uint8_t iterate = 0;	/* set to 1 if a view has to be skipped */
 
-    if(*pViews < CVIEW_T3_END)
-        pViews++;
+    pStartView = pViews;
+    /* set pointer to currently selected view and count number of entries */
+    while((*pViews != CVIEW_T3_END))
+    {
+    	if (*pViews == *tX_selection_customview)
+    	{
+    		pCurView = pViews;
+    	}
+    	pViews++;
+    }
+    pLastView = pViews;
+    pViews = pCurView;
+
+    do
+    {
+    	iterate = 0;
+		if((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_POS))
+		{
+			if(*pViews != CVIEW_T3_END)
+				pViews++;
 
-    if((*pViews == CVIEW_T3_TTS) && !pDecoinfo->output_time_to_surface_seconds)
-        pViews++;
+			if(*pViews == CVIEW_T3_END)
+			{
+				pViews = pStartView;
+			}
+		}
+		else
+		{
+			if(pViews == pStartView)
+			{
+				pViews = pLastView - 1;
+			}
+			else
+			{
+				pViews--;
+			}
+		}
+		if((*pViews == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
+		{
+			iterate = 1;
+		}
+	    if((*pViews == CVIEW_T3_TTS) && !pDecoinfo->output_time_to_surface_seconds)
+	    {
+	    	iterate = 1;
+	    }
+    }while (iterate == 1);
 
-    if(*pViews == CVIEW_T3_END)
-    {
-        *tX_selection_customview = tX_customviews[0];
-    }
-    else
-        *tX_selection_customview = *pViews;
+    *tX_selection_customview = *pViews;
 }
 
 
@@ -1251,3 +1290,36 @@
     GFX_draw_circle(tXscreen, center, 107, CLUT_Font030);
     GFX_draw_circle(tXscreen, center, 108, CLUT_Font030);
 }
+
+uint8_t t3_GetEnabled_customviews()
+{
+	int8_t i;
+    uint8_t enabledViewCnt = 0;
+    uint32_t cv_config = settingsGetPointer()->cv_configuration;
+
+    i=0;
+   	do
+    {
+        if(cv_changelist[i] == CVIEW_sensors) /* at the moment specific big font view may not be selected. Only sensor setting is taken from t7 configuration */
+        {
+          	 if(!CHECK_BIT_THOME(cv_config, cv_changelist[i]))
+          	 {
+           		 enabledViewCnt = NUMBER_OF_VIEWS - 1;		/* sensor shall not be displayed */
+           	 }
+          	 else
+          	 {
+           		 enabledViewCnt = NUMBER_OF_VIEWS; 			/* enable all possible views */
+           	 }
+             break;
+        }
+        i++;
+    } while(cv_changelist[i] != CVIEW_END);
+    if ((stateUsed->diveSettings.ppo2sensors_deactivated) || (stateUsed->diveSettings.ccrOption == 0))
+    {
+    	enabledViewCnt = NUMBER_OF_VIEWS - 1;		/* sensor shall not be displayed */
+    }
+
+    return enabledViewCnt;
+}
+
+
--- a/Discovery/Src/t5_gauge.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/t5_gauge.c	Sun Nov 24 15:46:58 2019 +0000
@@ -285,16 +285,16 @@
 }
 
 
-void t5_change_customview(void)
+void t5_change_customview(uint8_t action)
 {
-    t3_basics_change_customview(&t5_selection_customview, t5_customviews);
+    t3_basics_change_customview(&t5_selection_customview, t5_customviews, action);
 }
 
 
 void t5_refresh_customview(float depth)
 {
-    if((t5_selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t5_change_customview();
+ //   if((t5_selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
+ //       t5_change_customview();
 
     t3_basics_refresh_customview(depth, t5_selection_customview, &t5screen, &t5c1, &t5c2, DIVEMODE_Gauge);
 }
--- a/Discovery/Src/t6_apnea.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/t6_apnea.c	Sun Nov 24 15:46:58 2019 +0000
@@ -301,9 +301,9 @@
 
 
 
-void t6_change_customview(void)
+void t6_change_customview(uint8_t action)
 {
-    t3_basics_change_customview(&t6_selection_customview, t6_customviews);
+    t3_basics_change_customview(&t6_selection_customview, t6_customviews, action);
 }
 
 
@@ -311,9 +311,6 @@
 {
     uint8_t customViewLeftSide = CVIEW_T3_MaxDepth;
 
-    if((t6_selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t6_change_customview();
-
     if(t6_getCustomView() == CVIEW_T3_ApnoeSurfaceInfo)
         customViewLeftSide = CVIEW_T3_ApnoeSurfaceInfo;
 
--- a/Discovery/Src/t7.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/t7.c	Sun Nov 24 15:46:58 2019 +0000
@@ -38,6 +38,7 @@
 #include "simulation.h"
 #include "timer.h"
 #include "unit.h"
+#include "motion.h"
 
 /* Private function prototypes -----------------------------------------------*/
 
@@ -570,6 +571,8 @@
                 selection_customview = CVIEW_noneOrDebug;
             else
                 selection_customview = settingsGetPointer()->tX_customViewPrimary;
+
+            InitMotionDetection();
         }
 
         if(status.page == PageSurface)
@@ -600,6 +603,7 @@
         {
             last_mode = MODE_SURFACE;
             selection_customview = customviewsSurface[0];
+            InitMotionDetection();
         }
         if(status.page == PageDive)
             set_globalState(StS);
@@ -1440,64 +1444,144 @@
             selection_customview = settingsGetPointer()->tX_customViewPrimary;
 }
 
-void t7_change_customview(void)
+uint8_t t7_GetEnabled_customviews()
 {
-    const uint8_t *pViews;
+	int8_t i;
+    uint8_t *pViews;
+    uint8_t increment = 1;
+
+    uint8_t enabledViewCnt = 0;
+    uint32_t cv_config = settingsGetPointer()->cv_configuration;
+
+    if(stateUsed->mode == MODE_DIVE)
+        pViews = (uint8_t*)customviewsDive;
+    else
+        pViews = (uint8_t*)customviewsSurface;
+
+    while((*pViews != CVIEW_END))
+    {
+    	increment = 1;
+    /* check if view is enabled */
+    	i=0;
+    	do
+        {
+             if(*pViews == cv_changelist[i])
+             {
+            	 if(!CHECK_BIT_THOME(cv_config, cv_changelist[i]))
+             	 {
+            	 	 increment = 0;
+             	 }
+                 break;
+             }
+             i++;
+        } while(cv_changelist[i] != CVIEW_END);
+    	if(cv_changelist[i] == CVIEW_END)
+    	{
+    		 increment = 0;
+    	}
+        if (((*pViews == CVIEW_sensors) || (*pViews == CVIEW_sensors_mV)) &&
+           	((stateUsed->diveSettings.ppo2sensors_deactivated) || (stateUsed->diveSettings.ccrOption == 0)))
+        {
+        	increment = 0;
+        }
+
+    	pViews++;
+    	enabledViewCnt += increment;
+    }
+    return enabledViewCnt;
+}
+
+void t7_change_customview(uint8_t action)
+{
+	int8_t i;
+    uint8_t *pViews;
+    uint8_t *pStartView,*pCurView, *pLastView;
     _Bool cv_disabled = 0;
 
     if(stateUsed->mode == MODE_DIVE)
-        pViews = customviewsDive;
+        pViews = (uint8_t*)customviewsDive;
     else
-        pViews = customviewsSurface;
-
-    while((*pViews != CVIEW_END) && (*pViews != selection_customview))
-        {pViews++;}
-
-    if(*pViews < CVIEW_END)
-        pViews++;
-
-
-    if(*pViews == CVIEW_END)
+        pViews = (uint8_t*)customviewsSurface;
+
+    pStartView = pViews;
+    /* set pointer to currently selected view and count number of entries */
+    while((*pViews != CVIEW_END))
+    {
+    	if (*pViews == selection_customview)
+    	{
+    		pCurView = pViews;
+    	}
+    	pViews++;
+    }
+    pLastView = pViews;
+    pViews = pCurView;
+
+    if((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_POS))
     {
-        if(stateUsed->mode == MODE_DIVE)
-            pViews = customviewsDive;
-        else
-            pViews = customviewsSurface;
+		if(*pViews < CVIEW_END)
+			pViews++;
+
+		if(*pViews == CVIEW_END)
+		{
+			pViews = pStartView;
+		}
     }
-
-    if(stateUsed->mode == MODE_DIVE)
+    else
     {
-        do
+		if(pViews == pStartView)
+		{
+			pViews = pLastView - 1;
+		}
+		else
+		{
+			pViews--;
+		}
+    }
+
+    do
+    {
+        cv_disabled = 0;
+        i=0;
+       	while(cv_changelist[i] != CVIEW_END)
         {
-            cv_disabled = 0;
-            for(int i=0;i<6;i++)
-            {
-                if((*pViews == cv_changelist[i]) && !CHECK_BIT_THOME(settingsGetPointer()->cv_configuration, cv_changelist[i]))
-                {
-                    cv_disabled = 1;
-                    break;
-                }
-            }
-
-            if ((*pViews == CVIEW_sensors || *pViews == CVIEW_sensors_mV) &&
-            	stateUsed->diveSettings.ppo2sensors_deactivated)
-            {
-            	cv_disabled = 1;
-            }
-
-            if(cv_disabled)
-            {
-                if(*pViews < CVIEW_END)
-                {
-                    pViews++;
-                }
-                else
-                {
-                    pViews = customviewsDive;
-                }
-            }
-        } while(cv_disabled);
-    }
+             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;
+        }
+
+        if(cv_disabled)		/* view is disabled => jump to next view */
+        {
+          	if((action == ACTION_BUTTON_ENTER) || (action == ACTION_PITCH_POS))
+          	{
+           		pViews++;
+				if(*pViews == CVIEW_END)
+				{
+					pViews = pStartView;
+				}
+           	}
+           	else
+           	{
+           		if(pViews == pStartView)
+           		{
+           			pViews = pLastView - 1;
+           		}
+           		else
+           		{
+           			pViews--;
+           		}
+           	}
+        }
+    } while(cv_disabled);
+
     selection_customview = *pViews;
 }
 
@@ -1531,11 +1615,11 @@
 	pSettings = settingsGetPointer();
 
     if((selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview();
+        t7_change_customview(ACTION_BUTTON_ENTER);
     if((selection_customview == CVIEW_sensors_mV) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview();
+        t7_change_customview(ACTION_BUTTON_ENTER);
     if((selection_customview == CVIEW_sensors) &&(stateUsed->diveSettings.ccrOption == 0))
-        t7_change_customview();
+        t7_change_customview(ACTION_BUTTON_ENTER);
 
     switch(selection_customview)
     {
--- a/Discovery/Src/tHome.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/tHome.c	Sun Nov 24 15:46:58 2019 +0000
@@ -42,6 +42,7 @@
 #include "tMenuEditGasOC.h" // for openEdit_DiveSelectBetterGas()
 #include "tMenuEditSetpoint.h" // for openEdit_DiveSelectBetterSetpoint()
 #include "simulation.h"
+#include "motion.h"
 
 /* Private types -------------------------------------------------------------*/
 
@@ -56,7 +57,7 @@
 static uint16_t tHome_tick_count_cview;
 static uint16_t tHome_tick_count_field;
 
-const uint8_t cv_changelist[6] = {CVIEW_Compass, CVIEW_SummaryOfLeftCorner, CVIEW_Tissues, CVIEW_Profile, CVIEW_EADTime, CVIEW_Gaslist};
+const uint8_t cv_changelist[] = {CVIEW_Compass, CVIEW_SummaryOfLeftCorner, CVIEW_Tissues, CVIEW_Profile, CVIEW_EADTime, CVIEW_Gaslist, CVIEW_noneOrDebug, CVIEW_Decolist,CVIEW_sensors,CVIEW_sensors_mV, CVIEW_END};
 
 /* Private function prototypes -----------------------------------------------*/
 
@@ -147,8 +148,13 @@
             return;
 
         if(settingsGetPointer()->design == 3)
+        {
             settingsGetPointer()->design = 7;
-
+        	if(settingsGetPointer()->MotionDetection == MOTION_DETECT_SECTOR)
+        	{
+        		DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch,CUSTOMER_DEFINED_VIEWS);
+        	}
+        }
         switch(get_globalState())
         {
         case StD:
@@ -238,8 +244,14 @@
         if(settingsGetPointer()->design == 4)
             return;
 
-        if(settingsGetPointer()->design == 3)
+        if(settingsGetPointer()->design == 3)	/* switch back to t7 (standard) view */
+        {
             settingsGetPointer()->design = 7;
+        	if(settingsGetPointer()->MotionDetection == MOTION_DETECT_SECTOR)
+        	{
+        		DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch,CUSTOMER_DEFINED_VIEWS);
+        	}
+        }
 
         switch(get_globalState())
         {
@@ -330,20 +342,20 @@
 }
 
 
-void tHome_change_customview_button_pressed(void)
+void tHome_change_customview_button_pressed(uint8_t action)
 {
     tHome_tick_count_cview = 0;
     if(settingsGetPointer()->design == 7)
-        t7_change_customview();
+        t7_change_customview(action);
     else
     if(settingsGetPointer()->design == 3)
-        t3_change_customview();
+        t3_change_customview(action);
     else
     if(settingsGetPointer()->design == 5)
-        t5_change_customview();
+        t5_change_customview(action);
     else
     if(settingsGetPointer()->design == 6)
-        t6_change_customview();
+        t6_change_customview(action);
 }
 
 
--- a/Discovery/Src/tMenu.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/tMenu.c	Sun Nov 24 15:46:58 2019 +0000
@@ -315,7 +315,7 @@
 }
 
 
-static void tM_build_page(uint32_t id, char *text, uint16_t tab, char *subtext)
+void tM_build_page(uint32_t id, char *text, uint16_t tab, char *subtext)
 {
     uint8_t linesFound;
     uint16_t i;
--- a/Discovery/Src/tMenuEditSystem.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/tMenuEditSystem.c	Sun Nov 24 15:46:58 2019 +0000
@@ -38,12 +38,12 @@
 #include "tMenu.h"
 #include "tMenuEdit.h"
 #include "tMenuSystem.h"
+#include "Motion.h"
 #include "t7.h"
 
-/* uncomment to activate debug view option */
+
+#define CV_SUBPAGE_MAX		(2u)	/* max number of customer view selection pages */
 /*#define HAVE_DEBUG_VIEW */
-
-/* Private variables ---------------------------------------------------------*/
 static uint8_t infoPage = 0;
 
 /* Private function prototypes -----------------------------------------------*/
@@ -82,6 +82,7 @@
 uint8_t OnAction_CornerTimeout (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 uint8_t OnAction_CornerStandard(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 uint8_t OnAction_ExtraDisplay	 (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
+uint8_t OnAction_MotionCtrl	 (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 
 uint8_t OnAction_Exit					(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
 uint8_t OnAction_Confirm			(uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action);
@@ -154,12 +155,38 @@
 
 void openEdit_CustomviewDivemode(uint8_t line)
 {
+	static uint8_t customviewsSubpage = 0;
 	SSettings *pSettings = settingsGetPointer();
 	extern _Bool WriteSettings;
+	char text[MAX_PAGE_TEXTSIZE];
+	uint16_t tabPosition;
+	uint32_t id;
 
-    pSettings->cv_configuration ^= 1 << (cv_changelist[line-1]);
-    WriteSettings = 1;
-    exitMenuEdit_to_Menu_with_Menu_Update();
+
+	if((line == 6) || (cv_changelist[customviewsSubpage * 5 + line-1] == CVIEW_END))		/* select next set of views */
+	{
+		customviewsSubpage++;
+		if(customviewsSubpage == CV_SUBPAGE_MAX)
+		{
+			customviewsSubpage = 0;
+		}
+		set_CustomsviewsSubpage(customviewsSubpage);
+		/* rebuild the selection page with the next set of customer views */
+		id = tMSystem_refresh(0, text, &tabPosition, NULL);
+		tM_build_page(id, text, tabPosition, NULL);
+		openMenu(0);
+	}
+	else
+	{
+		pSettings->cv_configuration ^= 1 << (cv_changelist[customviewsSubpage * 5 + line-1]);
+		if(t7_GetEnabled_customviews() == 0)
+		{
+			pSettings->cv_configuration ^= (1 << CVIEW_noneOrDebug);
+		}
+		WriteSettings = 1;
+		InitMotionDetection(); /* consider new view setup for view selection by motion */
+		exitMenuEdit_to_Menu_with_Menu_Update();
+	}
 }
 
 
@@ -744,6 +771,7 @@
     write_field_button(StMSYS4_CornerStandard,		400, 700, ME_Y_LINE4,  &FontT48, "");
 
     write_field_button(StMSYS4_ExtraDisplay,		400, 700, ME_Y_LINE5,  &FontT48, "");
+    write_field_button(StMSYS4_MotionCtrl,			400, 700, ME_Y_LINE6,  &FontT48, "");
 
     setEvent(StMSYS4_CViewTimeout,		(uint32_t)OnAction_CViewTimeout);
     setEvent(StMSYS4_CViewStandard,		(uint32_t)OnAction_CViewStandard);
@@ -752,6 +780,7 @@
     setEvent(StMSYS4_CornerStandard,	(uint32_t)OnAction_CornerStandard);
 
     setEvent(StMSYS4_ExtraDisplay,		(uint32_t)OnAction_ExtraDisplay);
+    setEvent(StMSYS4_MotionCtrl,		(uint32_t)OnAction_MotionCtrl);
 }
 
 
@@ -913,6 +942,34 @@
     text[6] = 0;
     write_label_var(  30, 700, ME_Y_LINE5, &FontT48, text);
 
+
+    /* MotionCtrl */
+    text[0] = TXT_2BYTE;
+    text[1] = TXT2BYTE_MotionCtrl;
+    text[2] = ' ';
+    text[3] = ' ';
+    text[4] = TXT_2BYTE;
+    switch(settingsGetPointer()->MotionDetection)
+    {
+		case MOTION_DETECT_OFF:
+			text[5] = TXT2BYTE_MoCtrlNone;
+			break;
+		case MOTION_DETECT_MOVE:
+			text[5] = TXT2BYTE_MoCtrlPitch;
+			break;
+		case MOTION_DETECT_SECTOR:
+			text[5] = TXT2BYTE_MoCtrlSector;
+			break;
+		case MOTION_DETECT_SCROLL:
+			text[5] = TXT2BYTE_MoCtrlScroll;
+					break;
+		default:
+			snprintf(&text[4],2,"%u",settingsGetPointer()->MotionDetection);
+		break;
+    }
+    text[6] = 0;
+    write_label_var(  30, 700, ME_Y_LINE6, &FontT48, text);
+
     write_buttonTextline(TXT2BYTE_ButtonBack,TXT2BYTE_ButtonEnter,TXT2BYTE_ButtonNext);
 }
 
@@ -1051,6 +1108,32 @@
 }
 
 
+uint8_t OnAction_MotionCtrl	 (uint32_t editId, uint8_t blockNumber, uint8_t digitNumber, uint8_t digitContent, uint8_t action)
+{
+    uint8_t newValue;
+    switch(settingsGetPointer()->MotionDetection)
+    {
+    case MOTION_DETECT_OFF:
+        newValue = MOTION_DETECT_MOVE;
+        break;
+    case MOTION_DETECT_MOVE:
+        newValue = MOTION_DETECT_SECTOR;
+        break;
+    case MOTION_DETECT_SECTOR:
+        newValue = MOTION_DETECT_SCROLL;
+        break;
+    case MOTION_DETECT_SCROLL:
+    	newValue = MOTION_DETECT_OFF;
+    	break;
+    default:
+        newValue = MOTION_DETECT_OFF;
+        break;
+    }
+    settingsGetPointer()->MotionDetection = newValue;
+    InitMotionDetection();
+    return UNSPECIFIC_RETURN;
+}
+
 void openEdit_Information(void)
 {
     char text[70];
--- a/Discovery/Src/tMenuSystem.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/tMenuSystem.c	Sun Nov 24 15:46:58 2019 +0000
@@ -31,14 +31,22 @@
 #include "tMenuSystem.h"
 #include "tHome.h"  // for enum CUSTOMVIEWS and init_t7_compass()
 
+static uint8_t customviewsSubpage = 0;
+
 /* Private function prototypes -----------------------------------------------*/
 char customview_TXT2BYTE_helper(uint8_t customViewId);
 
+void set_CustomsviewsSubpage(uint8_t page)
+{
+	customviewsSubpage = page;
+}
+
 /* Exported functions --------------------------------------------------------*/
 
 uint32_t tMSystem_refresh(uint8_t line, char *text, uint16_t *tab, char *subtext)
 {
     SSettings *data;
+    int i;
     uint8_t textPointer;
     uint8_t dateFormat;
     uint8_t RTEhigh, RTElow;
@@ -56,18 +64,33 @@
     {
         uint8_t id;
 
-        for(int i=0; i<6;i++)
+        for(i=0; i<5;i++)		/* fill maximum 5 items and leave last one for sub page selection */
         {
-            id = cv_changelist[i];
-            text[textPointer++] = '\006' - CHECK_BIT_THOME(data->cv_configuration,id);
-            text[textPointer++] = ' ';
-            textPointer += snprintf(&text[textPointer], 60,
-                "%c%c\n\r",
-                TXT_2BYTE, customview_TXT2BYTE_helper(id)
-            );
+        	id = cv_changelist[customviewsSubpage * 5 + i];
+        	if(id == CVIEW_END)		/* last list item? */
+        	{
+        		break;
+        	}
+        	else
+        	{
+				text[textPointer++] = '\006' - CHECK_BIT_THOME(data->cv_configuration,id);
+				text[textPointer++] = ' ';
+				textPointer += snprintf(&text[textPointer], 60,
+					"%c%c\n\r",
+					TXT_2BYTE, customview_TXT2BYTE_helper(id));
+        	}
         }
+        text[textPointer++] = TXT_2BYTE;
+        text[textPointer++] = TXT2BYTE_ButtonNext;
         text[textPointer] = 0;
 
+        for(;i<5;i++)	/* clear empty lines in case menu shows less than 5 entries */
+        {
+        	text[textPointer++]='\n';
+        	text[textPointer++]='\r';
+        	text[textPointer] = 0;
+        }
+
         return StMSYS;
     }
 
@@ -300,6 +323,7 @@
         text = TXT2BYTE_Summary;
         break;
     case CVIEW_noneOrDebug:
+    	text = TXT2BYTE_DispNoneDbg;
         break;
     default:
         break;
--- a/Discovery/Src/text_multilanguage.c	Sun Nov 24 16:08:29 2019 +0100
+++ b/Discovery/Src/text_multilanguage.c	Sun Nov 24 15:46:58 2019 +0000
@@ -1269,6 +1269,37 @@
 static uint8_t text_IT_ExtraNone[] = "no";
 static uint8_t text_ES_ExtraNone[] = "ninguno";
 
+/* Menu SYS2 - Strings for Motion Control Selection */
+static uint8_t text_EN_MotionCtrl[] = "Motion Control";
+static uint8_t text_DE_MotionCtrl[] = "Bew. Steuerung";
+static uint8_t text_FR_MotionCtrl[] = "Motion Control";
+static uint8_t text_IT_MotionCtrl[] = "Motion Control";
+static uint8_t text_ES_MotionCtrl[] = "Motion Control";
+
+static uint8_t text_EN_MoCtrlNone[] = "Off";
+static uint8_t text_DE_MoCtrlNone[] = "Aus";
+static uint8_t text_FR_MoCtrlNone[] = "Off";
+static uint8_t text_IT_MoCtrlNone[] = "Off";
+static uint8_t text_ES_MoCtrlNone[] = "Off";
+
+static uint8_t text_EN_MoCtrlPitch[] = "Pitch move";
+static uint8_t text_DE_MoCtrlPitch[] = "Nickbewegung";
+static uint8_t text_FR_MoCtrlPitch[] = "Pitch move";
+static uint8_t text_IT_MoCtrlPitch[] = "Pitch move";
+static uint8_t text_ES_MoCtrlPitch[] = "Pitch move";
+
+static uint8_t text_EN_MoCtrlSector[] = "Sector";
+static uint8_t text_DE_MoCtrlSector[] = "Sektoren";
+static uint8_t text_FR_MoCtrlSector[] = "Sector";
+static uint8_t text_IT_MoCtrlSector[] = "Sector";
+static uint8_t text_ES_MoCtrlSector[] = "Sector";
+
+static uint8_t text_EN_MoCtrlScroll[] = "Scroll";
+static uint8_t text_DE_MoCtrlScroll[] = "Karussell";
+static uint8_t text_FR_MoCtrlScroll[] = "Scroll";
+static uint8_t text_IT_MoCtrlScroll[] = "Scroll";
+static uint8_t text_ES_MoCtrlScroll[] = "Scroll";
+
 // Menu SYS2 Reset RTE and Firmware Update During Bluetooth Connection
 static uint8_t text_EN_DecoDataLost[] = "Decompression data will be lost";
 static uint8_t text_DE_DecoDataLost[] = "Dekompressionsdaten verloren!";
@@ -1322,6 +1353,12 @@
 static uint8_t text_IT_Summary[] = "Tutto schermo";
 static uint8_t text_ES_Summary[] = "VisiĆ³n general";
 
+static uint8_t text_EN_DispNoneDbg[] = "Debug/None";
+static uint8_t text_DE_DispNoneDbg[] = "Debug/Leer";
+static uint8_t text_FR_DispNoneDbg[] = "Debug/None";
+static uint8_t text_IT_DispNoneDbg[] = "Debug/None";
+static uint8_t text_ES_DispNoneDbg[] = "Debug/None";
+
 static uint8_t text_EN_ApneaTotal[] = "total";
 static uint8_t text_DE_ApneaTotal[] = "gesamt";
 static uint8_t text_FR_ApneaTotal[] = "";
@@ -1710,6 +1747,11 @@
     {(uint8_t)TXT2BYTE_ExtraBigFont,	{text_EN_ExtraBigFont, text_DE_ExtraBigFont, text_FR_ExtraBigFont, text_IT_ExtraBigFont, text_ES_ExtraBigFont}},
     {(uint8_t)TXT2BYTE_ExtraDecoGame,	{text_EN_ExtraDecoGame, text_DE_ExtraDecoGame, text_FR_ExtraDecoGame, text_IT_ExtraDecoGame, text_ES_ExtraDecoGame}},
     {(uint8_t)TXT2BYTE_ExtraNone,		{text_EN_ExtraNone, text_DE_ExtraNone, text_FR_ExtraNone, text_IT_ExtraNone, text_ES_ExtraNone}},
+	{(uint8_t)TXT2BYTE_MotionCtrl,		{text_EN_MotionCtrl, text_DE_MotionCtrl, text_FR_MotionCtrl, text_IT_MotionCtrl, text_ES_MotionCtrl}},
+	{(uint8_t)TXT2BYTE_MoCtrlNone,		{text_EN_MoCtrlNone, text_DE_MoCtrlNone, text_FR_MoCtrlNone, text_IT_MoCtrlNone, text_ES_MoCtrlNone}},
+	{(uint8_t)TXT2BYTE_MoCtrlPitch,		{text_EN_MoCtrlPitch, text_DE_MoCtrlPitch, text_FR_MoCtrlPitch, text_IT_MoCtrlPitch, text_ES_MoCtrlPitch}},
+	{(uint8_t)TXT2BYTE_MoCtrlSector,	{text_EN_MoCtrlSector, text_DE_MoCtrlSector, text_FR_MoCtrlSector, text_IT_MoCtrlSector, text_ES_MoCtrlSector}},
+	{(uint8_t)TXT2BYTE_MoCtrlScroll,	{text_EN_MoCtrlScroll, text_DE_MoCtrlScroll, text_FR_MoCtrlScroll, text_IT_MoCtrlScroll, text_ES_MoCtrlScroll}},
     {(uint8_t)TXT2BYTE_DecoDataLost,	{text_EN_DecoDataLost, text_DE_DecoDataLost, text_FR_DecoDataLost, text_IT_DecoDataLost, text_ES_DecoDataLost}},
     {(uint8_t)TXT2BYTE_Info,			{text_EN_Info, text_DE_Info, text_FR_Info, text_IT_Info, text_ES_Info}},
     {(uint8_t)TXT2BYTE_Korrekturwerte,  {text_EN_Korrekturwerte, text_DE_Korrekturwerte, text_FR_Korrekturwerte, text_IT_Korrekturwerte, text_ES_Korrekturwerte}},
@@ -1725,6 +1767,7 @@
     {(uint8_t)TXT2BYTE_ButtonMitte,		{text_EN_ButtonMitte, text_DE_ButtonMitte, text_FR_ButtonMitte, text_IT_ButtonMitte, text_ES_ButtonMitte}},
     {(uint8_t)TXT2BYTE_ButtonRight,		{text_EN_ButtonRight, text_DE_ButtonRight, text_FR_ButtonRight, text_IT_ButtonRight, text_ES_ButtonRight}},
     {(uint8_t)TXT2BYTE_Summary,			{text_EN_Summary, text_DE_Summary, text_FR_Summary, text_IT_Summary, text_ES_Summary}},
+	{(uint8_t)TXT2BYTE_DispNoneDbg,     {text_EN_DispNoneDbg, text_DE_DispNoneDbg, text_FR_DispNoneDbg, text_IT_DispNoneDbg, text_ES_DispNoneDbg}},
     {(uint8_t)TXT2BYTE_ApneaLast,		{text_EN_ApneaLast, text_DE_ApneaLast, text_FR_ApneaLast, text_IT_ApneaLast, text_ES_ApneaLast}},
     {(uint8_t)TXT2BYTE_ApneaTotal,		{text_EN_ApneaTotal, text_DE_ApneaTotal, text_FR_ApneaTotal, text_IT_ApneaTotal, text_ES_ApneaTotal}},
     {(uint8_t)TXT2BYTE_ApneaSurface,	{text_EN_ApneaSurface, text_DE_ApneaSurface, text_FR_ApneaSurface, text_IT_ApneaSurface, text_ES_ApneaSurface}},