Loading...
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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | /*
* Copyright (c) 2019 omSquare s.r.o.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/uart.h>
#include <SEGGER_RTT.h>
#define DT_DRV_COMPAT segger_rtt_uart
extern struct k_mutex rtt_term_mutex;
struct uart_rtt_config {
void *up_buffer;
size_t up_size;
void *down_buffer;
size_t down_size;
uint8_t channel;
};
struct uart_rtt_data {
#ifdef CONFIG_UART_ASYNC_API
uart_callback_t callback;
void *user_data;
#endif /* CONFIG_UART_ASYNC_API */
};
static int uart_rtt_init(const struct device *dev)
{
/*
* Channel 0 is initialized at compile-time, Kconfig ensures that
* it is configured in correct, non-blocking mode. Other channels
* need to be configured at run-time.
*/
if (dev->config) {
const struct uart_rtt_config *cfg = dev->config;
SEGGER_RTT_ConfigUpBuffer(cfg->channel, dev->name,
cfg->up_buffer, cfg->up_size,
SEGGER_RTT_MODE_NO_BLOCK_SKIP);
SEGGER_RTT_ConfigDownBuffer(cfg->channel, dev->name,
cfg->down_buffer, cfg->down_size,
SEGGER_RTT_MODE_NO_BLOCK_SKIP);
}
return 0;
}
/**
* @brief Poll the device for input.
*
* @param dev UART device struct
* @param c Pointer to character
*
* @return 0 if a character arrived, -1 if the input buffer if empty.
*/
static int uart_rtt_poll_in(const struct device *dev, unsigned char *c)
{
const struct uart_rtt_config *config = dev->config;
unsigned int ch = config ? config->channel : 0;
unsigned int ret = SEGGER_RTT_Read(ch, c, 1);
return ret ? 0 : -1;
}
/**
* @brief Output a character in polled mode.
*
* @param dev UART device struct
* @param c Character to send
*/
static void uart_rtt_poll_out(const struct device *dev, unsigned char c)
{
const struct uart_rtt_config *config = dev->config;
unsigned int ch = config ? config->channel : 0;
SEGGER_RTT_Write(ch, &c, 1);
}
#ifdef CONFIG_UART_ASYNC_API
static int uart_rtt_callback_set(const struct device *dev,
uart_callback_t callback, void *user_data)
{
struct uart_rtt_data *data = dev->data;
data->callback = callback;
data->user_data = user_data;
return 0;
}
static int uart_rtt_tx(const struct device *dev,
const uint8_t *buf, size_t len, int32_t timeout)
{
const struct uart_rtt_config *cfg = dev->config;
struct uart_rtt_data *data = dev->data;
unsigned int ch = cfg ? cfg->channel : 0;
ARG_UNUSED(timeout);
/* RTT mutex cannot be claimed in ISRs */
if (k_is_in_isr()) {
return -ENOTSUP;
}
/* Claim the RTT lock */
if (k_mutex_lock(&rtt_term_mutex, K_NO_WAIT) != 0) {
return -EBUSY;
}
/* Output the buffer */
SEGGER_RTT_WriteNoLock(ch, buf, len);
/* Return RTT lock */
SEGGER_RTT_UNLOCK();
/* Send the TX complete callback */
if (data->callback) {
struct uart_event evt = {
.type = UART_TX_DONE,
.data.tx.buf = buf,
.data.tx.len = len
};
data->callback(dev, &evt, data->user_data);
}
return 0;
}
static int uart_rtt_tx_abort(const struct device *dev)
{
/* RTT TX is a memcpy, there is never a transmission to abort */
ARG_UNUSED(dev);
return -EFAULT;
}
static int uart_rtt_rx_enable(const struct device *dev,
uint8_t *buf, size_t len, int32_t timeout)
{
/* SEGGER RTT reception is implemented as a direct memory write to RAM
* by a connected debugger. As such there is no hardware interrupt
* or other mechanism to know when the debugger has added data to be
* read. Asynchronous RX does not make sense in such a context, and is
* therefore not supported.
*/
ARG_UNUSED(dev);
ARG_UNUSED(buf);
ARG_UNUSED(len);
ARG_UNUSED(timeout);
return -ENOTSUP;
}
static int uart_rtt_rx_disable(const struct device *dev)
{
/* Asynchronous RX not supported, see uart_rtt_rx_enable */
ARG_UNUSED(dev);
return -EFAULT;
}
static int uart_rtt_rx_buf_rsp(const struct device *dev,
uint8_t *buf, size_t len)
{
/* Asynchronous RX not supported, see uart_rtt_rx_enable */
ARG_UNUSED(dev);
ARG_UNUSED(buf);
ARG_UNUSED(len);
return -ENOTSUP;
}
#endif /* CONFIG_UART_ASYNC_API */
static const struct uart_driver_api uart_rtt_driver_api = {
.poll_in = uart_rtt_poll_in,
.poll_out = uart_rtt_poll_out,
#ifdef CONFIG_UART_ASYNC_API
.callback_set = uart_rtt_callback_set,
.tx = uart_rtt_tx,
.tx_abort = uart_rtt_tx_abort,
.rx_enable = uart_rtt_rx_enable,
.rx_buf_rsp = uart_rtt_rx_buf_rsp,
.rx_disable = uart_rtt_rx_disable,
#endif /* CONFIG_UART_ASYNC_API */
};
#define UART_RTT(idx) DT_NODELABEL(rtt##idx)
#define UART_RTT_PROP(idx, prop) DT_PROP(UART_RTT(idx), prop)
#define UART_RTT_CONFIG_NAME(idx) uart_rtt##idx##_config
#define UART_RTT_CONFIG(idx) \
static \
uint8_t uart_rtt##idx##_tx_buf[UART_RTT_PROP(idx, tx_buffer_size)]; \
static \
uint8_t uart_rtt##idx##_rx_buf[UART_RTT_PROP(idx, rx_buffer_size)]; \
\
static const struct uart_rtt_config UART_RTT_CONFIG_NAME(idx) = { \
.up_buffer = uart_rtt##idx##_tx_buf, \
.up_size = sizeof(uart_rtt##idx##_tx_buf), \
.down_buffer = uart_rtt##idx##_rx_buf, \
.down_size = sizeof(uart_rtt##idx##_rx_buf), \
}
#define UART_RTT_INIT(idx, config) \
struct uart_rtt_data uart_rtt##idx##_data; \
\
DEVICE_DT_DEFINE(UART_RTT(idx), uart_rtt_init, NULL, \
&uart_rtt##idx##_data, config, \
PRE_KERNEL_2, CONFIG_SERIAL_INIT_PRIORITY, \
&uart_rtt_driver_api)
#ifdef CONFIG_UART_RTT_0
UART_RTT_INIT(0, NULL);
#endif
#ifdef CONFIG_UART_RTT_1
UART_RTT_CONFIG(1);
UART_RTT_INIT(1, &UART_RTT_CONFIG_NAME(1));
#endif
#ifdef CONFIG_UART_RTT_2
UART_RTT_CONFIG(2);
UART_RTT_INIT(2, &UART_RTT_CONFIG_NAME(2));
#endif
#ifdef CONFIG_UART_RTT_3
UART_RTT_CONFIG(3);
UART_RTT_INIT(3, &UART_RTT_CONFIG_NAME(3));
#endif
|