I2C Behavior
Notice: This page is an original repo-authored summary informed by Atlas Scientific documentation. It is not an official Atlas Scientific manual.
Purpose
This page documents the I2C behavior that matters to ezo_send_command(), ezo_read_response(), and future I2C adapters.
Core Model
The repo treats EZO I2C as an addressed command-and-response device model:
- write an ASCII command to a device address
- wait long enough for the device to process it
- perform a later addressed read to fetch the response frame
That is why the transport contract is a single injected write_then_read(...) callback in src/ezo_i2c.h.
Response Frame Shape
At the repo level, an I2C response frame is interpreted as:
- one status byte
- an ASCII payload when present
- a terminating null byte in the text-oriented path
The current implementation centralizes this in src/ezo_i2c.c.
Status Byte Mapping
The core maps the vendor status model into ezo_device_status_t:
1-> success2-> fail / syntax-style error254-> not ready255-> no data
Unknown status bytes are treated as protocol errors.
An important contract point is that a valid device status is separate from the library result code:
EZO_OKmeans the transport and frame decode succeeded- the device status tells the caller whether the sensor had data, was ready, or rejected the request
- send helpers clear the cached last status before a new command
- read helpers refresh that cached status from the next decoded response
Timing And Read Discipline
I2C callers own timing in the same way UART callers do.
The generic timing hints in src/ezo.c are only broad defaults. Vendor documentation shows product-specific and command-specific delays, so the safest model is:
- use repo timing hints as fallback
- use product knowledge when you have it
- do not assume one wait time is correct for every EZO board
If a high-level product summary and a protocol-specific command table disagree slightly, prefer the product-aware or command-aware interpretation over the generic fallback.
NOT_READY is a normal part of the protocol, not a transport failure.
Commands With No Useful Immediate Response
Some command families can reboot the board, change protocol state, or enter sleep. In practice that means a caller may see:
- no useful follow-up payload
- a need to re-establish the expected mode
- a stale response if old bytes were not drained in an adapter layer
Those cases belong to product or protocol-control logic above the raw I2C transport surface.
Repo Implications
The current I2C layer intentionally keeps these boundaries:
- send and read are separate operations
- text reads and raw reads are separate operations
- caller code inspects
ezo_device_status_t - the core does not auto-retry
NOT_READY
That is the right baseline for a driver library. Future product-aware helpers should build on top of these explicit primitives rather than hiding them.