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:
parent
9a3f723fe1
commit
b541f27702
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue