#include <src/SDI12Recorder.h>
SDI12Recorder
class
High-level SDI-12 recorder transaction executor.
- Reference
- Detailed Descriptions
A transaction is a complete request-response exchange with a single sensor, including wake-up, command transmission, response collection, validation, and automatic retries according to the SDI-12 specification.
Usage:
Public types
- struct Identification
- Parsed response to an SDI-12 identification command.
- enum RecorderResult: uint8_t { RESULT_NONE = 0x00, RESULT_SUCCESS = 0x01, RESULT_NO_RESPONSE = 0x02, RESULT_FRAMING_ERROR = 0x03, RESULT_WRONG_ADDRESS = 0x04, RESULT_CRC_ERROR = 0x05, RESULT_BUFFER_OVERFLOW = 0x06, RESULT_MALFORMED_RESPONSE = 0x07, RESULT_RESPONSE_TIMEOUT = 0x08, RESULT_TRANSACTION_TIMEOUT = 0x09, RESULT_CANCELLED = 0x0A, RESULT_INVALID_ADDRESS = 0x0B, RESULT_INVALID_COMMAND_ARGUMENT = 0x0C, RESULT_BUSY = 0x0D, RESULT_CONTEXT_CAPACITY = 0x0E, RESULT_CONTEXT_REQUIRED = 0x0F, RESULT_DATA_BUFFER_TOO_SMALL = 0x10, RESULT_MEASUREMENT_ABORTED = 0x11, RESULT_INCOMPLETE_DATA = 0x12, RESULT_RETRIES_EXHAUSTED = 0x13, RESULT_UNEXPECTED_BREAK = 0x14 }
- Terminal result of a transaction.
- enum MeasurementState: uint8_t { MEASUREMENT_NONE = 0x00, MEASUREMENT_RUNNING = 0x01, MEASUREMENT_READY = 0x02 }
- Retained measurement state for one sensor address.
-
using RecorderResult = enum SDI12Recorder::
RecorderResult - Terminal result of a transaction.
-
using MeasurementState = enum SDI12Recorder::
MeasurementState - Retained measurement state for one sensor address.
Public static functions
- static void printSensorInfo(const Identification& identification, Stream& printStream)
- Print parsed sensor identification fields with descriptive labels.
Constructors, destructors, conversion operators
- SDI12Recorder(SDI12& sdi12) explicit
- Construct a recorder bound to an SDI12 transport instance.
- MeasurementState measurementState(char address) const -> MeasurementState
- Retrieve the retained measurement state for one sensor address.
- RecorderResult result() const -> RecorderResult
- Retrieve the terminal result of the completed transaction.
Public functions
- char queryAddress() -> char
- Query the address of the only sensor attached to the bus, blocking until completion.
- bool requestAcknowledgement(char address) -> bool
- Request acknowledgement from one sensor, blocking until completion.
- bool identify(char address, Identification& identification) -> bool
- Request and parse identification information, blocking until completion.
- bool changeAddress(char oldAddress, char newAddress) -> bool
- Change a sensor address, blocking until completion.
- void startQueryAddress()
- Start a non-blocking address query.
- void startRequestAcknowledgement(char address)
- Start a non-blocking acknowledgement request.
- void startIdentify(char address)
- Start a non-blocking identification request.
- void startChangeAddress(char oldAddress, char newAddress)
- Start a non-blocking address-change request.
- void startMeasurement(char address, uint8_t measurementNumber = 0U, bool requestCRC = false)
- Start a non-blocking normal measurement request.
- void startConcurrentMeasurement(char address, uint8_t measurementNumber = 0U, bool requestCRC = false)
- Start a non-blocking concurrent measurement request.
- size_t requestContinuousData(char address, float* values, size_t capacity, uint8_t dataOption, bool requestCRC) -> size_t
- Request one continuous measurement and retrieve its values, blocking until completion.
- void startRequestContinuousData(char address, float* values, size_t capacity, uint8_t dataOption, bool requestCRC)
- Start a non-blocking continuous measurement data request.
- void requestData(char address, float* values, size_t capacity)
- Retrieve all values from a retained measurement context.
- void requestDataImmediately(char address, float* values, size_t capacity)
- Attempt to retrieve all retained measurement values immediately.
- size_t measure(char address, float* values, size_t capacity, uint8_t measurementNumber = 0U, bool requestCRC = false) -> size_t
- Perform a normal measurement and retrieve all of its values, blocking until completion.
- bool isMeasurementReady(char address) const -> bool
- Check whether retained measurement data are ready for one sensor.
- void startRawCommand(char address, const String& command)
- Start a low-level raw command transaction.
- void update()
- Advance the transaction state machine.
- bool isBusy() const -> bool
- Check if a transaction is currently active.
- bool isOperationComplete() const -> bool
- Check if the current executor operation has completed.
- void printRecorderResult(Stream& printStream) const
- Print a human-readable description of the current recorder result.
- void printPhase(Stream& printStream) const
- Print a human-readable description of the current executor phase.
- char queriedAddress() const -> char
- Retrieve the address returned by a successful address query.
- char acknowledgedAddress() const -> char
- Retrieve the address returned by a successful acknowledgement.
- const Identification& identification() const -> const Identification&
- Retrieve the most recently parsed identification fields.
- uint16_t measurementSeconds() const -> uint16_t
- Retrieve the advertised time for the most recent measurement request.
- bool measurementServiceRequestReceived() const -> bool
- Check whether the most recent normal measurement completed by service request.
- uint32_t measurementServiceRequestMillis() const -> uint32_t
- Retrieve when the most recent normal-measurement service request began.
- uint32_t measurementAcknowledgementMillis() const -> uint32_t
- Retrieve when the most recent measurement acknowledgement was validated.
- uint8_t expectedValueCount() const -> uint8_t
- Retrieve the advertised value count for the most recent measurement.
- size_t dataValueCount() const -> size_t
- Retrieve the number of values accepted by the current data workflow.
- const char* response() const -> const char*
- Retrieve the collected response, if successful.
- size_t responseLength() const -> size_t
- Retrieve the number of payload characters in response().
- size_t copyResponse(char* destination, size_t capacity) const -> size_t
- Copy the response payload into an application-owned buffer.
- void cancel()
- Cancel the current transaction and return to idle.
- void clearResponse()
- Clear the collected response payload.
Enum documentation
enum SDI12Recorder:: RecorderResult: uint8_t
Terminal result of a transaction.
Each result code corresponds to a specific terminal condition. The recorder publishes these results to allow the application to decide on retry strategy (e.g., try a different sensor, abandon this measurement, etc.).
| Enumerators | |
|---|---|
| RESULT_NONE |
Transaction is in progress or has not been started. |
| RESULT_SUCCESS |
Transaction completed successfully; response is valid and available. |
| RESULT_NO_RESPONSE |
No response was received within the maximum allowed time. |
| RESULT_FRAMING_ERROR |
Response arrived but had invalid framing or parity. |
| RESULT_WRONG_ADDRESS |
Response address does not match the command address. |
| RESULT_CRC_ERROR |
CRC validation failed (if CRC was requested). |
| RESULT_BUFFER_OVERFLOW |
Response buffer overflowed before response completed. |
| RESULT_MALFORMED_RESPONSE |
Response-specific format validation failed. |
| RESULT_RESPONSE_TIMEOUT |
Response deadline (command-specific max time) was exceeded. |
| RESULT_TRANSACTION_TIMEOUT |
Overall transaction deadline was exceeded (retries not attempted). |
| RESULT_CANCELLED |
Transaction was cancelled by the application. |
| RESULT_INVALID_ADDRESS |
The supplied sensor address is not valid for the requested operation. |
| RESULT_INVALID_COMMAND_ARGUMENT |
A command-specific argument is outside its permitted range. |
| RESULT_BUSY |
A new operation was rejected because another operation is active. |
| RESULT_CONTEXT_CAPACITY |
No tracking slot is available for a new pending sensor transaction. |
| RESULT_CONTEXT_REQUIRED |
The requested operation requires pending measurement context. |
| RESULT_DATA_BUFFER_TOO_SMALL |
The caller-provided data buffer cannot hold all returned values. |
| RESULT_MEASUREMENT_ABORTED |
The sensor reported that its pending measurement was aborted. |
| RESULT_INCOMPLETE_DATA |
The advertised value count was not received by the end of D9. |
| RESULT_RETRIES_EXHAUSTED |
All protocol-required retry attempts were exhausted. |
| RESULT_UNEXPECTED_BREAK |
Another recorder break interrupted a normal measurement workflow. |
enum SDI12Recorder:: MeasurementState: uint8_t
Retained measurement state for one sensor address.
| Enumerators | |
|---|---|
| MEASUREMENT_NONE |
No pending measurement context is retained for the address. |
| MEASUREMENT_RUNNING |
A concurrent measurement is still within its advertised measurement time. |
| MEASUREMENT_READY |
Measurement data are ready to retrieve. |
Typedef documentation
typedef enum SDI12Recorder:: RecorderResult SDI12Recorder:: RecorderResult
Terminal result of a transaction.
Each result code corresponds to a specific terminal condition. The recorder publishes these results to allow the application to decide on retry strategy (e.g., try a different sensor, abandon this measurement, etc.).
Function documentation
static void SDI12Recorder:: printSensorInfo(const Identification& identification,
Stream& printStream)
Print parsed sensor identification fields with descriptive labels.
| Parameters | |
|---|---|
| identification | Parsed identification information to print. |
| printStream | Stream that will receive the identification information. |
A trailing newline is printed after the sensor-information field.
SDI12Recorder:: SDI12Recorder(SDI12& sdi12) explicit
Construct a recorder bound to an SDI12 transport instance.
| Parameters | |
|---|---|
| sdi12 | Reference to the SDI12 object that owns the data line. |
MeasurementState SDI12Recorder:: measurementState(char address) const
Retrieve the retained measurement state for one sensor address.
| Parameters | |
|---|---|
| address | Sensor address to query. |
| Returns | MeasurementState No context, concurrent measurement running, or data ready. |
Concurrent readiness is evaluated with rollover-safe elapsed-time arithmetic. This query does not start a bus operation or change executor completion state.
RecorderResult SDI12Recorder:: result() const
Retrieve the terminal result of the completed transaction.
| Returns | RecorderResult The result code. Returns RESULT_BUSY immediately after an operation was rejected while another transaction is active. Otherwise returns RESULT_NONE while the transaction is in progress. |
|---|
char SDI12Recorder:: queryAddress()
Query the address of the only sensor attached to the bus, blocking until completion.
| Returns | char The sensor address, or the null character on failure. Use result() for the detailed terminal reason. |
|---|
Sends ?! and accepts exactly one valid sensor address followed by CR/LF.
bool SDI12Recorder:: requestAcknowledgement(char address)
Request acknowledgement from one sensor, blocking until completion.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| Returns | bool true only when the correctly addressed acknowledgement is validated. |
Sends a! and requires the addressed sensor to return exactly a followed by CR/LF.
bool SDI12Recorder:: identify(char address,
Identification& identification)
Request and parse identification information, blocking until completion.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| identification | Destination updated only after a validated response. |
| Returns | bool true when identification was updated; otherwise false. |
Sends aI! and validates the fixed identification fields plus the optional 0-13 character sensor-information field.
bool SDI12Recorder:: changeAddress(char oldAddress,
char newAddress)
Change a sensor address, blocking until completion.
| Parameters | |
|---|---|
| oldAddress | Current sensor address. |
| newAddress | New sensor address. |
| Returns | bool true only when the new address is acknowledged. |
Sends aAb! and requires the sensor to acknowledge with the new address followed by CR/LF. After the acknowledgement, this function waits one second for the sensor to finish processing the address change.
void SDI12Recorder:: startQueryAddress()
Start a non-blocking address query.
Call update() until isOperationComplete() is true, then read queriedAddress() after a successful result.
void SDI12Recorder:: startRequestAcknowledgement(char address)
Start a non-blocking acknowledgement request.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
void SDI12Recorder:: startIdentify(char address)
Start a non-blocking identification request.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
Call update() until isOperationComplete() is true, then read identification() after a successful result.
void SDI12Recorder:: startChangeAddress(char oldAddress,
char newAddress)
Start a non-blocking address-change request.
| Parameters | |
|---|---|
| oldAddress | Current sensor address. |
| newAddress | New sensor address. |
The operation remains busy for one second after a valid acknowledgement so the sensor can finish processing the address change.
void SDI12Recorder:: startMeasurement(char address,
uint8_t measurementNumber = 0U,
bool requestCRC = false)
Start a non-blocking normal measurement request.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| measurementNumber | Zero for the unnumbered command, or 1 through 9. |
| requestCRC | true to request the MC command family and require CRC on the later data response. |
Sends aM!, aM1! through aM9!, aMC!, or aMC1! through aMC9!. After validating the acknowledgement, the recorder remains busy until the sensor sends its service request or the advertised measurement time expires. On success, the pending data context is retained for a later data request.
void SDI12Recorder:: startConcurrentMeasurement(char address,
uint8_t measurementNumber = 0U,
bool requestCRC = false)
Start a non-blocking concurrent measurement request.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| measurementNumber | Zero for the unnumbered command, or 1 through 9. |
| requestCRC | true to request the CC command family and require CRC on the later data response. |
Sends aC!, aC1! through aC9!, aCC!, or aCC1! through aCC9!. The executor operation completes after a valid atttnn acknowledgement while the per-address measurement context remains running or ready independently.
size_t SDI12Recorder:: requestContinuousData(char address,
float* values,
size_t capacity,
uint8_t dataOption,
bool requestCRC)
Request one continuous measurement and retrieve its values, blocking until completion.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| values | Caller-owned destination for parsed values. May be null only when capacity is zero. |
| capacity | Number of float elements available in values. |
| dataOption | Continuous measurement data option from 0 through 9. |
| requestCRC | true to use the RC command family and validate the response CRC. |
| Returns | size_t Number of values written on success, or zero on failure or a valid zero-value response. Use result() to distinguish those outcomes. |
Sends aR0! through aR9! or aRC0! through aRC9!. Each data option is an independent measurement; options do not need to be requested in sequence. An address-only response is a successful zero-value result indicating that the sensor cannot provide the requested continuous measurement.
void SDI12Recorder:: startRequestContinuousData(char address,
float* values,
size_t capacity,
uint8_t dataOption,
bool requestCRC)
Start a non-blocking continuous measurement data request.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| values | Caller-owned destination for parsed values. May be null only when capacity is zero. |
| capacity | Number of float elements available in values. |
| dataOption | Continuous measurement data option from 0 through 9. |
| requestCRC | true to use the RC command family and validate the response CRC. |
Sends aR0! through aR9! or aRC0! through aRC9! and strictly validates the immediate data response. Call update() until isOperationComplete() is true. The caller-owned buffer must remain valid and must not be modified until the operation completes or is cancelled.
void SDI12Recorder:: requestData(char address,
float* values,
size_t capacity)
Retrieve all values from a retained measurement context.
| Parameters | |
|---|---|
| address | Sensor address with retained measurement context. |
| values | Caller-owned destination for the parsed values. May be null only when the advertised value count is zero. |
| capacity | Number of float elements available in values. |
The recorder waits for a concurrent measurement to become ready, then generates D0 through D9 as needed. Each response is strictly validated and an optional CRC is checked according to the measurement that established the context.
Call update() until isOperationComplete() is true. The caller-owned buffer must remain valid and must not be modified until the operation completes or is cancelled. Values from each accepted data block are appended exactly once.
void SDI12Recorder:: requestDataImmediately(char address,
float* values,
size_t capacity)
Attempt to retrieve all retained measurement values immediately.
| Parameters | |
|---|---|
| address | Sensor address with retained measurement context. |
| values | Caller-owned destination for the parsed values. May be null only when the advertised value count is zero. |
| capacity | Number of float elements available in values. |
This diagnostic variant starts with D0 immediately, even when a retained concurrent measurement has not reached its advertised ready time. It uses the same typed response parsing, CRC validation, and D0 through D9 workflow as requestData(), but transmits each data command only once. Disabling retries keeps a later successful response from being attributed to the original probe time.
Call update() until isOperationComplete() is true. The caller-owned buffer must remain valid and must not be modified until the operation completes or is cancelled.
size_t SDI12Recorder:: measure(char address,
float* values,
size_t capacity,
uint8_t measurementNumber = 0U,
bool requestCRC = false)
Perform a normal measurement and retrieve all of its values, blocking until completion.
| Parameters | |
|---|---|
| address | Sensor address from 0-9, a-z, or A-Z. |
| values | Caller-owned destination for parsed values. |
| capacity | Number of float elements available in values. |
| measurementNumber | Zero for the unnumbered command, or 1 through 9. |
| requestCRC | true to use the MC command family and validate response CRCs. |
| Returns | size_t Number of values written on success, or zero on failure. Use result() to distinguish failure from a successful zero-value result. |
This convenience method drives startMeasurement(), update(), and requestData() without duplicating their command, validation, retry, or context logic.
bool SDI12Recorder:: isMeasurementReady(char address) const
Check whether retained measurement data are ready for one sensor.
| Parameters | |
|---|---|
| address | Sensor address to query. |
| Returns | bool true when measurementState() is MEASUREMENT_READY. |
void SDI12Recorder:: startRawCommand(char address,
const String& command)
Start a low-level raw command transaction.
| Parameters | |
|---|---|
| address | The SDI-12 address (0-9, a-z, A-Z) of the sensor to query. |
| command | The command body to transmit, without the address or terminating exclamation point. For example, "X" becomes "[address]X!" on the wire. |
This secondary interface supports manufacturer-specific extended commands and commands that do not yet have a typed recorder operation. The recorder transmits address, the unchanged command body, and a terminating exclamation point. It applies the normal break and retry policy, but only requires a non-empty response whose first character matches address. The remainder of the response is retained without command-specific validation or CRC checking.
Call update() until isOperationComplete() is true, then inspect result() and response(). Prefer a typed recorder method whenever one represents the desired standard command because typed methods provide command-specific validation and automatic multi-command workflows.
void SDI12Recorder:: update()
Advance the transaction state machine.
Call this method repeatedly (typically in loop()) to drive the transaction forward through its phases: break, mark, transmit, wait, receive, validate, and retry-decision phases. The method performs all work for the current phase and may move to the next phase if guard conditions are satisfied.
The method returns immediately if no work is needed in the current phase (e.g., waiting for a deadline). It is safe to call update() frequently without penalty.
bool SDI12Recorder:: isBusy() const
Check if a transaction is currently active.
| Returns | bool true if an operation has been started and has not yet completed or been cancelled. |
|---|
bool SDI12Recorder:: isOperationComplete() const
Check if the current executor operation has completed.
| Returns | bool true if the active operation has reached a terminal state (success or failure) and result() may be queried. |
|---|
void SDI12Recorder:: printRecorderResult(Stream& printStream) const
Print a human-readable description of the current recorder result.
| Parameters | |
|---|---|
| printStream | Stream that will receive the description. |
The text describes the same RecorderResult returned by result(). No trailing newline is printed.
void SDI12Recorder:: printPhase(Stream& printStream) const
Print a human-readable description of the current executor phase.
| Parameters | |
|---|---|
| printStream | Stream that will receive the description. |
No trailing newline is printed.
char SDI12Recorder:: queriedAddress() const
Retrieve the address returned by a successful address query.
| Returns | char The queried sensor address, or the null character when no successful address query is available. |
|---|
char SDI12Recorder:: acknowledgedAddress() const
Retrieve the address returned by a successful acknowledgement.
| Returns | char The acknowledged address, or the null character when unavailable. |
|---|
This accessor applies to requestAcknowledgement() and changeAddress().
const Identification& SDI12Recorder:: identification() const
Retrieve the most recently parsed identification fields.
| Returns | const Identification& Recorder-owned identification storage. Its fields are empty unless the most recent identification operation completed successfully. |
|---|
uint16_t SDI12Recorder:: measurementSeconds() const
Retrieve the advertised time for the most recent measurement request.
| Returns | uint16_t Measurement time in seconds from a validated atttn or atttnn response, or zero when unavailable or when the sensor reported immediate readiness. |
|---|
bool SDI12Recorder:: measurementServiceRequestReceived() const
Check whether the most recent normal measurement completed by service request.
| Returns | bool true when a validated service request ended the measurement wait; false when the advertised time elapsed or no valid service request is available. |
|---|
uint32_t SDI12Recorder:: measurementServiceRequestMillis() const
Retrieve when the most recent normal-measurement service request began.
| Returns | uint32_t Milliseconds from completion of the validated measurement acknowledgement to observation of the service-request start bit. The value is valid only when measurementServiceRequestReceived() returns true. |
|---|
uint32_t SDI12Recorder:: measurementAcknowledgementMillis() const
Retrieve when the most recent measurement acknowledgement was validated.
| Returns | uint32_t The millis() timestamp captured after validating the acknowledgement for a normal or concurrent measurement. The value is valid after a successful measurement-start operation and until another operation is started. |
|---|
uint8_t SDI12Recorder:: expectedValueCount() const
Retrieve the advertised value count for the most recent measurement.
| Returns | uint8_t Expected number of values from a validated atttn response, or zero when unavailable. |
|---|
size_t SDI12Recorder:: dataValueCount() const
Retrieve the number of values accepted by the current data workflow.
| Returns | size_t Number of values written to the caller-owned data buffer. |
|---|
const char* SDI12Recorder:: response() const
Retrieve the collected response, if successful.
| Returns | const char* The null-terminated response payload. Protocol envelope characters that have already been validated, including the address, CRC, and CR+LF terminator, are excluded. |
|---|
size_t SDI12Recorder:: responseLength() const
Retrieve the number of payload characters in response().
| Returns | size_t The response payload length, excluding the null terminator. |
|---|
size_t SDI12Recorder:: copyResponse(char* destination,
size_t capacity) const
Copy the response payload into an application-owned buffer.
| Parameters | |
|---|---|
| destination | Buffer that will receive the response payload. May be null only when capacity is zero. |
| capacity | Total destination capacity, including its null terminator. |
| Returns | size_t The complete response payload length, excluding the null terminator. |
Copies at most capacity minus one characters and null-terminates the destination whenever destination is not null and capacity is greater than zero. Compare the return value with capacity to detect truncation.
void SDI12Recorder:: cancel()
Cancel the current transaction and return to idle.
Stops all retry logic, releases the SDI-12 transport to listening, and resets the transaction executor to PHASE_IDLE. The result will be set to RESULT_CANCELLED.
void SDI12Recorder:: clearResponse()
Clear the collected response payload.
This does not change the current transaction phase or SDI-12 line state.