soft_uart: rework osmo_uart_rx_bit() to use flow state
Change-Id: I40ab5d12b6f7087daa51405468f5c4ea639561ea
Related: OS#4396
diff --git a/src/core/soft_uart.c b/src/core/soft_uart.c
index 5b58848..c7c8020 100644
--- a/src/core/soft_uart.c
+++ b/src/core/soft_uart.c
@@ -26,6 +26,14 @@
#include <osmocom/core/timer.h>
#include <osmocom/core/soft_uart.h>
+/*! Rx/Tx flow state of a soft-UART */
+enum suart_flow_state {
+ SUART_FLOW_ST_IDLE, /*!< waiting for a start bit or Tx data */
+ SUART_FLOW_ST_DATA, /*!< receiving/transmitting data bits */
+ SUART_FLOW_ST_PARITY, /*!< receiving/transmitting parity bits */
+ SUART_FLOW_ST_STOP, /*!< receiving/transmitting stop bits */
+};
+
/*! Internal state of a soft-UART */
struct osmo_soft_uart {
struct osmo_soft_uart_cfg cfg;
@@ -39,6 +47,7 @@
unsigned int flags;
unsigned int status;
struct osmo_timer_list timer;
+ enum suart_flow_state flow_state;
} rx;
struct {
bool running;
@@ -98,50 +107,46 @@
/* receive a single bit */
static inline void osmo_uart_rx_bit(struct osmo_soft_uart *suart, const ubit_t bit)
{
- unsigned int num_parity_bits = 0;
-
if (!suart->rx.running)
return;
- if (suart->rx.bit_count == 0) {
- /* start bit is 0. Wait if there is none */
- if (bit == 0) {
- /* START bit */
- suart->rx.flags = 0;
+ switch (suart->rx.flow_state) {
+ case SUART_FLOW_ST_IDLE:
+ if (bit == 0) { /* start bit condition */
+ suart->rx.flow_state = SUART_FLOW_ST_DATA;
+ suart->rx.flags = 0x00;
suart->rx.shift_reg = 0;
- suart->rx.bit_count++;
- }
- return;
- }
-
- if (suart->cfg.parity_mode != OSMO_SUART_PARITY_NONE)
- num_parity_bits = 1;
-
- suart->rx.bit_count++;
- if (suart->rx.bit_count <= 1 + suart->cfg.num_data_bits) {
- /* DATA bit */
- suart->rx.shift_reg = suart->rx.shift_reg >> 1;
- if (bit)
- suart->rx.shift_reg |= 0x80;
- } else if (suart->cfg.parity_mode != OSMO_SUART_PARITY_NONE &&
- suart->rx.bit_count == 1 + suart->cfg.num_data_bits + 1) {
- /* PARITY bit */
- suart->rx.parity_bit = bit;
- /* TODO: verify parity */
- //suart->rx.flags |= OSMO_SUART_F_PARITY_ERROR;
- } else if (suart->rx.bit_count <=
- 1 + suart->cfg.num_data_bits + num_parity_bits + suart->cfg.num_stop_bits) {
- /* STOP bit */
- if (bit != 1) {
- fprintf(stderr, "framing error: stop bit %u != 1\n", suart->rx.bit_count);
- suart->rx.flags |= OSMO_SUART_F_FRAMING_ERROR;
- }
-
- if (suart->rx.bit_count == 1 + suart->cfg.num_data_bits + num_parity_bits + suart->cfg.num_stop_bits) {
- //printf("Rx: 0x%02x %c\n", suart->rx.shift_reg, suart->rx.shift_reg);
- suart_rx_ch(suart, suart->rx.shift_reg);
suart->rx.bit_count = 0;
}
+ break;
+ case SUART_FLOW_ST_DATA:
+ suart->rx.bit_count++;
+ suart->rx.shift_reg >>= 1;
+ if (bit != 0)
+ suart->rx.shift_reg |= 0x80;
+ if (suart->rx.bit_count >= suart->cfg.num_data_bits) {
+ /* we have accumulated enough data bits */
+ if (suart->cfg.parity_mode != OSMO_SUART_PARITY_NONE)
+ suart->rx.flow_state = SUART_FLOW_ST_PARITY;
+ else
+ suart->rx.flow_state = SUART_FLOW_ST_STOP;
+ }
+ break;
+ case SUART_FLOW_ST_PARITY:
+ /* TODO: actually verify parity */
+ suart->rx.flow_state = SUART_FLOW_ST_STOP;
+ break;
+ case SUART_FLOW_ST_STOP:
+ suart->rx.bit_count++;
+ if (bit != 1)
+ suart->rx.flags |= OSMO_SUART_F_FRAMING_ERROR;
+
+ if (suart->rx.bit_count >= (suart->cfg.num_data_bits + suart->cfg.num_stop_bits)) {
+ /* we have accumulated enough stop bits */
+ suart_rx_ch(suart, suart->rx.shift_reg);
+ suart->rx.flow_state = SUART_FLOW_ST_IDLE;
+ }
+ break;
}
}
@@ -291,10 +296,12 @@
if (!enable && suart->rx.running) {
suart_flush_rx(suart);
suart->rx.running = false;
+ suart->rx.flow_state = SUART_FLOW_ST_IDLE;
} else if (enable && !suart->rx.running) {
if (!suart->rx.msg)
suart->rx.msg = msgb_alloc_c(suart, suart->cfg.rx_buf_size, "soft_uart rx");
suart->rx.running = true;
+ suart->rx.flow_state = SUART_FLOW_ST_IDLE;
}
return 0;