diff --git a/doc/guides/emulator/index.rst b/doc/guides/emulator/index.rst index 6c13de459dc..d96a8cdf5d5 100644 --- a/doc/guides/emulator/index.rst +++ b/doc/guides/emulator/index.rst @@ -88,6 +88,8 @@ Zephyr includes the following emulators: * eSPI emulator driver, which does the same for eSPI. The emulator is being developed to support more functionalities. +* CAN loopback driver + A GPIO emulator is planned but is not yet complete. Samples diff --git a/drivers/can/Kconfig.loopback b/drivers/can/Kconfig.loopback index 7d6b2da9834..5e21b092e7d 100644 --- a/drivers/can/Kconfig.loopback +++ b/drivers/can/Kconfig.loopback @@ -3,19 +3,16 @@ # Copyright (c) 2019 Alexander Wachter # SPDX-License-Identifier: Apache-2.0 +DT_COMPAT_ZEPHYR_CAN_LOOPBACK := zephyr,can-loopback + config CAN_LOOPBACK - bool "Loopback CAN driver" + bool "Emulated CAN loopback driver" + default $(dt_compat_enabled,$(DT_COMPAT_ZEPHYR_CAN_LOOPBACK)) help - This is a dummy driver that can only loopback messages. + This is an emulated driver that can only loopback messages. if CAN_LOOPBACK -config CAN_LOOPBACK_DEV_NAME - string "CAN loopback device name" - default "CAN_LOOPBACK" - help - "Device name for the loopback device" - config CAN_MAX_FILTER int "Maximum number of concurrent active filters" default 16 diff --git a/drivers/can/can_loopback.c b/drivers/can/can_loopback.c index c54efd0ef78..93eac8a034f 100644 --- a/drivers/can/can_loopback.c +++ b/drivers/can/can_loopback.c @@ -1,31 +1,45 @@ /* + * Copyright (c) 2021 Vestas Wind Systems A/S * Copyright (c) 2018 Alexander Wachter * * SPDX-License-Identifier: Apache-2.0 */ -#include -#include +#define DT_DRV_COMPAT zephyr_can_loopback + #include +#include + #include -#include "can_loopback.h" - +#include #include -LOG_MODULE_DECLARE(can_driver, CONFIG_CAN_LOG_LEVEL); -K_KERNEL_STACK_DEFINE(tx_thread_stack, - CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE); -struct k_thread tx_thread_data; +LOG_MODULE_REGISTER(can_loopback, CONFIG_CAN_LOG_LEVEL); -struct can_looppback_frame { +struct can_loopback_frame { struct zcan_frame frame; can_tx_callback_t cb; void *cb_arg; struct k_sem *tx_compl; }; -K_MSGQ_DEFINE(tx_msgq, sizeof(struct can_looppback_frame), - CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE, 4); +struct can_loopback_filter { + can_rx_callback_t rx_cb; + void *cb_arg; + struct zcan_filter filter; +}; + +struct can_loopback_data { + struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER]; + struct k_mutex mtx; + bool loopback; + struct k_msgq tx_msgq; + char msgq_buffer[CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE * sizeof(struct can_loopback_frame)]; + struct k_thread tx_thread_data; + + K_KERNEL_STACK_MEMBER(tx_thread_stack, + CONFIG_CAN_LOOPBACK_TX_THREAD_STACK_SIZE); +}; static void dispatch_frame(const struct zcan_frame *frame, struct can_loopback_filter *filter) @@ -52,12 +66,12 @@ void tx_thread(void *data_arg, void *arg2, void *arg3) { ARG_UNUSED(arg2); ARG_UNUSED(arg3); - struct can_looppback_frame frame; + struct can_loopback_frame frame; struct can_loopback_filter *filter; struct can_loopback_data *data = (struct can_loopback_data *)data_arg; while (1) { - k_msgq_get(&tx_msgq, &frame, K_FOREVER); + k_msgq_get(&data->tx_msgq, &frame, K_FOREVER); k_mutex_lock(&data->mtx, K_FOREVER); for (int i = 0; i < CONFIG_CAN_MAX_FILTER; i++) { @@ -83,9 +97,9 @@ int can_loopback_send(const struct device *dev, k_timeout_t timeout, can_tx_callback_t callback, void *user_data) { - struct can_loopback_data *data = DEV_DATA(dev); + struct can_loopback_data *data = dev->data; int ret; - struct can_looppback_frame loopback_frame; + struct can_loopback_frame loopback_frame; struct k_sem tx_sem; LOG_DBG("Sending %d bytes on %s. Id: 0x%x, ID type: %s %s", @@ -112,7 +126,7 @@ int can_loopback_send(const struct device *dev, k_sem_init(&tx_sem, 0, 1); } - ret = k_msgq_put(&tx_msgq, &loopback_frame, timeout); + ret = k_msgq_put(&data->tx_msgq, &loopback_frame, timeout); if (!callback) { k_sem_take(&tx_sem, K_FOREVER); @@ -137,7 +151,7 @@ int can_loopback_attach_isr(const struct device *dev, can_rx_callback_t isr, void *cb_arg, const struct zcan_filter *filter) { - struct can_loopback_data *data = DEV_DATA(dev); + struct can_loopback_data *data = dev->data; struct can_loopback_filter *loopback_filter; int filter_id; @@ -173,7 +187,7 @@ int can_loopback_attach_isr(const struct device *dev, can_rx_callback_t isr, void can_loopback_detach(const struct device *dev, int filter_id) { - struct can_loopback_data *data = DEV_DATA(dev); + struct can_loopback_data *data = dev->data; LOG_DBG("Detach filter ID: %d", filter_id); k_mutex_lock(&data->mtx, K_FOREVER); @@ -183,7 +197,7 @@ void can_loopback_detach(const struct device *dev, int filter_id) int can_loopback_set_mode(const struct device *dev, enum can_mode mode) { - struct can_loopback_data *data = DEV_DATA(dev); + struct can_loopback_data *data = dev->data; data->loopback = mode == CAN_LOOPBACK_MODE ? 1 : 0; return 0; @@ -243,7 +257,7 @@ int can_loopback_get_max_filters(const struct device *dev, enum can_ide id_type) return CONFIG_CAN_MAX_FILTER; } -static const struct can_driver_api can_api_funcs = { +static const struct can_driver_api can_loopback_driver_api = { .set_mode = can_loopback_set_mode, .set_timing = can_loopback_set_timing, .send = can_loopback_send, @@ -274,7 +288,7 @@ static const struct can_driver_api can_api_funcs = { static int can_loopback_init(const struct device *dev) { - struct can_loopback_data *data = DEV_DATA(dev); + struct can_loopback_data *data = dev->data; k_tid_t tx_tid; k_mutex_init(&data->mtx); @@ -283,8 +297,11 @@ static int can_loopback_init(const struct device *dev) data->filters[i].rx_cb = NULL; } - tx_tid = k_thread_create(&tx_thread_data, tx_thread_stack, - K_KERNEL_STACK_SIZEOF(tx_thread_stack), + k_msgq_init(&data->tx_msgq, data->msgq_buffer, sizeof(struct can_loopback_frame), + CONFIG_CAN_LOOPBACK_TX_MSGQ_SIZE); + + tx_tid = k_thread_create(&data->tx_thread_data, data->tx_thread_stack, + K_KERNEL_STACK_SIZEOF(data->tx_thread_stack), tx_thread, data, NULL, NULL, CONFIG_CAN_LOOPBACK_TX_THREAD_PRIORITY, 0, K_NO_WAIT); @@ -298,46 +315,50 @@ static int can_loopback_init(const struct device *dev) return 0; } -static struct can_loopback_data can_loopback_dev_data_1; - -DEVICE_DEFINE(can_loopback_1, CONFIG_CAN_LOOPBACK_DEV_NAME, - &can_loopback_init, NULL, - &can_loopback_dev_data_1, NULL, - POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, - &can_api_funcs); +#define CAN_LOOPBACK_INIT(inst) \ + static struct can_loopback_data can_loopback_dev_data_##inst; \ + \ + DEVICE_DT_INST_DEFINE(inst, &can_loopback_init, NULL, \ + &can_loopback_dev_data_##inst, NULL, \ + POST_KERNEL, CONFIG_CAN_INIT_PRIORITY, \ + &can_loopback_driver_api); +DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_INIT) #if defined(CONFIG_NET_SOCKETS_CAN) - #include "socket_can_generic.h" -static struct socket_can_context socket_can_context_1; +#define CAN_LOOPBACK_SOCKET_CAN(inst) \ + static struct socket_can_context socket_can_context_##inst; \ + \ + static int socket_can_init_##inst(const struct device *dev) \ + { \ + const struct device *can_dev = DEVICE_DT_INST_GET(inst); \ + struct socket_can_context *socket_context = dev->data; \ + \ + LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", \ + dev, dev->name, can_dev, can_dev->name); \ + \ + socket_context->can_dev = can_dev; \ + socket_context->msgq = &socket_can_msgq; \ + \ + socket_context->rx_tid = \ + k_thread_create(&socket_context->rx_thread_data, \ + rx_thread_stack, \ + K_KERNEL_STACK_SIZEOF(rx_thread_stack), \ + rx_thread, socket_context, NULL, NULL, \ + RX_THREAD_PRIORITY, 0, K_NO_WAIT); \ + \ + return 0; \ + } \ + \ + NET_DEVICE_INIT(socket_can_loopback_##inst, SOCKET_CAN_NAME_##inst, \ + socket_can_init_##inst, NULL, \ + &socket_can_context_##inst, NULL, \ + CONFIG_CAN_INIT_PRIORITY, &socket_can_api, \ + CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), \ + CAN_MTU); -static int socket_can_init_1(const struct device *dev) -{ - const struct device *can_dev = DEVICE_GET(can_loopback_1); - struct socket_can_context *socket_context = dev->data; - - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", - dev, dev->name, can_dev, can_dev->name); - - socket_context->can_dev = can_dev; - socket_context->msgq = &socket_can_msgq; - - socket_context->rx_tid = - k_thread_create(&socket_context->rx_thread_data, - rx_thread_stack, - K_KERNEL_STACK_SIZEOF(rx_thread_stack), - rx_thread, socket_context, NULL, NULL, - RX_THREAD_PRIORITY, 0, K_NO_WAIT); - - return 0; -} - -NET_DEVICE_INIT(socket_can_loopback_1, SOCKET_CAN_NAME_1, socket_can_init_1, - NULL, &socket_can_context_1, NULL, - CONFIG_CAN_INIT_PRIORITY, - &socket_can_api, - CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); +DT_INST_FOREACH_STATUS_OKAY(CAN_LOOPBACK_SOCKET_CAN) #endif /* CONFIG_NET_SOCKETS_CAN */ diff --git a/drivers/can/can_loopback.h b/drivers/can/can_loopback.h deleted file mode 100644 index 2e965b01b52..00000000000 --- a/drivers/can/can_loopback.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2019 Alexander Wachter - * - * SPDX-License-Identifier: Apache-2.0 - * - */ - -#ifndef ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_ -#define ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_ - -#include - -#define DEV_DATA(dev) ((struct can_loopback_data *const)(dev)->data) -#define DEV_CFG(dev) \ - ((const struct can_loopback_config *const)(dev)->config) - -struct can_loopback_filter { - can_rx_callback_t rx_cb; - void *cb_arg; - struct zcan_filter filter; -}; - -struct can_loopback_data { - struct can_loopback_filter filters[CONFIG_CAN_MAX_FILTER]; - struct k_mutex mtx; - bool loopback; -}; - -struct can_loopback_config { -}; - -#endif /*ZEPHYR_DRIVERS_CAN_LOOPBACK_CAN_H_*/ diff --git a/dts/bindings/can/zephyr,can-loopback.yaml b/dts/bindings/can/zephyr,can-loopback.yaml new file mode 100644 index 00000000000..531c6d965bf --- /dev/null +++ b/dts/bindings/can/zephyr,can-loopback.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2021 Vestas Wind Systems A/S +# SPDX-License-Identifier: Apache-2.0 + +description: Zephyr emulated CAN loopback controller + +compatible: "zephyr,can-loopback" + +include: can-controller.yaml diff --git a/tests/drivers/can/api/src/main.c b/tests/drivers/can/api/src/main.c index 36b09f184e9..48e89315c88 100644 --- a/tests/drivers/can/api/src/main.c +++ b/tests/drivers/can/api/src/main.c @@ -44,12 +44,7 @@ #define TEST_CAN_EXT_MASK_ID_2 0x1555556A #define TEST_CAN_EXT_MASK 0x1FFFFFF0 - -#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME) -#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME -#else #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) -#endif CAN_DEFINE_MSGQ(can_msgq, 5); struct k_sem rx_isr_sem; diff --git a/tests/drivers/can/canfd/src/main.c b/tests/drivers/can/canfd/src/main.c index 612c19b5232..7b8aa918a0d 100644 --- a/tests/drivers/can/canfd/src/main.c +++ b/tests/drivers/can/canfd/src/main.c @@ -28,12 +28,7 @@ #define TEST_CAN_STD_ID_1 0x555 #define TEST_CAN_STD_ID_2 0x556 - -#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME) -#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME -#else #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) -#endif CAN_DEFINE_MSGQ(can_msgq, 5); struct k_sem rx_isr_sem; diff --git a/tests/drivers/can/timing/prj_loopback.conf b/tests/drivers/can/timing/prj_loopback.conf deleted file mode 100644 index 7713e442898..00000000000 --- a/tests/drivers/can/timing/prj_loopback.conf +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_CAN=y -CONFIG_ZTEST=y -CONFIG_CAN_LOOPBACK=y diff --git a/tests/drivers/can/timing/src/main.c b/tests/drivers/can/timing/src/main.c index 48eeb3cf547..1b5575781a6 100644 --- a/tests/drivers/can/timing/src/main.c +++ b/tests/drivers/can/timing/src/main.c @@ -22,11 +22,7 @@ * @} */ -#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME) -#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME -#else #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) -#endif const struct device *can_dev; diff --git a/tests/drivers/can/timing/testcase.yaml b/tests/drivers/can/timing/testcase.yaml index d75029a2ce1..1d1c3ec968a 100644 --- a/tests/drivers/can/timing/testcase.yaml +++ b/tests/drivers/can/timing/testcase.yaml @@ -2,7 +2,3 @@ tests: drivers.can.timing: tags: driver can depends_on: can - drivers.can.timing_loopback: - tags: driver can - platform_allow: native_posix - extra_args: CONF_FILE="prj_loopback.conf" diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index 7ad74222582..0b98f778a3c 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -49,11 +49,7 @@ #define BS_TIMEOUT_UPPER_MS 1100 #define BS_TIMEOUT_LOWER_MS 1000 -#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME) -#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME -#else #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) -#endif /* * @addtogroup t_can diff --git a/tests/subsys/canbus/isotp/implementation/src/main.c b/tests/subsys/canbus/isotp/implementation/src/main.c index 3228c5d1577..bcea0ad67d9 100644 --- a/tests/subsys/canbus/isotp/implementation/src/main.c +++ b/tests/subsys/canbus/isotp/implementation/src/main.c @@ -12,11 +12,7 @@ #define NUMBER_OF_REPETITIONS 5 #define DATA_SIZE_SF 7 -#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME) -#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME -#else #define CAN_DEVICE_NAME DT_LABEL(DT_CHOSEN(zephyr_canbus)) -#endif /* * @addtogroup t_can