Sebastian Ortega / Mbed 2 deprecated mDot_AirQualitySensors2

Dependencies:   libmDot mbed-rtos mbed

main.cpp

Committer:
SebastianOZ
Date:
2017-06-13
Revision:
1:86a5ef2c60f2
Parent:
0:37bb545b7e21

File content as of revision 1:86a5ef2c60f2:

/**  mDot with AirQuality sensors (SDS018,CMM5042)
 *
 * This program reads CO(CMM5042) and particle(SDS018) sensor data
 * in specified time intervals. After defined wait time, prints read-out in USB 
 * serial port to PC, connects to LoRa gateway and sends data (CO_avg, PM2.5, PM10):
 *
 *      "AQ, %d,     %1.2f,     %1.2f,    %3.2f,\r\n",
 *      "AQ, seconds,PM2_5_avg, PM10_avg, CO_avg",
 *  
 * IT DOES NOT USE mDOT SLEEP MODE YET, JUST WAITS SOME TIME
 *
 * SDS018 (PM particle sensor)  5V
 * It reads out the digital serial PA_2 and PA_2 ((D1, D0) in UDK2 board)) and
 * calculates the respective PM2.5 and PM10 values.
 *
 * CMM 5042 (CO sensor) 2.5 - 5.3 V
 * Reads analog input connected to pin PB_1 (UDK2 pin A0). Since it is analog input
 * there is an averaging time (avg_time) and sampling time (time_wait) between 
 * read-outs. It then estimates the corresponding concentration (ppm).
 * Warm-up time for this sensor is 30 s so it is better to read after PM sensor.
 *
 * The only additional hardware is jumper wires from sensor to
 * board.
 *
 * Sebastian Ortega, 06/2016
 */

#include "mbed.h"
#include "mDot.h"

// Define objects (I/O, mDot)
mDot* dot;
Serial sensor1(PA_2, PA_3);  // sensor1 - particle sensor [(D1, D0) in UDK2 board]
AnalogIn sensor2(PB_1);      // sensor2 - CO sensor [A0 in UDK2 board]
Timer t;
//Serial pc(USBTX, USBRX); // tx, rx

// Gateway configuration variables
static std::string config_network_name = "SIGMA_LoRa";
static std::string config_network_pass = "sigma2013";
static uint8_t config_frequency_sub_band = 1;

//Function prototypes for network connections
//void batteryvoltageMonitorTock();
void printError(mDot* dot, int32_t returnCode);
void printVersion();
bool setFrequencySubBand(uint8_t subBand);
bool setNetworkName(const std::string name);
bool setNetworkPassphrase(const std::string passphrase);
bool setPower(uint8_t power);
bool setAck(uint8_t retries);
bool joinNetwork();
bool send(const std::string text);
void sleep(uint32_t);
float CO_sensor();
float particle_sensor();


// Global variables
float PM2_5_avg = 0, PM10_avg = 0, CO_avg = 0;
float V_ref = 3.02f; //3.013f
uint32_t time_sleep = 30; // Time in s to wait between reads
uint16_t time_avg_CO = 5000;  // Time in ms for average of CO sensor
uint8_t samples_CO = 10;    // Samples for average of particle sensor (0.1s per sample)
uint8_t samples_par = 5;    // Samples for average of particle sensor (1s per sample)
//static volatile bool timeToReadBatteryVoltage = true;
//static volatile bool dataChanged = true;

// MAIN PROGRAM-----------------------------------------------------------------------------
int main()
{
    printf("\r\n\r\n");
    printf("=====================================\r\n");
    printf("Air Quality with LoRa mDot\r\n");
    printf("=====================================\r\n");
    printVersion();  
    set_time(1465391100); // Wed, 08 Jun 2016 13:05:00 GMT
    time_t seconds = time(NULL);  
    printf("Unix Epoch time = %d\r\n", seconds);
    
    // NETWORK INITIALIZATION
    // get the mDot handle
    dot = mDot::getInstance();
    // reset to default config so we know what state we're in
    dot->resetNetworkSession();
    dot->resetConfig();
    if (dot->getPublicNetwork() == false) {
        dot->setPublicNetwork(true);
        printf("Public network = FALSE \r\n");
    }
    // set up the mDot with our network information
    setNetworkName(config_network_name);
    setNetworkPassphrase(config_network_pass);
    setFrequencySubBand(config_frequency_sub_band);
    setPower(14);    // Reduce latency for 868 units
    setAck(0);      // Disable ack for less latency
    
    while (!joinNetwork()) { 
        wait(2); 
        dot->resetNetworkSession(); 
    }

    // SENSOR READOUT
    while (true) 
    { 
        t.start(); // start of sensor readout
        
        char latestData[100];  
        int time_start = t.read_ms();
        // Read particle sensor data
        printf("\nPARTICLE\n\r");
        particle_sensor();
        int time_PART = t.read_ms();
        
       // Read CO sensor data 
        printf("\nC0 SENSOR\n\r");
        CO_sensor();
        int time_CO = t.read_ms();
        
        // Print out average readouts
        time_t seconds = time(NULL);  
        printf("\nCSV OUT:\n\r");
        printf("Time(s), time_particle(ms), time_CO(ms), time_ALL(ms), PM2.5 (ug/m3), PM10 (ug/m3), CO(ppm),\r\n");
        //printf("%f,\t%d,\t%d,\t%d,\t%1.2f,\t%1.2f,\t%3.2f,\r\n", t.read(),time_PART-time_start,time_CO-time_PART,time_CO-time_start, PM2_5_avg, PM10_avg, CO_avg);
        printf("%d,\t%d,\t%d,\t%d,\t%1.2f,\t%1.2f,\t%3.2f,\r\n", seconds,time_PART-time_start,time_CO-time_PART,time_CO-time_start, PM2_5_avg, PM10_avg, CO_avg);
        
        // Prepare data to send to gateway
        //sprintf(latestData,"AQ: %f,\t%1.2f,\t%1.2f,\t%3.2f,\r\n", t.read(),PM2_5_avg, PM10_avg, CO_avg);
        sprintf(latestData,"AQ, %d, %1.2f, %1.2f, %3.2f,\r\n", seconds,PM2_5_avg, PM10_avg, CO_avg);
        send(latestData);
        
        sleep(time_sleep);
    } // while (true)
}

// SENSOR FUNCTIONS----------------------------------------------------------------

float particle_sensor()
{    
    int aux=0, t_init =0;
    float PM2_5_A = 0, PM10_A = 0, PM2_5_sum = 0, PM10_sum = 0;
    uint8_t oneByte = 0, mCheck = 0, PM2_5 = 0, PM10 = 0, myData[10];
    int i = 0;
    printf("PM2.5,\tPM10,\n\r");
    while (aux < samples_par) //while(t.read_ms()-t_init < time_avg)
    {
        if (aux==0)           
            t_init = t.read_ms();
        while (sensor1.readable()) { // whenever sensor transmits packet (every 1 s)
        // packet format: AA C0 PM25_Low PM25_High PM10_A_Low PM10_A_High ID1 ID2 CRC AB
            oneByte = sensor1.getc();   
            if(oneByte == 0xAA) { // head1 (AB) ok
                myData[0] =  oneByte;
                //wait_ms(2);
                oneByte = sensor1.getc();
                if(oneByte == 0xc0) { // head2 (C0) ok
                    //printf("\n Packet: ");
                    myData[1] =  oneByte;
                    mCheck = 0;
                    for(i=0; i < 6; i++) { // DATA 1-6 received and crc calc
                        myData[i+2] = sensor1.getc();
                        //wait_ms(2);
                        mCheck += myData[i+2];
                    }
                    myData[8] = sensor1.getc(); // crc
                    //wait_ms(1);
                    myData[9] = sensor1.getc(); // tail (AB)
        
                    // Print the received packet HEX bytes
                    /*
                    for (i=0; i<=9 ; i++) {
                        printf("%X ",myData[i]);
                    }
                    */
                    if(mCheck == myData[8]) { // if checksum OK
                        PM2_5 = ((uint16_t)myData[2] | (uint16_t)(myData[3]<<8));
                        PM10 = ((uint16_t)myData[4] | (uint16_t)(myData[5]<<8));
        
                        PM2_5_A = (float) PM2_5/10;
                        PM10_A = (float) PM10/10;
        
                        if(PM2_5_A*10 > 9999)
                            PM2_5_A = 999.9;
                        if(PM10_A*10 > 9999)
                            PM10_A = 999.9;
                        
                        aux++;
                        // Print the PM received data
                        //printf("PM2.5_A:\t%1.2f \tPM10_A:\t%1.2f,\n\r", PM2_5_A, PM10_A);
                        PM2_5_sum+=PM2_5_A;  // sum samples for future averaging
                        PM10_sum+=PM10_A;  // sum samples for future averaging
                        printf("%1.2f,\t%1.2f,\n\r", PM2_5_A, PM10_A); // CSV print:  PM2.5,  PM10
                    } 
                } // head2
            } // head1
        } // while readable()
    //break;
    } // while aux<10
    PM2_5_avg = PM2_5_sum/aux; // AVERAGE
    PM10_avg = PM10_sum/aux; // AVERAGE
    printf("AVERAGE PARTICLE (Samples = %d):\r\n%1.2f,\t%1.2f,\n\r", aux,PM2_5_avg, PM10_avg); // CSV print:  PM2.5,  PM10
    return PM2_5_avg;
}

float CO_sensor()
{
    int count = 0, t_init = 0, tim1;
    float v_sum=0, CO_ppm;
    uint16_t time_wait = 100; // Time in ms to wait between ADC reads
    //uint16_t time_avg = 10000;  // Time in ms for average
    printf("Time,\tV_in_ADC,\tV_in(V),\tCO(ppm),\n\r");
    while(count < samples_CO)//while(t.read_ms()-t_init <= time_avg_CO)
    {
        if (count == 0){           
            t_init = t.read_ms();
        }
        tim1 = t.read_ms();
        float v_in_norm = sensor2.read(); // read analog input and returns value between [0.0,1.0]
        //printf("\n\rsensor read:\t %f\t", v_in_norm);
        float v_in = v_in_norm * V_ref;
        //printf("analog voltage:\t %1.3fV \r\n", v_in);
        CO_ppm = (v_in-2)*(-400);
        if (v_in >= 2) {
            CO_ppm = 0;
        } 
        else {
            CO_ppm = (v_in-2)*(-400);
        }
        count++;
        v_sum+=v_in_norm;  // sum samples for future averaging
        printf("%d,\t%f,\t%1.3f,\t\t%3.2f,\r\n", tim1, v_in_norm,v_in,CO_ppm);
        uint16_t print_delay = t.read_ms()-tim1;  // to measure delay of printf call
        wait_ms(time_wait-print_delay);
    }
    float v_norm_avg = v_sum/count; // AVERAGE
    float v_avg = v_norm_avg * V_ref;
    //float CO_avg = (v_avg-2)*(-400);
    if (v_avg >= 2) {
        CO_avg = 0;
    } 
    else {
            CO_avg = (v_avg-2)*(-400);
    }
    printf("AVERAGE CO (Samples = %d):\r\n%d,\t%f,\t%1.3f,\t\t%3.2f,\r\n", count, tim1, v_norm_avg,v_avg,CO_avg);
    return CO_avg;
}


// NETWORK FUNCTIONS----------------------------------------------------------------
void printVersion()
{
    printf("%s\r\n\r\n", dot->getId().c_str());
}

bool setFrequencySubBand(uint8_t subBand)
{
    int32_t returnCode;
    printf("Setting frequency sub band to '%d'...\r\n", subBand);
    if ((returnCode = dot->setFrequencySubBand(subBand)) != mDot::MDOT_OK) {
        printError(dot, returnCode);
        return false;
    }
    return true;
}

bool setNetworkName(const std::string name)
{
    int32_t returnCode;
    //printf("Setting network name to '%s'...\r\n", name.c_str());
    printf("Setting network name ...\r\n");
    if ((returnCode = dot->setNetworkName(name)) != mDot::MDOT_OK)
    {
        printError(dot, returnCode);
        return false;
    }
    return true;
}

bool setNetworkPassphrase(const std::string passphrase)
{
    int32_t returnCode;
    //printf("Setting passphrase to '%s'...\r\n", passphrase.c_str());
    printf("Setting passphrase...\r\n");
    if ((returnCode = dot->setNetworkPassphrase(passphrase)) != mDot::MDOT_OK)
    {
        printError(dot, returnCode);
        return false;
    }
    return true;
}

bool setPower(uint8_t power)
{
    int32_t returnCode;
    printf("Setting tx power to '%d'...\r\n", power);
    if ((returnCode = dot->setTxPower(power)) != mDot::MDOT_OK) {
        printError(dot, returnCode);
        return false;
    }
    return true;
}


bool joinNetwork()
{
    int32_t returnCode;
    printf("\r\nJoining network...\r\n");
    if ((returnCode = dot->joinNetworkOnce()) != mDot::MDOT_OK) {
        printError(dot, returnCode);
        return false;
    }
    printf("Network Joined!\r\n");
    return true;
}

bool setAck(uint8_t retries)
{
    int32_t returnCode;
    printf("Setting ack to '%d'...\r\n", retries);
    if ((returnCode = dot->setAck(retries)) != mDot::MDOT_OK)
    {
        printError(dot, returnCode);
        return false;
    }
    return true;
}

bool send(const std::string text)
{
    int32_t returnCode;
    uint32_t timeTillSend = dot->getNextTxMs();
    if (timeTillSend != 0) {
        printf("waiting %lu ms to send\r\n", timeTillSend);
        return false;
    }

    printf("Sending data...  ");
    std::vector<uint8_t> data(text.begin(), text.end());
    if ((returnCode = dot->send(data, 1)) != mDot::MDOT_OK)
    {
        printError(dot, returnCode);
        return false;
    }
    printf("Data sent!\r\n");
    return true;
}

void printError(mDot* dot, int32_t returnCode)
{
    std::string error = mDot::getReturnCodeString(returnCode) + " - " + dot->getLastError();
    printf("%s\r\n", error.c_str());
}

void sleep(uint32_t time_sleep)
{
     
    // TO DO: add mDot sleep sequence here
    printf("Going to sleep...\n\r\n\r");
    wait(time_sleep); 
}