aboutsummaryrefslogtreecommitdiffstats
path: root/include/osmocom/core/soft_uart.h
blob: afc6ad6db0382fb08ab7f04af916a72dc04fee7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#pragma once

/*! \file soft_uart.h
 *  Software UART implementation. */
/*
 * (C) 2022 by Harald Welte <laforge@gnumonks.org>
 * (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 *
 * All Rights Reserved
 *
 * SPDX-License-Identifier: GPL-2.0+
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <stdint.h>
#include <stdbool.h>

#include <osmocom/core/bits.h>
#include <osmocom/core/msgb.h>

/*! Parity mode.
 * https://en.wikipedia.org/wiki/Parity_bit */
enum osmo_soft_uart_parity_mode {
	OSMO_SUART_PARITY_NONE,		/*!< No parity bit */
	OSMO_SUART_PARITY_EVEN,		/*!< Even parity */
	OSMO_SUART_PARITY_ODD,		/*!< Odd parity */
	OSMO_SUART_PARITY_MARK,		/*!< Always 1 */
	OSMO_SUART_PARITY_SPACE,	/*!< Always 0 */
	_OSMO_SUART_PARITY_NUM
};

/*! Flags passed to the application. */
enum osmo_soft_uart_flags {
	OSMO_SUART_F_FRAMING_ERROR	= (1 << 0),	/*!< Framing error occurred */
	OSMO_SUART_F_PARITY_ERROR	= (1 << 1),	/*!< Parity error occurred */
	OSMO_SUART_F_BREAK		= (1 << 2),	/*!< Break condition (not implemented) */
};

/*! Modem status "line" flags.
 * https://en.wikipedia.org/wiki/RS-232#Data_and_control_signals */
enum osmo_soft_uart_status {
	OSMO_SUART_STATUS_F_DTR		= (1 << 0),	/*!< Data Terminal Ready */
	OSMO_SUART_STATUS_F_DCD		= (1 << 1),	/*!< Data Carrier Detect */
	OSMO_SUART_STATUS_F_DSR		= (1 << 2),	/*!< Data Set Ready */
	OSMO_SUART_STATUS_F_RI		= (1 << 3),	/*!< Ring Indicator */
	OSMO_SUART_STATUS_F_RTS_RTR	= (1 << 4),	/*!< Request To Send or Ready To Receive */
	OSMO_SUART_STATUS_F_CTS		= (1 << 5),	/*!< Clear To Send */
};

/*! Flow control mode.
 * https://en.wikipedia.org/wiki/Flow_control_(data)#Hardware_flow_control */
enum osmo_soft_uart_flow_ctrl_mode {
	/*! No flow control */
	OSMO_SUART_FLOW_CTRL_NONE,
	/*! DTR/DSR flow control: Tx if DSR is active and drop DTR if cannot Rx anymore. */
	OSMO_SUART_FLOW_CTRL_DTR_DSR,
	/*! RTS/CTS flow control: Tx if CTS is active and drop RTS if cannot Rx anymore.
	 * The technically correct name would be RTR/CTS, because the RTS signal actually
	 * indicates readiness to *receive* data (Ready To Receive), and not really used
	 * to request a transmission (Request To Send) nowadays.  Alternatively, the RTS
	 * signal can be interpreted as "Request To Send to me". */
	OSMO_SUART_FLOW_CTRL_RTS_CTS,
};

/*! Configuration for a soft-UART. */
struct osmo_soft_uart_cfg {
	/*! Number of data bits (typically 5, 6, 7 or 8). */
	uint8_t num_data_bits;
	/*! Number of stop bits (typically 1 or 2). */
	uint8_t num_stop_bits;
	/*! Parity mode (none, even, odd, space, mark). */
	enum osmo_soft_uart_parity_mode parity_mode;
	/*! Size of the receive buffer; UART will buffer up to that number
	 * of characters before calling the receive call-back. */
	unsigned int rx_buf_size;
	/*! Receive timeout; UART will flush the receive buffer via the receive call-back
	 * after indicated number of milliseconds, even if it is not full yet. */
	unsigned int rx_timeout_ms;

	/*! Opaque application-private data; passed to call-backs. */
	void *priv;

	/*! Receive call-back of the application.
	 *
	 * Called if at least one of the following conditions is met:
	 * a) rx_buf_size characters were received (Rx buffer is full);
	 * b) rx_timeout_ms expired and Rx buffer is not empty;
	 * c) a parity or framing error is occurred.
	 *
	 * \param[in] priv opaque application-private data.
	 * \param[in] rx_data msgb holding the received data.
	 *                    Must be free()ed by the application.
	 * \param[in] flags bit-mask of OSMO_SUART_F_*. */
	void (*rx_cb)(void *priv, struct msgb *rx_data, unsigned int flags);

	/*! Transmit call-back of the application.
	 *
	 * The implementation is expected to provide at most tx_data->data_len
	 * characters (the actual amount is determined by the number of requested
	 * bits and the effective UART configuration).
	 *
	 * \param[in] priv opaque application-private data.
	 * \param[inout] tx_data msgb for writing to be transmitted data. */
	void (*tx_cb)(void *priv, struct msgb *tx_data);

	/*! Modem status line change call-back.
	 * \param[in] priv opaque application-private data.
	 * \param[in] status updated status; bit-mask of OSMO_SUART_STATUS_F_*. */
	void (*status_change_cb)(void *priv, unsigned int status);

	/*! "Hardware" flow control mode. */
	enum osmo_soft_uart_flow_ctrl_mode flow_ctrl_mode;
};

extern const struct osmo_soft_uart_cfg osmo_soft_uart_default_cfg;

struct osmo_soft_uart;

struct osmo_soft_uart *osmo_soft_uart_alloc(void *ctx, const char *name,
					    const struct osmo_soft_uart_cfg *cfg);
void osmo_soft_uart_free(struct osmo_soft_uart *suart);
int osmo_soft_uart_configure(struct osmo_soft_uart *suart, const struct osmo_soft_uart_cfg *cfg);

const char *osmo_soft_uart_get_name(const struct osmo_soft_uart *suart);
void osmo_soft_uart_set_name(struct osmo_soft_uart *suart, const char *name);

int osmo_soft_uart_set_rx(struct osmo_soft_uart *suart, bool enable);
int osmo_soft_uart_set_tx(struct osmo_soft_uart *suart, bool enable);

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);

unsigned int osmo_soft_uart_get_status(const struct osmo_soft_uart *suart);
int osmo_soft_uart_set_status(struct osmo_soft_uart *suart, unsigned int status);
void osmo_soft_uart_set_status_line(struct osmo_soft_uart *suart,
				    enum osmo_soft_uart_status line,
				    bool active);

void osmo_soft_uart_flush_rx(struct osmo_soft_uart *suart);