![](/media/cache/profiles/725d948ddd84c02eadcdbaaf0c8586b1.jpg.50x50_q85.jpg)
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
Diff: main.cpp
- Revision:
- 5:a27fdb811237
- Parent:
- 4:4e35f2e4b786
- Child:
- 6:7f4ba36b025f
diff -r 4e35f2e4b786 -r a27fdb811237 main.cpp --- 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