![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Code for the Hexiwear sensor system. Requires an Air Quality Click, Carbon Monoxide Click, and Buzzer Click for full functionality. Currently only reads values and displays to the OLED while testing and alerting the user of present threats. Future goals are to incorporate button presses with separate screens to display the data as well as using the KW40 drivers to transmit the data. Still in early stages of development, many unnecessary files will be removed and cleaned up once final product is completed within the next month. Driver.cpp is the main driver for the program and was written for purposes of this project. All other headers and functions were found on mbed.org from other developers repositories or provided by NXP Semiconductors for purposes of this project.
Dependencies: Hexi_KW40Z images
driver.cpp@3:24b332b8e41d, 2017-04-28 (annotated)
- Committer:
- Gfolker
- Date:
- Fri Apr 28 07:26:16 2017 +0000
- Revision:
- 3:24b332b8e41d
- Parent:
- 2:aa8c291b3f9a
Final version of the project - BLE integrated, code cleaned up, ARC calculation implemented, all user interface screens/button presses implemented, alert states tested and verified
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Gfolker | 0:f70b1d60f794 | 1 | #include "mbed.h" |
Gfolker | 0:f70b1d60f794 | 2 | #include "pwm_tone.h" /* Tone library for Buzzer Click */ |
Gfolker | 0:f70b1d60f794 | 3 | #include "Hexi_OLED_SSD1351.h" /* Header file for OLED Display */ |
Gfolker | 0:f70b1d60f794 | 4 | #include "string.h" |
Gfolker | 0:f70b1d60f794 | 5 | #include "Hexi_KW40Z.h" /* Driver for button presses and BLE */ |
Gfolker | 0:f70b1d60f794 | 6 | #include <math.h> /* Used for ADC conversion algorithm */ |
Gfolker | 1:8ab4a1e27785 | 7 | #include "images.h" /* BMPs of the images drawn to the OLED */ |
Gfolker | 0:f70b1d60f794 | 8 | |
Gfolker | 0:f70b1d60f794 | 9 | /*****Function Prototypes*****/ |
Gfolker | 0:f70b1d60f794 | 10 | void readSensors(); |
Gfolker | 0:f70b1d60f794 | 11 | void ledColor(); |
Gfolker | 0:f70b1d60f794 | 12 | void led_out(); |
Gfolker | 0:f70b1d60f794 | 13 | void buzzer(); |
Gfolker | 0:f70b1d60f794 | 14 | void CalculatePPM(); |
Gfolker | 1:8ab4a1e27785 | 15 | void dataQueue(); |
Gfolker | 1:8ab4a1e27785 | 16 | void initModules(); |
Gfolker | 1:8ab4a1e27785 | 17 | void StartHaptic(void); |
Gfolker | 1:8ab4a1e27785 | 18 | void StopHaptic(void const *n); |
Gfolker | 2:aa8c291b3f9a | 19 | void txTask(void); |
Gfolker | 0:f70b1d60f794 | 20 | |
Gfolker | 0:f70b1d60f794 | 21 | PwmOut Buzzer(PTA10); /* Buzzer is attached to docking station port 1 */ |
Gfolker | 0:f70b1d60f794 | 22 | AnalogIn AQSensor(PTB3); /* Air Quality sensor is attached to docking station port 2 */ |
Gfolker | 0:f70b1d60f794 | 23 | AnalogIn COSensor(PTB6); /* Carbon Monoxide sensor is attached to docking station port 3 */ |
Gfolker | 0:f70b1d60f794 | 24 | |
Gfolker | 1:8ab4a1e27785 | 25 | /* Instantiate the SSD1351 OLED Driver */ |
Gfolker | 1:8ab4a1e27785 | 26 | SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); |
Gfolker | 1:8ab4a1e27785 | 27 | |
Gfolker | 0:f70b1d60f794 | 28 | BusOut led(PTC8, PTD0, PTC9); /* RGB Port Configurations */ |
Gfolker | 1:8ab4a1e27785 | 29 | DigitalOut haptic(PTB9); /* Port Configuration for vibrations */ |
Gfolker | 1:8ab4a1e27785 | 30 | /* Define timer for haptic feedback */ |
Gfolker | 1:8ab4a1e27785 | 31 | RtosTimer hapticTimer(StopHaptic, osTimerOnce); |
Gfolker | 1:8ab4a1e27785 | 32 | |
Gfolker | 1:8ab4a1e27785 | 33 | int screen = 1; //detects which screen the user is currently on |
Gfolker | 1:8ab4a1e27785 | 34 | bool is_drawn1 = 0; //detects if the screen is already drawn to the screen |
Gfolker | 1:8ab4a1e27785 | 35 | bool is_drawn2 = 0; |
Gfolker | 1:8ab4a1e27785 | 36 | bool is_drawn3 = 0; |
Gfolker | 2:aa8c291b3f9a | 37 | bool is_drawn4 = 0; |
Gfolker | 3:24b332b8e41d | 38 | bool is_ble = 0; //detects if the device is currently running BLE mode |
Gfolker | 1:8ab4a1e27785 | 39 | |
Gfolker | 1:8ab4a1e27785 | 40 | /* Screens */ |
Gfolker | 2:aa8c291b3f9a | 41 | const uint8_t *image1; //homescreen |
Gfolker | 1:8ab4a1e27785 | 42 | |
Gfolker | 2:aa8c291b3f9a | 43 | const uint8_t *image2; //air quality screen |
Gfolker | 1:8ab4a1e27785 | 44 | |
Gfolker | 2:aa8c291b3f9a | 45 | const uint8_t *image3; //co screen |
Gfolker | 0:f70b1d60f794 | 46 | |
Gfolker | 0:f70b1d60f794 | 47 | const int green = 5, |
Gfolker | 0:f70b1d60f794 | 48 | red = 6, /* LED Colors */ |
Gfolker | 0:f70b1d60f794 | 49 | black = 7, |
Gfolker | 0:f70b1d60f794 | 50 | yellow = 4; |
Gfolker | 0:f70b1d60f794 | 51 | |
Gfolker | 0:f70b1d60f794 | 52 | bool is_sounding = false; /* Set to high if the buzzer is going off */ |
Gfolker | 0:f70b1d60f794 | 53 | |
Gfolker | 0:f70b1d60f794 | 54 | int led_color; /* Variable to hold the current LED color */ |
Gfolker | 0:f70b1d60f794 | 55 | |
Gfolker | 0:f70b1d60f794 | 56 | Ticker sensor_read, /* Used for the read sensor subroutine call */ |
Gfolker | 0:f70b1d60f794 | 57 | buzzer_sound, /* Used for the sound buzzer subroutine call */ |
Gfolker | 0:f70b1d60f794 | 58 | led_flash, /* Used to determine the flash rate */ |
Gfolker | 0:f70b1d60f794 | 59 | ledcolor, /* Used to determine the LED color */ |
Gfolker | 1:8ab4a1e27785 | 60 | A2D_Convert, /* Used to convert the analog signal to digital */ |
Gfolker | 1:8ab4a1e27785 | 61 | push; /* Used to push values into the data array */ |
Gfolker | 0:f70b1d60f794 | 62 | |
Gfolker | 0:f70b1d60f794 | 63 | float B_4 = 1000000/Ti4, /* Tones that will play on the buzzer click */ |
Gfolker | 0:f70b1d60f794 | 64 | B_5 = 1000000/Ti5; |
Gfolker | 0:f70b1d60f794 | 65 | |
Gfolker | 0:f70b1d60f794 | 66 | char text[20]; /* Static Text Buffer for OLED Display */ |
Gfolker | 0:f70b1d60f794 | 67 | char AQ_level[20]; /* Dynamic Text Buffer for AQ total */ |
Gfolker | 0:f70b1d60f794 | 68 | char CO_level[20]; /* Dynamic Text Buffer for CO total */ |
Gfolker | 0:f70b1d60f794 | 69 | char average[20]; /* Dynamic Text Buffer for the Average total */ |
Gfolker | 0:f70b1d60f794 | 70 | char total_total[20]; /* Dynamic Text Buffer for the Total total */ |
Gfolker | 3:24b332b8e41d | 71 | char ble_status[20]; /* Informs the user if BLE is activated or disabled */ |
Gfolker | 0:f70b1d60f794 | 72 | |
Gfolker | 1:8ab4a1e27785 | 73 | /* Either unit16_t or double */ |
Gfolker | 1:8ab4a1e27785 | 74 | double total, /* Variable to store the total total */ |
Gfolker | 1:8ab4a1e27785 | 75 | aq_ppm, /* Variable used to store the AQ PPM */ |
Gfolker | 3:24b332b8e41d | 76 | co_ppm, /* Variable used to store the CO PPM */ |
Gfolker | 3:24b332b8e41d | 77 | prev_value; /* Used for ARC Calculation */ |
Gfolker | 3:24b332b8e41d | 78 | double ARC; |
Gfolker | 0:f70b1d60f794 | 79 | |
Gfolker | 0:f70b1d60f794 | 80 | uint16_t aq_total, /* Variable to store the AQ total */ |
Gfolker | 1:8ab4a1e27785 | 81 | co_total; /* Variable to store the CO total */ |
Gfolker | 1:8ab4a1e27785 | 82 | |
Gfolker | 2:aa8c291b3f9a | 83 | /*Create a Thread to handle sending BLE Sensor Data */ |
Gfolker | 2:aa8c291b3f9a | 84 | Thread txThread; |
Gfolker | 2:aa8c291b3f9a | 85 | |
Gfolker | 2:aa8c291b3f9a | 86 | /* Variables to handle the circular array algorithm */ |
Gfolker | 1:8ab4a1e27785 | 87 | const int SIZE = 500; |
Gfolker | 1:8ab4a1e27785 | 88 | double dataSet [SIZE]; |
Gfolker | 1:8ab4a1e27785 | 89 | int pushIndex = 0; |
Gfolker | 1:8ab4a1e27785 | 90 | bool calc = false; |
Gfolker | 1:8ab4a1e27785 | 91 | double avg = 0, sum = 0; |
Gfolker | 1:8ab4a1e27785 | 92 | |
Gfolker | 1:8ab4a1e27785 | 93 | /* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ |
Gfolker | 1:8ab4a1e27785 | 94 | KW40Z kw40z_device(PTE24, PTE25); |
Gfolker | 1:8ab4a1e27785 | 95 | |
Gfolker | 1:8ab4a1e27785 | 96 | /* Below are the functions to handle button presses and screens */ |
Gfolker | 1:8ab4a1e27785 | 97 | void ButtonRight(void)//CO screen button |
Gfolker | 1:8ab4a1e27785 | 98 | { |
Gfolker | 3:24b332b8e41d | 99 | StartHaptic(); |
Gfolker | 1:8ab4a1e27785 | 100 | screen = 3; |
Gfolker | 1:8ab4a1e27785 | 101 | } |
Gfolker | 1:8ab4a1e27785 | 102 | |
Gfolker | 1:8ab4a1e27785 | 103 | void ButtonLeft(void)//AQ screen button |
Gfolker | 1:8ab4a1e27785 | 104 | { |
Gfolker | 3:24b332b8e41d | 105 | StartHaptic(); |
Gfolker | 1:8ab4a1e27785 | 106 | screen = 2; |
Gfolker | 1:8ab4a1e27785 | 107 | } |
Gfolker | 1:8ab4a1e27785 | 108 | |
Gfolker | 1:8ab4a1e27785 | 109 | void ButtonDown(void)//home screen button |
Gfolker | 1:8ab4a1e27785 | 110 | { |
Gfolker | 3:24b332b8e41d | 111 | StartHaptic(); |
Gfolker | 1:8ab4a1e27785 | 112 | screen = 1; |
Gfolker | 2:aa8c291b3f9a | 113 | } |
Gfolker | 2:aa8c291b3f9a | 114 | |
Gfolker | 2:aa8c291b3f9a | 115 | void ButtonUp(void) {//toggles bluetooth mode |
Gfolker | 3:24b332b8e41d | 116 | StartHaptic(); |
Gfolker | 3:24b332b8e41d | 117 | screen = 4; |
Gfolker | 2:aa8c291b3f9a | 118 | kw40z_device.ToggleAdvertisementMode(); |
Gfolker | 3:24b332b8e41d | 119 | is_ble = !is_ble; |
Gfolker | 2:aa8c291b3f9a | 120 | } |
Gfolker | 2:aa8c291b3f9a | 121 | |
Gfolker | 2:aa8c291b3f9a | 122 | void PassKey(void) |
Gfolker | 2:aa8c291b3f9a | 123 | { |
Gfolker | 3:24b332b8e41d | 124 | StartHaptic(); |
Gfolker | 3:24b332b8e41d | 125 | strcpy((char *) text,"PAIR CODE"); |
Gfolker | 3:24b332b8e41d | 126 | oled.TextBox((uint8_t *)text,0,25,95,18); |
Gfolker | 2:aa8c291b3f9a | 127 | |
Gfolker | 2:aa8c291b3f9a | 128 | /* Display Bond Pass Key in a 95px by 18px textbox at x=0,y=40 */ |
Gfolker | 3:24b332b8e41d | 129 | sprintf(text,"%d", kw40z_device.GetPassKey()); |
Gfolker | 3:24b332b8e41d | 130 | oled.TextBox((uint8_t *)text,0,40,95,18); |
Gfolker | 1:8ab4a1e27785 | 131 | } |
Gfolker | 0:f70b1d60f794 | 132 | |
Gfolker | 0:f70b1d60f794 | 133 | int main(){ |
Gfolker | 0:f70b1d60f794 | 134 | |
Gfolker | 1:8ab4a1e27785 | 135 | initModules(); |
Gfolker | 0:f70b1d60f794 | 136 | |
Gfolker | 0:f70b1d60f794 | 137 | /* Subroutine Calls */ |
Gfolker | 2:aa8c291b3f9a | 138 | sensor_read.attach(&readSensors, 1); /* Read the sensor on a time interval */ |
Gfolker | 2:aa8c291b3f9a | 139 | A2D_Convert.attach(&CalculatePPM, 1); /* Convert the values read from the sensors to floating point ppm values */ |
Gfolker | 2:aa8c291b3f9a | 140 | push.attach(&dataQueue, 1); /* Push the value into the set and compute the average */ |
Gfolker | 0:f70b1d60f794 | 141 | ledcolor.attach(&ledColor, 0.5); /* Determine the LED color */ |
Gfolker | 0:f70b1d60f794 | 142 | led_flash.attach(&led_out, 0.25); /* Flash LED based on sensor data */ |
Gfolker | 0:f70b1d60f794 | 143 | buzzer_sound.attach(&buzzer, 0.25); /* Sensor values are sent to buzzer function */ |
Gfolker | 0:f70b1d60f794 | 144 | |
Gfolker | 1:8ab4a1e27785 | 145 | /* Register callbacks to button presses */ |
Gfolker | 1:8ab4a1e27785 | 146 | kw40z_device.attach_buttonDown(&ButtonDown); |
Gfolker | 1:8ab4a1e27785 | 147 | kw40z_device.attach_buttonLeft(&ButtonLeft); |
Gfolker | 1:8ab4a1e27785 | 148 | kw40z_device.attach_buttonRight(&ButtonRight); |
Gfolker | 2:aa8c291b3f9a | 149 | kw40z_device.attach_buttonUp(&ButtonUp); |
Gfolker | 2:aa8c291b3f9a | 150 | kw40z_device.attach_passkey(&PassKey); |
Gfolker | 1:8ab4a1e27785 | 151 | |
Gfolker | 2:aa8c291b3f9a | 152 | txThread.start(txTask); /*Start transmitting Sensor Tag Data */ |
Gfolker | 2:aa8c291b3f9a | 153 | |
Gfolker | 2:aa8c291b3f9a | 154 | while (1) { /* Loop to process and display data to the OLED */ |
Gfolker | 1:8ab4a1e27785 | 155 | |
Gfolker | 1:8ab4a1e27785 | 156 | /* Get OLED Class Default Text Properties */ |
Gfolker | 1:8ab4a1e27785 | 157 | oled_text_properties_t textProperties = {0}; |
Gfolker | 1:8ab4a1e27785 | 158 | oled.GetTextProperties(&textProperties); |
Gfolker | 0:f70b1d60f794 | 159 | |
Gfolker | 3:24b332b8e41d | 160 | /* Set text properties to green and right aligned for the dynamic text */ |
Gfolker | 3:24b332b8e41d | 161 | textProperties.fontColor = COLOR_GREEN; |
Gfolker | 1:8ab4a1e27785 | 162 | textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT; |
Gfolker | 1:8ab4a1e27785 | 163 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 164 | |
Gfolker | 1:8ab4a1e27785 | 165 | if (screen == 2){ //Air Quality Screen |
Gfolker | 1:8ab4a1e27785 | 166 | if(!is_drawn2){ |
Gfolker | 2:aa8c291b3f9a | 167 | is_drawn1 = 0; |
Gfolker | 2:aa8c291b3f9a | 168 | is_drawn3 = 0; |
Gfolker | 2:aa8c291b3f9a | 169 | is_drawn4 = 0; |
Gfolker | 1:8ab4a1e27785 | 170 | oled.DrawImage(image2,0,0); |
Gfolker | 1:8ab4a1e27785 | 171 | is_drawn2 = 1; |
Gfolker | 1:8ab4a1e27785 | 172 | } |
Gfolker | 3:24b332b8e41d | 173 | if (aq_ppm >= 50 and aq_ppm < 100){ |
Gfolker | 3:24b332b8e41d | 174 | textProperties.fontColor = COLOR_YELLOW; //color the font yellow |
Gfolker | 3:24b332b8e41d | 175 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 176 | } |
Gfolker | 3:24b332b8e41d | 177 | else if (aq_ppm >= 100){ |
Gfolker | 3:24b332b8e41d | 178 | textProperties.fontColor = COLOR_RED; //color the font red |
Gfolker | 3:24b332b8e41d | 179 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 180 | } |
Gfolker | 1:8ab4a1e27785 | 181 | sprintf(AQ_level,"%.2f",aq_ppm); /* Print the AQ PPM to the screen */ |
Gfolker | 1:8ab4a1e27785 | 182 | oled.TextBox((uint8_t *)AQ_level,35,76,35,15); |
Gfolker | 1:8ab4a1e27785 | 183 | } |
Gfolker | 1:8ab4a1e27785 | 184 | else if (screen == 3){ //Carbon Monoxide Screen |
Gfolker | 1:8ab4a1e27785 | 185 | if (!is_drawn3){ |
Gfolker | 2:aa8c291b3f9a | 186 | is_drawn2 = 0; |
Gfolker | 2:aa8c291b3f9a | 187 | is_drawn1 = 0; |
Gfolker | 2:aa8c291b3f9a | 188 | is_drawn4 = 0; |
Gfolker | 1:8ab4a1e27785 | 189 | oled.DrawImage(image3,0,0); |
Gfolker | 1:8ab4a1e27785 | 190 | is_drawn3 = 1; |
Gfolker | 1:8ab4a1e27785 | 191 | } |
Gfolker | 3:24b332b8e41d | 192 | if (co_ppm >= 50 and co_ppm < 100){ |
Gfolker | 3:24b332b8e41d | 193 | textProperties.fontColor = COLOR_YELLOW; //color the font yellow |
Gfolker | 3:24b332b8e41d | 194 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 195 | } |
Gfolker | 3:24b332b8e41d | 196 | |
Gfolker | 3:24b332b8e41d | 197 | else if (co_ppm >= 100) { |
Gfolker | 3:24b332b8e41d | 198 | textProperties.fontColor = COLOR_RED; //color the font red |
Gfolker | 3:24b332b8e41d | 199 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 200 | } |
Gfolker | 1:8ab4a1e27785 | 201 | sprintf(CO_level,"%.2f",co_ppm); /* Print the CO PPM to the screen */ |
Gfolker | 1:8ab4a1e27785 | 202 | oled.TextBox((uint8_t *)CO_level,35,76,35,15); |
Gfolker | 3:24b332b8e41d | 203 | |
Gfolker | 1:8ab4a1e27785 | 204 | } |
Gfolker | 1:8ab4a1e27785 | 205 | else if (screen == 1) { //Home Screen |
Gfolker | 1:8ab4a1e27785 | 206 | if (!is_drawn1){ |
Gfolker | 2:aa8c291b3f9a | 207 | is_drawn3 = 0; |
Gfolker | 2:aa8c291b3f9a | 208 | is_drawn2 = 0; |
Gfolker | 2:aa8c291b3f9a | 209 | is_drawn4 = 0; |
Gfolker | 1:8ab4a1e27785 | 210 | oled.DrawImage(image1,0,0); |
Gfolker | 1:8ab4a1e27785 | 211 | is_drawn1 = 1; |
Gfolker | 1:8ab4a1e27785 | 212 | } |
Gfolker | 3:24b332b8e41d | 213 | if (avg >= 50 and avg <100) { |
Gfolker | 3:24b332b8e41d | 214 | textProperties.fontColor = COLOR_YELLOW; //color the font yellow |
Gfolker | 3:24b332b8e41d | 215 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 216 | } |
Gfolker | 3:24b332b8e41d | 217 | else if (avg >=100){ |
Gfolker | 3:24b332b8e41d | 218 | textProperties.fontColor = COLOR_RED; //color the font red |
Gfolker | 3:24b332b8e41d | 219 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 220 | } |
Gfolker | 3:24b332b8e41d | 221 | |
Gfolker | 3:24b332b8e41d | 222 | sprintf(average, "%.2f", avg); |
Gfolker | 3:24b332b8e41d | 223 | oled.TextBox((uint8_t *)average,53,23,35,15); |
Gfolker | 3:24b332b8e41d | 224 | |
Gfolker | 3:24b332b8e41d | 225 | if (total >=50 and total < 100){ |
Gfolker | 3:24b332b8e41d | 226 | textProperties.fontColor = COLOR_YELLOW; //color the font yellow |
Gfolker | 3:24b332b8e41d | 227 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 228 | } |
Gfolker | 3:24b332b8e41d | 229 | else if (total >= 100) { |
Gfolker | 3:24b332b8e41d | 230 | textProperties.fontColor = COLOR_RED; //color the font red |
Gfolker | 3:24b332b8e41d | 231 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 232 | } |
Gfolker | 3:24b332b8e41d | 233 | else { |
Gfolker | 3:24b332b8e41d | 234 | textProperties.fontColor = COLOR_GREEN; //color the font green |
Gfolker | 3:24b332b8e41d | 235 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 236 | } |
Gfolker | 1:8ab4a1e27785 | 237 | sprintf(total_total, "%.2f", total); /* Print the total to the screen */ |
Gfolker | 3:24b332b8e41d | 238 | oled.TextBox((uint8_t *)total_total,53,39,35,15); |
Gfolker | 1:8ab4a1e27785 | 239 | } |
Gfolker | 2:aa8c291b3f9a | 240 | |
Gfolker | 2:aa8c291b3f9a | 241 | else if (screen == 4){ //BLE Pairing Screen |
Gfolker | 2:aa8c291b3f9a | 242 | if (!is_drawn4){ |
Gfolker | 2:aa8c291b3f9a | 243 | is_drawn3 = 0; |
Gfolker | 2:aa8c291b3f9a | 244 | is_drawn2 = 0; |
Gfolker | 2:aa8c291b3f9a | 245 | is_drawn1 = 0; |
Gfolker | 2:aa8c291b3f9a | 246 | oled.FillScreen(COLOR_BLACK); |
Gfolker | 2:aa8c291b3f9a | 247 | is_drawn4 = 1; |
Gfolker | 2:aa8c291b3f9a | 248 | } |
Gfolker | 3:24b332b8e41d | 249 | textProperties.alignParam = OLED_TEXT_ALIGN_CENTER; |
Gfolker | 3:24b332b8e41d | 250 | textProperties.fontColor = COLOR_BLUE; |
Gfolker | 3:24b332b8e41d | 251 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 252 | strcpy((char *) text,"BLUETOOTH"); |
Gfolker | 2:aa8c291b3f9a | 253 | oled.TextBox((uint8_t *)text,0,25,95,18); |
Gfolker | 3:24b332b8e41d | 254 | if (is_ble) { |
Gfolker | 3:24b332b8e41d | 255 | textProperties.fontColor = COLOR_GREEN; |
Gfolker | 3:24b332b8e41d | 256 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 257 | strcpy((char *) ble_status, "On"); |
Gfolker | 3:24b332b8e41d | 258 | oled.TextBox((uint8_t *)ble_status,0,55,95,18); |
Gfolker | 3:24b332b8e41d | 259 | } |
Gfolker | 3:24b332b8e41d | 260 | else { |
Gfolker | 3:24b332b8e41d | 261 | textProperties.fontColor = COLOR_RED; |
Gfolker | 3:24b332b8e41d | 262 | oled.SetTextProperties(&textProperties); |
Gfolker | 3:24b332b8e41d | 263 | strcpy((char *) ble_status, "Off"); |
Gfolker | 3:24b332b8e41d | 264 | oled.TextBox((uint8_t *)ble_status,0,55,95,18); |
Gfolker | 3:24b332b8e41d | 265 | } |
Gfolker | 2:aa8c291b3f9a | 266 | } |
Gfolker | 2:aa8c291b3f9a | 267 | Thread::wait(500); |
Gfolker | 1:8ab4a1e27785 | 268 | } |
Gfolker | 1:8ab4a1e27785 | 269 | |
Gfolker | 1:8ab4a1e27785 | 270 | return 0; |
Gfolker | 1:8ab4a1e27785 | 271 | } |
Gfolker | 2:aa8c291b3f9a | 272 | void txTask(void){ |
Gfolker | 2:aa8c291b3f9a | 273 | while (1){ |
Gfolker | 2:aa8c291b3f9a | 274 | /*Notify Hexiwear App that it is running Sensor Tag mode*/ |
Gfolker | 2:aa8c291b3f9a | 275 | kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG); |
Gfolker | 2:aa8c291b3f9a | 276 | kw40z_device.SendTemperature(100*aq_ppm); //send ppm Air Quality Click value |
Gfolker | 2:aa8c291b3f9a | 277 | kw40z_device.SendHumidity(100*co_ppm); //send ppm CO click value |
Gfolker | 3:24b332b8e41d | 278 | kw40z_device.SendPressure(100*total); //send total |
Gfolker | 2:aa8c291b3f9a | 279 | Thread::wait(1000); |
Gfolker | 2:aa8c291b3f9a | 280 | } |
Gfolker | 2:aa8c291b3f9a | 281 | } |
Gfolker | 1:8ab4a1e27785 | 282 | void initModules() { /* Function to initialize the system */ |
Gfolker | 1:8ab4a1e27785 | 283 | |
Gfolker | 1:8ab4a1e27785 | 284 | /* Turns on the OLED Display*/ |
Gfolker | 1:8ab4a1e27785 | 285 | oled.PowerON(); |
Gfolker | 1:8ab4a1e27785 | 286 | |
Gfolker | 3:24b332b8e41d | 287 | /* Sets the pointers to their respective images */ |
Gfolker | 1:8ab4a1e27785 | 288 | image1 = homescreen_bmp; |
Gfolker | 1:8ab4a1e27785 | 289 | image2 = airquality_bmp; |
Gfolker | 1:8ab4a1e27785 | 290 | image3 = co_bmp; |
Gfolker | 0:f70b1d60f794 | 291 | } |
Gfolker | 0:f70b1d60f794 | 292 | |
Gfolker | 0:f70b1d60f794 | 293 | void readSensors(){ /* Function to read sensors */ |
Gfolker | 0:f70b1d60f794 | 294 | |
Gfolker | 0:f70b1d60f794 | 295 | /* Grab the analog signal from the sensors as 16 bit unsigned integers */ |
Gfolker | 0:f70b1d60f794 | 296 | aq_total = AQSensor.read_u16(); |
Gfolker | 0:f70b1d60f794 | 297 | co_total = COSensor.read_u16(); |
Gfolker | 0:f70b1d60f794 | 298 | /* Grab the analog signal from the sensors as floats */ |
Gfolker | 0:f70b1d60f794 | 299 | //aq_total = AQSensor.read(); |
Gfolker | 0:f70b1d60f794 | 300 | //co_total = AQSensor.read(); |
Gfolker | 0:f70b1d60f794 | 301 | |
Gfolker | 0:f70b1d60f794 | 302 | } |
Gfolker | 0:f70b1d60f794 | 303 | |
Gfolker | 0:f70b1d60f794 | 304 | void ledColor(){ /* Function to determine the LED color */ |
Gfolker | 0:f70b1d60f794 | 305 | |
Gfolker | 3:24b332b8e41d | 306 | if ((total - avg) <= 10 and total < 50 and ARC < 10 ) { |
Gfolker | 0:f70b1d60f794 | 307 | led = green; |
Gfolker | 0:f70b1d60f794 | 308 | led_color = led; /* Store the LED color for the flash function */ |
Gfolker | 0:f70b1d60f794 | 309 | } |
Gfolker | 3:24b332b8e41d | 310 | else if ((total - avg) > 10 and (total - avg) < 50 and total < 100 or (ARC >= 10 and ARC < 20)) { |
Gfolker | 0:f70b1d60f794 | 311 | led = yellow; |
Gfolker | 0:f70b1d60f794 | 312 | led_color = led; /* Store the LED color for the flash function */ |
Gfolker | 0:f70b1d60f794 | 313 | } |
Gfolker | 3:24b332b8e41d | 314 | else if ((total - avg >= 50) or total >= 100 or avg >= 100 or ARC >= 20) { |
Gfolker | 0:f70b1d60f794 | 315 | led = red; |
Gfolker | 0:f70b1d60f794 | 316 | led_color = led; /* Store the LED color for the flash function */ |
Gfolker | 0:f70b1d60f794 | 317 | } |
Gfolker | 0:f70b1d60f794 | 318 | } |
Gfolker | 0:f70b1d60f794 | 319 | |
Gfolker | 0:f70b1d60f794 | 320 | void led_out() { /* Function to flash LEDs */ |
Gfolker | 0:f70b1d60f794 | 321 | |
Gfolker | 0:f70b1d60f794 | 322 | if (led == green) {return;} /* If green, don't blink */ |
Gfolker | 0:f70b1d60f794 | 323 | else if (led == black) {led = led_color;} |
Gfolker | 0:f70b1d60f794 | 324 | else {led = black;} |
Gfolker | 0:f70b1d60f794 | 325 | |
Gfolker | 0:f70b1d60f794 | 326 | } |
Gfolker | 0:f70b1d60f794 | 327 | |
Gfolker | 0:f70b1d60f794 | 328 | void buzzer() { /* Function to handle the buzzer sound */ |
Gfolker | 0:f70b1d60f794 | 329 | |
Gfolker | 3:24b332b8e41d | 330 | if ((total - avg) <=25 and ARC < 10){ /* No buzzer sound if PPM is under 10 */ |
Gfolker | 0:f70b1d60f794 | 331 | Buzzer.period_us(0); |
Gfolker | 0:f70b1d60f794 | 332 | is_sounding = false; |
Gfolker | 0:f70b1d60f794 | 333 | } |
Gfolker | 0:f70b1d60f794 | 334 | |
Gfolker | 3:24b332b8e41d | 335 | else if ((total - avg) > 25 and (total - avg) < 50 and total < 100 or (ARC >=10 and ARC < 20)) { |
Gfolker | 0:f70b1d60f794 | 336 | if (is_sounding == false){ /* If the buzzer is not triggered, trigger */ |
Gfolker | 0:f70b1d60f794 | 337 | Buzzer.period_us(B_4); /* Period of B4 */ |
Gfolker | 0:f70b1d60f794 | 338 | Buzzer.write(0.50f); /* 50% Duty Cycle on the Tone */ |
Gfolker | 0:f70b1d60f794 | 339 | is_sounding = true; /* Signal that the buzzer is currently triggering */ |
Gfolker | 0:f70b1d60f794 | 340 | } |
Gfolker | 0:f70b1d60f794 | 341 | else { |
Gfolker | 0:f70b1d60f794 | 342 | Buzzer.period_us(0); /* Turn off the buzzer (Period = 0us)*/ |
Gfolker | 0:f70b1d60f794 | 343 | is_sounding = false; /* Signal that the buzzer is no longer triggering */ |
Gfolker | 0:f70b1d60f794 | 344 | } |
Gfolker | 0:f70b1d60f794 | 345 | } |
Gfolker | 0:f70b1d60f794 | 346 | |
Gfolker | 3:24b332b8e41d | 347 | else if ((total - avg) >= 50 or total >= 100 or avg >= 100 or ARC >= 20){ |
Gfolker | 0:f70b1d60f794 | 348 | if (is_sounding == false){ |
Gfolker | 0:f70b1d60f794 | 349 | Buzzer.period_us(B_5); /* Period of B5 */ |
Gfolker | 0:f70b1d60f794 | 350 | Buzzer.write(0.50f); /* 50% Duty Cycle on the Tone */ |
Gfolker | 0:f70b1d60f794 | 351 | is_sounding = true; |
Gfolker | 0:f70b1d60f794 | 352 | } |
Gfolker | 0:f70b1d60f794 | 353 | else { |
Gfolker | 0:f70b1d60f794 | 354 | Buzzer.period_us(0); /* Turn off the buzzer */ |
Gfolker | 0:f70b1d60f794 | 355 | is_sounding = false; |
Gfolker | 0:f70b1d60f794 | 356 | } |
Gfolker | 0:f70b1d60f794 | 357 | } |
Gfolker | 0:f70b1d60f794 | 358 | } |
Gfolker | 0:f70b1d60f794 | 359 | |
Gfolker | 0:f70b1d60f794 | 360 | void CalculatePPM(){ /* Function to convert the analog signals to digital based on 16 bit adc steps */ |
Gfolker | 0:f70b1d60f794 | 361 | |
Gfolker | 0:f70b1d60f794 | 362 | const double AQ_Rl = 20000.0; // AQ_Rl (20kOhm) - Load resistance for AQ sensor |
Gfolker | 0:f70b1d60f794 | 363 | const double CO_Rl = 18500.0; // CO_Rl (18.5kOhm) - Load resistance for CO sensor |
Gfolker | 0:f70b1d60f794 | 364 | const double Vadc_33 = 0.0000503548; // ADC step 3,3V/65535 0.00503mV (16bit ADC) |
Gfolker | 0:f70b1d60f794 | 365 | //const double Vadc_5 = 5.0/65535; // ADC step 5.0V/2^16 (65535, 16bit ADC) |
Gfolker | 0:f70b1d60f794 | 366 | double Vrl; // Output voltage |
Gfolker | 0:f70b1d60f794 | 367 | double Rs; // Rs (Ohm) - Sensor resistance |
Gfolker | 0:f70b1d60f794 | 368 | double ratio; // Rs/Rl ratio |
Gfolker | 0:f70b1d60f794 | 369 | double lgPPM; |
Gfolker | 0:f70b1d60f794 | 370 | |
Gfolker | 3:24b332b8e41d | 371 | if (aq_total > 65533) //prevents NAN error from overflow of 16 bits |
Gfolker | 3:24b332b8e41d | 372 | aq_total = 65530; |
Gfolker | 0:f70b1d60f794 | 373 | Vrl = (double)aq_total * Vadc_33; // For 3.3V Vcc use Vadc_33 |
Gfolker | 0:f70b1d60f794 | 374 | Rs = AQ_Rl * (3.3 - Vrl)/Vrl; // Calculate sensor resistance |
Gfolker | 0:f70b1d60f794 | 375 | ratio = Rs/AQ_Rl; // Calculate ratio |
Gfolker | 1:8ab4a1e27785 | 376 | lgPPM = (log10(ratio) * -0.8) + 0.9; |
Gfolker | 1:8ab4a1e27785 | 377 | aq_ppm = 6* pow(10,lgPPM) - 12; // Calculate air quality ppm |
Gfolker | 0:f70b1d60f794 | 378 | |
Gfolker | 3:24b332b8e41d | 379 | if (co_total > 65533) //prevents NAN error from overflow of 16 bits |
Gfolker | 3:24b332b8e41d | 380 | co_total = 65530; |
Gfolker | 0:f70b1d60f794 | 381 | Vrl = (double)co_total * Vadc_33; // For 3.3V Vcc use Vadc_33 |
Gfolker | 0:f70b1d60f794 | 382 | Rs = CO_Rl * (3.3 - Vrl)/Vrl; // Calculate sensor resistance |
Gfolker | 0:f70b1d60f794 | 383 | ratio = Rs/CO_Rl; // Calculate ratio |
Gfolker | 1:8ab4a1e27785 | 384 | lgPPM = (log10(ratio) * -0.8) + 0.9; |
Gfolker | 1:8ab4a1e27785 | 385 | co_ppm = 6* pow(10,lgPPM) - 12; // Calculate carbon monoxide ppm |
Gfolker | 1:8ab4a1e27785 | 386 | |
Gfolker | 3:24b332b8e41d | 387 | if (aq_ppm < 0) |
Gfolker | 1:8ab4a1e27785 | 388 | aq_ppm = 0; //prevents underflow |
Gfolker | 1:8ab4a1e27785 | 389 | else if (aq_ppm >= 1000) |
Gfolker | 1:8ab4a1e27785 | 390 | aq_ppm = 999.99; //prevents overflow |
Gfolker | 1:8ab4a1e27785 | 391 | |
Gfolker | 1:8ab4a1e27785 | 392 | if (co_ppm <0) |
Gfolker | 1:8ab4a1e27785 | 393 | co_ppm = 0; |
Gfolker | 1:8ab4a1e27785 | 394 | else if (co_ppm >= 1000) |
Gfolker | 1:8ab4a1e27785 | 395 | co_ppm = 999.99; |
Gfolker | 1:8ab4a1e27785 | 396 | |
Gfolker | 1:8ab4a1e27785 | 397 | /* Calculate the total */ |
Gfolker | 3:24b332b8e41d | 398 | total = co_ppm + aq_ppm; |
Gfolker | 1:8ab4a1e27785 | 399 | if (total < 0) |
Gfolker | 1:8ab4a1e27785 | 400 | total = 0; |
Gfolker | 1:8ab4a1e27785 | 401 | else if (total >= 1000) |
Gfolker | 1:8ab4a1e27785 | 402 | total = 999.99; |
Gfolker | 1:8ab4a1e27785 | 403 | } |
Gfolker | 1:8ab4a1e27785 | 404 | |
Gfolker | 1:8ab4a1e27785 | 405 | void dataQueue() |
Gfolker | 1:8ab4a1e27785 | 406 | { /* Beginning of function */ |
Gfolker | 1:8ab4a1e27785 | 407 | if (pushIndex != SIZE and !calc){ /* Initially pushing values into the set */ |
Gfolker | 1:8ab4a1e27785 | 408 | dataSet[pushIndex] = total; //push value into the queue |
Gfolker | 1:8ab4a1e27785 | 409 | sum += dataSet[pushIndex]; //add the value to the sum |
Gfolker | 1:8ab4a1e27785 | 410 | pushIndex++; //increment the push index |
Gfolker | 1:8ab4a1e27785 | 411 | |
Gfolker | 1:8ab4a1e27785 | 412 | if (pushIndex == SIZE){ |
Gfolker | 1:8ab4a1e27785 | 413 | avg = sum / SIZE; //compute the average once the queue is full |
Gfolker | 1:8ab4a1e27785 | 414 | calc = true; //flag calc |
Gfolker | 3:24b332b8e41d | 415 | ARC = dataSet[SIZE - 1] - dataSet[SIZE - 2]; |
Gfolker | 1:8ab4a1e27785 | 416 | pushIndex = 0; //reset the push index back to 0 |
Gfolker | 1:8ab4a1e27785 | 417 | } |
Gfolker | 1:8ab4a1e27785 | 418 | } |
Gfolker | 1:8ab4a1e27785 | 419 | |
Gfolker | 1:8ab4a1e27785 | 420 | else if (pushIndex != SIZE and calc){ /* Pushing values into the set once the set is full */ |
Gfolker | 1:8ab4a1e27785 | 421 | sum -= dataSet[pushIndex]; //subtract the value to be overriden from the sum |
Gfolker | 1:8ab4a1e27785 | 422 | dataSet[pushIndex] = total; //push the value into the set |
Gfolker | 1:8ab4a1e27785 | 423 | sum += dataSet[pushIndex]; //add the value to the sum |
Gfolker | 3:24b332b8e41d | 424 | avg = sum / SIZE; //compute average |
Gfolker | 3:24b332b8e41d | 425 | if (pushIndex == 0){ |
Gfolker | 3:24b332b8e41d | 426 | prev_value = dataSet[SIZE - 1]; |
Gfolker | 3:24b332b8e41d | 427 | ARC = dataSet[pushIndex] - prev_value; |
Gfolker | 3:24b332b8e41d | 428 | } |
Gfolker | 3:24b332b8e41d | 429 | else { |
Gfolker | 3:24b332b8e41d | 430 | prev_value = dataSet[pushIndex - 1]; |
Gfolker | 3:24b332b8e41d | 431 | ARC = dataSet[pushIndex] - prev_value; |
Gfolker | 3:24b332b8e41d | 432 | } |
Gfolker | 1:8ab4a1e27785 | 433 | pushIndex++; //increment the push index |
Gfolker | 1:8ab4a1e27785 | 434 | |
Gfolker | 1:8ab4a1e27785 | 435 | if (pushIndex == SIZE) |
Gfolker | 1:8ab4a1e27785 | 436 | pushIndex = 0; //reset the push index back to 0 |
Gfolker | 1:8ab4a1e27785 | 437 | } |
Gfolker | 1:8ab4a1e27785 | 438 | |
Gfolker | 1:8ab4a1e27785 | 439 | } /* End of function */ |
Gfolker | 1:8ab4a1e27785 | 440 | |
Gfolker | 1:8ab4a1e27785 | 441 | void StartHaptic(void) |
Gfolker | 1:8ab4a1e27785 | 442 | { |
Gfolker | 3:24b332b8e41d | 443 | hapticTimer.start(50); |
Gfolker | 1:8ab4a1e27785 | 444 | haptic = 1; |
Gfolker | 1:8ab4a1e27785 | 445 | } |
Gfolker | 1:8ab4a1e27785 | 446 | |
Gfolker | 1:8ab4a1e27785 | 447 | void StopHaptic(void const *n) { |
Gfolker | 1:8ab4a1e27785 | 448 | haptic = 0; |
Gfolker | 1:8ab4a1e27785 | 449 | hapticTimer.stop(); |
Gfolker | 0:f70b1d60f794 | 450 | } |