From 713cc0b6c1ff67b1129b7092672c0c02bcb3e3db Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Thu, 28 Feb 2019 16:54:13 +0200 Subject: [PATCH 1/4] drivers: can: Add support for native_posix board This initial version supports SocketCAN. The driver passes CANBUS data between Linux vcan virtual CAN driver and Zephyr. You also need to use can-setup.sh script from the net-tools project in order to make communication work with Linux vcan driver. Signed-off-by: Jukka Rissanen --- drivers/can/CMakeLists.txt | 12 + drivers/can/Kconfig | 1 + drivers/can/Kconfig.native_posix | 28 +++ drivers/can/canbus_native_posix.c | 313 ++++++++++++++++++++++++ drivers/can/canbus_native_posix_adapt.c | 179 ++++++++++++++ drivers/can/canbus_native_posix_priv.h | 24 ++ 6 files changed, 557 insertions(+) create mode 100644 drivers/can/Kconfig.native_posix create mode 100644 drivers/can/canbus_native_posix.c create mode 100644 drivers/can/canbus_native_posix_adapt.c create mode 100644 drivers/can/canbus_native_posix_priv.h diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index 8276094bd737e..28e36c324e83d 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -12,3 +12,15 @@ zephyr_sources_ifdef(CONFIG_CAN_RCAR can_rcar.c) zephyr_sources_ifdef(CONFIG_USERSPACE can_handlers.c) zephyr_sources_ifdef(CONFIG_CAN_SHELL can_shell.c) zephyr_sources_ifdef(CONFIG_CAN_NET can_net.c) + +if(CONFIG_CAN_NATIVE_POSIX) + zephyr_library() + zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/l2) + zephyr_library_compile_definitions(NO_POSIX_CHEATS) + zephyr_library_compile_definitions(_BSD_SOURCE) + zephyr_library_compile_definitions(_DEFAULT_SOURCE) + zephyr_library_sources( + canbus_native_posix.c + canbus_native_posix_adapt.c + ) +endif() \ No newline at end of file diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index ba975e9640bdf..219282694d314 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -94,5 +94,6 @@ source "drivers/can/Kconfig.mcan" source "drivers/can/Kconfig.rcar" source "drivers/can/Kconfig.loopback" source "drivers/can/Kconfig.net" +source "drivers/can/Kconfig.native_posix" endif # CAN diff --git a/drivers/can/Kconfig.native_posix b/drivers/can/Kconfig.native_posix new file mode 100644 index 0000000000000..1efede3a36a2c --- /dev/null +++ b/drivers/can/Kconfig.native_posix @@ -0,0 +1,28 @@ +# Kconfig.native_posix - native_posix CAN configuration options + +# +# Copyright (c) 2019 Intel Corporation +# +# SPDX-License-Identifier: Apache-2.0 +# + +config CAN_NATIVE_POSIX + bool "native_posix CAN Driver" + depends on ARCH_POSIX + help + Enable native_posix CAN driver + +config CAN_MAX_FILTER + int "Maximum number of concurrent active filters" + depends on CAN_NATIVE_POSIX + default 32 + range 1 56 + help + Defines the array size of the callback/msgq pointers. + Must be at least the size of concurrent reads. + +config CAN_NATIVE_POSIX_INTERFACE_NAME + string "CANBUS interface name in Linux side" + default "zcan" + help + This option sets the CANBUS network interface name in host system. diff --git a/drivers/can/canbus_native_posix.c b/drivers/can/canbus_native_posix.c new file mode 100644 index 0000000000000..81bdaa9fc2658 --- /dev/null +++ b/drivers/can/canbus_native_posix.c @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * CANBUS driver for native_posix board. This is meant to test CANBUS + * connectivity between host and Zephyr. + */ + +#define LOG_MODULE_NAME canbus_posix +#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "canbus_native_posix_priv.h" + +#define NET_BUF_TIMEOUT K_MSEC(100) +#define DT_CAN_1_NAME "CAN_1" + +struct canbus_np_context { + u8_t recv[CAN_MTU]; + + struct device *can_dev; + struct k_msgq *msgq; + struct net_if *iface; + const char *if_name; + int dev_fd; + bool init_done; +}; + +NET_STACK_DEFINE(RX_ZCAN, canbus_rx_stack, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); +static struct k_thread rx_thread_data; + +/* TODO: support multiple interfaces */ +static struct canbus_np_context canbus_context_data; + +static int read_data(struct canbus_np_context *ctx, int fd) +{ + struct net_pkt *pkt; + int count; + + count = canbus_np_read_data(fd, ctx->recv, sizeof(ctx->recv)); + if (count <= 0) { + return 0; + } + + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count, + AF_CAN, 0, NET_BUF_TIMEOUT); + if (!pkt) { + return -ENOMEM; + } + + if (net_pkt_write_new(pkt, ctx->recv, count)) { + net_pkt_unref(pkt); + return -ENOBUFS; + } + + if (net_recv_data(ctx->iface, pkt) < 0) { + net_pkt_unref(pkt); + } + + return 0; +} + +static void canbus_np_rx(struct canbus_np_context *ctx) +{ + int ret; + + LOG_DBG("Starting ZCAN RX thread"); + + while (1) { + if (ctx->iface && net_if_is_up(ctx->iface)) { + ret = canbus_np_wait_data(ctx->dev_fd); + if (!ret) { + read_data(ctx, ctx->dev_fd); + } + } + + k_sleep(K_MSEC(50)); + } +} + +static void create_rx_handler(struct canbus_np_context *ctx) +{ + k_thread_create(&rx_thread_data, canbus_rx_stack, + K_THREAD_STACK_SIZEOF(canbus_rx_stack), + (k_thread_entry_t)canbus_np_rx, + ctx, NULL, NULL, K_PRIO_COOP(14), + 0, K_NO_WAIT); +} + +static int canbus_np_init(struct device *dev) +{ + struct canbus_np_context *ctx = dev->driver_data; + + ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_NAME; + + ctx->dev_fd = canbus_np_iface_open(ctx->if_name); + if (ctx->dev_fd < 0) { + LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd); + } else { + /* Create a thread that will handle incoming data from host */ + create_rx_handler(ctx); + } + + return 0; +} + +static int canbus_np_runtime_configure(struct device *dev, enum can_mode mode, + u32_t bitrate) +{ + ARG_UNUSED(dev); + ARG_UNUSED(mode); + ARG_UNUSED(bitrate); + + return 0; +} + +static int canbus_np_send(struct device *dev, const struct zcan_frame *msg, + s32_t timeout, can_tx_callback_t callback) +{ + struct canbus_np_context *ctx = dev->driver_data; + int ret = -ENODEV; + + ARG_UNUSED(timeout); + ARG_UNUSED(callback); + + if (ctx->dev_fd > 0) { + struct can_frame frame; + + can_copy_zframe_to_frame(msg, &frame); + + ret = canbus_np_write_data(ctx->dev_fd, &frame, sizeof(frame)); + if (ret < 0) { + LOG_ERR("Cannot send CAN data len %d (%d)", + frame.can_dlc, -errno); + } + } + + return ret < 0 ? ret : 0; +} + +static int canbus_np_attach_msgq(struct device *dev, struct k_msgq *msgq, + const struct zcan_filter *filter) +{ + ARG_UNUSED(dev); + ARG_UNUSED(msgq); + ARG_UNUSED(filter); + + return 0; +} + +static int canbus_np_attach_isr(struct device *dev, can_rx_callback_t isr, + const struct zcan_filter *filter) +{ + ARG_UNUSED(dev); + ARG_UNUSED(isr); + ARG_UNUSED(filter); + + return 0; +} + +static void canbus_np_detach(struct device *dev, int filter_nr) +{ + ARG_UNUSED(dev); + ARG_UNUSED(filter_nr); +} + +static const struct can_driver_api can_api_funcs = { + .configure = canbus_np_runtime_configure, + .send = canbus_np_send, + .attach_msgq = canbus_np_attach_msgq, + .attach_isr = canbus_np_attach_isr, + .detach = canbus_np_detach, +}; + +#ifdef CONFIG_CAN_1 + +DEVICE_AND_API_INIT(canbus_np_1, DT_CAN_1_NAME, + canbus_np_init, &canbus_context_data, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &can_api_funcs); + +#if defined(CONFIG_NET_SOCKETS_CAN) + +#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1" +#define SEND_TIMEOUT K_MSEC(100) +#define BUF_ALLOC_TIMEOUT K_MSEC(50) + +/* TODO: make msgq size configurable */ +CAN_DEFINE_MSGQ(socket_can_msgq, 5); + +static void socket_can_iface_init(struct net_if *iface) +{ + struct device *dev = net_if_get_device(iface); + struct canbus_np_context *socket_context = dev->driver_data; + + socket_context->iface = iface; + + LOG_DBG("Init CAN interface %p dev %p", iface, dev); +} + +static void tx_irq_callback(u32_t error_flags) +{ + if (error_flags) { + LOG_DBG("Callback! error-code: %d", error_flags); + } +} + +/* This is called by net_if.c when packet is about to be sent */ +static int socket_can_send(struct device *dev, struct net_pkt *pkt) +{ + struct canbus_np_context *socket_context = dev->driver_data; + int ret; + + if (net_pkt_family(pkt) != AF_CAN) { + return -EPFNOSUPPORT; + } + + ret = can_send(socket_context->can_dev, + (struct zcan_frame *)pkt->frags->data, + SEND_TIMEOUT, tx_irq_callback); + if (ret) { + LOG_DBG("Cannot send socket CAN msg (%d)", ret); + } + + /* If something went wrong, then we need to return negative value to + * net_if.c:net_if_tx() so that the net_pkt will get released. + */ + return -ret; +} + +static int socket_can_setsockopt(struct device *dev, void *obj, + int level, int optname, + const void *optval, socklen_t optlen) +{ + struct canbus_np_context *socket_context = dev->driver_data; + struct can_filter filter; + + if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { + errno = EINVAL; + return -1; + } + + /* Our userspace can send either zcan_filter or can_filter struct. + * They are different sizes so we need to convert them if needed. + */ + if (optlen != sizeof(struct can_filter) && + optlen != sizeof(struct zcan_filter)) { + errno = EINVAL; + return -1; + } + + if (optlen == sizeof(struct zcan_filter)) { + can_copy_zfilter_to_filter((struct zcan_filter *)optval, + &filter); + } else { + memcpy(&filter, optval, sizeof(filter)); + } + + return canbus_np_setsockopt(socket_context->dev_fd, level, optname, + &filter, sizeof(filter)); +} + +static struct canbus_api socket_can_api = { + .iface_api.init = socket_can_iface_init, + .send = socket_can_send, + .setsockopt = socket_can_setsockopt, +}; + +static int socket_can_init_1(struct device *dev) +{ + struct device *can_dev = DEVICE_GET(canbus_np_1); + struct canbus_np_context *socket_context = dev->driver_data; + + LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", + dev, dev->config->name, can_dev, can_dev->config->name); + + socket_context->can_dev = can_dev; + socket_context->msgq = &socket_can_msgq; + + return 0; +} + +NET_DEVICE_INIT(socket_can_native_posix_1, SOCKET_CAN_NAME_1, + socket_can_init_1, &canbus_context_data, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, + CANBUS_L2, NET_L2_GET_CTX_TYPE(CANBUS_L2), CAN_MTU); + +#endif /* CONFIG_NET_SOCKETS_CAN */ + +#endif /* CONFIG_CAN_1 */ diff --git a/drivers/can/canbus_native_posix_adapt.c b/drivers/can/canbus_native_posix_adapt.c new file mode 100644 index 0000000000000..3d06b30e0ba63 --- /dev/null +++ b/drivers/can/canbus_native_posix_adapt.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * Routines setting up the host system. Those are placed in separate file + * because there is naming conflicts between host and zephyr network stacks. + */ + +/* Host include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "posix_trace.h" + +#ifdef __linux +#include +#endif + +/* Zephyr include files. Be very careful here and only include minimum + * things needed. + */ +#define LOG_MODULE_NAME canbus_posix_adapt +#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include + +#include "canbus_native_posix_priv.h" + +int canbus_np_iface_open(const char *if_name) +{ + struct sockaddr_can addr; + struct ifreq ifr; + int fd, ret = -EINVAL; + + fd = socket(PF_CAN, SOCK_RAW, CAN_RAW); + if (fd < 0) { + return -errno; + } + + (void)memset(&ifr, 0, sizeof(ifr)); + (void)memset(&addr, 0, sizeof(addr)); + +#ifdef __linux + strncpy(ifr.ifr_name, if_name, IFNAMSIZ); + + ret = ioctl(fd, SIOCGIFINDEX, (void *)&ifr); + if (ret < 0) { + ret = -errno; + close(fd); + return ret; + } + + /* Setup address for bind */ + addr.can_ifindex = ifr.ifr_ifindex; + addr.can_family = PF_CAN; + + /* bind socket to the zcan interface */ + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + ret = -errno; + close(fd); + return ret; + } +#endif + + return fd; +} + +int canbus_np_iface_remove(int fd) +{ + return close(fd); +} + +static int ssystem(const char *fmt, ...) + __attribute__((__format__(__printf__, 1, 2))); + +static int ssystem(const char *fmt, ...) +{ + char cmd[255]; + va_list ap; + int ret; + + va_start(ap, fmt); + vsnprintf(cmd, sizeof(cmd), fmt, ap); + va_end(ap); + + posix_print_trace("%s\n", cmd); + + ret = system(cmd); + + return -WEXITSTATUS(ret); +} + +int canbus_np_wait_data(int fd) +{ + struct timeval timeout; + fd_set rset; + int ret; + + FD_ZERO(&rset); + + FD_SET(fd, &rset); + + timeout.tv_sec = 0; + timeout.tv_usec = 0; + + ret = select(fd + 1, &rset, NULL, NULL, &timeout); + if (ret < 0 && errno != EINTR) { + return -errno; + } else if (ret > 0) { + if (FD_ISSET(fd, &rset)) { + return 0; + } + } + + return -EAGAIN; +} + +ssize_t canbus_np_read_data(int fd, void *buf, size_t buf_len) +{ + return read(fd, buf, buf_len); +} + +ssize_t canbus_np_write_data(int fd, void *buf, size_t buf_len) +{ + return write(fd, buf, buf_len); +} + +int canbus_np_setsockopt(int fd, int level, int optname, + const void *optval, socklen_t optlen) +{ + return setsockopt(fd, level, optname, optval, optlen); +} + +int canbus_np_getsockopt(int fd, int level, int optname, + void *optval, socklen_t *optlen) +{ + return getsockopt(fd, level, optname, optval, optlen); +} + +#if defined(CONFIG_NET_PROMISCUOUS_MODE) +int canbus_np_promisc_mode(const char *if_name, bool enable) +{ + return ssystem("ip link set dev %s promisc %s", + if_name, enable ? "on" : "off"); +} +#endif /* CONFIG_NET_PROMISCUOUS_MODE */ + +/* If we have enabled manual setup, then interface cannot be + * taken up or down by the driver as we normally do not have + * enough permissions. + */ + +int canbus_np_if_up(const char *if_name) +{ + return ssystem("ip link set dev %s up", if_name); +} + +int canbus_np_if_down(const char *if_name) +{ + return ssystem("ip link set dev %s down", if_name); +} diff --git a/drivers/can/canbus_native_posix_priv.h b/drivers/can/canbus_native_posix_priv.h new file mode 100644 index 0000000000000..1a42c22fb5bc1 --- /dev/null +++ b/drivers/can/canbus_native_posix_priv.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** @file + * @brief Private functions for native posix canbus driver. + */ + +#ifndef ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_ +#define ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_ + +int canbus_np_iface_open(const char *if_name); +int canbus_np_iface_close(int fd); +int canbus_np_wait_data(int fd); +ssize_t canbus_np_read_data(int fd, void *buf, size_t buf_len); +ssize_t canbus_np_write_data(int fd, void *buf, size_t buf_len); +int canbus_np_setsockopt(int fd, int level, int optname, + const void *optval, socklen_t optlen); +int canbus_np_getsockopt(int fd, int level, int optname, + void *optval, socklen_t *optlen); + +#endif /* ZEPHYR_DRIVERS_CAN_NATIVE_POSIX_PRIV_H_ */ From 2d0cb8bed7ffb58f5de00acb4cf821922cfaee1c Mon Sep 17 00:00:00 2001 From: Jukka Rissanen Date: Fri, 8 Mar 2019 16:19:42 +0200 Subject: [PATCH 2/4] samples: net: sockets: can: Add native_posix board support Add native_posix board support to socket-can sample application. Signed-off-by: Jukka Rissanen --- samples/net/sockets/can/boards/native_posix.conf | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 samples/net/sockets/can/boards/native_posix.conf diff --git a/samples/net/sockets/can/boards/native_posix.conf b/samples/net/sockets/can/boards/native_posix.conf new file mode 100644 index 0000000000000..e3f7d0a941002 --- /dev/null +++ b/samples/net/sockets/can/boards/native_posix.conf @@ -0,0 +1,2 @@ +CONFIG_CAN_NATIVE_POSIX=y +CONFIG_ETH_NATIVE_POSIX=n From cdcc8bef18a05173ccda6a47c8e72fc1dcc7826a Mon Sep 17 00:00:00 2001 From: Ruixiang Du Date: Thu, 8 Apr 2021 18:22:40 +0800 Subject: [PATCH 3/4] rebase: rebased jukkar:canbus-driver-for-native_posix to tag zephyr-v2.6.0 Update file name canbus_native_posix_xx.x to can_native_posix_xx.x to keep consistent with can driver for other platforms. Update implementation to work with the current state of zephyr and update samples/net/sockets/can/boards/native_posix.conf. Replace deprecated DEVICE_AND_API_INIT() with DEVICE_DT_INST_DEFINE() and add can_1 and can_2 in native_posix.dts. Signed-off-by: Ruixiang Du --- boards/posix/native_posix/Kconfig.defconfig | 3 + boards/posix/native_posix/native_posix.dts | 20 + drivers/can/CMakeLists.txt | 6 +- drivers/can/Kconfig.native_posix | 56 ++- drivers/can/can_native_posix.c | 369 ++++++++++++++++++ ...posix_adapt.c => can_native_posix_adapt.c} | 4 +- ...e_posix_priv.h => can_native_posix_priv.h} | 0 drivers/can/canbus_native_posix.c | 313 --------------- 8 files changed, 448 insertions(+), 323 deletions(-) create mode 100644 drivers/can/can_native_posix.c rename drivers/can/{canbus_native_posix_adapt.c => can_native_posix_adapt.c} (97%) rename drivers/can/{canbus_native_posix_priv.h => can_native_posix_priv.h} (100%) delete mode 100644 drivers/can/canbus_native_posix.c diff --git a/boards/posix/native_posix/Kconfig.defconfig b/boards/posix/native_posix/Kconfig.defconfig index a226c26d60310..160ccad25b416 100644 --- a/boards/posix/native_posix/Kconfig.defconfig +++ b/boards/posix/native_posix/Kconfig.defconfig @@ -23,6 +23,9 @@ config NET_L2_ETHERNET config ETH_NATIVE_POSIX default y if NET_L2_ETHERNET +config CAN_NATIVE_POSIX + default y if NET_SOCKETS_CAN + endif # NETWORKING config FAKE_ENTROPY_NATIVE_POSIX diff --git a/boards/posix/native_posix/native_posix.dts b/boards/posix/native_posix/native_posix.dts index 5e52d3cbca163..28995c8ffaf01 100644 --- a/boards/posix/native_posix/native_posix.dts +++ b/boards/posix/native_posix/native_posix.dts @@ -141,6 +141,26 @@ current-speed = <0>; }; + can1: can_1 { + status = "okay"; + compatible = "zephyr,native-posix-can"; + label = "CAN_1"; + /* Dummy bus-speed entry to comply with can + * DTS binding + */ + bus-speed = <500000>; + }; + + can2: can_2 { + status = "okay"; + compatible = "zephyr,native-posix-can"; + label = "CAN_2"; + /* Dummy bus-speed entry to comply with can + * DTS binding + */ + bus-speed = <500000>; + }; + rng: rng { status = "okay"; compatible = "zephyr,native-posix-rng"; diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index 28e36c324e83d..cbd130e5b1761 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -20,7 +20,7 @@ if(CONFIG_CAN_NATIVE_POSIX) zephyr_library_compile_definitions(_BSD_SOURCE) zephyr_library_compile_definitions(_DEFAULT_SOURCE) zephyr_library_sources( - canbus_native_posix.c - canbus_native_posix_adapt.c + can_native_posix.c + can_native_posix_adapt.c ) -endif() \ No newline at end of file +endif() diff --git a/drivers/can/Kconfig.native_posix b/drivers/can/Kconfig.native_posix index 1efede3a36a2c..0b227e0bbc8b7 100644 --- a/drivers/can/Kconfig.native_posix +++ b/drivers/can/Kconfig.native_posix @@ -8,10 +8,12 @@ config CAN_NATIVE_POSIX bool "native_posix CAN Driver" - depends on ARCH_POSIX + depends on ARCH_POSIX && NETWORKING help Enable native_posix CAN driver +if CAN_NATIVE_POSIX + config CAN_MAX_FILTER int "Maximum number of concurrent active filters" depends on CAN_NATIVE_POSIX @@ -21,8 +23,52 @@ config CAN_MAX_FILTER Defines the array size of the callback/msgq pointers. Must be at least the size of concurrent reads. -config CAN_NATIVE_POSIX_INTERFACE_NAME - string "CANBUS interface name in Linux side" - default "zcan" +## Interface 1 +config CAN_NATIVE_POSIX_INTERFACE_1_ENABLE + bool "CANBUS interface 1" + default y + depends on CAN_NATIVE_POSIX + help + This option enables the CANBUS network interface for Native POSIX board. + +config CAN_NATIVE_POSIX_INTERFACE_1_NAME + string "CANBUS interface 1 name on Linux side" + depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLE + default "vcan0" + help + This option sets the CANBUS network interface 1 name in host system. + +config CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME + string "Network device name" + depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLE + default "SOCKET_CAN_1" + help + Name of the network device driver for SocketCAN. + +## Interface 2 +config CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + bool "CANBUS interface 2" + default y + depends on CAN_NATIVE_POSIX help - This option sets the CANBUS network interface name in host system. + This option enables the CANBUS network interface for Native POSIX board. + +if CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + +config CAN_NATIVE_POSIX_INTERFACE_2_NAME + string "CANBUS interface 2 name on Linux side" + depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + default "vcan1" + help + This option sets the CANBUS network interface 1 name in host system. + +config CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME + string "Network device name" + depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + default "SOCKET_CAN_2" + help + Name of the network device driver for SocketCAN. + +endif # CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + +endif # CAN_NATIVE_POSIX \ No newline at end of file diff --git a/drivers/can/can_native_posix.c b/drivers/can/can_native_posix.c new file mode 100644 index 0000000000000..2b12f328d098c --- /dev/null +++ b/drivers/can/can_native_posix.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2019 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * @file + * + * CANBUS driver for native_posix board. This is meant to test CANBUS + * connectivity between host and Zephyr. + */ + +#define DT_DRV_COMPAT zephyr_native_posix_can + +#define LOG_MODULE_NAME canbus_posix +#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL + +#include +LOG_MODULE_REGISTER(LOG_MODULE_NAME); + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "can_native_posix_priv.h" + +#define NET_BUF_TIMEOUT K_MSEC(100) + +struct canbus_np_context { + const struct device *can_dev; + struct k_msgq *msgq; + struct net_if *iface; + const char *if_name; + + int dev_fd; + struct can_frame frame; +}; + +static int read_data(struct canbus_np_context *ctx, int fd) +{ + struct net_pkt *pkt; + int count; + + count = canbus_np_read_data(fd, (void *)(&ctx->frame), + sizeof(ctx->frame)); + if (count <= 0) { + return 0; + } + + struct zcan_frame zframe; + can_copy_frame_to_zframe(&ctx->frame, &zframe); + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, sizeof(zframe), AF_CAN, + 0, NET_BUF_TIMEOUT); + if (!pkt) { + return -ENOMEM; + } + + if (net_pkt_write(pkt, (void *)(&zframe), sizeof(zframe))) { + net_pkt_unref(pkt); + return -ENOBUFS; + } + + if (net_recv_data(ctx->iface, pkt) < 0) { + net_pkt_unref(pkt); + } + + return 0; +} + +static void canbus_np_rx(struct canbus_np_context *ctx) +{ + LOG_DBG("Starting ZCAN RX thread"); + + while (1) { + if (ctx->iface && net_if_is_up(ctx->iface)) { + while (!canbus_np_wait_data(ctx->dev_fd)) { + read_data(ctx, ctx->dev_fd); + } + } + + k_sleep(K_MSEC(10)); + } +} + +static int canbus_np_send(const struct device *dev, + const struct zcan_frame *msg, k_timeout_t timeout, + can_tx_callback_t callback_isr, void *callback_arg) +{ + struct canbus_np_context *ctx = dev->data; + int ret = -ENODEV; + + ARG_UNUSED(timeout); + ARG_UNUSED(callback_isr); + ARG_UNUSED(callback_arg); + + if (ctx->dev_fd > 0) { + struct can_frame frame; + + can_copy_zframe_to_frame(msg, &frame); + + ret = canbus_np_write_data(ctx->dev_fd, &frame, sizeof(frame)); + if (ret < 0) { + LOG_ERR("Cannot send CAN data len %d (%d)", + frame.can_dlc, -errno); + } + } + + return ret < 0 ? ret : 0; +} + +static int canbus_np_attach_isr(const struct device *dev, can_rx_callback_t isr, + void *callback_arg, + const struct zcan_filter *filter) +{ + ARG_UNUSED(dev); + ARG_UNUSED(isr); + ARG_UNUSED(callback_arg); + ARG_UNUSED(filter); + + return 0; +} + +static void canbus_np_detach(const struct device *dev, int filter_nr) +{ + ARG_UNUSED(dev); + ARG_UNUSED(filter_nr); +} + +enum can_state canbus_np_get_state(const struct device *dev, + struct can_bus_err_cnt *err_cnt) +{ + ARG_UNUSED(dev); + ARG_UNUSED(err_cnt); + return CAN_ERROR_ACTIVE; +} + +void canbus_np_register_state_change_isr(const struct device *dev, + can_state_change_isr_t isr) +{ + ARG_UNUSED(dev); + ARG_UNUSED(isr); +} + +static const struct can_driver_api can_api_funcs = { + .send = canbus_np_send, + .attach_isr = canbus_np_attach_isr, + .detach = canbus_np_detach, + .get_state = canbus_np_get_state, + .register_state_change_isr = canbus_np_register_state_change_isr +}; + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE +K_KERNEL_STACK_DEFINE(canbus_rx_stack1, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); +static struct k_thread rx_thread_data1; +static struct canbus_np_context canbus_context_data1; + +static int canbus_np1_init(const struct device *dev) +{ + struct canbus_np_context *ctx = dev->data; + + ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_NAME; + + ctx->dev_fd = canbus_np_iface_open(ctx->if_name); + if (ctx->dev_fd < 0) { + LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd); + } else { + /* Create a thread that will handle incoming data from host */ + k_thread_create(&rx_thread_data1, canbus_rx_stack1, + K_THREAD_STACK_SIZEOF(canbus_rx_stack1), + (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL, + K_PRIO_COOP(14), 0, K_NO_WAIT); + } + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, &canbus_np1_init, NULL, + (void *)&canbus_context_data1, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &can_api_funcs); +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE */ + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE +K_KERNEL_STACK_DEFINE(canbus_rx_stack2, + CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); +static struct k_thread rx_thread_data2; +static struct canbus_np_context canbus_context_data2; + +static int canbus_np2_init(const struct device *dev) +{ + struct canbus_np_context *ctx = dev->data; + + ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_NAME; + + ctx->dev_fd = canbus_np_iface_open(ctx->if_name); + if (ctx->dev_fd < 0) { + LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd); + } else { + /* Create a thread that will handle incoming data from host */ + k_thread_create(&rx_thread_data2, canbus_rx_stack2, + K_THREAD_STACK_SIZEOF(canbus_rx_stack2), + (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL, + K_PRIO_COOP(14), 0, K_NO_WAIT); + } + + return 0; +} + +DEVICE_DT_INST_DEFINE(1, &canbus_np2_init, NULL, + (void *)&canbus_context_data2, NULL, + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, + &can_api_funcs); +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE */ + +#if defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE) || \ + defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE) + +#if defined(CONFIG_NET_SOCKETS_CAN) + +#define SEND_TIMEOUT K_MSEC(100) +#define BUF_ALLOC_TIMEOUT K_MSEC(50) + +static void socket_can_iface_init(struct net_if *iface) +{ + const struct device *dev = net_if_get_device(iface); + struct canbus_np_context *socket_context = dev->data; + + socket_context->iface = iface; + + LOG_DBG("Init CAN interface %p dev %p", iface, dev); +} + +static void tx_irq_callback(uint32_t error_flags, void *arg) +{ + if (error_flags) { + LOG_DBG("Callback! error-code: %d", error_flags); + } +} + +/* This is called by net_if.c when packet is about to be sent */ +static int socket_can_send(const struct device *dev, struct net_pkt *pkt) +{ + struct canbus_np_context *socket_context = dev->data; + int ret; + + if (net_pkt_family(pkt) != AF_CAN) { + return -EPFNOSUPPORT; + } + + ret = can_send(socket_context->can_dev, + (struct zcan_frame *)pkt->frags->data, SEND_TIMEOUT, + tx_irq_callback, NULL); + if (ret) { + LOG_DBG("Cannot send socket CAN msg (%d)", ret); + } + + /* If something went wrong, then we need to return negative value to + * net_if.c:net_if_tx() so that the net_pkt will get released. + */ + return -ret; +} + +static int socket_can_setsockopt(const struct device *dev, void *obj, int level, + int optname, const void *optval, + socklen_t optlen) +{ + struct canbus_np_context *socket_context = dev->data; + struct can_filter filter; + + if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { + errno = EINVAL; + return -1; + } + + /* Our userspace can send either zcan_filter or can_filter struct. + * They are different sizes so we need to convert them if needed. + */ + if (optlen != sizeof(struct can_filter) && + optlen != sizeof(struct zcan_filter)) { + errno = EINVAL; + return -1; + } + + if (optlen == sizeof(struct zcan_filter)) { + can_copy_zfilter_to_filter((struct zcan_filter *)optval, + &filter); + } else { + memcpy(&filter, optval, sizeof(filter)); + } + + return canbus_np_setsockopt(socket_context->dev_fd, level, optname, + &filter, sizeof(filter)); +} + +static void socket_can_close(const struct device *dev, int filter_id) +{ + struct canbus_np_context *socket_context = dev->data; + + can_detach(socket_context->can_dev, filter_id); +} + +static struct canbus_api socket_can_api = { + .iface_api.init = socket_can_iface_init, + .send = socket_can_send, + .close = socket_can_close, + .setsockopt = socket_can_setsockopt, +}; + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE +// static struct socket_can_context socket_can_context_1; +static int socket_can_init_1(const struct device *dev) +{ + const struct device *can_dev = DEVICE_DT_INST_GET(0); + struct canbus_np_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; + + return 0; +} + +NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_1, + CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME, 0, + socket_can_init_1, NULL, + &canbus_context_data1, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, + CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE */ + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE +static int socket_can_init_2(const struct device *dev) +{ + const struct device *can_dev = DEVICE_DT_INST_GET(1); + struct canbus_np_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; + + return 0; +} + +NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_2, + CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME, 1, + socket_can_init_2, NULL, + &canbus_context_data2, NULL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, + CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE */ + +#endif /* CONFIG_NET_SOCKETS_CAN */ + +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1 */ diff --git a/drivers/can/canbus_native_posix_adapt.c b/drivers/can/can_native_posix_adapt.c similarity index 97% rename from drivers/can/canbus_native_posix_adapt.c rename to drivers/can/can_native_posix_adapt.c index 3d06b30e0ba63..b7bb51d84b85c 100644 --- a/drivers/can/canbus_native_posix_adapt.c +++ b/drivers/can/can_native_posix_adapt.c @@ -24,7 +24,7 @@ #include #include #include -#include "posix_trace.h" +#include "arch/posix/posix_trace.h" #ifdef __linux #include @@ -41,7 +41,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include -#include "canbus_native_posix_priv.h" +#include "can_native_posix_priv.h" int canbus_np_iface_open(const char *if_name) { diff --git a/drivers/can/canbus_native_posix_priv.h b/drivers/can/can_native_posix_priv.h similarity index 100% rename from drivers/can/canbus_native_posix_priv.h rename to drivers/can/can_native_posix_priv.h diff --git a/drivers/can/canbus_native_posix.c b/drivers/can/canbus_native_posix.c deleted file mode 100644 index 81bdaa9fc2658..0000000000000 --- a/drivers/can/canbus_native_posix.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2019 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -/** - * @file - * - * CANBUS driver for native_posix board. This is meant to test CANBUS - * connectivity between host and Zephyr. - */ - -#define LOG_MODULE_NAME canbus_posix -#define LOG_LEVEL CONFIG_CAN_LOG_LEVEL - -#include -LOG_MODULE_REGISTER(LOG_MODULE_NAME); - -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "canbus_native_posix_priv.h" - -#define NET_BUF_TIMEOUT K_MSEC(100) -#define DT_CAN_1_NAME "CAN_1" - -struct canbus_np_context { - u8_t recv[CAN_MTU]; - - struct device *can_dev; - struct k_msgq *msgq; - struct net_if *iface; - const char *if_name; - int dev_fd; - bool init_done; -}; - -NET_STACK_DEFINE(RX_ZCAN, canbus_rx_stack, - CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, - CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); -static struct k_thread rx_thread_data; - -/* TODO: support multiple interfaces */ -static struct canbus_np_context canbus_context_data; - -static int read_data(struct canbus_np_context *ctx, int fd) -{ - struct net_pkt *pkt; - int count; - - count = canbus_np_read_data(fd, ctx->recv, sizeof(ctx->recv)); - if (count <= 0) { - return 0; - } - - pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, count, - AF_CAN, 0, NET_BUF_TIMEOUT); - if (!pkt) { - return -ENOMEM; - } - - if (net_pkt_write_new(pkt, ctx->recv, count)) { - net_pkt_unref(pkt); - return -ENOBUFS; - } - - if (net_recv_data(ctx->iface, pkt) < 0) { - net_pkt_unref(pkt); - } - - return 0; -} - -static void canbus_np_rx(struct canbus_np_context *ctx) -{ - int ret; - - LOG_DBG("Starting ZCAN RX thread"); - - while (1) { - if (ctx->iface && net_if_is_up(ctx->iface)) { - ret = canbus_np_wait_data(ctx->dev_fd); - if (!ret) { - read_data(ctx, ctx->dev_fd); - } - } - - k_sleep(K_MSEC(50)); - } -} - -static void create_rx_handler(struct canbus_np_context *ctx) -{ - k_thread_create(&rx_thread_data, canbus_rx_stack, - K_THREAD_STACK_SIZEOF(canbus_rx_stack), - (k_thread_entry_t)canbus_np_rx, - ctx, NULL, NULL, K_PRIO_COOP(14), - 0, K_NO_WAIT); -} - -static int canbus_np_init(struct device *dev) -{ - struct canbus_np_context *ctx = dev->driver_data; - - ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_NAME; - - ctx->dev_fd = canbus_np_iface_open(ctx->if_name); - if (ctx->dev_fd < 0) { - LOG_ERR("Cannot open %s (%d)", ctx->if_name, ctx->dev_fd); - } else { - /* Create a thread that will handle incoming data from host */ - create_rx_handler(ctx); - } - - return 0; -} - -static int canbus_np_runtime_configure(struct device *dev, enum can_mode mode, - u32_t bitrate) -{ - ARG_UNUSED(dev); - ARG_UNUSED(mode); - ARG_UNUSED(bitrate); - - return 0; -} - -static int canbus_np_send(struct device *dev, const struct zcan_frame *msg, - s32_t timeout, can_tx_callback_t callback) -{ - struct canbus_np_context *ctx = dev->driver_data; - int ret = -ENODEV; - - ARG_UNUSED(timeout); - ARG_UNUSED(callback); - - if (ctx->dev_fd > 0) { - struct can_frame frame; - - can_copy_zframe_to_frame(msg, &frame); - - ret = canbus_np_write_data(ctx->dev_fd, &frame, sizeof(frame)); - if (ret < 0) { - LOG_ERR("Cannot send CAN data len %d (%d)", - frame.can_dlc, -errno); - } - } - - return ret < 0 ? ret : 0; -} - -static int canbus_np_attach_msgq(struct device *dev, struct k_msgq *msgq, - const struct zcan_filter *filter) -{ - ARG_UNUSED(dev); - ARG_UNUSED(msgq); - ARG_UNUSED(filter); - - return 0; -} - -static int canbus_np_attach_isr(struct device *dev, can_rx_callback_t isr, - const struct zcan_filter *filter) -{ - ARG_UNUSED(dev); - ARG_UNUSED(isr); - ARG_UNUSED(filter); - - return 0; -} - -static void canbus_np_detach(struct device *dev, int filter_nr) -{ - ARG_UNUSED(dev); - ARG_UNUSED(filter_nr); -} - -static const struct can_driver_api can_api_funcs = { - .configure = canbus_np_runtime_configure, - .send = canbus_np_send, - .attach_msgq = canbus_np_attach_msgq, - .attach_isr = canbus_np_attach_isr, - .detach = canbus_np_detach, -}; - -#ifdef CONFIG_CAN_1 - -DEVICE_AND_API_INIT(canbus_np_1, DT_CAN_1_NAME, - canbus_np_init, &canbus_context_data, NULL, - POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, - &can_api_funcs); - -#if defined(CONFIG_NET_SOCKETS_CAN) - -#define SOCKET_CAN_NAME_1 "SOCKET_CAN_1" -#define SEND_TIMEOUT K_MSEC(100) -#define BUF_ALLOC_TIMEOUT K_MSEC(50) - -/* TODO: make msgq size configurable */ -CAN_DEFINE_MSGQ(socket_can_msgq, 5); - -static void socket_can_iface_init(struct net_if *iface) -{ - struct device *dev = net_if_get_device(iface); - struct canbus_np_context *socket_context = dev->driver_data; - - socket_context->iface = iface; - - LOG_DBG("Init CAN interface %p dev %p", iface, dev); -} - -static void tx_irq_callback(u32_t error_flags) -{ - if (error_flags) { - LOG_DBG("Callback! error-code: %d", error_flags); - } -} - -/* This is called by net_if.c when packet is about to be sent */ -static int socket_can_send(struct device *dev, struct net_pkt *pkt) -{ - struct canbus_np_context *socket_context = dev->driver_data; - int ret; - - if (net_pkt_family(pkt) != AF_CAN) { - return -EPFNOSUPPORT; - } - - ret = can_send(socket_context->can_dev, - (struct zcan_frame *)pkt->frags->data, - SEND_TIMEOUT, tx_irq_callback); - if (ret) { - LOG_DBG("Cannot send socket CAN msg (%d)", ret); - } - - /* If something went wrong, then we need to return negative value to - * net_if.c:net_if_tx() so that the net_pkt will get released. - */ - return -ret; -} - -static int socket_can_setsockopt(struct device *dev, void *obj, - int level, int optname, - const void *optval, socklen_t optlen) -{ - struct canbus_np_context *socket_context = dev->driver_data; - struct can_filter filter; - - if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { - errno = EINVAL; - return -1; - } - - /* Our userspace can send either zcan_filter or can_filter struct. - * They are different sizes so we need to convert them if needed. - */ - if (optlen != sizeof(struct can_filter) && - optlen != sizeof(struct zcan_filter)) { - errno = EINVAL; - return -1; - } - - if (optlen == sizeof(struct zcan_filter)) { - can_copy_zfilter_to_filter((struct zcan_filter *)optval, - &filter); - } else { - memcpy(&filter, optval, sizeof(filter)); - } - - return canbus_np_setsockopt(socket_context->dev_fd, level, optname, - &filter, sizeof(filter)); -} - -static struct canbus_api socket_can_api = { - .iface_api.init = socket_can_iface_init, - .send = socket_can_send, - .setsockopt = socket_can_setsockopt, -}; - -static int socket_can_init_1(struct device *dev) -{ - struct device *can_dev = DEVICE_GET(canbus_np_1); - struct canbus_np_context *socket_context = dev->driver_data; - - LOG_DBG("Init socket CAN device %p (%s) for dev %p (%s)", - dev, dev->config->name, can_dev, can_dev->config->name); - - socket_context->can_dev = can_dev; - socket_context->msgq = &socket_can_msgq; - - return 0; -} - -NET_DEVICE_INIT(socket_can_native_posix_1, SOCKET_CAN_NAME_1, - socket_can_init_1, &canbus_context_data, NULL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, - CANBUS_L2, NET_L2_GET_CTX_TYPE(CANBUS_L2), CAN_MTU); - -#endif /* CONFIG_NET_SOCKETS_CAN */ - -#endif /* CONFIG_CAN_1 */ From b1cf9c693b7f1700b9aef53ef266f991ed4c76f8 Mon Sep 17 00:00:00 2001 From: Pin Loon Lee Date: Wed, 21 Jul 2021 14:45:51 +0800 Subject: [PATCH 4/4] drivers: can: replace canbus_np_context with socket_can_context Move struct socket_can_context to socket_can_context.h to ensure struct socket_can_context can be included without replying on socket_can_generic.h. Change rx thread of canbus to be preemptive to avoid can frame loss. Update naming of _ENABLE to _ENABLED to follow convention in Kconfig.native_posix. Signed-off-by: Pin Loon Lee --- drivers/can/Kconfig.native_posix | 35 ++++---- drivers/can/can_native_posix.c | 140 +++++++++++-------------------- drivers/can/socket_can_context.h | 32 +++++++ drivers/can/socket_can_generic.h | 12 +-- 4 files changed, 99 insertions(+), 120 deletions(-) create mode 100644 drivers/can/socket_can_context.h diff --git a/drivers/can/Kconfig.native_posix b/drivers/can/Kconfig.native_posix index 0b227e0bbc8b7..5b8ae430c19a9 100644 --- a/drivers/can/Kconfig.native_posix +++ b/drivers/can/Kconfig.native_posix @@ -1,10 +1,7 @@ -# Kconfig.native_posix - native_posix CAN configuration options +# Native posix CAN configuration options -# # Copyright (c) 2019 Intel Corporation -# # SPDX-License-Identifier: Apache-2.0 -# config CAN_NATIVE_POSIX bool "native_posix CAN Driver" @@ -24,51 +21,51 @@ config CAN_MAX_FILTER Must be at least the size of concurrent reads. ## Interface 1 -config CAN_NATIVE_POSIX_INTERFACE_1_ENABLE +config CAN_NATIVE_POSIX_INTERFACE_1_ENABLED bool "CANBUS interface 1" - default y - depends on CAN_NATIVE_POSIX + default y + depends on CAN_NATIVE_POSIX help This option enables the CANBUS network interface for Native POSIX board. config CAN_NATIVE_POSIX_INTERFACE_1_NAME string "CANBUS interface 1 name on Linux side" - depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLE + depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLED default "vcan0" help This option sets the CANBUS network interface 1 name in host system. config CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME string "Network device name" - depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLE + depends on CAN_NATIVE_POSIX_INTERFACE_1_ENABLED default "SOCKET_CAN_1" help Name of the network device driver for SocketCAN. ## Interface 2 -config CAN_NATIVE_POSIX_INTERFACE_2_ENABLE +config CAN_NATIVE_POSIX_INTERFACE_2_ENABLED bool "CANBUS interface 2" - default y - depends on CAN_NATIVE_POSIX + default n + depends on CAN_NATIVE_POSIX help This option enables the CANBUS network interface for Native POSIX board. -if CAN_NATIVE_POSIX_INTERFACE_2_ENABLE +if CAN_NATIVE_POSIX_INTERFACE_2_ENABLED config CAN_NATIVE_POSIX_INTERFACE_2_NAME string "CANBUS interface 2 name on Linux side" - depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLED default "vcan1" help - This option sets the CANBUS network interface 1 name in host system. + This option sets the CANBUS network interface 2 name in host system. config CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME string "Network device name" - depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLE + depends on CAN_NATIVE_POSIX_INTERFACE_2_ENABLED default "SOCKET_CAN_2" help Name of the network device driver for SocketCAN. - -endif # CAN_NATIVE_POSIX_INTERFACE_2_ENABLE -endif # CAN_NATIVE_POSIX \ No newline at end of file +endif #CAN_NATIVE_POSIX_INTERFACE_2_ENABLED + +endif #CAN_NATIVE_POSIX diff --git a/drivers/can/can_native_posix.c b/drivers/can/can_native_posix.c index 2b12f328d098c..398abf8580d79 100644 --- a/drivers/can/can_native_posix.c +++ b/drivers/can/can_native_posix.c @@ -35,32 +35,27 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include "can_native_posix_priv.h" +#include "socket_can_context.h" #define NET_BUF_TIMEOUT K_MSEC(100) -struct canbus_np_context { - const struct device *can_dev; - struct k_msgq *msgq; - struct net_if *iface; - const char *if_name; - - int dev_fd; - struct can_frame frame; -}; - -static int read_data(struct canbus_np_context *ctx, int fd) +static int read_data(struct socket_can_context *ctx, int fd) { struct net_pkt *pkt; int count; - count = canbus_np_read_data(fd, (void *)(&ctx->frame), - sizeof(ctx->frame)); + struct can_frame frame; + + count = canbus_np_read_data(fd, (void *)(&frame), sizeof(frame)); + if (count <= 0) { return 0; } struct zcan_frame zframe; - can_copy_frame_to_zframe(&ctx->frame, &zframe); + + can_copy_frame_to_zframe(&frame, &zframe); + pkt = net_pkt_rx_alloc_with_buffer(ctx->iface, sizeof(zframe), AF_CAN, 0, NET_BUF_TIMEOUT); if (!pkt) { @@ -79,7 +74,7 @@ static int read_data(struct canbus_np_context *ctx, int fd) return 0; } -static void canbus_np_rx(struct canbus_np_context *ctx) +static void canbus_np_rx(struct socket_can_context *ctx) { LOG_DBG("Starting ZCAN RX thread"); @@ -98,7 +93,7 @@ static int canbus_np_send(const struct device *dev, const struct zcan_frame *msg, k_timeout_t timeout, can_tx_callback_t callback_isr, void *callback_arg) { - struct canbus_np_context *ctx = dev->data; + struct socket_can_context *ctx = dev->data; int ret = -ENODEV; ARG_UNUSED(timeout); @@ -161,15 +156,15 @@ static const struct can_driver_api can_api_funcs = { .register_state_change_isr = canbus_np_register_state_change_isr }; -#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED K_KERNEL_STACK_DEFINE(canbus_rx_stack1, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); static struct k_thread rx_thread_data1; -static struct canbus_np_context canbus_context_data1; +static struct socket_can_context canbus_context_data1; static int canbus_np1_init(const struct device *dev) { - struct canbus_np_context *ctx = dev->data; + struct socket_can_context *ctx = dev->data; ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_NAME; @@ -181,7 +176,7 @@ static int canbus_np1_init(const struct device *dev) k_thread_create(&rx_thread_data1, canbus_rx_stack1, K_THREAD_STACK_SIZEOF(canbus_rx_stack1), (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL, - K_PRIO_COOP(14), 0, K_NO_WAIT); + K_PRIO_PREEMPT(14), 0, K_NO_WAIT); } return 0; @@ -191,17 +186,17 @@ DEVICE_DT_INST_DEFINE(0, &canbus_np1_init, NULL, (void *)&canbus_context_data1, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &can_api_funcs); -#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE */ +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED */ -#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED K_KERNEL_STACK_DEFINE(canbus_rx_stack2, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE); static struct k_thread rx_thread_data2; -static struct canbus_np_context canbus_context_data2; +static struct socket_can_context canbus_context_data2; static int canbus_np2_init(const struct device *dev) { - struct canbus_np_context *ctx = dev->data; + struct socket_can_context *ctx = dev->data; ctx->if_name = CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_NAME; @@ -213,7 +208,7 @@ static int canbus_np2_init(const struct device *dev) k_thread_create(&rx_thread_data2, canbus_rx_stack2, K_THREAD_STACK_SIZEOF(canbus_rx_stack2), (k_thread_entry_t)canbus_np_rx, ctx, NULL, NULL, - K_PRIO_COOP(14), 0, K_NO_WAIT); + K_PRIO_PREEMPT(14), 0, K_NO_WAIT); } return 0; @@ -223,61 +218,20 @@ DEVICE_DT_INST_DEFINE(1, &canbus_np2_init, NULL, (void *)&canbus_context_data2, NULL, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &can_api_funcs); -#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE */ +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */ -#if defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE) || \ - defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE) +#if defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED) || \ + defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED) #if defined(CONFIG_NET_SOCKETS_CAN) -#define SEND_TIMEOUT K_MSEC(100) -#define BUF_ALLOC_TIMEOUT K_MSEC(50) +#include "socket_can_generic.h" -static void socket_can_iface_init(struct net_if *iface) -{ - const struct device *dev = net_if_get_device(iface); - struct canbus_np_context *socket_context = dev->data; - - socket_context->iface = iface; - - LOG_DBG("Init CAN interface %p dev %p", iface, dev); -} - -static void tx_irq_callback(uint32_t error_flags, void *arg) -{ - if (error_flags) { - LOG_DBG("Callback! error-code: %d", error_flags); - } -} - -/* This is called by net_if.c when packet is about to be sent */ -static int socket_can_send(const struct device *dev, struct net_pkt *pkt) -{ - struct canbus_np_context *socket_context = dev->data; - int ret; - - if (net_pkt_family(pkt) != AF_CAN) { - return -EPFNOSUPPORT; - } - - ret = can_send(socket_context->can_dev, - (struct zcan_frame *)pkt->frags->data, SEND_TIMEOUT, - tx_irq_callback, NULL); - if (ret) { - LOG_DBG("Cannot send socket CAN msg (%d)", ret); - } - - /* If something went wrong, then we need to return negative value to - * net_if.c:net_if_tx() so that the net_pkt will get released. - */ - return -ret; -} - -static int socket_can_setsockopt(const struct device *dev, void *obj, int level, +static int socket_can_np_setsockopt(const struct device *dev, void *obj, int level, int optname, const void *optval, socklen_t optlen) { - struct canbus_np_context *socket_context = dev->data; + struct socket_can_context *socket_context = dev->data; struct can_filter filter; if (level != SOL_CAN_RAW && optname != CAN_RAW_FILTER) { @@ -305,26 +259,24 @@ static int socket_can_setsockopt(const struct device *dev, void *obj, int level, &filter, sizeof(filter)); } -static void socket_can_close(const struct device *dev, int filter_id) -{ - struct canbus_np_context *socket_context = dev->data; - - can_detach(socket_context->can_dev, filter_id); -} - -static struct canbus_api socket_can_api = { +static struct canbus_api socket_can_np_api = { .iface_api.init = socket_can_iface_init, .send = socket_can_send, .close = socket_can_close, - .setsockopt = socket_can_setsockopt, + .setsockopt = socket_can_np_setsockopt, }; -#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE -// static struct socket_can_context socket_can_context_1; +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED + static int socket_can_init_1(const struct device *dev) { + /* To avoid warning, use socket_can_api defined in socket_can_generic.h. + * For native posix, use socket_can_np_api instead. + */ + (void)socket_can_api; + const struct device *can_dev = DEVICE_DT_INST_GET(0); - struct canbus_np_context *socket_context = dev->data; + 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); @@ -338,15 +290,21 @@ NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_1, CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME, 0, socket_can_init_1, NULL, &canbus_context_data1, NULL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_np_api, CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); -#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLE */ +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_ENABLED */ + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED -#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE static int socket_can_init_2(const struct device *dev) { + /* To avoid warning, use socket_can_api defined in socket_can_generic.h. + * For native posix, use socket_can_np_api instead. + */ + (void)socket_can_api; + const struct device *can_dev = DEVICE_DT_INST_GET(1); - struct canbus_np_context *socket_context = dev->data; + 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); @@ -360,10 +318,10 @@ NET_DEVICE_INIT_INSTANCE(socket_can_native_posix_2, CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_SOCKETCAN_NAME, 1, socket_can_init_2, NULL, &canbus_context_data2, NULL, - CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_api, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &socket_can_np_api, CANBUS_RAW_L2, NET_L2_GET_CTX_TYPE(CANBUS_RAW_L2), CAN_MTU); -#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLE */ +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */ #endif /* CONFIG_NET_SOCKETS_CAN */ -#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1 */ +#endif /* CAN_NATIVE_POSIX_INTERFACE_1_ENABLED || CAN_NATIVE_POSIX_INTERFACE_2_ENABLED */ diff --git a/drivers/can/socket_can_context.h b/drivers/can/socket_can_context.h new file mode 100644 index 0000000000000..7388e3fc81fdc --- /dev/null +++ b/drivers/can/socket_can_context.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + * + */ + +/* CANBUS related functions that are generic in all the drivers. */ + +#include +#include + +#ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_ +#define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_ + +struct socket_can_context { + const struct device *can_dev; + struct net_if *iface; + + /* for can on native posix */ + const char *if_name; + int dev_fd; + + /* for can on embedded board */ + struct k_msgq *msgq; + + /* TODO: remove the thread and push data to net directly from rx isr */ + k_tid_t rx_tid; + struct k_thread rx_thread_data; +}; + +#endif /* ZEPHYR_DRIVERS_CAN_SOCKET_CAN_CONTEXT_H_ */ diff --git a/drivers/can/socket_can_generic.h b/drivers/can/socket_can_generic.h index d6afbc0d4c97a..dce1b5199e999 100644 --- a/drivers/can/socket_can_generic.h +++ b/drivers/can/socket_can_generic.h @@ -13,6 +13,8 @@ #ifndef ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ #define ZEPHYR_DRIVERS_CAN_SOCKET_CAN_GENERIC_H_ +#include "socket_can_context.h" + #define SOCKET_CAN_NAME_0 "SOCKET_CAN_0" #define SOCKET_CAN_NAME_1 "SOCKET_CAN_1" #define SOCKET_CAN_NAME_2 "SOCKET_CAN_2" @@ -25,16 +27,6 @@ CAN_DEFINE_MSGQ(socket_can_msgq, 5); K_KERNEL_STACK_DEFINE(rx_thread_stack, RX_THREAD_STACK_SIZE); -struct socket_can_context { - const struct device *can_dev; - struct net_if *iface; - struct k_msgq *msgq; - - /* TODO: remove the thread and push data to net directly from rx isr */ - k_tid_t rx_tid; - struct k_thread rx_thread_data; -}; - static inline void socket_can_iface_init(struct net_if *iface) { const struct device *dev = net_if_get_device(iface);