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

328 lines
7.0 KiB
C

/*
* 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"
"-s <sample-point> CAN bitrate sample point\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"
"-o Enable CAN FD support\n"
"--- CAN FD options ---\n"
" -d <dbitrate> Maximum data bitrate for CAN FD (Hz)\n"
" -p <dsample-point> CAN FD data bitate sample point\n"
"---\n"
"-r Generate a random ID (will ignore the -I parameter)\n"
"-c 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"
"%s -i can1 -b 100000 -d 100000 -n 10 -o\n"
"\n", name, 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_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 = NULL;
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;
float sp = 0.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:a:d:s:t:oerRc")) > 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 'n':
num_msgs = strtoul(optarg, NULL, 10);
break;
case 't':
ms_delay = 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 '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 'o':
ifcfg.canfd_enabled = true;
break;
case 'r':
flags |= RANDOM_ID_MASK;
break;
case 'R':
flags |= RTR_BIT_MASK;
break;
case 'c':
flags |= RANDOM_DLC_MASK;
break;
default:
usage_and_exit(name, EXIT_FAILURE);
}
}
if (!iface) {
fprintf(stderr, "Error: CAN interface not specified\n");
return 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", TX_RETRIES);
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;
}