drivers/serial: Make serial_test a proper emul
Add emulator functionality to the serial_test driver, so that it can be used to simulate a device on the other end of the uart. If you don't set the buffer-size property in the dts node, there should be effectively no change from the previous behavior. Signed-off-by: Jeremy Bettis <jbettis@google.com>
This commit is contained in:
parent
672c7e5caf
commit
da9448396c
|
@ -9,18 +9,108 @@
|
|||
* devices for the "vnd,serial" devicetree compatible used in test code.
|
||||
*/
|
||||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/uart.h>
|
||||
#include <zephyr/drivers/uart/serial_test.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/ring_buffer.h>
|
||||
|
||||
#define DT_DRV_COMPAT vnd_serial
|
||||
struct serial_vnd_data {
|
||||
#ifdef CONFIG_RING_BUFFER
|
||||
struct ring_buf *written;
|
||||
struct ring_buf *read_queue;
|
||||
#endif
|
||||
serial_vnd_write_cb_t callback;
|
||||
void *callback_data;
|
||||
};
|
||||
|
||||
static int serial_vnd_poll_in(const struct device *dev, unsigned char *c)
|
||||
{
|
||||
#ifdef CONFIG_RING_BUFFER
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
uint32_t bytes_read;
|
||||
|
||||
if (data == NULL || data->read_queue == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
bytes_read = ring_buf_get(data->read_queue, c, 1);
|
||||
if (bytes_read == 1) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void serial_vnd_poll_out(const struct device *dev, unsigned char c)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
#ifdef CONFIG_RING_BUFFER
|
||||
if (data == NULL || data->written == NULL) {
|
||||
return;
|
||||
}
|
||||
ring_buf_put(data->written, &c, 1);
|
||||
#endif
|
||||
if (data->callback) {
|
||||
data->callback(dev, data->callback_data);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RING_BUFFER
|
||||
int serial_vnd_queue_in_data(const struct device *dev, unsigned char *c, uint32_t size)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
if (data == NULL || data->read_queue == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return ring_buf_put(data->read_queue, c, size);
|
||||
}
|
||||
|
||||
uint32_t serial_vnd_out_data_size_get(const struct device *dev)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
if (data == NULL || data->written == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return ring_buf_size_get(data->written);
|
||||
}
|
||||
|
||||
uint32_t serial_vnd_read_out_data(const struct device *dev, unsigned char *out_data, uint32_t size)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
if (data == NULL || data->written == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return ring_buf_get(data->written, out_data, size);
|
||||
}
|
||||
|
||||
uint32_t serial_vnd_peek_out_data(const struct device *dev, unsigned char *out_data, uint32_t size)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
if (data == NULL || data->written == NULL) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
return ring_buf_peek(data->written, out_data, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
void serial_vnd_set_callback(const struct device *dev, serial_vnd_write_cb_t callback,
|
||||
void *user_data)
|
||||
{
|
||||
struct serial_vnd_data *data = dev->data;
|
||||
|
||||
if (data == NULL) {
|
||||
return;
|
||||
}
|
||||
data->callback = callback;
|
||||
data->callback_data = user_data;
|
||||
}
|
||||
|
||||
static int serial_vnd_err_check(const struct device *dev)
|
||||
|
@ -55,8 +145,18 @@ static int serial_vnd_init(const struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define VND_SERIAL_DATA_BUFFER(n) \
|
||||
RING_BUF_DECLARE(written_data_##n, DT_INST_PROP(n, buffer_size)); \
|
||||
RING_BUF_DECLARE(read_queue_##n, DT_INST_PROP(n, buffer_size)); \
|
||||
static struct serial_vnd_data serial_vnd_data_##n = { \
|
||||
.written = &written_data_##n, \
|
||||
.read_queue = &read_queue_##n, \
|
||||
};
|
||||
#define VND_SERIAL_DATA(n) static struct serial_vnd_data serial_vnd_data_##n = {};
|
||||
#define VND_SERIAL_INIT(n) \
|
||||
DEVICE_DT_INST_DEFINE(n, &serial_vnd_init, NULL, NULL, NULL, POST_KERNEL, \
|
||||
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, buffer_size), (VND_SERIAL_DATA_BUFFER(n)), \
|
||||
(VND_SERIAL_DATA(n))) \
|
||||
DEVICE_DT_INST_DEFINE(n, &serial_vnd_init, NULL, &serial_vnd_data_##n, NULL, POST_KERNEL, \
|
||||
CONFIG_SERIAL_INIT_PRIORITY, &serial_vnd_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(VND_SERIAL_INIT)
|
||||
|
|
|
@ -11,3 +11,8 @@ properties:
|
|||
baud-rate:
|
||||
type: int
|
||||
required: false
|
||||
|
||||
buffer-size:
|
||||
type: int
|
||||
required: false
|
||||
description: "Size of buffer to capture output data or to queue input data."
|
||||
|
|
106
include/zephyr/drivers/uart/serial_test.h
Normal file
106
include/zephyr/drivers/uart/serial_test.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2022 The ChromiumOS Authors.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_DRIVERS_UART_SERIAL_TEST_H_
|
||||
#define ZEPHYR_INCLUDE_DRIVERS_UART_SERIAL_TEST_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <zephyr/device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Queues data to be read by the virtual serial port.
|
||||
*
|
||||
* @warning
|
||||
* Use cases involving multiple writers virtual serial port must prevent
|
||||
* concurrent write operations, either by preventing all writers from
|
||||
* being preempted or by using a mutex to govern writes.
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
* @param data Address of data.
|
||||
* @param size Data size (in bytes).
|
||||
*
|
||||
* @retval Number of bytes written.
|
||||
*/
|
||||
int serial_vnd_queue_in_data(const struct device *dev, unsigned char *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Returns size of unread written data.
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
*
|
||||
* @return Output data size (in bytes).
|
||||
*/
|
||||
uint32_t serial_vnd_out_data_size_get(const struct device *dev);
|
||||
|
||||
/**
|
||||
* @brief Read data written to virtual serial port.
|
||||
*
|
||||
* Consumes the data, such that future calls to serial_vnd_read_out_data() will
|
||||
* not include this data. Requires CONFIG_RING_BUFFER.
|
||||
*
|
||||
* @warning
|
||||
* Use cases involving multiple reads of the data must prevent
|
||||
* concurrent read operations, either by preventing all readers from
|
||||
* being preempted or by using a mutex to govern reads.
|
||||
*
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
* @param data Address of the output buffer. Can be NULL to discard data.
|
||||
* @param size Data size (in bytes).
|
||||
*
|
||||
* @retval Number of bytes written to the output buffer.
|
||||
*/
|
||||
uint32_t serial_vnd_read_out_data(const struct device *dev, unsigned char *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Peek at data written to virtual serial port.
|
||||
*
|
||||
* Reads the data without consuming it. Future calls to serial_vnd_peek_out_data() or
|
||||
* serial_vnd_read_out_data() will return this data again. Requires CONFIG_RING_BUFFER.
|
||||
*
|
||||
* @warning
|
||||
* Use cases involving multiple reads of the data must prevent
|
||||
* concurrent read operations, either by preventing all readers from
|
||||
* being preempted or by using a mutex to govern reads.
|
||||
*
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
* @param data Address of the output buffer. Cannot be NULL.
|
||||
* @param size Data size (in bytes).
|
||||
*
|
||||
* @retval Number of bytes written to the output buffer.
|
||||
*/
|
||||
uint32_t serial_vnd_peek_out_data(const struct device *dev, unsigned char *data, uint32_t size);
|
||||
|
||||
/**
|
||||
* @brief Callback called after bytes written to the virtual serial port.
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
* @param user_data User data.
|
||||
*/
|
||||
typedef void (*serial_vnd_write_cb_t)(const struct device *dev, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Sets the write callback on a virtual serial port.
|
||||
*
|
||||
* @param dev Address of virtual serial port.
|
||||
* @param callback Function to call after each write to the port.
|
||||
* @param user_data Opaque data to pass to the callback.
|
||||
*
|
||||
*/
|
||||
void serial_vnd_set_callback(const struct device *dev, serial_vnd_write_cb_t callback,
|
||||
void *user_data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_DRIVERS_UART_SERIAL_TEST_H_ */
|
Loading…
Reference in a new issue