TestCommands.ino example

1/**
2 * @example{lineno} TestCommands.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
5 * @author Sara Damiano <sdamiano@stroudcenter.org>
6 */
7
8#include <SDI12.h>
9
10#ifndef SDI12_DATA_PIN
11#define SDI12_DATA_PIN 7
12#endif
13#ifndef SDI12_POWER_PIN
14#define SDI12_POWER_PIN 22
15#endif
16
17// #define TEST_PRINT_ARRAY
18
19/* connection information */
20#if F_CPU > 48000000L
21uint32_t serialBaud = 921600; /*!< The baud rate for the output serial port */
22#else
23uint32_t serialBaud = 115200; /*!< The baud rate for the output serial port */
24#endif
25int8_t dataPin = SDI12_DATA_PIN; /*!< The pin of the SDI-12 data bus */
26int8_t powerPin = SDI12_POWER_PIN; /*!< The sensor power pin (or -1) */
27uint32_t wake_delay = 10; /*!< Extra time needed for the sensor to wake (0-100ms) */
28const int8_t firstAddress =
29 0; /* The first address in the address space to check (0='0') */
30const int8_t lastAddress =
31 61; /* The last address in the address space to check (61='z') */
32const int8_t commandsToTest =
33 1; /*!< The number of measurement commands to test, between 1 and 11. */
34
35/** Define the SDI-12 bus */
36SDI12 mySDI12(dataPin);
37
38/** Define some testing specs */
39const int8_t n_addresses = (lastAddress - firstAddress) + 1;
40
41/** Error codes, if returned */
42int8_t error_result_number = 7;
43float no_error_value = 0;
44
45/// variable that alternates output type back and forth between parsed and raw
46boolean flip = 0;
47
48String commands[] = {"", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
49
50// keeps track of active addresses
51bool isActive[n_addresses];
52
53// keeps track of the wait time for each active addresses
54uint32_t meas_time_ms[n_addresses];
55
56// keeps track of the time each sensor was started
57uint32_t millisStarted[n_addresses];
58
59// keeps track of the time each sensor will be ready
60uint32_t millisReady[n_addresses];
61
62// keeps track of the number of results expected
63uint8_t expectedResults[n_addresses];
64
65// keeps track of the number of results returned
66uint8_t returnedResults[n_addresses];
67
68String prev_result[n_addresses];
69String this_result[n_addresses];
70uint8_t numSensors = 0;
71
72struct startMeasurementResult { // Structure declaration
73 String returnedAddress;
74 uint8_t meas_time_s;
75 int numberResults;
76};
77
78struct getResultsResult { // Structure declaration
79 uint8_t resultsReceived;
80 uint8_t maxDataCommand;
81 bool addressMatch;
82 bool crcMatch;
83 bool errorCode;
84 bool success;
85};
86
87/**
88 * @brief converts allowable address characters ('0'-'9', 'a'-'z', 'A'-'Z') to a
89 * decimal number between 0 and 61 (inclusive) to cover the 62 possible
90 * addresses.
91 */
92byte charToDec(char i) {
93 if ((i >= '0') && (i <= '9')) return i - '0';
94 if ((i >= 'a') && (i <= 'z')) return i - 'a' + 10;
95 if ((i >= 'A') && (i <= 'Z'))
96 return i - 'A' + 36;
97 else
98 return i;
99}
100
101/**
102 * @brief maps a decimal number between 0 and 61 (inclusive) to allowable
103 * address characters '0'-'9', 'a'-'z', 'A'-'Z',
104 *
105 * THIS METHOD IS UNUSED IN THIS EXAMPLE, BUT IT MAY BE HELPFUL.
106 */
107char decToChar(byte i) {
108 if (i < 10) return i + '0';
109 if ((i >= 10) && (i < 36)) return i + 'a' - 10;
110 if ((i >= 36) && (i <= 62))
111 return i + 'A' - 36;
112 else
113 return i;
114}
115
116/**
117 * @brief gets identification information from a sensor, and prints it to the serial
118 * port
119 *
120 * @param i a character between '0'-'9', 'a'-'z', or 'A'-'Z'.
121 * @param printIO true to print the raw output and input from the command
122 */
123bool printInfo(char address, bool printIO = true) {
124 String command = "";
125 command += (char)address;
126 command += "I!";
127 mySDI12.sendCommand(command, wake_delay);
128 if (printIO) {
129 Serial.print(">>>");
130 Serial.println(command);
131 }
132 delay(30);
133
134 String sdiResponse = mySDI12.readStringUntil('\n');
135 sdiResponse.trim();
136 // allccccccccmmmmmmvvvxxx...xx<CR><LF>
137 if (printIO) {
138 Serial.print("<<<");
139 Serial.println(sdiResponse);
140 }
141
142 Serial.print("Address: ");
143 Serial.print(sdiResponse.substring(0, 1)); // address
144 Serial.print(", SDI-12 Version: ");
145 Serial.print(sdiResponse.substring(1, 3).toFloat() / 10); // SDI-12 version number
146 Serial.print(", Vendor ID: ");
147 Serial.print(sdiResponse.substring(3, 11)); // vendor id
148 Serial.print(", Sensor Model: ");
149 Serial.print(sdiResponse.substring(11, 17)); // sensor model
150 Serial.print(", Sensor Version: ");
151 Serial.print(sdiResponse.substring(17, 20)); // sensor version
152 Serial.print(", Sensor ID: ");
153 Serial.print(sdiResponse.substring(20)); // sensor id
154 Serial.println();
155
156 if (sdiResponse.length() < 3) { return false; };
157 return true;
158}
159
160getResultsResult getResults(char address, int resultsExpected, bool verify_crc = false,
161 bool printIO = true) {
162 uint8_t resultsReceived = 0;
163 uint8_t cmd_number = 0;
164 uint8_t cmd_retries = 0;
165
166 // From SDI-12 Protocol v1.4, Section 4.4 SDI-12 Commands and Responses:
167 // The maximum number of characters that can be returned in the <values> part of the
168 // response to a D command is either 35 or 75. If the D command is issued to
169 // retrieve data in response to a concurrent measurement command, or in response to
170 // a high-volume ASCII measurement command, the maximum is 75. The maximum is also
171 // 75 in response to a continuous measurement command. Otherwise, the maximum is 35.
172 int max_sdi_response = 76;
173 // From SDI-12 Protocol v1.4, Table 11 The send data command (aD0!, aD1! . . . aD9!):
174 // - the maximum number of digits for a data value is 7, even without a decimal point
175 // - the minimum number of digits for a data value (excluding the decimal point) is 1
176 // - the maximum number of characters in a data value is 9 (the (polarity sign + 7
177 // digits + the decimal point))
178 // - SRGD Note: The polarity symbol (+ or -) acts as a delimeter between the numeric
179 // values
180 int max_sdi_digits = 10;
181
182 String compiled_response = "";
183
184 bool success = true;
185
186 // Create the return struct
187 getResultsResult return_result;
188 return_result.resultsReceived = 0;
189 return_result.maxDataCommand = 0;
190 return_result.addressMatch = true;
191 return_result.crcMatch = true;
192 return_result.errorCode = false;
193 return_result.success = true;
194
195 while (resultsReceived < resultsExpected && cmd_number <= 9 && cmd_retries < 5) {
196 bool gotResults = false;
197 uint8_t cmd_results = 0;
198
199 // Assemble the command based on how many commands we've already sent,
200 // starting with D0 and ending with D9
201 // SDI-12 command to get data [address][D][dataOption][!]
202 mySDI12.clearBuffer();
203 String command = "";
204 command += address;
205 command += "D";
206 command += cmd_number;
207 command += "!";
208 mySDI12.sendCommand(command, wake_delay);
209 delay(30);
210 if (printIO) {
211 Serial.print(">>>");
212 Serial.println(command);
213 }
214 char resp_buffer[max_sdi_response] = {'\0'};
215
216 // read bytes into the char array until we get to a new line (\r\n)
217 size_t bytes_read = mySDI12.readBytesUntil('\n', resp_buffer, max_sdi_response);
218 // Serial.print(bytes_read);
219 // Serial.println(" characters");
220
221 size_t data_bytes_read = bytes_read - 1; // subtract one for the /r before the /n
222 String sdiResponse = String(resp_buffer);
223 compiled_response += sdiResponse;
224 sdiResponse.trim();
225 if (printIO) {
226 Serial.print("<<<");
227 Serial.println(sdiResponse);
228 // Serial.println(sdiResponse.length());
229 // Serial.print("<<<");
230 // Serial.println(resp_buffer);
231 // Serial.println(strnlen(resp_buffer, max_sdi_response));
232 }
233 // read and clear anything else from the buffer
234 int extra_chars = 0;
235 while (mySDI12.available()) {
236 Serial.write(mySDI12.read());
237 extra_chars++;
238 }
239 if (extra_chars > 0) {
240 Serial.print(extra_chars);
241 Serial.println(" additional characters received.");
242 }
243 mySDI12.clearBuffer();
244
245 // check the crc, break if it's incorrect
246 if (verify_crc) {
247 bool crcMatch = mySDI12.verifyCRC(sdiResponse);
248 // subtract the 3 characters of the CRC from the total number of data values
249 data_bytes_read = data_bytes_read - 3;
250 if (crcMatch) {
251 if (printIO) { Serial.println("CRC valid"); }
252 } else {
253 if (printIO) { Serial.println("CRC check failed!"); }
254 return_result.crcMatch = false;
255 success = false;
256 // if we failed CRC in the response, add one to the retry
257 // attempts but do not bump up the command number or transfer any
258 // results because we want to retry the same data command to try get
259 // a valid response
260 cmd_retries++;
261 // stop processing; no reason to read the numbers when we already know
262 // something's wrong
263 continue;
264 }
265 }
266
267 // check the address, break if it's incorrect
268 // NOTE: If the address is wrong because the response is garbled, the CRC check
269 // above should fail. But we still verify the address in case we're not checking the
270 // CRC or we got a well formed response from the wrong sensor.
271 char returnedAddress = resp_buffer[0];
272 if (returnedAddress != address) {
273 if (printIO) {
274 Serial.println("Wrong address returned!");
275 Serial.print("Expected ");
276 Serial.print(String(address));
277 Serial.print(" Got ");
278 Serial.println(String(returnedAddress));
279 Serial.println(String(resp_buffer));
280 }
281 success = false;
282 return_result.addressMatch = false;
283 // if we didn't get the correct address, add one to the retry
284 // attempts but do not bump up the command number or transfer any
285 // results because we want to retry the same data command to try get
286 // a valid response
287 cmd_retries++;
288 // stop processing; no reason to read the numbers when we already know
289 // something's wrong
290 continue;
291 }
292
293 bool bad_read = false;
294 char float_buffer[max_sdi_digits] = {'\0'};
295 bool got_decimal = false;
296 char* dec_pl = float_buffer; // just used for pretty printing
297 uint8_t fb_pos = 0; // start at start of buffer
298 // iterate through the char array and to check results
299 // NOTE: start at 1 since we already looked at the address!
300 for (size_t i = 1; i <= data_bytes_read; i++) {
301 // Get the character at position
302 char c = resp_buffer[i];
303 // Serial.print(i);
304 // Serial.print(" of ");
305 // Serial.print(data_bytes_read);
306 // Serial.print(" '");
307 // Serial.print(c);
308 // Serial.println("'");
309 // if we get a polarity sign (+ or -) that is not the first character after the
310 // address, or we've reached the end of the buffer, then we're at the end of the
311 // previous number and can parse the float buffer
312 if ((((c == '-' || c == '+') && i != 1) || i == data_bytes_read) &&
313 strnlen(float_buffer, max_sdi_digits) > 0) {
314 float result = atof(float_buffer);
315 if (printIO) {
316 Serial.print("Result ");
317 Serial.print(resultsReceived);
318 Serial.print(", Raw value: ");
319 Serial.print(float_buffer);
320 dec_pl = strchr(float_buffer, '.');
321 // NOTE: This bit below is just for pretty-printing
322 size_t len_post_dec = 0;
323 if (dec_pl != nullptr) { len_post_dec = strnlen(dec_pl, max_sdi_digits) - 1; }
324 Serial.print(", Len after decimal: ");
325 Serial.print(len_post_dec);
326 Serial.print(", Parsed value: ");
327 Serial.println(String(result, len_post_dec));
328 }
329 // add how many results we have
330 if (result != -9999) {
331 gotResults = true;
332 resultsReceived++;
333 }
334 // check for a failure error code at the end
335 if (error_result_number >= 1) {
336 if (resultsReceived == error_result_number && result != no_error_value) {
337 success = false;
338 return_result.errorCode = true;
339 if (printIO) {
340 Serial.print("Got a failure code of ");
341 Serial.println(String(result, strnlen(dec_pl, max_sdi_digits) - 1));
342 }
343 }
344 }
345 // empty the float buffer so it's ready for the next number
346 float_buffer[0] = '\0';
347 fb_pos = 0;
348 got_decimal = false;
349 }
350 if (i == data_bytes_read) { continue; }
351 // if we're mid-number and there's a digit, a decimal, or a negative sign in the
352 // sdi12 response buffer, add it to the current float buffer
353 if (c == '-' || (c >= '0' && c <= '9') || (c == '.' && !got_decimal)) {
354 float_buffer[fb_pos] = c;
355 fb_pos++;
356 float_buffer[fb_pos] = '\0'; // null terminate the buffer
357 // Serial.print("Added to float buffer, currently: '");
358 // Serial.print(float_buffer);
359 // Serial.print("' (");
360 // Serial.print(strnlen(float_buffer, max_sdi_digits));
361 // Serial.println(")");
362 } else if (c == '+') {
363 // if we get a "+", it's a valid SDI-12 polarity indicator, but not something
364 // accepted by atof in parsing the float, so we just ignore it
365 // NOTE: A mis-read like this should also cause the CRC to be wrong, but still
366 // check here in case we're not using a CRC.
367 } else { //(c != '-' && c != '+' && (c < '0' || c > '9') && c != '.')
368 Serial.print("Invalid data response character: ");
369 Serial.write(c);
370 Serial.println();
371 bad_read = true;
372 }
373 // if we get a decimal, mark it so we can verify we don't get repeated decimals
374 if (c == '.') { got_decimal = true; }
375 }
376
377 // if (!gotResults) {
378 // if (printIO) {
379 // Serial.println((" No results received, will not continue requests!"));
380 // }
381 // break;
382 // } // don't do another loop if we got nothing
383
384 if (gotResults && !bad_read) {
385 resultsReceived = resultsReceived + cmd_results;
386 if (printIO) {
387 Serial.print(F(" Total Results Received: "));
388 Serial.print(resultsReceived);
389 Serial.print(F(", Remaining: "));
390 Serial.println(resultsExpected - resultsReceived);
391 }
392 cmd_number++;
393 } else {
394 // if we got a bad charater in the response, add one to the retry
395 // attempts but do not bump up the command number or transfer any
396 // results because we want to retry the same data command to try get
397 // a valid response
398 cmd_retries++;
399 }
400 mySDI12.clearBuffer();
401 }
402
403 if (printIO) {
404 Serial.print("After ");
405 Serial.print(cmd_number);
406 Serial.print(" data commands got ");
407 Serial.print(resultsReceived);
408 Serial.print(" results of the expected ");
409 Serial.print(resultsExpected);
410 Serial.print(" expected. This is a ");
411 Serial.println(resultsReceived == resultsExpected ? "success." : "failure.");
412 }
413
414 success &= resultsReceived == resultsExpected;
415 this_result[charToDec(address) - firstAddress] = compiled_response;
416 return_result.resultsReceived = resultsReceived;
417 return_result.maxDataCommand = cmd_number;
418 return_result.success = success;
419 return return_result;
420}
421
422bool getContinuousResults(char address, int resultsExpected, bool printIO = true) {
423 uint8_t resultsReceived = 0;
424 uint8_t cmd_number = 0;
425 while (resultsReceived < resultsExpected && cmd_number <= 9) {
426 String command = "";
427 command += address;
428 command += "R";
429 command += cmd_number;
430 command += "!"; // SDI-12 command to get data [address][D][dataOption][!]
431 mySDI12.sendCommand(command, wake_delay);
432 if (printIO) {
433 Serial.print(">>>");
434 Serial.println(command);
435 }
436
437 uint32_t start = millis();
438 while (mySDI12.available() < 3 && (millis() - start) < 1500) {};
439 if (printIO) {
440 Serial.print("<<<");
441 Serial.write(mySDI12.read()); // ignore the repeated SDI12 address
442 }
443
444 while (mySDI12.available()) {
445 char c = mySDI12.peek();
446 if (c == '-' || c == '+' || (c >= '0' && c <= '9') || c == '.') {
447 float result = mySDI12.parseFloat();
448 Serial.print(String(result, 7));
449 if (result != -9999) { resultsReceived++; }
450 } else if (c >= 0 && c != '\r' && c != '\n') {
451 Serial.write(mySDI12.read());
452 } else {
453 mySDI12.read();
454 }
455 delay(10); // 1 character ~ 7.5ms
456 }
457 if (printIO) {
458 Serial.print("Total Results Received: ");
459 Serial.print(resultsReceived);
460 Serial.print(", Remaining: ");
461 Serial.println(resultsExpected - resultsReceived);
462 }
463 if (!resultsReceived) { break; } // don't do another loop if we got nothing
464 cmd_number++;
465 }
466 mySDI12.clearBuffer();
467
468 return resultsReceived == resultsExpected;
469}
470
471startMeasurementResult startMeasurement(char address, bool is_concurrent = false,
472 bool request_crc = false, String meas_type = "",
473 bool printIO = true) {
474 // Create the return struct
475 startMeasurementResult return_result;
476 return_result.returnedAddress = "";
477 return_result.meas_time_s = 0;
478 return_result.numberResults = 0;
479
480 String command = "";
481 command += address; // All commands start with the address
482 command += is_concurrent ? "C" : "M"; // C for concurrent, M for standard
483 command += request_crc ? "C" : ""; // add an additional C to request a CRC
484 command += meas_type; // Measurement type, "" or 0-9
485 command += "!"; // All commands end with "!"
486 mySDI12.sendCommand(command, wake_delay);
487 if (printIO) {
488 Serial.print(">>>");
489 Serial.println(command);
490 }
491 delay(30);
492
493 // wait for acknowledgement with format [address][ttt (3 char, seconds)][number of
494 // measurements available, 0-9]
495 String sdiResponse = mySDI12.readStringUntil('\n');
496 sdiResponse.trim();
497 if (printIO) {
498 Serial.print("<<<");
499 Serial.println(sdiResponse);
500 }
501 mySDI12.clearBuffer();
502
503 // check the address, return if it's incorrect
504 String returnedAddress = sdiResponse.substring(0, 1);
505 char ret_addr_array[2] = {'\0'};
506 returnedAddress.toCharArray(ret_addr_array, sizeof(ret_addr_array));
507 return_result.returnedAddress = ret_addr_array[0];
508 if (returnedAddress != String(address)) {
509 if (printIO) {
510 Serial.println("Wrong address returned!");
511 Serial.print("Expected ");
512 Serial.print(String(address));
513 Serial.print(" Got ");
514 Serial.println(returnedAddress);
515 }
516 return return_result;
517 }
518
519 // find out how long we have to wait (in seconds).
520 uint8_t meas_time_s = sdiResponse.substring(1, 4).toInt();
521 return_result.meas_time_s = meas_time_s;
522 if (printIO) {
523 Serial.print("expected measurement time: ");
524 Serial.print(meas_time_s);
525 Serial.print(" s, ");
526 }
527
528 // Set up the number of results to expect
529 int numResults = sdiResponse.substring(4).toInt();
530 return_result.numberResults = numResults;
531 if (printIO) {
532 Serial.print("Number Results: ");
533 Serial.println(numResults);
534 }
535
536 return return_result;
537}
538
539// This is a separate function in this example so the wait times can all be filled into
540// the appropriate arrays
541int startConcurrentMeasurement(char address, bool request_crc = false,
542 String meas_type = "", bool printIO = true) {
543 startMeasurementResult startResult = startMeasurement(address, true, request_crc,
544 meas_type, printIO);
545
546 uint8_t sensorNum = charToDec(address - firstAddress);
547 meas_time_ms[sensorNum] = (static_cast<uint32_t>(startResult.meas_time_s)) * 1000;
548 millisStarted[sensorNum] = millis();
549 if (startResult.meas_time_s == 0) {
550 millisReady[sensorNum] = millis();
551 } else {
552 // give an extra second
553 // millisReady[sensorNum] = millis() + meas_time_ms[sensorNum] + 1000;
554 // subtract a second to start polling early
555 millisReady[sensorNum] = millis() + meas_time_ms[sensorNum] - 1000;
556 }
557 expectedResults[sensorNum] = startResult.numberResults;
558
559 return startResult.numberResults;
560}
561
562uint32_t takeMeasurement(char address, bool request_crc = false, String meas_type = "",
563 bool printIO = true) {
564 startMeasurementResult startResult = startMeasurement(address, false, request_crc,
565 meas_type, printIO);
566 if (startResult.numberResults == 0) { return -1; }
567
568 uint32_t timerStart = millis();
569 uint32_t measTime = -1;
570 // wait up to 1 second longer than the specified return time
571 while ((millis() - timerStart) <
572 (static_cast<uint32_t>(startResult.meas_time_s) + 1) * 1000) {
573 if (mySDI12.available()) {
574 break;
575 } // sensor can interrupt us to let us know it is done early
576 }
577 measTime = millis() - timerStart;
578 String interrupt_response = mySDI12.readStringUntil('\n');
579 if (printIO) {
580 Serial.print("<<<");
581 Serial.println(interrupt_response);
582 Serial.print("Completed after ");
583 Serial.print(measTime);
584 Serial.println(" ms");
585 }
586
587 // if we got results, return the measurement time, else -1
588 if (getResults(address, startResult.numberResults, request_crc, printIO).success) {
589 return measTime;
590 }
591
592 return -1;
593}
594
595// this checks for activity at a particular address
596// expects a char, '0'-'9', 'a'-'z', or 'A'-'Z'
597bool checkActive(char address, int8_t numPings = 3, bool printIO = true) {
598 mySDI12.clearBuffer();
599 String command = "";
600 command += (char)address; // sends basic 'acknowledge' command [address][!]
601 command += "!";
602
603 for (int j = 0; j < numPings; j++) { // goes through rapid contact attempts
604 if (printIO) {
605 Serial.print(">>>");
606 Serial.println(command);
607 }
608 mySDI12.sendCommand(command, wake_delay);
609 delay(30);
610
611 // the sensor should just return its address followed by '\r\n'
612 if (mySDI12.available()) {
613 String sdiResponse_r = mySDI12.readStringUntil('\n');
614 String sdiResponse = sdiResponse_r;
615 sdiResponse_r.replace("\r", "←");
616 sdiResponse_r.replace("\n", "↓");
617 if (printIO) {
618 Serial.print("<<< '");
619 Serial.print(sdiResponse_r);
620 Serial.print("' (");
621 Serial.print(sdiResponse_r.length());
622 Serial.println(")");
623 }
624 sdiResponse.trim();
625 sdiResponse.replace("\r", "←");
626 sdiResponse.replace("\n", "↓");
627 if (printIO) {
628 Serial.print("<<< Trimmed: '");
629 Serial.print(sdiResponse);
630 Serial.print("' (");
631 Serial.print(sdiResponse.length());
632 Serial.println(")");
633 }
634 mySDI12.clearBuffer();
635
636 // check the address, return false if it's incorrect
637 String returnedAddress = sdiResponse.substring(0, 1);
638 Serial.print("returnedAddress '");
639 Serial.print(returnedAddress);
640 Serial.print("' (");
641 Serial.print(returnedAddress.length());
642 Serial.println(")");
643 if (returnedAddress == String(address)) {
644 if (printIO) {
645 Serial.print("Got response from '");
646 Serial.print(String(returnedAddress));
647 Serial.println("'");
648 }
649 return true;
650 } else {
651 if (printIO) {
652 Serial.println("Wrong address returned!");
653 Serial.print("Expected '");
654 Serial.print(String(address));
655 Serial.print("' Got '");
656 Serial.print(returnedAddress);
657 Serial.println("'");
658 // Serial.println(sdiResponse);
659 }
660 }
661 }
662 }
663 mySDI12.clearBuffer();
664 return false;
665}
666
667void setup() {
668 Serial.begin(serialBaud);
669 while (!Serial && millis() < 10000L);
670 char tbuf[3] = {'\0'};
671
672 Serial.print("Opening SDI-12 bus on pin ");
673 Serial.print(dataPin);
674 Serial.print(" (");
675 Serial.print(itoa(dataPin, tbuf, 10));
676 Serial.print(")");
677 Serial.println("...");
678 mySDI12.begin();
679 delay(500); // allow things to settle
680
681 Serial.println("Timeout value: ");
682 Serial.println(mySDI12.TIMEOUT);
683
684 // Fill arrays with 0's
685 for (int8_t address_number = firstAddress; address_number <= lastAddress;
686 address_number++) {
687 int8_t pos = address_number - firstAddress;
688 isActive[pos] = false;
689 meas_time_ms[pos] = 0;
690 millisStarted[pos] = 0;
691 millisReady[pos] = 0;
692 expectedResults[pos] = 0;
693 returnedResults[pos] = 0;
694 prev_result[pos] = "";
695 this_result[pos] = "";
696 }
697
698 // Power the sensors;
699 if (powerPin >= 0) {
700 Serial.print("Powering up sensors with pin ");
701 Serial.print(String(powerPin));
702 Serial.println(", wait 10s...");
703 pinMode(powerPin, OUTPUT);
704 digitalWrite(powerPin, HIGH);
705 delay(10000L);
706 } else {
707 Serial.println("Wait 5s...");
708 delay(5000L);
709 }
710
711 // Quickly scan the address space
712 Serial.println("\n\nScanning all addresses, please wait...");
713
714 for (int8_t address_number = firstAddress; address_number <= lastAddress;
715 address_number++) {
716 int8_t pos = address_number - firstAddress;
717 char address = decToChar(address_number);
718 Serial.print("i: ");
719 Serial.print(address_number);
720 Serial.print(", address: ");
721 Serial.print(address);
722 Serial.print(", reversed: ");
723 Serial.println(charToDec(address));
724 if (checkActive(address, 5, true)) {
725 numSensors++;
726 isActive[pos] = 1;
727 // Serial.println(", +");
728 printInfo(address, true);
729 } else {
730 // Serial.println(", -");
731 }
732 }
733 Serial.print("Total number of sensors found: ");
734 Serial.println(numSensors);
735
736 if (numSensors == 0) {
737 Serial.println(
738 "No sensors found, please check connections and restart the Arduino.");
739 while (true) { delay(10); } // do nothing forever
740 }
741
742 Serial.println();
743 Serial.println("-------------------------------------------------------------------"
744 "------------");
745 Serial.println("Wait 10s...");
746 delay(10000L);
747 Serial.println();
748 Serial.println("-------------------------------------------------------------------"
749 "------------");
750}
751
752void loop() {
753 flip = !flip; // flip the switch between concurrent and not
754 Serial.print("Starting ");
755 Serial.print(flip ? "concurrent" : "individual");
756 // flip = 1;
757 // flip = 0;
758 uint32_t start = millis();
759 // Serial.print("Flip: ");
760 // Serial.println(flip);
761
762 // Fill arrays with 0's
763 for (int8_t address_number = firstAddress; address_number <= lastAddress;
764 address_number++) {
765 int8_t pos = address_number - firstAddress;
766 meas_time_ms[pos] = 0;
767 millisStarted[pos] = 0;
768 millisReady[pos] = 0;
769 expectedResults[pos] = 0;
770 returnedResults[pos] = 0;
771 }
772
773 if (flip) {
774 // measure one at a time
775 for (int8_t address_number = firstAddress; address_number <= lastAddress;
776 address_number++) {
777 int8_t pos = address_number - firstAddress;
778 char address = decToChar(address_number);
779 if (isActive[pos]) {
780 for (uint8_t a = 0; a < commandsToTest; a++) {
781 takeMeasurement(address, true, commands[a], true);
782 Serial.println();
783 }
784 // getContinuousResults(address, 3);
785 } else {
786 Serial.print("Address ");
787 Serial.print(address);
788 Serial.println(" is not active");
789 }
790 }
791 Serial.print("Total Time for Individual Measurements: ");
792 Serial.println(millis() - start);
793 } else {
794 for (uint8_t a = 0; a < commandsToTest; a++) {
795 uint32_t min_wait = 60000L;
796 uint32_t max_wait = 0;
797 uint32_t for_start = millis();
798 // start all sensors measuring concurrently
799 for (int8_t address_number = firstAddress; address_number <= lastAddress;
800 address_number++) {
801 int8_t pos = address_number - firstAddress;
802 char address = decToChar(address_number);
803 if (isActive[pos]) {
804 startConcurrentMeasurement(address, true, commands[a], true);
805 if (meas_time_ms[pos] < min_wait) { min_wait = meas_time_ms[pos]; }
806 if (meas_time_ms[pos] > max_wait) { max_wait = meas_time_ms[pos]; }
807 } else {
808 Serial.print("Address ");
809 Serial.print(address);
810 Serial.println(" is not active");
811 }
812 }
813 // min_wait = 800;
814 min_wait = max(static_cast<uint32_t>(10), min_wait / 2);
815 max_wait = max(static_cast<uint32_t>(1000),
816 max_wait + static_cast<uint32_t>(2000));
817 Serial.print("minimum expected wait for all sensors: ");
818 Serial.println(min_wait);
819 Serial.print("maximum expected wait for all sensors: ");
820 Serial.println(max_wait);
821
822#if defined(TEST_PRINT_ARRAY)
823 Serial.print("address_number,\t");
824 Serial.print("address,\t");
825 Serial.print("position,\t");
826 Serial.print("isActive[i],\t");
827 Serial.print("millis,\t");
828 Serial.print("timeWaited,\t");
829 Serial.print("millisReady[i],\t");
830 Serial.print("expectedResults[i],\t");
831 Serial.print("returnedResults[i],\t");
832 Serial.print("millis() > millisReady[i],\t");
833 Serial.print("expectedResults[i] > 0,\t");
834 Serial.print("returnedResults[i] < expectedResults[i],\t");
835 Serial.print("numSensors,\t");
836 Serial.print("numReadingsRecorded,\t");
837 Serial.print("maxDataCommand,\t");
838 Serial.print("resultsReceived,\t");
839 Serial.print("errorCode,\t");
840 Serial.print("crcMatch,\t");
841 Serial.print("gotGoodResults,\t");
842 Serial.print("numReadingsRecorded");
843 Serial.println();
844#endif
845
846 uint8_t numReadingsRecorded = 0;
847 delay(min_wait);
848
849 do {
850 // get all readings
851 for (int8_t address_number = firstAddress; address_number <= lastAddress;
852 address_number++) {
853 int8_t pos = address_number - firstAddress;
854 uint32_t timeWaited = 0;
855 if (millisStarted[pos] != 0) { timeWaited = millis() - millisStarted[pos]; }
856 if (this_result[pos] != "") { prev_result[pos] = this_result[pos]; }
857
858 char addr = decToChar(address_number);
859
860#if defined(TEST_PRINT_ARRAY)
861 Serial.print(address_number);
862 Serial.print(",\t\"");
863 Serial.print(decToChar(address_number));
864 Serial.print("\",\t");
865 Serial.print(pos);
866 Serial.print(",\t\"");
867 Serial.print(isActive[pos]);
868 Serial.print(",\t");
869 Serial.print(millis());
870 Serial.print(",\t");
871 Serial.print(timeWaited);
872 Serial.print(",\t");
873 Serial.print(millisReady[pos]);
874 Serial.print(",\t");
875 Serial.print(expectedResults[pos]);
876 Serial.print(",\t");
877 Serial.print(returnedResults[pos]);
878 Serial.print(",\t");
879 Serial.print(millis() > millisReady[pos]);
880 Serial.print(",\t");
881 Serial.print(expectedResults[pos] > 0);
882 Serial.print(",\t");
883 Serial.print(returnedResults[pos] < expectedResults[pos]);
884 Serial.print(",\t");
885 Serial.print(numSensors);
886 Serial.print(",\t");
887 Serial.print(numReadingsRecorded);
888#endif
889
890 if (isActive[pos] && (millis() > millisReady[pos]) &&
891 (expectedResults[pos] > 0) &&
892 (returnedResults[pos] < expectedResults[pos])) {
893#ifndef TEST_PRINT_ARRAY
894 Serial.print("timeWaited: ");
895 Serial.println(timeWaited);
896#endif
897 getResultsResult cResult = getResults(addr, expectedResults[pos], true);
898 returnedResults[pos] = cResult.resultsReceived;
899 bool gotGoodResults = cResult.success;
900 if (gotGoodResults) {
901 numReadingsRecorded++;
902#ifndef TEST_PRINT_ARRAY
903 Serial.print("Got results from ");
904 Serial.print(numReadingsRecorded);
905 Serial.print(" of ");
906 Serial.print(numSensors);
907 Serial.print(" sensors");
908#endif
909 }
910#if defined(TEST_PRINT_ARRAY)
911 Serial.print(",\t");
912 Serial.print(cResult.maxDataCommand);
913 Serial.print(",\t");
914 Serial.print(cResult.resultsReceived);
915 Serial.print(",\t");
916 Serial.print(cResult.errorCode);
917 Serial.print(",\t");
918 Serial.print(cResult.crcMatch);
919 Serial.print(",\t");
920 Serial.print(gotGoodResults);
921#endif
922 }
923 }
924
925 } while (millis() - for_start < max_wait && numReadingsRecorded < numSensors);
926 }
927 Serial.print("Total Time for Concurrent Measurements: ");
928 Serial.println(millis() - start);
929 }
930
931 Serial.println("-------------------------------------------------------------------"
932 "------------");
933}