Represents a single device. Take measurements, send commands. Needs SDI12 bus instance as argument. Allows to detect devices on the bus

SDI12_device.h

Committer:
amateusz
Date:
2018-07-27
Revision:
2:e2db05bc4708
Parent:
1:6b1a21925a81
Child:
3:2847f7c543d3

File content as of revision 2:e2db05bc4708:

#include "SDI12.h"
#include <string>
#include "mbed.h"

class SDI12_device
{
public:
    struct Identification_struct {
        unsigned char sdi_version;
        char company[8+1];
        char model[6+1];
        char version[3+1];
    };

    struct Measurement_struct {
        unsigned long timestampMeasurementReadyAt;
        bool _measurementAlreadyRead;
        char count;
        float values[];
    };

    Identification_struct _ident_struct;

    static int detect(SDI12 &sdi12, char indices[]) {
        char found = 0;
        for (char i = '1'; i < '9'; ++i) {
            string question = "?!";
            question[0] = i;
            sdi12.sendCommand(question);
            std::string response;

            Timer detectTimer;
            detectTimer.start();
            while (sdi12.RxBufferAvailable() == 0)
                if(detectTimer.read_ms() > 800) {
                    ++i;
                    break;
                }
            unsigned char bufferSize = sdi12.RxBufferAvailable();
            char buffer[bufferSize];

            sdi12.getRxBuffer(buffer);
            // if first char is valid address char
            if (buffer[0] >= '0' && buffer[0] <= '9' ||
                    buffer[0] >= 'a' && buffer[0] <= 'z' ||
                    buffer[0] >= 'A' && buffer[0] <= 'Z') {
                indices[found++] = buffer[0];
            }
        }
        return found;
    };

    SDI12_device (SDI12 &inst, char address, EventQueue &mainDispatcher) : _sdi12(inst) {
        setAddress(address);
        sensorQueue.chain(&mainDispatcher);
        if(getIdentification(_ident_struct));
    };

//        void printIdentification(){
//                Serial.println(_ident_struct.company);
//                Serial.println(_ident_struct.model);
//                Serial.println(_ident_struct.version);
//        }
//

//        // returns after how many seconds a measurement will be ready
    int measure(bool concurrent = true) {
        std::string question = string("?") + string(concurrent?"C":"M") + string("!");
        question[0] = _address;
        _sdi12.sendCommand(question);

        Timer timeout;
        timeout.start();
        while (sdi12.RxBufferAvailable() == 0) {
            if (sdi12.RxInProgress()) timeout.reset();
            if(timeout.read_ms() > 100) {
                return false;
            }
        }
        unsigned char bufferSize = sdi12.RxBufferAvailable();
        char buffer[bufferSize+1];
        sdi12.getRxBuffer(buffer);
        buffer[bufferSize] = '\0';
        std::string response(buffer);

        if (response[0] == _address) {
            char measurementsCount = std::atoi(response.substr(1+3,(concurrent?2:1)).c_str());
            char waitFor = std::atoi(response.substr(1,3).c_str());
            _measurement.count = measurementsCount;
//            _measurement.timestampMeasurementReadyAt
            debug("wait for %d measurement for %d seconds...", _measurement.count, waitFor);
            sensorQueue.call_in(waitFor * 1000, callback(this, &SDI12_device::read));
            if (_measurement.values == NULL) delete[] _measurement.values;
            return 0;
        }
        return -1;
    };
//
//        bool isMeasurementReady(){
//            return (((unsigned)(_measurement.timestampMeasurementReadyAt - millis())>0)?false:true);
//        };
//
//        short unsigned int measurementReadyIn(){ // ms
//            if (isMeasurementReady())
//                return 0;
//            else{
//                return _measurement.timestampMeasurementReadyAt - millis();
//            }
//        };
//
    bool read() {
        char alreadyRead = 0;

        std::string question = string("?") + string("D0") + string("!");
        question[0] = _address;
        _sdi12.sendCommand(question);

        Timer timeout;
        timeout.start();
        while (sdi12.RxBufferAvailable() == 0) {
            if (sdi12.RxInProgress()) timeout.reset();
            if(timeout.read_ms() > 100) {
                return false;
            }
        }
        unsigned char bufferSize = sdi12.RxBufferAvailable();
        char buffer[bufferSize+1];
        sdi12.getRxBuffer(buffer);
        buffer[bufferSize] = '\0';
        std::string response(buffer);

        debug("parser");
        // if (response[0] == _address) {
//            debug("parser");
//            // parser here
//            response = response.substr(1); // to limit repeting this operation later
//            // the only two possible delimeters of a value
//            uint8_t start_index = 0;
//
//            int8_t index_pos = response.indexOf('+', start_index);
//            int8_t index_neg = response.indexOf('-', start_index);
//
//            Serial.println(index_pos);
//            Serial.println(index_pos);
//
//            do {
//                // determine start index:
//                if (index_pos != -1 && index_neg != -1) start_index = min(index_pos,index_neg);
//                else if (index_pos == -1) start_index = index_neg;
//                else if (index_neg == -1) start_index = index_pos;
//
//                int8_t index_pos_next = response.indexOf('+', start_index +1);
//                int8_t index_neg_next = response.indexOf('-', start_index +1);
//
//                uint8_t end_index;
//                if (index_pos_next != -1 && index_neg_next != -1)   end_index = min(index_pos_next,index_neg_next);
//                else if (index_pos_next == -1) end_index = index_neg_next;
//                else if (index_neg_next == -1) end_index = index_pos_next;
//
//                _measurement.values[alreadyRead++] = response.substr(start_index, end_index).toFloat();
//
//                index_pos = response.indexOf('+', start_index);
//                index_neg = response.indexOf('-', start_index);
//            } while(index_pos != -1 || index_neg != -1);
//        }
    }
//
    unsigned char getMeasurementCount() {
        return _measurement.count;
    }

    float getMeasurementValue(char which) {
        return _measurement.values[which];
    }

    void setAddress(char address) {
        _address = address;
    };
//
//
private:
    SDI12 &_sdi12;
    char _address;
    Measurement_struct _measurement;

    EventQueue sensorQueue;

    bool getIdentification(Identification_struct &ident) {
//        _sdi12.sendCommand(std::string(_address) + "I!");
        std::string question = "?I!";
        question[0] = _address;
        _sdi12.sendCommand(question);

        Timer timeout;
        timeout.start();
        while (sdi12.RxBufferAvailable() == 0) {
            if (sdi12.RxInProgress()) timeout.reset();
            if(timeout.read_ms() > 20) {
                return false;
            }
        }
        unsigned char bufferSize = sdi12.RxBufferAvailable();
        char buffer[bufferSize+1];
        sdi12.getRxBuffer(buffer);
        buffer[bufferSize] = '\0';
        std::string response(buffer);

        if (response[0] == _address) {
            // e.g.: 113DECAGON GS3   402

            ident.sdi_version = std::atoi(response.substr(1, 2).c_str());
            debug("|%d| /%s/\r\n",ident.sdi_version ,response.substr(1, 2).c_str());

            std::string tempStr = response.substr(3, 8);
            strcpy(ident.company, tempStr.c_str());

            tempStr = response.substr(3+8, 6);
            strcpy(ident.model, tempStr.c_str());

            tempStr = response.substr(3+8+6, 3);
            strcpy(ident.version, tempStr.c_str());
            return true;
        }
        return false;
    }

};