diff --git a/CODEOWNERS b/CODEOWNERS index 7f5a8a4ed0..fab228eab3 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -118,6 +118,7 @@ /sys/xtimer/ @kaspar030 @MichelRottleuthner /tests/ @smlng @leandrolanzieri @aabadie @MichelRottleuthner @fjmolinas +/tests/candev/ @wosym /tests/emb6* @miri64 /tests/gnrc* @miri64 /tests/lwip* @miri64 diff --git a/tests/candev/Makefile b/tests/candev/Makefile new file mode 100644 index 0000000000..f7b1d3adae --- /dev/null +++ b/tests/candev/Makefile @@ -0,0 +1,20 @@ +include ../Makefile.tests_common + +USEMODULE += shell +USEMODULE += can +USEMODULE += isrpipe + +# define the CAN driver you want to use here +CAN_DRIVER ?= native + +ifeq ($(CAN_DRIVER), PERIPH_CAN) +# periph_can modules/variables go here + +else ifeq ($(CAN_DRIVER), CAN_NATIVE) +# can_native modules/variables go here + +endif + +CFLAGS += -DCAN_DRIVER_$(CAN_DRIVER) + +include $(RIOTBASE)/Makefile.include diff --git a/tests/candev/Makefile.ci b/tests/candev/Makefile.ci new file mode 100644 index 0000000000..b32e5717ca --- /dev/null +++ b/tests/candev/Makefile.ci @@ -0,0 +1 @@ +FEATURES_BLACKLIST += arch_msp430 diff --git a/tests/candev/README.md b/tests/candev/README.md new file mode 100644 index 0000000000..b7de114bfa --- /dev/null +++ b/tests/candev/README.md @@ -0,0 +1,109 @@ +# Candev abstraction test + +## About + +This application is a test for using the candev abstraction directly. +Use this if you want to use a single CAN driver and thus don't need the CAN-DLL layer. + +Native prerequisites +============ +For using the can stack on top of socketCAN, available for linux, you need: +- socketCAN (part of kernel starting from 2.6.25) +- install the 32bit version of libsocketcan: + +if you're on a 64bit system: +``` +sudo dpkg --add-architecture i386 +sudo apt-get update +sudo apt-get install libsocketcan-dev:i386 +``` +On 32 bit you can just do the following: +``` +sudo apt-get install libsocketcan-dev +``` + +Alternatively, you can compile from source: + +``` +wget http://www.pengutronix.de/software/libsocketcan/download/libsocketcan-0.0.10.tar.bz2 +$ sudo tar xvjf libsocketcan-0.0.10.tar.bz2 + +$ sudo rm -rf libsocketcan-0.0.10.tar.bz2 + +$ sudo cd libsocketcan-0.0.10 + +$ sudo ./configure + +compile in 32bits + +./configure --build=i686-pc-linux-gnu "CFLAGS=-m32" "CXXFLAG + +$ sudo make + +$ sudo make install + +sudo ldconfig /usr/local/lib +``` + +The default native configuration defines two virtual can ifaces to be used. +Before running this test on native, you should create those: + +``` +sudo modprobe vcan +sudo ip link add dev vcan0 type vcan +sudo ip link add dev vcan1 type vcan +sudo ip link set vcan0 up +sudo ip link set vcan1 up +``` + +## Usage + +### Sending + +Messages can be sent over the CAN-bus through the `send` command. Optionally, up to 8 bytes can be passed as arguments (in decimal form). If no arguments are passed it will default to sending AB CD EF (hex). + +``` +send +``` + +When running the app native on linux, the sent bytes can be seen by scanning the CANbus with candump: + +``` +$ candump vcan0 +``` + +### Receiving + +The test-app is always listening for incoming CAN messages. They will be stored asynchronously in a buffer and can be requested by means of the `receive` command. Optionally, an argument n can be passed to receive n messages in a row. + +``` +receive +``` + +If more messages are requested than are available in the buffer, the receive function will block until new data is available. + +When running the app native on linux, data can be sent with `cansend`: + +``` +$ cansend : +``` + +e.g.: + +``` +$ cansend vcan0 001:1234ABCD +``` + +An alternative is to use `cangen` to generate a number of random can messages: + +``` +$ cangen -v -n +``` + +e.g.: + +``` +$ cangen vcan0 -v -n 5 +``` + +will send 5 can messages to vcan0 with verbose output. diff --git a/tests/candev/main.c b/tests/candev/main.c new file mode 100644 index 0000000000..b2a9421ea8 --- /dev/null +++ b/tests/candev/main.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2020 Nalys + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test application for the candev abstraction + * + * @author Toon Stegen + * @author Wouter Symons + * + * @} + */ + +#define ENABLE_DEBUG (0) + +#include +#include +#include +#include +#include +#include +#include "shell.h" +#include "can/device.h" + +#ifdef BOARD_NATIVE + +#include + +static candev_linux_t linux_dev; + +#else +/* add other candev drivers here */ +#endif + +#define RX_RINGBUFFER_SIZE 128 /* Needs to be a power of 2! */ +static isrpipe_t rxbuf; +static uint8_t rx_ringbuf[RX_RINGBUFFER_SIZE]; + +static candev_t *candev = NULL; + +static int _send(int argc, char **argv) +{ + int ret = 0; + + struct can_frame frame = { + .can_id = 1, + .can_dlc = 3, + .data[0] = 0xAB, + .data[1] = 0xCD, + .data[2] = 0xEF, + }; + + if (argc > 1) { + if (argc > 1 + CAN_MAX_DLEN) { + printf("Could not send. Maximum CAN-bytes: %d\n", CAN_MAX_DLEN); + return -1; + } + for (int i = 1; i < argc; i++) { + frame.data[i - 1] = atoi(argv[i]); + } + frame.can_dlc = argc - 1; + } + + ret = candev->driver->send(candev, &frame); + if (ret < 0) { + puts("Failed to send CAN-message!"); + } + else { + DEBUG("sent using mailbox: %d\n", ret); + } + + return 0; +} + +static int _receive(int argc, char **argv) +{ + uint8_t buf[CAN_MAX_DLEN]; + int n = 1; + + if (argc > 1) { + n = strtol(argv[1], NULL, 10); + if (n < 1) { + puts("Usage: receive "); + return -1; + } + } + + for (int i = 0; i < n; i++) { + uint32_t can_id = 0; + uint8_t can_dlc = 0; + + puts("Reading from Rxbuf..."); + isrpipe_read(&rxbuf, buf, 4); /* can-id */ + can_id = ((uint32_t)buf[0] << 24) | + ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | + ((uint32_t)buf[3]); + isrpipe_read(&rxbuf, buf, 1); /* can-dlc */ + can_dlc = buf[0]; + isrpipe_read(&rxbuf, buf, can_dlc); /* data */ + + printf("id: %" PRIx32 " dlc: %" PRIx8 " Data: \n", can_id, can_dlc); + for (int i = 0; i < can_dlc; i++) { + printf("0x%X ", buf[i]); + } + puts(""); + } + + return 0; +} + +static const shell_command_t shell_commands[] = { + { "send", "send some data", _send }, + { "receive", "receive some data", _receive }, + { NULL, NULL, NULL } +}; + +static void _can_event_callback(candev_t *dev, candev_event_t event, void *arg) +{ + (void)arg; + struct can_frame *frame; + + switch (event) { + case CANDEV_EVENT_ISR: + DEBUG("_can_event: CANDEV_EVENT_ISR\n"); + dev->driver->isr(candev); + break; + case CANDEV_EVENT_WAKE_UP: + DEBUG("_can_event: CANDEV_EVENT_WAKE_UP\n"); + break; + case CANDEV_EVENT_TX_CONFIRMATION: + DEBUG("_can_event: CANDEV_EVENT_TX_CONFIRMATION\n"); + break; + case CANDEV_EVENT_TX_ERROR: + DEBUG("_can_event: CANDEV_EVENT_TX_ERROR\n"); + break; + case CANDEV_EVENT_RX_INDICATION: + DEBUG("_can_event: CANDEV_EVENT_RX_INDICATION\n"); + + frame = (struct can_frame *)arg; + + DEBUG("\tid: %" PRIx32 " dlc: %" PRIx8 " Data: \n\t", frame->can_id, + frame->can_dlc); + for (uint8_t i = 0; i < frame->can_dlc; i++) { + DEBUG("0x%X ", frame->data[i]); + } + DEBUG(" "); + + /* Store in buffer until user requests the data */ + isrpipe_write_one(&rxbuf, + (uint8_t)((frame->can_id & 0x1FFFFFFF) >> 24)); + isrpipe_write_one(&rxbuf, + (uint8_t)((frame->can_id & 0xFF0000) >> 16)); + isrpipe_write_one(&rxbuf, (uint8_t)((frame->can_id & 0xFF00) >> 8)); + isrpipe_write_one(&rxbuf, (uint8_t)((frame->can_id & 0xFF))); + + isrpipe_write_one(&rxbuf, frame->can_dlc); + for (uint8_t i = 0; i < frame->can_dlc; i++) { + isrpipe_write_one(&rxbuf, frame->data[i]); + } + + break; + case CANDEV_EVENT_RX_ERROR: + DEBUG("_can_event: CANDEV_EVENT_RX_ERROR\n"); + break; + case CANDEV_EVENT_BUS_OFF: + dev->state = CAN_STATE_BUS_OFF; + break; + case CANDEV_EVENT_ERROR_PASSIVE: + dev->state = CAN_STATE_ERROR_PASSIVE; + break; + case CANDEV_EVENT_ERROR_WARNING: + dev->state = CAN_STATE_ERROR_WARNING; + break; + default: + DEBUG("_can_event: unknown event\n"); + break; + } +} + +int main(void) +{ + + puts("candev test application\n"); + + isrpipe_init(&rxbuf, (uint8_t *)rx_ringbuf, sizeof(rx_ringbuf)); +#ifdef BOARD_NATIVE + puts("Initializing Linux Can device"); + candev_linux_init( &linux_dev, &(candev_linux_conf[0])); /* vcan0 */ + candev = (candev_t *)&linux_dev; +#else + /* add initialization for other candev drivers here */ +#endif + + assert(candev); + + candev->event_callback = _can_event_callback; + candev->isr_arg = NULL; + + candev->driver->init(candev); + + char line_buf[SHELL_DEFAULT_BUFSIZE]; + shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); + + return 0; +}