can: add two examples for the can interface

Added two examples about how to configure and set a CAN
interface to establish a communication receiving and
sending frames.

Signed-off-by: fgilmar <francisco.gilmartinez@digi.com>
This commit is contained in:
fgilmar 2018-11-13 17:46:07 +01:00
parent 9a3f723fe1
commit b541f27702
4 changed files with 777 additions and 0 deletions

View File

@ -0,0 +1,44 @@
#
# Copyright 2017, Digi International Inc.
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
#
all: BINARYTX BINARYRX
BINARYTX := apix-can-send-example
BINARYRX := apix-can-recv-example
BINARIES := $(BINARYTX) $(BINARYRX)
CFLAGS += -Wall -O0
CFLAGS += $(shell pkg-config --cflags libdigiapix)
LDLIBS += $(shell pkg-config --libs libdigiapix)
BINARYTX: can-send-example.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $(BINARYTX)
BINARYRX: can-recv-example.o
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $(BINARYRX)
.PHONY: install
install: $(BINARIES)
install -d $(DESTDIR)/usr/bin
install -m 0755 $^ $(DESTDIR)/usr/bin/
.PHONY: all
all: $(BINARYTX) $(BINARYRX)
.PHONY: clean
clean:
-rm -f *.o $(BINARYTX) $(BINARYRX)

134
apix-can-examples/README.md Normal file
View File

@ -0,0 +1,134 @@
Digi APIX CAN Example Applications
===================================
Example applications to access and manage CAN interface using the Digi APIX library.
These applications enable one CAN interface of the board and start a tranmission or
reception using the selected baudrate.
In the reception example the application will wait for frames and print them in the
console. You can configure filters to listen to some kind of frames only.
In the transmission example the application will generate and send frames configure the DLC,
the ID and print in the console.
The CAN interface for this example depends on the running platform:
ConnectCore 6 SBC: CAN connector of the board (J27).
CAN1_L: Pin 1
CAN1_H: Pin 2
GND: Pin 3
CAN2_L: Pin 4 *
CAN2_H: Pin 5 *
GND: Pin 6
ConnectCore 6 Plus SBC: CAN connector of the board (J27).
CAN1_L: Pin 1
CAN1_H: Pin 2
GND: Pin 3
CAN2_L: Pin 4 *
CAN2_H: Pin 5 *
GND: Pin 6
ConnectCore 6UL SBC Express: Raspberry PI connector (J8).
(An external CAN transceiver is needed).
RX: Pin 26
TX: Pin 22
ConnectCore 6UL SBC Pro: CAN connector of the board (J27).
CAN1_L: Pin 1
CAN1_H: Pin 2
GND: Pin 3
CAN2_L: Pin 4 *
CAN2_H: Pin 5 *
GND: Pin 6
ConnectCore CC8X SBC Pro: Expansion connector (J27).
CAN1_L: D 5
CAN1_H: D 6
GND: Pin 3
CAN2_L: C 5
CAN2_H: C 6
*Note: These pins are not enabled by default, you need to create a custom device tree
Running the apix-can-recv-example application
-----------------------
Once the binary is in the target, launch the application:
```
# ./apix-can-recv-example
Example application using libdigiapix CAN support"
Usage: %s -i <can-iface> -b <bitrate> [options]"
-i <can-iface> Name of the CAN interface"
-b <bitrate> Bitrate to use (Hz)"
-f <filters> Comma-separated filter list in the format"
id:mask (id and mask values in hex)"
-p Print message info"
-c Print message counter"
-h Help"
Examples:\n"
%s -i can0 -b 500000 -f 023:fff,006:00f
%s -i can1 -b 100000
```
If no arguments are provided, the example will use the default values:
- Specific application default values are defined in the main file.
The application will wait for frames. If you provide some filters it will only
wait for the chosen ones.
Running the apix-can-send-example application
-----------------------
Once the binary is in the target, launch the application:
```
# ./apix-can-send-example
Example application using libdigiapix CAN support"
"Usage: %s -i <can-iface> -b <bitrate> [options]"
"-i <can-iface> Name of the CAN interface"
"-b <bitrate> Bitrate to use (Hz)"
"-n <num_msgs> Number of messages to send (default 1)"
"-t <delay> Inter frame delay in ms (default 100)"
"-I <msg_id> Message id in hex (default 123)"
"-l <data_length> Payload length (default 8)"
"-r Generate a random ID (will ignore the -I parameter)"
"-p Generate a random payload (will ignore the -l parameter)"
"-e Use extended id"
"-R Set RTR"
```
You need to provide at least the can-iface and the bitrate.
For the other values if arguments are not provided, the example will use the default values:
- Specific application default values are defined in the main file.
The application will send frames periodically with the selected time rate.
Compiling the application
-------------------------
These demos can be compiled using a Digi Embedded Yocto based toolchain. Make
sure to source the corresponding toolchain of the platform you are using, e.g:
```
$> . <DEY-toolchain-path>/environment-setup-cortexa7hf-vfp-neon-dey-linux-gnueabi
$> make
```
More information about [Digi Embedded Yocto](https://github.com/digi-embedded/meta-digi).
License
-------
Copyright 2018, Digi International Inc.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.

View File

@ -0,0 +1,300 @@
/*
* Copyright 2018, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libdigiapix/can.h>
#define MAX_RECEPTION_BUFFER 512*1024
static can_if_t *can_if;
static struct can_filter *cfilter;
static struct can_filter *canfilter;
static bool running = true;
static bool prn_msg_info = false;
static bool prn_msg_count = false;
/*
* usage_and_exit() - Show usage information and exit with 'exitval' return
* value
*
* @name: Application name.
* @exitval: The exit code.
*/
static void usage_and_exit(char *name, int exitval)
{
printf(
"Example application using libdigiapix CAN support\n"
"\n"
"Usage: %s -i <can-iface> -b <bitrate> [options]\n\n"
"-i <can-iface> Name of the CAN interface\n"
"-b <bitrate> Bitrate to use (Hz)\n"
"-f <filters> Comma-separated filter list in the format\n"
" id:mask (id and mask values in hex)\n"
"-p Print message info\n"
"-c Print message counter\n"
"-h Help\n"
"\n"
"Examples:\n"
"%s -i can0 -b 500000 -f 023:fff,006:00f\n"
"%s -i can1 -b 100000\n"
"\n", name, name, name);
exit(exitval);
}
/*
* cleanup() - Frees all the allocated memory before exiting
*/
static void cleanup(void)
{
if (canfilter)
free(canfilter);
if (can_if) {
ldx_can_stop(can_if);
ldx_can_free(can_if);
running = false;
}
}
/*
* sigaction_handler() - Handler to execute after receiving a signal
*
* @signum: Received signal.
*/
static void sigaction_handler(int signum)
{
/* 'atexit' executes the cleanup function */
exit(EXIT_FAILURE);
}
/*
* register_signals() - Registers program signals
*/
static void register_signals(void)
{
struct sigaction action;
action.sa_handler = sigaction_handler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaction(SIGHUP, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
}
static void can_rx_callback(struct canfd_frame *frame, struct timeval *tv)
{
static uint32_t nframe = 1;
if (prn_msg_count) {
printf("CAN frame %u\n", nframe);
} else {
printf("CAN frame\n");
}
if (prn_msg_info) {
printf(
" - Time: %ld.%06ld\n"
" - Type: %s\n"
" - ID: %x\n"
" - Data length: %u\n"
" - Data: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
"\n",
tv->tv_sec, tv->tv_usec, ldx_can_is_extid_frame(frame) ?
"Extended ID" : "Standard ID", ldx_can_get_id(frame), frame->len,
frame->data[0], frame->data[1], frame->data[2], frame->data[3],
frame->data[4], frame->data[5], frame->data[6], frame->data[7]);
}
nframe++;
}
static int strchartimes(const char *str, int c)
{
int count = 0;
char *character;
for (character = (char *)str;
character && *character != '\0';
character++) {
if (*character == c)
count++;
}
return count;
}
/*
* parse_filters() -
*
* @str: String that contains all the filters
* @cfilter: Struct that contains the filters
* @nfilters: Number of valid filters found on str.
*
* Return: 0 on success, error code otherwise.
*/
static int parse_filters(char *str, struct can_filter **cfilter, int *nfilters)
{
int ret;
int posible_filters;
int good_filters = 0;
char *p = str;
/* First compute the number of filters */
posible_filters = strchartimes(str, ',');
posible_filters++;
/* Allocate the memory for all the possible filters */
canfilter = malloc(sizeof(struct can_filter) * posible_filters);
if (!canfilter) {
printf("Unable to allocate memory for filters\n");
return -ENOMEM;
}
/* Parse the information for each filter */
while (posible_filters-- && p) {
ret = sscanf(p, "%x:%x",
&canfilter[good_filters].can_id,
&canfilter[good_filters].can_mask);
if (ret == 2)
good_filters++;
p = strchr(p, ',');
if (p)
p++;
}
*nfilters = good_filters;
*cfilter = canfilter;
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
char *name = basename(argv[0]);
char *iface;
can_if_cfg_t ifcfg;
int nfilters = 0;
int opt;
int ret;
struct can_filter deffilter;
deffilter.can_id = 0;
deffilter.can_mask = 0;
if (argc <= 3) {
usage_and_exit(name, EXIT_FAILURE);
}
ldx_can_set_defconfig(&ifcfg);
while ((opt = getopt(argc, argv, "i:b:f:pc")) > 0) {
switch (opt) {
case 'i':
iface = optarg;
break;
case 'b':
ifcfg.bitrate = strtoul(optarg, NULL, 10);
break;
case 'f':
ret = parse_filters(optarg, &cfilter, &nfilters);
if (ret) {
printf("Unable to parse filter information\n\n");
usage_and_exit(name, EXIT_FAILURE);
}
break;
case 'p':
prn_msg_info = true;
break;
case 'c':
prn_msg_count = true;
break;
case 'h':
usage_and_exit(name, EXIT_SUCCESS);
break;
default:
usage_and_exit(name, EXIT_FAILURE);
}
}
printf("Requesting CAN interface %s... ", iface);
can_if = ldx_can_request_by_name(iface);
if (!can_if) {
printf("ERROR\n");
return EXIT_FAILURE;
}
printf("OK\n");
/* Register signals and exit cleanup function */
atexit(cleanup);
register_signals();
/* Increase the buffer reception size */
ifcfg.rx_buf_len = MAX_RECEPTION_BUFFER;
printf("Initializing CAN interface... ");
ret = ldx_can_init(can_if, &ifcfg);
if (ret) {
printf("ERROR\n");
goto error;
}
printf("OK\n");
/*
* Configure a callback to process the defined filters, otherwise,
* use the default filter.
*/
if (nfilters == 0) {
nfilters = 1;
cfilter = &deffilter;
}
ret = ldx_can_register_rx_handler(can_if, can_rx_callback,
cfilter, nfilters);
if (ret < 0) {
printf("Failed to register rx msg handler\n");
goto error;
}
while (running) {
sleep(5);
printf("Waiting for CAN frames...\n");
}
error:
printf("\n\nCan receive frame application has finished\n");
return ret;
}

View File

@ -0,0 +1,299 @@
/*
* Copyright 2018, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libdigiapix/can.h>
#define TX_RETRIES 10
#define RANDOM_ID_BIT 0
#define EXT_ID_BIT 1
#define RTR_BIT 2
#define RANDOM_DLC_BIT 3
#define RANDOM_ID_MASK 0x01
#define EXT_ID_MASK 0x02
#define RTR_BIT_MASK 0x04
#define RANDOM_DLC_MASK 0x08
#define RANDOM_ID(random_id) (random_id << RANDOM_ID_BIT)
#define EXT_ID(extended_id) (extended_id << EXT_ID_BIT)
#define RTR(rtr) (rtr << RTR_BIT)
#define RANDOM_DLC(dlc) (dlc << RANDOM_DLC_BIT)
static can_if_t *can_if;
static bool running = true;
/*
* usage_and_exit() - Show usage information and exit with 'exitval' return
* value
*
* @name: Application name.
* @exitval: The exit code.
*/
static void usage_and_exit(char *name, int exitval)
{
printf(
"Example application using libdigiapix CAN support\n"
"\n"
"Usage: %s -i <can-iface> -b <bitrate> [options]\n\n"
"-i <can-iface> Name of the CAN interface\n"
"-b <bitrate> Bitrate to use (Hz)\n"
"-n <num_msgs> Number of messages to send (default 1)\n"
"-t <delay> Inter frame delay in ms (default 100)\n"
"-I <msg_id> Message id in hex (default 123)\n"
"-l <data_length> Payload length (default 8)\n"
"-r Generate a random ID (will ignore the -I parameter)\n"
"-p Generate a random payload (will ignore the -l parameter)\n"
"-e Use extended id\n"
"-R Set RTR\n"
"\n"
"Examples:\n"
"%s -i can0 -b 500000 -n 100 -R\n"
"%s -i can1 -b 100000\n"
"\n", name, name, name);
exit(exitval);
}
/*
* ms_sleep() - Wait ms miliseconds
*
* ms: Number of ms to wait.
*/
void ms_sleep(uint32_t ms)
{
struct timespec ts;
if (ms < 1000) {
ts.tv_sec = 0;
ts.tv_nsec = ms * 1000000;
} else {
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
}
nanosleep(&ts, NULL);
}
/*
* cleanup() - Frees all the allocated memory before exiting
*/
static void cleanup(void)
{
if (can_if) {
ldx_can_stop(can_if);
ldx_can_free(can_if);
running = false;
}
}
/*
* sigaction_handler() - Handler to execute after receiving a signal
*
* @signum: Received signal.
*/
static void sigaction_handler(int signum)
{
/* 'atexit' executes the cleanup function */
exit(EXIT_FAILURE);
}
/*
* register_signals() - Registers program signals
*/
static void register_signals(void)
{
struct sigaction action;
action.sa_handler = sigaction_handler;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
sigaction(SIGHUP, &action, NULL);
sigaction(SIGINT, &action, NULL);
sigaction(SIGTERM, &action, NULL);
}
void update_msg(struct canfd_frame *frame, uint32_t id, uint8_t dlc, uint8_t flags)
{
uint8_t index;
if (flags & RANDOM_ID_MASK)
id = rand() % 2047 + 1;
if (flags & EXT_ID_MASK) {
frame->can_id = id & CAN_EFF_MASK;
frame->can_id |= CAN_EFF_FLAG;
} else {
frame->can_id = id & CAN_SFF_MASK;
}
if (flags & RTR_BIT_MASK)
frame->can_id |= CAN_RTR_FLAG;
if (flags & RANDOM_DLC_MASK)
dlc = rand() % 8 + 1;
frame->len = dlc;
/* Currently we just do incremental updates on the payload */
for (index = 0; index < dlc; index++) {
frame->data[index] = frame->data[index] + 1;
if (frame->data[index])
break;
}
}
int main(int argc, char **argv)
{
char *name = basename(argv[0]);
char *iface;
can_if_cfg_t ifcfg;
int opt;
int ret;
uint32_t ms_delay = 1;
uint32_t num_msgs = 1;
uint32_t msg_id = 0x123;
uint8_t msg_len = 8;
uint8_t flags = 0;
struct canfd_frame frame;
srand (time(NULL));
if (argc <= 3) {
usage_and_exit(name, EXIT_FAILURE);
}
ldx_can_set_defconfig(&ifcfg);
while ((opt = getopt(argc, argv, "i:b:n:t:I:l:erRp")) > 0) {
switch (opt) {
case 'i':
iface = optarg;
break;
case 'b':
ifcfg.bitrate = strtoul(optarg, NULL, 10);
break;
case 'n':
num_msgs = strtoul(optarg, NULL, 10);
break;
case 't':
ms_delay = strtoul(optarg, NULL, 10);
break;
case 'I':
msg_id = strtoul(optarg, NULL, 16);
break;
case 'l':
msg_len = strtoul(optarg, NULL, 10);
break;
case 'e':
flags |= EXT_ID_MASK;
break;
case 'r':
flags |= RANDOM_ID_MASK;
break;
case 'R':
flags |= RTR_BIT_MASK;
break;
case 'p':
flags |= RANDOM_DLC_MASK;
break;
default:
usage_and_exit(name, EXIT_FAILURE);
}
}
printf("Requesting CAN interface %s... ", iface);
can_if = ldx_can_request_by_name(iface);
if (!can_if) {
printf("ERROR\n");
return EXIT_FAILURE;
}
printf("OK\n");
/* Register signals and exit cleanup function */
atexit(cleanup);
register_signals();
printf("Initializing CAN interface... ");
ret = ldx_can_init(can_if, &ifcfg);
if (ret) {
printf("ERROR\n");
goto error;
}
printf("OK\n");
memset(&frame, 0, sizeof(frame));
while (running && num_msgs) {
int retries = TX_RETRIES;
/* If we need to create more configuration bits, we have this variable flags*/
update_msg(&frame, msg_id, msg_len, flags);
while (retries--) {
ret = ldx_can_tx_frame(can_if, &frame);
if (!ret) {
break;
} else if (ret == -CAN_ERROR_TX_RETRY_LATER) {
ms_sleep(1);
} else {
printf("Failed to send CAN frame (%d)\n", ret);
goto error;
}
}
if (!retries) {
printf("Failed to send CAN frame after %d tries\n", ret);
goto error;
}
num_msgs--;
if (ms_delay)
ms_sleep(ms_delay);
}
ms_sleep(1000);
error:
printf("\n\nCan send frame application has finished\n");
return ret;
}