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
main.cpp
- Committer:
- asong
- Date:
- 2018-04-13
- Revision:
- 17:746dc1b7b218
- Parent:
- 16:537ef0c72084
- Child:
- 18:1f28eca85e3f
File content as of revision 17:746dc1b7b218:
/********************************************************************** HexiHeart Texas State University Senior Project - Fall 2017/Spring 2018 Team Zeta: Alex Song - https://www.linkedin.com/in/alex-song-a12632134/ Jasmine Rounsaville - https://www.linkedin.com/in/jasmine-rounsaville/ Issam Hichami - https://www.linkedin.com/in/issam-hichami-06878aa3/ Neil Baker - https://www.linkedin.com/in/neil-baker-41602a23/ You can find more about Team Zeta here: https://os.mbed.com/teams/Hexiwear_zeta/ ****** Program layout******** Declarations Up Button routines Down Button routines Right Button routines Left Button routines Main() Main display screen routines Function and interrupt routines Display data screen update routines ************** Versions **************** v2.14 - Retasked hr_led Ticker to turn off heart rate zone LEDs thereby preventing the system from having to spend half its time in a wait state. added HR screen #7 to screens that get refreshed with new data twice a second. Reduced WDT back to 2 seconds. Increased rolling average to 10 samples. removed 0.05s wait during HR read. v2.13 - Added heart rate measurement, heart rate simulation, improved heart rate leds, and optimized heart rate functionalities 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 - 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. v2.08 - Fixed impact detect functionality, all fall detect parameters are now adjustable, added motion detect function, incorporated new heat index calc, increased font by 20% for time/date. Added SW and power resetting to initialize sensors in known state. v2.07 - 2/18/18 - Added fall mode option to test fall/impact separately, Added global interrupt disable prevent button interrupts while refreshing screen, this caused haptic timer to stop working right. v1.0 - 11/12/17 This version has basic menu layout and screen timeout feature. The menu are just placeholders (for the most part) and will be either adjusted or replaced with graphic images. ***********************************************************************/ #include "mbed.h" #include "Hexi_KW40Z.h" // Button and BLE fuctions #include "FXOS8700.h" // Freescale/NXP FXOS8700CQ - 3D Accelorometer & Mag #include "FXAS21002.h" // Freescale/NXP FXAS21002CQ - 3-Axis Gyroscope //#include "MPL3115A2.h" // Freescale/NXP MPL3115A2 - pressure sensor #include "HTU21D.h" // Non-Freescale/NXP - HTU21D - combo temperature and Humidity #include "W25Q64FV.h" // Non-Freescale/NXP - W25Q64FVSSIG - 8MB/64Mbit Serial Flash memory #include "MAX30101.h" // Non-Freescale MAX30101 - Optical Heart rate sensor //#include "TSL2561.h" // Non-Freescale/NXP TSL2561 - light sensor #include "Hexi_Battery/hexi_battery.h" // Battery status #include "Hexi_OLED_SSD1351.h" // OLED fuctions #include "OLED_types.h" // Text attributs #include "string.h" #include "OpenSans_Font.h" #include "images.h" /* General Definitions */ #define SW_Ver 2.14 // 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 2.0 // Set Watch Dog timer to 1.5 seconds (1.5s reset in certain subroutines) #define MAX_AVE_NUM 10 // maximum averaging depth of rolling average for batt, temp and humid #define Debug 1 // If "Debug" is defined, our code will compile for debug. Comment out for Production code. #define FXOS8700_I2C_ADDRESS_ (0x1E<<1) //pins SA0,SA1=0 #define FXAS21002_I2C_ADDRESS_ 0x40 // //#define TSL2561_I2C_ADDRESS_ (0x29 << 1) // Address select line is grounded //#define MPL3115A2_I2C_ADDRESS_ ? // /*Heart Rate Definitions */ #define HIGHEST_ZONE 4 // Highest heart rate zone #define LOWEST_ZONE 1 #define ENTER_BELOW 25 #define ENTER_ABOVE 50 #define EXIT_BELOW 75 #define EXIT_ABOVE 100 #define VIB_OPT_2 75 // Haptic vibration pattern option for heart rate functions #define HR_LED_on_time 0.5 //how long should zone LED stay on for? #define HR_LED_period 1.0 //how often should zone LED blink? /* I2C Address */ #define HR_W_ADDR 0xAE #define HR_R_ADDR 0xAF /* Status */ #define REG_INT_MSB 0x00 /* Interrupt Status 1 */ #define REG_INT_LSB 0x01 /* Interrupt Status 2 */ #define REG_INT_ENB_MSB 0x02 /* Interrupt Enable 1 */ #define REG_INT_ENB_LSB 0x03 /* Interrupt Enable 2 */ /* FIFO */ #define REG_FIFO_WR_PTR 0x04 /* FIFO Write Pointer */ #define REG_OVF_COUNTER 0x05 /* Overflow Counter */ #define REG_FIFO_RD_PTR 0x06 /* FIFO Read Pointer */ #define REG_FIFO_DATA 0x07 /* FIFO Data Register */ /* Configuration */ #define REG_FIFO_CONFIG 0x08 /* FIFO Configuration */ #define REG_MODE_CONFIG 0x09 /* Mode Configuration */ #define REG_SPO2_CONFIG 0x0A /* SpO2 Configuration */ /* reserved 0x0B */ #define REG_LED1_PA 0x0C /* RED LED Pulse Amplitude 1 */ #define REG_LED2_PA 0x0D /* IR LED Pulse Amplitude 2 */ #define REG_LED3_PA 0x0E /* GREEN LED Pulse Amplitude 3 */ /* reserved 0x0F */ #define REG_PILOT_PA 0x10 /* Proximity LED Pulse Amplitude */ #define REG_SLOT_MSB 0x11 /* Multi-LED Mode Control Registers 2, 1 */ #define REG_SLOT_LSB 0x12 /* Multi-LED Mode Control Registers 4, 3 */ /* DIE Temperature */ #define REG_TEMP_INT 0x1F /* Die Temperature Integer */ #define REG_TEMP_FRAC 0x20 /* Die Temperature Fraction */ #define REG_TEMP_EN 0x21 /* Die Temperature Config */ /* Proximity Function */ #define REG_PROX_INT_THR 0x30 /* Proximity Interrupt Threshold */ /* Part ID */ #define REG_REV_ID 0xFE /* Revision ID */ #define REG_PART_ID 0xFF /* Part ID: 0x15 */ /* Depth of FIFO */ #define FIFO_DEPTH 32 /* End of heart rate definitions */ void StartHaptic(void); void Haptic_Off_(void); // added by NRB void StartHaptic(int x); void StopHaptic(void const *n); 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(); void Increment_Age(); void Increment_Target_Zone(); void Decrement_Target_Zone(); void Increment_HR_Vibr_Pref(); void Decrement_HR_Vibr_Pref(); void Determine_Current_Zone(); void Heart_Rate_Vibrations(); void Increment_Heart_Rate(); void Decrement_Heart_Rate(); void Enable_Heart_Rate(); void Disable_Heart_Rate(); void Led_Zone_Indicator(); void Led_Zone_Indicator_off(); // turns off LEDs after 0.5 seconds instead of using a wait command void Heat_Index_Calculation(); void fall_config(uint8_t); //function call to setup fall detecting modes void accel_sensor_config(uint8_t); void gyro_sensor_config(uint8_t); void light_config(uint8_t); void press_config(uint8_t); void fall_detect(void); // Interupt routine void fall_detect_debug(void); // Interupt routine void fall_det_end(void); // Interupt routine void fall_det_end_debug(void); // Interupt routine void chkfall(void); // Routine used with Ticker void interupt_off(void); void clear_fall(void); // Routine used with Ticker void impact_detect(void); // Interupt routine void impact_detect_debug(void); // Interupt routine 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 txTask(void); void PassKey(void); void MAX30101_test_config(uint8_t); 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 void HR_Simulation(void); // Step through a constrained random heart rate simulation to demo zones void readRegs(int, uint8_t *, int); //I2c read for maxim chip void writeRegs(uint8_t, int); //I2c write for maxim chip /* Functions for setting maxim chip values */ void setIntEnable(uint16_t); void setFIFO_WR_PTR(uint8_t); void setOVF_COUNTER(uint8_t); void setFIFO_RD_PTR(uint8_t); void setFIFO_DATA(uint8_t); void setFIFO_CONFIG(uint8_t); void setMODE_CONFIG(uint8_t); void setSPO2_CONFIG(uint8_t); void setLED1_PA(uint8_t); void setLED2_PA(uint8_t); void setLED3_PA(uint8_t); void setPILOT_PA(uint8_t); void setSLOT(uint16_t); void setPROX_INT_THR(uint8_t); void clearFIFO(void); uint32_t readFIFO(void); //Read from the maxim chips fifo void maxReset(void); //Reset maxim chip void maxInit(void); //Initialize the maxim chip with necessary values uint16_t getIntEnable(void); void maxEnable(void); //Begin the maxim chip light measurements void maxDeinit(void); //Turn off the maxim chip uint32_t isPeak(uint32_t *); //Calculate the peak of a sample from the maxim chip void processHeartRate(void); //Calculate the heart rate measurement // ***************** Global variables *********************** char text_1[20]; // Text buffer - Do we need more? char display_buff[30]; //Buffer for conversion to char to display char text[20]; // Text Buffer for dynamic value displayed bool BLE_On = 1; // Initialize as BLE on char pass [20]; // Passcode bool Led_Zones = 1; bool HR_Enable = 0; bool OLED_ON = 1; // Turn OLED power on/off bool Fall_Alert = 1; // Initialize as no active alert bool Panic_Alert = 0; // Initialize as no active alert uint8_t Fall_Alert_Mode = 5; // Initialize with fall alert mode on bool Heart_Rate_Mode = 0; // Initialize with Heart rate off float Accel_Mag=0.0; // Vector magnitude calculated from sensor data float Accel_Data[3]; // Accel Data from sensor float Accel_Data_Event[3]; // Accel Data from sensor at interupt float Fall_Event_Data[7]; // Fall event Data ff-value, ff-time, impact-value, 4byte timestamp float Gyro_Mag=0.0; // Vector magnitude calculated from sensor data float Gyro_Data[3]; // Gyro data from sensor float Fall_Thresh=0.5; // Initialize Free-Fall detect Threshold as being <= 0.5g float Fall_Impact_Max_Wait_Time=2.0;// maximum wait time from end of fall detect to impact detect float Impact_Thresh=3.0; // Initialize Impact detect Threshold float Movement_Thresh=50.0; // Initialize Movement detect Threshold 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 = 0; uint8_t *HR_return; uint8_t Age = 25; // Initialize age uint8_t Max_Bpm = 220 - Age; // Initialize Max BPM uint8_t Screen_Num = 0; // Initialize to main screen uint8_t Error_Num = 0; // Error num for debug uint8_t HR_Vibration = 2; //Choose Heart Rate Vibration Options uint8_t Target_Zone = 2; //Initialize Target Heart Rate Zone to Zone 3 uint8_t HR_Zone1[2] = {Max_Bpm * .50, Max_Bpm * .60}; //Heart Rate Zone 1 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 uint8_t heat_index; // used in Heat index calc int hi_calc; // used in Heat index calc int adjustment; // used in Heat index calc bool randomized = 0; //Initialize to 0, since srand has not been called int simulation_stage = 0; uint32_t hr_data[100]; // 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; //const uint8_t *NB_Linkedin = NB_Linkedin_bmp; //const uint8_t *AS_Linkedin = NB_Linkedin_bmp; //const uint8_t *IR_Linkedin = NB_Linkedin_bmp; //const uint8_t *IH_Linkedin = NB_Linkedin_bmp; // ***************** Define pins ***************************** //W25Q64FVSSIG - 8MB/64Mbit Serial Flash memory (SPI1)(MOSI,SCLK,POWER,CS,RST,DC) //W25Q64FV(PinName mosi, PinName miso, PinName sclk, PinName cs, int frequency=10000000); //MKW40Z (SPI1) SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); // SSD1351 OLED Driver SPI2(MOSI,SCLK,POWER,CS,RST,DC) FXAS21002 gyro(PTC11,PTC10); // Gyroscope (I2C1 data bus(SDA, SCL)) FXOS8700 accel(PTC11, PTC10); // Accelorometer (I2C1 data bus(SDA, SCL)) FXOS8700 mag(PTC11, PTC10); // Mag (same chip as Accel) (I2C1 data bus(SDA, SCL)) //MAX30101 heart(PTB1, PTB0); //Heart Rate Chip (I2C0 data bus(SDA, SCL)) HTU21D temphumid(PTB1,PTB0); // HTU21D Sensor (I2C0 data bus(SDA, SCL)) //TSL2561 - (PTB1, PTB0); //Amb light sensor (I2C0 data bus(SDA, SCL)) // initialize I2C bus for FXOS8700, FXAS-Gyro, MPL-Pressure I2C i2c_bus1(PTC11, PTC10); // (SDA, SCL) // initialize I2C bus for MAX30101, HTU21D, TSL2561 I2C i2c_bus0(PTB1, PTB0); // (SDA, SCL) // initialize SPI bus for W25Q64FVSSIG, (and MKW40Z if needed) // SPI spi_bus1(PTD6, PTD7, PTD5); // (MOSI, MISO, SCLK) CS=PTD4?(low=select) 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 supply to OLED display DigitalOut PowerEN (PTB12); // 3V3B Power Enable for HTU21D (Temp/Hum sensor) and Light sensor Sensor supply DigitalOut maxim(PTA29); // this pin turns on/off power to 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); /* Define timer for haptic feedback */ RtosTimer hapticTimer(StopHaptic, osTimerOnce); /*Create a Thread to handle sending BLE Sensor Data */ //Thread txThread; //***************** Interrups ***************** InterruptIn Accel_INT1(PTC1); // Accel sensor's interupt 1 InterruptIn Accel_INT2(PTD13); // Accel sensor's interupt 2 InterruptIn Gyro_INT1(PTD1); // Gyro sensor's interupt 1 InterruptIn Gyro_INT2(PTC18); // Gyro sensor's interupt 2 //InterruptIn Amb_Light_INT1(PTC0); // TSL2561- Light sensor's interupt //InterruptIn HR_INT1(PTB18); // MAX30101 - Heart rate sensor's interupt //InterruptIn Pressure_INT1(PTD12); // MPL3115A2 pressure sensor's interupt 1 //InterruptIn Pressure_INT2(PTD10); // MPL3115A2 pressure sensor's interupt 2 //***************** 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 Ticker Haptic_Timer; Ticker WDT_Timer; Ticker hr_led; Ticker hr_simulation; Ticker hr_ticker; Ticker hr_measure_ticker; /***************************************************************************** Name: timout_timer() 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() || (uint8_t)battery.readLevelPercent() > 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() || 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 /* Turn on the backlight of the OLED Display */ //oled.DimScreenON(); just dim display for debug OLED_PWR = 0; // Turn off OLED power supply OLED_ON = 0; // set flag to off Screen_Timer.detach(); // detach Ticker #ifdef Debug // in debug keep screens on for demo } // endelse #endif }//end timout_timer routine /***************************************************************************** Name: ButtonUp() Purpose: Routine called when MK46 recieves a ButtonUP interrupt from KW40 Inputs: Uses global Screen_Num value and other status varibles Returns: None ******************************************************************************/ 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(); } else { switch(Screen_Num) { case 0: {// We're in Main Screen // do nothing, wrong button break; } case 1: {// Panic Alert option StartHaptic(); Screen_Num = 5; //Change to screen 5 #ifdef Debug // in debug show debug/diagnostic screens Screen_Num = 26; //Change to screen 20 #endif update_display(); break; } case 2: {// Fall Alert option StartHaptic(); Screen_Num = 71; //Change to screen 71 update_display(); break; } case 3: {// Heart Rate Monitoring option StartHaptic(); Screen_Num = 2; //Change to screen 2 update_display(); break; } case 4: {// Alert History option StartHaptic(); Screen_Num = 3; //Change to screen 3 update_display(); break; } case 5: {// About HexiHeart StartHaptic(); Screen_Num = 3; //Change to screen 3, skip 4 update_display(); break; } case 6: {// Panic Alert StartHaptic(); Screen_Num = 51; Panic_Alert = 1; Send_Alert(10); // send/store alert type zero update_display(); break; } case 7: {// Heart Rate Zone StartHaptic(); maxInit(); maxEnable(); hr_led.attach(&Led_Zone_Indicator, HR_LED_period); // blink every second hr_ticker.attach(&processHeartRate, 5); break; } case 8: {// Alert History StartHaptic(); //Increment alert index break; } case 9: {// HexiHeart About info1 StartHaptic(); Screen_Num = 11; //Change to screen 11 update_display(); break; } case 10: {// HexiHeart About info2 StartHaptic(); Screen_Num = 9; //Change to screen 9 update_display(); break; } case 11: {// HexiHeart About info3 StartHaptic(); Screen_Num = 10; //Change to screen 9 update_display(); break; } case 20: {// Diagnostic/Debug Screens StartHaptic(); Screen_Num = 5; //Change to screen 5 update_display(); break; } case 21: {// Fall Diagnostic StartHaptic(); Screen_Num = 49; //Change to screen 49 update_display(); break; } case 22: {// Fall Debug StartHaptic(); Screen_Num = 21; //Change to screen 21 update_display(); break; } case 23: {// Heart Rate Diagnostic StartHaptic(); Screen_Num = 22; //Change to screen 22 update_display(); break; } case 24: {// Heart Rate Debug StartHaptic(); Screen_Num = 23; //Change to screen 23 update_display(); break; } case 25: {// Heat Index Diagnostic StartHaptic(); Screen_Num = 24; //Change to screen 24 update_display(); break; } case 26: {//Heart Rate Config Option StartHaptic(); Screen_Num = 20; update_display(); break; } case 27: {//Incrementing Age Increment_Age(); Set_Zone_Boundaries(); update_display(); break; } case 28: {//Changing Heart Rate Vibration Preferences Increment_HR_Vibr_Pref(); update_display(); break; } case 30: {//Change Target Heart Rate Zone Preference Increment_Target_Zone(); update_display(); break; } case 31: { //Manually Increment Heart Rate by 1 //StartHaptic(); if(maxim == 0) { Increment_Heart_Rate(); // Determine_Current_Zone(); update_display(); } break; } case 32: {//Turn on HR led blinking for manual demonstration hr_led.attach(&Led_Zone_Indicator, HR_LED_period); break; } case 33:{//Start heart rate simulation StartHaptic(); if(maxim == 0) { hr_led.attach(&Led_Zone_Indicator, HR_LED_period); hr_simulation.attach(&HR_Simulation, 5.0); } update_display(); break; } case 41: {//Fall mode 0,1,2,3,4,5 // 0=nothing, 1=fall_only, 2=impact only, 3=motion_only, 4=all, 5=main sequence StartHaptic(); Fall_Alert_Mode++; if(Fall_Alert_Mode > 5){ Fall_Alert_Mode = 0; }//endif update_display(); __disable_irq(); // Disable all Interrupts fall_config(10); // reset accel sensor //gyro_sensor_config(10); // reset gyro sensor wait(0.1); //gyro_sensor_config(Fall_Alert_Mode); // leave gyro sensor active fall_config(Fall_Alert_Mode); wait(0.1); __enable_irq(); // Enable all Interrupts wait(0.3); update_display(); break; } case 42: {// F-Th adj StartHaptic(); Fall_Thresh = Fall_Thresh + 0.05f; if(Fall_Thresh > 0.9f){ Fall_Thresh = 0.9; }//endif update_display(); break; } case 43: {// I-Th adj StartHaptic(); Impact_Thresh = Impact_Thresh + 0.1f; if(Impact_Thresh > 3.9f){ Impact_Thresh = 3.9; }//endif update_display(); break; } case 44: {// M-Th adj StartHaptic(); Movement_Thresh = Movement_Thresh + 5.0f; if(Movement_Thresh > 300.0f){ Movement_Thresh = 300.0; }//endif update_display(); break; } case 45: {// Min_Movement_Time adj StartHaptic(); Min_Movement_Time = Min_Movement_Time + 0.1f; if(Min_Movement_Time > 2.4f){ Min_Movement_Time = 2.4; }//endif update_display(); break; } case 46: {// Min_Movement_duration adj StartHaptic(); Min_Movement_duration = Min_Movement_duration + 5.0f; if(Min_Movement_duration > 300.0f){ Min_Movement_duration = 300.0; }//endif update_display(); break; } case 49: {// WDT debug test screen StartHaptic(); Screen_Num = 25; //Change to screen 25 update_display(); break; } case 71: {// BLE StartHaptic(); Screen_Num = 1; //Change to screen 1 update_display(); break; } case 72: {// BlueTooth on/off // do nothing, wrong button or change to another screen number if you're making more BLE type screens break; } default: { break; } }// end case switch }// end if }// end ButtonUp /***************************************************************************** Name: ButtonDown() Purpose: Routine called when MK46 recieves a ButtonDown interrupt from KW40 Inputs: Uses global Screen_Num value and other status varibles Returns: None ******************************************************************************/ 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(); } else { switch(Screen_Num) { case 0: {// We're in Main Screen // do nothing, wrong button break; } case 1: {// Panic Alert option StartHaptic(); Screen_Num = 71; //Change to screen 71 update_display(); break; } case 2: {// Fall Alert option StartHaptic(); Screen_Num = 3; //Change to screen 3 update_display(); break; } case 3: {// Heart Rate Monitoring option StartHaptic(); Screen_Num = 5; //Change to screen 5, skip 4 update_display(); break; } case 4: {// Alert History option StartHaptic(); Screen_Num = 5; //Change to screen 5 update_display(); break; } case 5: {// About HexiHeart option StartHaptic(); Screen_Num = 26; //Change to screen 1 #ifdef Debug // in debug show debug/diagnostic screens Screen_Num = 20; //Change to screen 20 #endif update_display(); break; } case 6: {// Panic Alert // do nothing, wrong button break; } case 7: {// Heart Rate Zone StartHaptic(); maxDeinit(); break; } case 8: {// Alert History StartHaptic(); //decriment alert index break; } case 9: {// HexiHeart About info1 StartHaptic(); Screen_Num = 10; //Change to screen 10 update_display(); break; } case 10: {// HexiHeart About info2 StartHaptic(); Screen_Num = 11; //Change to screen 11 update_display(); break; } case 11: {// HexiHeart About info3 StartHaptic(); Screen_Num = 9; //Change to screen 9 update_display(); break; } case 20: {// Diagnostic/Debug Screens StartHaptic(); Screen_Num = 26; //Change to screen 1 update_display(); break; } case 21: {// Fall Diagnostic StartHaptic(); Screen_Num = 22; //Change to screen 22 update_display(); break; } case 22: {// Fall Debug StartHaptic(); Screen_Num = 23; //Change to screen 23 update_display(); break; } case 23: {// Heart Rate Diagnostic StartHaptic(); Screen_Num = 24; //Change to screen 24 update_display(); break; } case 24: {// Heart Rate Debug StartHaptic(); Screen_Num = 25; //Change to screen 25 update_display(); break; } case 25: {// Heat Index Diagnostic StartHaptic(); Screen_Num = 49; //Change to screen 49 update_display(); break; } case 26: {//Heart Rate Configs StartHaptic(); Screen_Num = 1; update_display(); break; } case 27: { //Decrement Age Decrement_Age(); Set_Zone_Boundaries(); update_display(); break; } case 28: { //Changing Heart Rate Vibration Preference /* StartHaptic(); if(HR_Vibration == 1) { HR_Vibration = 3; } else { HR_Vibration -= 1; } */ Decrement_HR_Vibr_Pref(); update_display(); break; } case 30: {//Change Target Heart Rate Zone Preference Decrement_Target_Zone(); update_display(); break; } case 31: { //Manually decrement heart rate by 1 if(maxim == 0) { Decrement_Heart_Rate(); // Determine_Current_Zone(); update_display(); } break; } case 32: {//End HR led used for manual demonstration hr_led.detach(); RED_Led = LED_OFF; GRN_Led = LED_OFF; BLU_Led = LED_OFF; break; } case 33: {//End HR Simulation early StartHaptic(); if(maxim == 0) { hr_simulation.detach(); simulation_stage = 0; hr_led.detach(); RED_Led = LED_OFF; GRN_Led = LED_OFF; BLU_Led = LED_OFF; } update_display(); break; } case 41: {//Fall mode 0,1,2,3,4,5 // 0=nothing, 1=fall_only, 2=impact only, 3=motion_only, 4=all, 5=main sequence StartHaptic(); Fall_Alert_Mode--; if(Fall_Alert_Mode > 5){// should be 0xff if decr from zero Fall_Alert_Mode = 5; } //endif update_display(); __disable_irq(); // Disable all Interrupts fall_config(10); // reset accel sensor //gyro_sensor_config(10); // reset gyro sensor wait(0.1); //gyro_sensor_config(Fall_Alert_Mode); // leave gyro sensor active fall_config(Fall_Alert_Mode); wait(0.1); __enable_irq(); // Enable all Interrupts wait(0.2); update_display(); break; } case 42: {// F-Th adj StartHaptic(); Fall_Thresh = Fall_Thresh - 0.05f; if(Fall_Thresh < 0.1f){ Fall_Thresh = 0.1; }//endif update_display(); break; } case 43: {// I-Th adj StartHaptic(); Impact_Thresh = Impact_Thresh - 0.1f; if(Impact_Thresh < 0.9f){ Impact_Thresh = 0.9; }//endif update_display(); break; } case 44: {// M-Th adj StartHaptic(); Movement_Thresh = Movement_Thresh - 5.0f; if(Movement_Thresh < 5.0f){ Movement_Thresh = 5.0; }//endif update_display(); break; } case 45: {// Min_Movement_Time adj StartHaptic(); Min_Movement_Time = Min_Movement_Time - 0.1f; if(Min_Movement_Time < 0.5f){ Min_Movement_Time = 0.5; }//endif update_display(); break; } case 46: {// Min_Movement_duration adj StartHaptic(); Min_Movement_duration = Min_Movement_duration - 5.0f; if(Min_Movement_duration < 5.0f){ Min_Movement_duration = 5.0; }//endif update_display(); break; } case 49: {// WDT diagnostic test screen StartHaptic(); Screen_Num = 21; //Change to screen 21 update_display(); break; } case 71: {// BLE StartHaptic(); Screen_Num = 2; //Change to screen 2 update_display(); break; } case 72: {// BlueTooth on/off // do nothing, wrong button or change to another screen number if you're making more BLE type screens break; } default: { break; } }//end case switch }//end if }// end ButtonDown() /***************************************************************************** Name: ButtonRight() Purpose: Routine called when MK46 recieves a ButtonRight interrupt from KW40 Inputs: Uses global Screen_Num value and other status varibles Returns: None ******************************************************************************/ 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(); } else { switch(Screen_Num) { case 0: {// We're in Main Screen StartHaptic(); Screen_Num = 1; //Change to screen 1 update_display(); break; } case 1: {// Panic Alert option StartHaptic(); Screen_Num = 6; //Change to screen 6 update_display(); break; } case 2: {// Fall Alert option StartHaptic(); if(Fall_Alert == 1){ Fall_Alert = 0; fall_config(0); // configure sensors for standby } else{ //Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine Fall_Alert = 1; fall_config(Fall_Alert_Mode); // configure sensors for current fall mode } update_display(); break; } case 3: {// Heart Rate Monitoring option StartHaptic(); Screen_Num = 7; //Change to screen 7 update_display(); break; } case 4: {// Alert History option StartHaptic(); Screen_Num = 8; //Change to screen 8 update_display(); break; } case 5: {// About HexiHeart option StartHaptic(); Screen_Num = 9; //Change to screen 9 update_display(); break; } case 6: {// Panic Alert // do nothing, wrong button break; } case 7: {// Heart Rate Zone StartHaptic(); Screen_Num = 31; update_display(); break; } case 20: {// Diagnostic/Debug Screens StartHaptic(); Screen_Num = 21; //Change to screen 21 update_display(); break; } case 22: {// Fall Debug StartHaptic(); Screen_Num = 41; //Change to screen 41 update_display(); break; } case 26: {//Change to Heart Rate Config Screen StartHaptic(); Screen_Num = 27; update_display(); break; } case 27: {//Change to Heart Rate Vibration Preferences StartHaptic(); Screen_Num = 28; update_display(); break; } case 28: {//Change to Heart Rate Zone Boundary Info StartHaptic(); Screen_Num = 29; update_display(); break; } case 29: {//Change Target Heart Rate Zone Preference StartHaptic(); Screen_Num = 30; update_display(); break; } case 30: {//Change to Heart Rate Config Screen StartHaptic(); Screen_Num = 27; update_display(); break; } case 31: { StartHaptic(); Screen_Num = 32; update_display(); break; } case 32: { StartHaptic(); Screen_Num = 33; update_display(); break; } case 33: { StartHaptic(); Screen_Num = 7; update_display(); break; } case 41: {// Fall-Mode adj StartHaptic(); Screen_Num = 42; //Change to screen 42 update_display(); break; } case 42: {// F-Th adj StartHaptic(); Screen_Num = 43; //Change to screen 43 update_display(); break; } case 43: {// I-Th adj StartHaptic(); Screen_Num = 44; //Change to screen 44 update_display(); break; } case 44: {// M-Th adj StartHaptic(); Screen_Num = 45; //Change to screen 44 update_display(); break; } case 45: {// Min_time adj StartHaptic(); Screen_Num = 46; //Change to screen 44 update_display(); break; } case 46: {// Time_dur adj //do nothing for now break; } case 47: {// Fall-Detected screen "are you ok?" StartHaptic(); Send_Alert(20); // send/store alert type 20 Screen_Num = 48; //Change to screen 48 (send alert screen) update_display(); break; } case 49: {// start WDT test StartHaptic(); Screen_Num = 50; //Change to screen 50 update_display(); break; } case 71: {// BLE StartHaptic(); Screen_Num = 72; //Change to screen 72 update_display(); break; } case 72: {// BlueTooth on/off StartHaptic(); BLE_On = !BLE_On; kw40z_device.ToggleAdvertisementMode(); update_display(); break; } default: { break; } }//end case switch }//end if }//end ButtonRight /***************************************************************************** Name: ButtonLeft() Purpose: Routine called when MK46 recieves a ButtonLeft interrupt from KW40 Inputs: Uses global Screen_Num value and other status varibles Returns: None ******************************************************************************/ 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 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 StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 2: {// Fall Alert option StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 3: {// Heart Rate Monitoring option StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 4: {// Alert History option StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 5: {// About HexiHeart option StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 6: {// Panic Alert StartHaptic(); Screen_Num = 1; //Change to screen 1 update_display(); break; } case 7: {// Heart Rate Zone StartHaptic(); Screen_Num = 3; //Change to screen 3 update_display(); break; } case 8: {// Alert History StartHaptic(); Screen_Num = 4; //Change to screen 4 update_display(); break; } case 9: {// About HexiHeart info1 StartHaptic(); Screen_Num = 5; //Change to screen 5 update_display(); break; } case 10: {// HexiHeart About info2 StartHaptic(); Screen_Num = 5; //Change to screen 5 update_display(); break; } case 11: {// HexiHeart About info3 StartHaptic(); Screen_Num = 5; //Change to screen 5 update_display(); break; } case 20: {// Diagnostic/Debug Screens StartHaptic(); Screen_Num = 0; //Change to screen 0 update_display(); break; } case 21: {// Fall Diagnostic StartHaptic(); Screen_Num = 20; //Change to screen 20 update_display(); break; } case 22: {// Fall Debug StartHaptic(); Screen_Num = 20; //Change to screen 20 update_display(); break; } case 23: {// Heart Rate Diagnostic StartHaptic(); Screen_Num = 20; //Change to screen 20 update_display(); break; } case 24: {// Heart Rate Debug StartHaptic(); Screen_Num = 20; //Change to screen 20 update_display(); break; } case 25: {// Heat Index Diagnostic StartHaptic(); Screen_Num = 20; //Change to screen 20 update_display(); break; } case 26: {//Heart Rate Config Option StartHaptic(); Screen_Num = 0; update_display(); break; } case 27: {//Enter Age StartHaptic(); Screen_Num = 26; update_display(); break; } case 28: {//Heart Rate Vibration Preference Screen StartHaptic(); Screen_Num = 27; update_display(); break; } case 29: {//Heart Rate Zone Boundary Info StartHaptic(); Screen_Num = 28; update_display(); break; } case 30: {//Change Target Heart Rate Zone Preference StartHaptic(); Screen_Num = 29; update_display(); break; } case 31: { StartHaptic(); Screen_Num = 7; update_display(); break; } case 32: { StartHaptic(); Screen_Num = 31; update_display(); break; } case 33: { StartHaptic(); Screen_Num = 32; update_display(); break; } case 41: {// Fall mode screen StartHaptic(); Screen_Num = 22; update_display(); break; } case 42: {// F-Th adj StartHaptic(); Screen_Num = 41; //Change to screen 41 update_display(); break; } case 43: {// I-Th adj StartHaptic(); Screen_Num = 42; //Change to screen 42 update_display(); break; } case 44: {// M-Th adj StartHaptic(); Screen_Num = 43; //Change to screen 43 update_display(); break; } case 45: {// M-time adj StartHaptic(); Screen_Num = 44; //Change to screen 44 update_display(); break; } case 46: {// M-dur adj StartHaptic(); Screen_Num = 45; //Change to screen 45 update_display(); break; } case 47: {// Fall-detected screen StartHaptic(); Led_clk1 = 0; // Turn off LED1, on docking station Led_clk2 = 0; // Turn off LED2, on docking station Screen_Num = 0; //Change to screen 0 update_display(); break; } case 48: {// Sending Fall-Alert screen StartHaptic(); Led_clk1 = 0; // Turn off LED1, on docking station Led_clk2 = 0; // Turn off LED2, on docking station // stop/dismiss alert Send_Alert(0); Screen_Num = 0; //Change to screen 0 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 update_display(); break; } case 72: {// BlueTooth on/off StartHaptic(); Screen_Num = 71; //Change to screen 71 update_display(); break; } default: { break; } }// end case switch }// end if }// end ButtonLeft /***************************************************************************** Name: ButtonSlide() Purpose: Routine called when MK46 recieves a ButtonSlide interrupt from KW40, which we never get. Inputs: None Returns: None ******************************************************************************/ 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 } StartHaptic(); oled.FillScreen(COLOR_BLACK); // Clear screen strcpy((char *) text_1,"Slide Button"); oled.Label((uint8_t *)text_1,0,40); }// end ButtonSlide int main() { //__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 << did nothing for battery time //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; 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 // ***************** Reset sensors *********************** OLED_PWR = 0; // Turn off OLED power supply PowerEN = 1; // Turn off (=1)HTU21(Temp/Hum) and TSL2561(Light) sensors to reset them maxim = 0; // Turn off (=0) Heart rate sensor 1.8V and HRM(3.3V) supply to reset wait(0.2); // how long should we wait for sensors to power down? PowerEN = 0; // Turn on (=0) HTU21(Temp/Hum) and TSL2561(Light) sensors to reset them // maxim = 1; // Turn on (=1)Heart rate sensor OLED_PWR = 1; // Turn on OLED power supply wait(0.2); // how long should we wait for sensors to power up? oled.FillScreen(COLOR_BLACK); // Clear screen fall_config(10); // SW reset accell and gyro sensor // gyro_sensor_config(10); // SW reset gyro sensor press_config(0); // put pressure sensor into 2uA standby, we're not using it // MAX30101_test_config(10); // SW reset HR sensor << power is off 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(); // original configure accel sensor fall_config(Fall_Alert_Mode); // configure sensor (I2C1) for current fall mode //Fall_Alert_Mode: 0=none, 1=fall_only, 2=impact only, 3=motion_only, 4=all three, 5=full sequencial //gyro.gyro_config(); // original configure gyro sensor //gyro_sensor_config(Fall_Alert_Mode); // configure gyro sensor (I2C1) 0=standby, 1=active, 2=interupt set up (now setup in fall_config()) //mag.mag_config(); // we don't need mag //light_config(0); // config TSL2561 ambient light sensor (I2C0) for lowest power - cycling PowerEn should have reset it to state //Configure HTU21(Temp/Hum)? No need, it seems to draw 0.02uA when not being activly read over data bus // need to configure MAX30101 at some point // MAX30101_test_config(0); // ***** 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_passkey(&PassKey); // ***** attaching interupts to functions ********* //Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 (PTC1) calls interupt routine (now setup in fall_config()) //Accel_INT2.fall(&impact_detect); //Accel sensor's int#2 (PTD13) calls interupt routine(now setup in fall_config()) //Gyro_INT1.fall(&motion_detect); // Gyro sensor's int#1 (PTD1) calls interupt routine (now setup in fall_config()) //Gyro_INT2.fall(&motion_detect); // Gyro sensor's int#2 (PTC18) calls interupt routine (not used) //HR_INT1.fall(&some_HR_read_function_yet_to_be_named); // MAX30101 - Heart rate sensor's interupt (PTB18) // **** Get OLED Class Default Text Properties **************** oled_text_properties_t textProperties = {0}; oled.GetTextProperties(&textProperties); // *********Set text color and screen alignment ************** //textProperties.font = OpenSans_12x18_Regular; // Max Width of Character = 12px, Max Height of Character = 18px //textProperties.font = OpenSans_10x15_Regular; // <-This is default Font, Max Width of Character = 10px, Max Height of Character = 15px textProperties.fontColor = COLOR_WHITE; textProperties.alignParam = OLED_TEXT_ALIGN_LEFT; oled.SetTextProperties(&textProperties); // ************** Display spash screen ********************** /* oled.FillScreen(COLOR_BLACK); // Clear screen oled.DrawImage(Hexi_Heart_,0,0); // my Hexi_Heart image is offset for some reason wait(0.5); // wait 0.5 seconds */ oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.font = OpenSans_12x18_Regular; // Max Width of Character = 12px, Max Height of Character = 18px oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Hexi",18,5); // Display white "Hexi" at x,y textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart",47,5); // Display red "Heart" at x,y textProperties.font = OpenSans_10x15_Regular; // Max Width of Character = 10px, Max Height of Character = 15px oled.SetTextProperties(&textProperties); strcpy((char *) text_1,"This is a"); oled.Label((uint8_t *)text_1,19,25); // text_1 at x,y strcpy((char *) text_1,"Demo Proj"); oled.Label((uint8_t *)text_1,15,40); // text_1 at x,y strcpy((char *) text_1,"SW_Ver:"); oled.Label((uint8_t *)text_1,10,70); // text_1 at x,y textProperties.fontColor = COLOR_MAGENTA; oled.SetTextProperties(&textProperties); sprintf(text_1,"%2.2f ",SW_Ver); oled.Label((uint8_t *)text_1,60,70);// text_1 at x,y StartHaptic(); textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 ************************* 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 CLRWDT(); if(OLED_PWR==1){ update_display_date(); // refresh display data twice a second w/o updating entire display }// end if i++; }// end 10 second while(i<20) loop if(maxim==0){// don't use red LED while heart rate zone routine is active 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 if(maxim==0){// don't use red LED while heart rate zone routine is active 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 10.5 seconds } // 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 __disable_irq(); // Disable all Interrupts switch(Screen_Num) { case 0: {// Main Screen HexiwearBattery battery; battery.sensorOn(); oled.FillScreen(COLOR_BLACK); // Clear screen if (battery.isBatteryCharging()) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); // sprintf(text_1, "%s", "chrg"); 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%%", 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 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 oled.Label((uint8_t *)"BT",40,80); //Display "BT" at x,y oled.Label((uint8_t *)"Menu",60,80); //Display "Menu" at x,y textProperties.fontColor = COLOR_GRAY; if(BLE_On == 1){ textProperties.fontColor = COLOR_BLUE; // If BLE on make "BT" blue! } oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"BT",40,80); //Display "BT" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); textProperties.fontColor = COLOR_GRAY; if(Fall_Alert == 1){ textProperties.fontColor = COLOR_GREEN; // is Fall protection on? } if(Fall_Alert == 1 && Led_clk1 == 1){ textProperties.fontColor = COLOR_YELLOW; // is Fall detected? } if(Fall_Alert == 1 && Led_clk1 == 1 && Led_clk2 == 1){ textProperties.fontColor = COLOR_RED; // is impact detected? } oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"FAP",3,0); //Display "FAP" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); // added real time and date information char buffer[32]; time_t seconds = time(NULL); strftime(buffer,32, "%a,%d %m %Y.%H:%M:%S\r", localtime(&seconds)); //format local time and store in buffer textProperties.font = OpenSans_12x18_Regular; // Max Width of Character = 12px, Max Height of Character = 18px textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); sprintf(text_1,"%c%c/%c%c/%c%c%c%c ",buffer[7],buffer[8],buffer[4],buffer[5],buffer[10],buffer[11],buffer[12],buffer[13]); oled.Label((uint8_t *)text_1,15,25);// Date at x,y sprintf(text_1,"%c%c:%c%c:%c%c ",buffer[15],buffer[16],buffer[18],buffer[19],buffer[21],buffer[22]); oled.Label((uint8_t *)text_1,25,40);// Time 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); Heat_Index_Calculation(); sprintf(text,"%i",heat_index); oled.Label((uint8_t *)text,3,80);// HI at x,y //oled.TextBox((uint8_t *)text,3,80); //show HI in a 15px by 15px text box at x=3, y=80 strcpy((char *) text,"F"); oled.Label((uint8_t *)text,25,80); // was "dF" at 18,80 if(Heart_Rate_Mode == 1) { oled.Label((uint8_t *)"BPM",35,60); } break; } case 1: {// Panic Alert option oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Panic Alert",18,5); // Display at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display "enter" at x,y break; } 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,20); oled.Label((uint8_t *)"FAP",15,40); if (Fall_Alert == 1){ textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)" On ",42,40); } else { textProperties.fontColor = COLOR_GRAY; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)" Off ",40,40); } textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 oled.Label((uint8_t *)"Toggle",59,80); //Display "Toggle" at x,y break; } case 3: {// Heart Rate Monitoring option oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Heart Rate",18,5); // Display at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display at x,y break; } case 4: {// Alert History option oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Alert History",10,5); // Display at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display at x,y break; } case 5: {// About HexiHeart Screen oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Hexi",20,20); // Display white "Hexi" at x,y textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart",45,20); // Display red "Heart" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); strcpy((char *) text_1,"About"); oled.Label((uint8_t *)text_1,30,5); // text_1 at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display at x,y break; } case 6: {// Panic Alert oled.FillScreen(COLOR_BLACK); // Clear screen 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 break; } case 7: {// Heart Rate Zone oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart Rate",18,5); // Display at x,y oled.Label((uint8_t *)"HR:",10,25); // Display at x,y sprintf(display_buff, "%u", Heart_Rate); textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)display_buff,43,25); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Age: ",10,45); // Display at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); //implements the color change sprintf(display_buff, "%u", Age); //Convert int to char array for displaying user age oled.Label((uint8_t *)display_buff,43,45); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"On",80,15); // "+" at x,y oled.Label((uint8_t *)"Off",78,60); // "-" at x,y oled.Label((uint8_t *)"Menu",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); // Display "Next" at x,y break; } case 8: {// Alert History oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Alert History",5,5); // Display at x,y oled.Label((uint8_t *)"Date - Time",20,40); // Display at x,y oled.Label((uint8_t *)"Alert Type:",20,60); // Display at x,y 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 break; } case 9: {// About HexiHeart info1 oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Hexi",20,1); // Display white "Hexi" at x,y textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart",45,0); // Display red "Heart" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Senior Proj",5,15); // oled.Label((uint8_t *)"Team Zeta E2.7",5,30); // oled.Label((uint8_t *)"Texas State Univ",0,45); // 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 break; } case 10: {// About HexiHeart info2 oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"Hexi",20,0); // Display white "Hexi" at x,y textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart",45,0); // Display red "Heart" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); // oled.Label((uint8_t *)"E2.7 Team Zeta",2,12); // oled.Label((uint8_t *)"Alex Song",5,12); // oled.Label((uint8_t *)"Jasmine ",5,24); // Jasmine Rounsaville is to long oled.Label((uint8_t *)"Rounsaville",15,37); // Jasmine Rounsaville is to long oled.Label((uint8_t *)"Issam Hichami",5,51); // oled.Label((uint8_t *)"Neil Baker",5,64); // 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 break; } case 11: {// About HexiHeart info3 oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.font = OpenSans_12x18_Regular; // Max Width of Character = 12px, Max Height of Character = 18px oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Hexi",17,5); // Display white "Hexi" at x,y textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Heart",46,5); // Display red "Heart" at x,y textProperties.font = OpenSans_10x15_Regular; // Max Width of Character = 10px, Max Height of Character = 15px oled.SetTextProperties(&textProperties); strcpy((char *) text_1,"This is a"); oled.Label((uint8_t *)text_1,19,25); // text_1 at x,y strcpy((char *) text_1,"Demo Proj"); oled.Label((uint8_t *)text_1,15,40); // text_1 at x,y strcpy((char *) text_1,"SW_Ver:"); oled.Label((uint8_t *)text_1,10,65); // text_1 at x,y textProperties.fontColor = COLOR_MAGENTA; oled.SetTextProperties(&textProperties); sprintf(text_1,"%2.2f ",SW_Ver); oled.Label((uint8_t *)text_1,60,65);// text_1 at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 break; } #ifdef Debug // if this is non-production/debug version - do this case 20: {// Diagnostic/Debug Screens oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Diagnostics",18,5); // Display at x,y oled.Label((uint8_t *)"Enter",60,80); //Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 break; } case 21: {// Fall Alert Diagnostic Screen if(Fall_Alert_Mode == 0){ fall_config(11); // turn accel sensor to active to take reading } oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Fall-Diag",25,5); // Display at x,y // oled.Label((uint8_t *)"Diagnostic",25,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); gyro.acquire_gyro_data_dps(Gyro_Data); Gyro_Mag = (abs(Gyro_Data[0])+abs(Gyro_Data[1])+abs(Gyro_Data[2])); accel.acquire_accel_data_g(Accel_Data); if(Fall_Alert_Mode == 0){ fall_config(12); // turn accel sensor to standby } Accel_Mag = 2*sqrt(((Accel_Data[0]*Accel_Data[0])+(Accel_Data[1]*Accel_Data[1])+(Accel_Data[2]*Accel_Data[2]))); sprintf(text_1," Accel:%2.2f g ",Accel_Mag); oled.Label((uint8_t *)text_1,5,40);// text_1 at x,y sprintf(text_1," Gyro:%4.0f D/S ",Gyro_Mag); oled.Label((uint8_t *)text_1,5,60);// text_1 at x,y 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 break; } case 22: {// Fall Alert Debug Screen oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Fall Debug",15,5); // Display at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); sprintf(text_1," %i ",Fall_Alert_Mode); oled.Label((uint8_t *)text_1,36,20);// text_1 at x,y textProperties.fontColor = COLOR_GRAY; if(Fall_Alert_Mode == 1 || Fall_Alert_Mode >= 4){ textProperties.fontColor = COLOR_GREEN; } oled.SetTextProperties(&textProperties); sprintf(text_1," %1.2f g ",Fall_Thresh); oled.Label((uint8_t *)text_1,35,35);// text_1 at x,y textProperties.fontColor = COLOR_GRAY; if(Fall_Alert_Mode == 2 || Fall_Alert_Mode >= 4){ textProperties.fontColor = COLOR_GREEN; } oled.SetTextProperties(&textProperties); sprintf(text_1," %2.2f g ",Impact_Thresh); oled.Label((uint8_t *)text_1,35,50);// text_1 at x,y textProperties.fontColor = COLOR_GRAY; if(Fall_Alert_Mode == 3 || Fall_Alert_Mode >= 4){ textProperties.fontColor = COLOR_GREEN; } oled.SetTextProperties(&textProperties); sprintf(text_1," %3.0f D/S ",Movement_Thresh); oled.Label((uint8_t *)text_1,35,65);// text_1 at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Mode:",5,20); // "*" at x,y oled.Label((uint8_t *)"F-Th:",5,35); // "*" at x,y oled.Label((uint8_t *)"I-Th:",5,50); // "*" at x,y oled.Label((uint8_t *)"M-Th:",5,65); // "*" at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display at x,y break; } case 23: {// Heart Rate Diagnostic Screen oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"H.R. Diagnostic",5,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 // oled.Label((uint8_t *)" Enter ",59,80); //Display at x,y break; } case 24: {// Heart Rate Debug Screen oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"H.R. Debug",10,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 // oled.Label((uint8_t *)" Enter ",59,80); //Display at x,y break; } case 25: {// Heat Index Diagnostic Screen oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"H.I. Diagnostic",5,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); 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 // oled.Label((uint8_t *)" Enter ",59,80); //Display at x,y Heat_Index_Calculation(); oled_text_properties_t textProperties = {0}; oled.GetTextProperties(&textProperties); strcpy((char *) text,"Temp."); oled.Label((uint8_t *)text,5,40); strcpy((char *) text,"Humidity"); oled.Label((uint8_t *)text,5,57); strcpy((char *) text,"H.I."); oled.Label((uint8_t *)text,5,23); /* Set text properties to white and right aligned for the dynamic text */ textProperties.fontColor = COLOR_GREEN; textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT; oled.SetTextProperties(&textProperties); /* Format the value */ sprintf(text,"%i",sample_ftemp); /* Display temp reading in 15px by 15px textbox at(x=55, y=40) */ oled.TextBox((uint8_t *)text,55,40,15,15); //Increase textbox for more digits /* Display Units */ strcpy((char *) text,"dF"); oled.Label((uint8_t *)text,71,40); /* Format the value */ sprintf(text,"%i",sample_humid); /* Display Hum reading in 15px by 15px textbox at(x=55, y=57) */ oled.TextBox((uint8_t *)text,55,57,15,15); //Increase textbox for more digits /* Display Units */ strcpy((char *) text,"%"); oled.Label((uint8_t *)text,71,57); /* Set text properties to white and right aligned for the dynamic text */ textProperties.fontColor = COLOR_BLUE; textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT; oled.SetTextProperties(&textProperties); /* Format the value */ sprintf(text,"%i",heat_index); /* Display HI reading in 15px by 15px textbox at(x=55, y=23) */ oled.TextBox((uint8_t *)text,55,23,15,15); //Increase textbox for more digits /* Display Units */ strcpy((char *) text,"dF"); oled.Label((uint8_t *)text,71,23); break; } case 26: {//Heart Rate Config Option oled.FillScreen(COLOR_BLACK); // Clear screen oled.Label((uint8_t *)"HR Config",18,5); // Display at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display "enter" at x,y break; } case 27: { //Enter Age Screen oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Input Age", 10, 5); sprintf(display_buff, "%u", Age); //Convert int to char array for displaying user age oled.Label((uint8_t *)"Age:", 10, 30); oled.Label((uint8_t *)"+",85,15); // "*" at x,y oled.Label((uint8_t *)"-",85,60); // "*" at x,y oled.Label((uint8_t *)"Menu",10,80); // Display "Menu" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff,43,30); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Max bpm:",10,50); textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); //implements the color change sprintf(display_buff, "%u", Max_Bpm); //Convert int to char array for displaying user max bpm oled.Label((uint8_t *)display_buff, 65, 50); textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; } case 28: {//Choose Heart Rate Vibration Option oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Vibrate Pref", 10, 10); oled.Label((uint8_t *)"Option:", 10, 25); 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 oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y sprintf(display_buff, "%u", HR_Vibration); //Convert int to char array for displaying user preference textProperties.fontColor = COLOR_GREEN; //Change font to green oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)display_buff,55,25); // Display at x,y if(HR_Vibration == 1) { textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties); //Implement color change oled.Label((uint8_t *)"All On",10,45); // Display at x,y } else if(HR_Vibration == 2) { textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Only Entering",10,38);// Display at x,y oled.Label((uint8_t *)"And Exiting",10,53);// Display at x,y oled.Label((uint8_t *)"Target Zone",10,68);// Display at x,y } else if(HR_Vibration == 3) { textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties); //Implement color change oled.Label((uint8_t *)"All Off",10,45);// Display at x,y } textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; } case 29: { //Zone Boundary Info oled.FillScreen(COLOR_BLACK); textProperties.fontColor = COLOR_WHITE; //Change font to yellow oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"HR Zone Info", 10, 5);// Display at x,y textProperties.fontColor = COLOR_YELLOW; //Change font to yellow oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z1:", 10, 20);// Display at x,y sprintf(display_buff, "%u", HR_Zone1[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 20);// Display at x,y oled.Label((uint8_t *)"-", 52, 20);// Display at x,y sprintf(display_buff, "%u", HR_Zone1[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 20);// Display at x,y textProperties.fontColor = COLOR_BLUE; //Change font to blue oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z2:", 10, 35);// Display at x,y sprintf(display_buff, "%u", HR_Zone2[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 35);// Display at x,y oled.Label((uint8_t *)"-", 52, 35);// Display at x,y sprintf(display_buff, "%u", HR_Zone2[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 35);// Display at x,y textProperties.fontColor = COLOR_GREEN; //Change font to green oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z3:", 10, 50);// Display at x,y sprintf(display_buff, "%u", HR_Zone3[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 50);// Display at x,y oled.Label((uint8_t *)"-", 52, 50);// Display at x,y sprintf(display_buff, "%u", HR_Zone3[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 50);// Display at x,y textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z4:", 10, 65);// Display at x,y sprintf(display_buff, "%u", HR_Zone4[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 65);// Display at x,y oled.Label((uint8_t *)"-", 52, 65);// Display at x,y sprintf(display_buff, "%u", HR_Zone4[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 65);// Display at x,y textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y break; } case 30: { //Enter Target Heart Rate Zone Preference oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Zone Pref", 10, 5);// Display at x,y oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y oled.Label((uint8_t *)"+",85,15); // "+" at x,y oled.Label((uint8_t *)"-",85,60); // "-" at x,y oled.Label((uint8_t *)"Target:", 10, 25);// Display at x,y sprintf(display_buff, "%u", Target_Zone); // Convert int to char to display if(Target_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; //Change font to yellow oled.SetTextProperties(&textProperties);//Implement color change } else if(Target_Zone == 2) { textProperties.fontColor = COLOR_BLUE; //Change font to blue oled.SetTextProperties(&textProperties);//Implement color change } else if(Target_Zone == 3) { textProperties.fontColor = COLOR_GREEN; //Change font to green oled.SetTextProperties(&textProperties);//Implement color change } else if(Target_Zone == 4) { textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change } oled.Label((uint8_t *)display_buff, 55, 25);// Display at x,y textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Bounds:", 10, 45);// Display at x,y if(Target_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; //Change font to yellow oled.SetTextProperties(&textProperties);//Implement color change sprintf(display_buff, "%u", HR_Zone1[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 10, 60);// Display at x,y oled.Label((uint8_t *)"-", 32, 60);// Display at x,y sprintf(display_buff, "%u", HR_Zone1[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 40, 60);// Display at x,y } else if(Target_Zone == 2) { textProperties.fontColor = COLOR_BLUE; //Change font to blue oled.SetTextProperties(&textProperties);//Implement color change sprintf(display_buff, "%u", HR_Zone2[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 10, 60);// Display at x,y oled.Label((uint8_t *)"-", 32, 60);// Display at x,y sprintf(display_buff, "%u", HR_Zone2[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 40, 60);// Display at x,y } else if(Target_Zone == 3) { textProperties.fontColor = COLOR_GREEN; //Change font to green oled.SetTextProperties(&textProperties);//Implement color change sprintf(display_buff, "%u", HR_Zone3[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 10, 60); // Display at x,y oled.Label((uint8_t *)"-", 32, 60); // Display at x,y sprintf(display_buff, "%u", HR_Zone3[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 40, 60);// Display at x,y } else if(Target_Zone == 4) { textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change sprintf(display_buff, "%u", HR_Zone4[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 10, 60); // Display at x,y oled.Label((uint8_t *)"-", 32, 60); // Display at x,y sprintf(display_buff, "%u", HR_Zone4[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 40, 60); // Display at x,y } textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change break; } case 31: { oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Enter HR", 10, 5);// Display at x,y oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y oled.Label((uint8_t *)"HR:", 10, 25); sprintf(display_buff, "%u", Heart_Rate); // Convert int to char to display textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)display_buff, 40, 25); textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Cur Zone:", 10, 45); if(Current_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } sprintf(display_buff, "%u", Current_Zone); // Convert int to char to display oled.Label((uint8_t *)display_buff, 71, 45); textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Prev Zone:", 10, 60); if(Prev_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } sprintf(display_buff, "%u", Prev_Zone); // Convert int to char to display oled.Label((uint8_t *)display_buff, 71, 60); textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change break; } case 32: { //Zone Boundary Info oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"HR Zone Info", 10, 5);// Display at x,y textProperties.fontColor = COLOR_YELLOW; //Change font to yellow oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z1:", 10, 20);// Display at x,y sprintf(display_buff, "%u", HR_Zone1[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 20);// Display at x,y oled.Label((uint8_t *)"-", 52, 20);// Display at x,y sprintf(display_buff, "%u", HR_Zone1[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 20);// Display at x,y textProperties.fontColor = COLOR_BLUE; //Change font to blue oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z2:", 10, 35);// Display at x,y sprintf(display_buff, "%u", HR_Zone2[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 35);// Display at x,y oled.Label((uint8_t *)"-", 52, 35);// Display at x,y sprintf(display_buff, "%u", HR_Zone2[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 35);// Display at x,y textProperties.fontColor = COLOR_GREEN; //Change font to green oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z3:", 10, 50);// Display at x,y sprintf(display_buff, "%u", HR_Zone3[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 50);// Display at x,y oled.Label((uint8_t *)"-", 52, 50);// Display at x,y sprintf(display_buff, "%u", HR_Zone3[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 50);// Display at x,y textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Z4:", 10, 65);// Display at x,y sprintf(display_buff, "%u", HR_Zone4[0]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 30, 65);// Display at x,y oled.Label((uint8_t *)"-", 52, 65);// Display at x,y sprintf(display_buff, "%u", HR_Zone4[1]); // Convert int to char to display oled.Label((uint8_t *)display_buff, 60, 65);// Display at x,y textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y break; } case 33: {//Heart rate simulator oled.FillScreen(COLOR_BLACK); textProperties.fontColor = COLOR_WHITE; oled.Label((uint8_t *)"HR Simulation", 10, 5);// Display at x,y oled.Label((uint8_t *)"HR: ", 10, 40);// Display at x,y oled.Label((uint8_t *)"Back",10,80); // Display "Back" at x,y oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y oled.Label((uint8_t *)"On",75,25); // "*" at x,y oled.Label((uint8_t *)"Off",75,55); // "*" at x,y sprintf(display_buff, "%u", Heart_Rate); // Convert int to char to display if(Current_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } oled.Label((uint8_t *)display_buff, 35, 40);// Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; } case 43: { //Impact Thresh oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Adj I-Th", 10, 5); sprintf(display_buff, "%2.2f g", Impact_Thresh); //Convert int to char array for displaying mode oled.Label((uint8_t *)"I_Th:", 5, 30); 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 oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff,43,30); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; } case 44: { //Motion Thresh oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Adj M-Th", 10, 5); sprintf(display_buff, "%4.0f D/S", Movement_Thresh); //Convert int to char array for displaying mode oled.Label((uint8_t *)"M_Th:", 5, 30); 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 oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff,43,30); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; }//end case 44 case 45: { //Min_Movement_Time oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Adj MinM_Tim", 10, 5); sprintf(display_buff, "%1.2fSec", Min_Movement_Time); //Convert int to char array for displaying mode oled.Label((uint8_t *)"m_Tm:", 5, 30); 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 oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff,43,30); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; }//end case 45 case 46: { //Min_Movement_Time oled.FillScreen(COLOR_BLACK); oled.Label((uint8_t *)"Adj MinM_Dur", 10, 5); sprintf(display_buff, "%2.1fSec", Min_Movement_duration); //Convert int to char array for displaying mode oled.Label((uint8_t *)"mDur:", 5, 30); 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 // oled.Label((uint8_t *)"Next",60,80); //Display "Next" at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff,43,30); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; }//end case 46 case 47: { //Post fall "are you OK?" screen oled.FillScreen(COLOR_BLACK); textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Fall Detected!", 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 *)"Do you need", 5, 20); oled.Label((uint8_t *)"Help?", 10, 35); //oled.Label((uint8_t *)"+",85,15); // "*" at x,y //oled.Label((uint8_t *)"-",85,60); // "*" at x,y oled.Label((uint8_t *)"No",10,75); // Display "Back" at x,y oled.Label((uint8_t *)"YES!",60,75); //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 47 case 48: { //Sending Fall alert screen oled.FillScreen(COLOR_BLACK); textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Fall Detected!", 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 48 case 49: { //Testing WDT diagnostic screen oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"WDT Test",15,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"This will",16,25); // Display at x,y oled.Label((uint8_t *)"Cause a",17,40); // Display at x,y oled.Label((uint8_t *)"SW Reset",15,55); // Display at x,y 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 oled.Label((uint8_t *)"Enter",60,80); //Display at x,y break; }//end case 49 case 50: { //WDT timeout screen CLRWDT(); oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"WDT Test",15,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Reset in",17,25); // Display at x,y sprintf(display_buff, "%2.1f Sec", WDT_TIME); //Convert int to char array for displaying mode oled.Label((uint8_t *)display_buff,18,40); // Display at x,y //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 //oled.Label((uint8_t *)"Enter",60,80); //Display at x,y haptic = 0; 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 case 71: {// BLE oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"BLUETOOTH",15,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"Enter",60,80); //Display at x,y 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 break; } case 72: {// BlueTooth on/off oled.FillScreen(COLOR_BLACK); // Clear screen textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"BLUETOOTH",10,5); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); if (BLE_On == 1) { /* Display PAIR CODE in a 90px by 18px textbox at x=0,y=25 */ strcpy((char *) text,"PAIR CODE"); oled.TextBox((uint8_t *)text,10,25,80,18); /* Display Bond Pass Key in a 90px by 18px textbox at x=0,y=40 */ sprintf(text,"%d", kw40z_device.GetPassKey()); oled.TextBox((uint8_t *)text,10,45,80,18); } else { oled.Label((uint8_t *)" Off ",40,45); } // 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 oled.Label((uint8_t *)"Toggle",59,80); //Display "Toggle" at x,y break; } default: { Error_Num=1; error_screen(); // Clear screen break; } }//end of switch __enable_irq(); // Enable all Interrupts }// end upday_display() void error_screen(void) { oled.FillScreen(COLOR_RED); // Clear screen oled.Label((uint8_t *)"Error! ",30,30); // Display error at x,y sprintf(text_1," %i ",Error_Num); oled.Label((uint8_t *)text_1,30,60); // Display error at x,y wait(3); // wait 3 seconds oled.FillScreen(COLOR_BLACK); // Clear screen } /***************************************************************************** Name: StartHaptic Purpose: Cause the HexiHeart device to vibrate for a predetermined amount of time Inputs: None Returns: None ******************************************************************************/ void StartHaptic(void) { Haptic_Timer.attach(&Haptic_Off_,(0.05)); // hapticTimer.start(30); // was originaly 50, then 30 /* this 30 value seems to not work after Neil added a global __disable_irq() and __enable_irq() for the update_display() functions on 2/18/18 */ haptic = 1; } void Haptic_Off_(void) { haptic = 0; } /***************************************************************************** Name: StartHaptic Purpose: Cause the HexiHeart device to vibrate for x amount of time Inputs: An int representing the duration of the vibration Returns: None ******************************************************************************/ void StartHaptic(int x) { hapticTimer.start(x); haptic = 1; } void StopHaptic(void const *n) { haptic = 0; hapticTimer.stop(); } /***************************************************************************** Name: Increment_Age Purpose: Increment the user's age by 1 Inputs: None Returns: None ******************************************************************************/ void Increment_Age() { StartHaptic(); if(Age < 100) { Age += 1; Screen_Num = 27; } else { Age = 1; } } /***************************************************************************** Name: Decrement_Age Purpose: Decrement the user's age by 1 Inputs: None Returns: None ******************************************************************************/ void Decrement_Age() { StartHaptic(); if(Age == 1) { Age = 100; } else { Age -= 1; Screen_Num = 27; } } /***************************************************************************** Name: Set_Max_Bpm Purpose: Calculates the user's maximum heart rate based on their age Inputs: None Returns: None ******************************************************************************/ void Set_Max_Bpm() { Max_Bpm = 220 - Age; } /***************************************************************************** Name: Set_Zone_Boundaries Purpose: Calculates the user's heart rate zones' boundaries based on the user's maximum heart rate Inputs: None Returns: None ******************************************************************************/ void Set_Zone_Boundaries() { Set_Max_Bpm(); HR_Zone1[0] = Max_Bpm * .50; //Set Heart Rate Zone 1 HR_Zone1[1] = Max_Bpm * .60; //Set Heart Rate Zone 1 HR_Zone2[0] = HR_Zone1[1] + 1; //Set Heart Rate Zone 2 HR_Zone2[1] = Max_Bpm * .70; //Set Heart Rate Zone 2 HR_Zone3[0] = HR_Zone2[1] + 1; //Set Heart Rate Zone 3 HR_Zone3[1] = Max_Bpm * .80; //Set Heart Rate Zone 3 HR_Zone4[0] = HR_Zone3[1] + 1; //Set Heart Rate Zone 4 HR_Zone4[1] = Max_Bpm; //Set Heart Rate Zone 4 } /***************************************************************************** Name: Increment_Target_Zone Purpose: Imcrements the user's target heart rate zone preference by 1 Inputs: None Returns: None ******************************************************************************/ void Increment_Target_Zone() { StartHaptic(); if(Target_Zone == 4) { Target_Zone = 1; } else { Target_Zone += 1; } } /***************************************************************************** Name: Decrement_Target_Zone Purpose: Decrements the user's target heart rate zone preference by 1 Inputs: None Returns: None ******************************************************************************/ void Decrement_Target_Zone() { StartHaptic(); if(Target_Zone == 1) { Target_Zone = 4; } else { Target_Zone -= 1; } } /***************************************************************************** Name: Increment_HR_Vibr_Pref Purpose: Increment the user's heart rate vibration preference by 1 Inputs: None Returns: None ******************************************************************************/ void Increment_HR_Vibr_Pref() { StartHaptic(); if(HR_Vibration == 3) { HR_Vibration = 1; } else { HR_Vibration += 1; } } /***************************************************************************** Name: Decrement_HR_Vibr_Pref Purpose: Decrement the user's heart rate vibration preference by 1 Inputs: None Returns: None ******************************************************************************/ void Decrement_HR_Vibr_Pref() { StartHaptic(); if(HR_Vibration == 1) { HR_Vibration = 3; } else { HR_Vibration -= 1; } } /***************************************************************************** Name: Enable_Heart_Rate Purpose: Turn on the HexiHeart heart rate function Inputs: None Returns: None ******************************************************************************/ void Enable_Heart_Rate() { Heart_Rate_Mode = true; } /***************************************************************************** Name: Disable_Heart_Rate Purpose: Turn off the HexiHeart heart rate function Inputs: None Returns: None ******************************************************************************/ void Disable_Heart_Rate() { Heart_Rate_Mode = false; } /***************************************************************************** Name: Determine_Current_Zone Purpose: Determines which zone the heart rate is in and assigns the curent zone and previous zone Inputs: None Returns: None ******************************************************************************/ void Determine_Current_Zone() { Prev_Zone = Current_Zone; if(Heart_Rate >= HR_Zone1[0] && Heart_Rate <= HR_Zone1[1]) { Current_Zone = 1; } else if(Heart_Rate >= HR_Zone2[0] && Heart_Rate <= HR_Zone2[1]) { Current_Zone = 2; } else if(Heart_Rate >= HR_Zone3[0] && Heart_Rate <= HR_Zone3[1]) { Current_Zone = 3; } else if(Heart_Rate >= HR_Zone4[0] && Heart_Rate <= HR_Zone4[1]) { Current_Zone = 4; } else { //error reading, don't change anything } Heart_Rate_Vibrations(); } /***************************************************************************** Name: Run_Heart_Vibrations Purpose: Performs the HexiHeart heart rate function Inputs: None Returns: None ******************************************************************************/ void Heart_Rate_Vibrations() { if(HR_Vibration == 1) { //All Pre-loaded vibrations enabled if(Current_Zone == Prev_Zone) { // Do nothing if no zone change } else if(Current_Zone == Target_Zone) { //Changed to target zone if(Target_Zone == LOWEST_ZONE || Prev_Zone > Target_Zone) { //must have entered from above haptic = 1; wait(0.5); haptic = 0; wait(0.5); haptic = 1; wait(0.5); haptic = 0; } else if(Target_Zone == HIGHEST_ZONE || Prev_Zone < Target_Zone) { //must have entered from below haptic = 1; wait(0.5); haptic = 0; } } else if(Current_Zone != Target_Zone && Prev_Zone == Target_Zone) { if(Target_Zone == HIGHEST_ZONE || Current_Zone < Target_Zone) { //must have exited below haptic = 1; wait(1); haptic = 0; } else if(Target_Zone == LOWEST_ZONE || Current_Zone > Target_Zone) { //must have exited above haptic = 1; wait(1); haptic = 0; wait(1); haptic = 1; wait(1); haptic = 0; } } } else if(HR_Vibration == 2) { //Only Entering and Exiting target zone if(Current_Zone == Prev_Zone) { //do nothing } else if(Current_Zone == Target_Zone) { haptic = 1; wait(0.2); haptic = 0; wait(0.2); haptic = 1; wait(0.2); haptic = 0; } else if(Current_Zone != Target_Zone && Prev_Zone == Target_Zone) { haptic = 1; wait(1); haptic = 0; } } else if(HR_Vibration == 3) { //No Vibrations } else { //Error, can only be choices 1-3 error_screen(); } } /***************************************************************************** Name: Increment_Heart_Rate Purpose: Manually increment the the heart rate measurement by 1 for testing purposes Inputs: None Returns: None ******************************************************************************/ void Increment_Heart_Rate() { //StartHaptic(); if(Heart_Rate == HR_Zone4[1]) { Heart_Rate = HR_Zone1[0]; } else { Heart_Rate += 1; } Determine_Current_Zone(); } /***************************************************************************** Name: Decrement_Heart_Rate Purpose: Manually decrement the the heart rate measurement by 1 for testing purposes Inputs: None Returns: None ******************************************************************************/ void Decrement_Heart_Rate() { //StartHaptic(); if(Heart_Rate == HR_Zone1[0]) { Heart_Rate = HR_Zone4[1]; } else { Heart_Rate -= 1; } Determine_Current_Zone(); } /***************************************************************************** Name: Led_Zone_Indicator() Purpose: Ticker interupt routine called every 1.0 Seconds in order to Blink LED to indicate current Heart Rate zone Inputs: hr_led Ticker ******************************************************************************/ void Led_Zone_Indicator() { CLRWDT();// Reset watchdog timer before we do this long opperation if(Led_Zones == true) { if(Current_Zone == 1) { BLU_Led = LED_OFF; RED_Led = LED_ON; GRN_Led = LED_ON; hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED //wait(0.5); //RED_Led = LED_OFF; // GRN_Led = LED_OFF; } else if(Current_Zone == 2) { if(Prev_Zone == 1) { RED_Led = LED_OFF; GRN_Led = LED_OFF; } else if(Prev_Zone == 3) { GRN_Led = LED_OFF; } BLU_Led = LED_ON; hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED // wait(0.5); // BLU_Led = LED_OFF; } else if(Current_Zone == 3) { if(Prev_Zone == 2) { BLU_Led = LED_OFF; } else if(Prev_Zone == 4) { RED_Led = LED_OFF; } GRN_Led = LED_ON; hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED // wait(0.5); // GRN_Led = LED_OFF; } else if(Current_Zone == 4) { GRN_Led = LED_OFF; RED_Led = LED_ON; hr_led.attach(&Led_Zone_Indicator_off, HR_LED_on_time); // in 0.5 seconds turn off LED // wait(0.5); // RED_Led = LED_OFF; } } }//end of Led_Zone_Indicator /***************************************************************************** Name: Led_Zone_Indicator_off() Purpose: Ticker interupt routine called every 0.5 Seconds after LEDs turned on to turn them back off. This avoids the 0.5 wait every second, freeing up the system. Inputs: hr_led Ticker ******************************************************************************/ //turns off LEDs after 0.5 seconds instead of using a wait command void Led_Zone_Indicator_off(){ RED_Led = LED_OFF; GRN_Led = LED_OFF; BLU_Led = LED_OFF; hr_led.attach(&Led_Zone_Indicator, HR_LED_period); // blink every second }//end void Led_Zone_Indicator_off() /***************************************************************************** Name: Heat_Index_Calculation() Purpose: Calculates the heat index using the temperature and humidity sensors Inputs: None Returns: None ******************************************************************************/ void Heat_Index_Calculation(){ //sample_ftemp = temphumid.sample_ftemp(); //sample_humid = temphumid.sample_humid(); hi_calc = -42.379 + 2.04901523 * sample_ftemp + 10.14333127 * sample_humid - 0.22475541 * sample_ftemp * sample_humid - 0.00683783 * sample_ftemp * sample_ftemp - 0.05481717 * sample_humid * sample_humid + 0.00122874 * sample_ftemp * sample_ftemp * sample_humid + 0.00085282 * sample_ftemp * sample_humid * sample_humid - 0.00000199 * sample_ftemp * sample_ftemp * sample_humid * sample_humid; if (sample_humid < 13 && sample_ftemp > 80 && sample_ftemp < 112){ adjustment = ((13 - sample_humid) / 4) * sqrt((17-abs(sample_ftemp-95.0))/17); heat_index = hi_calc - adjustment; } else if (sample_humid > 85 && sample_ftemp > 80 && sample_ftemp < 87){ adjustment = ((sample_humid - 85) / 10) * ((87 - sample_ftemp)/5); heat_index = hi_calc + adjustment; } else if (hi_calc < 80){ heat_index = 0.5 * (sample_ftemp + 61.0 + ((sample_ftemp - 68.0) * 1.2) + (sample_humid * 0.094)); } else {heat_index = hi_calc;} } /***************************************************************************** Name: fall_detect_debug() Purpose: Debug Interupt routine called when accelerometer IC has detected a free-fall (accel <= 0.5g) Inputs: interupt1 of accel sensor ******************************************************************************/ void fall_detect_debug(){// fall detect interupt routine if(Fall_Alert == 1){ 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(); } // endif if (Screen_Num != 21){ Screen_Num = 21; //Change to screen 21 (Fall diag screen) update_display(); } // endif //__disable_irq(); // Disable all Interrupts // oled.Label((uint8_t *)" Fall Detected ",05,70); // Display at x,y Accel_Mag = 2*sqrt(((Accel_Data_Event[0]*Accel_Data_Event[0])+(Accel_Data_Event[1]*Accel_Data_Event[1])+(Accel_Data_Event[2]*Accel_Data_Event[2]))); sprintf(text_1,"Free-Fall:%2.2fg",Accel_Mag); oled.Label((uint8_t *)text_1,2,5);// text_1 at x,y BLU_Led = LED_ON; // LEDs default to on, need to turn off Led_clk1 = 1; // Turn on LED1, on docking station StartHaptic(); // haptic = 1; Accel_INT1.rise(&fall_det_end_debug); // reset accel sensor's int#1 to active high and proper int routine //__enable_irq(); // Enable all Interrupts }// end if }//end fall_detect_debug interupt routine /***************************************************************************** Name: fall_det_end_debug() Purpose: Debug interupt routine called when accelerometer IC has detected that the free-fall acceleration has ended (accel now >0.5g) Inputs: interupt1 of accel sensor ******************************************************************************/ void fall_det_end_debug(){ haptic = 0; // Turn off Haptic BLU_Led = LED_OFF; // Turn off HexiHeart Blue LED Led_clk1 = 0; // Turn off LED1, on docking station fall_config(21); // reads interrupts to clear old interupt // oled.Label((uint8_t *)" ",05,70); // clear display at x,y Accel_INT1.fall(&fall_detect_debug); // reset accel sensor's int#1 to active low and proper int routine } //end fall_det_end_debug interupt routine /***************************************************************************** Name: impact_detect_debug() Purpose: Debug Interupt routine called when accelerometer IC has detected a vector magnitude acceleration >= 3.0g Inputs: interupt2 of accel sensor ******************************************************************************/ void impact_detect_debug(){ if(Fall_Alert == 1){ accel.acquire_accel_data_g(Accel_Data_Event); haptic = 1; 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(); } // endif if (Screen_Num != 21){ Screen_Num = 21; //Change to screen 21 (Fall diag screen) update_display(); } // endif accel.acquire_accel_data_g(Accel_Data); Accel_Mag = 2*sqrt(((Accel_Data_Event[0]*Accel_Data_Event[0])+(Accel_Data_Event[1]*Accel_Data_Event[1])+(Accel_Data_Event[2]*Accel_Data_Event[2]))); sprintf(text_1,"Impact:%2.2fg",Accel_Mag); oled.Label((uint8_t *)text_1,3,20);// text_1 at x,y wait(0.1); Led_clk2 = 0; // Turn LED2 off docking station on haptic = 0; }// end if }//end impact_detect_debug interupt routine /***************************************************************************** Name: motion_detect_debug() Purpose: Debug Interupt routine called when gyro IC has detected motion >= 50 deg/sec in order to see if fall-impact resulted in motion-less person. Inputs: interupt1 of gyro sensor ******************************************************************************/ void motion_detect_debug(){ float Gyro_Data_Event[3]; // store right away to see what it was if(Fall_Alert == 1 && Fall_Alert_Mode > 2){// only service interupt if automatic fall detect is selected by user gyro.acquire_gyro_data_dps(Gyro_Data_Event); Gyro_Mag = (abs(Gyro_Data_Event[0])+abs(Gyro_Data_Event[1])+abs(Gyro_Data_Event[2])); haptic = 1; 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(); } // endif if (Screen_Num != 21){ Screen_Num = 21; //Change to screen 21 (Fall diag screen) update_display(); } // endif sprintf(text_1,"Motion:%4.0f d/s",Gyro_Mag); oled.Label((uint8_t *)text_1,3,20);// text_1 at x,y gyro_sensor_config(13); // reset motion counter wait(0.1); Led_clk3 = 0; // Turn LED3 off docking station on haptic = 0; }// end if }//end motion_detect_debug interupt routine //********** Full sequential fall interup routines below ********************* /***************************************************************************** Name: fall_detect() Purpose: Interupt routine called when accelerometer IC has detected a free-fall (accel <= 0.5g) Inputs: interupt1 of accel sensor ******************************************************************************/ void fall_detect(){// fall detect interupt routine if(Fall_Alert == 1 && Led_clk2 == 0){// are we looking for falls? Have we already det impact? accel.acquire_accel_data_g(Accel_Data_Event); f_time.reset(); f_time.start(); //start measuring fall time for (int i=0; i<7; i++){ Fall_Event_Data[i] = 0; // clear any old information }//end for loop // Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED //time_t seconds = time(NULL); //store time into Fall_Event_Data buffer Fall_Event_Data[0] = 2*sqrt(((Accel_Data_Event[0]*Accel_Data_Event[0])+(Accel_Data_Event[1]*Accel_Data_Event[1])+(Accel_Data_Event[2]*Accel_Data_Event[2]))); Led_clk1 = 1; // Turn on LED1, on docking station //Led_clk2 = 0; // Turn off LED2, on docking station Accel_INT1.rise(&fall_det_end); // look for end of fall by reseting accel sensor's int#1 to active high // Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine Accel_INT2.fall(&impact_detect); //Start looking for vector impacts // Gyro_INT1.fall(&motion_detect); // Gyro sensor's int#1 (PTD1) calls interupt routine chk_fall.attach(&chkfall,(0.5)); //initialize ticker to check for end of fall every half second }// end if }//end fall_detect interupt routine /***************************************************************************** Name: chkfall() Purpose: Ticker interupt routine called every 0.5 Seconds (after a free-fall has been detected) to check to see if we've missed the interupt indicating the free-fall event is over. Inputs: chk_fall Ticker ******************************************************************************/ void chkfall(){// Ticker fall-end detect routine to see if we missed interupt if(Accel_INT1 == 0){//fall still active accel.acquire_accel_data_g(Accel_Data_Event); Accel_Mag = 2*sqrt(((Accel_Data_Event[0]*Accel_Data_Event[0])+(Accel_Data_Event[1]*Accel_Data_Event[1])+(Accel_Data_Event[2]*Accel_Data_Event[2]))); if (Accel_Mag < Fall_Event_Data[0]){ Fall_Event_Data[0] = Accel_Mag;// if fall is less than previous re-store value }//endif }//endif else{//fall interupt off f_time.stop(); // stop fall timer chk_fall.detach(); //stop ticker, interupt caught end of fall chk_fall.attach(&clear_fall,(2.0)); //initialize ticker to check no impact in 2 seconds Accel_INT1.fall(NULL); // turn off accel sensor's int#1 }//end else }//end chkfall ticker interupt routine /***************************************************************************** Name: interupt_off() Purpose: Interupts are supposed to be turned off by using "Int_name.fall(NULL);", but that doesn't seem to work. ******************************************************************************/ void interupt_off(){// turn off an interupt by substituting this one // Do nothing }//end interupt_off routine /***************************************************************************** Name: fall_det_end() Purpose: Interupt routine called when accelerometer IC has detected that the free-fall acceleration has ended (accel now >0.5g) Inputs: interupt1 of accel sensor ******************************************************************************/ void fall_det_end(){ // accel detected end of free-fall f_time.stop(); // stop fall timer chk_fall.detach(); //stop ticker, interupt caught end of fall chk_fall.attach(&clear_fall,(Fall_Impact_Max_Wait_Time)); //initialize ticker to check no impact in 2 seconds // fall_config(21); // reads interrupts to clear old interupt Accel_INT1.fall(NULL); // Turn off accel sensor's int#1 } //end fall_det_end interupt routine /***************************************************************************** Name: clear_fall() Purpose: Ticker interupt routine called to clear/cancel fall detection routine if no impact was detected withing 2.0 seconds after the free-fall event Inputs: chk_fall Ticker ******************************************************************************/ void clear_fall(){// Ticker routine to clear_fall detect routine if no impact in 2.0 seconds after free-fall event is over if(Led_clk2 == 1){// have we detected an impact? chk_fall.detach(); //just stop ticker }//endif else{ Accel_INT1.fall(&fall_detect); // reset accel sensor's int#1 to active low and reset for next fall Accel_INT2.fall(NULL); //Stop looking for vector impacts, Led_clk1 = 0; // Turn off LED1, on docking station }//end else }//end clear_fall ticker interupt routine /***************************************************************************** Name: impact_detect() Purpose: Interupt routine called when accelerometer IC has detected a vector magnitude acceleration >= 3.0g Inputs: interupt2 of accel sensor ******************************************************************************/ void impact_detect(){// we may detect multiple impacts, this needs to work from last impact detected if(Fall_Alert == 1){ f_time.stop(); // stop fall timer accel.acquire_accel_data_g(Accel_Data_Event); chk_fall.detach(); //detach/stop ticker, impact was detected wait(0.1); Fall_Event_Data[1] = f_time;// store free-fall time Led_clk2 = 1; // Turn on LED2, on docking station gyro_sensor_config(13); // reset motion counter Gyro_INT1.fall(&motion_detect); // Start looking for motion chk_motion.attach(&chkmotion,(Min_Movement_duration)); //initialize ticker to check for motion during Min_Movement_duration } // endif Accel_Mag = 2*sqrt(((Accel_Data_Event[0]*Accel_Data_Event[0])+(Accel_Data_Event[1]*Accel_Data_Event[1])+(Accel_Data_Event[2]*Accel_Data_Event[2]))); if(Accel_Mag>Fall_Event_Data[2]){ Fall_Event_Data[2] = Accel_Mag; // if impact accel is higher than last measured, update }//endif haptic = 1;// vibrate a little wait_ms(50); haptic = 0; //wait(0.1); //Led_clk3 = 1; // Turn on LED3, on docking station - we're looking for motion }//end impact_detect interupt routine /***************************************************************************** Name: motion_detect() Purpose: Interupt routine called when gyro IC has detected motion >= 50 deg/sec in order to see if fall-impact resulted in motion-less person. Inputs: interupt1 of gyro sensor ******************************************************************************/ void motion_detect(){// 2 seconds of motion was detected chk_motion.detach(); //stop ticker, we've detected motion Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine Accel_INT2.fall(NULL); //Reset for next event Gyro_INT1.fall(NULL); //Reset for next event //wait(0.1); Led_clk1 = 0; // Turn off LED1, on docking station Led_clk2 = 0; // Turn off LED2, on docking station }//end motion_detect interupt routine /***************************************************************************** Name: chkmotion() Purpose: Ticker interupt routine called when 60sec window has elapsed without 2seconds of motion being detected. Inputs: chk_motion Ticker ******************************************************************************/ void chkmotion(){// if we got here we didn't detect motion // chk_motion.detach(); //stop ticker Screen_Num = 47; //Change to screen 47 (Fall diag screen) Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED 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(); haptic = 1; wait(0.2);// aggressive hapic haptic = 0; wait(0.2); haptic = 1; wait(0.2);// aggressive hapic CLRWDT(); haptic = 0; wait(0.2); haptic = 1; wait(0.2);// aggressive hapic haptic = 0; }//end of chkmotion ticker interupt routine /***************************************************************************** Name: chk_help_needed() Purpose: Ticker interupt routine called when X sec window has elapsed without user dimissing "Are you OK" screen, sends automatic alert. Inputs: chk_motion Ticker ******************************************************************************/ void chk_help_needed(){// Were they able to dismiss on their own? // chk_motion.detach(); //stop ticker if (Screen_Num == 47){// are we still on screen 47? Screen_Num = 48; //Change to screen 48 and send alert Screen_Timer.attach(&timout_timer,(SCRN_TIME));// Reset/restart ticker timer for OLED to keep it on 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); textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"No response!", 5, 20); textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); Send_Alert(30); // send alert type two CLRWDT(); haptic = 1; wait(0.5);// very aggressive hapic haptic = 0; wait(0.2); haptic = 1; CLRWDT(); wait(0.5);// very aggressive hapic haptic = 0; wait(0.2); haptic = 1; CLRWDT(); wait(0.5);// very aggressive hapic haptic = 0; } // endif }//end of chkmotion ticker interupt routine /***************************************************************************** Name: Send_Alert() Purpose: routine used to store and send alert Inputs: int value from 0 to 256 10=Panic, 20=Fall+asked for help, 30=Fall+No response, 40=?... Returns: None ******************************************************************************/ void Send_Alert(uint8_t Num){ // store alert // ************ transmit alert /*Notify Hexiwear App that it is running Sensor Tag mode*/ kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG); /*Send Ambient Light Level at with aler number */ //10=Panic, 20=Fall+asked for help, 30=Fall+No response, 40=?... kw40z_device.SendAmbientLight(Num); }//end Send_Alert routine /***************************************************************************** Name: fall_config() Purpose: routine used to set accelerometer and gyro sensors' internal registers for chip level interrupts Inputs: int value from 0 to 256 Returns: None ******************************************************************************/ void fall_config(uint8_t Num){ // this is more than just accel config // use case switches here to configure for switch(Num) { case 0: {// put in standby accel_sensor_config(0); // set accel sensor to standby /*For lowest accel power ~2uA in standby mode */ gyro_sensor_config(0); // set gyro sensor to standby /*For lowest gyro power ~2.8uA in standby mode */ Accel_INT1.fall(NULL); // Turn off Accel sensor's int#1 Accel_INT2.fall(NULL); // Turn off Accel sensor's int#2 Gyro_INT1.fall(NULL); // Turn off Gyro sensor's int#1 break; }// end of case 0 case 1: {// configure for free-fall int only accel_sensor_config(1); // set accel sensor for free-fall gyro_sensor_config(0); // set gyro sensor to standby Accel_INT1.fall(NULL); // Turn off Accel sensor's int#1 Accel_INT2.fall(NULL); // Turn off Accel sensor's int#2 Gyro_INT1.fall(NULL); // Turn off Gyro sensor's int#1 Accel_INT1.fall(&fall_detect_debug); // Accel sensor's int#1 calls interupt routine break; }// end of case 1 case 2: {// configure for vector impact only accel_sensor_config(2); // set accel sensor vector impact only gyro_sensor_config(0); // set gyro sensor to standby Accel_INT1.fall(NULL); // Turn off Accel sensor's int#1 // Accel_INT2.fall(NULL); // Turn off Accel sensor's int#2 Gyro_INT1.fall(NULL); // Turn off Gyro sensor's int#1 Accel_INT2.fall(&impact_detect_debug); //Accel sensor's int#2 calls interupt routine break; }// end of case 2 case 3: {// configure for motion int only accel_sensor_config(0); // set accel sensor vector impact only gyro_sensor_config(3); // set gyro sensor to standby Accel_INT1.fall(NULL); // Turn off Accel sensor's int#1 Accel_INT2.fall(NULL); // Turn off Accel sensor's int#2 Gyro_INT1.fall(&motion_detect_debug); // Gyro sensor's int#1 (PTD1) calls interupt routine break; }// end of case 3 case 4: {// configure FFMT for free-fall event AND config for vector impact accel_sensor_config(4); // set accel sensor Free-fall and vector impact gyro_sensor_config(3); // set gyro sensor motion Accel_INT1.fall(&fall_detect_debug); // Accel sensor's int#1 calls interupt routine Accel_INT2.fall(&impact_detect_debug); //Accel sensor's int#2 calls interupt routine Gyro_INT1.fall(&motion_detect_debug); // Gyro sensor's int#1 (PTD1) calls interupt routine break; }// end of case 4 case 5: {// configure for sequential free-fall, vector impact then motion accel_sensor_config(4); // set accel sensor Free-fall and vector impact gyro_sensor_config(3); // set gyro sensor motion Accel_INT1.fall(&fall_detect); // Accel sensor's int#1 calls interupt routine Accel_INT2.fall(NULL); //Accel sensor's int#2 calls interupt routine Gyro_INT1.fall(NULL); // Gyro sensor's int#1 (PTD1) calls interupt routine break; }// end of case 4 case 10: {// reset IC accel_sensor_config(10); // reset accel sensor gyro_sensor_config(10); // reset gyro sensor break; }// end case 10 case 11: {// wake both sensors for simple data read, they were in stanby accel_sensor_config(11); // set accel sensor active for read gyro_sensor_config(11); // set accel sensor active for read break; }// end of case 11 case 12: {// put into standby for low power accel_sensor_config(12); // set accel sensor to standby gyro_sensor_config(12); // set gyro sensor to standby break; }// end of case 112 case 20: {// read INT_Source to clear VECM int, shouldn't have to do this // This was not working for me but it was due to me using the wrong FXOS8700_I2C_ADDRESS_ char d[2];//, data_byte_[1]; d[0] = 0x0c; // 0x0c is INT_Source Reg i2c_bus1.write(FXOS8700_I2C_ADDRESS_,d,1,true); // "true" is needed to prevent stop wait(0.01); if(i2c_bus1.read(FXOS8700_I2C_ADDRESS_,d,1) == 1){ // read Who am I Reg for debug sprintf(text_1," INT_Read_Err "); oled.Label((uint8_t *)text_1,5,50); // Display error at x,y wait(1); // wait 1 seconds }//endif break; }// end of case 20 case 21: {// read A_FFMT_SRC reg to clear FFMT int, shouldn't have to do this // This was not working for me but it was due to me using the wrong FXOS8700_I2C_ADDRESS_ char d[2];//, data_byte_[1]; d[0] = 0x16; // 0x16 is A_FFMT_SRC Reg i2c_bus1.write(FXOS8700_I2C_ADDRESS_,d,1,true); // "true" is needed to prevent stop wait(0.01); if(i2c_bus1.read(FXOS8700_I2C_ADDRESS_,d,1) == 1){ // read Who am I Reg for debug sprintf(text_1," INT_Read_Err "); oled.Label((uint8_t *)text_1,5,50); // Display error at x,y wait(1); // wait 1 seconds }//endif break; }// end of case 21 default: { oled.Label((uint8_t *)" Mode? ",30,60); // Display "mode" at x,y // unknown config break; } }// end switch }// end Fall_config /***************************************************************************** Name: accel_sensor_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 accel_sensor_config(uint8_t Num){ // use case switches here to configure for switch(Num) { case 0: {// put in standby char d[2]; d[0] = FXOS8700_CTRL_REG1; //Puts device in Standby mode d[1] = 0x00; i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2); /*For lowest power ~8uA, set ODR-12.5Hz,(low-pwr accel mode) or 2uA in standby mode */ break; }// end of case 0 case 1: {// configure for free-fall int only char d[2]; d[0] = 0x2a; //0x2a Config reg1 d[1] = 0x00; //Put device in Standby mode if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc1a err",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] = 0b00000001; //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 *)"Acc1b err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if /* d[0] = 0x0a; //TRIG_CFG (address of FIFO 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 *)"Acc1c err",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 *)"Acc1d err",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 *)"Acc1e err",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 d[1] = 0b00001001; //Turns Auto-Sleep mode off (b/c it wasn't waking on int) and low-noise, low power if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc1f err",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 *)"Acc1g err",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] = 0b10000100; // 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 *)"Acc1h err",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 *)"Acc1i err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x29; //ASLP_Count (counter used to go to sleep reg), write in Standby only d[1] = 0b00001010; // 10*320mS=3.2S of no inturrupts to go to sleep if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc1j err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x2a; //0x2a Config 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 *)"Acc1k err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 1 case 2: {// configure for vector impact only char d[2]; d[0] = FXOS8700_CTRL_REG1; //Config reg1 0x2a d[1] = 0x00; //Put device in Standby mode if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2a err",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] = 0b00000001; //Set data to +/-4g for full range (0.488mg/LSB), High-pass filter off if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2b err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if /* d[0] = 0x0a; //TRIG_CFG (address of FIFO trigger config reg) d[1] = 0b00000110; //Trigger on freefall and on Vector 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] = 0x5f; //A_VECM_CFG (address of Vector config reg), write in Standby only d[1] = 0b00111000; //Use reference values, don't update ref, enable. if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2c err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x60; //A_VECM_MSB (address of Vector threshold reg), write in Active or Standby // d[1] = 0b00000111; //set impact threshold to less than 1g for now d[1] = (uint8_t)((1000*Impact_Thresh/0.488f)/256); //set MSB Impact threshold - Resolution is 0.488mg/LSB so 0.5g=1024.6 => MSB=0b00000100 LSB=0b00000000 if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2d err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x61; //A_VECM_LSB (address of Vector threshold reg), write in Active or Standby // d[1] = 0b00000011; //set impact threshold to less than 1g for now d[1] = (uint8_t)(1000*Impact_Thresh/0.488f); d[1] = (uint8_t)(d[1]%256); //set MSB Impact threshold - Resolution 0.488mg/LSB so 0.5g=1024.6 => MSB=0b00000100 LSB=0b00000000 if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2e err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x62; //A_VECM_COUNT (address of Vector debounce counter), write in Active or Standby d[1] = 0b00000110; //with ODR at 100Hz, should equal ??mS debounce time or ??mS in Sleep if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2f err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // Registers 0x63 - 0x68 are vector reference values which I'm leaving set to 0 because we want absolute measurements 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 d[1] = 0b00001001; //Turns Auto-Sleep mode off (b/c it wasn't waking on int) and low-noise, low power if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2g err",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] = 0b00000100; //Vector will wake chip from sleep, int are active high // 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 *)"Acc2h err",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] = 0b10000010; // Vector int enabled // d[1] = 0b00000100; // FFMT int enabled if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2i err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if //wait(0.2); // people have had a problem here and needed a delay d[0] = 0x2e; //CTRL_REG5 (Int routing reg), write in Standby only d[1] = 0b00000100; // Make FFMT int output on pin INT1(PTC1) and Vector on INT2(PTD13) if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2j err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x29; //ASLP_Count (counter used to go to sleep reg), write in Standby only d[1] = 0b00001010; // 10*320mS=3.2S of no inturrupts to go to sleep if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc2k err",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 *)"Acc2L err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 2 case 3: {// configure for motion int only char d[2]; d[0] = 0x2a; //0x2a Config reg1 d[1] = 0x00; //Put device in Standby mode if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc3a err",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] = 0b00000001; //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 *)"Acc3b err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x2a; //0x2a Config 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 *)"Acc3c err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 3 case 4: {// configure FFMT for free-fall event AND config for vector impact char d[2]; d[0] = 0x2a; //0x2a Config reg1, d[1] = 0x00; //Put device in Standby mode if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4a err",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] = 0b00000001; //Set data to +/-4g for full range (0.488mg/LSB), High-pass filter off if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4b err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if /* d[0] = 0x0a; //TRIG_CFG (address of FIFO trigger config reg) d[1] = 0b00000110; //Trigger on freefall and on Vector 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 *)"Acc4c err",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 *)"Acc4d err",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 *)"Acc4e err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x5f; //A_VECM_CFG (address of Vector config reg), write in Standby only d[1] = 0b00111000; //Use reference values, don't update ref, enable. if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4f err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x60; //A_VECM_MSB (address of Vector threshold reg), write in Active or Standby // d[1] = 0b00000111; //set impact threshold to less than 1g for now d[1] = (uint8_t)((1000*Impact_Thresh/0.488f)/256); //set MSB Impact threshold - Resolution is 0.488mg/LSB so 0.5g=1024.6 => MSB=0b00000100 LSB=0b00000000 if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4g err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x61; //A_VECM_LSB (address of Vector threshold reg), write in Active or Standby // d[1] = 0b00000011; //set impact threshold to less than 1g for now d[1] = (uint8_t)(1000*Impact_Thresh/0.488f); d[1] = (uint8_t)(d[1]%256); //set MSB Impact threshold - Resolution 0.488mg/LSB so 0.5g=1024.6 => MSB=0b00000100 LSB=0b00000000 if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4h err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x62; //A_VECM_COUNT (address of Vector debounce counter), write in Active or Standby d[1] = 0b00000100; //with ODR at 100Hz, 0x04 should equal 40mS debounce time or 80mS in 50Hz Sleep if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4i err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // Registers 0x63 - 0x68 are vector reference values which I'm leaving set to 0 because we want absolute measurements 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 d[1] = 0b00001001; //Turns Auto-Sleep mode off (b/c it wasn't waking on int) and low-noise, low power if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4jerr",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] = 0b00001100; //FFMT or Vector will wake chip from sleep, int are active high if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4k err",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] = 0b10000110; // FFMT and Vector int enabled if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4L err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // wait(0.2); // people have had a problem here and needed a delay d[0] = 0x2e; //CTRL_REG5 (Int routing reg), write in Standby only d[1] = 0b00000100; // Make FFMT int output on pin INT1(PTC1) and Vector on INT2(PTD13) if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4m err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x29; //ASLP_Count (counter used to go to sleep reg), write in Standby only d[1] = 0b00001010; // 10*320mS=3.2S of no inturrupts to go to sleep if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"Acc4n err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x2a; //0x2a Config 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 *)"Acc4o err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 4 case 10: {// reset IC char d[2]; d[0] = 0x2a; //0x2a Config reg1 d[1] = 0x00; //Put device in Standby mode if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)" Step10a err",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = 0x2b; //CTRL_REG2 d[1] = 0b01000000; // set bit to force reset of FXOS8700 if(i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)" Reset error ",30,05); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // oled.Label((uint8_t *)"Acc_Reset",20,60); // Display "reset" at x,y break; }// end case 10 case 11: {// wake for simple data read, was in stanby char d[2]; d[0] = FXOS8700_CTRL_REG1; //Puts device in Standby mode just in case d[1] = 0x00; i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2); d[0] = 0x0e; //XYZ_DATA_CFG (set full-scall range) d[1] = 0b00000001; //Set data to +/-4g for full range (0.488mg/LSB), High-pass filter off i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d,2); /*For lowest power ~8uA, set ODR-12.5Hz,(low-pwr accel mode) or 2uA in standby mode */ d[0] = 0x2a; //0x2a Config 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 i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d, 2); break; }// end of case 11 case 12: {// put into standby for low power char d[2]; d[0] = FXOS8700_CTRL_REG1; //Puts device in Standby mode d[1] = 0x00; i2c_bus1.write(FXOS8700_I2C_ADDRESS_, d, 2); /*For lowest power ~8uA, set ODR-12.5Hz,(low-pwr accel mode) or 2uA in standby mode */ break; }// end of case 11 case 20: {// read INT_Source to clear VECM int, shouldn't have to do this // This was not working for me but it was due to me using the wrong FXOS8700_I2C_ADDRESS_ char d[2];//, data_byte_[1]; d[0] = 0x0c; // 0x0c is INT_Source Reg i2c_bus1.write(FXOS8700_I2C_ADDRESS_,d,1,true); // "true" is needed to prevent stop wait(0.01); if(i2c_bus1.read(FXOS8700_I2C_ADDRESS_,d,1) == 1){ // read Who am I Reg for debug sprintf(text_1," INT_Read_Err "); oled.Label((uint8_t *)text_1,5,50); // Display error at x,y wait(1); // wait 1 seconds }//endif break; }// end of case 20 case 21: {// read A_FFMT_SRC reg to clear FFMT int, shouldn't have to do this // This was not working for me but it was due to me using the wrong FXOS8700_I2C_ADDRESS_ char d[2];//, data_byte_[1]; d[0] = 0x16; // 0x16 is A_FFMT_SRC Reg i2c_bus1.write(FXOS8700_I2C_ADDRESS_,d,1,true); // "true" is needed to prevent stop wait(0.01); if(i2c_bus1.read(FXOS8700_I2C_ADDRESS_,d,1) == 1){ // read Who am I Reg for debug sprintf(text_1," INT_Read_Err "); oled.Label((uint8_t *)text_1,5,50); // Display error at x,y wait(1); // wait 1 seconds }//endif break; }// end of case 21 default: { oled.Label((uint8_t *)" Mode? ",30,60); // Display "mode" at x,y // unknown config break; } }// end switch }// end accel_sensor_cconfig /***************************************************************************** Name: gyro_sensor_config() Purpose: Used to set gyro IC's internal registers for chip level interrupts and power modes Inputs: int value from 0 to 256 Returns: None ******************************************************************************/ void gyro_sensor_config(uint8_t Num){ // use case switches here to configure for switch(Num) { case 0: {// put in standby /*For lowest power ~2.8uA in standby mode */ char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0b00001100; //puts device in standby mode and leaves ODR set to 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err0a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 0 case 1: {// Fall_Alert mode=1, put in active mode se we can read gyro measurments char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0x00; //Puts device in standby mode if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err1a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = FXAS21002_CTRL_REG0; //CTRL_REG0=0x0d d[1] = 0x00; //sets FS =+/- 2000 dps if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err1b",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0x0e; //0x0e puts device in active mode with ODR = 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err1c",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 1 case 3: {// Fall_Alert mode 3, set up interupt, put in active mode char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0x00; //0x08 puts device in standby mode if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // set RT_CFG reg 0x0e - Rate int config d[0] = 0x0e; //set RT_CFG reg 0x0e - Rate int config d[1] = 0b00000111; // enable x,y,z axis if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // set RT_THS reg 0x10 - Rate Threshold value d[0] = 0x10; //set RT_THS reg 0x10 - Rate Threshold config // d[1] = 0b00000111; // bit7=couter mode(1=clr,0=dec), rate Tresh(dps)=(THS+1)*Sensitivity(dps/LSB // Sensitivity(dps/LSB), we should have mdps/LSB=62.50 or a full range of +/- 2000 dps // Movement_Thresh 50 dps=(THS+1)*256*Sensitivity(dps/LSB) => THS = Movement_Thresh/(16.0f)-1 // We specified that 50 dps was the magnitude some of all 3 axis so THS is 1/3 of that d[1] = (uint8_t)((Movement_Thresh/(3*16.0f))-1); // Movement_Thresh 50 dps setting Tresh(dps)=(THS+1)*256*Sensitivity(dps/LSB) if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3b",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // set RT_COUNT reg 0x11 - Rate Threshold counter d[0] = 0x11; //set RT_COUNT reg 0x11 - Rate Threshold counter // d[1] = 0b10000000; // debounce count value (Count=10, ODR=100Hz => 100mS) d[1] = (uint8_t)(Min_Movement_Time/0.01f); // debounce count value (at ODR=100Hz, each count = 10mS) 2.55s=255 // need to calculate and store this value if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3c",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // set CTRL_REG2 reg 0x14 - Int config d[0] = 0x14; //set CTRL_REG2 reg 0x14 - Int config d[1] = 0b01110000; // enable RT &FIFO interupts, int=act_low, push/pull if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3d",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // set CTRL_REG3 reg 0x15 - Auto inc config, external power, FSR <=don't need? d[0] = 0x15; //CTRL_REG3 reg 0x15 d[1] = 0x00; //Auto inc config, external power, FSR if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3e",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = FXAS21002_CTRL_REG0; //CTRL_REG0=0x0d d[1] = 0x00; //sets FS=0,mdps/LSB=62.50 => +/- 2000 dps if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3f",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1 0x13 - Op mode, ODR selection, reset d[1] = 0b00001110; //0x0e puts device in active mode and sets ODR to 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err3g",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 3 case 10: {// reset Gyro IC char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1 0x13 - Op mode, ODR selection, reset d[1] = 0b01000000; //resets IC if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err10a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if // oled.Label((uint8_t *)"G_Reset ",30,45); // Display "reset" at x,y break; }// end case 10 case 11: {// set sensor to active to read gyro measurments char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0b00001110; //0x0e puts device in active mode with ODR = 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err11a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 11 case 12: {// put in standby /*For lowest power ~2.8uA in standby mode */ char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0b00001100; //puts device in standby mode and leaves ODR set to 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err12a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 12 case 13: {// put in standby then back to active, to clear counter /*For lowest power ~2.8uA in standby mode */ char d[2]; d[0] = FXAS21002_CTRL_REG1; //CTRL_REG1=0x13 d[1] = 0b00001100; //puts device in standby mode and leaves ODR set to 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err12a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if d[1] = 0b00001110; //0x0e puts device in active mode with ODR = 100Hz if(i2c_bus1.write(FXAS21002_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"gyr_err11a",20,45); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 13 default: { oled.Label((uint8_t *)"Gyro_Mode?",20,45); // Display "mode" at x,y // unknown config break; } }// end switch }// end gyro_sensor_config /***************************************************************************** Name: press_config() Purpose: Used to set pressure sensor's internal registers for power modes Inputs: int value from 0 to 256 Returns: None ******************************************************************************/ void press_config(uint8_t Num){ // use case switches here to configure switch(Num) { case 0: {// put in standby (AKA powered down) mode //For lowest power ~2.8uA in standby mode, sensor should default to this after reset char d[2]; d[0] = 0x26; //CTRL_REG1=0x26 d[1] = 0x00; //Puts device in powered down mode if(i2c_bus1.write(0xC0, d,2) ==1){ // 0xc0 is MPL3115A2 address oled.Label((uint8_t *)"press_err0a",20,30); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 0 default: { oled.Label((uint8_t *)"PRESS_Mode?",20,45); // Display "mode" at x,y // unknown config break; } }// end switch }// end press_config /***************************************************************************** Name: MAX30101_test_config() Purpose: Used to test operation of the MAX30101 heart-rate sensor Inputs: int value from 0 to 256 Returns: None ******************************************************************************/ void MAX30101_test_config(uint8_t Num){ // use case switches here to configure switch(Num) { case 0: {// test char d[2] = {0xfe, 0x07}; if(i2c_bus0.read(0xae, d, 2) == 1){ // read RevID value 0-255 sprintf(text_1,"M_R_Er %i %i",d[0],d[1]); oled.Label((uint8_t *)text_1,5,16); // Display error at x,y }//end if else{ sprintf(text_1,"M_R_data %i %i",d[0],d[1]); oled.Label((uint8_t *)text_1,5,16); // Display good data at x,y } wait(1); // wait 1 seconds d[0] = 0x09; // Mod_conf reg - SHDN, reset, modes d[1] = 0b00000111; // set mode to red, green and/or IR LEDs if(i2c_bus0.write(0xaf, d, 1) ==1){; // "true" is needed to prevent stop, MAX30101 address is 0xae but left shifted oled.Label((uint8_t *)"MAX_W_err0a",5,30); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if wait(5); // wait 5 seconds /* d[0] = 0xfe; //lets try to read revID value 0-255 d[1] = 0x00; //Puts device in powered down mode if(i2c_bus0.write(0xae<<1, d,2) ==1){ // MAX30101 address is 0xae but left shifted oled.Label((uint8_t *)"Max_err0a",20,30); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if */ break; }// end of case 0 case 10: {// reset if(maxim == 0) { } else { char d[2]; d[0] = 0x09; // Mod_conf reg - SHDN, reset, modes d[1] = 0b01000000; //resets IC if(i2c_bus0.write(0xaf, d, 2) ==1){ oled.Label((uint8_t *)"MAX_W_Err10a",5,1); // Display "error" at x,y wait(2.0); // wait 0 seconds }//end if else { // oled.Label((uint8_t *)"MAX_Reset",20,30); // Display "reset" at x,y } wait(0.01); // wait 0.01 seconds } break; }// end of case 10 default: { oled.Label((uint8_t *)"MAX_Mode?",20,45); // Display "mode" at x,y // unknown config break; } }// end switch }// end light_config /***************************************************************************** Name: light_config() Purpose: Used to set ambient light sensor's internal registers for power modes Inputs: int value from 0 to 256 Returns: None ******************************************************************************/ /* void light_config(uint8_t Num){ // use case switches here to configure switch(Num) { case 0: {// put in standby (AKA powered down) mode //For lowest power ~2.8uA in standby mode, sensor should default to this after reset char d[2]; d[0] = TSL2561_CONTROL; //CTRL_REG0=0x00 d[1] = 0x00; //Puts device in powered down mode if(i2c_bus0.write(TSL2561_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"light_err0a",20,30); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 0 case 1: {// put in active char d[2]; d[0] = TSL2561_CONTROL; //CTRL_REG=0x00 d[1] = 0x03; //Puts device in powered up mode if(i2c_bus0.write(TSL2561_I2C_ADDRESS_, d,2) ==1){ oled.Label((uint8_t *)"light_err0a",20,30); // Display "error" at x,y wait(3.0); // display for 3 seconds }//end if break; }// end of case 1 default: { oled.Label((uint8_t *)"LGHT_Mode?",20,45); // Display "mode" at x,y // unknown config break; } }// end switch }// end light_config */ /***************************************************************************** Name: update_display_date Purpose: Updating display data without updating any data labels. This keeps measurements and time values current while reducing screen flicker. ******************************************************************************/ void update_display_date(void) { oled_text_properties_t textProperties = {0}; // Need these to change font color oled.GetTextProperties(&textProperties); // Need these to change font color __disable_irq(); // Disable all Interrupts switch(Screen_Num) { case 0: {// Main Screen HexiwearBattery battery; battery.sensorOn(); if (battery.isBatteryCharging()) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); 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%%", 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 textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); // added real time and date information char buffer[32]; time_t seconds = time(NULL); strftime(buffer,32, "%a,%d %m %Y.%H:%M:%S\r", localtime(&seconds)); // sprintf(text_1,"%c%c/%c%c/%c%c%c%c ",buffer[7],buffer[8],buffer[4],buffer[5],buffer[10],buffer[11],buffer[12],buffer[13]); // oled.Label((uint8_t *)text_1,20,20);// Date at x,y sprintf(text_1,"%c%c:%c%c:%c%c ",buffer[15],buffer[16],buffer[18],buffer[19],buffer[21],buffer[22]); 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 *)text_1,25,40);// Time 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); 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 oled.Label((uint8_t *)text,3,80);// HI at x,y textProperties.fontColor = COLOR_GRAY; if(Fall_Alert == 1){ textProperties.fontColor = COLOR_GREEN; // is Fall protection on? } if(Fall_Alert == 1 && Led_clk1 == 1){ textProperties.fontColor = COLOR_YELLOW; // is Fall detected? } if(Fall_Alert == 1 && Led_clk1 == 1 && Led_clk2 == 1){ textProperties.fontColor = COLOR_RED; // is impact detected? } oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)"AFP",3,0); //Display "AFP" at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; }// end case 0 case 7: {// Heart Rate Zone textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); sprintf(display_buff, "%u", Heart_Rate); textProperties.fontColor = COLOR_RED; //Change font to red oled.SetTextProperties(&textProperties);//Implement color change oled.Label((uint8_t *)display_buff,43,25); // Display at x,y textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); //implements the color change sprintf(display_buff, "%u", Age); //Convert int to char array for displaying user age oled.Label((uint8_t *)display_buff,43,45); // Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; }// end case 7 case 21: {// Fall Alert Diagnostic Screen if(Fall_Alert_Mode == 0){ fall_config(11); // turn accel sensor to active mode to take a reading, may take 80mS to 300mS } textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); gyro.acquire_gyro_data_dps(Gyro_Data); Gyro_Mag = (abs(Gyro_Data[0])+abs(Gyro_Data[1])+abs(Gyro_Data[2])); sprintf(text_1," %4.0f D/S ",Gyro_Mag); oled.Label((uint8_t *)text_1,37,60);// text_1 at x,y accel.acquire_accel_data_g(Accel_Data); if(Fall_Alert_Mode == 0){ fall_config(12); // turn accel sensor back to standby } Accel_Mag = 2*sqrt(((Accel_Data[0]*Accel_Data[0])+(Accel_Data[1]*Accel_Data[1])+(Accel_Data[2]*Accel_Data[2]))); sprintf(text_1," %2.2f g ",Accel_Mag); oled.Label((uint8_t *)text_1,39,40);// text_1 at x,y if(Accel_Mag > Fall_Thresh + 0.05f && Led_clk2 == 1){// are we stuck in limbo? fall_det_end(); } break; }//end case 21 case 31: { sprintf(display_buff, "%u", Heart_Rate); // Convert int to char to display textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); oled.Label((uint8_t *)display_buff, 40, 25); if(Current_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } sprintf(display_buff, "%u", Current_Zone); // Convert int to char to display oled.Label((uint8_t *)display_buff, 71, 45); if(Prev_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Prev_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } sprintf(display_buff, "%u", Prev_Zone); // Convert int to char to display oled.Label((uint8_t *)display_buff, 71, 60); textProperties.fontColor = COLOR_WHITE; //Change font to white oled.SetTextProperties(&textProperties);//Implement color change break; } case 33: { sprintf(display_buff, "%u", Heart_Rate); // Convert int to char to display if(Current_Zone == 1) { textProperties.fontColor = COLOR_YELLOW; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 2) { textProperties.fontColor = COLOR_BLUE; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 3) { textProperties.fontColor = COLOR_GREEN; oled.SetTextProperties(&textProperties); } else if(Current_Zone == 4) { textProperties.fontColor = COLOR_RED; oled.SetTextProperties(&textProperties); } oled.Label((uint8_t *)display_buff, 35, 40);// Display at x,y textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); break; } case 72: {// BlueTooth on/off textProperties.fontColor = COLOR_WHITE; oled.SetTextProperties(&textProperties); if (BLE_On == 1) { /* re-Display Bond Pass Key in a 90px by 18px textbox at x=0,y=40 */ sprintf(text,"%d", kw40z_device.GetPassKey()); oled.TextBox((uint8_t *)text,10,45,80,18); } else { // do nothing, don't update when not active } break; }// end case 72 default: { // do nothing for other screens break; } }// end switch __enable_irq(); // Enable all Interrupts }// end of update_display_date /***************************************************************************** Name: txTask() Purpose: HexiHeart Connecction Inputs: None Returns: None ******************************************************************************/ void txTask(void)// we're not really using this because we arn't always transmitting { while (true) { // update sensor data /*Notify Hexiwear App that it is running Sensor Tag mode*/ kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG); /* send sensor data //Send Battery Level kw40z_device.SendBatteryLevel(battery); //Send Ambient Light Level kw40z_device.SendAmbientLight(light); //Send Humidity kw40z_device.SendHumidity(humidity); //Send Temperature kw40z_device.SendTemperature(temperature); //Send Pressure kw40z_device.SendPressure(pressure); //Send Mag,Accel,Gyro Data. kw40z_device.SendGyro(x,y,z); kw40z_device.SendAccel(z,x,y); kw40z_device.SendMag(y,z,x); */ Thread::wait(1000); }// end while }// 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 = (uint8_t)((Ave_Num-1)*batt_per_level/Ave_Num + 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 > MAX_AVE_NUM){ Ave_Num = MAX_AVE_NUM;//set limit } }// end UpDate_Ave void HR_Simulation(void) { if(randomized == 0) { srand(hi_calc); randomized = 1; } if(simulation_stage == 0) { Heart_Rate = HR_Zone1[0] + rand() %( HR_Zone1[1] - HR_Zone1[0] + 1); } else if(simulation_stage == 1) { Heart_Rate = HR_Zone2[0] + rand() %( HR_Zone2[1] - HR_Zone2[0] + 1); } else if(simulation_stage == 2) { Heart_Rate = HR_Zone3[0] + rand() %( HR_Zone3[1] - HR_Zone3[0] + 1); } else if(simulation_stage == 3) { Heart_Rate = HR_Zone4[0] + rand() %( HR_Zone4[1] - HR_Zone4[0] + 1); } else if(simulation_stage == 4) { Heart_Rate = HR_Zone3[0] + rand() %( HR_Zone3[1] - HR_Zone3[0] + 1); } else { simulation_stage = -1; } simulation_stage++; Determine_Current_Zone(); //update_display(); // I don't think we should update display, let update_data() do that } void readRegs(int addr, uint8_t * data, int len) { char temp[1] = {addr}; i2c_bus0.write(HR_W_ADDR, temp, 1, true); i2c_bus0.read(HR_R_ADDR, (char*)data, len); } void writeRegs(uint8_t * data, int len) { i2c_bus0.write(HR_W_ADDR, (char*)data, len); } void setIntEnable(uint16_t mask) { uint8_t res[3]; res[0] = REG_INT_ENB_MSB; res[1] = (mask >> 8) & 0xFF; res[2] = (mask & 0xFF); writeRegs(res, 3); } void setFIFO_WR_PTR(uint8_t data) { uint8_t res[2]; res[0] = REG_FIFO_WR_PTR; res[1] = data; writeRegs(res, 2); } void setOVF_COUNTER(uint8_t data) { uint8_t res[2]; res[0] = REG_OVF_COUNTER; res[1] = data; writeRegs(res, 2); } uint8_t getFIFO_RD_PTR(void) { uint8_t data; readRegs(REG_FIFO_RD_PTR, &data, 1); return (data); } void setSLOT(uint16_t data) { uint8_t res[3]; res[0] = REG_SLOT_MSB; res[1] = (data >> 8) & 0xFF; res[2] = data & 0xFF; writeRegs(res, 3); } void setFIFO_RD_PTR(uint8_t data) { uint8_t res[2]; res[0] = REG_FIFO_RD_PTR; res[1] = data; writeRegs(res, 2); } void setFIFO_DATA(uint8_t data) { uint8_t res[2]; res[0] = REG_FIFO_DATA; res[1] = data; writeRegs(res, 2); } void setFIFO_CONFIG(uint8_t data) { uint8_t res[2]; res[0] = REG_FIFO_CONFIG; res[1] = data; writeRegs(res, 2); } void setMODE_CONFIG(uint8_t data) { uint8_t res[2]; res[0] = REG_MODE_CONFIG; res[1] = data; writeRegs (res, 2); } void setSPO2_CONFIG(uint8_t data) { uint8_t res[2] ; res[0] = REG_SPO2_CONFIG ; res[1] = data ; writeRegs(res, 2) ; } void setLED1_PA(uint8_t data) { uint8_t res[2] ; res[0] = REG_LED1_PA ; res[1] = data ; writeRegs(res, 2) ; } void setLED2_PA(uint8_t data) { uint8_t res[2] ; res[0] = REG_LED2_PA ; res[1] = data ; writeRegs(res, 2) ; } void setLED3_PA(uint8_t data) { uint8_t res[2] ; res[0] = REG_LED3_PA ; res[1] = data ; writeRegs(res, 2) ; } void setPILOT_PA(uint8_t data) { uint8_t res[2] ; res[0] = REG_PILOT_PA ; res[1] = data ; writeRegs(res, 2) ; } void setPROX_INT_THR(uint8_t data) { uint8_t res[2] ; res[0] = REG_PROX_INT_THR ; res[1] = data ; writeRegs(res, 2) ; } void clearFIFO(void) { uint8_t res[5] ; res[0] = REG_FIFO_WR_PTR ; res[1] = 0x00 ; /* FIFO_WR_PTR */ res[2] = 0x00 ; /* OVF_COUNTER */ res[3] = 0x00 ; /* FIFO_RD_PTR */ res[4] = 0x00 ; /* FIFO_DATA (do we need to clear this?) */ writeRegs(res, 5) ; } /* * readFIFO(void) * FIFO data is always a 3-bytes data * byte1[1:0] : FIFO_DATA[17]-FIFO_DATA[16] * byte2[7:0] : FIFO_DATA[15]-FIFO_DATA[8] * byte3[7:0] : FIFO_DATA[7]-FIFO_DATA[0] * The data is left aligned, so FIFO_DATA[17] * is always MSB, although the data length * can be 18-bit ~ 15-bit */ uint32_t readFIFO(void) { uint32_t data = 0 ; uint8_t res[3] ; readRegs(REG_FIFO_DATA, res, 3) ; data = ((res[0] & 0x03)<<16) | (res[1] << 8) | res[2] ; return( data ) ; } void maxReset(void) { uint8_t res[2] ; res[0] = REG_MODE_CONFIG ; res[1] = 0x40 ; /* reset */ writeRegs(res, 2) ; } void maxInit(void) { maxim = 1; maxReset(); wait(0.05); setLED1_PA(0xFF); setLED2_PA(0x33); setLED3_PA(0xFF); setPILOT_PA(0x19); wait(0.05); setSLOT(0x0300); setFIFO_CONFIG(0x06); setSPO2_CONFIG(0x42); wait(0.05); setPROX_INT_THR(0x14); clearFIFO(); wait(0.05); } void maxEnable(void) { setIntEnable(0x8000); setMODE_CONFIG(0x07); Enable_Heart_Rate(); } void maxDeinit(void) { maxim = 0; hr_ticker.detach(); hr_measure_ticker.detach(); Disable_Heart_Rate(); hr_led.detach(); RED_Led = LED_OFF; GRN_Led = LED_OFF; BLU_Led = LED_OFF; } void processHeartRate(void) { uint32_t peak; for(int i = 0; i < 100; i++) { hr_data[i] = readFIFO(); //if(i % 3 == 1) // there seems to be a missing "{" here // wait(0.01); // every third read wait 0.05s, this adds about 1.65s } peak = isPeak(hr_data); uint8_t hr = (uint8_t)((60 * peak * 50)/ 100); if(hr >= HR_Zone1[0] && hr <= HR_Zone4[1]) { Heart_Rate = hr; // update_display();//I don't think we need to update display here, let update_data do that } Determine_Current_Zone(); } uint32_t isPeak(uint32_t hr_array[]) { uint32_t peaks[100]; uint32_t numPeaks = 0; uint32_t index = 0; uint32_t currentPeak = 0; for(int i = 1; i < 100; i++) { if((hr_array[i] > hr_array[i + 1]) && (hr_array[i] > hr_array[i - 1])) { peaks[index] = hr_array[i]; numPeaks++; index++; } } if(numPeaks > 0) { currentPeak = peaks[0]; for(int i = 0; i < numPeaks; i++) { if(currentPeak < peaks[i]) { currentPeak = peaks[i]; } } } return currentPeak; }