dey-examples/apix-can-examples/can-recv-example.c

331 lines
7.1 KiB
C

/*
* Copyright 2018-2024, 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"
"-s <sample-point> Bitrate Sample Point\n"
"-f <filters> Comma-separated filter list in the format\n"
" id:mask (id and mask values in hex)\n"
"-o Enable CAN FD support\n"
"--- CAN FD options ---\n"
" -d <dbitrate> Maximum data bitrate for CAN FD (Hz)\n"
" -a <dsample-point> CAN FD data bitate sample point\n"
"---\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"
"%s -i can1 -b 100000 -d 100000 -o -p\n"
"\n", name, 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_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;
int i;
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: "
,tv->tv_sec, tv->tv_usec, ldx_can_is_extid_frame(frame) ?
"Extended ID" : "Standard ID", ldx_can_get_id(frame), frame->len);
for (i=0;i<frame->len;i++) {
printf("%02x", frame->data[i]);
if (i < (frame->len -1))
printf(":");
}
printf("\n\n");
}
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;
float sp = 0.0;
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:d:s:a:opc")) > 0) {
switch (opt) {
case 'i':
iface = optarg;
break;
case 'b':
ifcfg.bitrate = strtoul(optarg, NULL, 10);
break;
case 'd':
ifcfg.dbitrate = strtoul(optarg, NULL, 10);
break;
case 's':
sp = strtof(optarg, NULL);
ifcfg.bit_timing.sample_point = (__u32)(sp * 1000);
break;
case 'a':
sp = strtof(optarg, NULL);
ifcfg.dbit_timing.sample_point = (__u32)(sp * 1000);
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 'o':
ifcfg.canfd_enabled = true;
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;
}