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-08-07
- Revision:
- 18:365e8aa4002c
- Parent:
- 17:5cabfc047b40
- Child:
- 19:a29b98ae0005
File content as of revision 18:365e8aa4002c:
#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; char readyIn; bool _measurementAlreadyRead; char count; float * values; // not float values [] !! :O }; Identification_struct _ident_struct; static int detect(SDI12 &sdi12, char indices[], int stop = -1, int start = -1) { char found = 0; for (size_t i = (start==-1?0:start); i < (stop==-1?ADDRRICES.size():stop+1); ++i) { string question = "?!"; question[0] = ADDRRICES[i]; sdi12.sendCommand(question); std::string response; Timer detectTimer; detectTimer.start(); while (detectTimer.read_ms() < RESPONSE_TIMEOUT * 4) { if (sdi12.RxInProgress()) detectTimer.reset(); if (sdi12.RxBufferAvailable()) { unsigned char bufferSize = sdi12.RxBufferAvailable(); char buffer[bufferSize]; sdi12.getRxBuffer(buffer); // if first char is valid address char if (ADDRRICES.find(buffer[0])) { indices[found++] = buffer[0]; debug("FOUND: %d -> %c\r\n", i, indices[found-1]); } } } osDelay(100); } return found; }; SDI12_device() { debug("DEFAULT\r\n"); } SDI12_device (SDI12 *inst, char address) : _sdi12(inst) { setAddress(address); if(getIdentification(_ident_struct)); }; SDI12_device & operator= (const SDI12_device & old) { _address = old._address; _ident_struct = old._ident_struct; // _sdi12 = old._sdi12; // non-copyable -.- _measurement = old._measurement; _valuesReadyCount = old._valuesReadyCount; _measurementReady = old._measurementReady; } ~SDI12_device () { delete [] _measurement.values; } // concurrent means that device under measurement won't signal its prempt readiness to the bus int measure(bool concurrent = true, char group = '0') { std::string question = string("?") + string(concurrent?"C":"M") + string("!"); question[0] = _address; if (group != '0') question.insert(2, 1, group); // e.g. 2M! -> 2M1! _sdi12->sendCommand(question); Timer timeout; timeout.start(); while (sdi12.RxBufferAvailable() == 0) { if (sdi12.RxInProgress()) timeout.reset(); if(timeout.read_ms() > RESPONSE_TIMEOUT) { 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.values = new float[measurementsCount]; _measurement.readyIn = waitFor; // _measurement.timestampMeasurementReadyAt debug("wait for %d measurement for %d seconds...", _measurement.count, waitFor); _valuesReadyCount = 0; _measurementReady = false; // debug("measurement scheduled"); // if (_measurement.values != NULL) delete[] _measurement.values; // _measurement.values = new float[measurementsCount]; return 0; } return -1; }; char readyIn() { return _measurement.readyIn; } bool isReady() { return _measurementReady; } bool read(char group = '0') { // Measurement (M), Continuous (R), and Concurrent (C) commands and subsequent Data (D) std::string question = std::string("?") + std::string("D") + std::string(1,group)+ std::string("!"); question[0] = _address; _sdi12->sendCommand(question); Timer timeout; timeout.start(); while (sdi12.RxBufferAvailable() == 0) { if (sdi12.RxInProgress()) timeout.reset(); if(timeout.read_ms() > RESPONSE_TIMEOUT) { return false; } } unsigned char bufferSize = sdi12.RxBufferAvailable(); char buffer[bufferSize+1]; sdi12.getRxBuffer(buffer); buffer[bufferSize] = '\0'; const std::string response(buffer); // debug("parser. recv: %s\r\n", response); if (response[0] == _address) { // parser here // const!!! response = response.substr(1); // to limit repeting this operation later. i.e. extract only values e.g. +21.3-123+123 // the only two possible delimeters of a value size_t next_start_index = response.find_first_of("-+", 0 + 1); // address offset! size_t next_end_index; // ready, steady, parse!! while(next_start_index != std::string::npos) { // determine start index: next_end_index = response.find_first_of("-+", next_start_index + 1); // std::substr is prepared to take std::npos float value = std::atof(response.substr(next_start_index, next_end_index).c_str()); // debug("parsed: %f\r\n", value); _measurement.values[_valuesReadyCount++] = value; next_start_index = response.find_first_of("-+", next_end_index); } // if current parsing doesn't return all the expexted measurements, then press harder and poll further Dx commands. RECURSION HERE *.* if (_valuesReadyCount < _measurement.count) read(group + 1); else { _measurementReady = true; } } return true; } // const unsigned char getMeasurementCount() { return _measurement.count; } const float getMeasurementValue(char which) { _measurementReady = false; // reading /any/ of the values resets this return _measurement.values[which]; } void setAddress(char address) { _address = address; }; // // private: static const int RESPONSE_TIMEOUT = 15+1; // device should start to respond within [ms] static const std::string ADDRRICES; // as in index -> indices, SDI12 *_sdi12; char _address; Measurement_struct _measurement; size_t _valuesReadyCount; bool _measurementReady; 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() > RESPONSE_TIMEOUT) { return false; } } unsigned char bufferSize = sdi12.RxBufferAvailable(); char buffer[bufferSize+1]; sdi12.getRxBuffer(buffer); buffer[bufferSize] = '\0'; const std::string response(buffer); if (response[0] == _address) { // e.g.: 113DECAGON GS3 402 ident.sdi_version = std::atoi(response.substr(1, 2).c_str()); const std::string tempStr = response.substr(3, 8); strcpy(ident.company, tempStr.c_str()); strcpy(ident.model, response.substr(3+8, 6).c_str()); strcpy(ident.version, response.substr(3+8+6, 3).c_str()); return true; } return false; } }; const std::string SDI12_device::ADDRRICES = "0123456789abcdefgijklmnoprstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";