laforge has submitted this change. ( 
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/libosmocore.map
M src/core/soft_uart.c
3 files changed, 96 insertions(+), 28 deletions(-)

Approvals:
  laforge: Looks good to me, approved
  Jenkins Builder: Verified




diff --git a/include/osmocom/core/soft_uart.h b/include/osmocom/core/soft_uart.h
index 2b9d67f..df2faac 100644
--- a/include/osmocom/core/soft_uart.h
+++ b/include/osmocom/core/soft_uart.h
@@ -68,6 +68,11 @@
         * 'flags' is a bit-mask of osmo_soft_uart_flags,  */
        void (*rx_cb)(void *priv, struct msgb *rx_data, unsigned int flags);

+       /*! transmit call-back. The implementation is expected to provide at 
most
+        * tx_data->data_len characters (the actual amount is detetmined by the
+        * number of requested bits and the effective UART configuration). */
+       void (*tx_cb)(void *priv, struct msgb *tx_data);
+
        /*! modem status line change call-back. gets bitmask of 
osmo_soft_uart_status */
        void (*status_change_cb)(void *priv, unsigned int status);
 };
@@ -86,5 +91,4 @@
 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);
 int osmo_soft_uart_set_status(struct osmo_soft_uart *suart, unsigned int 
status);
diff --git a/src/core/libosmocore.map b/src/core/libosmocore.map
index a9d25fb..e6a1866 100644
--- a/src/core/libosmocore.map
+++ b/src/core/libosmocore.map
@@ -447,7 +447,6 @@
 osmo_soft_uart_set_tx;
 osmo_soft_uart_rx_ubits;
 osmo_soft_uart_tx_ubits;
-osmo_soft_uart_tx;
 osmo_soft_uart_set_status;
 osmo_stat_item_dec;
 osmo_stat_item_flush;
diff --git a/src/core/soft_uart.c b/src/core/soft_uart.c
index d8ce9d9..238425a 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 <lafo...@gnumonks.org>
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
  *
  * All Rights Reserved
  *
@@ -53,8 +54,8 @@
                bool running;
                uint8_t bit_count;
                uint8_t shift_reg;
-               struct msgb *msg;
-               struct llist_head queue;
+               ubit_t parity_bit; /* 0 (even) / 1 (odd) */
+               enum suart_flow_state flow_state;
        } tx;
 };

@@ -79,7 +80,7 @@
                if (suart->cfg.rx_cb) {
                        suart->cfg.rx_cb(suart->cfg.priv, suart->rx.msg, 
suart->rx.flags);
                        /* call-back has taken ownership of msgb, no need to 
free() here */
-                       suart->rx.msg = msgb_alloc_c(suart, 
suart->cfg.rx_buf_size, "soft_uart rx");
+                       suart->rx.msg = msgb_alloc_c(suart, 
suart->cfg.rx_buf_size, "soft_uart_rx");
                } else {
                        msgb_reset(suart->rx.msg);
                }
@@ -191,29 +192,64 @@
  * Transmitter
  *************************************************************************/

-/*! Enqueue the given message buffer into the transmit queue 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)
-{
-       if (!suart->tx.msg)
-               suart->tx.msg = tx_data;
-       else
-               msgb_enqueue(&suart->tx.queue, tx_data);
-}
-
 /* pull a single bit out of the UART transmitter */
-static inline ubit_t osmo_uart_tx_bit(struct osmo_soft_uart *suart)
+static inline ubit_t osmo_uart_tx_bit(struct osmo_soft_uart *suart, struct 
msgb *msg)
 {
-       if (!suart->tx.running)
-               return 1;
+       ubit_t tx_bit = 1;

-       if (suart->tx.bit_count == 0) {
-               /* do we have anything to transmit? */
-               /* FIXME */
+       if (!suart->tx.running)
+               return tx_bit;
+
+       switch (suart->tx.flow_state) {
+       case SUART_FLOW_ST_IDLE:
+               if (msgb_length(msg) > 0) { /* if we have pending data */
+                       suart->tx.shift_reg = msgb_pull_u8(msg);
+                       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:
+               default: /* shall not happen */
+                       OSMO_ASSERT(0);
+               }
+
+               suart->tx.flow_state = SUART_FLOW_ST_STOP;
+               break;
+       case SUART_FLOW_ST_STOP:
+               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.
@@ -223,9 +259,28 @@
  * \returns number of unpacked bits pulled; negative on error. */
 int osmo_soft_uart_tx_ubits(struct osmo_soft_uart *suart, ubit_t *ubits, 
size_t n_ubits)
 {
+       const struct osmo_soft_uart_cfg *cfg = &suart->cfg;
+       size_t n_frame_bits;
+       struct msgb *msg;
+
+       /* calculate UART frame size for the effective config */
+       n_frame_bits = 1 + cfg->num_data_bits + cfg->num_stop_bits;
+       if (cfg->parity_mode != OSMO_SUART_PARITY_NONE)
+               n_frame_bits += 1;
+
+       /* allocate a Tx buffer msgb */
+       msg = msgb_alloc_c(suart, n_ubits / n_frame_bits, "soft_uart_tx");
+       OSMO_ASSERT(msg != NULL);
+
+       /* call the .tx_cb() to populate the Tx buffer */
+       OSMO_ASSERT(cfg->tx_cb != NULL);
+       suart->cfg.tx_cb(cfg->priv, msg);
+
        for (size_t i = 0; i < n_ubits; i++)
-               ubits[i] = osmo_uart_tx_bit(suart);
-       return n_ubits;
+               ubits[i] = osmo_uart_tx_bit(suart, msg);
+       msgb_free(msg);
+
+       return 0;
 }

 /*! Set the modem status lines of the given soft-UART.
@@ -300,7 +355,6 @@
        suart->cfg = *cfg;

        osmo_timer_setup(&suart->rx.timer, suart_rx_timer_cb, suart);
-       INIT_LLIST_HEAD(&suart->tx.queue);

        return 0;
 }
@@ -332,10 +386,11 @@
 int osmo_soft_uart_set_tx(struct osmo_soft_uart *suart, bool enable)
 {
        if (!enable && suart->tx.running) {
-               /* FIXME: Tx */
                suart->tx.running = false;
+               suart->tx.flow_state = SUART_FLOW_ST_IDLE;
        } else if (enable && !suart->tx.running) {
                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: 5
Gerrit-Owner: fixeria <vyanits...@sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: jolly <andr...@eversberg.eu>
Gerrit-Reviewer: laforge <lafo...@osmocom.org>
Gerrit-MessageType: merged

Reply via email to