Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
SDI12_device.h
- Committer:
- amateusz
- Date:
- 2018-08-08
- Revision:
- 21:aa7b255c5896
- Parent:
- 20:abccaaa16955
- Child:
- 22:c6e99d486304
File content as of revision 21:aa7b255c5896:
#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;
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\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;
return *this;
}
~SDI12_device () {
// delete [] _measurement.values;
}
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.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)
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) {
// 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!");
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";