Library to manage Inovafitness SDS021 particles sensor

Dependents:   LoRaWAN-demo-72-bootcamp SDS021Test

Sds021.cpp

Committer:
abouillot
Date:
2017-01-28
Revision:
1:fb3d61ffd503
Parent:
0:0c1a6a29b8c4
Child:
2:49822e10d111

File content as of revision 1:fb3d61ffd503:

/*!
 * Sds021.cpp
 *
 * Control the inovafitness particles sensor SDS021
 *
 * Copyright (c) 2017 -  Alexandre Bouillot github.com/abouillot
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documnetation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to  whom the Software is
 * furished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
 
 #include "Sds021.h"

char* SDS021::prepareMessage(SDS021::action_t action, bool set, int address, int value)
{
    // reset command content
    memset(outMessage, 0, kOutputLength);

    // Sets common message values
    outMessage[0] = head;
    outMessage[1] = commandCmd;
    outMessage[2] = action;
    outMessage[3] = set;
    outMessage[4] = value;
    outMessage[15] = address >> 8;
    outMessage[16] = address & 0xFF;
    outMessage[kOutputLength - 1] = tail;

    return outMessage;
}

char SDS021::calcCheckSum(char* buffer, int start_idx, int stop_idx)
{
    int chk = 0;
    for (int i = start_idx; i < stop_idx; i++)
        chk += buffer[i];
    chk &= 0xFF;
    return (char)chk;
}

bool SDS021::checkSum(char* buffer, int start_idx, int stop_idx)
{
    return calcCheckSum(buffer, start_idx, stop_idx) == buffer[stop_idx];
}

void SDS021::writeMessage(char* buffer)
{
    // Calculates and stores checksum in output buffer
    outMessage[17] = calcCheckSum(outMessage, 2, 17);
    _sds021.write(outMessage, kOutputLength);

    // Waits for software serial to finish sending message
//    delay(20); // (19 bytes * 8 bits * 0.104 ms = 15.808 ms minimum)
//    delete[] buffer;

    while (!update());

}

bool SDS021::update()
{
    bool updated = false;

    // Check Serial input buffer for a message
    while (_sds021.readable()) {
        int bufPos = 0;

        // Clear the local buffer
        memset(inMessage, 0, kInputLength);

        do {
            while(!_sds021.readable()) ;
            inMessage[bufPos] = _sds021.getc();
        } while (inMessage[bufPos] != head);


        while (++bufPos < kInputLength) {
            while(!_sds021.readable()) ;
            inMessage[bufPos] = _sds021.getc();
        }

        for (int i=0; i<kInputLength; i++) {
            printf("%02x_", inMessage[i]);
        }
        printf("\n");
        
        // Update local values if message is valid
        if (checkSum(inMessage)) {
            char command_id = inMessage[1];

            // Parse data frame
            if (command_id == dataCmd) {
                _PM2_5 = (float)((inMessage[3] << 8) + inMessage[2]) / 10.0;
                _PM10 = (float)((inMessage[5] << 8) + inMessage[4]) / 10.0;
            }

            // Parse reply frame
            else if (command_id == replyCmd) {
                char action = inMessage[2];

                if (action == modeAct)
                    _mode = inMessage[4];
                else if (action == stateAct)
                    _state = inMessage[4];
                else if (action == intervalAct)
                    _interval = inMessage[4];
                else if (action == versionAct) {
                    _firmware.year = inMessage[3];
                    _firmware.month = inMessage[4];
                    _firmware.day = inMessage[5];
                }
            }

            // Update device ID
            _id = (inMessage[6] << 8) + inMessage[7];

            updated = true;
        } else
            printf("checksum error %02x %02x\n", calcCheckSum(inMessage, 2, 8), inMessage[8]);
    }

    return updated;
}

void SDS021::setId(int new_id)
{
    // Compiles the message
    prepareMessage(idAct, true, _id);
    outMessage[13] = new_id >> 8;
    outMessage[14] = new_id & 0xFF;

    for (int i=0; i<kOutputLength; i++)
        printf("%02x.", outMessage[i]);
    printf("\n");
    writeMessage(outMessage);
}

void SDS021::setPassiveMode(bool passive)
{
    // Compiles the message
    prepareMessage(modeAct, true, _id, passive);
    writeMessage(outMessage);
}

void SDS021::readData()
{
    prepareMessage(queryAct, false, _id);
    writeMessage(outMessage);
}


void SDS021::setInterval(uint8_t minutes)
{
    // Clamps minutes between 0-30
    if (minutes > 30)
        minutes = 30;

    // Compiles the message
    prepareMessage(intervalAct, true, _id, minutes);
    writeMessage(outMessage);
}

void SDS021::setAwake(bool working)
{
    // Compiles the message
    prepareMessage(stateAct, true, _id, working);
    writeMessage(outMessage);
}

SDS021::version_t SDS021::getVersion()
{
    // Compiles the message
    prepareMessage(versionAct, true, _id);
    writeMessage(outMessage);

    return _firmware;
}