ezsp 6.0.1

Ember ZNet Serial Protocol
Documentation
# ezsp

Rust implementation of the EmberZNet Serial Protocol (EZSP) host side.

EZSP is the command protocol used by a host application processor to communicate
with the EmberZNet PRO stack running on a Silicon Labs Network Co-Processor
(NCP). The crate models the EZSP command/response surface, frame headers,
parameter payloads, asynchronous callbacks, and the UART transport used by
EZSP-UART NCP firmware.

## Documentation Basis

The crate documentation is based on these Silicon Labs references:

- `UG100: EZSP Reference Guide`, Rev. 5.1, for EmberZNet PRO 7.4.2.
- `UG101: UART-EZSP Gateway Protocol Reference`, Rev. 1.3, for ASHv2 over UART.
- <https://docs.silabs.com/zigbee/latest/sisdk-ezsp-reference-guide/>, which
  currently documents the Simplicity SDK EZSP guide for Zigbee 9.1.0 /
  EmberZNet PRO 8.1 and notes the v8 API/type renaming split from UG100.
- <https://docs.silabs.com/zigbee/6.6/em35x/>, the older EmberZNet API
  reference used by several Ember type descriptions.

The implementation keeps the legacy EZSP naming used throughout UG100 and the
EmberZNet 6.x/7.x API surface where that naming is reflected in the crate.

## Features

- `ashv2`: enables the ASHv2 serial transport (`uart::Uart`).
- `apis-saltans`: enables `apis_saltans_hw` integration for `Ncp`/`Builder` and pulls in `apis-saltans` APS/core/hardware/ZDP crates.
- `semver`: enables `semver` support for EZSP version APIs.

## Protocol Model

EZSP messages are exchanged between a host and an NCP over SPI or UART. This
crate currently provides the UART path via ASHv2.

- The host starts normal EZSP use by sending the `version` command after NCP
  reset. A successful version transaction establishes the protocol version that
  both sides will use.
- EZSP fields wider than one byte are serialized little-endian, including EUI64
  values.
- Frames contain a sequence number, frame control, frame ID, and typed
  parameters. EZSP protocol versions before 8 use a three-byte legacy header;
  versions 8 and newer use the extended five-byte header.
- Most commands form a two-message transaction: host command, then NCP response.
  UART NCPs may also send callbacks asynchronously as they occur.
- The response frame control reports NCP status bits such as overflow,
  truncation, callback-pending state, and callback type.

## UART and ASHv2

UG101 describes ASH as the data-link layer below EZSP and above the serial
driver. ASHv2 frames add reliability around EZSP payloads: CRC validation, byte
stuffing, data-field randomization, sliding-window acknowledgements, ACK/NAK
frames, reset handling, and optional not-ready flow control.

The `ashv2` feature delegates this link layer to the `ashv2` crate and keeps the
EZSP-specific work in this crate:

- `uart::Encoder` serializes EZSP headers and parameters into ASHv2 payloads.
- `uart::Decoder` parses ASHv2 payloads back into typed EZSP frames.
- `uart::Splitter` routes normal responses to the pending request path and UART
  asynchronous callbacks to the callback channel.

## Core API

The crate is transport-first:

- `Transport` defines the low-level async connection and request/response primitives.
- EZSP command traits (`Configuration`, `Messaging`, `Networking`, `Security`, ...) are blanket-implemented for any `T: Transport`.
- `Ezsp` is a convenience trait that combines all command traits.
- `Ncp<T>` wraps a transport and adds host-side NCP helpers for scans, APS send
  confirmation, transaction/message sequence counters, and callback correlation.
- Protocol types are exposed through `ember`, `ezsp`, and the typed frame/parameter model.

Implementing `Transport` gives access to the full typed command surface.

## `ashv2` transport

The crate currently ships one concrete transport implementation: `uart::Uart` (`feature = "ashv2"`).

`Uart` provides:

- protocol negotiation through `Transport::connect()` / `Transport::ensure_connection()`
- typed EZSP request/response handling over ASHv2 payload framing
- response/callback demultiplexing
- serial constructors:
  - `Uart::open(path, flow_control, protocol_version, &ChannelSizes)`
  - `Uart::from_serial_port(serial_port, protocol_version, &ChannelSizes)`
  - `Uart::new(proxy, ash_rx, callbacks_tx, protocol_version, channel_size)` (advanced integration)
- `Uart::abort()` for aborting the background splitter task

Additional types:

- `uart::ChannelSizes` to tune queue capacities for `Uart::open` / `from_serial_port`
- `uart::Buffers` for ASHv2 queue sizing in integration helper constructors

### Minimal `ashv2` usage

```rust
use ezsp::uart::{ChannelSizes, Uart};
use ezsp::{Transport, Utilities};

// Requires feature = "ashv2"
// Requires a Tokio runtime.
async fn example() -> Result<(), ezsp::Error> {
    let serial_port = /* your serial port implementing ashv2::SerialPort */;
    let sizes = ChannelSizes::default();

    let (mut uart, _ash_tasks, _callbacks) =
        Uart::from_serial_port(serial_port, ezsp::MIN_NON_LEGACY_VERSION, &sizes)?;

    uart.ensure_connection().await?;
    let _eui64 = uart.get_eui64().await?;
    Ok(())
}
```

## NCP Helper

`Ncp<T>` is the high-level host helper for an EZSP Network Co-Processor. It owns
the transport and dereferences to it, so all normal command traits remain
available.

`Ncp` adds behavior that needs more than a single command/response exchange:

- active and energy scans with callback aggregation,
- neighbor table collection,
- unicast and multicast APS sends with `messageSent` confirmation,
- broadcast APS sends with immediate confirmation,
- message tag, APS sequence, and transaction sequence counters,
- clean event-handler shutdown through `Ncp::terminate()`.

`Ncp::build(transport, callbacks)` returns `Builder<T>`. The builder stores
policies, configuration values, security keys, APS options, concentrator
settings, network formation settings, and channel buffer sizing for the startup
implementation.

If `ashv2` is enabled, `Ncp::ashv2(serial_port)` and
`Builder::<uart::Uart>::ashv2(serial_port)` create a builder backed by the
crate's ASHv2 UART transport.

## `apis-saltans` Integration (`apis-saltans` Feature)

When `apis-saltans` is enabled, the crate adapts `Ncp` and `Builder` to the
`apis_saltans_hw` traits.

- `Ncp<T>: apis_saltans_hw::NcpDriver` when
  `T: Configuration + Security + Messaging + Networking + Utilities + Send + Sync`.
- `Builder<T>: apis_saltans_hw::Start` when `T: Transport + Sync + 'static`.
- `Start::start(endpoints)` configures the EZSP stack, starts callback
  translation, spawns the NCP actor, and returns
  `(apis_saltans_hw::NcpHandle, tokio::sync::mpsc::Receiver<apis_saltans_hw::Event>)`.
- `Ncp::terminate()` stops the event handler and returns the underlying transport.

The integration layer translates EZSP callbacks into `apis_saltans_hw::Event`,
including network-up/down/open/closed events, child join/leave events,
trust-center join/rejoin/leave events, and incoming APS messages. It also
aggregates scan callbacks for `NcpDriver` scan calls and correlates
`messageSent` callbacks with outgoing message tags.

## Legal

This project is free software and is not affiliated with Silicon Labs. Silicon
Labs documentation is cited only to describe the public protocol implemented by
this crate.

## Contribution guidelines

- Format: `cargo +nightly fmt`
- Lint: `cargo clippy`