215 uint32_t last_1w_activity_ms, uint32_t now, uint32_t quiet_ms,
216 uint32_t max_defer_ms) {
217 if (!next_op_is_background || last_1w_activity_ms == 0)
219 if (now - first_1w_activity_ms >= max_defer_ms)
221 return (now - last_1w_activity_ms) < quiet_ms;
235 return last_1w_activity_ms == 0 || (now - last_1w_activity_ms) >= quiet_ms;
PairingDiscoveryDisposition
Disposition during pairing discovery phase.
@ ACCEPT
Valid discovery response received.
@ NO_RESPONSE
No packets received on the channel within timeout.
@ INVALID
Packets seen but none were valid discovery (0x29) frames.
bool frame_matches_nodes(const IoFrame &frame, const uint8_t expected_src[NODE_ID_SIZE], const uint8_t expected_dst[NODE_ID_SIZE])
Check if two frames have identical src/dst node IDs.
bool is_duplicate_1w_frame(const OneWayDedupState &last, const OneWayDedupState &incoming, uint32_t window_ms)
Decide whether an incoming 1W frame repeats the previous one inside the burst window.
bool is_exchange_internal_command(uint8_t cmd)
Returns true for commands that are internal to an exchange handshake and carry no useful information ...
PairingKeyChallengeDisposition classify_pairing_key_challenge(const IoFrame &candidate, const uint8_t device_id[NODE_ID_SIZE], const uint8_t controller_id[NODE_ID_SIZE])
Decide if a frame is a valid key-challenge (0x3C) during pairing key exchange.
ExchangeFirstResponseDisposition classify_exchange_first_response(const IoFrame &request, const IoFrame &candidate)
Decide how to handle the first response packet in an authenticated exchange.
ExchangeFinalResponseDisposition
Disposition for the final response after authentication.
@ ACCEPT
Frame matches expected response — exchange succeeds.
@ IGNORE_UNRELATED
Frame doesn't match endpoints — ignore.
bool oneway_burst_started_fresh(uint32_t last_1w_activity_ms, uint32_t now, uint32_t quiet_ms)
Whether a 1W frame arriving at now starts a new burst rather than extending the current one — true if...
PairingKeyChallengeDisposition
Disposition during pairing key-challenge phase.
@ ACCEPT
Valid 0x3C challenge from target device.
@ IGNORE
Not a valid challenge (wrong cmd, length, or sender).
ExchangeFirstResponseDisposition
Disposition for the first response in an authenticated exchange.
@ REQUIRE_AUTH
Matching 0x3C challenge — device demands authentication.
@ IGNORE_UNRELATED
Frame doesn't match endpoints or failed parse — keep waiting.
@ COMPLETE_DIRECT
Matching non-challenge frame — operation complete, no auth needed.
bool defer_background_poll_for_1w_activity(bool next_op_is_background, uint32_t first_1w_activity_ms, uint32_t last_1w_activity_ms, uint32_t now, uint32_t quiet_ms, uint32_t max_defer_ms)
Decide whether to hold back a queued background poll because a 1W remote is still transmitting.
PairingDiscoveryDisposition classify_pairing_discovery_response(const IoFrame &candidate, const uint8_t controller_id[NODE_ID_SIZE])
Decide if a frame is a valid discovery response (0x29) during pairing.
uint32_t response_wait_slice_ms(uint32_t remaining_ms)
Slice remaining wait time into bounded intervals to allow frequency hopping.
bool frame_matches_exchange_endpoints(const IoFrame &request, const IoFrame &candidate)
Check if candidate frame endpoints are the reverse of the request (dst==request.src,...
ExchangeFinalResponseDisposition classify_exchange_final_response(const IoFrame &request, const IoFrame &candidate)
Decide if a candidate frame is an acceptable final response after authentication.
static constexpr uint8_t NODE_ID_SIZE
Device/node addresses are 3 bytes (e.g., "123ABC").
static constexpr uint8_t HMAC_SIZE
Authentication HMAC is 6 bytes (truncated AES output).
static constexpr uint8_t CMD_CHALLENGE_REQ
6-byte random challenge.
static constexpr uint8_t CMD_DISCOVER_RESP
Device responds with its ID and type.
static constexpr uint8_t CMD_CHALLENGE_RESP
HMAC proof answering a 0x3C.
static constexpr int32_t RESPONSE_CHANNEL_WAIT_MS
Per-channel dwell while waiting for an exchange response.
IO-Homecontrol command IDs, result codes and protocol enumerations.
IO-Homecontrol 2W frame container: control bytes, IoFrame and (de)serialization.
Physical-layer radio and timing parameters for the IO-Homecontrol protocol.
Parsed IO‑Homecontrol frame (CTRL0/1 + addresses + command + data).
uint8_t src[NODE_ID_SIZE]
Source node ID (3 bytes).
uint8_t dst[NODE_ID_SIZE]
Destination node ID (3 bytes).
uint8_t data_len
Actual length of data.
Key fields of the last processed 1W frame, used to collapse a remote's repeat burst.
uint8_t main1
Second main byte.
std::string src_id
Source node ID of the last processed frame; empty before the first.
uint8_t main0
First main byte — what distinguishes a move from a stop.
uint32_t timestamp
millis() when the frame was processed.
bool has_intent
Whether main0/main1 were decoded (execute / activate-mode only).