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-05-10
- Revision:
- 22:3de592f8e696
- Parent:
- 21:76237b62466b
File content as of revision 22:3de592f8e696:
/**********************************************************************
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/
******Basic 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.17 - Added heart rate measurement to the main screen when any of the heart
rate features are enabled. Fixed some WDT resets with certain heart rate
vibrations.
v2.16 - Cast rolling average calculations as float to reduce rounding error.
removed two screens from diagnostic because we don't use them.
Changed FAP to AFP in two locations.
v2.15 - added display screens 41 and 42 back in.
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.17 // 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.0f // 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) //I2C address, pins SA0,SA1=0
#define FXAS21002_I2C_ADDRESS_ 0x40 //I2C address
//#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 rand_stage;
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; //
float Ave_Num = 0.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 - not used
StartHaptic();
Screen_Num = 22; //Change to screen 22
update_display();
break;
}
case 24: {// Heart Rate Debug - not used
StartHaptic();
Screen_Num = 23; //Change to screen 23
update_display();
break;
}
case 25: {// Heat Index Diagnostic
StartHaptic();
Screen_Num = 21; //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);
Heart_Rate_Mode = 1;
break;
}
case 33:{//Start heart rate simulation
StartHaptic();
if(maxim == 0)
{
simulation_stage = 0;
Heart_Rate_Mode = 1;
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 = 25; //Change to screen 23
update_display();
break;
}
case 23: {// Heart Rate Diagnostic - not used
StartHaptic();
Screen_Num = 24; //Change to screen 24
update_display();
break;
}
case 24: {// Heart Rate Debug - not used
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();
Heart_Rate_Mode = 0;
RED_Led = LED_OFF;
GRN_Led = LED_OFF;
BLU_Led = LED_OFF;
break;
}
case 33: {//End HR Simulation early
StartHaptic();
if(maxim == 0)
{
Heart_Rate_Mode = 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
set_time((2018-1970)*365.25f*24*3600 + (31+28+31+30+10-1)*24*3600 + (13)*3600 + (15)*60+ (0) + 29); // Set RTC time to 5/10/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_alert(&TimeSet);
//kw40z_device.attach_alertIn(&TimeSet);
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 *)"AFP",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) {
sprintf(text,"%i",Heart_Rate);
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 *)text,35,60);
textProperties.fontColor = COLOR_WHITE;
oled.SetTextProperties(&textProperties);
}
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 *)"AFP",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);
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,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 41: { //Fall mode
oled.FillScreen(COLOR_BLACK);
oled.Label((uint8_t *)"Adj Fall Mode", 10, 5);
sprintf(display_buff, "%u", Fall_Alert_Mode); //Convert int to char array for displaying mode
oled.Label((uint8_t *)"Mode:", 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 42: { //Fall Thresh
oled.FillScreen(COLOR_BLACK);
oled.Label((uint8_t *)"Adj F-Th", 10, 5);
sprintf(display_buff, "%2.2f g", Fall_Thresh); //Convert int to char array for displaying mode
oled.Label((uint8_t *)"F_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 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
CLRWDT();
haptic = 1;
wait(0.5);
haptic = 0;
wait(0.5);
CLRWDT();
haptic = 1;
wait(0.5);
haptic = 0;
} else if(Target_Zone == HIGHEST_ZONE || Prev_Zone < Target_Zone) { //must have entered from below
CLRWDT();
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
CLRWDT();
haptic = 1;
wait(1);
haptic = 0;
} else if(Target_Zone == LOWEST_ZONE || Current_Zone > Target_Zone) { //must have exited above
haptic = 1;
CLRWDT();
wait(1);
haptic = 0;
wait(1);
CLRWDT();
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) {
CLRWDT();
haptic = 1;
wait(0.2);
haptic = 0;
wait(0.2);
CLRWDT();
haptic = 1;
wait(0.2);
haptic = 0;
} else if(Current_Zone != Target_Zone && Prev_Zone == Target_Zone) {
haptic = 1;
CLRWDT();
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(); // sampling is now done in rolling UpDate_Ave() function
//sample_humid = temphumid.sample_humid(); // sampling is now done in rolling UpDate_Ave() function
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);
if(Heart_Rate_Mode == 1) {
sprintf(text,"%i ",Heart_Rate);
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 *)text,35,60);
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);
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,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.0f){
// 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); // do calculation as a float but return an uint8
sample_ftemp = (int)(Ave_Num-1)*sample_ftemp/Ave_Num + temphumid.sample_ftemp()/Ave_Num;
sample_humid = (int)(Ave_Num-1)*sample_humid/Ave_Num + temphumid.sample_humid()/Ave_Num;
}//end else
Ave_Num = Ave_Num + 1;
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 if(simulation_stage == 5)
{
Heart_Rate = HR_Zone2[0] + rand() %( HR_Zone2[1] - HR_Zone2[0] + 1);
}
else if(simulation_stage == 6)
{
Heart_Rate = HR_Zone1[0] + rand() %( HR_Zone1[1] - HR_Zone1[0] + 1);
}
else
{
rand_stage = rand() % 4 + 1;
if(rand_stage == 1)
{
Heart_Rate = HR_Zone1[0] + rand() %( HR_Zone1[1] - HR_Zone1[0] + 1);
}
else if(rand_stage == 2)
{
Heart_Rate = HR_Zone2[0] + rand() %( HR_Zone2[1] - HR_Zone2[0] + 1);
}
else if(rand_stage == 3)
{
Heart_Rate = HR_Zone3[0] + rand() %( HR_Zone3[1] - HR_Zone3[0] + 1);
}
else if(rand_stage == 4)
{
Heart_Rate = HR_Zone4[0] + rand() %( HR_Zone4[1] - HR_Zone4[0] + 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();
}
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;
}
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;
}
