fixeria has uploaded this change for review. (
https://gerrit.osmocom.org/c/libosmocore/+/35044?usp=email )
Change subject: soft_uart: implement the transmitter
......................................................................
soft_uart: implement the transmitter
Change-Id: Ibcd9643227e5616efd8bbd7a1430feda6fcef45c
Related: OS#4396
---
M include/osmocom/core/soft_uart.h
M src/core/soft_uart.c
2 files changed, 104 insertions(+), 17 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/44/35044/1
diff --git a/include/osmocom/core/soft_uart.h b/include/osmocom/core/soft_uart.h
index df14648..6088922 100644
--- a/include/osmocom/core/soft_uart.h
+++ b/include/osmocom/core/soft_uart.h
@@ -53,6 +53,8 @@
uint8_t num_stop_bits;
/*! parity mode (none, even, odd) */
enum osmo_soft_uart_parity_mode parity_mode;
+ /*! size of transmit buffer */
+ unsigned int tx_buf_size;
/*! size of receive buffer; UART will buffer up to that number of characters
* before calling the receive call-back */
unsigned int rx_buf_size;
@@ -85,5 +87,5 @@
int osmo_soft_uart_rx_ubits(struct osmo_soft_uart *suart, const ubit_t *ubits, size_t
n_ubits);
int osmo_soft_uart_tx_ubits(struct osmo_soft_uart *suart, ubit_t *ubits, size_t
n_ubits);
-void osmo_soft_uart_tx(struct osmo_soft_uart *suart, struct msgb *tx_data);
+size_t osmo_soft_uart_tx(struct osmo_soft_uart *suart, const uint8_t *data, size_t
data_len);
int osmo_soft_uart_set_status(struct osmo_soft_uart *suart, unsigned int status);
diff --git a/src/core/soft_uart.c b/src/core/soft_uart.c
index d92b8bc..9b6ca05 100644
--- a/src/core/soft_uart.c
+++ b/src/core/soft_uart.c
@@ -2,6 +2,7 @@
* Software UART implementation. */
/*
* (C) 2022 by Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
*
* All Rights Reserved
*
@@ -52,8 +53,14 @@
bool running;
uint8_t bit_count;
uint8_t shift_reg;
- struct msgb *msg;
- struct llist_head queue;
+ struct {
+ uint8_t *buf;
+ unsigned int rpos;
+ unsigned int wpos;
+ unsigned int pending;
+ } rb;
+ ubit_t parity_bit; /* 0 (even) / 1 (odd) */
+ enum suart_flow_state flow_state;
} tx;
};
@@ -62,6 +69,7 @@
.num_data_bits = 8,
.num_stop_bits = 1,
.parity_mode = OSMO_SUART_PARITY_NONE,
+ .tx_buf_size = 1024,
.rx_buf_size = 1024,
.rx_timeout_ms = 100,
.priv = NULL,
@@ -194,29 +202,90 @@
* Transmitter
*************************************************************************/
-/*! Enqueue the given message buffer into the transmit queue of the soft-UART.
+/*! Append data to the transmit buffer of the soft-UART.
* \param[in] suart soft-UART instance for transmitting data.
- * \param[in] tx_data message buffer containing to be transmitted data. */
-void osmo_soft_uart_tx(struct osmo_soft_uart *suart, struct msgb *tx_data)
+ * \param[in] data data to be transmitted.
+ * \param[in] data_len number of characters to be transmitted.
+ * \returns Number of characters appended, equal to or less than data_len. */
+size_t osmo_soft_uart_tx(struct osmo_soft_uart *suart,
+ const uint8_t *data, size_t data_len)
{
- if (!suart->tx.msg)
- suart->tx.msg = tx_data;
- else
- msgb_enqueue(&suart->tx.queue, tx_data);
+ size_t len;
+
+ len = OSMO_MIN(data_len, suart->cfg.tx_buf_size - suart->tx.rb.pending);
+ for (size_t i = 0; i < len; i++) {
+ if (suart->tx.rb.wpos >= suart->cfg.tx_buf_size)
+ suart->tx.rb.wpos = 0;
+ suart->tx.rb.buf[suart->tx.rb.wpos++] = data[i];
+ }
+
+ suart->tx.rb.pending += len;
+ return len;
}
/* pull a single bit out of the UART transmitter */
static inline ubit_t osmo_uart_tx_bit(struct osmo_soft_uart *suart)
{
+ ubit_t tx_bit;
+
if (!suart->tx.running)
return 1;
- if (suart->tx.bit_count == 0) {
- /* do we have anything to transmit? */
- /* FIXME */
+ switch (suart->tx.flow_state) {
+ case SUART_FLOW_ST_IDLE:
+ tx_bit = 1;
+ if (suart->tx.rb.pending) {
+ if (suart->tx.rb.rpos >= suart->cfg.tx_buf_size)
+ suart->tx.rb.rpos = 0;
+ suart->tx.shift_reg = suart->tx.rb.buf[suart->tx.rb.rpos++];
+ suart->tx.rb.pending--;
+ suart->tx.flow_state = SUART_FLOW_ST_DATA;
+ suart->tx.bit_count = 0;
+ suart->tx.parity_bit = 0;
+ tx_bit = 0;
+ }
+ break;
+ case SUART_FLOW_ST_DATA:
+ tx_bit = suart->tx.shift_reg & 1;
+ suart->tx.parity_bit ^= tx_bit;
+ suart->tx.shift_reg >>= 1;
+ suart->tx.bit_count++;
+ if (suart->tx.bit_count >= suart->cfg.num_data_bits) {
+ /* we have transmitted all data bits */
+ if (suart->cfg.parity_mode != OSMO_SUART_PARITY_NONE)
+ suart->tx.flow_state = SUART_FLOW_ST_PARITY;
+ else
+ suart->tx.flow_state = SUART_FLOW_ST_STOP;
+ }
+ break;
+ case SUART_FLOW_ST_PARITY:
+ switch (suart->cfg.parity_mode) {
+ case OSMO_SUART_PARITY_EVEN:
+ /* number of 1-bits (in both data and parity) shall be even */
+ tx_bit = suart->tx.parity_bit;
+ break;
+ case OSMO_SUART_PARITY_ODD:
+ /* number of 1-bits (in both data and parity) shall be odd */
+ tx_bit = !suart->tx.parity_bit;
+ break;
+ case OSMO_SUART_PARITY_NONE: /* shall not happen */
+ default:
+ OSMO_ASSERT(0);
+ }
+
+ suart->tx.flow_state = SUART_FLOW_ST_STOP;
+ break;
+ case SUART_FLOW_ST_STOP:
+ tx_bit = 1;
+ suart->tx.bit_count++;
+ if (suart->tx.bit_count >= (suart->cfg.num_data_bits +
suart->cfg.num_stop_bits)) {
+ /* we have transmitted all stop bits, we're done */
+ suart->tx.flow_state = SUART_FLOW_ST_IDLE;
+ }
+ break;
}
- /* FIXME */
- return 1;
+
+ return tx_bit;
}
/*! Pull a number of unpacked bits out of the soft-UART transmitter.
@@ -297,7 +366,6 @@
suart->cfg = *cfg;
osmo_timer_setup(&suart->rx.timer, suart_rx_timer_cb, suart);
- INIT_LLIST_HEAD(&suart->tx.queue);
return 0;
}
@@ -329,10 +397,17 @@
int osmo_soft_uart_set_tx(struct osmo_soft_uart *suart, bool enable)
{
if (!enable && suart->tx.running) {
- /* FIXME: Tx */
+ suart->tx.rb.wpos = 0;
+ suart->tx.rb.rpos = 0;
+ suart->tx.rb.pending = 0;
suart->tx.running = false;
+ suart->tx.flow_state = SUART_FLOW_ST_IDLE;
} else if (enable && !suart->tx.running) {
+ if (suart->tx.rb.buf == NULL)
+ suart->tx.rb.buf = talloc_size(suart, suart->cfg.tx_buf_size);
+ OSMO_ASSERT(suart->tx.rb.buf != NULL);
suart->tx.running = true;
+ suart->tx.flow_state = SUART_FLOW_ST_IDLE;
}
return 0;
--
To view, visit
https://gerrit.osmocom.org/c/libosmocore/+/35044?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ibcd9643227e5616efd8bbd7a1430feda6fcef45c
Gerrit-Change-Number: 35044
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-MessageType: newchange