POC Breath using SMD commercial sensors

Dependencies:   iAQ_Core Adafruit_SGP30_mbed mbed BME680

main.cpp

Committer:
christodoulos
Date:
2020-06-14
Revision:
10:aad246b57873
Parent:
9:81d1b4833516

File content as of revision 10:aad246b57873:

#include "mbed.h"
#include "flow.h"
#include <math.h>
#include "iAQ_Core.h"
#include "Adafruit_SGP30.h"
#include"BME680.h"
/////////////////////////
// In this version of the program developed for the Breath project, flow and CO2, as well as 8 channel sensors,
// are measured in a separate .h file called: "flow.h" which is included in the
// main code. So 10 sets of data is streamed using a serial connection (TTL cable or Bluetooth)
// without any intruption.
// This version is especially suitable to be used for KST.
// Also, a solenoid would be turned on and off based on calculating the standard deviation in CO2 profile.
//
// START POINT: calculates SD for 9 samples of CO2, if it's grater than 0.02 it enables the solenoid.
// END POINT: calculates SD for 9 samples of CO2, if it's grater thatn 0.05 it disables the solenoid.
//
// You can easily change the threshold of Standard deviation to detect plateau
//
// Generated by: Mehrnaz Javadipour
//////////////////////////

Serial ttl(PC_12,PD_2);  //TTL cable TX,RX
DigitalOut sol(PC_5);   //Solenoid: Digital Output
PwmOut led(PB_6);
Timer stream;

///SENSOR SETUP///
BME680 myBME680     ( PC_1,PC_0, 400000 ); //BME680
iAQ_Core myiAQ_Core ( PB_11_ALT0,PB_10_ALT0, iAQ_Core::iAQ_Core_ADDRESS ); //iAQ-Core C
Adafruit_SGP30 sgp30(PB_14,PB_13); // SGP30
I2C ZMODtemp(PB_9, PB_8); //ZMOD and Si7050

iAQ_Core::iAQ_Core_status_t  aux;
iAQ_Core::iAQ_Core_data_t    myiAQ_Core_data;

///BME680 EXTRA FUNCTIONS///
Ticker      newReading;

uint32_t    myState = 0;

//@brief   FUNCTION PROTOTYPES
void    changeDATA     ( void );
void    user_delay_ms  ( uint32_t  period );
int8_t  user_i2c_read  ( uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len );
int8_t  user_i2c_write ( uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len );

void changeDATA ( void )
{
    myState = 1;
}

void user_delay_ms ( uint32_t period )
{
    wait( 0.01 );
}

int8_t user_i2c_read ( uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len )
{
    int8_t rslt = 0; // Return 0 for Success, non-zero for failure

    uint32_t aux     =   0;
    aux      =   myBME680._i2c.write ( dev_id, (char*)&reg_addr, 1, true );
    aux      =   myBME680._i2c.read  ( dev_id, (char*)&reg_data[0], len );



    if ( aux == 0 ) {
        rslt     =   0;
    } else {
        rslt     =   0xFF;
    }


    return rslt;
}

int8_t user_i2c_write ( uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len )
{
    int8_t rslt = 0; // Return 0 for Success, non-zero for failure

    uint32_t     aux     =   0;
    char         cmd[16] =  { 0 };
    uint32_t     i       =   0;

    // Prepare the data to be sent
    cmd[0]   =   reg_addr;
    for ( i = 1; i <= len; i++ ) {
        cmd[i]   =   reg_data[i - 1];
    }

    // Write data
    aux      =   myBME680._i2c.write ( dev_id, &cmd[0], len + 1, false );



    if ( aux == 0 ) {
        rslt     =   0;
    } else {
        rslt     =   0xFF;
    }


    return rslt;
}
///END SENSOR SETUP///

int main()
{
    ttl.baud(115200); //baudrate for the serial connection, 9600 for hc05 115200 for rn

    ttl.printf("$");//enter command mode only for rn
    wait(0.5);
    ttl.printf("$$");//enter command mode
    wait(0.5);
    ttl.printf("SN,POC Breath\r");//set new name
    wait(0.5);
    ttl.printf("SS,C0\r");//set transparent uart
    wait(0.5);
    ttl.printf("&,86DA9DA1FBA2\r");//Assign mac
    wait(0.5);
    ttl.printf("---\r");//enter data mode
    wait(0.5);

    ///SENSOR INITIALISATION///

    ///IAQ DOESN'T REQUIRE INITIALISATION///

    ///SGP30///
    sgp30.begin();//begin sgp30
    sgp30.IAQinit();//initialise sgp30



    ///BME680//
    struct bme680_dev gas_sensor;

    gas_sensor.dev_id   =   BME680_I2C_ADDR_PRIMARY;
    gas_sensor.intf     =   BME680_I2C_INTF;
    gas_sensor.read     =   user_i2c_read;
    gas_sensor.write    =   user_i2c_write;
    gas_sensor.delay_ms =   user_delay_ms;
    // amb_temp can be set to 25 prior to configuring the gas sensor
    // or by performing a few temperature readings without operating the gas sensor.
    gas_sensor.amb_temp =   25;


    int8_t rslt = BME680_OK;
    rslt = myBME680.bme680_init ( &gas_sensor );


    uint8_t set_required_settings;

    // Set the temperature, pressure and humidity settings
    gas_sensor.tph_sett.os_hum  = BME680_OS_2X;
    gas_sensor.tph_sett.os_pres = BME680_OS_4X;
    gas_sensor.tph_sett.os_temp = BME680_OS_8X;
    gas_sensor.tph_sett.filter  = BME680_FILTER_SIZE_3;

    // Set the remaining gas sensor settings and link the heating profile
    gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
    // Create a ramp heat waveform in 3 steps
    gas_sensor.gas_sett.heatr_temp  = 320; // degree Celsius
    gas_sensor.gas_sett.heatr_dur   = 150; // milliseconds

    // Select the power mode
    // Must be set before writing the sensor configuration
    gas_sensor.power_mode = BME680_FORCED_MODE;

    // Set the required sensor settings needed
    set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;

    // Set the desired sensor configuration
    rslt = myBME680.bme680_set_sensor_settings ( set_required_settings, &gas_sensor );

    // Set the power mode
    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor );


    // Get the total measurement duration so as to sleep or wait till the measurement is complete
    uint16_t meas_period;
    myBME680.bme680_get_profile_dur ( &meas_period, &gas_sensor );

    struct bme680_field_data data;


    newReading.attach( &changeDATA, 1 );                                        // the address of the function to be attached ( changeDATA ) and the interval ( 1s )

    //END BME680///

    ///ZMOD AND TEMP///
    int ZMODTEMPaddr=0x80; //si7050 8bit address

    char wTemp[1];
    wTemp[0]=0xE3; //Hold master mode
    char rTemp[2]; //Temperature returns MSB and LSB
    //assume MBS in rTemp[0] and LSB in rTemp[1]

    char wInit[2];
    wInit[0]=0xE6; //User register 1
    wInit[1]=0x00; //Set 14 bit resolution, other read-ony registers shouldn't be affected

    ZMODtemp.write(ZMODTEMPaddr,wInit,2);
    ///END ZMOD AND TEMP///

    ///END SENSOR INITIALISATION///
    flow();         //calling flow from flow.h
    carbon();       //calling CO2 from flow.h
    s1();           //calling 8 channels from flow.h
    s2();
    s3();
    s4();
    s5();
    s6();
    s7();
    s8();
    getTemp();      //calling Temperature from flow.h

    //////////////////////////////
    // I defined a flag for each section of specific functions, so by enabling the
    // flag the section starts and by disabling the flag it finishes the section.
    // at the end of the program, I reset the flags so it would be ready for the next loop.
    /////////////////////////////

    int bf=0;         //FLAG for detecting base flow
    int i=0;
    float bfArray[4]; //sampling flow for finding the average base flow
    float sf=0;       //sum of flow samples for calculating base flow
    float fv=0;       //final value of base flow

    int measurement_started=0; //FLAG for starting calculations after detecting breath

    int solstart=0;         //FLAG for starting calculations for detecting plateau
    int m=0;
    int myArray[9];         //sampling 9 values of CO2
    unsigned int sum=0;     //sum of 9 samples of CO2
    int avg=0;              //average of 9 samples of CO2
    int difSum=0;           //used for the Standard deviation algorithm
    long double var=0.0;    //used for the Standard deviation algorithm
    float sigma=0.0;        //final value for standar deviation
    int flags=0;            //FLAG for keep taking samples from CO2 profile when it's too early to detect plateau

    int solend=0;           //FLAG for ending calculations for detecting plateau
    unsigned int sum2=0;    //same as before; used for finding standard deviation
    long double var2=0.0;
    float sigma2=0.0;
    int difSum2=0;
    int avg2=0;
    int flage=0;            //FLAG for keep taking samples from CO2 profile when it's too early to finish plateau

    int fin=0;
    wait(1);
    sol=1;//sol off 1

    while(1) {

        //led=0.4f;      //an LED is fully turned on at the beginning, the brightness will be reduced when the plateau is detected.
        //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor

        myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
        wait(0.1);
        sgp30.IAQmeasure();//Measurement from SGP30

        rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

        ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
        ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
        ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
        float temp_code=(rTemp[0]<<8)+rTemp[1];
        float SiTemp=((175.72*temp_code)/65536)-46.85;
        ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
        rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
        
        wait(0.01);
        if (bf==0) {    //finding base flow before breath
            for(i=0; i<4; i++) {
                bfArray[i]=flow();
                sf+=bfArray[i];
            }
            fv=sf/4;
            //fv=fv+0.2;
            fv=0.1;
            //ttl.printf("set\n");
            bf=1;
        }

        //Starts calculations when it detects breathing into the device:

        if ((flow()>fv) and (measurement_started ==0)) {
            stream.start();
            measurement_started = 1;
        }

        //Starts detecting plateau:

        if ((measurement_started == 1) and (solstart==0)) {

            //Takes 9 samples of CO2:
            //I have also included printing the values inside the loops so we don't loose any data during calculatins.
            for(m=0; m<9; m++) {
                //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                wait(0.1);
                sgp30.IAQmeasure();//Measurement from SGP30

                rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                float temp_code=(rTemp[0]<<8)+rTemp[1];
                float SiTemp=((175.72*temp_code)/65536)-46.85;

                ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                
                myArray[m]=carbon();
                wait(0.1);
            }
            while(flags==0) {
                //While "flags" is enabled, keeps calculating the standard deviation.
                for(int m=0; m<9; m++) {
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor

                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                    
                    sum+=myArray[m];
                    wait(0.1);

                }
                avg=sum/9;
                for(int m=0; m<9; m++) {
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                    
                    difSum+=(myArray[m]-avg)*(myArray[m]-avg); //Find sum of difference between value X and mean
                    wait(0.1);
                }
                var=difSum/9;
                sigma=sqrt(var);
                if (sigma<0.02) {

                    //if SD is less than 0.02 it means that it is too early to start the plateau
                    //So we shift all but the first sample and define the new set of arrays:

                    for(int m=0; m<8; m++) {
                        //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                        myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                        wait(0.1);
                        sgp30.IAQmeasure();//Measurement from SGP30

                        rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                        ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                        ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                        ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                        float temp_code=(rTemp[0]<<8)+rTemp[1];
                        float SiTemp=((175.72*temp_code)/65536)-46.85;
                        ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                        rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                        
                        myArray[m]=myArray[m+1];  //Shift all CO2 values to the left by 1 value
                        wait(0.1);

                    }
                    myArray[8]=carbon();  //assign a new value for the 9th sample
                }
                //The new set of arrays are now generated and is sent back to be used for preveious SD calculations.
                //If sigma for the new set is still small, a newer set will be generated and replaced
                //Otherwise, it's accepted and will turn on the solenoid:
                else {
                    sol=0;      //Solenoid is ON 0
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), 100.00,s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(),0.00,s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                   rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                   
                    //led=0.4f;  //The brightness is reduced to half during the plateau
                    wait(0.1);
                    flags=1;    //breakes the while loop
                }
            }
            solend=1;   //prepares the next section for finishing the plateau
            solstart =1;
        }
        if ((measurement_started == 1) and (solend==1)) {
            // same process happens for finishing the plateau:

            for(m=0; m<9; m++) {
                //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                wait(0.1);
                sgp30.IAQmeasure();//Measurement from SGP30

                rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                float temp_code=(rTemp[0]<<8)+rTemp[1];
                float SiTemp=((175.72*temp_code)/65536)-46.85;
                ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                
                myArray[m]=carbon();
                wait(0.1);
            }
            while(flage==0) {
                for(int m=0; m<9; m++) {
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                    
                    sum2+=myArray[m];
                    wait(0.1);
                }
                avg2=sum2/9;
                for(int m=0; m<9; m++) {
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                    
                    difSum2+=(myArray[m]-avg2)*(myArray[m]-avg2);
                    wait(0.1);
                }
                var2=difSum2/9;
                sigma2=sqrt(var2);
                if (sigma2<0.05) {
                    // here we defined the end threshold to be 0.05, it can be changed later based on experiment results
                    for(int m=0; m<8; m++) {
                        //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                        myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                        wait(0.1);
                        sgp30.IAQmeasure();//Measurement from SGP30

                        rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                        ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                        ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                        ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                        float temp_code=(rTemp[0]<<8)+rTemp[1];
                        float SiTemp=((175.72*temp_code)/65536)-46.85;
                        ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                        rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                        
                        myArray[m]=myArray[m+1];
                        wait(0.1);

                    }
                    myArray[8]=carbon();
                } else {
                    sol=1;  //Solenoid is OFF 1
                    //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(), 100.00,s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
                    myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
                    wait(0.1);
                    sgp30.IAQmeasure();//Measurement from SGP30

                    rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

                    ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
                    ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
                    ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
                    float temp_code=(rTemp[0]<<8)+rTemp[1];
                    float SiTemp=((175.72*temp_code)/65536)-46.85;
                    ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), 0.00,s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
                    rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
                    
                    wait(0.1);

                    flage=1;    //breakes the loop
                }
            }

            //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(),carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
            myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
            wait(0.1);
            sgp30.IAQmeasure();//Measurement from SGP30

            rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

            ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
            ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
            ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
            float temp_code=(rTemp[0]<<8)+rTemp[1];
            float SiTemp=((175.72*temp_code)/65536)-46.85;
            ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
            rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
            
            //led=0.4f;  //LED is back to full brightness
            bf=0;       //reset the detecting base flow flag
            fin=1;      //enables the next section flag



        }

        if(carbon()<2.00 && fin ==1) {
            //User has to wait for the CO2 level to drop less than 2% before testing again.
            //Once it is less than 2%, all the flags and parameters used in calculations are reset

            //ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f\n",getTemp(),flow(),carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read()); //chemical sensor
            myiAQ_Core.iAQ_Core_GetNewReading (  &myiAQ_Core_data ); //Measurement from iAQ-Core C
            wait(0.1);
            sgp30.IAQmeasure();//Measurement from SGP30

            rslt = myBME680.bme680_get_sensor_data ( &data, &gas_sensor ); //Measurement for BME680

            ZMODtemp.write(ZMODTEMPaddr,wInit,2); //maybe?
            ZMODtemp.write(ZMODTEMPaddr,wTemp,1);
            ZMODtemp.read(ZMODTEMPaddr,rTemp,2); //Returns 2 bytes
            float temp_code=(rTemp[0]<<8)+rTemp[1];
            float SiTemp=((175.72*temp_code)/65536)-46.85;
            ttl.printf("tt%.2f,ff%.2f,cc%.2f,sa%i,sb%i,sc%i,sd%i,se%i,sf%i,sg%i,sh%i,ti%.2f,ic%d,iv%d,ir%d,gc%d,gv%d,br%d,bt%.2f,bh%.2f,bp%.2f,zi%f,zh%f,zc%f,st%.2f\n",0.00,flow(), carbon(),s1(),s2(),s3(),s4(),s5(),s6(),s7(),s8(),stream.read(),myiAQ_Core_data.pred, myiAQ_Core_data.Tvoc, myiAQ_Core_data.resistance, sgp30.eCO2,sgp30.TVOC, data.gas_resistance,( data.temperature/100.0f ), ( data.humidity / 1000.0f ), ( data.pressure / 100.0f ),0.00,0.00,0.00,SiTemp);    //Results after 5 mins of ON
            rslt = myBME680.bme680_set_sensor_mode ( &gas_sensor ); //BME680 reset
            
            stream.reset();
            stream.stop();
            measurement_started =0;
            solstart=0;
            sum=0;
            var=0.0;
            sigma=0.0;
            difSum=0;
            sum2=0;
            var2=0.0;
            sigma2=0.0;
            difSum2=0;
            avg2=0;
            avg=0;
            flags=0;
            flage=0;
            fin=0;
        }

    }
}