Hexiwear / Mbed OS Hexi_BreathAnalyzer_Application

Dependencies:   Hexi_KW40Z Hexi_OLED_SSD1351

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /****************************************************************************
00002 * Title                 :   iBreathe Breathalyzer
00003 * Filename              :   breathalyzer
00004 * Author                :   Dave Clarke
00005 * Origin Date           :   27/09/2016
00006 * Notes                 :   Breathalyzer utilizing Hexiware, Alcohol click and Wolksense
00007 *****************************************************************************/
00008 /**************************CHANGE LIST **************************************
00009 *
00010 *    Date    Software Version    Initials       Description
00011 *  27/09/16       1.0.0            DC        Interface Created.
00012 *
00013 *****************************************************************************/
00014 
00015 /**
00016  * @page TEST_CFG Test Configurations
00017  * <h3> Test configuration : </h3>
00018  * @par
00019  * <ul>
00020  * <li><b> MCU           </b> :      MK64FN1M0XXX12               </li>
00021  * <li><b> Dev. Board    </b> :      HEXIWEAR                     </li>
00022  * <li><b> Oscillator    </b> :      12 MHz external              </li>
00023  * <li><b> Ext. Modules  </b> :      Alcohol Click on mikroBUS 1  </li>
00024  * <li><b> SW            </b> :      mBed OS5    </li>
00025  * </ul>
00026  */
00027 
00028 /**
00029  * @mainpage
00030  * <h3> Breathalyser created with HEXIWEAR and mBed OS 5 </h3>
00031  * @par This will show you how much you've drunk and tell you with an Emoticon if
00032  * you're too hammered to even consider driving. Using the Hexiware app the readings
00033  * are transmitted to the cloud via bluetooth. Is it time to give up drinking yet?!
00034  
00035  * <h3> Alcohol Features </h3>
00036  * @par Alcohol click, Hexiwear docking station, Hexiware
00037  */
00038 
00039 /******************************************************************************
00040 * Includes
00041 *******************************************************************************/
00042 
00043 #include "mbed.h"
00044 #include "Hexi_KW40Z.h"
00045 #include "Hexi_OLED_SSD1351.h"
00046 #include "OLED_types.h"
00047 #include "OpenSans_Font.h"
00048 #include "string.h"
00049 #include "iBreatheImages.h"
00050 
00051 /******************************************************************************
00052 * Module Variable Definitions
00053 *******************************************************************************/
00054 
00055 #define LED_ON      0
00056 #define LED_OFF     1
00057 
00058                           // Pointers to:  
00059 const uint8_t   *welcome, // Welcome screen image
00060                 *blank,   // blank image
00061                 *blow,    // Start Blowing Image
00062                 *drink,   // You've been drinking image
00063                 *drive,   // Don't drive image
00064                 *hang,    // You'll have a hangover image
00065                 *ini,     // Initialising image
00066                 *sober;   // Sober as a judge image
00067 
00068 const float     Vadc_3V3  = 0.00005035;    // 16-Bit ADC step 3V3/65535   = 0.05035 mV
00069        
00070 float           Vrl = 0,                   // Output voltage
00071                 ambientAlc = 0,            // Abmient Output voltage from sensor
00072                 SensorRes = 0,             // SensorRes (Ohm) - Sensor resistance
00073                 SensorRes1 = 0,            // SensorRes (Ohm) - Sensor resistance
00074                 ppm = 0,                   // ppm
00075                 ppm_1 = 0,                 // Ambient ppm variable  
00076                 ratio = 0;                 // SensorRes/LoadRes ratio
00077               
00078 unsigned short  adc_rd = 0; //Initialise anologue read variable
00079 
00080 const uint8_t   ppmText[] = "ppm:"; // text for PPM label
00081 
00082 char            text[20],           // Text array variables
00083                 text2[20],
00084                 text3[20];
00085 
00086 float           value[20],  // initial sensor set up values
00087                 value1[20]; // initial sensor set up values
00088 
00089 bool            isFirstBoot = true;                   
00090                 
00091 
00092 /******************************************************************************
00093 * Function Prototypes
00094 *******************************************************************************/
00095 
00096 void sysinit(void);
00097 void ReadSensor();
00098 void CalculatePPM(int times, bool amb);
00099 void ambient(int times);
00100 void StartHaptic(void);
00101 void StopHaptic(void const *n);
00102 void ButtonUp(void);
00103 void txTask(void);
00104 
00105 /******************************************************************************
00106 * Instance setups
00107 *******************************************************************************/
00108 /* Define timer for haptic feedback */
00109 RtosTimer hapticTimer(StopHaptic, osTimerOnce);
00110 
00111 //set up Analog read pin for alcohol sensor
00112 AnalogIn Alcohol(PTB2);
00113 
00114 /* Instantiate the SSD1351 OLED Driver */ 
00115 SSD1351 oled(PTB22,PTB21,PTC13,PTB20,PTE6, PTD15); /* (MOSI,SCLK,POWER,CS,RST,DC) */
00116       
00117 /* Get OLED Class Default Text Properties */
00118 oled_text_properties_t textProperties = {0};
00119 
00120 /* Instantiate the Hexi KW40Z Driver (UART TX, UART RX) */ 
00121 KW40Z kw40z_device(PTE24, PTE25);
00122 
00123 /* LED and Haptic Set ups */
00124 DigitalOut redLed(LED1);
00125 DigitalOut greenLed(LED2);
00126 DigitalOut blueLed(LED3);
00127 DigitalOut haptic(PTB9);
00128 
00129 /******************************************************************************
00130 * Bluetooth button functions and passkey function
00131 *******************************************************************************/
00132 
00133 void ButtonRight(void)
00134 {
00135     StartHaptic();
00136     kw40z_device.ToggleAdvertisementMode();
00137     blueLed = kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00138     redLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00139     greenLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00140 }
00141 
00142 void ButtonLeft(void)
00143 {
00144     StartHaptic();
00145     kw40z_device.ToggleAdvertisementMode();
00146     blueLed = kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00147     redLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00148     greenLed = !kw40z_device.GetAdvertisementMode(); /*Indicate BLE Advertisment Mode*/
00149 }
00150 
00151 void PassKey(void)
00152 {
00153     StartHaptic();
00154     strcpy((char *) text,"PAIR CODE");
00155     oled.TextBox((uint8_t *)text,0,25,95,18);
00156   
00157     /* Display Bond Pass Key in a 95px by 18px textbox at x=0,y=40 */
00158     sprintf(text3,"%d", kw40z_device.GetPassKey());
00159     oled.TextBox((uint8_t *)text3,0,40,95,18);
00160 }
00161 
00162 /******************************************************************************
00163 * Main
00164 *******************************************************************************/
00165 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00166 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00167 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00168 int main()
00169 {
00170      /* Set pointers to the BMPs stored in  iBreatheImages.c */
00171      welcome = iBreatheWS_bmp;    // Welcome screen image 
00172      blank = iBreatheBlank_bmp;   // blank image
00173      blow = iBreatheBlow_bmp;    // Start Blowing Image
00174      drink = iBreatheDrink_bmp;   // You've been drinking image
00175      drive = iBreatheDrive_bmp;   // Don't drive image
00176      hang = iBreatheHang_bmp;    // You'll have a hangover image
00177      ini = iBreatheini_bmp;     // Initialising image
00178      sober = iBreatheSober_bmp;   // Sober as a judge image
00179        
00180      /* Set initial Values */
00181      sysinit();
00182 }
00183 
00184 /******************************************************************************
00185 * Public Function Definitions
00186 *******************************************************************************/
00187 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00188 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00189 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00190 /**************************************************************************************************
00191 * Function readSensor(void)
00192 * -------------------------------------------------------------------------------------------------
00193 * Overview: Read sensor
00194 * Input: None
00195 * Output: None
00196 **************************************************************************************************/
00197 
00198 void ReadSensor()
00199 {
00200     /* Read 16 Bit Analog value */
00201     adc_rd = Alcohol.read_u16();
00202 
00203     // pause 200ms 
00204     Thread::wait(200);
00205 }
00206 
00207 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00208 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00209 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00210 /**************************************************************************************************
00211 * Function CalculatePPM(Int times, bool amb)
00212 * -------------------------------------------------------------------------------------------------
00213 * Overview: Calculation of PPM
00214 * Input: times = Number of samples to take, amb sets either ambient reading or test reading (true for test)
00215 * Output: None
00216 **************************************************************************************************/
00217 
00218 void CalculatePPM(int times, bool amb)
00219 {
00220         float   lgPPM;
00221         
00222         /* Read values x times */
00223         for(int x = 0; x < times; x++)
00224         {
00225             ReadSensor();    
00226             value[x] = ((float)adc_rd  * Vadc_3V3);
00227             StartHaptic();
00228             Thread::wait(50);
00229         }    
00230         
00231         /* Calculate the average value for accuratcy */
00232         for(int y = 0; y < times; y++)
00233         {
00234             Vrl += value[y];
00235         }
00236         Vrl = Vrl / times;       
00237 
00238         /* Set SensorRes reference value */
00239         SensorRes =    (Vrl / 3.3);
00240         
00241         /* Set ratio */
00242         ratio     = SensorRes1 / SensorRes;
00243 
00244         /* Convert to PPM */
00245         lgPPM = ( log10( ratio ) * -1.5512 ) + 2.5911;
00246         
00247         /* If true create test result, flase creates reference result */
00248         if (amb == true)
00249         {
00250             ppm = pow( 10, lgPPM );
00251         }
00252         else
00253         {
00254             ppm_1 = pow( 10, lgPPM );
00255         }    
00256 }
00257 
00258 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00259 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00260 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00261 /**************************************************************************************************
00262 * Function void ambient(int times)
00263 * -------------------------------------------------------------------------------------------------
00264 * Overview: Reading of the Ambient Voltgage of the sensor for reference
00265 * Input: times = Number of samples to take
00266 * Output: None
00267 **************************************************************************************************/
00268 
00269 void ambient(int times)
00270 {
00271     /* Read ambient values x times flashing green led*/
00272     for(int x = 0; x < times; x++)
00273     {
00274         redLed      = LED_OFF;
00275         greenLed    = LED_OFF;
00276         blueLed     = LED_OFF;
00277         
00278         ReadSensor();
00279         value1[x] = (float)adc_rd  * Vadc_3V3; 
00280         
00281         redLed      = LED_OFF;
00282         greenLed    = LED_ON;
00283         blueLed     = LED_OFF;
00284         Thread::wait(48);   
00285     }
00286     
00287     /* Calculate the average value for accuratcy */
00288     for(int y = 0; y < times; y++)
00289     {
00290         ambientAlc+=value1[y];            
00291     }
00292     ambientAlc = ambientAlc / times;
00293   
00294     /* Set SensorRes1 reference value */
00295     SensorRes1 =   (ambientAlc / 3.3);
00296 }
00297 
00298 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00299 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00300 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00301 /**************************************************************************************************
00302 * Function void StartHaptic(void)
00303 * -------------------------------------------------------------------------------------------------
00304 * Overview: Start Buzzing haptic motor
00305 * Input:  None
00306 * Output: None
00307 **************************************************************************************************/
00308 
00309 void StartHaptic(void)
00310 {
00311     hapticTimer.start(50);
00312     haptic = 1;
00313 }
00314 
00315 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00316 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00317 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00318 /**************************************************************************************************
00319 * Function void StopHaptic(void)
00320 * -------------------------------------------------------------------------------------------------
00321 * Overview: Stop Buzzing haptic motor
00322 * Input:  None
00323 * Output: None
00324 **************************************************************************************************/
00325 
00326 void StopHaptic(void const *n) {
00327     haptic = 0;
00328     hapticTimer.stop();
00329 }
00330 
00331 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00332 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00333 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00334 /**************************************************************************************************
00335 * Function void ButtonUp(void)
00336 * -------------------------------------------------------------------------------------------------
00337 * Overview: Function called whe up button pressed, Begins Breathilyzer testing procedure
00338 * Input:  None
00339 * Output: None
00340 **************************************************************************************************/
00341 
00342 void ButtonUp(void)
00343 {
00344     StartHaptic();
00345     
00346     bool Ref = false;
00347     bool Test = true;
00348         
00349     /* LED set to green for test beginning*/
00350     redLed      = LED_OFF;
00351     greenLed    = LED_ON;
00352     blueLed     = LED_OFF;
00353     
00354     /* Fill 96px by 96px Screen with 96px by 96px Initialising Image starting at x=0,y=0 */   
00355     oled.DrawImage(ini,0,0);
00356     
00357     /* first boot bug work around to stop junk values */
00358     if (isFirstBoot == true)
00359     {
00360         /*read ambient atmosphere levels with 10 samples and set flag to show it's ambient basline figure*/
00361         ambient(1);
00362         CalculatePPM(1,Ref);
00363         isFirstBoot = false;
00364     }
00365     
00366     /*read ambient atmosphere levels with 10 samples and set flag to show it's ambient basline figure*/
00367     ambient(10);
00368     CalculatePPM(10,Ref);
00369     
00370     
00371     /* Fill 96px by 96px Screen with 96px by 96px Blowing Image starting at x=0,y=0 */  
00372     oled.DrawImage(blow,0,0);
00373     
00374     /*read breathe alcohol levels with 10 samples and set flag to show it's breathilyzer test figure*/
00375     CalculatePPM(10,Test);
00376     
00377     /*Calculate the difference in Alcohol level based on Ambient and test sample*/
00378     ppm = ppm - ppm_1;
00379     
00380     /*Throw away any values less than 0*/
00381     if (ppm < 0)
00382     {
00383          ppm = 0;
00384     }     
00385     
00386     /* Fill 96px by 96px Screen with 96px by 96px Blank Background Image starting at x=0,y=0 */
00387     oled.DrawImage(blank,0,0);     
00388     
00389     /* Show Calculated alcohol level in PPM and send data via bluetooth to the cloud */
00390     oled.SetTextProperties(&textProperties);
00391     oled.Label(ppmText,20,36);
00392     sprintf(text,"%.2f",ppm);
00393     oled.Label((uint8_t *)text,50,36);
00394     Thread::wait(1000);
00395     
00396     /* Currently sending to the Pressure variable as a temp place holder */
00397     kw40z_device.SendPressure(ppm * 10);
00398     
00399     /* You've got a Hangover coming!*/
00400     if ( ppm > 200)
00401     {
00402         redLed      = LED_ON;
00403         greenLed    = LED_OFF;
00404         blueLed     = LED_OFF;
00405         
00406         StartHaptic();
00407         
00408         /* Fill 96px by 96px Screen with 96px by 96px Hangover Image starting at x=0,y=0 */
00409         oled.DrawImage(hang,0,0);
00410     }   
00411     
00412     /* You Shouldn't drive */
00413     else if (ppm < 200 && ppm > 150)
00414     {
00415         redLed      = LED_ON;
00416         greenLed    = LED_OFF;
00417         blueLed     = LED_ON;
00418         
00419         StartHaptic();
00420       
00421         /* Fill 96px by 96px Screen with 96px by 96px Don't Drive Image starting at x=0,y=0 */      
00422         oled.DrawImage(drive,0,0);
00423     } 
00424     
00425     /* You've had a drink */
00426     else if (ppm < 150 && ppm > 50)
00427     {
00428         redLed      = LED_OFF;
00429         greenLed    = LED_ON;
00430         blueLed     = LED_ON;
00431         
00432         StartHaptic();
00433     
00434         /* Fill 96px by 96px Screen with 96px by 96px Had a drink Image starting at x=0,y=0 */     
00435         oled.DrawImage(drink,0,0);
00436     }
00437     
00438     /* Sober as a judge*/   
00439     else
00440     {
00441         redLed      = LED_OFF;
00442         greenLed    = LED_ON;
00443         blueLed     = LED_OFF;
00444         
00445         StartHaptic();
00446         oled.DrawImage(sober,0,0);    
00447     }
00448     Thread::wait(5000);
00449     
00450     /* Go back to start screen */
00451     sysinit();   
00452 }
00453 
00454 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00455 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00456 /////////////////////////////////////////////////////////////////////////////////////////////////////////////
00457 /**************************************************************************************************
00458 * Function void sysint(void)
00459 * -------------------------------------------------------------------------------------------------
00460 * Overview: System Initial Values Set up
00461 * Input: None
00462 * Output: None
00463 **************************************************************************************************/
00464 void sysinit(void)
00465 {
00466     /* Set LED to Blue by default*/      
00467     redLed      = LED_OFF;
00468     greenLed    = LED_OFF;
00469     blueLed     = LED_ON;
00470     
00471     /* Turn on the backlight of the OLED Display */
00472 //    oled.DimScreenON();
00473     
00474     /* Fill 96px by 96px Screen with 96px by 96px Welcome Image starting at x=0,y=0 */
00475     oled.DrawImage(welcome,0,0);
00476     
00477     /* Register callbacks to application functions */
00478     kw40z_device.attach_buttonUp(&ButtonUp);
00479     kw40z_device.attach_buttonLeft(&ButtonLeft);
00480     kw40z_device.attach_buttonRight(&ButtonRight);
00481     kw40z_device.attach_passkey(&PassKey);
00482     
00483     /* Send sensor data to bluetooth */
00484     kw40z_device.SendSetApplicationMode(GUI_CURRENT_APP_SENSOR_TAG);
00485     
00486     /* Change font color to White */
00487     oled.GetTextProperties(&textProperties); 
00488     textProperties.fontColor   = COLOR_WHITE;
00489     oled.SetTextProperties(&textProperties);
00490 }