Skip to content

Commit a7e72e3

Browse files
Damian-Nordicnordicjm
authored andcommitted
nrf_rpc_uart: improve hdlc decoding
1. Skip incoming bytes while in the unsync state. 2. Handle receive buffer overflow. 3. Prepare hdlc_decode_byte() for multiple simultaneous decoding states. Signed-off-by: Damian Krolik <[email protected]>
1 parent c4b9e10 commit a7e72e3

File tree

1 file changed

+69
-48
lines changed

1 file changed

+69
-48
lines changed

subsys/nrf_rpc/nrf_rpc_uart.c

Lines changed: 69 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,24 @@ struct trx_flips {
3333
uint16_t last_rx_crc;
3434
};
3535

36-
typedef enum {
36+
enum hdlc_state {
37+
/* Ignore incoming bytes until the delimiter is found. */
3738
HDLC_STATE_UNSYNC,
38-
HDLC_STATE_FRAME_START,
39+
/* Append incoming bytes to the output buffer. */
40+
HDLC_STATE_FRAME,
41+
/* Found the delimeter when the output buffer was non-empty. */
3942
HDLC_STATE_FRAME_FOUND,
43+
/* Found the escape byte. Append the following byte XORed with 0x20 to the output buffer. */
4044
HDLC_STATE_ESCAPE,
41-
} hdlc_state_t;
45+
};
46+
47+
struct hdlc_decode_ctx {
48+
enum hdlc_state state;
49+
/* The number of bytes of the current packet that have been decoded so far. */
50+
uint16_t len;
51+
/* The capacity of the buffer to store a decoded packet. */
52+
uint16_t capacity;
53+
};
4254

4355
struct nrf_rpc_uart {
4456
const struct device *uart;
@@ -56,10 +68,9 @@ struct nrf_rpc_uart {
5668

5769
K_KERNEL_STACK_MEMBER(rx_workq_stack, CONFIG_NRF_RPC_UART_RX_THREAD_STACK_SIZE);
5870

59-
/* HDLC frame parsing state */
60-
hdlc_state_t hdlc_state;
61-
uint8_t rx_packet[CONFIG_NRF_RPC_UART_MAX_PACKET_SIZE];
62-
size_t rx_packet_len;
71+
/* HDLC packet decoding state */
72+
struct hdlc_decode_ctx rx_pkt_ctx;
73+
uint8_t rx_pkt[CONFIG_NRF_RPC_UART_MAX_PACKET_SIZE];
6374

6475
/* Ack waiting semaphore */
6576
struct k_sem ack_sem;
@@ -91,12 +102,12 @@ static void send_byte(const struct device *dev, uint8_t byte);
91102

92103
static void ack_rx(struct nrf_rpc_uart *uart_tr)
93104
{
94-
if (!IS_ENABLED(CONFIG_NRF_RPC_UART_RELIABLE) || uart_tr->rx_packet_len != CRC_SIZE) {
95-
log_hexdump_dbg(uart_tr->rx_packet, uart_tr->rx_packet_len, ">>> RX invalid frame");
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");
96107
return;
97108
}
98109

99-
uint16_t rx_ack = sys_get_le16(uart_tr->rx_packet);
110+
uint16_t rx_ack = sys_get_le16(uart_tr->rx_pkt);
100111

101112
LOG_DBG(">>> RX ack %04x", rx_ack);
102113

@@ -176,39 +187,48 @@ static bool crc_compare(uint16_t rx_crc, uint16_t calc_crc)
176187
return rx_crc == calc_crc;
177188
}
178189

179-
static void hdlc_decode_byte(struct nrf_rpc_uart *uart_tr, uint8_t byte)
190+
static void hdlc_decode_byte(struct hdlc_decode_ctx *ctx, uint8_t *out, uint8_t in)
180191
{
181-
/* TODO: handle frame buffer overflow */
182-
183-
if (uart_tr->hdlc_state == HDLC_STATE_ESCAPE) {
184-
uart_tr->rx_packet[uart_tr->rx_packet_len++] = byte ^ 0x20;
185-
uart_tr->hdlc_state = HDLC_STATE_FRAME_START;
186-
} else if (byte == HDLC_CHAR_ESCAPE) {
187-
uart_tr->hdlc_state = HDLC_STATE_ESCAPE;
188-
} else if (byte == HDLC_CHAR_DELIMITER) {
189-
uart_tr->hdlc_state = (uart_tr->hdlc_state == HDLC_STATE_FRAME_START)
190-
? HDLC_STATE_FRAME_FOUND
191-
: HDLC_STATE_UNSYNC;
192-
} else {
193-
uart_tr->rx_packet[uart_tr->rx_packet_len++] = byte;
194-
uart_tr->hdlc_state = HDLC_STATE_FRAME_START;
192+
switch (ctx->state) {
193+
case HDLC_STATE_UNSYNC:
194+
if (in == HDLC_CHAR_DELIMITER) {
195+
ctx->len = 0;
196+
ctx->state = HDLC_STATE_FRAME;
197+
}
198+
return;
199+
case HDLC_STATE_FRAME_FOUND:
200+
ctx->len = 0;
201+
ctx->state = HDLC_STATE_FRAME;
202+
__fallthrough;
203+
case HDLC_STATE_FRAME:
204+
if (in == HDLC_CHAR_DELIMITER) {
205+
if (ctx->len > 0) {
206+
ctx->state = HDLC_STATE_FRAME_FOUND;
207+
}
208+
return;
209+
} else if (in == HDLC_CHAR_ESCAPE) {
210+
ctx->state = HDLC_STATE_ESCAPE;
211+
return;
212+
}
213+
break;
214+
case HDLC_STATE_ESCAPE:
215+
in ^= 0x20;
216+
ctx->state = HDLC_STATE_FRAME;
217+
break;
195218
}
196219

197-
if (uart_tr->hdlc_state == HDLC_STATE_FRAME_FOUND) {
198-
if (uart_tr->rx_packet_len > CRC_SIZE) {
199-
uart_tr->rx_packet_len -= CRC_SIZE;
200-
} else {
201-
ack_rx(uart_tr);
202-
uart_tr->rx_packet_len = 0;
203-
uart_tr->hdlc_state = HDLC_STATE_UNSYNC;
204-
}
220+
if (ctx->len >= ctx->capacity) {
221+
/* Ignore too long frame */
222+
ctx->state = HDLC_STATE_UNSYNC;
223+
return;
205224
}
225+
226+
out[ctx->len++] = in;
206227
}
207228

208229
static void work_handler(struct k_work *work)
209230
{
210231
struct nrf_rpc_uart *uart_tr = CONTAINER_OF(work, struct nrf_rpc_uart, rx_work);
211-
const struct nrf_rpc_tr *transport = uart_tr->transport;
212232
uint8_t *data;
213233
size_t len;
214234
int ret;
@@ -219,24 +239,28 @@ static void work_handler(struct k_work *work)
219239
len = ring_buf_get_claim(&uart_tr->rx_ringbuf, &data,
220240
CONFIG_NRF_RPC_UART_MAX_PACKET_SIZE);
221241
for (size_t i = 0; i < len; i++) {
222-
hdlc_decode_byte(uart_tr, data[i]);
242+
hdlc_decode_byte(&uart_tr->rx_pkt_ctx, uart_tr->rx_pkt, data[i]);
223243

224-
if (uart_tr->hdlc_state != HDLC_STATE_FRAME_FOUND) {
244+
if (uart_tr->rx_pkt_ctx.state != HDLC_STATE_FRAME_FOUND) {
225245
continue;
226246
}
227247

228-
crc_received = sys_get_le16(uart_tr->rx_packet + uart_tr->rx_packet_len);
248+
if (uart_tr->rx_pkt_ctx.len <= CRC_SIZE) {
249+
ack_rx(uart_tr);
250+
continue;
251+
}
252+
253+
uart_tr->rx_pkt_ctx.len -= CRC_SIZE;
254+
crc_received = sys_get_le16(uart_tr->rx_pkt + uart_tr->rx_pkt_ctx.len);
229255
crc_calculated =
230-
crc16_ccitt(0xffff, uart_tr->rx_packet, uart_tr->rx_packet_len);
256+
crc16_ccitt(0xffff, uart_tr->rx_pkt, uart_tr->rx_pkt_ctx.len);
231257

232-
log_hexdump_dbg(uart_tr->rx_packet, uart_tr->rx_packet_len,
258+
log_hexdump_dbg(uart_tr->rx_pkt, uart_tr->rx_pkt_ctx.len,
233259
">>> RX packet %04x", crc_received);
234260

235261
if (!crc_compare(crc_received, crc_calculated)) {
236262
LOG_ERR("Invalid packet CRC: calculated %04x but received %04x",
237263
crc_calculated, crc_received);
238-
uart_tr->rx_packet_len = 0;
239-
uart_tr->hdlc_state = HDLC_STATE_UNSYNC;
240264
continue;
241265
}
242266

@@ -245,13 +269,10 @@ static void work_handler(struct k_work *work)
245269
if (rx_flip_check(uart_tr, crc_received)) {
246270
LOG_WRN("Duplicate packet %04x", crc_received);
247271
} else {
248-
uart_tr->receive_callback(transport, uart_tr->rx_packet,
249-
uart_tr->rx_packet_len,
272+
uart_tr->receive_callback(uart_tr->transport, uart_tr->rx_pkt,
273+
uart_tr->rx_pkt_ctx.len,
250274
uart_tr->receive_ctx);
251275
}
252-
253-
uart_tr->rx_packet_len = 0;
254-
uart_tr->hdlc_state = HDLC_STATE_UNSYNC;
255276
}
256277

257278
ret = ring_buf_get_finish(&uart_tr->rx_ringbuf, len);
@@ -350,8 +371,8 @@ static int init(const struct nrf_rpc_tr *transport, nrf_rpc_tr_receive_handler_t
350371
k_work_init(&uart_tr->rx_work, work_handler);
351372
ring_buf_init(&uart_tr->rx_ringbuf, sizeof(uart_tr->rx_buffer), uart_tr->rx_buffer);
352373

353-
uart_tr->hdlc_state = HDLC_STATE_UNSYNC;
354-
uart_tr->rx_packet_len = 0;
374+
uart_tr->rx_pkt_ctx.state = HDLC_STATE_UNSYNC;
375+
uart_tr->rx_pkt_ctx.capacity = sizeof(uart_tr->rx_pkt);
355376
uart_irq_rx_enable(uart_tr->uart);
356377
nrf_rpc_uart_initialized_hook(uart_tr->uart);
357378

0 commit comments

Comments
 (0)