Using Hexiware, Hexiware dock and an Alcohol click board, create your own breathalizer that connects to Wolksense to record your readings

Dependencies:   Hexi_KW40Z Hexi_OLED_SSD1351

Fork of Hexi_OLED_Text_Example by Hexiwear

Revision:
5:a27fdb811237
Parent:
4:4e35f2e4b786
Child:
6:7f4ba36b025f
--- a/main.cpp	Sun Aug 28 16:48:46 2016 +0000
+++ b/main.cpp	Tue Sep 27 09:27:06 2016 +0000
@@ -1,56 +1,476 @@
+/****************************************************************************
+* Title                 :   iBreathe Breathalyzer
+* Filename              :   breathalyzer
+* Author                :   Dave Clarke
+* Origin Date           :   27/09/2016
+* Notes                 :   Breathalyzer utilizing Hexiware, Alcohol click and Wolksense
+*****************************************************************************/
+/**************************CHANGE LIST **************************************
+*
+*    Date    Software Version    Initials       Description
+*  27/09/16       1.0.0            DC        Interface Created.
+*
+*****************************************************************************/
+
+/**
+ * @page TEST_CFG Test Configurations
+ * <h3> Test configuration : </h3>
+ * @par
+ * <ul>
+ * <li><b> MCU           </b> :      MK64FN1M0XXX12               </li>
+ * <li><b> Dev. Board    </b> :      HEXIWEAR                     </li>
+ * <li><b> Oscillator    </b> :      12 MHz external              </li>
+ * <li><b> Ext. Modules  </b> :      Alcohol Click on mikroBUS 1  </li>
+ * <li><b> SW            </b> :      mBed OS5    </li>
+ * </ul>
+ */
+
+/**
+ * @mainpage
+ * <h3> Breathalyser created with HEXIWEAR and mBed OS 5 </h3>
+ * @par This will show you how much you've drunk and tell you with an Emoticon if
+ * you're too hammered to even consider driving. Using the Hexiware app the readings
+ * are transmitted to the cloud via bluetooth. Is it time to give up drinking yet?!
+ 
+ * <h3> Alcohol Features </h3>
+ * @par Alcohol click, Hexiwear docking station, Hexiware
+ */
+
+/******************************************************************************
+* Includes
+*******************************************************************************/
+
 #include "mbed.h"
+#include "Hexi_KW40Z.h"
 #include "Hexi_OLED_SSD1351.h"
+#include "OLED_types.h"
+#include "OpenSans_Font.h"
 #include "string.h"
+#include "iBreatheImages.h"
+
+/******************************************************************************
+* Module Variable Definitions
+*******************************************************************************/
+
+#define LED_ON      0
+#define LED_OFF     1
+
+                          // Pointers to:  
+const uint8_t   *welcome, // Welcome screen image
+                *blank,   // blank image
+                *blow,    // Start Blowing Image
+                *drink,   // You've been drinking image
+                *drive,   // Don't drive image
+                *hang,    // You'll have a hangover image
+                *ini,     // Initialising image
+                *sober;   // Sober as a judge image
+
+const float     Vadc_3V3  = 0.00005035;    // 16-Bit ADC step 3V3/65535   = 0.05035 mV
+       
+float           Vrl = 0,                   // Output voltage
+                ambientAlc = 0,            // Abmient Output voltage from sensor
+                SensorRes = 0,             // SensorRes (Ohm) - Sensor resistance
+                SensorRes1 = 0,            // SensorRes (Ohm) - Sensor resistance
+                ppm = 0,                   // ppm
+                ppm_1 = 0,                 // Ambient ppm variable  
+                ratio = 0;                 // SensorRes/LoadRes ratio
+              
+unsigned short  adc_rd = 0; //Initialise anologue read variable
+
+const uint8_t   ppmText[] = "ppm:"; // text for PPM label
+
+char            text[20],           // Text array variables
+                text2[20],
+                text3[20];
+
+float           value[20],  // initial sensor set up values
+                value1[20]; // initial sensor set up values   
+                
+
+/******************************************************************************
+* Function Prototypes
+*******************************************************************************/
+
+void sysinit(void);
+void ReadSensor();
+void CalculatePPM(int times, bool amb);
+void ambient(int times);
+void StartHaptic(void);
+void StopHaptic(void const *n);
+void ButtonUp(void);
+void txTask(void);
+
+/******************************************************************************
+* Instance setups
+*******************************************************************************/
 
-int main() {
-    char text[20];  /* Text Buffer */ 
-    Timer time;     /* Instantiate Time */
+/* Instantiate the SSD1351 OLED Driver */ 
+SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); /* (MOSI,SCLK,POWER,CS,RST,DC) */
+      
+/* Get OLED Class Default Text Properties */
+oled_text_properties_t textProperties = {0};
+ 
+//set up Analog read pin for alcohol sensor
+AnalogIn Alcohol(PTB2);
+
+/* Define timer for haptic feedback */
+RtosTimer hapticTimer(StopHaptic, osTimerOnce);
+
+/* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ 
+KW40Z kw40z_device(PTE24, PTE25);
+
+/* LED and Haptic Set ups */
+DigitalOut redLed(LED1);
+DigitalOut greenLed(LED2);
+DigitalOut blueLed(LED3);
+DigitalOut haptic(PTB9);
+
+/******************************************************************************
+* Bluetooth button functions and passkey function
+*******************************************************************************/
+
+void ButtonRight(void)
+{
+    StartHaptic();
+    kw40z_device.ToggleAdvertisementMode();
+    blueLed = kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+    redLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+    greenLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+}
+
+void ButtonLeft(void)
+{
+    StartHaptic();
+    kw40z_device.ToggleAdvertisementMode();
+    blueLed = kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+    redLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+    greenLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
+}
+
+void PassKey(void)
+{
+    StartHaptic();
+    strcpy((char *) text,"PAIR CODE");
+    oled.TextBox((uint8_t *)text,0,25,95,18);
+  
+    /* Display Bond Pass Key in a 95px by 18px textbox at x=0,y=40 */
+    sprintf(text3,"%d", kw40z_device.GetPassKey());
+    oled.TextBox((uint8_t *)text3,0,40,95,18);
+}
+
+/******************************************************************************
+* Main
+*******************************************************************************/
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+int main()
+{
+     /* Set pointers to the BMPs stored in  iBreatheImages.c */
+     welcome = iBreatheWS_bmp;    // Welcome screen image 
+     blank = iBreatheBlank_bmp;   // blank image
+     blow = iBreatheBlow_bmp;    // Start Blowing Image
+     drink = iBreatheDrink_bmp;   // You've been drinking image
+     drive = iBreatheDrive_bmp;   // Don't drive image
+     hang = iBreatheHang_bmp;    // You'll have a hangover image
+     ini = iBreatheini_bmp;     // Initialising image
+     sober = iBreatheSober_bmp;   // Sober as a judge image
+        
+     /* Set initial Values */
+     sysinit();
+}
+
+/******************************************************************************
+* Public Function Definitions
+*******************************************************************************/
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function readSensor(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: Read sensor
+* Input: None
+* Output: None
+**************************************************************************************************/
+
+void ReadSensor()
+{
+    /* Read 16 Bit Analog value */
+    adc_rd = Alcohol.read_u16();
+
+    // pause 200ms 
+    Thread::wait(200);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function CalculatePPM(Int times, bool amb)
+* -------------------------------------------------------------------------------------------------
+* Overview: Calculation of PPM
+* Input: times = Number of samples to take, amb sets either ambient reading or test reading (true for test)
+* Output: None
+**************************************************************************************************/
 
-    /* Instantiate the SSD1351 OLED Driver */ 
-    SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); /* (MOSI,SCLK,POWER,CS,RST,DC) */
+void CalculatePPM(int times, bool amb)
+{
+        float   lgPPM;
+        
+        /* Read values x times */
+        for(int x = 0; x < times; x++)
+        {
+            ReadSensor();    
+            value[x] = ((float)adc_rd  * Vadc_3V3);
+            StartHaptic();
+            Thread::wait(50);
+        }    
+        
+        /* Calculate the average value for accuratcy */
+        for(int y = 0; y < times; y++)
+        {
+            Vrl += value[y];
+        }
+        Vrl = Vrl / times;       
+
+        /* Set SensorRes reference value */
+        SensorRes =    (Vrl / 3.3);
+        
+        /* Set ratio */
+        ratio     = SensorRes1 / SensorRes;
+
+        /* Convert to PPM */
+        lgPPM = ( log10( ratio ) * -1.5512 ) + 2.5911;
+        
+        /* If true create test result, flase creates reference result */
+        if (amb == true)
+        {
+            ppm = pow( 10, lgPPM );
+        }
+        else
+        {
+            ppm_1 = pow( 10, lgPPM );
+        }    
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void ambient(int times)
+* -------------------------------------------------------------------------------------------------
+* Overview: Reading of the Ambient Voltgage of the sensor for reference
+* Input: times = Number of samples to take
+* Output: None
+**************************************************************************************************/
+
+void ambient(int times)
+{
+    /* Read ambient values x times flashing green led*/
+    for(int x = 0; x < times; x++)
+    {
+        redLed      = LED_OFF;
+        greenLed    = LED_OFF;
+        blueLed     = LED_OFF;
+        
+        ReadSensor();
+        value1[x] = (float)adc_rd  * Vadc_3V3; 
+        
+        redLed      = LED_OFF;
+        greenLed    = LED_ON;
+        blueLed     = LED_OFF;
+        Thread::wait(48);   
+    }
     
-    /* Get OLED Class Default Text Properties */
-    oled_text_properties_t textProperties = {0};
-    oled.GetTextProperties(&textProperties);    
+    /* Calculate the average value for accuratcy */
+    for(int y = 0; y < times; y++)
+    {
+        ambientAlc+=value1[y];            
+    }
+    ambientAlc = ambientAlc / times;
+  
+    /* Set SensorRes1 reference value */
+    SensorRes1 =   (ambientAlc / 3.3);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void StartHaptic(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: Start Buzzing haptic motor
+* Input:  None
+* Output: None
+**************************************************************************************************/
+
+void StartHaptic(void)
+{
+    hapticTimer.start(50);
+    haptic = 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void StopHaptic(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: Stop Buzzing haptic motor
+* Input:  None
+* Output: None
+**************************************************************************************************/
+
+void StopHaptic(void const *n) {
+    haptic = 0;
+    hapticTimer.stop();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void ButtonUp(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: Function called whe up button pressed, Begins Breathilyzer testing procedure
+* Input:  None
+* Output: None
+**************************************************************************************************/
 
+void ButtonUp(void)
+{
+    StartHaptic();
+        
+    /* LED set to green for test beginning*/
+    redLed      = LED_OFF;
+    greenLed    = LED_ON;
+    blueLed     = LED_OFF;
+    
+    /* Fill 96px by 96px Screen with 96px by 96px Initialising Image starting at x=0,y=0 */   
+    oled.DrawImage(ini,0,0);
+    
+    /*read ambient atmosphere levels with 10 samples and set flag to show it's ambient basline figure*/
+    ambient(10);
+    CalculatePPM(10,false);
+    
+    /* Fill 96px by 96px Screen with 96px by 96px Blowing Image starting at x=0,y=0 */  
+    oled.DrawImage(blow,0,0);
+    
+    /*read breathe alcohol levels with 10 samples and set flag to show it's breathilyzer test figure*/
+    CalculatePPM(10,true);
+    
+    /*Calculate the difference in Alcohol level based on Ambient and test sample*/
+    ppm = ppm - ppm_1;
+    
+    /*Throw away any values less than 0*/
+    if (ppm < 0)
+    {
+         ppm = 0;
+    }     
+    
+    /* Fill 96px by 96px Screen with 96px by 96px Blank Background Image starting at x=0,y=0 */
+    oled.DrawImage(blank,0,0);     
+    
+    /* Show Calculated alcohol level in PPM and send data via bluetooth to the cloud */
+    oled.SetTextProperties(&textProperties);
+    oled.Label(ppmText,20,36);
+    sprintf(text,"%.2f",ppm);
+    oled.Label((uint8_t *)text,50,36);
+    Thread::wait(1000);
+    
+    /* Currently sending to the Pressure variable as a temp place holder */
+    kw40z_device.SendPressure(ppm * 10);
+    
+    /* You've got a Hangover coming!*/
+    if ( ppm > 200)
+    {
+        redLed      = LED_ON;
+        greenLed    = LED_OFF;
+        blueLed     = LED_OFF;
+        
+        StartHaptic();
+        
+        /* Fill 96px by 96px Screen with 96px by 96px Hangover Image starting at x=0,y=0 */
+        oled.DrawImage(hang,0,0);
+    }   
+    
+    /* You Shouldn't drive */
+    else if (ppm < 200 && ppm > 150)
+    {
+        redLed      = LED_ON;
+        greenLed    = LED_OFF;
+        blueLed     = LED_ON;
+        
+        StartHaptic();
+      
+        /* Fill 96px by 96px Screen with 96px by 96px Don't Drive Image starting at x=0,y=0 */      
+        oled.DrawImage(drive,0,0);
+    } 
+    
+    /* You've had a drink */
+    else if (ppm < 150 && ppm > 50)
+    {
+        redLed      = LED_OFF;
+        greenLed    = LED_ON;
+        blueLed     = LED_ON;
+        
+        StartHaptic();
+    
+        /* Fill 96px by 96px Screen with 96px by 96px Had a drink Image starting at x=0,y=0 */     
+        oled.DrawImage(drink,0,0);
+    }
+    
+    /* Sober as a judge*/   
+    else
+    {
+        redLed      = LED_OFF;
+        greenLed    = LED_ON;
+        blueLed     = LED_OFF;
+        
+        StartHaptic();
+        oled.DrawImage(sober,0,0);    
+    }
+    Thread::wait(5000);
+    
+    /* Go back to start screen */
+    sysinit();   
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**************************************************************************************************
+* Function void sysint(void)
+* -------------------------------------------------------------------------------------------------
+* Overview: System Initial Values Set up
+* Input: None
+* Output: None
+**************************************************************************************************/
+void sysinit(void)
+{
+    /* Set LED to Blue by default*/      
+    redLed      = LED_OFF;
+    greenLed    = LED_OFF;
+    blueLed     = LED_ON;
+    
     /* Turn on the backlight of the OLED Display */
     oled.DimScreenON();
     
-    /* Fills the screen with solid black */         
-    oled.FillScreen(COLOR_BLACK);
-
-    /* Display Text at (x=7,y=0) */
-    strcpy((char *) text,"TEXT EXAMPLE");
-    oled.Label((uint8_t *)text,7,0);
-        
-    /* Change font color to blue */ 
-    textProperties.fontColor   = COLOR_BLUE;
+    /* Fill 96px by 96px Screen with 96px by 96px Welcome Image starting at x=0,y=0 */
+    oled.DrawImage(welcome,0,0);
+    
+    /* Register callbacks to application functions */
+    kw40z_device.attach_buttonUp(&ButtonUp);
+    kw40z_device.attach_buttonLeft(&ButtonLeft);
+    kw40z_device.attach_buttonRight(&ButtonRight);
+    kw40z_device.attach_passkey(&PassKey);
+    
+    /* Send sensor data to bluetooth */
+    kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG);
+    
+    /* Change font color to White */
+    oled.GetTextProperties(&textProperties); 
+    textProperties.fontColor   = COLOR_WHITE;
     oled.SetTextProperties(&textProperties);
-
-    /* Display text at (x=5,y=40) */ 
-    strcpy(text,"Timer(s):");
-    oled.Label((uint8_t *)text,5,40);
-        
-    /* 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);    
-
-    
-    time.start(); /* start timer */
-
-    while (true) {
-        
-        /* Format the time reading */
-        sprintf(text,"%.2f",time.read());
-        
-        /* Display time reading in 35px by 15px textbox at(x=55, y=40) */
-        oled.TextBox((uint8_t *)text,55,40,35,15); //Increase textbox for more digits
-             
-        Thread::wait(1000);
-    }
-}
-
-
-    
-    
\ No newline at end of file
+}
\ No newline at end of file