Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
radio_soft_phy.h
Go to the documentation of this file.
1#pragma once
2
3/// @file radio_soft_phy.h
4/// @brief Software PHY for radios without IoHomeOn hardware framing.
5/// @ingroup hioc_radio
6///
7/// Chips such as the SX1262 and LR1121 have no hardware mode equivalent to the SX1276's
8/// IoHomeOn: they provide generic GFSK framing only. This header
9/// declares the chip-agnostic pieces such a driver needs to reproduce IO-Homecontrol framing
10/// in software — UART bit-encoding for TX, and a UART-decode probe (with CRC validation) to
11/// recover frame boundaries from an unaligned raw RX bitstream.
12
13#include "radio_interface.h"
14
15#include <cstdint>
16
17namespace esphome {
18namespace home_io_control {
19
20/// @brief Result of the UART probe: best candidate frame within a raw capture.
22 bool valid{false}; ///< A plausible frame was found.
23 uint8_t bit_offset{0}; ///< Bit offset where the best decode started.
24 uint8_t decoded_len{0}; ///< Total number of bytes decoded at that offset.
25 uint8_t frame_start{0}; ///< Index into decoded buffer where the frame begins.
26 uint8_t frame_len{0}; ///< Length of the candidate IoFrame (decoded bytes).
27 uint8_t decoded[RADIO_PACKET_BUFFER_SIZE]{}; ///< Full decoded UART stream at the chosen offset.
28};
29
30/// @brief Decode a UART-encoded bitstream from the given bit offset.
31uint8_t decode_uart_probe(const uint8_t *raw, uint8_t raw_len, uint8_t bit_offset, uint8_t *decoded,
32 uint8_t decoded_max_len);
33
34/// @brief Search raw RX buffer for the best CRC-validated IO-Homecontrol frame.
35UartProbeResult find_uart_probe(const uint8_t *raw, uint8_t raw_len);
36
37/// @brief Bits an on-air UART cell spends per protocol byte: start(1) + data(8) + stop(1).
38static constexpr uint8_t UART_CELL_BITS = 10;
39
40/// @brief Raw on-air bytes needed to carry a whole frame: `frame_len` protocol bytes plus the
41/// two trailing CRC bytes, each UART-packed into a 10-bit cell.
42///
43/// This is what makes a length-driven receive possible at all: a frame's own size is knowable
44/// from its first decoded byte, so the raw byte count it will occupy is knowable too — no chip
45/// needs to tell us where the frame ends.
46/// @param frame_len Protocol frame length in bytes (CTRL0's own length field, +1).
47/// @return Raw byte count, rounded up to whole bytes.
48uint8_t soft_phy_raw_bytes_for_frame(uint8_t frame_len);
49
50/// @brief Recover a frame's total length from the very first UART cell of a reception.
51///
52/// CTRL0 bits [4:0] hold `frame_length - 1` (see proto_frame.h), and CTRL0 is the first byte
53/// after the sync word — so ten bits of air time are enough to learn how long the whole frame
54/// will be. Alignment is not yet known at that point, so every probe offset is tried and the
55/// largest plausible answer wins: over-waiting by a few bytes costs a little latency, whereas
56/// under-waiting would truncate the frame.
57/// @param raw Raw bytes read from the chip's data buffer, starting at the reception's own offset.
58/// @param raw_len Number of raw bytes available (three is enough at any alignment).
59/// @return Plausible frame length in bytes, or 0 when no offset yields one.
60uint8_t soft_phy_peek_frame_length(const uint8_t *raw, uint8_t raw_len);
61
62/// @brief UART-encode a buffer of bytes (start bit 0, 8 data bits LSB-first, stop bit 1).
63/// @return Number of encoded bytes, or 0 if the output buffer is too small.
64uint8_t uart_encode_packet(const uint8_t *data, uint8_t len, uint8_t *encoded, uint8_t encoded_max_len);
65
66} // namespace home_io_control
67} // namespace esphome
uint8_t decode_uart_probe(const uint8_t *raw, uint8_t raw_len, uint8_t bit_offset, uint8_t *decoded, uint8_t decoded_max_len)
Decode a raw UART‑encoded bitstream into bytes.
uint8_t soft_phy_peek_frame_length(const uint8_t *raw, uint8_t raw_len)
Recover a frame's total length from the very first UART cell of a reception.
uint8_t uart_encode_packet(const uint8_t *data, uint8_t len, uint8_t *encoded, uint8_t encoded_max_len)
UART-encode a buffer of bytes (start bit 0, 8 data bits LSB-first, stop bit 1).
UartProbeResult find_uart_probe(const uint8_t *raw, uint8_t raw_len)
Search raw RX buffer for the best CRC-validated IO-Homecontrol frame.
uint8_t soft_phy_raw_bytes_for_frame(uint8_t frame_len)
Raw on-air bytes needed to carry a whole frame: frame_len protocol bytes plus the two trailing CRC by...
constexpr uint8_t RADIO_PACKET_BUFFER_SIZE
Scratch buffer size for raw radio packets and recovered frames.
static constexpr uint8_t UART_CELL_BITS
Bits an on-air UART cell spends per protocol byte: start(1) + data(8) + stop(1).
Radio abstraction layer for IO-Homecontrol.
Result of the UART probe: best candidate frame within a raw capture.
uint8_t decoded_len
Total number of bytes decoded at that offset.
uint8_t frame_start
Index into decoded buffer where the frame begins.
bool valid
A plausible frame was found.
uint8_t bit_offset
Bit offset where the best decode started.
uint8_t frame_len
Length of the candidate IoFrame (decoded bytes).
uint8_t decoded[RADIO_PACKET_BUFFER_SIZE]
Full decoded UART stream at the chosen offset.