From 186cd2e91749f6479e5864102fca4a015744eb00 Mon Sep 17 00:00:00 2001 From: Joshua Wise Date: Tue, 9 Jun 2026 16:57:57 -0400 Subject: [PATCH] nimble/transport/common/hci_h4: add HCI H4 packet callback Certain controllers have extensions to the HCI H4 protocol (i.e., TI CC256x has eHCILL, which are additional bytes that show up in the stream to indicate power mode transitions). The transport needs to be able to handle these; provide a callback that a custom hcill_uart_transport could request to be able to consume bytes at packet boundaries in the HCI H4 state machine. Signed-off-by: Joshua Wise --- .../hci_h4/include/nimble/transport/hci_h4.h | 16 ++++++++++++++++ nimble/transport/common/hci_h4/src/hci_h4.c | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h b/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h index 6ad083a05f..2378d658f8 100644 --- a/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h +++ b/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h @@ -43,8 +43,17 @@ struct hci_h4_allocators { extern const struct hci_h4_allocators hci_h4_allocs_from_ll; extern const struct hci_h4_allocators hci_h4_allocs_from_hs; +/** Callback invoked on every frame that the H4 parser sees; it is this + * callback's responsibility to dispatch packets to the transport layer. + */ typedef int (hci_h4_frame_cb)(uint8_t pkt_type, void *data); +/** Callback invoked at the start of every packet that the H4 parser sees, + * to allow a transport to parse custom types of packets that the H4 parser + * may not otherwise understand (for instance, TI eHCILL packets). + */ +typedef uint16_t(hci_h4_packet_cb)(const uint8_t *buf, uint16_t len); + struct hci_h4_sm { uint8_t state; uint8_t pkt_type; @@ -59,12 +68,19 @@ struct hci_h4_sm { const struct hci_h4_allocators *allocs; hci_h4_frame_cb *frame_cb; + hci_h4_packet_cb *packet_cb; }; void hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs, hci_h4_frame_cb *frame_cb); +/* We do not include this in sm_init to avoid breaking the API for other + * users, but ideally if you need to call this, you will call it immediately + * once, right after sm_init. + */ +void hci_h4_sm_set_packet_cb(struct hci_h4_sm *h4sm, hci_h4_packet_cb *packet_cb); + int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len); #endif /* _HCI_H4_H_ */ diff --git a/nimble/transport/common/hci_h4/src/hci_h4.c b/nimble/transport/common/hci_h4/src/hci_h4.c index fd89154a34..41a29c3f01 100644 --- a/nimble/transport/common/hci_h4/src/hci_h4.c +++ b/nimble/transport/common/hci_h4/src/hci_h4.c @@ -283,6 +283,15 @@ hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len) rc = 0; switch (h4sm->state) { case HCI_H4_SM_W4_PKT_TYPE: + if (h4sm->packet_cb) { + /* perhaps the chipset / transport driver wants to inspect + * start-of-packet and consume it on its own? */ + uint16_t consumed = h4sm->packet_cb(ib.buf, ib.len); + if (consumed) { + hci_h4_ib_consume(&ib, consumed); + continue; + } + } hci_h4_frame_start(h4sm, ib.buf[0]); hci_h4_ib_consume(&ib, 1); h4sm->state = HCI_H4_SM_W4_HEADER; @@ -337,3 +346,9 @@ hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs, h4sm->allocs = allocs; h4sm->frame_cb = frame_cb; } + +void +hci_h4_sm_set_packet_cb(struct hci_h4_sm *h4sm, hci_h4_packet_cb *packet_cb) +{ + h4sm->packet_cb = packet_cb; +}