This example uses an Arduino as an interactive SDI-12 command terminal, a passive bus monitor, or an interface between PC software and an SDI-12 sensor. It replaces the deprecated g_terminal_window and i_SDI-12_interface examples.
The sketch continuously listens to the SDI-12 bus and forwards each received character to the serial port once. Entering a line in the serial terminal sends it as an SDI-12 command. CR, LF, and CRLF serial line endings are supported.
In the default SDI-12 command mode, the sketch adds ! only when it is missing; all other characters, including lowercase sensor addresses, remain unchanged. Use mode v to send entered text verbatim. Use fb off after selecting verbatim mode for a quiet software interface without input echo or interface messages. The serial line ending terminates the PC message and is not transmitted on the SDI-12 bus.
Because the Arduino remains in listening mode between commands, the sketch can also monitor communication between another data recorder and its sensors. Do not enter commands while using it only as a passive monitor.
PlatformIO Configuration
1; PlatformIO Project Configuration File
4description = SDI-12 Library Example G: SDI-12 Terminal and PC Interface
5src_dir = .piolibdeps/Arduino-SDI-12_ID1486/examples/g_terminal_interface
The Complete Example
2 * @example{lineno} g_terminal_interface.ino
3 * @copyright Stroud Water Research Center
4 * @license This example is published under the BSD-3 license.
5 * @author Kevin M. Smith <SDI12@ethosengineering.org>
6 * @author Ruben Kertesz <github@emnet.net>
7 * @author D. Wasielewski
9 * @brief Example G: Using an Arduino as an SDI-12 terminal and PC interface
11 * This example accepts SDI-12 commands from a serial terminal, forwards SDI-12
12 * traffic to the serial port, and can passively monitor communication between
13 * another recorder and its sensors. It replaces the former terminal-window and
14 * SDI-12-interface examples.
17#include <SDI12Config.h>
18#if (defined(__AVR__) || defined(ARDUINO_ARCH_AVR)) && !defined(SDI12_INTERNAL_PCINT)
19#include <EnableInterrupt.h>
25#define SDI12_DATA_PIN 7
27#ifndef SDI12_POWER_PIN
28#define SDI12_POWER_PIN 22
30#ifndef SDI12_TERMINAL_BAUD
31#define SDI12_TERMINAL_BAUD 115200
34uint32_t serialBaud = SDI12_TERMINAL_BAUD; /*!< The baud rate for the serial port */
35int8_t dataPin = SDI12_DATA_PIN; /*!< The pin of the SDI-12 data bus */
36int8_t powerPin = SDI12_POWER_PIN; /*!< The sensor power pin (or -1) */
38/** Define the SDI-12 bus. */
39SDI12 mySDI12(dataPin);
41bool commandMode = true; /*!< Add a missing ! to commands when true. */
42bool feedback = true; /*!< Echo serial input and print interface messages. */
44const unsigned int maxSerialMessageLength = SDI12_BUFFER_SIZE -
45 1U; /*!< Maximum accepted serial input line length. */
47/** Print the commands understood by this interface. */
49 Serial.println(F("OPTIONS:"));
50 Serial.println(F("help : Print this message"));
51 Serial.println(F("mode s : SDI-12 command mode; a missing ! is added [default]"));
52 Serial.println(F("mode v : Verbatim mode; text is sent unchanged"));
54 F("fb on : Echo typed characters and print interface messages [default]"));
55 Serial.println(F("fb off : Disable input echo and interface messages"));
56 Serial.println(F("Anything else is sent to the SDI-12 bus."));
60 * @brief Process one complete line received from the serial port.
62 * The PC must send one command at a time and wait for its SDI-12 transmission
63 * to finish before sending the next command. The sketch does not read the
64 * serial port while sendCommand() is running, so input received during the
65 * transmission can overflow the serial receive buffer.
67void processSerialMessage(String& message) {
68 String lowerMessage = message;
69 lowerMessage.toLowerCase();
71 if (lowerMessage == "help") {
73 } else if (lowerMessage == "mode s") {
76 Serial.println(F("SDI-12 command mode; a missing ! will be added."));
78 } else if (lowerMessage == "mode v") {
80 if (feedback) { Serial.println(F("Verbatim mode; text will be sent unchanged.")); }
81 } else if (lowerMessage == "fb off") {
82 if (feedback) { Serial.println(F("Feedback off.")); }
84 } else if (lowerMessage == "fb on") {
86 Serial.println(F("Feedback on."));
88 if (commandMode && !message.endsWith("!")) { message += '!'; }
89 mySDI12.sendCommand(message);
95/** Read one serial character and assemble complete CR-, LF-, or CRLF-ended lines. */
96void readSerialInput() {
97 static String serialMessage;
98 static bool previousWasCarriageReturn = false;
99 static bool discardingLine = false;
101 if (!Serial.available()) { return; }
103 char incoming = static_cast<char>(Serial.read());
104 if (incoming == '\r') {
105 previousWasCarriageReturn = true;
106 if (feedback) { Serial.println(); }
107 if (!discardingLine && serialMessage.length() > 0) {
108 processSerialMessage(serialMessage);
111 discardingLine = false;
112 } else if (incoming == '\n') {
113 if (previousWasCarriageReturn) {
114 previousWasCarriageReturn = false;
117 if (feedback) { Serial.println(); }
118 if (!discardingLine && serialMessage.length() > 0) {
119 processSerialMessage(serialMessage);
122 discardingLine = false;
123 } else if (discardingLine) {
124 previousWasCarriageReturn = false;
125 } else if (incoming == '\b' || incoming == 0x7F) {
126 previousWasCarriageReturn = false;
127 if (serialMessage.length() > 0) {
128 serialMessage.remove(serialMessage.length() - 1);
129 if (feedback) { Serial.print(F("\b \b")); }
132 previousWasCarriageReturn = false;
133 if (serialMessage.length() >= maxSerialMessageLength) {
135 discardingLine = true;
136 if (feedback) { Serial.println(F("\n[Serial input line too long; discarded]")); }
138 serialMessage += incoming;
139 if (feedback) { Serial.print(incoming); }
144/** Forward all received SDI-12 traffic to the serial port exactly once. */
145void forwardSDI12Input() {
146 if (mySDI12.available() < 0) {
147 mySDI12.clearBuffer();
148 if (feedback) { Serial.println(F("[SDI-12 receive buffer overflow]")); }
152 while (mySDI12.available() > 0) {
153 int incoming = mySDI12.read();
154 if (incoming >= 0) { Serial.write(static_cast<uint8_t>(incoming)); }
159 Serial.begin(serialBaud);
160 while (!Serial && millis() < 10000L) {}
163 Serial.println(F("Powering up sensors..."));
164 pinMode(powerPin, OUTPUT);
165 digitalWrite(powerPin, HIGH);
169 Serial.print(F("Opening SDI-12 bus on pin "));
170 Serial.print(dataPin);
171 Serial.println(F("..."));
173 mySDI12.forceListen();
184// cSpell:ignore Kertesz Wasielewski