mDot / Mbed OS Honneywell_Dust_Simple

Main.cpp

Committer:
jacobgqc
Date:
2017-12-01
Revision:
14:0e9566546fda
Parent:
13:e5f9b5ec30e1
Child:
16:6550040fbdf4

File content as of revision 14:0e9566546fda:

/* Run Honeywell Dust Sensor in continous Sampling Mode on a mDot or 
   Freedom K64 board
   Version 2.1
   Steve Mylroie Roitronic November 29 2017
   @C Copyright Global Quality Corp
*/

#include "mbed.h"
#include "stdlib.h"

#define VERSION  "2.1"

#define TRACE_MODE

//Turn on trace logging to the PC USB port
#ifdef TRACE_MODE
//Log level need to be set one level higher than the highest level to be output
#define LOG_LEVEL 2
#define DEBUG
#endif


const uint8_t* measureCommand = "68014057";
const uint8_t* stopCommand    = "68012077";

//Sensor command response codes
#define OK   0xA5A5
#define BAD  0x9696

//Auto Mode measurement response lenght
#define MESSAGE_LEN 32

//sensor measurement cycle in millseconds
#define MEASURE_DELAY 1500 

Serial pc(USBTX, USBRX, 115200);

//Use USB debug pott for the debug stream
#ifdef DEBUG
uint32_t debugLevel  = LOG_LEVEL;
#else
uint32_t debugLevel = 0;
#endif

void logInfo(char* text) {
     if ( debugLevel > 0 ) {
          pc.printf("\n%s\n", text );
     }
     return;
 }
 
void logTrace(uint8_t data) {
    if (debugLevel > 2 ){ 
        pc.putc( data );
    }
    return;
} 

//Board specfic serial port pin definitions

#ifdef TARGET_Freescale  //Freedom Board

#define SENSOR_XMT D1
#define SENSOR_RCV D0

#endif

#ifdef TARGET_MTS_MDOT_F411RE  //Multi Tech mDot

#define SENSOR_XMT PA_2
#define SENSOR_RCV PA_3

#endif

#define RESPONSE_MSG_LEN 2
#define AUTO_MSG_LEN 8

//Time required to receive one character at 9600 baud
#define CHAR_TIME 1000/9600 & 10

enum MSG_TYPE{  UNKNOWN,
                ACK_MSG,
                NAK_MSG,
                AUTO_MSG,
                READ_ERROR } msgType;


uint8_t dataBuffer[AUTO_MSG_LEN];
uint8_t* bufferPtr;
uint32_t msgLen;

       
//Use a boards second UART   to communicate witb the Honneywell sensor
//Default UART setting are 8,N,1
RawSerial sensor( SENSOR_XMT, SENSOR_RCV, 9600);

//Serial Received chararter interupt handler

void receiveInterrupt() {
    uint8_t data;
    if(sensor.readable()) {
        data = sensor.getc();
        if(msgType == UNKNOWN) {  //Start of a new message
            bufferPtr = dataBuffer;
            switch(data) {
                case 0x42:
                    msgType = AUTO_MSG;
                    msgLen = AUTO_MSG_LEN;
                    break;
                case 0xA5:
                    msgType = ACK_MSG;
                    msgLen = RESPONSE_MSG_LEN;
                    break;
                case 0x69:
                    msgType = NAK_MSG;
                    msgLen = RESPONSE_MSG_LEN;
                    break;
            }
        }
        if(msgLen--  > 0 ) {  //Insert Character into type ahead buffer
            *bufferPtr++ = data;
        }
    }
    return;    
}

//Read last message received from type ahead message buffer
//Mbed 5 Serial class only supports single character read and writes or
// async buffer reads and wrutes
MSG_TYPE readBuffer(uint8_t* buffer, uint16_t count)
{
    if(buffer == NULL || count > AUTO_MSG_LEN ) { //Calling without buffer or
        return READ_ERROR;                    //asking for too many chars
    }                                         //is an error
    int counter = 0;
    uint8_t* inPointer;
    uint8_t* outPointer;
    int delay;
    logInfo( "Reading last message from sensor\n");
    while(msgType == UNKNOWN ) { //No message received since last read
        Thread::wait(CHAR_TIME); //Wait for new message
        counter++;
        if(counter > 40) { //Timeout exit after 40 character 40 Charcter times
            break;
        }
    }
    counter = 0;    
    while(msgLen > 0 ) { //Wait for complete message to arrive
        delay = CHAR_TIME * msgLen;
        Thread::wait(delay);
        counter++;
        if(counter > 40) { //Time out exit after 40 character times
            pc.printf("msgLen: %d", msgLen);
            break;
        }
    }
    if(counter > 40 ) { //Report timeout error
       msgType = UNKNOWN;
       return READ_ERROR;
     }
    else {
        //Copy the message to the requesters buffer 
        inPointer = &dataBuffer[1];
        outPointer = buffer;
        for(int i = 0; i < count; i++) {
            *outPointer++ = *inPointer++;
        }
    }
    MSG_TYPE temp = msgType;
    //Start Search for the next message
    msgType = UNKNOWN;     
    return temp;
}
    
            
void writeBuffer(const uint8_t* buffer, uint16_t count)
{
    logInfo( "Sending Command to sensor\n");
    uint8_t* pointer = (uint8_t*)buffer;
    uint16_t counter = count;
    while(1)
    {
        if(sensor.writeable())
        {
            logTrace(*pointer);
            sensor.putc(*pointer++);
            counter--;
        }
        if(counter == 0) {
            return;
        }
    }
} 

//Validate the received mesurements checksum

bool checkValue(uint8_t *thebuf, uint8_t leng)
{  
    bool receiveflag = false;
    uint16_t receiveSum = 0;
    
    //Don't include the checksum bytes in the sum
    for(int i=0; i<(leng-3); i++){
    r   eceiveSum=receiveSum+thebuf[i];
    }
    receiveSum=receiveSum + 0x42;
    
    if(receiveSum == ((thebuf[leng-2]<<8)+thebuf[leng-1]))  //check the debug data 
    {
        receiveSum = 0;
        receiveflag = true;
    }
    return receiveflag;
}

//Extract the 1 micron particle count from the messaage
uint16_t transmitPM01(uint8_t *thebuf)
{
    uint16_t PM01Val;
    PM01Val=((thebuf[3]<<8) + thebuf[4]); //count PM1.0 value of the air detector module
    return PM01Val;
}

//Extract the 2.5 micron particle count from the messaage
uint16_t transmitPM2_5(uint8_t *thebuf)
{
    uint16_t PM2_5Val;
    PM2_5Val=((thebuf[5]<<8) + thebuf[6]);//count PM2.5 value of the air detector module
    return PM2_5Val;
}

//Extract the 10 micron particle count from the messaage
uint16_t transmitPM10(uint8_t *thebuf)
{
    uint16_t PM10Val;
    PM10Val=((thebuf[7]<<8) + thebuf[8]); //count PM10 value of the air detector module  
    return PM10Val;
}

int main()
{
    uint8_t dataBuffer[MESSAGE_LEN];
    MSG_TYPE mType;
    uint16_t PM01Value=0;     //define PM1.0 value of the air detector module
    uint16_t PM2_5Value=0;        //define PM2.5 value of the air detector module
    uint16_t PM10Value=0;         //define PM10 value of the air detector module
    
    pc.printf("Starting Honeywell Dust Sesor App version %\n", VERSION);
    //Attach a receive interrupt handler
    sensor.attach(receiveInterrupt, Serial::RxIrq);
    msgType = UNKNOWN;
    //Send start command to the sensor
    writeBuffer(measureCommand, 4);
 /*
 Not geting response from sensor - first characters received are measurement data   
    //Wait for sensors response
    //while(!sensor.readable());
    readBuffer(dataBuffer, 2);
    response = dataBuffer[0] << 8 || dataBuffer[1];

    switch(response) {
        case OK:
        logInfo("Sensor Auto Measurement Started");
        break;
        case BAD:
        logInfo("Sensor rejected Start Measurement Commmand");
        return -1;
        default:
        logInfo("Communication Error: Invalid Sensor Response");
        return -2;
    }
*/    

    //Start continous loop 
    while(1) {
        if((mType = readBuffer(dataBuffer, MESSAGE_LEN -1)) == AUTO_MSG) {
            if(dataBuffer[0] == 0x4d){
                if(checkValue(dataBuffer, MESSAGE_LEN-1)){
                    PM01Value = transmitPM01(dataBuffer); //count PM1.0 value of the air detector module
                    PM2_5Value = transmitPM2_5(dataBuffer);//count PM2.5 value of the air detector module
                    PM10Value = transmitPM10(dataBuffer); //count PM10 value of the air detector module 
                }
                else {
                    pc.puts("Message checksum error\n");
                }
            }
            else {
                pc.printf("Second Character was %x\n", dataBuffer[0]);
            }
             //Check for exit request
            if(pc.readable()) { // Returning false here
                char input = pc.getc();
                if(input == 'Q' || input == 'q')
                { 
                    //Shutdown the sensor
                    writeBuffer(stopCommand, 4);
                    //Unlink the receive interrupt handler
                    sensor.attach(0, Serial::RxIrq);
                    pc.puts("Exit request received\n");
                    return 0;
                }
            }
            // Use MBed wait function instead of Arduino delay loop
            wait_ms(1000);          
                  
            pc.printf("PM1.0: %d ug/m3\n", PM01Value);  
                
            pc.printf("PM2.5: %d ug/m3\n", PM2_5Value);  
                  
            pc.printf("PM10: %d ug/m3\n", PM10Value);  
        
            pc.printf("\n");
        }
        else {
            switch(mType) {
                case ACK_MSG:
                    if(dataBuffer[0] == 0xA5) {
                        pc.puts("Recived ACK response'\n");
                    }
                    else {
                        pc.puts("Received corrupt ACK Response\n");
                    }
                    break;
                case NAK_MSG:
                    if(dataBuffer[0] == 0x69) {
                        pc.puts("Recived NAK response'\n");
                    }
                    else {
                        pc.puts("Received corrupt NAK Response\n");
                    }
                    break;
                case READ_ERROR:
//                    pc.printf("%s", dataBuffer);
                    pc.printf("%d", msgLen);
                    pc.printf("\nMESSAGE_LEN: %d    ", MESSAGE_LEN);
                    pc.puts("Data Reading Error\n");
                    break;
                }
            }
        }
    }