Skip to content

Commit bdae0c8

Browse files
committed
nrf_rpc_uart: decode ACKs in ISR
Currently, decoding both normal packets and ACKs happens in the receive thread. This imposes certain limitations, for example the receive thread shall not send any packets as this would introduce a chicken-egg problem: the thread is waiting for an ACK but the ACK can only be decoded by the current thread. More importantly, this can also introduce spurious ACK timeouts and retransissions because the receive thread may be blocked when trying to push a packet to the thead pool. Move the ACK decoding to ISR to overcome the mentioned issues.
1 parent 147b35e commit bdae0c8

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

subsys/nrf_rpc/nrf_rpc_uart.c

+23-5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ struct nrf_rpc_uart {
6060

6161
K_KERNEL_STACK_MEMBER(rx_workq_stack, CONFIG_NRF_RPC_UART_RX_THREAD_STACK_SIZE);
6262

63+
/* HDLC ack decoding state */
64+
enum hdlc_state rx_ack_state;
65+
uint8_t rx_ack[2];
66+
size_t rx_ack_len;
67+
6368
/* HDLC packet decoding state */
6469
enum hdlc_state rx_pkt_state;
6570
size_t rx_pkt_len;
@@ -95,12 +100,12 @@ static void send_byte(const struct device *dev, uint8_t byte);
95100

96101
static void ack_rx(struct nrf_rpc_uart *uart_tr)
97102
{
98-
if (!IS_ENABLED(CONFIG_NRF_RPC_UART_RELIABLE) || uart_tr->rx_pkt_len != CRC_SIZE) {
99-
log_hexdump_dbg(uart_tr->rx_pkt, uart_tr->rx_pkt_len, ">>> RX invalid frame");
103+
if (!IS_ENABLED(CONFIG_NRF_RPC_UART_RELIABLE) || uart_tr->rx_ack_len != CRC_SIZE) {
104+
log_hexdump_dbg(uart_tr->rx_ack, uart_tr->rx_ack_len, ">>> RX invalid frame");
100105
return;
101106
}
102107

103-
uint16_t rx_ack = sys_get_le16(uart_tr->rx_pkt);
108+
uint16_t rx_ack = sys_get_le16(uart_tr->rx_ack);
104109

105110
LOG_DBG(">>> RX ack %04x", rx_ack);
106111

@@ -110,7 +115,6 @@ static void ack_rx(struct nrf_rpc_uart *uart_tr)
110115
}
111116

112117
k_sem_give(&uart_tr->ack_sem);
113-
k_yield();
114118
}
115119

116120
static void ack_tx(struct nrf_rpc_uart *uart_tr, uint16_t ack_pld)
@@ -241,7 +245,7 @@ static void work_handler(struct k_work *work)
241245
}
242246

243247
if (uart_tr->rx_pkt_len <= CRC_SIZE) {
244-
ack_rx(uart_tr);
248+
/* ACKs are already handled in ISR, so only process normal packets in this handler */
245249
continue;
246250
}
247251

@@ -276,6 +280,18 @@ static void work_handler(struct k_work *work)
276280
}
277281
}
278282

283+
static void decode_ack(struct nrf_rpc_uart *inst, const uint8_t *rx, size_t len)
284+
{
285+
for (size_t i = 0; i < len; i++) {
286+
hdlc_decode_byte(&inst->rx_ack_state, inst->rx_ack, &inst->rx_ack_len,
287+
sizeof(inst->rx_ack), rx[i]);
288+
289+
if (inst->rx_ack_state == HDLC_STATE_FRAME_FOUND) {
290+
ack_rx(inst);
291+
}
292+
}
293+
}
294+
279295
static void serial_cb(const struct device *uart, void *user_data)
280296
{
281297
struct nrf_rpc_uart *uart_tr = user_data;
@@ -288,6 +304,7 @@ static void serial_cb(const struct device *uart, void *user_data)
288304
uart_tr->rx_ringbuf.size);
289305
if (rx_len > 0) {
290306
rx_len = uart_fifo_read(uart, rx_buffer, rx_len);
307+
decode_ack(uart_tr, rx_buffer, rx_len);
291308
int err = ring_buf_put_finish(&uart_tr->rx_ringbuf, rx_len);
292309
(void)err; /*silence the compiler*/
293310
__ASSERT_NO_MSG(err == 0);
@@ -365,6 +382,7 @@ static int init(const struct nrf_rpc_tr *transport, nrf_rpc_tr_receive_handler_t
365382
k_work_init(&uart_tr->rx_work, work_handler);
366383
ring_buf_init(&uart_tr->rx_ringbuf, sizeof(uart_tr->rx_buffer), uart_tr->rx_buffer);
367384

385+
uart_tr->rx_ack_state = HDLC_STATE_UNSYNC;
368386
uart_tr->rx_pkt_state = HDLC_STATE_UNSYNC;
369387
uart_irq_rx_enable(uart_tr->uart);
370388

0 commit comments

Comments
 (0)