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-09
- Revision:
- 23:59447d795751
- Parent:
- 22:c6e99d486304
File content as of revision 23:59447d795751:
#include "SDI12.h" #include <string> #include "mbed.h" extern void printStackStats(char num); class SDI12_device { public: struct Identification_struct { unsigned char sdi_version; char company[8+1]; char model[6+1]; char version[3+1]; }; Identification_struct _ident_struct; struct Measurement_struct { unsigned long timestampMeasurementReadyAt; char readyIn; bool _measurementAlreadyRead; char count; // float * values; // not float values [] !! :O float values[20]; // !! :O }; const 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) { const std::string question = std::string(1, ADDRRICES[i]) + "!"; sdi12.sendCommand(question); 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): %d -> %c\r\n", found, i, indices[found-1]); } } } osDelay(100); } return found; }; SDI12_device() { debug("default in %s\r\n", __FILE__); } SDI12_device (SDI12 *inst, char address) : _sdi12(inst) { setAddress(address); if(getIdentification(_ident_struct)); }; SDI12_device (const SDI12_device &old) { debug("copy in %s\r\n", __FILE__); _address = old._address; _ident_struct = old._ident_struct; _sdi12 = old._sdi12; _measurement = old._measurement; _measurementReady = false; _valuesReadyCount = old._valuesReadyCount; _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?! } SDI12_device & operator= (const SDI12_device & old) { debug("assign in %s\r\n", __FILE__); _address = old._address; _ident_struct = old._ident_struct; _sdi12 = old._sdi12; _measurement = old._measurement; _measurementReady = false; _valuesReadyCount = old._valuesReadyCount; _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?! return *this; } ~SDI12_device () { debug("destructor in %s\r\n", __FILE__); } bool present() { const std::string question = std::string(1, _address) + std::string("!"); _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]; sdi12.getRxBuffer(buffer); // only to flush the buffer return true; } // concurrent means that device under measurement won't signal its prempt readiness to the bus int measure(bool concurrent = true, char group = '0') { const std::string question = std::string(1, _address) + std::string(concurrent?"C": (group=='0'?"M":("M"+std::string(1,group)))) + std::string("!"); // if (group != '0') // ABOVE DOES THIS // 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 -2; } } 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.readyIn = waitFor; // _measurement.timestampMeasurementReadyAt debug("wait for %d measurement for %d seconds...", _measurement.count, waitFor); _valuesReadyCount = 0; _measurementReady = false; return 0; } return -1; }; char readyIn() { return _measurement.readyIn; } bool isReady() { return _measurementReady; } bool read(char group = '0') { char group_a[] = {group}; printStackStats(std::atoi(group_a)); // Measurement (M), Continuous (R), and Concurrent (C) commands and subsequent Data (D) const std::string question = std::string(1, _address) + std::string("D") + std::string(1, group)+ std::string("!"); _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 && response.size() > 1) { // debug("__%s__\r\n", response); // 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) { debug("values count: %d\r\n", _valuesReadyCount); 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!"); const std::string question = std::string(1, _address) + "I!"; _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";