#include <src/SDI12.h>
SDI12 class

The main class for SDI 12 instances.

Public types

enum SDI12_LINE_EVENT: uint8_t { SDI12_LINE_EVENT_NONE = 0x00, SDI12_LINE_EVENT_BREAK_THRESHOLD_REACHED = 0x01, SDI12_LINE_EVENT_BREAK_COMPLETED = 0x02, SDI12_LINE_EVENT_MARKING_THRESHOLD_REACHED = 0x04, SDI12_LINE_EVENT_MARKING_COMPLETED = 0x08 }
Line-condition events published by the transport ISR.
enum SDI12_RECEIVE_EVENT: uint8_t { SDI12_RECEIVE_EVENT_NONE = 0x00, SDI12_RECEIVE_EVENT_START_BIT_OBSERVED = 0x01, SDI12_RECEIVE_EVENT_CHARACTER_COMPLETED = 0x02, SDI12_RECEIVE_EVENT_MESSAGE_COMPLETED = 0x04, SDI12_RECEIVE_EVENT_FRAMING_ERROR = 0x08, SDI12_RECEIVE_EVENT_BUFFER_OVERFLOW = 0x10, SDI12_RECEIVE_EVENT_COMMAND_COMPLETED = 0x20 }
Character-receive events published by the transport ISR.
using SDI12_LINE_EVENT = enum SDI12::SDI12_LINE_EVENT
Line-condition events published by the transport ISR.
using SDI12_RECEIVE_EVENT = enum SDI12::SDI12_RECEIVE_EVENT
Character-receive events published by the transport ISR.

Public static functions

static uint8_t parity_even_bit(uint8_t v) -> uint8_t
Calculate the parity value for a character using even parity.
static void publishEvent(volatile uint8_t& flags, uint8_t event)
Atomically publish an ISR-owned event flag.
static uint8_t takeEvents(volatile uint8_t& flags) -> uint8_t
Atomically consume and clear a set of ISR-owned event flags.

Public functions

void setPinInterrupts(bool enable)
Set the pin interrupts to be on (enabled) or off (disabled).
void setLineState(SDI12_LINE_STATE state)
Set the the state of the SDI12 object.
void resetEdgeState(bool listening, sdi12timer_t timerTime, uint8_t pinLevel)
Reset edge-history state when listening begins or line ownership changes.
uint8_t observeLineEdge(sdi12timer_t timerTime, uint8_t pinLevel) -> uint8_t
Classify the line interval ending at one captured edge.
void routeEdge()
Route one captured edge to line observation and character decoding.
void forceHold()
Set line state to SDI12_HOLDING.
void forceListen()
Set line state to SDI12_LISTENING.
void startBreak()
Begin driving a recorder break without waiting for it to complete.
void startMarking()
Begin driving recorder marking without waiting for it to complete.
uint8_t takeLineEvents() -> uint8_t
Atomically consume all pending line-condition events.
uint8_t takeReceiveEvents() -> uint8_t
Atomically consume all pending character-receive events.
void serviceLineConditions()
Service continuous line conditions that can reach a threshold without an edge.
uint16_t calculateCRC(String& resp) -> uint16_t
Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.
uint16_t calculateCRC(const char* resp) -> uint16_t
Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.
uint16_t calculateCRC(FlashString resp) -> uint16_t
Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.
String crcToString(uint16_t crc) -> String
Converts a numeric 16-bit CRC to an ASCII String.
bool verifyCRC(String& respWithCRC) -> bool
Verifies that the CRC returned at the end of an SDI-12 message matches that of the content of the message.

Constructor, Destructor, Begins, and Setters

These functions set up the SDI-12 object and prepare it for use.

int16_t TIMEOUT
The value to return if a parse or read times out with no return from the sensor.
SDI12()
Construct a new SDI12 instance with no data pin set.
SDI12(int8_t dataPin) explicit
Construct a new SDI12 with the data pin set.
~SDI12()
Destroy the SDI12 object.
void begin()
Begin the SDI-12 object.
void begin(int8_t dataPin)
Set the SDI12::_datapin and begin the SDI-12 object.
void end()
Disable the SDI-12 object (but do not destroy it).
int16_t getTimeoutValue() -> int16_t
Get the current value that will be returned IF a parse int or parse float times out with no return from the sensor.
void setTimeoutValue(int16_t value)
Set the value to return if a parse int or parse float times out with no return from the sensor.
int8_t getDataPin() -> int8_t
Get the data pin for the current SDI-12 instance.
void setDataPin(int8_t dataPin)
Set the data pin for the current SDI-12 instance.

Reading from the SDI-12 Buffer

These functions are for reading incoming data stored in the SDI-12 buffer.

int available() -> int override
Return the number of bytes available in the Rx buffer.
int peek(bool use_parity) -> int
Reveal the next byte in the Rx buffer without consuming it.
int peek() -> int override
Reveal the next byte (7E1) in the Rx buffer without consuming it.
int peekBinary(void) -> int
Reveal the next byte (8N1) at the head of the Rx buffer without consuming it.
void clearBuffer()
Clear the Rx buffer by setting the head and tail pointers to the same value.
int read(bool use_parity) -> int
Return next byte in the Rx buffer, consuming it.
int read() -> int override
Return next byte in the Rx buffer excluding parity bit, consuming it.
int readBinary(void) -> int
Return the next byte in the Rx buffer including the 8th bit, consuming it.
size_t readBinary(char* output, size_t length) -> size_t
Return up to length bytes before timeout and store them in output.
int timedReadBinary(void) -> int
Reads the next byte from the buffer (and moves the index ahead) with timeout.
void flush() override
Wait for sending to finish - because no TX buffering and the write function is blocking, we don't need to do anything.
unsigned long getTimeout() -> unsigned long
Get the current stream timeout time.
long parseInt(LookaheadMode = SKIP_NONE, char = '+') -> long
Return the first valid (long) integer value from the current position.
float parseFloat(LookaheadMode = SKIP_NONE, char = '+') -> float
Return the first valid float value from the current position.

Using more than one SDI-12 Object

Functions needed for multiple instances of the SDI12 class.

This library is allows for multiple instances of itself running on the same or different pins. SDI-12 can support up to 62 sensors on a single pin/bus, so it is not necessary to use an instance for each sensor.

Because we are using pin change interrupts there can only be one active object at a time (since this is the only reliable way to determine which pin the interrupt occurred on). The active object is the only object that will respond properly to interrupts. However promoting another instance to Active status does not automatically remove the interrupts on the other pin. For proper behavior it is recommended to use this pattern:

1mySDI12.forceHold();
2myOtherSDI12.setActive();
bool setActive() -> bool
Set this instance as the active SDI-12 instance.
bool isActive() -> bool
Check if this instance is active.

Waking Up and Talking To Sensors

These functions are needed to communicate with SDI-12 sensors (slaves) or an SDI-12 data logger (master).

size_t write(uint8_t byte) -> size_t virtual
Write out a byte using 7E1 parity on the SDI-12 line.
size_t write(const uint8_t* buffer, size_t size) -> size_t virtual
Write out multiple bytes using 7E1 parity on the SDI-12 line.
template<typename T>
size_t writeBytes(T value) -> size_t
Write out number of bytes on the SDI-12 line, least significant byte first (little-endian transmission).
void sendCommand(String& cmd, int8_t extraWakeTime = 0) deprecated
Send a command out on the data line, acting as a data logger (master).
void sendCommand(const char* cmd, int8_t extraWakeTime = 0) deprecated
Send a command out on the data line, acting as a data logger (master).
void sendCommand(FlashString cmd, int8_t extraWakeTime = 0) deprecated
Send a command out on the data line, acting as a data logger (master).
void sendResponse(String& resp, bool addCRC = false) deprecated
Send a response out on the data line (for slave use).
void sendResponse(const char* resp, bool addCRC = false) deprecated
Send a response out on the data line (for slave use).
void sendResponse(FlashString resp, bool addCRC = false) deprecated
Send a response out on the data line (for slave use).

Interrupt Service Routine

Functions for handling interrupts - responding to changes on the data line and converting them to characters in the Rx buffer.

static void handleInterrupt()
Intermediary used by the ISR - passes off responsibility for the interrupt to the active object.

Enum documentation

enum SDI12::SDI12_LINE_EVENT: uint8_t

Line-condition events published by the transport ISR.

Events are coalescing flags. The basic SDI12 class publishes them, and recorder or sensor classes consume all pending flags with takeLineEvents(). The events do not carry timestamps: Completion events flags are set when the interrupt service routine catches an edge. Threshold events event flags are set when the sensor or recorder calls the serviceLineConditions() function to check for them.

Enumerators
SDI12_LINE_EVENT_NONE

No line event is pending.

SDI12_LINE_EVENT_BREAK_THRESHOLD_REACHED

Continuous spacing reached the minimum break duration.

SDI12_LINE_EVENT_BREAK_COMPLETED

A spacing interval reached the break minimum and ended.

SDI12_LINE_EVENT_MARKING_THRESHOLD_REACHED

Continuous marking reached the pre-character minimum.

SDI12_LINE_EVENT_MARKING_COMPLETED

A marking interval reached the required minimum and ended.


enum SDI12::SDI12_RECEIVE_EVENT: uint8_t

Character-receive events published by the transport ISR.

Events describe observed transport facts, not retry or protocol-role policy. They are coalescing flags consumed by takeReceiveEvents().

Enumerators
SDI12_RECEIVE_EVENT_NONE

No receive event is pending.

SDI12_RECEIVE_EVENT_START_BIT_OBSERVED

A start bit was observed.

SDI12_RECEIVE_EVENT_CHARACTER_COMPLETED

A character was reconstructed.

SDI12_RECEIVE_EVENT_MESSAGE_COMPLETED

A CR LF response terminator was seen.

SDI12_RECEIVE_EVENT_FRAMING_ERROR

An incomplete character was reset.

SDI12_RECEIVE_EVENT_BUFFER_OVERFLOW

A character could not enter the buffer.

SDI12_RECEIVE_EVENT_COMMAND_COMPLETED

An exclamation-point command terminator was seen.



Typedef documentation

typedef enum SDI12::SDI12_LINE_EVENT SDI12::SDI12_LINE_EVENT

Line-condition events published by the transport ISR.

Events are coalescing flags. The basic SDI12 class publishes them, and recorder or sensor classes consume all pending flags with takeLineEvents(). The events do not carry timestamps: Completion events flags are set when the interrupt service routine catches an edge. Threshold events event flags are set when the sensor or recorder calls the serviceLineConditions() function to check for them.


typedef enum SDI12::SDI12_RECEIVE_EVENT SDI12::SDI12_RECEIVE_EVENT

Character-receive events published by the transport ISR.

Events describe observed transport facts, not retry or protocol-role policy. They are coalescing flags consumed by takeReceiveEvents().



Function documentation

static uint8_t SDI12::parity_even_bit(uint8_t v)

Calculate the parity value for a character using even parity.

Parameters
v uint8_t (char) the character to calculate the parity of
Returns uint8_t The input character with the 8th bit set to the even parity value for that character

Sets up parity and interrupts for different processor types - that is, imports the interrupts and parity for the AVR processors where they exist.

This function is defined in the Arduino core for AVR processors, but must be defined here for SAMD and ESP cores.


static void SDI12::publishEvent(volatile uint8_t& flags, uint8_t event)

Atomically publish an ISR-owned event flag.

Parameters
flags The coalescing flag byte to update.
event The event bits to publish.

static uint8_t SDI12::takeEvents(volatile uint8_t& flags)

Atomically consume and clear a set of ISR-owned event flags.

Parameters
flags The coalescing flag byte to consume.
Returns uint8_t The pending event bits before the flag byte was cleared.

void SDI12::setPinInterrupts(bool enable)

Set the pin interrupts to be on (enabled) or off (disabled).

Parameters
enable True to enable pin interrupts

A private helper function to turn pin interrupts on or off


void SDI12::setLineState(SDI12_LINE_STATE state)

Set the the state of the SDI12 object.

Parameters
state The state the SDI-12 object should be set to, from the SDI12_LINE_STATE enum.

This is a private function, and only used internally.


void SDI12::resetEdgeState(bool listening, sdi12timer_t timerTime, uint8_t pinLevel)

Reset edge-history state when listening begins or line ownership changes.

Parameters
listening True when a new listening interval is beginning.
timerTime The selected timer count at the start of that interval.
pinLevel The physical data-line level at the start of that interval.

uint8_t SDI12::observeLineEdge(sdi12timer_t timerTime, uint8_t pinLevel)

Classify the line interval ending at one captured edge.

Parameters
timerTime The selected SDI-12 timer count at the edge.
pinLevel The new physical data-line level.
Returns uint8_t A bitwise combination of SDI12_LINE_EVENT values published for the edge.

void SDI12::forceHold()

Set line state to SDI12_HOLDING.

A public function which forces the line into a "holding" state. This is generally unneeded, but for deployments where interference is an issue, it should be used after all expected bytes have been returned from the sensor.


void SDI12::forceListen()

Set line state to SDI12_LISTENING.

A public function which forces the line into a "listening" state. This may be needed for implementing a slave-side device, which should relinquish control of the data line when not transmitting.


void SDI12::startBreak()

Begin driving a recorder break without waiting for it to complete.

This low-level operation takes ownership of the data line and drives spacing. The caller is responsible for maintaining the break for the required duration and following it with marking before transmitting a command.


void SDI12::startMarking()

Begin driving recorder marking without waiting for it to complete.

This low-level operation takes ownership of the data line and drives marking. The caller is responsible for maintaining marking for the required duration.


uint8_t SDI12::takeLineEvents()

Atomically consume all pending line-condition events.

Returns uint8_t A bitwise combination of SDI12_LINE_EVENT values.

Multiple occurrences of the same event coalesce until this method is called. The recorder or sensor application must call this method outside an ISR.


uint8_t SDI12::takeReceiveEvents()

Atomically consume all pending character-receive events.

Returns uint8_t A bitwise combination of SDI12_RECEIVE_EVENT values.

Multiple occurrences of the same event coalesce until this method is called. The recorder or sensor application must call this method outside an ISR.


void SDI12::serviceLineConditions()

Service continuous line conditions that can reach a threshold without an edge.

The recorder or sensor application calls this method outside the ISR. It reads only the board-selected bit timer. Call it often enough that the timer cannot complete an unobserved rollover after a threshold is reached. Once a break or marking minimum is latched, later timer rollover cannot undo it; the edge ending that interval consumes the latch.

This method or the ending-edge classifier sets each latch. Latches are reset when listening begins, line ownership changes, an ending edge consumes them, a message completes, or a framing or buffer-overflow condition invalidates receive state.

The 8 MHz, 8-bit Timer2 configuration cannot span either required minimum and remains a documented deferred exception.


uint16_t SDI12::calculateCRC(String& resp)

Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.

Parameters
resp The message to calculate the CRC for.
Returns uint16_t The calculated CRC

uint16_t SDI12::calculateCRC(const char* resp)

Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.

Parameters
resp The message to calculate the CRC for.
Returns uint16_t The calculated CRC

uint16_t SDI12::calculateCRC(FlashString resp)

Calculates the 16-bit Cyclic Redundancy Check (CRC) for an SDI-12 message.

Parameters
resp The message to calculate the CRC for.
Returns uint16_t The calculated CRC

String SDI12::crcToString(uint16_t crc)

Converts a numeric 16-bit CRC to an ASCII String.

Parameters
crc The 16-bit CRC
Returns String An ASCII string for the CRC

From the SDI-12 Specifications:

The 16 bit CRC is encoded as three ASCII characters
using the following algorithm:
    1st character = 0x40 OR (CRC shifted right 12 bits)
    2nd character = 0x40 OR ((CRC shifted right 6 bits) AND 0x3F)
    3rd character = 0x40 OR (CRC AND 0x3F)

bool SDI12::verifyCRC(String& respWithCRC)

Verifies that the CRC returned at the end of an SDI-12 message matches that of the content of the message.

Parameters
respWithCRC The full SDI-12 message, including the CRC at the end.
Returns bool True if the CRC matches and the message is valid, false if the CRC doesn't match and the message could be retried.

SDI12::SDI12()

Construct a new SDI12 instance with no data pin set.

Before using the SDI-12 instance, the data pin must be set with SDI12::setDataPin(dataPin) or SDI12::begin(dataPin). This empty constructor is provided for easier integration with other Arduino libraries.

When the constructor is called it resets the buffer overflow status to FALSE.


SDI12::SDI12(int8_t dataPin) explicit

Construct a new SDI12 with the data pin set.

Parameters
dataPin The data pin's digital pin number

When the constructor is called it resets the buffer overflow status to FALSE and assigns the pin number "dataPin" to the private variable "_dataPin".


SDI12::~SDI12()

Destroy the SDI12 object.

When the destructor is called, it's main task is to disable any interrupts that had been previously assigned to the pin, so that the pin will behave as expected when used for other purposes. This is achieved by putting the SDI-12 object in the SDI12_DISABLED state. After disabling interrupts, the pointer to the current active SDI-12 instance is set to null if it had pointed to the destroyed object. Finally, for AVR board, the timer prescaler is set back to whatever it had been prior to creating the SDI-12 object.


void SDI12::begin()

Begin the SDI-12 object.

This is called to begin the functionality of the SDI-12 object. It sets the object as the active object, sets the stream timeout to 150ms to match SDI-12 specs, sets the timeout return value to SDI12::TIMEOUT, and configures the timer prescaler.


void SDI12::begin(int8_t dataPin)

Set the SDI12::_datapin and begin the SDI-12 object.

Parameters
dataPin The data pin's digital pin number

This is called to begin the functionality of the SDI-12 object. It sets the object as the active object, sets the stream timeout to 150ms to match SDI-12 specs, sets the timeout return value to SDI12::TIMEOUT, and configures the timer prescaler. If the SDI-12 instance is created using the empty constructor, this must be used to set the data pin.


void SDI12::end()

Disable the SDI-12 object (but do not destroy it).

Set the SDI-12 state to disabled, set the pointer to the current active instance to null, and then, for AVR boards, unset the timer prescaler.

This can be called to temporarily cease all functionality of the SDI-12 object. It is not as harsh as destroying the object with the destructor, as it will maintain the memory buffer.


int16_t SDI12::getTimeoutValue()

Get the current value that will be returned IF a parse int or parse float times out with no return from the sensor.

Returns int16_t The current timeout value The timeout return for parseInt and parseFloat of an Arduino stream object when no character is available in the Rx buffer is "0." For environmental sensors (the typical SDI-12 users) 0 is a common result value. To better distinguish between a timeout because of no sensor response and a true zero return, the timeout should be set to some value that is NOT a possible return from that sensor. If the timeout is not set, -9999 is used.

void SDI12::setTimeoutValue(int16_t value)

Set the value to return if a parse int or parse float times out with no return from the sensor.

Parameters
value the value to return on timeout The timeout return for parseInt and parseFloat of an Arduino stream object when no character is available in the Rx buffer is "0." For environmental sensors (the typical SDI-12 users) 0 is a common result value. To better distinguish between a timeout because of no sensor response and a true zero return, the timeout should be set to some value that is NOT a possible return from that sensor. If the timeout is not set, -9999 is used.

int8_t SDI12::getDataPin()

Get the data pin for the current SDI-12 instance.

Returns int8_t The data pin number

void SDI12::setDataPin(int8_t dataPin)

Set the data pin for the current SDI-12 instance.

Parameters
dataPin The data pin's digital pin number

int SDI12::available() override

Return the number of bytes available in the Rx buffer.

Returns int The number of characters in the buffer

available() is a public function that returns the number of characters available in the Rx buffer.

To understand how: _rxBufferTail + SDI12_BUFFER_SIZE - _rxBufferHead) % SDI12_BUFFER_SIZE; accomplishes this task, we will use a few examples.

To start take the buffer below that has SDI12_BUFFER_SIZE = 10. The message "abc" has been wrapped around (circular buffer).

1_rxBufferTail = 1 // points to the '-' after c
2_rxBufferHead = 8 // points to 'a'

[ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ a ] [ b ]

The number of available characters is (1 + 10 - 8) % 10 = 3

The '' or modulo operator finds the remainder of division of one number by another. In integer arithmetic 3 / 10 = 0, but has a remainder of 3. We can only get the remainder by using the the modulo ''. 3 % 10 = 3. This next case demonstrates more clearly why the modulo is used.

1_rxBufferTail = 4 // points to the '-' after c
2_rxBufferHead = 1 // points to 'a'

[ a ] [ b ] [ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ]

The number of available characters is (4 + 10 - 1) % 10 = 3

If we did not use the modulo we would get either ( 4 + 10 - 1 ) = 13 characters or ( 4 + 10 - 1 ) / 10 = 1 character. Obviously neither is correct.

If there has been a buffer overflow, available() will return -1.


int SDI12::peek(bool use_parity)

Reveal the next byte in the Rx buffer without consuming it.

Parameters
use_parity True to verify parity and return a character that excludes the parity bit. If use_parity is set to true and the next character fails the parity check, -1 will be returned.
Returns int The next byte in the character buffer.

peek() is a public function that allows the user to look at the character that is at the head of the buffer. Unlike read() it does not consume the character (i.e. the index addressed by _rxBufferHead is not changed). peek() returns -1 if there are no characters to show.


int SDI12::peek() override

Reveal the next byte (7E1) in the Rx buffer without consuming it.

Returns int The next byte in the character buffer, or -1 if the buffer is empty or the next byte in the buffer doesn't pass parity check.

int SDI12::peekBinary(void)

Reveal the next byte (8N1) at the head of the Rx buffer without consuming it.

Returns int The next byte in the character buffer, or -1 if the buffer is empty.

void SDI12::clearBuffer()

Clear the Rx buffer by setting the head and tail pointers to the same value.

clearBuffer() is a public function that clears the buffers contents by setting the index for both head and tail back to zero.


int SDI12::read(bool use_parity)

Return next byte in the Rx buffer, consuming it.

Parameters
use_parity True to verify parity and return a character that excludes the parity bit. If use_parity is set to true and the next character fails the parity check, -1 will be returned.
Returns int The next byte in the character buffer.

read() returns the character at the current head in the buffer after incrementing the index of the buffer head. This action 'consumes' the character, meaning it can not be read from the buffer again. If you would rather see the character, but leave the index to head intact, you should use peek();


int SDI12::read() override

Return next byte in the Rx buffer excluding parity bit, consuming it.

Returns int The next byte in the character buffer, 7E1, excluding parity.

This is used for standard SDI-12 7E1 characters.


int SDI12::readBinary(void)

Return the next byte in the Rx buffer including the 8th bit, consuming it.

Returns int The next byte in the character buffer, 8N1, including 8th bit!.

size_t SDI12::readBinary(char* output, size_t length)

Return up to length bytes before timeout and store them in output.

Parameters
output out Location in memory where the bytes will be stored.
length in Maximum number of bytes to read from the buffer.
Returns size_t The number of bytes read from the buffer.

readBinary(char* output, size_t length) attempts to read up to length bytes by incrementing the index of the buffer head using


int SDI12::timedReadBinary(void)

Reads the next byte from the buffer (and moves the index ahead) with timeout.

Returns int Byte data from buffer or -1 if buffer is empty or timeout during read

unsigned long SDI12::getTimeout()

Get the current stream timeout time.

Returns unsigned long The current timeout time in milliseconds.

long SDI12::parseInt(LookaheadMode = SKIP_NONE, char = '+')

Return the first valid (long) integer value from the current position.

Returns long The next valid integer in the stream or -9999 if there is a timeout or the next character is not part of an integer.

This function is customized to only return numbers as they are passed in the data command responses.

A data command response is structured [addr][values][CR][LF] or [addr][values][CRC][CR][LF] the value portion must be structred as pd.d

  • p - the polarity sign (+ or -)
  • d - numeric digits before the decimal place
  • . - the decimal point (optional)
  • d - numeric digits after the decimal point
  • the maximum number of digits for a data value is 7, even without a decimal point
  • the minimum number of digits for a data value (excluding the decimal point) is 1
  • the maximum number of characters in a data value is 9 (the (polarity sign + 7 digits + the decimal point))
  • The polarity symbol (+ or -) acts as a delimeter between the numeric values

Because of the well codified structure of the response, we know that we can always set the LookaheadMode to not skip any characters (LookaheadMode::SKIP_NONE), we accept a + or - only as the first character, and we should not ignore any other characters.


float SDI12::parseFloat(LookaheadMode = SKIP_NONE, char = '+')

Return the first valid float value from the current position.

Returns float The first valid float in the stream or -9999 if there is a timeout or the next character is not part of an float.

This is identical to SDI12::parseInt(LookaheadMode, char) except that it looks for a decimal and returns a float.


bool SDI12::setActive()

Set this instance as the active SDI-12 instance.

Returns bool True indicates that the current SDI-12 instance was not formerly the active one and now is. False indicates that the current SDI-12 instance is already the active one and the state was not changed.

A method for setting the current object as the active object; returns TRUE if the object was not formerly the active object and now is.

  • Promoting an inactive to the active instance will start it in the SDI12_HOLDING state and return TRUE.
  • Otherwise, if the object is currently the active instance, it will remain unchanged and return FALSE.

bool SDI12::isActive()

Check if this instance is active.

Returns bool True indicates that the curren SDI-12 instance is the active one.

isActive() is a method for checking if the object is the active object. Returns true if the object is currently the active object, false otherwise.


size_t SDI12::write(uint8_t byte) virtual

Write out a byte using 7E1 parity on the SDI-12 line.

Parameters
byte The character to write
Returns size_t The number of characters written

Sets the state to transmitting, writes a character, and then sets the state back to listening.


size_t SDI12::write(const uint8_t* buffer, size_t size) virtual

Write out multiple bytes using 7E1 parity on the SDI-12 line.

Parameters
buffer The data to write
size The size of the data buffer to write
Returns size_t The number of characters written

Sets the state to transmitting, writes multiple characters, and then sets the state back to listening.


template<typename T>
size_t SDI12::writeBytes(T value)

Write out number of bytes on the SDI-12 line, least significant byte first (little-endian transmission).

Template parameters
T ['value type']
Parameters
value Data to be converted to byte chunks
Returns size_t sizeof( T ), number of bytes written out

Sets the state to transmitting, starts writing byte chunks of value from least significant byte to most significant byte, and then sets the state back to listening.


void SDI12::sendCommand(String& cmd, int8_t extraWakeTime = 0) deprecated

Send a command out on the data line, acting as a data logger (master).

Parameters
cmd the command to send
extraWakeTime The amount of additional time in milliseconds that the sensor takes to wake before being ready to receive a command. Default is 0ms - meaning the sensor is ready for a command by the end of the 12ms break. Per protocol, the wake time must be less than 100 ms.

A publicly accessible function that sends a break to wake sensors and sends out a command byte by byte on the data line.


void SDI12::sendCommand(const char* cmd, int8_t extraWakeTime = 0) deprecated

Send a command out on the data line, acting as a data logger (master).

Parameters
cmd The null-terminated command to send.
extraWakeTime Additional sensor wake time in milliseconds.

void SDI12::sendCommand(FlashString cmd, int8_t extraWakeTime = 0) deprecated

Send a command out on the data line, acting as a data logger (master).

Parameters
cmd The flash-resident command to send.
extraWakeTime Additional sensor wake time in milliseconds.

void SDI12::sendResponse(String& resp, bool addCRC = false) deprecated

Send a response out on the data line (for slave use).

Parameters
resp the response to send
addCRC True to append a CRC to the outgoing response

A publicly accessible function that sends out an 8.33 ms marking and a response byte by byte on the data line. This is needed if the Arduino is acting as an SDI-12 device itself, not as a recorder for another SDI-12 device.


void SDI12::sendResponse(const char* resp, bool addCRC = false) deprecated

Send a response out on the data line (for slave use).

Parameters
resp The null-terminated response to send.
addCRC True to append a CRC to the outgoing response.

void SDI12::sendResponse(FlashString resp, bool addCRC = false) deprecated

Send a response out on the data line (for slave use).

Parameters
resp The flash-resident response to send.
addCRC True to append a CRC to the outgoing response.

static void SDI12::handleInterrupt()

Intermediary used by the ISR - passes off responsibility for the interrupt to the active object.

On espressif boards (ESP8266 and ESP32), the ISR must be stored in IRAM



Variable documentation

int16_t SDI12::TIMEOUT

The value to return if a parse or read times out with no return from the sensor.

The timeout return for parseInt and parseFloat of an Arduino stream object when no character is available in the Rx buffer is "0." For environmental sensors (the typical SDI-12 users) 0 is a common result value. To better distinguish between a timeout because of no sensor response and a true zero return, the timeout should be set to some value that is NOT a possible return from that sensor. If the timeout is not set, -9999 is used.