mirror of
https://github.com/gosticks/RIOT.git
synced 2025-10-16 12:05:37 +00:00
can: add conn_can test app
This commit is contained in:
parent
ab5f8548f2
commit
0a052f6b97
23
tests/conn_can/Makefile
Normal file
23
tests/conn_can/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
export APPLICATION = can
|
||||
include ../Makefile.tests_common
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := chronos msb-430 msb-430h nucleo32-f031 nucleo32-f042 \
|
||||
nucleo32-f303 nucleo32-l031 nucleo-f030 nucleo-f070 \
|
||||
nucleo-f072 nucleo-f302 nucleo-f303 nucleo-f334 \
|
||||
nucleo-l053 stm32f0discovery telosb weio wsn430-v1_3b \
|
||||
wsn430-v1_4 z1
|
||||
|
||||
|
||||
CFLAGS += -DDEVELHELP
|
||||
CFLAGS += -DLOG_LEVEL=LOG_ALL
|
||||
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
|
||||
USEMODULE += conn_can
|
||||
USEMODULE += can_isotp
|
||||
USEMODULE += conn_can_isotp_multi
|
||||
USEMODULE += can_pm
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
||||
152
tests/conn_can/README.md
Normal file
152
tests/conn_can/README.md
Normal file
@ -0,0 +1,152 @@
|
||||
tests/conn_can
|
||||
================
|
||||
Demo application for the CAN stack with conn_can interface.
|
||||
|
||||
|
||||
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
|
||||
=====
|
||||
|
||||
Build, flash and start the application:
|
||||
```
|
||||
export BOARD=your_board
|
||||
make
|
||||
make flash
|
||||
make term
|
||||
```
|
||||
|
||||
The CAN interfaces are registered at startup to the dll. The list of registered
|
||||
interfaces and their RIOT names can be retrieved with:
|
||||
```
|
||||
can list
|
||||
```
|
||||
|
||||
To send a raw CAN frame, id 0x100 with 2 bytes of data 01 02 on interface 0:
|
||||
```
|
||||
can send 0 100 01 02
|
||||
```
|
||||
|
||||
Two threads are launched to enable receiving frames. To receive raw CAN frames,
|
||||
ids 0x100 and 0x500 with thread 0 on interface 1, with 10s timeout:
|
||||
```
|
||||
can recv 1 0 10000000 100 500
|
||||
```
|
||||
|
||||
A connection can be closed with its thread id, for instance:
|
||||
```
|
||||
can close 0
|
||||
```
|
||||
|
||||
|
||||
To send an ISO-TP datagram, first bind a connection with one of the threads,
|
||||
source id 700, dest id 708, thread 1 and interface 0:
|
||||
```
|
||||
can bind_isotp 0 1 700 708
|
||||
```
|
||||
Then send the data 01 02 03 04 05 0a 0b 0c:
|
||||
```
|
||||
can send_isotp 1 01 02 03 04 05 0a 0b 0c
|
||||
```
|
||||
|
||||
To receive from an ISO-TP channel, it must be bound, then with the previous channel,
|
||||
and 10s timeout:
|
||||
```
|
||||
can recv_isotp 1 10000000
|
||||
```
|
||||
|
||||
An ISO-TP channel can be closed with:
|
||||
```
|
||||
can close_isotp 1
|
||||
```
|
||||
|
||||
You can also set a bitrate (this won't work on native with vcan, only with real
|
||||
interfaces, but then root access are needed), for instance 250000 bit/s with
|
||||
sampling point 87.5%:
|
||||
```
|
||||
can set_bitrate 250000 875
|
||||
```
|
||||
|
||||
Linux CAN basic commands
|
||||
========================
|
||||
|
||||
Once the interfaces are set up, can-utils commands provide a way to send and receive
|
||||
raw CAN frames and ISO-TP datagrams.
|
||||
|
||||
For ISO-TP, an experimental module for linux can be found [here](https://github.com/hartkopp/can-isotp).
|
||||
It needs to be loaded before trying to use ISO-TP protocol.
|
||||
|
||||
Here are some basics examples.
|
||||
|
||||
Send a raw CAN frame, id 0x100, data 00 11 22:
|
||||
```
|
||||
cansend vcan0 100#001122
|
||||
```
|
||||
|
||||
Dump the traffic on a CAN interface:
|
||||
```
|
||||
candump vcan0
|
||||
```
|
||||
|
||||
Send an ISO-TP datagram, source id 700, dest id 708, data 00 11 22 33 aa bb cc dd:
|
||||
```
|
||||
echo 00 11 22 33 aa bb cc dd | isotpsend -s 700 -d 708 vcan0
|
||||
```
|
||||
|
||||
Receive ISO-TP datagram:
|
||||
```
|
||||
isotprecv -s 708 -d 700 vcan0
|
||||
```
|
||||
|
||||
Please read commands help for more details on usage.
|
||||
634
tests/conn_can/main.c
Normal file
634
tests/conn_can/main.c
Normal file
@ -0,0 +1,634 @@
|
||||
/*
|
||||
* Copyright (C) 2016 OTA keys S.A.
|
||||
*
|
||||
* 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 main
|
||||
*
|
||||
* @author Vincent Dupont <vincent@otakeys.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "shell.h"
|
||||
#include "board.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "can/can.h"
|
||||
#include "can/conn/raw.h"
|
||||
#include "can/conn/isotp.h"
|
||||
#include "can/device.h"
|
||||
|
||||
#define THREAD_STACKSIZE (THREAD_STACKSIZE_MAIN)
|
||||
#define RECEIVE_THREAD_MSG_QUEUE_SIZE (8)
|
||||
|
||||
#include "timex.h"
|
||||
#define TEST_CONN_CAN_RECV_TIMEOUT (30 * US_PER_SEC)
|
||||
|
||||
#define RCV_THREAD_NUMOF (2)
|
||||
|
||||
#define MAX_FILTER (16)
|
||||
|
||||
#define CAN_MSG_RECV 0x400
|
||||
#define CAN_MSG_BIND_ISOTP 0x401
|
||||
#define CAN_MSG_RECV_ISOTP 0x402
|
||||
#define CAN_MSG_CLOSE_ISOTP 0x403
|
||||
#define CAN_MSG_SEND_ISOTP 0x404
|
||||
|
||||
static char thread_stack[RCV_THREAD_NUMOF][THREAD_STACKSIZE];
|
||||
static kernel_pid_t receive_pid[RCV_THREAD_NUMOF];
|
||||
|
||||
static conn_can_raw_t conn[RCV_THREAD_NUMOF];
|
||||
static struct can_filter filters[RCV_THREAD_NUMOF][MAX_FILTER];
|
||||
|
||||
#ifdef MODULE_CAN_ISOTP
|
||||
#define ISOTP_BUF_SIZE 1024
|
||||
static uint8_t isotp_buf[RCV_THREAD_NUMOF][ISOTP_BUF_SIZE];
|
||||
|
||||
static conn_can_isotp_t conn_isotp[RCV_THREAD_NUMOF];
|
||||
#endif
|
||||
|
||||
static int thread_busy[RCV_THREAD_NUMOF];
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
puts("test_can list");
|
||||
puts("test_can send ifnum can_id [B1 [B2 [B3 [B4 [B5 [B6 [B7 [B8]]]]]]]]");
|
||||
printf("test_can recv ifnum user_id timeout can_id1 [can_id2..can_id%d]\n", MAX_FILTER);
|
||||
puts("test_can close user_id");
|
||||
#ifdef MODULE_CAN_ISOTP
|
||||
puts("test_can bind_isotp ifnum user_id source_id dest_id");
|
||||
puts("test_can send_isotp user_id [B1 [.. [ Bn ]]]");
|
||||
puts("test_can recv_isotp user_id timeout");
|
||||
puts("test_can close_isotp user_id");
|
||||
#endif
|
||||
puts("test_can get_filter ifnum");
|
||||
puts("test_can set_bitrate ifnum bitrate [sample_point]");
|
||||
puts("test_can get_bitrate ifnum");
|
||||
puts("test_can get_counter ifnum");
|
||||
puts("test_can power_up ifnum");
|
||||
puts("test_can power_down ifnum");
|
||||
}
|
||||
|
||||
static int _list(int argc, char **argv) {
|
||||
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
for (int i = 0; i < CAN_DLL_NUMOF; i++) {
|
||||
const char *name = raw_can_get_name_by_ifnum(i);
|
||||
if (name) {
|
||||
printf("CAN #%d: %s\n", i, name);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _send(int argc, char **argv)
|
||||
{
|
||||
if (argc < 5) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
struct can_frame frame;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
frame.can_id = strtoul(argv[3], NULL, 16);
|
||||
frame.can_dlc = argc - 4;
|
||||
if (frame.can_dlc > 8) {
|
||||
puts("Invalid length");
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < frame.can_dlc; i++) {
|
||||
frame.data[i] = strtol(argv[4 + i], NULL, 16);
|
||||
}
|
||||
conn_can_raw_t conn;
|
||||
conn_can_raw_create(&conn, NULL, 0, ifnum, 0);
|
||||
int ret = conn_can_raw_send(&conn, &frame, 0);
|
||||
if (ret < 0) {
|
||||
puts("Error when trying to send");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _receive(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int res;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thread_nb = strtol(argv[3], NULL, 0);
|
||||
int filt_num = argc - 5;
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
if (thread_busy[thread_nb]) {
|
||||
puts("Thread already in use");
|
||||
return 1;
|
||||
}
|
||||
if (filt_num > MAX_FILTER) {
|
||||
puts("Too many filters");
|
||||
return 1;
|
||||
}
|
||||
for (int i = 0; i < filt_num; i++) {
|
||||
filters[thread_nb][i].can_id = strtoul(argv[5 + i], NULL, 16);
|
||||
filters[thread_nb][i].can_mask = 0xffffffff;
|
||||
}
|
||||
uint32_t timeout = strtoul(argv[4], NULL, 0);
|
||||
msg_t msg;
|
||||
msg.type = CAN_MSG_RECV;
|
||||
msg.content.value = timeout;
|
||||
res = conn_can_raw_create(&conn[thread_nb], filters[thread_nb],
|
||||
filt_num, ifnum, 0);
|
||||
if (res < 0) {
|
||||
puts("Error when setting filters");
|
||||
return 1;
|
||||
}
|
||||
thread_busy[thread_nb] = 1;
|
||||
msg_send(&msg, receive_pid[thread_nb]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _close(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int thread_nb = strtol(argv[2], NULL, 0);
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
conn_can_raw_close(&conn[thread_nb]);
|
||||
thread_busy[thread_nb] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MODULE_CAN_ISOTP
|
||||
static int _bind_isotp(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int ret;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int thread_nb = strtol(argv[3], NULL, 0);
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
if (thread_busy[thread_nb]) {
|
||||
puts("Thread already in use");
|
||||
return 1;
|
||||
}
|
||||
struct isotp_options isotp_opt;
|
||||
memset(&isotp_opt, 0, sizeof(isotp_opt));
|
||||
isotp_opt.tx_id = strtoul(argv[4], NULL, 16);
|
||||
isotp_opt.rx_id = strtoul(argv[5], NULL, 16);
|
||||
|
||||
#ifdef MODULE_CONN_CAN_ISOTP_MULTI
|
||||
conn_can_isotp_init_slave(&conn_isotp[thread_nb], (conn_can_isotp_slave_t *)&conn_isotp[thread_nb]);
|
||||
#endif
|
||||
ret = conn_can_isotp_create(&conn_isotp[thread_nb], &isotp_opt, ifnum);
|
||||
if (ret == 0) {
|
||||
ret = conn_can_isotp_bind(&conn_isotp[thread_nb]);
|
||||
}
|
||||
if (ret < 0) {
|
||||
puts("Error when binding connection");
|
||||
return 1;
|
||||
}
|
||||
thread_busy[thread_nb] = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _send_isotp(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int thread_nb = strtoul(argv[2], NULL, 0);
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
int len = argc - 3;
|
||||
uint8_t data[len];
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[i] = strtol(argv[3 + i], NULL, 16);
|
||||
}
|
||||
|
||||
msg_t msg, reply;
|
||||
can_opt_t opt;
|
||||
opt.data = data;
|
||||
opt.data_len = len;
|
||||
msg.type = CAN_MSG_SEND_ISOTP;
|
||||
msg.content.ptr = &opt;
|
||||
int res = msg_send_receive(&msg, &reply, receive_pid[thread_nb]);
|
||||
if (res < 0 || (int)reply.content.value < 0) {
|
||||
puts("Error when sending");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _receive_isotp(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int thread_nb = strtol(argv[2], NULL, 0);
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
uint32_t timeout = strtoul(argv[3], NULL, 0);
|
||||
|
||||
msg_t msg;
|
||||
msg.type = CAN_MSG_RECV_ISOTP;
|
||||
msg.content.value = timeout;
|
||||
msg_send(&msg, receive_pid[thread_nb]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _close_isotp(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int thread_nb = strtol(argv[2], NULL, 0);
|
||||
if (thread_nb >= RCV_THREAD_NUMOF) {
|
||||
printf("Invalid thread number, range=0..%d\n", RCV_THREAD_NUMOF - 1);
|
||||
return 1;
|
||||
}
|
||||
conn_can_isotp_close(&conn_isotp[thread_nb]);
|
||||
thread_busy[thread_nb] = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif /* MODULE_CAN_ISOTP */
|
||||
|
||||
static int _get_filter(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
int res;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
struct can_filter filters[32];
|
||||
can_opt_t opt;
|
||||
opt.data = (void *)filters;
|
||||
opt.data_len = sizeof(filters);
|
||||
opt.opt = CANOPT_RX_FILTERS;
|
||||
res = raw_can_get_can_opt(ifnum, &opt);
|
||||
if (res < 0) {
|
||||
puts("Error when reading filters");
|
||||
}
|
||||
else if (res == 0) {
|
||||
puts("No filter set");
|
||||
}
|
||||
else {
|
||||
for (unsigned int i = 0; i < res / sizeof(filters[0]); i++) {
|
||||
printf("Filter %d: 0x%" PRIx32"\n", i, filters[i].can_id);
|
||||
printf("Mask %d: 0x%" PRIx32"\n", i, filters[i].can_mask);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _set_bitrate(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
printf("Invalid ifnum %d\n", ifnum);
|
||||
return 1;
|
||||
}
|
||||
uint32_t bitrate = strtoul(argv[3], NULL, 0);
|
||||
uint32_t sample_point = 0;
|
||||
|
||||
int ret;
|
||||
if (argc > 4) {
|
||||
sample_point = strtoul(argv[4], NULL, 0);
|
||||
}
|
||||
printf("Setting bitrate=%" PRIu32 ", sample point=%" PRIu32 "\n",
|
||||
bitrate, sample_point);
|
||||
ret = raw_can_set_bitrate(ifnum, bitrate, sample_point);
|
||||
if (ret < 0) {
|
||||
printf("Error when setting bitrate: res=%d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
else if (ret == 1) {
|
||||
puts("Bitrate/sample_point cannot be reached");
|
||||
}
|
||||
|
||||
puts("Bittimings successfully set");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_bitrate(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
struct can_bittiming bittiming;
|
||||
can_opt_t opt;
|
||||
opt.data = &bittiming;
|
||||
opt.data_len = sizeof(bittiming);
|
||||
opt.opt = CANOPT_BITTIMING;
|
||||
|
||||
int ret = raw_can_get_can_opt(ifnum, &opt);
|
||||
if (ret < 0) {
|
||||
printf("Error when getting bitrate: res=%d\n", ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Bitrate read: bitrate=%" PRIu32 ", sample_point=%" PRIu32
|
||||
"\nbrp=%" PRIu32 "phase-seg1=%" PRIu32
|
||||
", phase-seg2=%" PRIu32 ", sjw=%" PRIu32 "\n", bittiming.bitrate,
|
||||
bittiming.sample_point, bittiming.brp, bittiming.phase_seg1,
|
||||
bittiming.phase_seg2, bittiming.sjw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _get_counter(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t cnt;
|
||||
can_opt_t opt;
|
||||
opt.data = &cnt;
|
||||
opt.data_len = sizeof(cnt);
|
||||
opt.opt = CANOPT_TEC;
|
||||
|
||||
int ret = raw_can_get_can_opt(ifnum, &opt);
|
||||
if (ret < 0) {
|
||||
printf("Error when getting TEC: res=%d\n", ret);
|
||||
res = 1;
|
||||
}
|
||||
else {
|
||||
printf("TEC=%" PRIu16, cnt);
|
||||
}
|
||||
|
||||
opt.opt = CANOPT_REC;
|
||||
|
||||
ret = raw_can_get_can_opt(ifnum, &opt);
|
||||
if (ret < 0) {
|
||||
printf("\nError when getting REC: res=%d\n", ret);
|
||||
res = 1;
|
||||
}
|
||||
else {
|
||||
printf(", REC=%" PRIu16 "\n", cnt);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _power_up(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = raw_can_power_up(ifnum);
|
||||
if (ret < 0) {
|
||||
printf("Error when powering up: res=%d\n", ret);
|
||||
res = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _power_down(int argc, char **argv)
|
||||
{
|
||||
if (argc < 3) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
int ifnum = strtol(argv[2], NULL, 0);
|
||||
if (ifnum >= CAN_DLL_NUMOF) {
|
||||
puts("Invalid interface number");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ret = raw_can_power_down(ifnum);
|
||||
if (ret < 0) {
|
||||
printf("Error when powering up: res=%d\n", ret);
|
||||
res = 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int _can_handler(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
print_usage();
|
||||
return 1;
|
||||
}
|
||||
else if (strncmp(argv[1], "list", 5) == 0) {
|
||||
return _list(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "send", 5) == 0) {
|
||||
return _send(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "recv", 5) == 0) {
|
||||
return _receive(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "close", 6) == 0) {
|
||||
return _close(argc, argv);
|
||||
}
|
||||
#ifdef MODULE_CAN_ISOTP
|
||||
else if (strncmp(argv[1], "bind_isotp", 11) == 0) {
|
||||
return _bind_isotp(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "send_isotp", 11) == 0) {
|
||||
return _send_isotp(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "recv_isotp", 11) == 0) {
|
||||
return _receive_isotp(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "close_isotp", 12) == 0) {
|
||||
return _close_isotp(argc, argv);
|
||||
}
|
||||
#endif
|
||||
else if (strncmp(argv[1], "get_filter", 10) == 0) {
|
||||
return _get_filter(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "set_bitrate", 11) == 0) {
|
||||
return _set_bitrate(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "get_bitrate", 11) == 0) {
|
||||
return _get_bitrate(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "get_counter", 11) == 0) {
|
||||
return _get_counter(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "power_up", 9) == 0) {
|
||||
return _power_up(argc, argv);
|
||||
}
|
||||
else if (strncmp(argv[1], "power_down", 11) == 0) {
|
||||
return _power_down(argc, argv);
|
||||
}
|
||||
else {
|
||||
printf("unknown command: %s\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void *_receive_thread(void *args)
|
||||
{
|
||||
int thread_nb = (int)args;
|
||||
struct can_frame frame;
|
||||
msg_t msg, msg_queue[RECEIVE_THREAD_MSG_QUEUE_SIZE];
|
||||
|
||||
/* setup the device layers message queue */
|
||||
msg_init_queue(msg_queue, RECEIVE_THREAD_MSG_QUEUE_SIZE);
|
||||
|
||||
printf("%d: launching receive_thread\n", thread_nb);
|
||||
|
||||
while (1) {
|
||||
msg_receive(&msg);
|
||||
switch (msg.type) {
|
||||
case CAN_MSG_RECV:
|
||||
{
|
||||
int ret;
|
||||
while ((ret = conn_can_raw_recv(&conn[thread_nb], &frame, msg.content.value))
|
||||
== sizeof(struct can_frame)) {
|
||||
printf("%d: %-8s %" PRIx32 " [%x] ",
|
||||
thread_nb, raw_can_get_name_by_ifnum(conn[thread_nb].ifnum),
|
||||
frame.can_id, frame.can_dlc);
|
||||
for (int i = 0; i < frame.can_dlc; i++) {
|
||||
printf(" %02X", frame.data[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("%d: recv terminated: ret=%d\n", thread_nb, ret);
|
||||
conn_can_raw_close(&conn[thread_nb]);
|
||||
thread_busy[thread_nb] = 0;
|
||||
break;
|
||||
}
|
||||
#ifdef MODULE_CAN_ISOTP
|
||||
case CAN_MSG_RECV_ISOTP:
|
||||
{
|
||||
int ret;
|
||||
while ((ret = conn_can_isotp_recv(&conn_isotp[thread_nb], isotp_buf[thread_nb],
|
||||
ISOTP_BUF_SIZE, msg.content.value))
|
||||
<= ISOTP_BUF_SIZE && ret >= 0) {
|
||||
printf("%d: %-8s ISOTP [%d] ",
|
||||
thread_nb, raw_can_get_name_by_ifnum(conn_isotp[thread_nb].ifnum), ret);
|
||||
for (int i = 0; i < ret; i++) {
|
||||
printf(" %02X", isotp_buf[thread_nb][i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("%d: recv terminated: ret=%d\n", thread_nb, ret);
|
||||
break;
|
||||
}
|
||||
case CAN_MSG_SEND_ISOTP:
|
||||
{
|
||||
msg_t reply;
|
||||
can_opt_t *opt = msg.content.ptr;
|
||||
int ret = conn_can_isotp_send(&conn_isotp[thread_nb], opt->data, opt->data_len, 0);
|
||||
reply.type = msg.type;
|
||||
reply.content.value = ret;
|
||||
msg_reply(&msg, &reply);
|
||||
break;
|
||||
}
|
||||
#endif /* MODULE_CAN_ISOTP */
|
||||
default:
|
||||
printf("%d: _receive_thread: received unknown message\n", thread_nb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const shell_command_t _commands[] = {
|
||||
{"test_can", "Test CAN functions", _can_handler},
|
||||
{ NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
for (int i = 0; i < RCV_THREAD_NUMOF; i++) {
|
||||
receive_pid[i] = thread_create(thread_stack[i], THREAD_STACKSIZE,
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST, _receive_thread,
|
||||
(void*)i, "receive_thread");
|
||||
}
|
||||
|
||||
char line_buf[SHELL_DEFAULT_BUFSIZE];
|
||||
shell_run(_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user