The HexiHeart is a demo project product that takes advantage of many of the onboard Hexiwear sensors and capabilities to create a multifunctional fitness and safety watch.

Dependencies:   FXAS21002 FXOS8700 Hexi_KW40Z Hexi_OLED_SSD1351 MAXIM W25Q64FVSSIG HTU21D MPL3115A2 TSL2561

Fork of HexiHeart_Alex by Hexiwear_zeta

Files at this revision

API Documentation at this revision

Comitter:
nbaker
Date:
Mon Apr 09 13:31:46 2018 +0000
Parent:
12:fd39a7983e06
Child:
14:c3b080cdf36b
Commit message:
v2.12 - Added hidden reset feature (push L-button 9+ times to reset), added line that might put K64 into low pow run mode, added dimming feature, changed humid/temp & battery measurement to a rolling average. Made new screen for panic alert.

Changed in this revision

main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/main.cpp	Thu Mar 29 16:55:40 2018 +0000
+++ b/main.cpp	Mon Apr 09 13:31:46 2018 +0000
@@ -20,14 +20,18 @@
 Display data screen update routines
 
 **************   Versions  ****************
-v2.11 - Added Send_Alert(0) to turn off alerts by sending amb_light=0, 
+v2.12 - Added hidden reset feature (push left button 9+ times, on screen zero, to reset), added line that 
+might put K64 into low power run mode, added dimming feature to display, changed humid/temp and battery 
+measurement to a rolling average. Made new screen for sending panic alert.
+
+v2.11 - 4/1/18 - Added Send_Alert(0) to turn off alerts by sending amb_light=0, 
 added WDT and added WDT testing screens, changed fall Min_Movement_duration 
 from 60s to 10s, added subtle vibration after impact for diagnostic purposes.
 
 v2.10 - Adding BLE pairing code, spoofing amb light sensor data for alert status 
 light=10 =>Panic Alert, 20=Fall+asked for help, 30=Fall+No response, 40=?...
 
-v2.09 - Added final fall mode (full sequential fall algorithm), including alert screen 
+v2.09 - 3/25/18 - Added final fall mode (full sequential fall algorithm), including alert screen 
 and dismiss alert screen.  Added FAP (Fall Alert Protection) to main screen. fixed "aggressive Haptic" problem by using a Ticker to 
 turn off Haptic instead of RTOS timer.
 
@@ -63,11 +67,11 @@
 
 
 //***************  Definitions
-#define SW_Ver          2.11    // For displaying software version
+#define SW_Ver          2.12    // For displaying software version
 #define LED_ON          0
 #define LED_OFF         1
 #define SCRN_TIME       10.0    // Set OLED screen turn off time to 10.0 seconds
-#define WDT_TIME        1.5     // Set Watch Dog timer to 1.5 seconds (1.0s reset in certain subroutines)
+#define WDT_TIME        2.0     // Set Watch Dog timer to 1.5 seconds (1.5s reset in certain subroutines)
 #define Debug           1       // If "Debug" is defined, our code will compile for debug.  Comment out for Production code.
 #define HIGHEST_ZONE    4       // Highest heart rate zone
 #define LOWEST_ZONE     1
@@ -81,6 +85,7 @@
 //#define TSL2561_I2C_ADDRESS_  (0x29 << 1) // Address select line is grounded
 //#define MPL3115A2_I2C_ADDRESS_  ? // 
 
+
 void StartHaptic(void);
 void Haptic_Off_(void); // added by NRB
 void StartHaptic(int x);
@@ -88,6 +93,7 @@
 void error_screen(void);  // display error screen 
 void update_display(void);// Screen lables refreshed
 void update_display_date(void);  // Screen data(only)refreshed 
+void Screen_timer1(void);
 void Decrement_Age();
 void Set_Max_Bpm();
 void Set_Zone_Boundaries();
@@ -121,10 +127,14 @@
 void motion_detect();           // Interupt routine
 void motion_detect_debug();     // Interupt routine
 void chkmotion(void);           // Routine used with Ticker
-void chk_help_needed(void);      // Routine used with Ticker
+void chk_help_needed(void);     // Routine used with Ticker
 void txTask(void);
+void PassKey(void);
 void MAX30101_test_config(uint8_t);
-void Send_Alert(uint8_t);    // fuction to store and send alert
+void Send_Alert(uint8_t);       // function to store and send alert
+void WDT_Timeout(void);         // WDT Routine used reset
+void CLRWDT(void);              // function to clear WDT
+void UpDate_Ave(void);          // function used to update slow changing measurments
 
 // *****************  Global variables  ***********************
 char text_1[20];            // Text buffer - Do we need more?
@@ -152,6 +162,7 @@
 float Min_Movement_Time=5.0;    // Initialize Movement minimum movement time to 5 sec
 float Min_Movement_duration=10.0;    // Initialize Movement min-movement testing duration to 60 sec
 float Do_You_Need_Help_Time=10.0; // Time to dismiss "Do you need Help" screen
+uint8_t Reset_Count = 0;
 uint8_t Current_Zone = 1;
 uint8_t Prev_Zone = 1;
 uint8_t Heart_Rate = 100;
@@ -167,11 +178,14 @@
 uint8_t HR_Zone2[2] = {HR_Zone1[1] + 1, Max_Bpm * .70};       //Heart Rate Zone 2
 uint8_t HR_Zone3[2] = {HR_Zone2[1] + 1, Max_Bpm * .80};       //Heart Rate Zone 3
 uint8_t HR_Zone4[2] = {HR_Zone3[1] + 1, Max_Bpm};       //Heart Rate Zone 4
-int sample_ftemp;               // used in Heat index calc
-int sample_humid;                // used in Heat index calc
 int heat_index;                  // used in Heat index calc
 int hi_calc;                    // used in Heat index calc
 int adjustment;                 // used in Heat index calc
+// slow changing variables
+int sample_ftemp = 0;               // used in Heat index calc
+int sample_humid = 0;               // used in Heat index calc
+uint8_t batt_per_level = 0;         //
+uint8_t Ave_Num  = 0; 
 
 // Pointers for screen images 
 const uint8_t *Hexi_Heart_ = Hexi_Heart_bmp;
@@ -238,26 +252,43 @@
 
 //***************** Tickers and Timers *****************
 Ticker Screen_Timer;// use ticker to turn off OLED
-Timer f_time; // Timer used to measure fall 
-Ticker chk_fall; // Ticker used to check on active fall
-Ticker chk_motion; // Ticker used to check on post fall motion
+Timer f_time;       // Timer used to measure fall 
+Ticker chk_fall;    // Ticker used to check on active fall
+Ticker chk_motion;  // Ticker used to check on post fall motion
 Ticker Haptic_Timer;
 Ticker WDT_Timer;
 
-
 /*****************************************************************************
 Name: timout_timer()
-Purpose: Used to turn the OLED screen off after 10s to save power
-Inputs: None
-Returns: None
+Purpose: Ticker interupt routine used to dim the OLED screen 3s before turning screen off
+Inputs: Screen_Timer Ticker
 ******************************************************************************/
 void timout_timer(){ // turn off display mode
+        HexiwearBattery battery;
+        battery.sensorOn();  
+    if (battery.isBatteryCharging() || batt_per_level > 99) {
+        oled.DimScreenOFF();
+        Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged
+    } //end if
+    else {
+    Screen_Timer.attach(&Screen_timer1,(3));// Dim display for 3 seconds befor turning off display
+    oled.DimScreenON(); //Dim display if 3 seconds from turning off
+    }//end else
+}// end Screen_timer1()
+
+/*****************************************************************************
+Name: Screen_timer1(()
+Purpose: Ticker interupt routine used to turn off the OLED screen after ~13s to save power
+Inputs: Screen_Timer Ticker
+******************************************************************************/
+void Screen_timer1(){ // turn off display mode
 #ifdef Debug    // in debug keep screens on for demo  
         HexiwearBattery battery;
         battery.sensorOn();  
                               
-        if (battery.isBatteryCharging() || (uint8_t)battery.readLevelPercent()> 99) {
+        if (battery.isBatteryCharging() || batt_per_level > 99) {
            Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged
+           oled.DimScreenOFF();
         } //end if
     else {
 #endif        
@@ -271,62 +302,6 @@
 #endif   
 }//end timout_timer routine
 
-/*****************************************************************************
-Name: WDT_Timeout()
-Purpose: Interrupt routine used by Watch Dog timer Ticker. 
-Note that there are a few ways to implement a WDT. The best would be an external 
-circuit that resets the K46 if it became unresponsive. The next best would be using 
-the internal WDT that is built into microprocessor. And lastly there is this 
-method, using a Ticker/timer.
-Inputs: None
-Returns: None
-******************************************************************************/
-void WDT_Timeout(){ // turn off display mode
-    Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
-    if (OLED_ON == 0) {
-        OLED_ON = 1; // Screen was off, set to On
-    }
-    oled_text_properties_t textProperties = {0};  // Need these to change font color
-    oled.GetTextProperties(&textProperties);      // Need these to change font color
-    oled.FillScreen(COLOR_BLACK); // Clear screen
-    textProperties.font = OpenSans_12x18_Regular;  //  Max Width of Character  = 12px, Max Height of Character = 18px 
-    textProperties.fontColor = COLOR_WHITE;
-    oled.SetTextProperties(&textProperties); 
-    oled.Label((uint8_t *)"WatchDog",10,30); // Display "Back" at x,y
-    oled.Label((uint8_t *)" Reset!",20,55); // Display "Back" at x,y
-    wait(0.1);// display for 100ms
-
-    NVIC_SystemReset(); // software reset
-}//end WDT_Timeout routine
-
-
-/*****************************************************************************
-Name: CLRWDT()
-Purpose: Routine to clear/reset Watch Dog timer Ticker
-Inputs: None
-Returns: None
-******************************************************************************/
-void CLRWDT(){ // turn off display mode
-    WDT_Timer.attach(&WDT_Timeout,(WDT_TIME));//re-attach/reset WDT
-}//end WDT_Timeout routine
-
-
-/*****************************************************************************
-Name: PassKey()
-Purpose: Interrupt routine called when MK46 recieves Passkey from KW40
-Inputs: None
-Returns: None
-******************************************************************************/
-void PassKey(void)// 
-{
-    Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
-    if (OLED_ON == 0) {
-        OLED_ON = 1; // Scree was off, set to On
-    }
-        Screen_Num = 72;  //Change to screen BLE screen 72
-        StartHaptic();
-        update_display();
-}// PassKey
 
 /*****************************************************************************
 Name: ButtonUp()
@@ -337,6 +312,7 @@
 void ButtonUp(void)
 {
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    oled.DimScreenOFF();
     if (OLED_ON == 0) {
         OLED_ON = 1; // Scree was off, set to On
         update_display();
@@ -382,13 +358,9 @@
             }
             case 6: {// Panic Alert
                 StartHaptic();
-                Panic_Alert = !Panic_Alert;
-                if(Panic_Alert == 1){
+                Screen_Num = 51; 
+                Panic_Alert = 1;
                 Send_Alert(10); // send/store alert type zero
-                }//endif
-                else{
-                 Send_Alert(0);   
-                    }
                 update_display();
                 break;
             }
@@ -588,6 +560,7 @@
 void ButtonDown(void)
 {
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    oled.DimScreenOFF();
     if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On
         update_display();
@@ -834,7 +807,9 @@
 ******************************************************************************/
 void ButtonRight(void)
 {
+    Reset_Count = 0;
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    oled.DimScreenOFF();
     if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On
         update_display();
@@ -1027,13 +1002,31 @@
 void ButtonLeft(void)
 {
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    oled.DimScreenOFF();
     if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On
         update_display();
     } else {
         switch(Screen_Num) {
             case 0: {// We're in Main Screen
-                // do nothing, wrong button
+                Reset_Count++;
+                if(Reset_Count >= 8){
+                    __disable_irq();    // Disable all Interrupts
+                    oled_text_properties_t textProperties = {0};  // Need these to change font color
+                    oled.GetTextProperties(&textProperties);      // Need these to change font color
+                    textProperties.font = OpenSans_12x18_Regular;  //  Max Width of Character  = 12px, Max Height of Character = 18px 
+                    textProperties.fontColor = COLOR_WHITE;
+                    oled.SetTextProperties(&textProperties); 
+                    wait_ms(100);
+                    oled.FillScreen(COLOR_BLACK); // Clear screen
+                    wait_ms(100);
+                    oled.Label((uint8_t *)"Hidden",20,20); // Display "Back" at x,y
+                    oled.Label((uint8_t *)" Reset ",20,40); // Display "Back" at x,y
+                    oled.Label((uint8_t *)"Feature",20,60); // Display "Back" at x,y
+                    wait_ms(500);// display for 100ms
+                    NVIC_SystemReset(); // software reset
+                    wait(3.0);// should never get here
+                    }//end if
                 break;
             }
             case 1: {// Panic Alert option
@@ -1234,7 +1227,14 @@
                 update_display();
                 break;
             }       
-                          
+            case 51: {// Sending Panic Alert
+                StartHaptic();
+                Screen_Num = 6;  //Change to screen 6
+                Panic_Alert = 0;
+                Send_Alert(0); // send/store alert type zero
+                update_display();
+                break;
+            }              
              case 71: {// BLE
                 StartHaptic();
                 Screen_Num = 0;  //Change to screen 0
@@ -1266,6 +1266,7 @@
 void ButtonSlide(void)  // What is this Slide button???
 {
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    oled.DimScreenOFF();
     if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On
     }
@@ -1277,11 +1278,16 @@
 
 int main()
 {
-//   set_time(1256729737);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
- //  set_time((Year-1970)*365*24*3600+(days of this year)*24*3600+(hr)*3600 + (min)*60 + (Sec) - fudge factor);  // Set RTC time to Mon, 19 Feb 2018 10:00
-  //set_time(48*365*24*3600 + 61*24*3600 + 10*3600-4);  // Set RTC time to Mon, 19 Feb 2018 10:00
-   //set_time((2018-1970)*365.25f*24*3600 + (31+28+1-1)*24*3600 + (16)*3600 + (5)*60+ (1) + 38);  // Set RTC time to 3/01/2018 16:04:20
-    set_time((2018-1970)*365.25f*24*3600 + (31+28+26-1)*24*3600 + (10)*3600 + (0)*60+ (0) + 28);  // Set RTC time to 3/26/2018 10:00:00
+//__STATIC_INLINE void __set_PMCTRL(0b01000000);// set K64 SMC_PMCTRL register to VLPR (Very low power run) mode
+ //   SMC->PMCTRL = (uint8_t)((SYSTEM_SMC_PMCTRL_VALUE) & (SMC_PMCTRL_RUNM_MASK)); // Enable VLPR mode    
+    SMC->PMCTRL = (0b01000000);// set K64 SMC_PMCTRL register to VLPR (Very low power run) mode 
+    
+//set_time(1256729737);  // Set RTC time to Wed, 28 Oct 2009 11:35:37
+//set_time((Year-1970)*365*24*3600+(days of this year)*24*3600+(hr)*3600 + (min)*60 + (Sec) - fudge factor);  // Set RTC time to Mon, 19 Feb 2018 10:00
+//set_time(48*365*24*3600 + 61*24*3600 + 10*3600-4);  // Set RTC time to Mon, 19 Feb 2018 10:00
+//set_time((2018-1970)*365.25f*24*3600 + (31+28+1-1)*24*3600 + (16)*3600 + (5)*60+ (1) + 38);  // Set RTC time to 3/01/2018 16:04:20
+//set_time((2018-1970)*365.25f*24*3600 + (31+28+26-1)*24*3600 + (10)*3600 + (0)*60+ (0) + 28);  // Set RTC time to 3/26/2018 9:59:31
+    set_time((2018-1970)*365.25f*24*3600 + (31+28+31+18-1)*24*3600 + (10)*3600 + (0)*60+ (0) + 29);  // Set RTC time to 4/18/2018 9:59:31
     RED_Led = LED_OFF;
     GRN_Led = LED_OFF;
     BLU_Led = LED_OFF;
@@ -1388,8 +1394,9 @@
     wait(2);  // wait 3 seconds
     
    // txThread.start(txTask); /*Start transmitting Sensor Tag Data */
-    
+    oled.DimScreenOFF();
     update_display(); // Displays current screen (screen 0)
+    UpDate_Ave(); // Update slow changing measurements once every 30 seconds
     Screen_Timer.attach(&timout_timer,(SCRN_TIME)); //start ticker timer for turning off LCD
     WDT_Timer.attach(&WDT_Timeout,(WDT_TIME));      //attach/start WDT
 //  ******************* Main Loop *************************
@@ -1399,6 +1406,9 @@
     {
     Thread::wait(500);          // wait 0.5 sec each loop
     CLRWDT();
+ //   SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
+ //   __WFI();
+  //  deepsleep();
     if(OLED_PWR==1){
     update_display_date();     // refresh display date w/o updating entire display 
         }// end if
@@ -1408,11 +1418,14 @@
     RED_Led = LED_ON;    // Used only for diagnostic of wait command
     Led_clk3 = 1;         // Used only for diagnostic of wait command
     wait(0.01);          // BLIP led 1/10 sec each loop
-///    VLPW(0.01);          // BLIP led 1/10 sec each loop
+//    NVIC_VLPW(0.01);          // BLIP led 1/10 sec each loop
+//   NVIC_SystemReset(); // software reset
     RED_Led = LED_OFF;    // Used only for diagnostic of wait command
     Led_clk3 = 0; 
     Thread::wait(490);    // keep up the pace, at 0.5 sec (0.01s+0.49s) update date 
+    
     CLRWDT();
+    UpDate_Ave(); // Update slow changing measurements once every 30 seconds 
     } // end of while(true)
 
 }
@@ -1434,10 +1447,11 @@
             textProperties.fontColor = COLOR_GREEN;
             oled.SetTextProperties(&textProperties);  
   //          sprintf(text_1, "%s", "chrg");           
-            sprintf(text_1, "%i%%+", (uint8_t)battery.readLevelPercent());
+            sprintf(text_1, "%i%%+", batt_per_level);
             Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged
+            oled.DimScreenOFF();
             } else {
-            sprintf(text_1, "%i%%", (uint8_t)battery.readLevelPercent());
+            sprintf(text_1, "%i%%", batt_per_level);
             }
             oled.TextBox((uint8_t *)text_1,60,0,35,15); //show level value of battery in a 35px by 15px text box at x=60, y=0
         
@@ -1473,7 +1487,7 @@
                 textProperties.fontColor = COLOR_RED; // is impact detected? 
             }       
             oled.SetTextProperties(&textProperties); 
-            oled.Label((uint8_t *)"FAP",1,0);  //Display "FAP" at x,y
+            oled.Label((uint8_t *)"FAP",3,0);  //Display "FAP" at x,y
             textProperties.fontColor = COLOR_WHITE;
             oled.SetTextProperties(&textProperties);
            
@@ -1498,7 +1512,7 @@
             Heat_Index_Calculation();
             sprintf(text,"%i",heat_index);
             oled.TextBox((uint8_t *)text,3,80,15,15); //show HI in a 15px by 15px text box at x=3, y=80
-            strcpy((char *) text,"dF");oled.Label((uint8_t *)text,18,80);
+            strcpy((char *) text,"F");oled.Label((uint8_t *)text,22,80); // was "dF" at 18,80
             
             if(Heart_Rate_Mode == 1) {
                 oled.Label((uint8_t *)"BPM",35,60); // Display "H.I." at x,y
@@ -1577,11 +1591,7 @@
 
         case 6: {// Panic Alert
             oled.FillScreen(COLOR_BLACK); // Clear screen
-            if (Panic_Alert == 0) {
-                oled.Label((uint8_t *)"Send ",20,10); // Display at x,y
-            } else {
-                oled.Label((uint8_t *)"Dismiss ",17,10); // Display at x,y
-            }
+            oled.Label((uint8_t *)"Send ",20,10); // Display at x,y
             oled.Label((uint8_t *)"Panic Alert",15,40); // Display at x,y
             oled.Label((uint8_t *)"-->",80,15); // "*" at x,y
             oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y
@@ -2089,6 +2099,7 @@
             oled.Label((uint8_t *)display_buff, 71, 60);
             textProperties.fontColor = COLOR_WHITE; //Change font to white
             oled.SetTextProperties(&textProperties);//Implement color change
+            CLRWDT();
             Led_Zone_Indicator();
             break;
         }
@@ -2308,6 +2319,24 @@
             wait(WDT_TIME+1.0);
             break;
         }//end case 50
+        
+        case 51: { //Sending panic alert screen
+            oled.FillScreen(COLOR_BLACK);
+            textProperties.fontColor = COLOR_RED;
+            oled.SetTextProperties(&textProperties);
+            oled.Label((uint8_t *)"Panic Alert!", 5, 5);
+            textProperties.font = OpenSans_12x18_Regular;  //  Max Width of Character  = 12px, Max Height of Character = 18px 
+            textProperties.fontColor = COLOR_WHITE;
+            oled.SetTextProperties(&textProperties); 
+            oled.Label((uint8_t *)"Sending", 20, 40);
+            oled.Label((uint8_t *)"Alert", 25, 55);
+            oled.Label((uint8_t *)"Dismiss?",5,75); // Display "Back" at x,y
+            //oled.Label((uint8_t *)"YES!",60,80);  //Display "Next" at x,y
+            textProperties.font = OpenSans_10x15_Regular;  //  Max Width of Character  = 10px, Max Height of Character = 15px 
+            textProperties.fontColor = COLOR_WHITE;
+            oled.SetTextProperties(&textProperties);
+            break;
+        }//end case 51
 
 #endif  // end of non-production/debug version code
 
@@ -2735,9 +2764,9 @@
 Returns: None
 ******************************************************************************/
 void Heat_Index_Calculation(){
-    sample_ftemp = temphumid.sample_ftemp();
+    //sample_ftemp = temphumid.sample_ftemp();
  
-    sample_humid = temphumid.sample_humid();
+    //sample_humid = temphumid.sample_humid();
             
     hi_calc = -42.379 +
            2.04901523 * sample_ftemp +
@@ -2777,7 +2806,7 @@
  accel.acquire_accel_data_g(Accel_Data_Event);
 // for now just turn on display and give haptic feedback
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED
-         
+        oled.DimScreenOFF(); 
         if (OLED_ON == 0) {
         OLED_ON = 1; // Scree was off, set to On  
         update_display();      
@@ -2831,6 +2860,7 @@
     Led_clk2 = 1;  // Turn LED2 on docking station on
 
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED
+    oled.DimScreenOFF();
         if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On  
         update_display();      
@@ -2865,6 +2895,7 @@
     Led_clk3 = 1;  // Turn on LED3, on docking station
 
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED
+    oled.DimScreenOFF();
         if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On  
         update_display();      
@@ -3042,6 +3073,7 @@
         if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On          
          }  // endif 
+         oled.DimScreenOFF();
         update_display(); //
         chk_motion.attach(&chk_help_needed,(Do_You_Need_Help_Time)); //initialize ticker to send automatic alert 
         CLRWDT();
@@ -3075,6 +3107,7 @@
         if (OLED_ON == 0) {
         OLED_ON = 1; // Screen was off, set to On        
         }  // endif 
+        oled.DimScreenOFF();
         update_display();
         oled_text_properties_t textProperties = {0};
         oled.GetTextProperties(&textProperties);
@@ -4029,10 +4062,10 @@
             textProperties.fontColor = COLOR_GREEN;
             oled.SetTextProperties(&textProperties);  
                      
-            sprintf(text_1, "%i%%+", (uint8_t)battery.readLevelPercent());
+            sprintf(text_1, "%i%%+", batt_per_level);
   //          Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED while fully charged
             } else {
-            sprintf(text_1, "%i%%", (uint8_t)battery.readLevelPercent());
+            sprintf(text_1, "%i%%", batt_per_level);
             }
             oled.TextBox((uint8_t *)text_1,60,0,35,15); //show level value of battery in a 35px by 15px text box at x=60, y=0
 
@@ -4071,7 +4104,7 @@
                 textProperties.fontColor = COLOR_RED; // is impact detected? 
             }       
             oled.SetTextProperties(&textProperties); 
-            oled.Label((uint8_t *)"FAP",1,0);  //Display "FAP" at x,y
+            oled.Label((uint8_t *)"FAP",3,0);  //Display "FAP" at x,y
             textProperties.fontColor = COLOR_WHITE;
             oled.SetTextProperties(&textProperties);
             
@@ -4163,4 +4196,94 @@
         */  
         Thread::wait(1000);  
     }// end while
-}// end TxTask
\ No newline at end of file
+}// end TxTask
+
+
+/*****************************************************************************
+Name: WDT_Timeout()
+Purpose: Interrupt routine used by Watch Dog timer Ticker. 
+Note that there are a few ways to implement a WDT. The best would be an external 
+circuit that resets the K46 if it became unresponsive. The next best would be using 
+the internal WDT that is built into microprocessor. And lastly there is this 
+method, using a Ticker/timer.
+Inputs: None
+Returns: None
+******************************************************************************/
+void WDT_Timeout(){ // turn off display mode
+    Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    if (OLED_ON == 0) {
+        OLED_ON = 1; // Screen was off, set to On
+    }
+    oled.DimScreenOFF();
+    __disable_irq();    // Disable all Interrupts
+    oled_text_properties_t textProperties = {0};  // Need these to change font color
+    oled.GetTextProperties(&textProperties);      // Need these to change font color
+    oled.FillScreen(COLOR_BLACK); // Clear screen
+    textProperties.font = OpenSans_12x18_Regular;  //  Max Width of Character  = 12px, Max Height of Character = 18px 
+    textProperties.fontColor = COLOR_WHITE;
+    oled.SetTextProperties(&textProperties); 
+    oled.Label((uint8_t *)"WatchDog",10,30); // Display "Back" at x,y
+    oled.Label((uint8_t *)" Reset!",20,55); // Display "Back" at x,y
+    wait(0.1);// display for 100ms
+
+    NVIC_SystemReset(); // software reset
+}//end WDT_Timeout routine
+
+
+/*****************************************************************************
+Name: CLRWDT()
+Purpose: Routine to clear/reset Watch Dog timer Ticker
+Inputs: None
+Returns: None
+******************************************************************************/
+void CLRWDT(){ // turn off display mode
+    WDT_Timer.attach(&WDT_Timeout,(WDT_TIME));//re-attach/reset WDT
+}//end WDT_Timeout routine
+
+
+/*****************************************************************************
+Name: PassKey()
+Purpose: Interrupt routine called when MK46 recieves Passkey from KW40
+Inputs: None
+Returns: None
+******************************************************************************/
+void PassKey(void)// 
+{
+    Screen_Timer.attach(&timout_timer,(SCRN_TIME));//Is this sufficient to reset/restart ticker timer for OLED?
+    if (OLED_ON == 0) {
+        OLED_ON = 1; // Scree was off, set to On
+    }
+    oled.DimScreenOFF();
+        Screen_Num = 72;  //Change to screen BLE screen 72
+        StartHaptic();
+        update_display();
+}// PassKey
+
+/*****************************************************************************
+Name: UpDate_Ave()
+Purpose: Routine called to update rolling average of slow changing sensor readings
+Inputs: Temp/humid sensor readings and battery measurement
+Returns: updated global variables
+******************************************************************************/
+void UpDate_Ave(void)//
+{
+    //int i = 4; // used in rolling average
+    HexiwearBattery battery;
+    battery.sensorOn();  
+    if(Ave_Num == 0){  
+    // this is first measurement since reboot         
+    batt_per_level = (uint8_t)battery.readLevelPercent();
+    sample_ftemp = temphumid.sample_ftemp();
+    sample_humid = temphumid.sample_humid();
+    }//end if
+    else{
+    // updated measurments on a rolling average basis: 1/4 new measurement to 3/4 running average
+    batt_per_level = (Ave_Num-1)*batt_per_level/Ave_Num + (uint8_t)battery.readLevelPercent()/Ave_Num;
+    sample_ftemp = (Ave_Num-1)*sample_ftemp/Ave_Num + temphumid.sample_ftemp()/Ave_Num;
+    sample_humid = (Ave_Num-1)*sample_humid/Ave_Num + temphumid.sample_humid()/Ave_Num;  
+        }//end else
+    Ave_Num++;
+    if(Ave_Num>4){
+        Ave_Num = 4;//set limit 
+        }    
+    }// end UpDate_Ave
\ No newline at end of file