# hart-rs
A `no_std` HART protocol implementation for embedded systems, written in Rust.
[](https://github.com/fishloa/hart-rs/actions/workflows/ci.yml)
## What it is
HART (Highway Addressable Remote Transducer) is an industrial protocol layered
over a 4-20 mA current loop. This workspace implements the full protocol stack
— codec, modem driver, and async master — as three `no_std` crates targeting
embedded microcontrollers such as the STM32H7 with an AD5700-1 HART modem.
## Crate architecture
```
hart-protocol (codec: encode, decode, typed commands)
^
|
ad5700 (AD5700-1 modem driver: blocking + async)
^
|
embassy-hart (async HART master via Embassy + embassy-time)
```
`hart-protocol` is a standalone codec with no hardware dependencies.
`ad5700` wraps the modem with `embedded-hal` traits and uses `hart-protocol`.
`embassy-hart` builds on `ad5700`'s async driver and adds timeout management.
## Supported commands
### Universal read commands
| 0 | Read unique identifier (device ID) |
| 1 | Read primary variable |
| 2 | Read loop current and percent range |
| 3 | Read dynamic variables |
### Common-practice read commands
| 9 | Read device variables with status |
| 11 | Read unique identifier by tag |
| 12 | Read message |
| 13 | Read tag, descriptor, and date |
| 14 | Read primary variable transducer info|
| 15 | Read device info |
| 16 | Read final assembly number |
| 20 | Read long tag |
| 48 | Read additional device status |
### Write commands
| 6 | Write polling address |
| 17 | Write message |
| 18 | Write tag, descriptor, and date |
| 19 | Write final assembly number |
| 22 | Write long tag |
| 38 | Reset configuration changed flag |
## Quick start
Encode a Command 0 request frame and decode a response using `hart-protocol`
(no hardware or I/O involved):
```rust
use hart_protocol::encode::encode_frame;
use hart_protocol::decode::Decoder;
use hart_protocol::types::{Address, FrameType, MasterRole};
use hart_protocol::commands::read_device_id::{ReadDeviceIdRequest, ReadDeviceIdResponse};
use hart_protocol::commands::{CommandRequest, CommandResponse};
use hart_protocol::consts::MIN_PREAMBLE_COUNT;
// --- Encode a Command 0 request ---
let address = Address::Short {
master: MasterRole::Primary,
burst: false,
poll_address: 0,
};
let req = ReadDeviceIdRequest;
let mut data_buf = [0u8; 4];
let data_len = req.encode_data(&mut data_buf).unwrap();
let mut frame_buf = [0u8; 32];
let frame_len = encode_frame(
FrameType::Request,
&address,
ReadDeviceIdRequest::COMMAND_NUMBER,
&data_buf[..data_len],
MIN_PREAMBLE_COUNT,
&mut frame_buf,
).unwrap();
// frame_buf[..frame_len] is ready to send to the modem.
// --- Decode a Command 0 response byte-by-byte ---
let raw_response: &[u8] = &[
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // preamble
0x06, // delimiter: response short
0x80, // address
0x00, // command 0
0x0E, // byte count (14 = 2 status + 12 data)
0x00, 0x00, // response status bytes
0xFE, 0x1A, 0x2B, 0x05, 0x07,
0x01, 0x03, 0x04, 0x00, 0x11, 0x22, 0x33, // device identity
0x00, // checksum (illustrative)
];
let mut decoder = Decoder::new();
let mut raw_frame = None;
for &byte in raw_response {
if let Some(frame) = decoder.feed(byte).unwrap_or(None) {
raw_frame = Some(frame);
break;
}
}
if let Some(frame) = raw_frame {
// Strip the two response status bytes before decoding the command payload.
let payload = &frame.data[2..];
let resp = ReadDeviceIdResponse::decode_data(payload).unwrap();
let _ = resp.device_id;
}
```
## Hardware target
This stack is designed for the **STM32H7** microcontroller paired with the
**Analog Devices AD5700-1** HART modem. The `ad5700` and `embassy-hart` crates
depend on `embedded-hal` and `Embassy` respectively, keeping the codec
(`hart-protocol`) portable to any platform.
## Releasing
1. Update version in root `Cargo.toml` (`[workspace.package] version = "X.Y.Z"`)
2. Commit: `release: vX.Y.Z`
3. Tag: `git tag vX.Y.Z`
4. Push: `git push && git push --tags`
CI will verify tests pass, check the tag matches Cargo.toml, and publish all crates to crates.io in dependency order.
Requires `CARGO_REGISTRY_TOKEN` secret in GitHub repository settings.
## License
Licensed under either of:
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
at your option.