changeset 372:75eedde05ff6 MotionDetection

merged default into MotionDetection
author Ideenmodellierer
date Mon, 19 Aug 2019 17:50:55 +0200
parents fca370f847f8 (diff) 0756013e43b3 (current diff)
children 7b981f8bdd41
files Common/Inc/settings.h Current build/OSTC4update_190720.bin Discovery/Src/settings.c Discovery/Src/t7.c
diffstat 14 files changed, 597 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- a/Common/Inc/settings.h	Mon Aug 19 11:42:31 2019 +0000
+++ b/Common/Inc/settings.h	Mon Aug 19 17:50:55 2019 +0200
@@ -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	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Inc/base.h	Mon Aug 19 17:50:55 2019 +0200
@@ -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	Mon Aug 19 17:50:55 2019 +0200
@@ -0,0 +1,47 @@
+/*
+ * 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 numer of selected views */
+
+typedef enum
+{
+		MOTION_DETECT_OFF = 0,
+		MOTION_DETECT_SECTOR,
+		MOTION_DETECT_MOVE
+} 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 upperlimit;
+    float lowerlimit;
+} SSector;
+
+void InitMotionDetection(void);
+void DefinePitchSectors(float centerAngle, uint8_t numOfSectors);
+detectionState_t detectPitch(float currentPitch);
+detectionState_t detectSectorButtonEvent(float curPitch);
+
+#endif /* INC_MOTION_H_ */
--- a/Discovery/Inc/t7.h	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Inc/t7.h	Mon Aug 19 17:50:55 2019 +0200
@@ -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	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Inc/tHome.h	Mon Aug 19 17:50:55 2019 +0200
@@ -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);
--- a/Discovery/Inc/tStructure.h	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Inc/tStructure.h	Mon Aug 19 17:50:55 2019 +0200
@@ -284,8 +284,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	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Inc/text_multilanguage.h	Mon Aug 19 17:50:55 2019 +0200
@@ -274,6 +274,11 @@
 		TXT2BYTE_ExtraDecoGame,
 		TXT2BYTE_ExtraNone,
 		/* */
+		TXT2BYTE_MotionCtrl,
+		TXT2BYTE_MoCtrlNone,
+		TXT2BYTE_MoCtrlPitch,
+		TXT2BYTE_MoCtrlSector,
+		/* */
 		TXT2BYTE_DecoDataLost,
 		TXT2BYTE_Info,
 		TXT2BYTE_Korrekturwerte,
--- a/Discovery/Src/base.c	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/base.c	Mon Aug 19 17:50:55 2019 +0200
@@ -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,26 @@
 	        DoDisplayRefresh = 0;
         	RefreshDisplay();
 
+        	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;
+        		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 +542,9 @@
     }
 }
 
+
+
+
 //  ===============================================================================
 //	timer IRQ
 /// @brief	this is called periodically
@@ -817,12 +852,7 @@
 		break;
 	}
 }
-static uint8_t ButtonAction = ACTION_END;
 
-static void StoreButtonAction(uint8_t action)
-{
-	ButtonAction = action;
-}
 
 static void TriggerButtonAction()
 {
@@ -866,14 +896,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_SECTOR) && (action == ACTION_BUTTON_ENTER))  /* Button pressed while sector detection is active => calibrate to current pitch value */
+							{
+								DefinePitchSectors(stateRealGetPointer()->lifeData.compass_pitch,CUSTOMER_DEFINED_VIEWS);
+							}
+						}
+						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	Mon Aug 19 17:50:55 2019 +0200
@@ -0,0 +1,267 @@
+/*
+ * motion.c
+ *
+ *  Created on: 20.05.2019
+ *      Author: Thorsten Sonntag
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <math.h>
+#include "motion.h"
+#include "data_central.h"
+#include "t7.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 MOVE_DELTA_SPEED			4	/* Delta speed needed to identify a valid movement */
+#define PITCH_DELTA_COUNT			10	/* Delta count needed to identify a valid minima / maxima */
+#define PITCH_DELTA_END				10	/* Delta allowed between start and end position */
+
+
+#define SECTOR_WINDOW				40.0  	/* Pitch window which is used for custom view projection */
+#define SECTOR_HYSTERY				3		/* 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					10		/* maximum number of sectors */
+
+static detectionState_t detectionState = DETECT_NOTHING;
+
+static uint8_t curSector;
+static uint8_t targetSector;
+static uint8_t sectorSize;
+static uint8_t sectorCount;
+
+SSector PitchSector[10];			/* max number of enabled custom views */
+
+
+uint8_t GetSectorForPitch(float pitch)
+{
+	static float lastPitch = 1000;
+	float newPitch;
+	uint8_t index;
+	uint8_t sector = 0;
+
+	if(lastPitch == 1000)						/* init at first call */
+	{
+		lastPitch = pitch;
+	}
+
+	newPitch = lastPitch + (pitch / SECTOR_FILTER);
+
+	for(index = 1; index < sectorCount; index++)
+	{
+		if((pitch < PitchSector[index].upperlimit) && (pitch > PitchSector[index].lowerlimit ))
+		{
+			sector = index;
+			break;
+		}
+	}
+	lastPitch = newPitch;
+	return sector;
+}
+
+void DefinePitchSectors(float centerPitch,uint8_t numOfSectors)
+{
+	uint8_t index;
+
+	if(numOfSectors == CUSTOMER_DEFINED_VIEWS)
+	{
+		sectorCount =  t7_GetEnabled_customviews();
+		if(sectorCount > 5)
+		{
+			sectorCount = 5;	/* more views are hard to manually control */
+		}
+	}
+	else
+	{
+		sectorCount = numOfSectors;
+	}
+	sectorSize = SECTOR_WINDOW / sectorCount;
+
+	PitchSector[0].upperlimit = centerPitch + (SECTOR_WINDOW / 2);
+	PitchSector[0].lowerlimit = PitchSector[0].upperlimit - sectorSize - SECTOR_HYSTERY;
+
+	for(index = 1; index < sectorCount; index++)
+	{
+		PitchSector[index].upperlimit = PitchSector[0].upperlimit - index * sectorSize + SECTOR_HYSTERY;
+		PitchSector[index].lowerlimit = PitchSector[0].upperlimit - (index + 1) * sectorSize - SECTOR_HYSTERY;
+	}
+
+	PitchSector[0].upperlimit = SECTOR_BORDER;
+	PitchSector[index - 1].lowerlimit = SECTOR_BORDER * -1.0;
+
+/* get the current sector */
+	curSector = GetSectorForPitch(stateRealGetPointer()->lifeData.compass_pitch);
+	targetSector = curSector;
+}
+
+void InitMotionDetection(void)
+{
+	targetSector = 0;
+	curSector = 0;
+	sectorSize = 0;
+	sectorCount = 0;
+
+	switch(settingsGetPointer()->MotionDetection)
+	{
+		case MOTION_DETECT_SECTOR: DefinePitchSectors(0,CUSTOMER_DEFINED_VIEWS);
+			break;
+		case MOTION_DETECT_MOVE: DefinePitchSectors(0,SECTOR_MAX);
+			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)
+	{
+		targetSector = newTargetSector;
+	}
+	lastTargetSector = 	newTargetSector;
+	if(targetSector != curSector)
+	{
+		 if(targetSector > curSector)
+		 {
+			 curSector++;
+			PitchEvent = DETECT_POS_PITCH;
+		 }
+		 else
+		 {
+			 curSector--;
+			 PitchEvent = DETECT_NEG_PITCH;
+		 }
+	}
+	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 stableCnt = 0;
+	static float lastPitch = 0.0;
+	static float startPitch = 0.0;
+	float curSpeed;
+
+
+	if((detectionState == DETECT_NEG_PITCH) || (detectionState == DETECT_POS_PITCH))	/* discard last detection */
+	{
+		detectionState = DETECT_NOTHING;
+	}
+
+	curSpeed = currentPitch - lastPitch;
+
+	/* feed value into state machine */
+	switch (detectionState)
+	{
+			case DETECT_NOTHING: 	if(fabsf(curSpeed) < MOVE_DELTA_SPEED)	/* detect a stable condition before evaluating for the next move */
+									{
+										stableCnt++;
+									}
+									else
+									{
+										stableCnt=0;
+									}
+
+									if(stableCnt > STABLE_STATE_COUNT)
+									{
+										detectionState = DETECT_START;
+										stableCnt = 0;
+									}
+				break;
+			case DETECT_START:		if(fabsf(curSpeed) > MOVE_DELTA_SPEED)
+									{
+										if(curSpeed > 0)
+										{
+											detectionState = DETECT_POS_MOVE;
+										}
+										else
+										{
+											detectionState = DETECT_NEG_MOVE;
+										}
+										stableCnt = 0;
+										startPitch = lastPitch;
+									}
+				break;
+			case DETECT_NEG_MOVE:
+			case DETECT_POS_MOVE:	if(fabsf(curSpeed) > MOVE_DELTA_SPEED )
+									{
+										stableCnt++;
+									}
+									else
+									{
+										if(stableCnt >= STABLE_STATE_COUNT)	/* debounce movement */
+										{
+											if(fabsf(startPitch - currentPitch) > PITCH_DELTA_COUNT)
+											{
+												detectionState++;
+											}
+											else
+											{
+												detectionState = DETECT_NOTHING;
+											}
+										}
+										else
+										{
+											detectionState = DETECT_NOTHING;
+										}
+										stableCnt = 0;
+									}
+				break;
+			case DETECT_MINIMA:
+			case DETECT_MAXIMA:		/* stay at maximum for short time to add a pattern for user interaction */
+									if(fabsf(curSpeed) < MOVE_DELTA_SPEED )
+									{
+										stableCnt++;
+									}
+									else
+									{
+										if(stableCnt > 0)
+										{
+											detectionState++;
+										}
+										else
+										{
+											detectionState = DETECT_NOTHING;
+										}
+										stableCnt = 0;
+									}
+				break;
+			case DETECT_RISEBACK:
+			case DETECT_FALLBACK:	if(fabsf(curSpeed) < MOVE_DELTA_SPEED)
+									{
+										if(fabsf(startPitch - currentPitch) < PITCH_DELTA_END)
+										{
+											detectionState++;
+										}
+									}
+									stableCnt++;
+				break;
+			default:
+				detectionState = DETECT_NOTHING;
+				break;
+
+	}
+	if(stableCnt > STABLE_STATE_TIMEOUT)
+	{
+		detectionState = DETECT_NOTHING;
+		stableCnt = 0;
+	}
+
+	lastPitch = currentPitch;
+	return detectionState;
+}
--- a/Discovery/Src/settings.c	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/settings.c	Mon Aug 19 17:50:55 2019 +0200
@@ -82,7 +82,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 +307,7 @@
     .FactoryButtonBalance[2] = 3,
 	.FlipDisplay = 0,
 	.cv_configuration = 0xFFFFFFFF,
+	.MotionDetection = 0,
 };
 
 /* Private function prototypes -----------------------------------------------*/
@@ -353,6 +354,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 +452,9 @@
     case 0xFFFF0018:
     	pSettings->cv_configuration = 0xFFFFFFFF;
     	// no break
+    case 0xFFFF0019:
+    	pSettings->MotionDetection = 0;
+    	// no break
     default:
         pSettings->header = pStandard->header;
         break; // no break before!!
@@ -1347,6 +1352,11 @@
     	Settings.FlipDisplay = 0;
 	    corrections++;
    	}
+    if(Settings.MotionDetection > 2) /* At the moment only two detection functions available */
+   	{
+    	Settings.MotionDetection = 0;
+	    corrections++;
+   	}
 
     if(corrections > 255)
         return 255;
@@ -1399,7 +1409,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/t7.c	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/t7.c	Mon Aug 19 17:50:55 2019 +0200
@@ -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);
@@ -1495,9 +1499,47 @@
             selection_customview = settingsGetPointer()->tX_customViewPrimary;
 }
 
-void t7_change_customview(void)
+uint8_t t7_GetEnabled_customviews()
 {
-    const uint8_t *pViews;
+    uint8_t *pViews;
+    uint8_t increment = 1;
+
+    uint8_t enabledViewCnt = 0;
+    uint32_t cv_config = settingsGetPointer()->cv_configuration;
+
+    if(stateUsed->mode == MODE_DIVE)
+        pViews = customviewsDive;
+    else
+        pViews = customviewsSurface;
+
+    while((*pViews != CVIEW_END))
+    {
+    	increment = 1;
+    /* check if view is enabled */
+        for(int i=0;i<6;i++)
+        {
+             if((*pViews == cv_changelist[i]) && !CHECK_BIT_THOME(cv_config, (1 << cv_changelist[i])))
+             {
+            	 increment = 0;
+                   break;
+             }
+        }
+        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)
+{
+    uint8_t *pViews;
+    uint8_t *pStartView,*pCurView, *pLastView;
     _Bool cv_disabled = 0;
 
     if(stateUsed->mode == MODE_DIVE)
@@ -1505,54 +1547,83 @@
     else
         pViews = customviewsSurface;
 
-    while((*pViews != CVIEW_END) && (*pViews != selection_customview))
-        {pViews++;}
-
-    if(*pViews < CVIEW_END)
-        pViews++;
-
-
-    if(*pViews == CVIEW_END)
+    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;
+        for(int i=0;i<6;i++)
         {
-            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;
+             }
+        }
+
+        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;
 }
 
@@ -1586,11 +1657,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	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/tHome.c	Mon Aug 19 17:50:55 2019 +0200
@@ -42,6 +42,7 @@
 #include "tMenuEditGasOC.h" // for openEdit_DiveSelectBetterGas()
 #include "tMenuEditSetpoint.h" // for openEdit_DiveSelectBetterSetpoint()
 #include "simulation.h"
+#include "motion.h"
 
 /* Private types -------------------------------------------------------------*/
 
@@ -330,11 +331,11 @@
 }
 
 
-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();
--- a/Discovery/Src/tMenuEditSystem.c	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/tMenuEditSystem.c	Mon Aug 19 17:50:55 2019 +0200
@@ -36,9 +36,9 @@
 #include "settings.h" // for getLicence()
 #include "tHome.h"  // for enum CUSTOMVIEWS and init_t7_compass()
 #include "tMenuEdit.h"
+#include "Motion.h"
 
 /* Private variables ---------------------------------------------------------*/
-
 uint8_t infoPage = 0;
 
 /* Private function prototypes -----------------------------------------------*/
@@ -77,6 +77,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);
@@ -732,9 +733,10 @@
     write_field_button(StMSYS4_CViewStandard,		400, 700, ME_Y_LINE2,  &FontT48, "");
 
     write_field_button(StMSYS4_CornerTimeout,		400, 700, ME_Y_LINE3,  &FontT48, "");
-    write_field_button(StMSYS4_CornerStandard,	400, 700, ME_Y_LINE4,  &FontT48, "");
+    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);
@@ -743,6 +745,7 @@
     setEvent(StMSYS4_CornerStandard,	(uint32_t)OnAction_CornerStandard);
 
     setEvent(StMSYS4_ExtraDisplay,		(uint32_t)OnAction_ExtraDisplay);
+    setEvent(StMSYS4_MotionCtrl,		(uint32_t)OnAction_MotionCtrl);
 }
 
 
@@ -904,6 +907,31 @@
     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;
+		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);
 }
 
@@ -1042,6 +1070,28 @@
 }
 
 
+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 0:
+        newValue = 1;
+        break;
+    case 1:
+        newValue = 2;
+        break;
+    case 2:
+        newValue = 0;
+        break;
+    default:
+        newValue = 0;
+        break;
+    }
+    settingsGetPointer()->MotionDetection = newValue;
+    return UNSPECIFIC_RETURN;
+}
+
 void openEdit_Information(void)
 {
     char text[70];
--- a/Discovery/Src/text_multilanguage.c	Mon Aug 19 11:42:31 2019 +0000
+++ b/Discovery/Src/text_multilanguage.c	Mon Aug 19 17:50:55 2019 +0200
@@ -1262,6 +1262,32 @@
 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";
+
+
 // 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!";
@@ -1716,6 +1742,10 @@
     {(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_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}},