Skip to content

Commit ed2aa99

Browse files
committed
feat(srv/stm32-uart): Add support for receive timeout
1 parent 3446ffd commit ed2aa99

File tree

2 files changed

+79
-30
lines changed

2 files changed

+79
-30
lines changed

services/stm32-uart/stm32-uart.c

+77-30
Original file line numberDiff line numberDiff line change
@@ -162,28 +162,6 @@ static stream_ret_t stream_write(Stream *self, const void *buf, size_t size) {
162162
}
163163

164164

165-
static stream_ret_t stream_read(Stream *self, void *buf, size_t size, size_t *read) {
166-
if (u_assert(self != NULL) ||
167-
u_assert(buf != NULL) ||
168-
u_assert(size > 0)) {
169-
return STREAM_RET_FAILED;
170-
}
171-
Stm32Uart *stm32_uart = (Stm32Uart *)self->parent;
172-
173-
size_t r = xStreamBufferReceive(stm32_uart->rxbuf, buf, size, portMAX_DELAY);
174-
if (r == 0) {
175-
return STREAM_RET_EOF;
176-
} else if (r > 0) {
177-
if (read != NULL) {
178-
*read = r;
179-
}
180-
return STREAM_RET_OK;
181-
}
182-
183-
return STREAM_RET_FAILED;
184-
}
185-
186-
187165
static stream_ret_t stream_write_timeout(Stream *self, const void *buf, size_t size, size_t *written, uint32_t timeout_ms) {
188166
if (u_assert(self != NULL) ||
189167
u_assert(buf != NULL) ||
@@ -231,17 +209,54 @@ static stream_ret_t stream_read_timeout(Stream *self, void *buf, size_t size, si
231209
}
232210
Stm32Uart *stm32_uart = (Stm32Uart *)self->parent;
233211

234-
size_t r = xStreamBufferReceive(stm32_uart->rxbuf, buf, size, pdMS_TO_TICKS(timeout_ms));
235-
if (r == 0) {
236-
return STREAM_RET_TIMEOUT;
237-
} else if (r > 0) {
238-
if (read != NULL) {
239-
*read = r;
212+
/* Allow using constant for the max delay, see @p stream_read below. */
213+
if (timeout_ms != portMAX_DELAY) {
214+
timeout_ms = pdMS_TO_TICKS(timeout_ms);
215+
}
216+
217+
for (size_t i = 0; i < size; i++) {
218+
uint8_t c;
219+
/* Waiting with timeout for the first byte only. */
220+
size_t r = xStreamBufferReceive(stm32_uart->rxbuf, &c, sizeof(c), i ? 0 : timeout_ms);
221+
222+
if (r == 0) {
223+
if (read != NULL) {
224+
*read = i;
225+
}
226+
return i ? STREAM_RET_OK : STREAM_RET_TIMEOUT;
227+
} else {
228+
if (c == 0x1b) {
229+
/* Do not handle timeout. We are sure there is another byte ready
230+
* when ESC is received. Read the next byte after the ESC. */
231+
r = xStreamBufferReceive(stm32_uart->rxbuf, &c, sizeof(c), timeout_ms);
232+
((uint8_t *)buf)[i] = c;
233+
} else if (c == 0x17) {
234+
/* Handle end of block (signalled by RTO interrupt). */
235+
if (read != NULL) {
236+
*read = i;
237+
}
238+
return STREAM_RET_EOT;
239+
} else {
240+
((uint8_t *)buf)[i] = c;
241+
}
240242
}
241-
return STREAM_RET_OK;
243+
}
244+
if (read != NULL) {
245+
*read = size;
242246
}
243247

244-
return STREAM_RET_FAILED;
248+
return STREAM_RET_OK;
249+
}
250+
251+
252+
static stream_ret_t stream_read(Stream *self, void *buf, size_t size, size_t *read) {
253+
if (u_assert(self != NULL) ||
254+
u_assert(buf != NULL) ||
255+
u_assert(size > 0)) {
256+
return STREAM_RET_FAILED;
257+
}
258+
259+
return stream_read_timeout(self, buf, size, read, portMAX_DELAY);
245260
}
246261

247262

@@ -351,12 +366,26 @@ stm32_uart_ret_t stm32_uart_interrupt_handler(Stm32Uart *self) {
351366
uint8_t b = usart_recv(self->port);
352367

353368
BaseType_t woken = pdFALSE;
369+
/* For any character < 0x20, prepend ESC */
370+
if (b < 0x20) {
371+
const uint8_t esc = 0x1b;
372+
xStreamBufferSendFromISR(self->rxbuf, &esc, sizeof(esc), &woken);
373+
}
354374
/* Do not check the return value. If there was not enough space to save
355375
* the received byte, we have nothing else to do. */
356376
xStreamBufferSendFromISR(self->rxbuf, &b, sizeof(b), &woken);
357377
portYIELD_FROM_ISR(woken);
358378
}
359379

380+
if (USART_ISR(self->port) & USART_ISR_RTOF) {
381+
USART_ICR(self->port) |= USART_ICR_RTOCF;
382+
383+
BaseType_t woken = pdFALSE;
384+
const uint8_t etb = 0x17;
385+
xStreamBufferSendFromISR(self->rxbuf, &etb, sizeof(etb), &woken);
386+
portYIELD_FROM_ISR(woken);
387+
}
388+
360389
/* Enabling the RXNE interrupt also enables ORE. We must handle it properly. */
361390
if ((USART_ISR(self->port) & USART_ISR_ORE)) {
362391
USART_ICR(self->port) |= USART_ICR_ORECF;
@@ -372,3 +401,21 @@ stm32_uart_ret_t stm32_uart_set_de(Stm32Uart *self, uint32_t de_port, uint32_t d
372401

373402
return STM32_UART_RET_OK;
374403
}
404+
405+
406+
stm32_uart_ret_t stm32_uart_set_rto(Stm32Uart *self, bool rto) {
407+
self->enable_rto = rto;
408+
if (rto) {
409+
/* Set receiver timeout enable. 3 character time. */
410+
USART_CR2(self->port) |= USART_CR2_RTOEN;
411+
USART_RTOR(self->port) = 20L;
412+
413+
/* Enable timeout interrupt. */
414+
USART_CR1(self->port) |= USART_CR1_RTOIE;
415+
} else {
416+
USART_CR2(self->port) &= ~USART_CR2_RTOEN;
417+
USART_CR1(self->port) &= ~USART_CR1_RTOIE;
418+
}
419+
420+
return STM32_UART_RET_OK;
421+
}

services/stm32-uart/stm32-uart.h

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ typedef struct {
2222
Uart uart;
2323
Stream stream;
2424
uint32_t port;
25+
bool enable_rto;
2526

2627
uint32_t de_port;
2728
uint32_t de_pin;
@@ -37,3 +38,4 @@ stm32_uart_ret_t stm32_uart_init(Stm32Uart *self, uint32_t port);
3738
stm32_uart_ret_t stm32_uart_free(Stm32Uart *self);
3839
stm32_uart_ret_t stm32_uart_interrupt_handler(Stm32Uart *self);
3940
stm32_uart_ret_t stm32_uart_set_de(Stm32Uart *self, uint32_t de_port, uint32_t de_pin);
41+
stm32_uart_ret_t stm32_uart_set_rto(Stm32Uart *self, bool rto);

0 commit comments

Comments
 (0)