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

Revision:
1:8ab4a1e27785
Parent:
0:f70b1d60f794
Child:
2:aa8c291b3f9a
diff -r f70b1d60f794 -r 8ab4a1e27785 driver.cpp
--- a/driver.cpp	Wed Mar 15 19:14:55 2017 +0000
+++ b/driver.cpp	Mon Mar 27 17:36:47 2017 +0000
@@ -4,7 +4,7 @@
 #include "string.h"
 #include "Hexi_KW40Z.h"   /* Driver for button presses and BLE */
 #include <math.h>       /* Used for ADC conversion algorithm */
-#include <iostream>   /* Used for debugging */
+#include "images.h"     /* BMPs of the images drawn to the OLED */
 
 /*****Function Prototypes*****/
 void readSensors();
@@ -12,13 +12,37 @@
 void led_out();
 void buzzer();
 void CalculatePPM();
+void dataQueue();
+void initModules();
+void StartHaptic(void);
+void StopHaptic(void const *n);
 
 PwmOut Buzzer(PTA10);   /* Buzzer is attached to docking station port 1 */
-
 AnalogIn AQSensor(PTB3);   /* Air Quality sensor is attached to docking station port 2 */
 AnalogIn COSensor(PTB6);   /* Carbon Monoxide sensor is attached to docking station port 3 */
 
+/* Instantiate the SSD1351 OLED Driver */ 
+SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15);
+
 BusOut led(PTC8, PTD0, PTC9);   /* RGB Port Configurations */
+DigitalOut haptic(PTB9);        /* Port Configuration for vibrations */
+/* Define timer for haptic feedback */
+RtosTimer hapticTimer(StopHaptic, osTimerOnce);
+
+int screen = 1;         //detects which screen the user is currently on
+bool is_drawn1 = 0;      //detects if the screen is already drawn to the screen
+bool is_drawn2 = 0;
+bool is_drawn3 = 0;
+
+/* Screens */
+const uint8_t *image1;
+//image1  = homescreen_bmp; 
+    
+const uint8_t *image2;
+//image2  = airquality_bmp;
+
+const uint8_t *image3;
+//image3  = co_bmp;
 
 const int green = 5,
           red = 6,          /* LED Colors */
@@ -33,7 +57,8 @@
        buzzer_sound,     /* Used for the sound buzzer subroutine call */
        led_flash,        /* Used to determine the flash rate */
        ledcolor,        /* Used to determine the LED color */
-       A2D_Convert;    /* Used to convert the analog signal to digital */
+       A2D_Convert,    /* Used to convert the analog signal to digital */
+       push;            /* Used to push values into the data array */
 
 float B_4 = 1000000/Ti4,    /* Tones that will play on the buzzer click */
       B_5 = 1000000/Ti5;
@@ -44,104 +69,245 @@
 char average[20]; /* Dynamic Text Buffer for the Average total */
 char total_total[20]; /* Dynamic Text Buffer for the Total total */
 
-/* Either unit16_t or float */
-double   total,    /* Variable to store the total total */
-         aq_ppm,   /* Variable used to store the AQ PPM */
-         co_ppm,   /* Variable used to store the CO PPM */ 
-         avg;      /* Variable to store the average total */
+/* Either unit16_t or double */
+double     total,    /* Variable to store the total total */
+           aq_ppm,   /* Variable used to store the AQ PPM */
+           co_ppm;   /* Variable used to store the CO PPM */ 
          
 uint16_t aq_total, /* Variable to store the AQ total */
-         co_total; /* Variable to store the CO total */          
+         co_total; /* Variable to store the CO total */  
+         
+/* Variables to handle the data queue algorithm */
+const int SIZE = 500;
+double dataSet [SIZE];
+int pushIndex = 0;
+bool calc = false;  
+double avg = 0, sum = 0;     
+
+/* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ 
+KW40Z kw40z_device(PTE24, PTE25);
+
+/* Instantiate the SSD1351 OLED Driver */ 
+//SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15);
+/* Get OLED Class Default Text Properties */
+//oled_text_properties_t textProperties = {0};
+//oled.GetTextProperties(&textProperties);
+
+/* Below are the functions to handle button presses and screens */
+
+void ButtonRight(void)//CO screen button
+{   
+    screen = 3;
+    //StartHaptic();
+    
+    //oled.DrawImage(image3,0,0);
+    
+    /* Get OLED Class Default Text Properties */
+    //oled_text_properties_t textProperties = {0};
+    //oled.GetTextProperties(&textProperties);
+    
+    //textProperties.fontColor = COLOR_WHITE;
+    //textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+    //oled.SetTextProperties(&textProperties);
+}
+
+void ButtonLeft(void)//AQ screen button
+{
+    screen = 2;
+    //StartHaptic();
+    
+    //oled.DrawImage(image2,0,0);
+    
+    /* Get OLED Class Default Text Properties */
+    //oled_text_properties_t textProperties = {0};
+    //oled.GetTextProperties(&textProperties);
+        
+    //textProperties.fontColor = COLOR_WHITE;
+    //textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+    //oled.SetTextProperties(&textProperties); 
+}
+
+void ButtonDown(void)//home screen button
+{
+    screen = 1;
+    //StartHaptic();
+    //const uint8_t *image1;
+    //image1 = homescreen_bmp;
+    
+    //oled.DrawImage(image1,0,0);
+    
+    /* Get OLED Class Default Text Properties */
+    //oled_text_properties_t textProperties = {0};
+    //oled.GetTextProperties(&textProperties);
+    
+    //textProperties.fontColor = COLOR_WHITE;
+    //textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+    //oled.SetTextProperties(&textProperties);
+} 
       
 int main(){
-
-    /* Instantiate the SSD1351 OLED Driver */ 
-    SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15);
     
     /* Get OLED Class Default Text Properties */
-    oled_text_properties_t textProperties = {0};
-    oled.GetTextProperties(&textProperties);
+    //oled_text_properties_t textProperties = {0};
+    //oled.GetTextProperties(&textProperties);
     
     /* Turns on the OLED Display*/
-    oled.PowerON();
+    //oled.PowerON();
+    
+  //  const uint8_t *image1;
+    //image1 = homescreen_bmp;
+    
+   // oled.DrawImage(image1,0,0); 
     
     /* Fills the screen with solid black */         
-    oled.FillScreen(COLOR_BLACK);
+    //oled.FillScreen(COLOR_BLACK);
     
     /* Display 'GAS LEVELS' at (x = 13,y = 0) */
-    strcpy((char *) text,"GAS LEVELS");
-    oled.Label((uint8_t *)text,13,0);
+    //strcpy((char *) text,"GAS LEVELS");
+    //oled.Label((uint8_t *)text,13,0);
     
     /* Change font color to green for Air Quality */ 
-    textProperties.fontColor   = COLOR_GREEN;
-    oled.SetTextProperties(&textProperties);
+    //textProperties.fontColor   = COLOR_GREEN;
+    //oled.SetTextProperties(&textProperties);
     
     /* Display 'Air Quality: ' at (x = 0, y = 20) */ 
-    strcpy(text,"AQ: ");
-    oled.Label((uint8_t *)text,0,20);
+    //strcpy(text,"AQ: ");
+    //oled.Label((uint8_t *)text,0,20);
     
     /* Change font color to red for Carbon Monoxide */
-    textProperties.fontColor   = COLOR_RED;
-    oled.SetTextProperties(&textProperties);
+    //textProperties.fontColor   = COLOR_RED;
+    //oled.SetTextProperties(&textProperties);
     
     /* Display 'CO: ' at (x = 0, y = 40) */
-    strcpy(text, "CO: ");
-    oled.Label((uint8_t *)text,0,40);
+    //strcpy(text, "CO: ");
+    //oled.Label((uint8_t *)text,0,40);
     
     /* Change font color to blue for Average and Total total */
-    textProperties.fontColor   = COLOR_BLUE;
-    oled.SetTextProperties(&textProperties);
+    //textProperties.fontColor   = COLOR_BLUE;
+    //oled.SetTextProperties(&textProperties);
     
     /* Display 'Average: ' at (x = 0, y = 60) */
-    strcpy(text, "Average: ");
-    oled.Label((uint8_t *)text, 0, 60);
+    //strcpy(text, "Average: ");
+    //oled.Label((uint8_t *)text, 0, 60);
     
     /* Display 'Total: ' at (x = 0, y = 80) */
-    strcpy(text, "Total: ");
-    oled.Label((uint8_t *)text,0,80);
+    //strcpy(text, "Total: ");
+    //oled.Label((uint8_t *)text,0,80);
     
     /* Set text properties to white and right aligned for the dynamic text */
-    textProperties.fontColor = COLOR_WHITE;
-    textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
-    oled.SetTextProperties(&textProperties);
+    //textProperties.fontColor = COLOR_WHITE;
+    //textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+    //oled.SetTextProperties(&textProperties);
+    
+    initModules();
     
     /* Subroutine Calls */
-    sensor_read.attach(&readSensors, 1);   /* Read the sensor on a time interval (Currently 3s) */
-    A2D_Convert.attach(&CalculatePPM, 1);  /* Convert the values read from the sensors to 16 bit integers */
+    //sensor_read.attach(&readSensors, 1);   /* Read the sensor on a time interval */
+    //A2D_Convert.attach(&CalculatePPM, 1);  /* Convert the values read from the sensors to floating point ppm values */
+    //push.attach(&dataQueue, 1);            /* Push the value into the set and compute the average */
     ledcolor.attach(&ledColor, 0.5);       /* Determine the LED color */
     led_flash.attach(&led_out, 0.25);      /* Flash LED based on sensor data */
     buzzer_sound.attach(&buzzer, 0.25);    /* Sensor values are sent to buzzer function */
     
-    while (1) { /* Loop to process and display data */
+    /* Register callbacks to button presses */
+    kw40z_device.attach_buttonDown(&ButtonDown);
+    kw40z_device.attach_buttonLeft(&ButtonLeft);
+    kw40z_device.attach_buttonRight(&ButtonRight);
+    
+    while (1) { /* Loop to display data to the OLED */
+    
+        /* Get OLED Class Default Text Properties */
+        oled_text_properties_t textProperties = {0};
+        oled.GetTextProperties(&textProperties);
         
-        /*                                       */
-        /*                                       */
-        /*                                       */
-        /* Code to process sensor data goes here */
-        /*                                       */
-        /*                                       */
-        /*                                       */
-        
-        sprintf(AQ_level,"%.2f",aq_ppm);    /* Print the AQ PPM to the screen */
-        
-        /* Display time reading in 35px by 15px textbox at(x=55, y=40) */
-        oled.TextBox((uint8_t *)AQ_level,55,20,35,15); //Increase textbox for more digits
-        
-        sprintf(CO_level,"%.2f",co_ppm);    /* Print the CO PPM to the screen */
-        
-        oled.TextBox((uint8_t *)CO_level,55,40,35,15);
+        /* Set text properties to white and right aligned for the dynamic text */
+        textProperties.fontColor = COLOR_WHITE;
+        textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+        oled.SetTextProperties(&textProperties);
+
+        readSensors();
+        CalculatePPM();
+        dataQueue();
+        //ledColor();
+        //led_out();
+        //buzzer();
+        if (screen == 2){   //Air Quality Screen
+            is_drawn1 = 0;
+            is_drawn3 = 0;
+            if(!is_drawn2){
+                oled.DrawImage(image2,0,0);
+                is_drawn2 = 1;
+            }
+            sprintf(AQ_level,"%.2f",aq_ppm);    /* Print the AQ PPM to the screen */
+            oled.TextBox((uint8_t *)AQ_level,35,76,35,15);
+        }
+        else if (screen == 3){  //Carbon Monoxide Screen
+            is_drawn2 = 0;
+            is_drawn1 = 0;
+            if (!is_drawn3){
+                oled.DrawImage(image3,0,0);
+                is_drawn3 = 1;
+            }
+            sprintf(CO_level,"%.2f",co_ppm);    /* Print the CO PPM to the screen */        
+            oled.TextBox((uint8_t *)CO_level,35,76,35,15);
+        }
+        else if (screen == 1) {   //Home Screen
+            is_drawn3 = 0;
+            is_drawn2 = 0;
+            if (!is_drawn1){
+                oled.DrawImage(image1,0,0);
+                is_drawn1 = 1;
+            }
+            sprintf(average, "%.2f", avg);      /* Print the average to the screen */
+            oled.TextBox((uint8_t *)average,55,20,35,15);
+            sprintf(total_total, "%.2f", total);   /* Print the total to the screen */
+            oled.TextBox((uint8_t *)total_total,55,40,35,15);
+        }
+        Thread::wait(100);
+    }
+    
+    return 0;
+}
+
+void initModules() {    /* Function to initialize the system */
+
+    /* Turns on the OLED Display*/
+    oled.PowerON();
+    
+    image1 = homescreen_bmp;
+    image2 = airquality_bmp;
+    image3  = co_bmp;
+    
+    //oled.DrawImage(image1,0,0); 
+    //screen = 1;
+    
+    /* Register callbacks to button presses */
+    //kw40z_device.attach_buttonDown(&ButtonDown);
+    //kw40z_device.attach_buttonLeft(&ButtonLeft);
+    //kw40z_device.attach_buttonRight(&ButtonRight);
+    
+    /* Set text properties to white and right aligned for the dynamic text */
+    //textProperties.fontColor = COLOR_WHITE;
+    //textProperties.alignParam = OLED_TEXT_ALIGN_RIGHT;
+    //oled.SetTextProperties(&textProperties);
+    
+    /* while (1) {
+        readSensors();
+        CalculatePPM();
+        dataQueue();
+        ledColor();
+        led_out();
+        buzzer();
         
         sprintf(average, "%.2f", avg);      /* Print the average to the screen */
-        
-        oled.TextBox((uint8_t *)average,55,60,35,15);
+    
+       /* oled.TextBox((uint8_t *)average,55,20,35,15);
         
         sprintf(total_total, "%.2f", total);   /* Print the total to the screen */
         
-        oled.TextBox((uint8_t *)total_total,55,80,35,15);
-        
-    }
-    
-    return 0;
+       /* oled.TextBox((uint8_t *)total_total,55,40,35,15);
+        Thread::wait(50); */
+    //}
 }
 
 void readSensors(){  /* Function to read sensors */
@@ -157,15 +323,15 @@
 
 void ledColor(){    /* Function to determine the LED color */
     
-    if (total <= 10) {
+    if ((total - avg) <= 10) {
         led = green;
         led_color = led;     /* Store the LED color for the flash function */
     }
-    else if (total > 10 && total < 50) {
+    else if ((total - avg) > 10 && (total - avg) < 50) {
         led = yellow;
         led_color = led;     /* Store the LED color for the flash function */
     }
-    else if (total >= 50) {
+    else if ((total - avg >= 50) or total >= 100) {
         led = red;
         led_color = led;     /* Store the LED color for the flash function */
     }
@@ -181,12 +347,12 @@
 
 void buzzer() { /* Function to handle the buzzer sound */
 
-    if (total <=25){            /* No buzzer sound if PPM is under 10 */
+    if ((total - avg) <=25){            /* No buzzer sound if PPM is under 10 */
         Buzzer.period_us(0);
         is_sounding = false;  
     }
 
-    else if (total > 25 and total < 50) {
+    else if ((total - avg) > 25 and (total - avg) < 50) {
         if (is_sounding == false){      /* If the buzzer is not triggered, trigger */
             Buzzer.period_us(B_4);      /* Period of B4 */
             Buzzer.write(0.50f);        /* 50% Duty Cycle on the Tone */
@@ -198,7 +364,7 @@
         }        
     }
     
-    else if (total >= 50){
+    else if ((total - avg) >= 50 or total >= 100){
         if (is_sounding == false){
             Buzzer.period_us(B_5);      /* Period of B5 */
             Buzzer.write(0.50f);        /* 50% Duty Cycle on the Tone */
@@ -225,16 +391,68 @@
     Vrl = (double)aq_total * Vadc_33;            // For 3.3V Vcc use Vadc_33
     Rs = AQ_Rl * (3.3 - Vrl)/Vrl;                 // Calculate sensor resistance
     ratio = Rs/AQ_Rl;                             // Calculate ratio
-    lgPPM = (log10(ratio) * -0.8) + 0.9;       // Calculate air quality ppm
-    aq_ppm = 6* pow(10,lgPPM);                 // Calculate air quality ppm
+    lgPPM = (log10(ratio) * -0.8) + 0.9;      
+    aq_ppm = 6* pow(10,lgPPM) - 12;                 // Calculate air quality ppm
     
     Vrl = (double)co_total * Vadc_33;            // For 3.3V Vcc use Vadc_33
     Rs = CO_Rl * (3.3 - Vrl)/Vrl;                 // Calculate sensor resistance
     ratio = Rs/CO_Rl;                             // Calculate ratio
-    lgPPM = (log10(ratio) * -0.8) + 0.9;       // Calculate carbon monoxide ppm
-    co_ppm = 6* pow(10,lgPPM);                 // Calculate carbon monoxide ppm
+    lgPPM = (log10(ratio) * -0.8) + 0.9;       
+    co_ppm = 6* pow(10,lgPPM) - 12;                 // Calculate carbon monoxide ppm
+    
+     if (aq_ppm < 0)
+        aq_ppm = 0;             //prevents underflow
+    else if (aq_ppm >= 1000)
+        aq_ppm = 999.99;        //prevents overflow
+    
+    if (co_ppm <0)
+        co_ppm = 0;
+    else if (co_ppm >= 1000)
+        co_ppm = 999.99;
+      
+    /* Calculate the total */
+    total = co_ppm + aq_ppm;     
+    if (total < 0)
+        total = 0;
+    else if (total >= 1000)
+        total = 999.99; 
+}
+
+void dataQueue()
+{   /* Beginning of function */
     
-    /* Calculate the average and total */
-    total = co_ppm + aq_ppm;    
-    avg = (total)/2;  
+    if (pushIndex != SIZE and !calc){    /* Initially pushing values into the set */
+        dataSet[pushIndex] = total;          //push value into the queue
+        sum += dataSet[pushIndex];  //add the value to the sum
+        pushIndex++;                    //increment the push index
+        
+        if (pushIndex == SIZE){
+            avg = sum / SIZE;       //compute the average once the queue is full
+            calc = true;                //flag calc
+            pushIndex = 0;              //reset the push index back to 0
+        }
+    }
+    
+    else if (pushIndex != SIZE and calc){   /* Pushing values into the set once the set is full */
+        sum -= dataSet[pushIndex];          //subtract the value to be overriden from the sum
+        dataSet[pushIndex] = total;           //push the value into the set
+        sum += dataSet[pushIndex];          //add the value to the sum
+        avg = sum / SIZE;                   
+        pushIndex++;                        //increment the push index
+        
+        if (pushIndex == SIZE)
+            pushIndex = 0;    //reset the push index back to 0
+    }
+
+} /* End of function */
+
+void StartHaptic(void)
+{
+    hapticTimer.start(100);
+    haptic = 1;
+}
+
+void StopHaptic(void const *n) {
+    haptic = 0;
+    hapticTimer.stop();
 }
\ No newline at end of file