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