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

Committer:
amateusz
Date:
Thu Aug 09 10:44:42 2018 +0000
Revision:
23:59447d795751
Parent:
22:c6e99d486304
idk

Who changed what in which revision?

UserRevisionLine numberNew contents of line
amateusz 0:d58ebb2bed9a 1 #include "SDI12.h"
amateusz 0:d58ebb2bed9a 2 #include <string>
amateusz 2:e2db05bc4708 3 #include "mbed.h"
amateusz 22:c6e99d486304 4 extern void printStackStats(char num);
amateusz 0:d58ebb2bed9a 5
amateusz 0:d58ebb2bed9a 6 class SDI12_device
amateusz 0:d58ebb2bed9a 7 {
amateusz 0:d58ebb2bed9a 8 public:
amateusz 0:d58ebb2bed9a 9 struct Identification_struct {
amateusz 0:d58ebb2bed9a 10 unsigned char sdi_version;
amateusz 0:d58ebb2bed9a 11 char company[8+1];
amateusz 0:d58ebb2bed9a 12 char model[6+1];
amateusz 0:d58ebb2bed9a 13 char version[3+1];
amateusz 0:d58ebb2bed9a 14 };
amateusz 0:d58ebb2bed9a 15
amateusz 22:c6e99d486304 16 Identification_struct _ident_struct;
amateusz 22:c6e99d486304 17
amateusz 0:d58ebb2bed9a 18 struct Measurement_struct {
amateusz 0:d58ebb2bed9a 19 unsigned long timestampMeasurementReadyAt;
amateusz 4:11438803516c 20 char readyIn;
amateusz 0:d58ebb2bed9a 21 bool _measurementAlreadyRead;
amateusz 0:d58ebb2bed9a 22 char count;
amateusz 22:c6e99d486304 23 // float * values; // not float values [] !! :O
amateusz 22:c6e99d486304 24 float values[20]; // !! :O
amateusz 0:d58ebb2bed9a 25 };
amateusz 0:d58ebb2bed9a 26
amateusz 19:a29b98ae0005 27 const static int detect(SDI12 &sdi12, char indices[], int stop = -1, int start = -1) {
amateusz 0:d58ebb2bed9a 28 char found = 0;
amateusz 10:efd1e313fe8c 29 for (size_t i = (start==-1?0:start); i < (stop==-1?ADDRRICES.size():stop+1); ++i) {
amateusz 21:aa7b255c5896 30 const std::string question = std::string(1, ADDRRICES[i]) + "!";
amateusz 0:d58ebb2bed9a 31 sdi12.sendCommand(question);
amateusz 0:d58ebb2bed9a 32 Timer detectTimer;
amateusz 0:d58ebb2bed9a 33 detectTimer.start();
amateusz 15:530bf2e09814 34 while (detectTimer.read_ms() < RESPONSE_TIMEOUT * 4) {
amateusz 5:e53104570fde 35 if (sdi12.RxInProgress()) detectTimer.reset();
amateusz 7:1f506c65c4e8 36 if (sdi12.RxBufferAvailable()) {
amateusz 7:1f506c65c4e8 37 unsigned char bufferSize = sdi12.RxBufferAvailable();
amateusz 7:1f506c65c4e8 38 char buffer[bufferSize];
amateusz 7:1f506c65c4e8 39 sdi12.getRxBuffer(buffer);
amateusz 7:1f506c65c4e8 40 // if first char is valid address char
amateusz 7:1f506c65c4e8 41 if (ADDRRICES.find(buffer[0])) {
amateusz 7:1f506c65c4e8 42 indices[found++] = buffer[0];
amateusz 19:a29b98ae0005 43 debug("FOUND (%d): %d -> %c\r\n", found, i, indices[found-1]);
amateusz 7:1f506c65c4e8 44 }
amateusz 7:1f506c65c4e8 45 }
amateusz 0:d58ebb2bed9a 46 }
amateusz 13:0093792f2325 47 osDelay(100);
amateusz 0:d58ebb2bed9a 48 }
amateusz 0:d58ebb2bed9a 49 return found;
amateusz 0:d58ebb2bed9a 50 };
amateusz 17:5cabfc047b40 51
amateusz 17:5cabfc047b40 52 SDI12_device() {
amateusz 22:c6e99d486304 53 debug("default in %s\r\n", __FILE__);
amateusz 17:5cabfc047b40 54 }
amateusz 17:5cabfc047b40 55
amateusz 18:365e8aa4002c 56 SDI12_device (SDI12 *inst, char address) : _sdi12(inst) {
amateusz 15:530bf2e09814 57 setAddress(address);
amateusz 1:6b1a21925a81 58 if(getIdentification(_ident_struct));
amateusz 0:d58ebb2bed9a 59 };
amateusz 15:530bf2e09814 60
amateusz 22:c6e99d486304 61 SDI12_device (const SDI12_device &old) {
amateusz 22:c6e99d486304 62 debug("copy in %s\r\n", __FILE__);
amateusz 15:530bf2e09814 63 _address = old._address;
amateusz 15:530bf2e09814 64 _ident_struct = old._ident_struct;
amateusz 22:c6e99d486304 65 _sdi12 = old._sdi12;
amateusz 15:530bf2e09814 66 _measurement = old._measurement;
amateusz 22:c6e99d486304 67 _measurementReady = false;
amateusz 15:530bf2e09814 68 _valuesReadyCount = old._valuesReadyCount;
amateusz 22:c6e99d486304 69 _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?!
amateusz 22:c6e99d486304 70 }
amateusz 22:c6e99d486304 71
amateusz 22:c6e99d486304 72 SDI12_device & operator= (const SDI12_device & old) {
amateusz 22:c6e99d486304 73 debug("assign in %s\r\n", __FILE__);
amateusz 22:c6e99d486304 74 _address = old._address;
amateusz 22:c6e99d486304 75 _ident_struct = old._ident_struct;
amateusz 22:c6e99d486304 76 _sdi12 = old._sdi12;
amateusz 22:c6e99d486304 77 _measurement = old._measurement;
amateusz 22:c6e99d486304 78 _measurementReady = false;
amateusz 22:c6e99d486304 79 _valuesReadyCount = old._valuesReadyCount;
amateusz 22:c6e99d486304 80 _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?!
amateusz 22:c6e99d486304 81
amateusz 19:a29b98ae0005 82 return *this;
amateusz 15:530bf2e09814 83 }
amateusz 15:530bf2e09814 84
amateusz 10:efd1e313fe8c 85 ~SDI12_device () {
amateusz 22:c6e99d486304 86 debug("destructor in %s\r\n", __FILE__);
amateusz 10:efd1e313fe8c 87 }
amateusz 22:c6e99d486304 88
amateusz 19:a29b98ae0005 89 bool present() {
amateusz 21:aa7b255c5896 90 const std::string question = std::string(1, _address) + std::string("!");
amateusz 19:a29b98ae0005 91 _sdi12->sendCommand(question);
amateusz 19:a29b98ae0005 92
amateusz 19:a29b98ae0005 93 Timer timeout;
amateusz 19:a29b98ae0005 94 timeout.start();
amateusz 19:a29b98ae0005 95 while (sdi12.RxBufferAvailable() == 0) {
amateusz 19:a29b98ae0005 96 if (sdi12.RxInProgress()) timeout.reset();
amateusz 19:a29b98ae0005 97 if(timeout.read_ms() > RESPONSE_TIMEOUT) {
amateusz 19:a29b98ae0005 98 return false;
amateusz 19:a29b98ae0005 99 }
amateusz 19:a29b98ae0005 100 }
amateusz 19:a29b98ae0005 101 unsigned char bufferSize = sdi12.RxBufferAvailable();
amateusz 19:a29b98ae0005 102 char buffer[bufferSize];
amateusz 19:a29b98ae0005 103 sdi12.getRxBuffer(buffer); // only to flush the buffer
amateusz 19:a29b98ae0005 104 return true;
amateusz 19:a29b98ae0005 105 }
amateusz 15:530bf2e09814 106 // concurrent means that device under measurement won't signal its prempt readiness to the bus
amateusz 13:0093792f2325 107 int measure(bool concurrent = true, char group = '0') {
amateusz 4:11438803516c 108
amateusz 21:aa7b255c5896 109 const std::string question = std::string(1, _address) + std::string(concurrent?"C": (group=='0'?"M":("M"+std::string(1,group)))) + std::string("!");
amateusz 21:aa7b255c5896 110 // if (group != '0') // ABOVE DOES THIS
amateusz 20:abccaaa16955 111 // question.insert(2, 1, group); // e.g. 2M! -> 2M1!
amateusz 15:530bf2e09814 112 _sdi12->sendCommand(question);
amateusz 2:e2db05bc4708 113
amateusz 2:e2db05bc4708 114 Timer timeout;
amateusz 2:e2db05bc4708 115 timeout.start();
amateusz 2:e2db05bc4708 116 while (sdi12.RxBufferAvailable() == 0) {
amateusz 2:e2db05bc4708 117 if (sdi12.RxInProgress()) timeout.reset();
amateusz 5:e53104570fde 118 if(timeout.read_ms() > RESPONSE_TIMEOUT) {
amateusz 19:a29b98ae0005 119 return -2;
amateusz 2:e2db05bc4708 120 }
amateusz 2:e2db05bc4708 121 }
amateusz 10:efd1e313fe8c 122
amateusz 2:e2db05bc4708 123 unsigned char bufferSize = sdi12.RxBufferAvailable();
amateusz 2:e2db05bc4708 124 char buffer[bufferSize+1];
amateusz 2:e2db05bc4708 125 sdi12.getRxBuffer(buffer);
amateusz 2:e2db05bc4708 126 buffer[bufferSize] = '\0';
amateusz 2:e2db05bc4708 127 std::string response(buffer);
amateusz 2:e2db05bc4708 128
amateusz 2:e2db05bc4708 129 if (response[0] == _address) {
amateusz 2:e2db05bc4708 130 char measurementsCount = std::atoi(response.substr(1+3,(concurrent?2:1)).c_str());
amateusz 2:e2db05bc4708 131 char waitFor = std::atoi(response.substr(1,3).c_str());
amateusz 2:e2db05bc4708 132 _measurement.count = measurementsCount;
amateusz 22:c6e99d486304 133
amateusz 4:11438803516c 134 _measurement.readyIn = waitFor;
amateusz 2:e2db05bc4708 135 // _measurement.timestampMeasurementReadyAt
amateusz 2:e2db05bc4708 136 debug("wait for %d measurement for %d seconds...", _measurement.count, waitFor);
amateusz 11:e0ccc1072c42 137 _valuesReadyCount = 0;
amateusz 13:0093792f2325 138 _measurementReady = false;
amateusz 2:e2db05bc4708 139 return 0;
amateusz 2:e2db05bc4708 140 }
amateusz 2:e2db05bc4708 141 return -1;
amateusz 2:e2db05bc4708 142 };
amateusz 13:0093792f2325 143
amateusz 4:11438803516c 144 char readyIn() {
amateusz 4:11438803516c 145 return _measurement.readyIn;
amateusz 4:11438803516c 146 }
amateusz 4:11438803516c 147
amateusz 13:0093792f2325 148 bool isReady() {
amateusz 13:0093792f2325 149 return _measurementReady;
amateusz 13:0093792f2325 150 }
amateusz 13:0093792f2325 151
amateusz 11:e0ccc1072c42 152 bool read(char group = '0') {
amateusz 22:c6e99d486304 153 char group_a[] = {group};
amateusz 22:c6e99d486304 154 printStackStats(std::atoi(group_a));
amateusz 11:e0ccc1072c42 155 // Measurement (M), Continuous (R), and Concurrent (C) commands and subsequent Data (D)
amateusz 21:aa7b255c5896 156 const std::string question = std::string(1, _address) + std::string("D") + std::string(1, group)+ std::string("!");
amateusz 15:530bf2e09814 157 _sdi12->sendCommand(question);
amateusz 2:e2db05bc4708 158
amateusz 2:e2db05bc4708 159 Timer timeout;
amateusz 2:e2db05bc4708 160 timeout.start();
amateusz 2:e2db05bc4708 161 while (sdi12.RxBufferAvailable() == 0) {
amateusz 2:e2db05bc4708 162 if (sdi12.RxInProgress()) timeout.reset();
amateusz 5:e53104570fde 163 if(timeout.read_ms() > RESPONSE_TIMEOUT) {
amateusz 2:e2db05bc4708 164 return false;
amateusz 2:e2db05bc4708 165 }
amateusz 2:e2db05bc4708 166 }
amateusz 2:e2db05bc4708 167 unsigned char bufferSize = sdi12.RxBufferAvailable();
amateusz 2:e2db05bc4708 168 char buffer[bufferSize+1];
amateusz 2:e2db05bc4708 169 sdi12.getRxBuffer(buffer);
amateusz 2:e2db05bc4708 170 buffer[bufferSize] = '\0';
amateusz 17:5cabfc047b40 171 const std::string response(buffer);
amateusz 2:e2db05bc4708 172
amateusz 23:59447d795751 173 // debug("parser recv: %s\r\n", response);
amateusz 23:59447d795751 174 if (response[0] == _address && response.size() > 1) {
amateusz 22:c6e99d486304 175 // debug("__%s__\r\n", response);
amateusz 3:2847f7c543d3 176 // parser here
amateusz 17:5cabfc047b40 177 // const!!! response = response.substr(1); // to limit repeting this operation later. i.e. extract only values e.g. +21.3-123+123
amateusz 3:2847f7c543d3 178 // the only two possible delimeters of a value
amateusz 17:5cabfc047b40 179 size_t next_start_index = response.find_first_of("-+", 0 + 1); // address offset!
amateusz 3:2847f7c543d3 180 size_t next_end_index;
amateusz 3:2847f7c543d3 181 // ready, steady, parse!!
amateusz 3:2847f7c543d3 182 while(next_start_index != std::string::npos) {
amateusz 3:2847f7c543d3 183 // determine start index:
amateusz 3:2847f7c543d3 184 next_end_index = response.find_first_of("-+", next_start_index + 1); // std::substr is prepared to take std::npos
amateusz 17:5cabfc047b40 185
amateusz 3:2847f7c543d3 186 float value = std::atof(response.substr(next_start_index, next_end_index).c_str());
amateusz 4:11438803516c 187 // debug("parsed: %f\r\n", value);
amateusz 11:e0ccc1072c42 188 _measurement.values[_valuesReadyCount++] = value;
amateusz 3:2847f7c543d3 189 next_start_index = response.find_first_of("-+", next_end_index);
amateusz 3:2847f7c543d3 190 }
amateusz 11:e0ccc1072c42 191 // if current parsing doesn't return all the expexted measurements, then press harder and poll further Dx commands. RECURSION HERE *.*
amateusz 22:c6e99d486304 192 if (_valuesReadyCount < _measurement.count) {
amateusz 22:c6e99d486304 193 debug("values count: %d\r\n", _valuesReadyCount);
amateusz 11:e0ccc1072c42 194 read(group + 1);
amateusz 22:c6e99d486304 195 } else {
amateusz 13:0093792f2325 196 _measurementReady = true;
amateusz 13:0093792f2325 197 }
amateusz 3:2847f7c543d3 198 }
amateusz 4:11438803516c 199 return true;
amateusz 2:e2db05bc4708 200 }
amateusz 4:11438803516c 201
amateusz 4:11438803516c 202
amateusz 0:d58ebb2bed9a 203 //
amateusz 4:11438803516c 204 const unsigned char getMeasurementCount() {
amateusz 2:e2db05bc4708 205 return _measurement.count;
amateusz 2:e2db05bc4708 206 }
amateusz 2:e2db05bc4708 207
amateusz 4:11438803516c 208 const float getMeasurementValue(char which) {
amateusz 13:0093792f2325 209 _measurementReady = false; // reading /any/ of the values resets this
amateusz 2:e2db05bc4708 210 return _measurement.values[which];
amateusz 2:e2db05bc4708 211 }
amateusz 2:e2db05bc4708 212
amateusz 0:d58ebb2bed9a 213 void setAddress(char address) {
amateusz 0:d58ebb2bed9a 214 _address = address;
amateusz 0:d58ebb2bed9a 215 };
amateusz 0:d58ebb2bed9a 216 //
amateusz 0:d58ebb2bed9a 217 //
amateusz 0:d58ebb2bed9a 218 private:
amateusz 13:0093792f2325 219 static const int RESPONSE_TIMEOUT = 15+1; // device should start to respond within [ms]
amateusz 5:e53104570fde 220 static const std::string ADDRRICES; // as in index -> indices,
amateusz 5:e53104570fde 221
amateusz 15:530bf2e09814 222 SDI12 *_sdi12;
amateusz 0:d58ebb2bed9a 223 char _address;
amateusz 17:5cabfc047b40 224
amateusz 0:d58ebb2bed9a 225 Measurement_struct _measurement;
amateusz 11:e0ccc1072c42 226 size_t _valuesReadyCount;
amateusz 13:0093792f2325 227 bool _measurementReady;
amateusz 0:d58ebb2bed9a 228
amateusz 1:6b1a21925a81 229 bool getIdentification(Identification_struct &ident) {
amateusz 15:530bf2e09814 230 // _sdi12->sendCommand(std::string(_address) + "I!");
amateusz 21:aa7b255c5896 231 const std::string question = std::string(1, _address) + "I!";
amateusz 15:530bf2e09814 232 _sdi12->sendCommand(question);
amateusz 0:d58ebb2bed9a 233
amateusz 1:6b1a21925a81 234 Timer timeout;
amateusz 1:6b1a21925a81 235 timeout.start();
amateusz 1:6b1a21925a81 236 while (sdi12.RxBufferAvailable() == 0) {
amateusz 1:6b1a21925a81 237 if (sdi12.RxInProgress()) timeout.reset();
amateusz 5:e53104570fde 238 if(timeout.read_ms() > RESPONSE_TIMEOUT) {
amateusz 1:6b1a21925a81 239 return false;
amateusz 1:6b1a21925a81 240 }
amateusz 1:6b1a21925a81 241 }
amateusz 1:6b1a21925a81 242 unsigned char bufferSize = sdi12.RxBufferAvailable();
amateusz 1:6b1a21925a81 243 char buffer[bufferSize+1];
amateusz 1:6b1a21925a81 244 sdi12.getRxBuffer(buffer);
amateusz 1:6b1a21925a81 245 buffer[bufferSize] = '\0';
amateusz 17:5cabfc047b40 246 const std::string response(buffer);
amateusz 0:d58ebb2bed9a 247
amateusz 1:6b1a21925a81 248 if (response[0] == _address) {
amateusz 1:6b1a21925a81 249 // e.g.: 113DECAGON GS3 402
amateusz 2:e2db05bc4708 250
amateusz 1:6b1a21925a81 251 ident.sdi_version = std::atoi(response.substr(1, 2).c_str());
amateusz 17:5cabfc047b40 252 const std::string tempStr = response.substr(3, 8);
amateusz 1:6b1a21925a81 253 strcpy(ident.company, tempStr.c_str());
amateusz 1:6b1a21925a81 254
amateusz 17:5cabfc047b40 255 strcpy(ident.model, response.substr(3+8, 6).c_str());
amateusz 1:6b1a21925a81 256
amateusz 17:5cabfc047b40 257 strcpy(ident.version, response.substr(3+8+6, 3).c_str());
amateusz 1:6b1a21925a81 258 return true;
amateusz 0:d58ebb2bed9a 259 }
amateusz 1:6b1a21925a81 260 return false;
amateusz 1:6b1a21925a81 261 }
amateusz 5:e53104570fde 262 };
amateusz 5:e53104570fde 263
amateusz 5:e53104570fde 264 const std::string SDI12_device::ADDRRICES = "0123456789abcdefgijklmnoprstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";