diff --git a/drivers/can/CMakeLists.txt b/drivers/can/CMakeLists.txt index 7784e2e278448..dba961ace68ed 100644 --- a/drivers/can/CMakeLists.txt +++ b/drivers/can/CMakeLists.txt @@ -9,3 +9,14 @@ zephyr_sources_ifdef(CONFIG_CAN_MCUX_FLEXCAN can_mcux_flexcan.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(_DEFAULT_SOURCE) + zephyr_library_sources( + can_native_posix.c + can_native_posix_adapt.c + ) +endif() diff --git a/drivers/can/Kconfig b/drivers/can/Kconfig index 69d40532f97c4..ab02d9215bbbf 100644 --- a/drivers/can/Kconfig +++ b/drivers/can/Kconfig @@ -62,5 +62,6 @@ source "drivers/can/Kconfig.mcux" source "drivers/can/Kconfig.mcp2515" 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..fbc46fc56814e --- /dev/null +++ b/drivers/can/Kconfig.native_posix @@ -0,0 +1,64 @@ +# 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 && NETWORKING + 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. + +## Interface 1 +config CAN_NATIVE_POSIX_INTERFACE_1 + bool "CANBUS interface 1" + 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 + 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 + default "SOCKET_CAN_1" + help + Name of the network device driver for SocketCAN. + +## Interface 2 +config CAN_NATIVE_POSIX_INTERFACE_2 + bool "CANBUS interface 2" + depends on CAN_NATIVE_POSIX + help + This option enables the CANBUS network interface for Native POSIX board. + +config CAN_NATIVE_POSIX_INTERFACE_2_NAME + string "CANBUS interface 2 name on Linux side" + depends on CAN_NATIVE_POSIX_INTERFACE_2 + 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 + default "SOCKET_CAN_2" + help + Name of the network device driver for SocketCAN. diff --git a/drivers/can/can_native_posix.c b/drivers/can/can_native_posix.c new file mode 100644 index 0000000000000..a78fb8ea8a93e --- /dev/null +++ b/drivers/can/can_native_posix.c @@ -0,0 +1,381 @@ +/* + * 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 + +#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) +{ + 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 int canbus_np_runtime_configure(const struct device *dev, + enum can_mode mode, uint32_t bitrate) +{ + ARG_UNUSED(dev); + ARG_UNUSED(mode); + ARG_UNUSED(bitrate); + + return 0; +} + +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 = { + .configure = canbus_np_runtime_configure, + .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 +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_AND_API_INIT(canbus_np_1, CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_NAME, + canbus_np1_init, &canbus_context_data1, NULL, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &can_api_funcs); +#endif + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2 +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_AND_API_INIT(canbus_np_2, CONFIG_CAN_NATIVE_POSIX_INTERFACE_2_NAME, + canbus_np2_init, &canbus_context_data2, NULL, POST_KERNEL, + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &can_api_funcs); +#endif + +#if defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_1) || \ + defined(CONFIG_CAN_NATIVE_POSIX_INTERFACE_2) + +#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 +// 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_GET(canbus_np_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_1, + CONFIG_CAN_NATIVE_POSIX_INTERFACE_1_SOCKETCAN_NAME, 1, + socket_can_init_1, device_pm_control_nop, + &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 */ + +#ifdef CONFIG_CAN_NATIVE_POSIX_INTERFACE_2 +static int socket_can_init_2(const struct device *dev) +{ + const struct device *can_dev = DEVICE_GET(canbus_np_2); + 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, 2, + socket_can_init_2, device_pm_control_nop, + &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 */ + +#endif /* CONFIG_NET_SOCKETS_CAN */ + +#endif /* CONFIG_CAN_NATIVE_POSIX_INTERFACE_1 */ diff --git a/drivers/can/can_native_posix_adapt.c b/drivers/can/can_native_posix_adapt.c new file mode 100644 index 0000000000000..b7bb51d84b85c --- /dev/null +++ b/drivers/can/can_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 "arch/posix/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 "can_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/can_native_posix_priv.h b/drivers/can/can_native_posix_priv.h new file mode 100644 index 0000000000000..1a42c22fb5bc1 --- /dev/null +++ b/drivers/can/can_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_ */ 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 diff --git a/samples/net/sockets/can_native_posix/CMakeLists.txt b/samples/net/sockets/can_native_posix/CMakeLists.txt new file mode 100644 index 0000000000000..7533db0ce0048 --- /dev/null +++ b/samples/net/sockets/can_native_posix/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(can_native_posix) + +target_sources(app PRIVATE src/main.c) + +include(${ZEPHYR_BASE}/samples/net/common/common.cmake) diff --git a/samples/net/sockets/can_native_posix/README.rst b/samples/net/sockets/can_native_posix/README.rst new file mode 100644 index 0000000000000..9aac14ddaa6ad --- /dev/null +++ b/samples/net/sockets/can_native_posix/README.rst @@ -0,0 +1,146 @@ +.. _eth-native-posix-sample: + +Native Posix Ethernet +##################### + +Overview +******** + +The eth_native_posix sample application for Zephyr creates a **zeth** network +interface to the host system. One can communicate with Zephyr via this network +interface. + +The source code for this sample application can be found at: +:zephyr_file:`samples/net/eth_native_posix`. + +Building And Running +******************** + +To build the eth_native_posix sample application, follow the steps +below. + +.. zephyr-app-commands:: + :zephyr-app: samples/net/eth_native_posix + :host-os: unix + :board: native_posix + :conf: + :goals: build + :compact: + +Normally one needs extra privileges to create and configure the TAP device in +the host system. If the user has set the +:option:`CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC` option (this is disabled +by default), then the user needs to use ``sudo`` to execute the Zephyr process +with admin privileges, like this: + +.. code-block:: console + + sudo --preserve-env=ZEPHYR_BASE make -Cbuild run + +If the ``sudo --preserve-env=ZEPHYR_BASE`` gives an error, +just use ``sudo --preserve-env`` instead. + +If the :option:`CONFIG_ETH_NATIVE_POSIX_STARTUP_AUTOMATIC` option +is not enabled (this is the default), then the user should +execute the ``net-setup.sh`` script from Zephyr `net-tools`_ repository. +The script should be run before executing the Zephyr process. The script +will create the zeth interface and set up IP addresses and routes. +While running ``net-setup.sh`` requires root access, afterwards Zephyr +process can be run as a non-root user. + +You can run the ``net-setup.sh`` script like this:: + + cd net-tools + sudo ./net-setup.sh + +or:: + + sudo ./net-setup.sh --config ./zeth-vlan.conf + +See also other command line options by typing ``net-setup.sh --help``. + +When the network interface is set up manually, you can leave the wireshark +to monitor the interface, and then start and stop the zephyr process without +stopping the wireshark. + +Setting things manually works the same as working with SLIP connectivity +in QEMU. + +If you want to connect two Zephyr instances together, you can do it like this: + +Create two Zephyr config files prj1.conf and prj2.conf. You can use +:zephyr_file:`samples/net/eth_native_posix/prj.conf` as a base. + +Set prj1.conf IP address configuration like this: + +.. code-block:: console + + CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8:100::1" + CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8:100::2" + CONFIG_NET_CONFIG_MY_IPV4_ADDR="198.51.100.1" + CONFIG_NET_CONFIG_PEER_IPV4_ADDR="198.51.100.2" + CONFIG_NET_CONFIG_MY_IPV4_GW="203.0.113.1" + CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=n + CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:64" + CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT="echo" + CONFIG_ETH_NATIVE_POSIX_DRV_NAME="zeth.1" + +Set prj2.conf IP address configuration like this: + +.. code-block:: console + + CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8:200::1" + CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8:200::2" + CONFIG_NET_CONFIG_MY_IPV4_ADDR="203.0.113.1" + CONFIG_NET_CONFIG_PEER_IPV4_ADDR="203.0.113.2" + CONFIG_NET_CONFIG_MY_IPV4_GW="198.51.100.1" + CONFIG_ETH_NATIVE_POSIX_RANDOM_MAC=n + CONFIG_ETH_NATIVE_POSIX_MAC_ADDR="00:00:5e:00:53:c8" + CONFIG_ETH_NATIVE_POSIX_SETUP_SCRIPT="echo" + CONFIG_ETH_NATIVE_POSIX_DRV_NAME="zeth.2" + +Then compile and run two Zephyr instances +(if ``sudo --preserve-env=ZEPHYR_BASE`` gives an error, +just use ``sudo --preserve-env`` instead): + +.. code-block:: console + + cmake -DCONF_FILE=prj1.conf -DBOARD=native_posix -Bbuild1/native_posix . + make -s -C build1/native_posix + sudo --preserve-env=ZEPHYR_BASE make -s -C build1/native_posix run + +.. code-block:: console + + cmake -DCONF_FILE=prj2.conf -DBOARD=native_posix -Bbuild2/native_posix . + make -s -C build2/native_posix + sudo --preserve-env=ZEPHYR_BASE make -s -C build2/native_posix run + +Bridge the two Zephyr instances together: + +.. code-block:: console + + sudo brctl addbr zeth-br + sudo brctl addif zeth-br zeth.1 + sudo brctl addif zeth-br zeth.2 + sudo ifconfig zeth-br up + +After this, you are able to ping device 1 from device 2 in net-shell: + +.. code-block:: console + + # In device 1 + net ping 2001:db8:200::1 + net ping 203.0.113.1 + +.. code-block:: console + + # In device 2 + net ping 2001:db8:100::1 + net ping 198.51.100.1 + +Note that in this setup you cannot access these two Zephyr devices from +your host. If you want to do that, then you could create a new network +interface with proper IP addresses and add that interface to the Zephyr +bridge. + +.. _`net-tools`: https://github.com/zephyrproject-rtos/net-tools diff --git a/samples/net/sockets/can_native_posix/boards/native_posix.conf b/samples/net/sockets/can_native_posix/boards/native_posix.conf new file mode 100644 index 0000000000000..ee227d9b112e9 --- /dev/null +++ b/samples/net/sockets/can_native_posix/boards/native_posix.conf @@ -0,0 +1,54 @@ +CONFIG_SOC_POSIX=y +CONFIG_BOARD_NATIVE_POSIX_32BIT=y + +# # CONFIG_UART_NATIVE_POSIX=y +# # CONFIG_NATIVE_UART_0_ON_OWN_PTY=y +# # CONFIG_NATIVE_UART_0_ON_STDINOUT=n +# # CONFIG_UART_NATIVE_POSIX_PORT_1_ENABLE=n +CONFIG_LOG_BACKEND_NATIVE_POSIX=y + +CONFIG_NETWORKING=y +CONFIG_CAN_NATIVE_POSIX=y +CONFIG_ETH_NATIVE_POSIX=n +CONFIG_CAN_NATIVE_POSIX_INTERFACE_1=y +CONFIG_CAN_NATIVE_POSIX_INTERFACE_2=y + +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_CAN=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y + +# CONFIG_CAN_NET=y +# CONFIG_NET_L2_CANBUS=y +CONFIG_NET_L2_CANBUS_RAW=y + +CONFIG_NET_SOCKETS_CAN_RECEIVERS=4 + +# CONFIG_NET_IPV6=n +# CONFIG_NET_IPV4=n +# CONFIG_NET_MGMT=n +# CONFIG_NET_TCP=n +# CONFIG_NET_UDP=n + +# CONFIG_NET_DEFAULT_IF_CANBUS_RAW=y + +# CONFIG_NET_PKT_RX_COUNT=30 +# CONFIG_NET_PKT_TX_COUNT=30 +# CONFIG_NET_BUF_RX_COUNT=30 +# CONFIG_NET_BUF_TX_COUNT=30 + +# CONFIG_TEST_RANDOM_GENERATOR=y + +# CONFIG_NET_SHELL=y +# CONFIG_LOG=y +# CONFIG_NET_LOG=y +# CONFIG_LOG_IMMEDIATE=y + +# CONFIG_NET_SOCKETS_LOG_LEVEL_DBG=y +# CONFIG_CAN_LOG_LEVEL_DBG=y +# #CONFIG_NET_CONTEXT_LOG_LEVEL_DBG=y +# #CONFIG_NET_CORE_LOG_LEVEL_DBG=y +# #CONFIG_NET_CONN_LOG_LEVEL_DBG=y + +# # Use smaller buffers for net_buf as CANBUS packets are quite small. +# CONFIG_NET_BUF_DATA_SIZE=64 +# CONFIG_NET_BUF_USER_DATA_SIZE=0 diff --git a/samples/net/sockets/can_native_posix/prj.conf b/samples/net/sockets/can_native_posix/prj.conf new file mode 100644 index 0000000000000..ae9216a853a6d --- /dev/null +++ b/samples/net/sockets/can_native_posix/prj.conf @@ -0,0 +1,2 @@ +CONFIG_CAN=y +CONFIG_CAN_MAX_FILTER=5 diff --git a/samples/net/sockets/can_native_posix/sample.yaml b/samples/net/sockets/can_native_posix/sample.yaml new file mode 100644 index 0000000000000..1714e5e2eb0b4 --- /dev/null +++ b/samples/net/sockets/can_native_posix/sample.yaml @@ -0,0 +1,9 @@ +common: + harness: net + tags: net +sample: + description: Can be used to test native posix connectivity via ethernet. + name: Native posix ethernet demo application +tests: + sample.net.eth_native_posix: + platform_allow: native_posix native_posix_64 diff --git a/samples/net/sockets/can_native_posix/src/main.c b/samples/net/sockets/can_native_posix/src/main.c new file mode 100644 index 0000000000000..32b8733dc87e1 --- /dev/null +++ b/samples/net/sockets/can_native_posix/src/main.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2018 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +LOG_MODULE_REGISTER(net_socket_can_sample, LOG_LEVEL_DBG); + +#include + +#include +#include + +#define PRIORITY k_thread_priority_get(k_current_get()) +#define STACKSIZE 1024 +#define SLEEP_PERIOD K_SECONDS(1) + +#define CLOSE_PERIOD 15 + +static const struct zcan_filter zfilter = { + .id_type = CAN_STANDARD_IDENTIFIER, + .rtr = CAN_DATAFRAME, + .std_id = 0x1, + .rtr_mask = 1, + .std_id_mask = 0x000, //CAN_STD_ID_MASK +}; + +static struct can_filter filter; + +struct net_if *net_if_get_second_by_type(const struct net_l2 *l2) +{ + int count = 0; + Z_STRUCT_SECTION_FOREACH(net_if, iface) + { + if (IS_ENABLED(CONFIG_NET_OFFLOAD) && !l2 && + net_if_offload(iface)) { + return iface; + } + if (net_if_l2(iface) == l2) { + if (count++ == 1) + return iface; + } + } + + return NULL; +} + +static int create_socket(int i) +{ + struct sockaddr_can can_addr; + int fd, ret; + + fd = socket(AF_CAN, SOCK_RAW, CAN_RAW); + if (fd < 0) { + printk("ERROR: Cannot create CAN socket (%d)\n", fd); + return fd; + } + + struct net_if *iface; + if (i == 0) { + iface = net_if_get_first_by_type(&NET_L2_GET_NAME(CANBUS_RAW)); + } else { + iface = net_if_get_second_by_type(&NET_L2_GET_NAME(CANBUS_RAW)); + } + if (!iface) { + printk("ERROR: No CANBUS network interface found!\n"); + return -ENOENT; + } + + can_addr.can_ifindex = net_if_get_by_iface(iface); + can_addr.can_family = PF_CAN; + + ret = bind(fd, (struct sockaddr *)&can_addr, sizeof(can_addr)); + if (ret < 0) { + printk("ERROR: Cannot bind %s CAN socket (%d)\n", "2nd", + -errno); + (void)close(fd); + return ret; + } + + printk("INFO: CAN socket created (fd: %d)\n", fd); + + return fd; +} + +static void tx_task(int *can_fd) +{ + int fd = POINTER_TO_INT(can_fd); + struct zcan_frame msg = { 0 }; + struct can_frame frame = { 0 }; + int ret, i; + + msg.dlc = 8U; + msg.id_type = CAN_STANDARD_IDENTIFIER; + msg.std_id = 0x1; + msg.rtr = CAN_DATAFRAME; + + for (i = 0; i < msg.dlc; i++) { + msg.data[i] = 0xF0 | i; + } + + can_copy_zframe_to_frame(&msg, &frame); + + printk("INFO: TX task running ... [%d]\n", fd); + + while (1) { + ret = send(fd, &frame, sizeof(frame), 0); + if (ret < 0) { + printk("ERROR: Cannot send CAN message (%d)\n", -errno); + } + + k_sleep(SLEEP_PERIOD); + } +} + +static void rx_task(int *can_fd, int *do_close_period, + const struct can_filter *filter) +{ + int close_period = POINTER_TO_INT(do_close_period); + int fd = POINTER_TO_INT(can_fd); + struct sockaddr_can can_addr; + socklen_t addr_len; + struct zcan_frame msg; + struct can_frame frame; + volatile int ret; + + printk("INFO: RX task running ... [%d]\n", fd); + + while (1) { + uint8_t *data; + + memset(&frame, 0, sizeof(frame)); + addr_len = sizeof(can_addr); + + ret = recvfrom(fd, &frame, sizeof(struct can_frame), 0, + (struct sockaddr *)&can_addr, &addr_len); + if (ret < 0) { + printk("ERROR: [%d] Cannot receive CAN message (%d)\n", + fd, -errno); + continue; + } + + can_copy_frame_to_zframe(&frame, &msg); + + printk("INFO: [%d] CAN msg: type 0x%x RTR 0x%x EID 0x%x DLC 0x%x\n", + fd, msg.id_type, msg.rtr, msg.std_id, msg.dlc); + printk("INFO: [%d] CAN data: ", fd); + for (int i = 0; i < msg.dlc; ++i) + printk("%x ", msg.data[i]); + printk("\n"); + + if (!msg.rtr) { + if (msg.dlc > 8) { + data = (uint8_t *)msg.data_32; + } else { + data = msg.data; + } + + LOG_HEXDUMP_INF(data, msg.dlc, "Data"); + } else { + printk("INFO: [%d] EXT Remote message received\n", fd); + } + + // if (POINTER_TO_INT(do_close_period) > 0) { + // close_period--; + // if (close_period <= 0) { + // (void)close(fd); + + // k_sleep(K_SECONDS(1)); + + // fd = create_socket(filter); + // if (fd < 0) { + // printk("ERROR: Cannot get socket (%d)\n", + // -errno); + // return; + // } + + // close_period = POINTER_TO_INT(do_close_period); + // } + // } + } +} + +static k_tid_t tx_tid1; +static K_THREAD_STACK_DEFINE(tx_stack1, STACKSIZE); +static struct k_thread tx_data1; + +static k_tid_t tx_tid2; +static K_THREAD_STACK_DEFINE(tx_stack2, STACKSIZE); +static struct k_thread tx_data2; + +int setup_tx_task1() +{ + int ret = -1; + + int fd = create_socket(0); + if (fd < 0) { + printk("Failed to create socket for tx task (%d)\n", fd); + return -1; + } + + tx_tid1 = k_thread_create(&tx_data1, tx_stack1, + K_THREAD_STACK_SIZEOF(tx_stack1), + (k_thread_entry_t)tx_task, INT_TO_POINTER(fd), + NULL, NULL, PRIORITY, 0, K_NO_WAIT); + if (!tx_tid1) { + ret = -ENOENT; + errno = -ret; + printk("Cannot create TX thread!\n"); + (void)close(fd); + } + + printk("Started socket CAN TX thread\n"); + + return 0; +} + +int setup_tx_task2() +{ + int ret = -1; + + int fd = create_socket(1); + if (fd < 0) { + printk("Failed to create socket for tx task (%d)\n", fd); + return -1; + } + + tx_tid2 = k_thread_create(&tx_data2, tx_stack2, + K_THREAD_STACK_SIZEOF(tx_stack2), + (k_thread_entry_t)tx_task, INT_TO_POINTER(fd), + NULL, NULL, PRIORITY, 0, K_NO_WAIT); + if (!tx_tid2) { + ret = -ENOENT; + errno = -ret; + printk("Cannot create TX thread!\n"); + (void)close(fd); + } + + printk("Started socket CAN TX thread\n"); + + return 0; +} + +static k_tid_t rx_tid1; +static K_THREAD_STACK_DEFINE(rx_stack1, STACKSIZE); +static struct k_thread rx_data1; + +static k_tid_t rx_tid2; +static K_THREAD_STACK_DEFINE(rx_stack2, STACKSIZE); +static struct k_thread rx_data2; + +int setup_rx_task1() +{ + int ret = -1; + + int fd = create_socket(0); + if (fd < 0) { + printk("Failed to create socket for rx task (%d)\n", fd); + return -1; + } + + // set filter + can_copy_zfilter_to_filter(&zfilter, &filter); + ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, + sizeof(filter)); + if (ret < 0) { + ret = -errno; + printk("ERROR: Cannot set CAN sockopt (%d)\n", ret); + close(fd); + return ret; + } + + rx_tid1 = k_thread_create(&rx_data1, rx_stack1, + K_THREAD_STACK_SIZEOF(rx_stack1), + (k_thread_entry_t)rx_task, INT_TO_POINTER(fd), + INT_TO_POINTER(CLOSE_PERIOD), &filter, + PRIORITY, 0, K_NO_WAIT); + if (!rx_tid1) { + ret = -ENOENT; + errno = -ret; + printk("Cannot create RX thread!\n"); + (void)close(fd); + } + + printk("Started socket CAN RX thread\n"); + + return 0; +} + +int setup_rx_task2() +{ + int ret = -1; + + int fd = create_socket(1); + if (fd < 0) { + printk("Failed to create socket for rx task (%d)\n", fd); + return -1; + } + + // set filter + can_copy_zfilter_to_filter(&zfilter, &filter); + ret = setsockopt(fd, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, + sizeof(filter)); + if (ret < 0) { + ret = -errno; + printk("ERROR: Cannot set CAN sockopt (%d)\n", ret); + close(fd); + return ret; + } + + rx_tid2 = k_thread_create(&rx_data2, rx_stack2, + K_THREAD_STACK_SIZEOF(rx_stack2), + (k_thread_entry_t)rx_task, INT_TO_POINTER(fd), + INT_TO_POINTER(CLOSE_PERIOD), &filter, + PRIORITY, 0, K_NO_WAIT); + if (!rx_tid2) { + ret = -ENOENT; + errno = -ret; + printk("Cannot create RX thread!\n"); + (void)close(fd); + } + + printk("Started socket CAN RX thread\n"); + + return 0; +} + +void main(void) +{ + printk("Running app with board: %s\n", CONFIG_BOARD); + + /* Let the device start before doing anything */ + k_sleep(K_SECONDS(2)); + + /* Create TX and RX tasks */ + (void)setup_tx_task1(); + (void)setup_tx_task2(); + (void)setup_rx_task1(); + (void)setup_rx_task2(); +}