Mateusz Grzywacz / SDI12_device
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SDI12_device.h Source File

SDI12_device.h

00001 #include "SDI12.h"
00002 #include <string>
00003 #include "mbed.h"
00004 extern void printStackStats(char num);
00005 
00006 class SDI12_device
00007 {
00008 public:
00009     struct Identification_struct {
00010         unsigned char sdi_version;
00011         char company[8+1];
00012         char model[6+1];
00013         char version[3+1];
00014     };
00015 
00016     Identification_struct _ident_struct;
00017 
00018     struct Measurement_struct {
00019         unsigned long timestampMeasurementReadyAt;
00020         char readyIn;
00021         bool _measurementAlreadyRead;
00022         char count;
00023 //        float * values;  // not float values [] !! :O
00024         float values[20]; // !! :O
00025     };
00026 
00027     const static int detect(SDI12 &sdi12, char indices[], int stop = -1, int start = -1) {
00028         char found = 0;
00029         for (size_t i = (start==-1?0:start); i < (stop==-1?ADDRRICES.size():stop+1); ++i) {
00030             const std::string question = std::string(1, ADDRRICES[i]) + "!";
00031             sdi12.sendCommand(question);
00032             Timer detectTimer;
00033             detectTimer.start();
00034             while (detectTimer.read_ms() < RESPONSE_TIMEOUT * 4) {
00035                 if (sdi12.RxInProgress()) detectTimer.reset();
00036                 if (sdi12.RxBufferAvailable()) {
00037                     unsigned char bufferSize = sdi12.RxBufferAvailable();
00038                     char buffer[bufferSize];
00039                     sdi12.getRxBuffer(buffer);
00040                     // if first char is valid address char
00041                     if (ADDRRICES.find(buffer[0])) {
00042                         indices[found++] = buffer[0];
00043                         debug("FOUND (%d): %d -> %c\r\n", found, i, indices[found-1]);
00044                     }
00045                 }
00046             }
00047             osDelay(100);
00048         }
00049         return found;
00050     };
00051 
00052     SDI12_device() {
00053         debug("default in %s\r\n", __FILE__);
00054     }
00055 
00056     SDI12_device (SDI12 *inst, char address) : _sdi12(inst) {
00057         setAddress(address);
00058         if(getIdentification(_ident_struct));
00059     };
00060 
00061     SDI12_device (const SDI12_device &old) {
00062         debug("copy in %s\r\n", __FILE__);
00063         _address = old._address;
00064         _ident_struct = old._ident_struct;
00065         _sdi12 = old._sdi12;
00066         _measurement = old._measurement;
00067         _measurementReady = false;
00068         _valuesReadyCount = old._valuesReadyCount;
00069         _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?!
00070     }
00071 
00072     SDI12_device & operator= (const SDI12_device & old) {
00073         debug("assign in %s\r\n", __FILE__);
00074         _address = old._address;
00075         _ident_struct = old._ident_struct;
00076         _sdi12 = old._sdi12;
00077         _measurement = old._measurement;
00078         _measurementReady = false;
00079         _valuesReadyCount = old._valuesReadyCount;
00080         _measurementReady = old._measurementReady; // why?!?!! new _measureStruct here worked ?!
00081 
00082         return *this;
00083     }
00084 
00085     ~SDI12_device () {
00086         debug("destructor in %s\r\n", __FILE__);
00087     }
00088 
00089     bool present() {
00090         const std::string question = std::string(1, _address) + std::string("!");
00091         _sdi12->sendCommand(question);
00092 
00093         Timer timeout;
00094         timeout.start();
00095         while (sdi12.RxBufferAvailable() == 0) {
00096             if (sdi12.RxInProgress()) timeout.reset();
00097             if(timeout.read_ms() > RESPONSE_TIMEOUT) {
00098                 return false;
00099             }
00100         }
00101         unsigned char bufferSize = sdi12.RxBufferAvailable();
00102         char buffer[bufferSize];
00103         sdi12.getRxBuffer(buffer); // only to flush the buffer
00104         return true;
00105     }
00106     // concurrent means that device under measurement won't signal its prempt readiness to the bus
00107     int measure(bool concurrent = true, char group = '0') {
00108 
00109         const std::string question = std::string(1, _address) + std::string(concurrent?"C": (group=='0'?"M":("M"+std::string(1,group)))) + std::string("!");
00110 //        if (group != '0') // ABOVE DOES THIS
00111 //            question.insert(2, 1, group); // e.g. 2M! -> 2M1!
00112         _sdi12->sendCommand(question);
00113 
00114         Timer timeout;
00115         timeout.start();
00116         while (sdi12.RxBufferAvailable() == 0) {
00117             if (sdi12.RxInProgress()) timeout.reset();
00118             if(timeout.read_ms() > RESPONSE_TIMEOUT) {
00119                 return -2;
00120             }
00121         }
00122 
00123         unsigned char bufferSize = sdi12.RxBufferAvailable();
00124         char buffer[bufferSize+1];
00125         sdi12.getRxBuffer(buffer);
00126         buffer[bufferSize] = '\0';
00127         std::string response(buffer);
00128 
00129         if (response[0] == _address) {
00130             char measurementsCount = std::atoi(response.substr(1+3,(concurrent?2:1)).c_str());
00131             char waitFor = std::atoi(response.substr(1,3).c_str());
00132             _measurement.count = measurementsCount;
00133 
00134             _measurement.readyIn = waitFor;
00135 //            _measurement.timestampMeasurementReadyAt
00136             debug("wait for %d measurement for %d seconds...", _measurement.count, waitFor);
00137             _valuesReadyCount = 0;
00138             _measurementReady = false;
00139             return 0;
00140         }
00141         return -1;
00142     };
00143 
00144     char readyIn() {
00145         return _measurement.readyIn;
00146     }
00147 
00148     bool isReady() {
00149         return _measurementReady;
00150     }
00151 
00152     bool read(char group = '0') {
00153         char group_a[] = {group};
00154         printStackStats(std::atoi(group_a));
00155 //         Measurement (M), Continuous (R), and Concurrent (C) commands and subsequent Data (D)
00156         const std::string question = std::string(1, _address) + std::string("D") + std::string(1, group)+ std::string("!");
00157         _sdi12->sendCommand(question);
00158 
00159         Timer timeout;
00160         timeout.start();
00161         while (sdi12.RxBufferAvailable() == 0) {
00162             if (sdi12.RxInProgress()) timeout.reset();
00163             if(timeout.read_ms() > RESPONSE_TIMEOUT) {
00164                 return false;
00165             }
00166         }
00167         unsigned char bufferSize = sdi12.RxBufferAvailable();
00168         char buffer[bufferSize+1];
00169         sdi12.getRxBuffer(buffer);
00170         buffer[bufferSize] = '\0';
00171         const std::string response(buffer);
00172 
00173 //        debug("parser recv: %s\r\n", response);
00174         if (response[0] == _address && response.size() > 1) {
00175 //            debug("__%s__\r\n", response);
00176             // parser here
00177             // const!!! response = response.substr(1); // to limit repeting this operation later. i.e. extract only values e.g. +21.3-123+123
00178             // the only two possible delimeters of a value
00179             size_t next_start_index = response.find_first_of("-+", 0 + 1); // address offset!
00180             size_t next_end_index;
00181             // ready, steady, parse!!
00182             while(next_start_index != std::string::npos) {
00183                 // determine start index:
00184                 next_end_index = response.find_first_of("-+", next_start_index + 1); // std::substr is prepared to take std::npos
00185 
00186                 float value = std::atof(response.substr(next_start_index, next_end_index).c_str());
00187 //                debug("parsed: %f\r\n", value);
00188                 _measurement.values[_valuesReadyCount++] = value;
00189                 next_start_index = response.find_first_of("-+", next_end_index);
00190             }
00191             // if current parsing doesn't return all the expexted measurements, then press harder and poll further Dx commands. RECURSION HERE *.*
00192             if (_valuesReadyCount < _measurement.count) {
00193                 debug("values count: %d\r\n", _valuesReadyCount);
00194                 read(group + 1);
00195             } else {
00196                 _measurementReady = true;
00197             }
00198         }
00199         return true;
00200     }
00201 
00202 
00203 //
00204     const unsigned char getMeasurementCount() {
00205         return _measurement.count;
00206     }
00207 
00208     const float getMeasurementValue(char which) {
00209         _measurementReady = false; // reading /any/ of the values resets this
00210         return _measurement.values[which];
00211     }
00212 
00213     void setAddress(char address) {
00214         _address = address;
00215     };
00216 //
00217 //
00218 private:
00219     static const int RESPONSE_TIMEOUT = 15+1; // device should start to respond within [ms]
00220     static const std::string ADDRRICES; // as in index -> indices,
00221 
00222     SDI12 *_sdi12;
00223     char _address;
00224 
00225     Measurement_struct _measurement;
00226     size_t _valuesReadyCount;
00227     bool _measurementReady;
00228 
00229     bool getIdentification(Identification_struct &ident) {
00230 //        _sdi12->sendCommand(std::string(_address) + "I!");
00231         const std::string question = std::string(1, _address) + "I!";
00232         _sdi12->sendCommand(question);
00233 
00234         Timer timeout;
00235         timeout.start();
00236         while (sdi12.RxBufferAvailable() == 0) {
00237             if (sdi12.RxInProgress()) timeout.reset();
00238             if(timeout.read_ms() > RESPONSE_TIMEOUT) {
00239                 return false;
00240             }
00241         }
00242         unsigned char bufferSize = sdi12.RxBufferAvailable();
00243         char buffer[bufferSize+1];
00244         sdi12.getRxBuffer(buffer);
00245         buffer[bufferSize] = '\0';
00246         const std::string response(buffer);
00247 
00248         if (response[0] == _address) {
00249             // e.g.: 113DECAGON GS3   402
00250 
00251             ident.sdi_version = std::atoi(response.substr(1, 2).c_str());
00252             const std::string tempStr = response.substr(3, 8);
00253             strcpy(ident.company, tempStr.c_str());
00254 
00255             strcpy(ident.model, response.substr(3+8, 6).c_str());
00256 
00257             strcpy(ident.version, response.substr(3+8+6, 3).c_str());
00258             return true;
00259         }
00260         return false;
00261     }
00262 };
00263 
00264 const std::string SDI12_device::ADDRRICES = "0123456789abcdefgijklmnoprstuvwxyzABCDEFGHIJKLMNOPRSTUVWXYZ";