mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #13360 from wosym/tests/candev_native4
Tests/candev: Initial version with native support
This commit is contained in:
commit
bb025e46ac
@ -125,6 +125,7 @@
|
||||
/sys/ztimer/ @kaspar030 @bergzand
|
||||
|
||||
/tests/ @smlng @leandrolanzieri @aabadie @MichelRottleuthner @fjmolinas
|
||||
/tests/candev/ @wosym
|
||||
/tests/emb6* @miri64
|
||||
/tests/gnrc* @miri64
|
||||
/tests/lwip* @miri64
|
||||
|
@ -726,7 +726,6 @@ ifneq (,$(filter can_linux,$(USEMODULE)))
|
||||
endif
|
||||
|
||||
ifneq (,$(filter can,$(USEMODULE)))
|
||||
DEFAULT_MODULE += auto_init_can
|
||||
USEMODULE += can_raw
|
||||
ifneq (,$(filter can_mbox,$(USEMODULE)))
|
||||
USEMODULE += core_mbox
|
||||
|
20
tests/candev/Makefile
Normal file
20
tests/candev/Makefile
Normal file
@ -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
|
1
tests/candev/Makefile.ci
Normal file
1
tests/candev/Makefile.ci
Normal file
@ -0,0 +1 @@
|
||||
FEATURES_BLACKLIST += arch_msp430
|
109
tests/candev/README.md
Normal file
109
tests/candev/README.md
Normal file
@ -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 <bytes>
|
||||
```
|
||||
|
||||
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 <n>
|
||||
```
|
||||
|
||||
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 <interface> <can_id>:<hexbytes>
|
||||
```
|
||||
|
||||
e.g.:
|
||||
|
||||
```
|
||||
$ cansend vcan0 001:1234ABCD
|
||||
```
|
||||
|
||||
An alternative is to use `cangen` to generate a number of random can messages:
|
||||
|
||||
```
|
||||
$ cangen <interface> -v -n <n>
|
||||
```
|
||||
|
||||
e.g.:
|
||||
|
||||
```
|
||||
$ cangen vcan0 -v -n 5
|
||||
```
|
||||
|
||||
will send 5 can messages to vcan0 with verbose output.
|
214
tests/candev/main.c
Normal file
214
tests/candev/main.c
Normal file
@ -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 <tstegen@nalys-group.com>
|
||||
* @author Wouter Symons <wsymons@nalys-group.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <isrpipe.h>
|
||||
#include "shell.h"
|
||||
#include "can/device.h"
|
||||
|
||||
#ifdef BOARD_NATIVE
|
||||
|
||||
#include <candev_linux.h>
|
||||
|
||||
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 <number>");
|
||||
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;
|
||||
}
|
@ -11,6 +11,7 @@ USEMODULE += can_isotp
|
||||
USEMODULE += conn_can_isotp_multi
|
||||
USEMODULE += can_pm
|
||||
USEMODULE += can_trx
|
||||
USEMODULE += auto_init_can
|
||||
|
||||
CFLAGS += -DGNRC_PKTBUF_SIZE=4096
|
||||
CFLAGS += -DCAN_PKT_BUF_SIZE=64
|
||||
|
Loading…
Reference in New Issue
Block a user