-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Vincent Dupont
committed
Aug 31, 2016
1 parent
d72f830
commit 18ad903
Showing
3 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
export APPLICATION = can | ||
include ../Makefile.tests_common | ||
|
||
OS:=$(shell uname) | ||
|
||
CFLAGS += -DDEVELHELP | ||
CFLAGS += -DLOG_LEVEL=LOG_ALL | ||
CFLAGS_OPT = -O0 | ||
|
||
USEMODULE += shell | ||
USEMODULE += can | ||
USEMODULE += shell_commands | ||
USEMODULE += ps | ||
USEMODULE += xtimer | ||
|
||
ifeq ($(BOARD),native) | ||
ifeq ($(OS),Linux) | ||
USEMODULE += can_linux | ||
endif | ||
endif | ||
|
||
include $(RIOTBASE)/Makefile.include |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
tests/conn_can | ||
================ | ||
Demo application for the CAN stack with conn_can interface. | ||
|
||
|
||
Native prerequisites | ||
============ | ||
|
||
The native can_conf.h file 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 | ||
===== | ||
|
||
Add a can_conf.h file to boards/<board>/include which defines the can | ||
devices to use. | ||
Build, flash and start the application: | ||
``` | ||
export BOARD=your_board | ||
make | ||
make flash | ||
make term | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
/* | ||
* Copyright (C) 2016 OTA keys S.A. | ||
*/ | ||
|
||
/** | ||
* @ingroup main | ||
* @{ | ||
* | ||
* @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_can.h" | ||
|
||
#define THREAD_STACKSIZE (THREAD_STACKSIZE_MAIN) | ||
#define RECEIVE_THREAD_MSG_QUEUE_SIZE (8) | ||
|
||
#include "timex.h" | ||
#define TEST_CONN_CAN_RECV_TIMEOUT (10 * SEC_IN_USEC) | ||
|
||
static char thread_stack[THREAD_STACKSIZE]; | ||
kernel_pid_t receive_pid; | ||
|
||
static int _send(int argc, char **argv) | ||
{ | ||
if (argc < 5) { | ||
puts("Send: Not enough arguments\n"); | ||
return 1; | ||
} | ||
struct can_frame frame; | ||
int ifnum = strtol(argv[2], NULL, 0); | ||
|
||
frame.can_id = strtoul(argv[3], NULL, 0); | ||
frame.can_dlc = strtol(argv[4], NULL, 0); | ||
if (argc < 5 + frame.can_dlc) { | ||
puts("Not enough arguments\n"); | ||
return 1; | ||
} | ||
for (int i = 0; i < frame.can_dlc; i++) { | ||
frame.data[i] = strtol(argv[5 + i], NULL, 0); | ||
} | ||
conn_can_t conn; | ||
conn_can_create(&conn, NULL, 0, ifnum, CONN_CAN_RAW, 0); | ||
int ret = conn_can_send(&conn, &frame, sizeof(frame), 0); | ||
if (ret < 0) { | ||
puts("Error when trying to send\n"); | ||
} | ||
conn_can_close(&conn); | ||
return 0; | ||
} | ||
|
||
static int _receive(int argc, char **argv) | ||
{ | ||
if (argc < 4) { | ||
puts("Not enough arguments\n"); | ||
return 1; | ||
} | ||
int res; | ||
int ifnum = strtol(argv[2], NULL, 0); | ||
int filt_num = strtol(argv[3], NULL, 0); | ||
if (argc < 4 + filt_num) { | ||
puts("Not enough arguments\n"); | ||
return 1; | ||
} | ||
struct can_filter filters[filt_num]; | ||
for (int i = 0; i < filt_num; i++) { | ||
filters[i].can_id = strtoul(argv[4 + i], NULL, 0); | ||
filters[i].can_mask = 0xffffffff; | ||
} | ||
msg_t msg, reply; | ||
can_opt_t opt; | ||
opt.data = filters; | ||
opt.data_len = filt_num * sizeof(filters[0]); | ||
opt.context = ifnum; | ||
msg.type = CAN_MSG_SET; | ||
msg.content.ptr = &opt; | ||
res = msg_send_receive(&msg, &reply, receive_pid); | ||
if (res < 0 || (int)reply.content.value < 0) { | ||
puts("Error when setting filters\n"); | ||
return 1; | ||
} | ||
return 0; | ||
} | ||
|
||
static int _stop_receive(int argc, char **argv) | ||
{ | ||
(void) argc; | ||
(void) argv; | ||
msg_t msg; | ||
msg.type = 0x1234; | ||
msg_send(&msg, receive_pid); | ||
return 0; | ||
} | ||
|
||
static int _get_filter(int argc, char **argv) | ||
{ | ||
if (argc < 3) { | ||
puts("Not enough arguments\n"); | ||
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\n"); | ||
} | ||
else if (res == 0) { | ||
puts("No filter set\n"); | ||
} | ||
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) { | ||
puts("Not enough argument\n"); | ||
return 1; | ||
} | ||
|
||
int ifnum = strtol(argv[2], NULL, 0); | ||
uint32_t bitrate = strtoul(argv[3], NULL, 0); | ||
|
||
// Unable to find a function to set bitrate | ||
printf("Function not implemented. Bitrate (%"PRIu32") of Interface num: %d is still equal to its default value\n", bitrate, ifnum); | ||
|
||
// convertion bitrate to bit timing ???? | ||
return 0; // return = raw_can_set_can_opt(ifnum, CAN_MSG_SET, bitrate_into_bittiming) | ||
} | ||
|
||
static int _can_handler(int argc, char **argv) | ||
{ | ||
if (argc < 2) { | ||
puts("can send ifnum id len [B1 [B2 [B3 [B4 [B5 [B6 [B7 [B8]]]]]]]]\n"); | ||
puts("can recv ifnum nb_id id1 [id2..id16]\n"); | ||
puts("can get_filter ifnum\n"); | ||
puts("can set_bitrate ifnum bitrate\n"); | ||
return 1; | ||
} | ||
else if (strncmp(argv[1], "send", 4) == 0) { | ||
return _send(argc, argv); | ||
} | ||
else if (strncmp(argv[1], "recv", 4) == 0) { | ||
return _receive(argc, argv); | ||
} | ||
else if (strncmp(argv[1], "stop_recv", 9) == 0) { | ||
return _stop_receive(argc, argv); | ||
} | ||
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 { | ||
printf("unknown command: %s\n", argv[1]); | ||
return 1; | ||
} | ||
} | ||
|
||
static void *_receive_thread(void *args) | ||
{ | ||
(void) 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); | ||
|
||
while (1) { | ||
msg_receive(&msg); | ||
switch (msg.type) { | ||
case CAN_MSG_SET: | ||
{ | ||
int ret; | ||
msg_t reply; | ||
conn_can_t conn; | ||
can_opt_t *opt = msg.content.ptr; | ||
ret = conn_can_create(&conn, opt->data, opt->data_len, opt->context, CONN_CAN_RAW, 0); | ||
reply.type = msg.type; | ||
reply.content.value = ret; | ||
msg_reply(&msg, &reply); | ||
while ((ret = conn_can_recv(&conn, &frame, sizeof(struct can_frame), TEST_CONN_CAN_RECV_TIMEOUT)) == sizeof(struct can_frame)) { | ||
printf("Frame received 0x%" PRIx32 " dlc: 0x%02x data:", frame.can_id, frame.can_dlc); | ||
for (int i = 0; i < frame.can_dlc; i++) { | ||
printf(" 0x%02x", frame.data[i]); | ||
} | ||
printf("\n"); | ||
} | ||
printf("recv terminated: ret=%d\n", ret); | ||
conn_can_close(&conn); | ||
} | ||
break; | ||
|
||
case 0x1234: | ||
puts("_receive_thread: stop receiving\n"); | ||
break; | ||
|
||
default: | ||
puts("_receive_thread: received unknown message\n"); | ||
break; | ||
} | ||
} | ||
|
||
return NULL; | ||
} | ||
|
||
static const shell_command_t _commands[] = { | ||
{"can", "CAN functions", _can_handler}, | ||
{ NULL, NULL, NULL}, | ||
}; | ||
|
||
int main(void) | ||
{ | ||
char line_buf[SHELL_DEFAULT_BUFSIZE]; | ||
|
||
msg_t msg_queue[8]; | ||
msg_init_queue(msg_queue, 8); | ||
|
||
receive_pid = thread_create(thread_stack, THREAD_STACKSIZE, THREAD_PRIORITY_MAIN - 1, | ||
0, _receive_thread, NULL, "receive_thread"); | ||
|
||
shell_run(_commands, line_buf, SHELL_DEFAULT_BUFSIZE); | ||
|
||
return 0; | ||
} |