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

Revision:
4:0803151bc5e4
Parent:
3:6792c1ba586c
Child:
5:e1431272be79
--- a/main.cpp	Thu Feb 08 03:25:01 2018 +0000
+++ b/main.cpp	Mon Feb 12 19:31:23 2018 +0000
@@ -13,10 +13,14 @@
 #include "FXOS8700.h"           // 3D Accelorometer & Mag
 #include "FXAS21002.h"          // 3-Axis Gyroscope
 #include "Hexi_OLED_SSD1351.h"  // OLED fuctions
+                                // Non-Freescale HTU21D - combo temperature and Humidity
+#include "W25Q64FV.h"           // W25Q64FVSSIG Serial Flash 
+                                // Non-Freescale MPL3115A2 - pressure sensor 
+#include "Hexi_Battery/hexi_battery.h"  // Battery status
 #include "OLED_types.h"         // Text attributs
 #include "string.h"
 #include "OpenSans_Font.h"
-#include "MAX30101.h"
+#include "MAX30101.h"           // Non-Freescale MAX30101 - Optical Heart rate sensor
 
 
 /* We need to confirm whether it's better to include and
@@ -36,13 +40,15 @@
 #define EXIT_BELOW      75
 #define EXIT_ABOVE      100
 #define VIB_OPT_2       75
+#define FXOS8700_I2C_ADDRESS_ (0x1E<<1) //pins SA0,SA1=0 
 
 
 void StartHaptic(void);
 void StartHaptic(int x);
 void StopHaptic(void const *n);
 void error_screen(void);
-void update_display(void);
+void update_display(void);// Screen lables refreshed
+void update_data(void);   // Screen data(only)refreshed 
 void Decrement_Age();
 void Set_Max_Bpm();
 void Set_Zone_Boundaries();
@@ -59,6 +65,11 @@
 void Disable_Heart_Rate();
 void Led_Zone_Indicator();
 
+void fall_config(uint8_t); 
+void fall_detect(void);
+void fall_det_end(void);
+void fall_detect_off(void);
+void impact_detect(void);
 
 // *****************  Global variables  ***********************
 char text_1[20];            // Text buffer - Do we need more?
@@ -66,7 +77,7 @@
 bool Led_Zones = 1;
 bool HR_Enable = 0;
 bool OLED_ON = 1;           // Turn OLED power on/off
-bool Fall_Alert = 0;        // Initialize as no active alert
+bool Fall_Alert = 1;        // Initialize as no active alert
 bool Panic_Alert = 0;        // Initialize as no active alert
 bool Fall_Alert_Mode = 1;   //  Initialize with fall alert mode on
 bool Heart_Rate_Mode = 0;   //  Initialize with Heart rate off
@@ -99,10 +110,24 @@
 FXOS8700 mag(PTC11, PTC10);   // Mag (same chip as Accel)
 //MAX30101 heart(PTB1, PTB0); //Heart Rate Chip
 
+// initialize I2C bus for FXOS8700, FXAS-Gyro, MPL-Pressure
+    I2C i2c_bus1(PTC11, PTC10);  // (SDA, SCL)
+
 DigitalOut RED_Led(LED1);
 DigitalOut GRN_Led(LED2);
 DigitalOut BLU_Led(LED3);
 DigitalOut haptic(PTB9);
+DigitalOut Led_clk1(PTA12);
+DigitalOut Led_clk2(PTA13);
+DigitalOut Led_clk3(PTA14);
+
+DigitalOut OLED_PWR(PTC13);     // this pin turns on/off 15V to OLED display
+DigitalOut Non_Free_PWR(PTB13);  // this pin turns on/off non-freescale sensors (Pres/Temp/Hum/Light)
+DigitalOut HR_PWR(PTA29);       // this pin turns on/off Heart rate sensor
+//DigitalIn   Sw1(PTA12);  //Switch 'T1' on docking station AND Led_clk1!!
+//DigitalIn   Sw2(PTA13);  //Switch 'T2' on docking station AND Led_clk2!!
+DigitalIn   Sw3(PTA15);  //Switch 'T3' on docking station 
+
 
 /* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */
 KW40Z kw40z_device(PTE24, PTE25);
@@ -110,14 +135,18 @@
 /* Define timer for haptic feedback */
 RtosTimer hapticTimer(StopHaptic, osTimerOnce);
 
+//***************** Interrups *****************
+InterruptIn Accel_INT1(PTC1);  // Accel sensor's interupt 1
+InterruptIn Accel_INT2(PTD13);  // Accel sensor's interupt 2
+
 //***************** Tickers and Timers *****************
 Ticker Screen_Timer;// use ticker to turn off OLED
 
-void timout_timer() // turn off display mode
-{
-    oled.FillScreen(COLOR_BLACK); // Clear screen.. is there a better command for this?
-    OLED_ON = 0;  // set flag to off
-    Screen_Timer.detach();
+void timout_timer(){ // turn off display mode
+//  oled.FillScreen(COLOR_BLACK); // Clear screen.. is there a better command for this?
+     OLED_PWR = 0;  // Turn off OLED power supply
+     OLED_ON = 0;  // set flag to off
+     Screen_Timer.detach();  // detach Ticker
 }//end routine
 
 void ButtonUp(void)
@@ -421,7 +450,15 @@
             }
             case 2: {// Fall Alert option
                 StartHaptic();
-                // toggle on/off
+                if(Fall_Alert == 1){
+                    Accel_INT1.fall(&fall_detect_off); // turn off Accel sensor's int#1 calls interupt routine
+                    Fall_Alert = 0;
+                    }
+                else{     
+                    Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine
+                    Fall_Alert = 1;
+                    }
+                update_display();
                 break;
             }
             case 3: {// Heart Rate Monitoring option
@@ -668,24 +705,39 @@
 
 int main()
 {
+    OLED_PWR = 1;  // Turn on OLED power supply
     oled.FillScreen(COLOR_BLACK); // Clear screen
 // *****************  Local variables  ***********************
 //   float accel_data[3]; float accel_rms=0.0;
-
+    int i;
+ 
 // **************  configure sensor modules  ******************
-    accel.accel_config();
+    //    accel.accel_config();   // configure sensor
+    fall_config(1);         // configure sensor for fall detect
+    // Fall_config(Fall_Alert_Mode); // configure sensor for fall mode
     mag.mag_config();
-//    gyro.gyro_config();
+    gyro.gyro_config();
 
     RED_Led = LED_OFF;
     GRN_Led = LED_OFF;
     BLU_Led = LED_OFF;
+    Led_clk1 = 0; // LEDs on docking station default to off, need to turn on with a 1
+    Led_clk2 = 0; // LEDs on docking station default to off, need to turn on with a 1
+    Led_clk3 = 0; // LEDs on docking station default to off, need to turn on with a 1
+    Non_Free_PWR = 1;   // Start with non-freescale sensors (Pres/Temp/Hum/Light)on
+    HR_PWR = 1;         // Start with Heart rate sensor powered on
+    
 // ***** Register callbacks/interupts to application functions *********
     kw40z_device.attach_buttonUp(&ButtonUp);
     kw40z_device.attach_buttonDown(&ButtonDown);
     kw40z_device.attach_buttonLeft(&ButtonLeft);
     kw40z_device.attach_buttonRight(&ButtonRight);
-    kw40z_device.attach_buttonSlide(&ButtonSlide);
+ //   kw40z_device.attach_buttonSlide(&ButtonSlide);
+
+// ***** attaching interupts to functions *********
+   Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine
+ //  Accel_INT2.fall(&impact_detect); //Accel sensor's int#2 calls interupt routine
+   
 
 // **** Get OLED Class Default Text Properties ****************
     oled_text_properties_t textProperties = {0};
@@ -715,20 +767,56 @@
     Screen_Timer.attach(&timout_timer,(SCRN_TIME));//start ticker timer for turning off LCD
 //  ******************* Main Loop *************************
     while (true) {
+            i=0;
+    while (i<20)// used for "Heart beat flash and updated any displayed data)
+    {
+    Thread::wait(500);          // wait 0.5 sec each loop
+    if(OLED_PWR==1){
+ //       update_data();
+        }// end if
+    i++;
+    }// end while(i<20)
+//    wait(10);          // wait 10 sec each loop, was orig half sec
+    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
+    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
 
-        Thread::wait(500); // wait half a sec in each loop
-    }
+//    update_data();        // refresh display date w/o updating entire display 
+
+    } // end of while(true)
+
 }
 //  ************** end of main()
 
 void update_display(void)
 {
+    OLED_PWR = 1;  // make sure OLED power supply is on
     oled_text_properties_t textProperties = {0};  // Need these to change font color
     oled.GetTextProperties(&textProperties);      // Need these to change font color
     switch(Screen_Num) {
         case 0: {// Main Screen
+            HexiwearBattery battery;
+            battery.sensorOn();  
             oled.FillScreen(COLOR_BLACK); // Clear screen
-            oled.Label((uint8_t *)"Batt",60,0); // Display "Batt" at x,y
+            
+            if (battery.isBatteryCharging()) {
+            textProperties.fontColor = COLOR_GREEN;
+            oled.SetTextProperties(&textProperties);  
+  //          sprintf(text_1, "%s", "chrg");           
+            sprintf(text_1, "%i%%+", (uint8_t)battery.readLevelPercent());
+            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());
+            }
+            oled.TextBox((uint8_t *)text_1,60,0,35,15); //show level value of battery originaly at  55,40,35,15
+        
+        textProperties.fontColor = COLOR_WHITE;
+        oled.SetTextProperties(&textProperties);
+            
+            oled.Label((uint8_t *)"Batt",35,0); // Display "Batt" at x,y
             oled.Label((uint8_t *)"Date",35,20); // Display "Date" at x,y
             oled.Label((uint8_t *)"Time",35,40); // Display "Time" at x,y
             oled.Label((uint8_t *)"H.I.",10,80); // Display "H.I." at x,y
@@ -751,6 +839,13 @@
         case 2: {// Fall Alert option
             oled.FillScreen(COLOR_BLACK); // Clear screen
             oled.Label((uint8_t *)"Fall Alert",20,5); // Display at x,y
+            oled.Label((uint8_t *)"Protection",15,25);  
+            if (Fall_Alert == 1){  
+            oled.Label((uint8_t *)" On ",42,40);   
+            }
+            else {               
+            oled.Label((uint8_t *)" Off ",40,40);   
+                } 
             oled.Label((uint8_t *)"*",85,15); // "*" at x,y
             oled.Label((uint8_t *)"*",85,60); // "*" at x,y
             oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y
@@ -1516,7 +1611,7 @@
     } else {
         Heart_Rate -= 1;
     }
-}
+}  // end of Decrement_Heart_Rate
 
 void Led_Zone_Indicator()
 {
@@ -1568,6 +1663,178 @@
         wait(0.5);  
         RED_Led = LED_OFF; 
     }
-  }   
+  }  
+}//end of Led_Zone_Indicator 
+/*****************************************************************************
+Name: fall_detect()
+Purpose: Interupt rutine called when accelerometer IC has detected a free-fall >= 0.5g
+
+******************************************************************************/
+
+void fall_detect(){// fall detect interupt rutine
+if(Fall_Alert == 1){
+ 
+// for now just turn on display and give haptic feedback
+   Screen_Num = 22;  //Change to screen 22 (Fall diag screen)
+    Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED
+        if (OLED_ON == 0) {
+        OLED_ON = 1; // Scree was off, set to On  
+         }  // endif
+         
+//__disable_irq();    // Disable all Interrupts
+//    oled.Label((uint8_t *)" Fall Detected ",05,70); // Display at x,y 
+ 
+    update_display();
+    BLU_Led = LED_ON;  // LEDs default to on, need to turn off
+    Led_clk2 = 1;  // Turn LED2 on docking station on
+    haptic = 1;
+    Accel_INT1.rise(&fall_det_end); // Accel sensor's int#1 calls interupt routine
+//__enable_irq();     // Enable all Interrupts
+}// end if     
+}//end fall_detect interupt routine
+
+
+void fall_detect_off(){// fall detect interupt rutine
+// for now just turn on display and give haptic feedback
+}//end fall_detect_off interupt routine
+  
+void fall_det_end(){
+    haptic = 0;         // Turn off Haptic
+    BLU_Led = LED_OFF;  // Turn off HexiHeart Blue LED
+    Led_clk2 = 0;       // Turn off LED2 on docking station on
+    oled.Label((uint8_t *)"                         ",05,70); // clear display at x,y
+    Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine
+}    //end fall_det_end interupt routine
+
+/*****************************************************************************
+Name: impact_detect()
+Purpose: Interupt rutine called when accelerometer IC has detected a vector
+magnitude acceleration >= 3.0g
+
+******************************************************************************/
+      
+void impact_detect(){
+ //       oled.Label((uint8_t *)" Impact Detected ",05,60); // Display at x,y
+ //       GRN_Led = LED_ON;  // LEDs default to on, need to turn off
+        Led_clk3 = 1;  // Turn LED2 on docking station on
+}//end impact_detect interupt routine
+
+/*****************************************************************************
+Name: fall_config()
+Purpose: Used to set accelerometer IC's internal registers to set up chip level
+interrupts
+Inputs: int value from 0 to 256
+Returns: None
+******************************************************************************/
+      
 
-}
+void fall_config(uint8_t Num){ 
+// use case switches here to configure for 
+switch(Num) {
+                case 0: {// configure as normal (or maybe sleep)
+                  char d[2]; 
+                    d[0] = FXOS8700_CTRL_REG1;                     //Puts device in Standby mode
+                    d[1] = 0x00; 
+                    i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2);
+                    
+                    d[0] = FXOS8700_CTRL_REG1;                     //Puts device back into active mode
+                    d[1] = 0x01;
+                    i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d, 2);
+                    oled.Label((uint8_t *)" Mode 0 ",30,60); // Display "mode" at x,y
+                    break;
+                }
+                case 1: {// configure for free-fall int
+                    StartHaptic();  // for debug
+                    char d[2]; 
+                    d[0] = FXOS8700_CTRL_REG1;                      //Config reg1
+                    d[1] = 0x00;                                    //Put device in Standby mode
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step1 error ",30,05); // Display "error" at x,y                  
+                        wait(3.0); // display for 3 seconds
+                    }//end if
+                    
+                    d[0] = 0x0e;                                    //XYZ_DATA_CFG (set full-scall range)
+                    d[1] = 0b00000000;                              //Set data to default range of +/-2g for full range (2x0.488mg/LSB), High-pass filter off
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step1a error ",30,05); // Display "error" at x,y      
+                        wait(3.0); // display for 3 seconds
+                    }//end if
+ 
+                    d[0] = 0x0a;                                    //TRIG_CFG (address of trigger config reg)
+                    d[1] = 0b00000100;                              //Trigger on freefall
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step2 error ",30,05); // Display "error" at x,y      
+                        wait(3.0); // display for 3 seconds
+                    }//end if
+                    
+                    d[0] = 0x15;                                    //A_FFMT_CFG (address of Free fall trigger config reg), write in Standby only
+                    d[1] = 0b00111000;                              //set to freefall, and look at all axis.
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step3 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if
+                       
+                    d[0] = 0x17;                                    //A_FFMT_THS (address of Free fall threshold reg), write in Active or Standby
+                    d[1] = 0b00001000;                                //set freefall threshold to about 756mg for now                   
+  //                 d[1] = uint8_t(1000*Fall_Thresh/63);            //set freefall threshold - Resolution is 63mg/LSB, 0b111_1111 is maximum value
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step4 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if  
+                     
+                    d[0] = 0x18;                                    //A_FFMT_COUNT (address of Free fall debounce counter), write in Active or Standby
+                    d[1] = 0b00000110;                              //with ODR at 100Hz, should equal 60mS debounce time or 120mS in Sleep
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step5 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if 
+                           
+                    d[0] = 0x2b;                                    //CTRL_REG2 (address of control reg), write in Standby only
+                    d[1] = 0b00001101;                              //Turns Auto-Sleep mode on and low-noise, low power
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step6 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if    
+                    
+                    d[0] = 0x2c;                                    //CTRL_REG3 (address of Int control reg), write in Standby only
+                    d[1] = 0b00001000;                              //FFMT will wake chip from sleep, int are active high
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step7 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if    
+                        
+                    d[0] = 0x2d;                                    //CTRL_REG4 (address of Int enable reg), write in Standby only
+                    d[1] = 0b00000100;                              // FFMT int enabled and for debug I'm using a sleep int
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step8 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if            
+                 
+                    d[0] = 0x2e;                                    //CTRL_REG5 (Int routing reg), write in Standby only
+                    d[1] = 0b00000100;                              // Make FFMT int output on pin INT1(PTC1)
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step9 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if                  
+                    
+                    d[0] = FXOS8700_CTRL_REG1;                     //CTRL_REG1, write in Standby only except for bit[0]
+                    d[1] = 0b00011001;                    //Auto-Sleep mode on set to 50Hz, ODR set to 100Hz Puts device back into Active mode 
+                    if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){
+                        oled.Label((uint8_t *)" Step10 error ",30,05); // Display "error" at x,y 
+                        wait(3.0); // display for 3 seconds
+                    }//end if  
+                    
+                    //oled.FillScreen(COLOR_BLACK); // Clear screen
+                    oled.Label((uint8_t *)" Mode 1 ",30,60); // Display "mode" at x,y   
+                    GRN_Led = LED_ON;  // LEDs default to on, need to turn on     
+                    break;
+                }
+                default: {
+                    oled.Label((uint8_t *)" Mode ? ",30,60); // Display "mode" at x,y
+                    // unknown config
+                    break;
+                } 
+}// end switch                
+
+}// end Fall_config
+