Skip to content

Commit b4a4d1a

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. Signed-off-by: Damian Krolik <damian.krolik@nordicsemi.no>
1 parent 915dfce commit b4a4d1a

File tree

1 file changed

+24
-7
lines changed

1 file changed

+24
-7
lines changed

subsys/nrf_rpc/nrf_rpc_uart.c

+24-7
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
LOG_MODULE_REGISTER(nrf_rpc_uart, CONFIG_NRF_RPC_TR_LOG_LEVEL);
1919

20+
#define CRC_SIZE sizeof(uint16_t)
21+
2022
enum {
2123
HDLC_CHAR_ESCAPE = 0x7d,
2224
HDLC_CHAR_DELIMITER = 0x7e,
@@ -68,6 +70,10 @@ struct nrf_rpc_uart {
6870

6971
K_KERNEL_STACK_MEMBER(rx_workq_stack, CONFIG_NRF_RPC_UART_RX_THREAD_STACK_SIZE);
7072

73+
/* HDLC ack decoding state */
74+
struct hdlc_decode_ctx rx_ack_ctx;
75+
uint8_t rx_ack[CRC_SIZE];
76+
7177
/* HDLC packet decoding state */
7278
struct hdlc_decode_ctx rx_pkt_ctx;
7379
uint8_t rx_pkt[CONFIG_NRF_RPC_UART_MAX_PACKET_SIZE];
@@ -96,18 +102,16 @@ static void log_hexdump_dbg(const uint8_t *data, size_t length, const char *fmt,
96102
}
97103
}
98104

99-
#define CRC_SIZE sizeof(uint16_t)
100-
101105
static void send_byte(const struct device *dev, uint8_t byte);
102106

103107
static void ack_rx(struct nrf_rpc_uart *uart_tr)
104108
{
105-
if (!IS_ENABLED(CONFIG_NRF_RPC_UART_RELIABLE) || uart_tr->rx_pkt_ctx.len != CRC_SIZE) {
106-
log_hexdump_dbg(uart_tr->rx_pkt, uart_tr->rx_pkt_ctx.len, ">>> RX invalid frame");
109+
if (!IS_ENABLED(CONFIG_NRF_RPC_UART_RELIABLE) || uart_tr->rx_ack_ctx.len != CRC_SIZE) {
110+
log_hexdump_dbg(uart_tr->rx_ack, uart_tr->rx_ack_ctx.len, ">>> RX invalid frame");
107111
return;
108112
}
109113

110-
uint16_t rx_ack = sys_get_le16(uart_tr->rx_pkt);
114+
uint16_t rx_ack = sys_get_le16(uart_tr->rx_ack);
111115

112116
LOG_DBG(">>> RX ack %04x", rx_ack);
113117

@@ -117,7 +121,6 @@ static void ack_rx(struct nrf_rpc_uart *uart_tr)
117121
}
118122

119123
k_sem_give(&uart_tr->ack_sem);
120-
k_yield();
121124
}
122125

123126
static void ack_tx(struct nrf_rpc_uart *uart_tr, uint16_t ack_pld)
@@ -245,8 +248,8 @@ static void work_handler(struct k_work *work)
245248
continue;
246249
}
247250

251+
/* ACKs are already handled in ISR, so process only normal packets here */
248252
if (uart_tr->rx_pkt_ctx.len <= CRC_SIZE) {
249-
ack_rx(uart_tr);
250253
continue;
251254
}
252255

@@ -282,6 +285,17 @@ static void work_handler(struct k_work *work)
282285
}
283286
}
284287

288+
static void decode_ack(struct nrf_rpc_uart *inst, const uint8_t *in, size_t len)
289+
{
290+
for (size_t i = 0; i < len; i++) {
291+
hdlc_decode_byte(&inst->rx_ack_ctx, inst->rx_ack, in[i]);
292+
293+
if (inst->rx_ack_ctx.state == HDLC_STATE_FRAME_FOUND) {
294+
ack_rx(inst);
295+
}
296+
}
297+
}
298+
285299
static void serial_cb(const struct device *uart, void *user_data)
286300
{
287301
struct nrf_rpc_uart *uart_tr = user_data;
@@ -294,6 +308,7 @@ static void serial_cb(const struct device *uart, void *user_data)
294308
uart_tr->rx_ringbuf.size);
295309
if (rx_len > 0) {
296310
rx_len = uart_fifo_read(uart, rx_buffer, rx_len);
311+
decode_ack(uart_tr, rx_buffer, rx_len);
297312
int err = ring_buf_put_finish(&uart_tr->rx_ringbuf, rx_len);
298313
(void)err; /*silence the compiler*/
299314
__ASSERT_NO_MSG(err == 0);
@@ -373,6 +388,8 @@ static int init(const struct nrf_rpc_tr *transport, nrf_rpc_tr_receive_handler_t
373388

374389
uart_tr->rx_pkt_ctx.state = HDLC_STATE_UNSYNC;
375390
uart_tr->rx_pkt_ctx.capacity = sizeof(uart_tr->rx_pkt);
391+
uart_tr->rx_ack_ctx.state = HDLC_STATE_UNSYNC;
392+
uart_tr->rx_ack_ctx.capacity = sizeof(uart_tr->rx_ack);
376393
uart_irq_rx_enable(uart_tr->uart);
377394

378395
return 0;

0 commit comments

Comments
 (0)