123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /*
- * canfdtest.c - Full-duplex test program (DUT and host part)
- *
- * (C) 2009 by Vladislav Gribov, IXXAT Automation GmbH, <gribov@ixxat.de>
- * (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * Send feedback to <linux-can@vger.kernel.org>
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <signal.h>
- #include <libgen.h>
- #include <getopt.h>
- #include <time.h>
- #include <sched.h>
- #include <limits.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <net/if.h>
- #include <linux/can.h>
- #include <linux/can/raw.h>
- #define CAN_MSG_ID 0x77
- #define CAN_MSG_LEN 8
- #define CAN_MSG_COUNT 50
- #define CAN_MSG_WAIT 27
- static int running = 1;
- static int verbose;
- static int sockfd;
- static int test_loops;
- static void print_usage(char *prg)
- {
- fprintf(stderr,
- "Usage: %s [options] <can-interface>\n"
- "\n"
- "Options: -v (low verbosity)\n"
- " -vv (high verbosity)\n"
- " -g (generate messages)\n"
- " -l COUNT (test loop count)\n"
- "\n"
- "With the option '-g' CAN messages are generated and checked\n"
- "on <can-interface>, otherwise all messages received on the\n"
- "<can-interface> are sent back incrementing the CAN id and\n"
- "all data bytes. The program can be aborted with ^C.\n"
- "\n"
- "Example:\n"
- "\ton DUT : %s -v can0\n"
- "\ton Host: %s -g -v can2\n",
- prg, prg, prg);
- exit(1);
- }
- static void print_frame(struct can_frame *frame)
- {
- int i;
- printf("%04x: ", frame->can_id);
- if (frame->can_id & CAN_RTR_FLAG) {
- printf("remote request");
- } else {
- printf("[%d]", frame->can_dlc);
- for (i = 0; i < frame->can_dlc; i++)
- printf(" %02x", frame->data[i]);
- }
- printf("\n");
- }
- static void print_compare(struct can_frame *exp, struct can_frame *rec)
- {
- printf("expected: ");
- print_frame(exp);
- printf("received: ");
- print_frame(rec);
- }
- static void compare_frame(struct can_frame *exp, struct can_frame *rec)
- {
- int i;
- if (rec->can_id != exp->can_id) {
- printf("Message ID mismatch!\n");
- print_compare(exp, rec);
- running = 0;
- } else if (rec->can_dlc != exp->can_dlc) {
- printf("Message length mismatch!\n");
- print_compare(exp, rec);
- running = 0;
- } else {
- for (i = 0; i < rec->can_dlc; i++) {
- if (rec->data[i] != exp->data[i]) {
- printf("Databyte %x mismatch !\n", i);
- print_compare(exp,
- rec);
- running = 0;
- }
- }
- }
- }
- static void millisleep(int msecs)
- {
- struct timespec rqtp, rmtp;
- int err;
- /* sleep in ms */
- rqtp.tv_sec = msecs / 1000;
- rqtp.tv_nsec = msecs % 1000 * 1000000;
- do {
- err = clock_nanosleep(CLOCK_MONOTONIC, 0, &rqtp, &rmtp);
- if (err != 0 && err != EINTR) {
- printf("t\n");
- break;
- }
- rqtp = rmtp;
- } while (err != 0);
- }
- static void echo_progress(unsigned char data)
- {
- if (data == 0xff) {
- printf(".");
- fflush(stdout);
- }
- }
- static void signal_handler(int signo)
- {
- close(sockfd);
- running = 0;
- }
- static int recv_frame(struct can_frame *frame)
- {
- int ret;
- ret = recv(sockfd, frame, sizeof(*frame), 0);
- if (ret != sizeof(*frame)) {
- if (ret < 0)
- perror("recv failed");
- else
- fprintf(stderr, "recv returned %d", ret);
- return -1;
- }
- return 0;
- }
- static int send_frame(struct can_frame *frame)
- {
- int ret;
- while ((ret = send(sockfd, frame, sizeof(*frame), 0))
- != sizeof(*frame)) {
- if (ret < 0) {
- if (errno != ENOBUFS) {
- perror("send failed");
- return -1;
- } else {
- if (verbose) {
- printf("N");
- fflush(stdout);
- }
- }
- } else {
- fprintf(stderr, "send returned %d", ret);
- return -1;
- }
- }
- return 0;
- }
- static int can_echo_dut(void)
- {
- unsigned int frame_count = 0;
- struct can_frame frame;
- int i;
- while (running) {
- if (recv_frame(&frame))
- return -1;
- frame_count++;
- if (verbose == 1) {
- echo_progress(frame.data[0]);
- } else if (verbose > 1) {
- printf("%04x: ", frame.can_id);
- if (frame.can_id & CAN_RTR_FLAG) {
- printf("remote request");
- } else {
- printf("[%d]", frame.can_dlc);
- for (i = 0; i < frame.can_dlc; i++)
- printf(" %02x", frame.data[i]);
- }
- printf("\n");
- }
- frame.can_id++;
- for (i = 0; i < frame.can_dlc; i++)
- frame.data[i]++;
- if (send_frame(&frame))
- return -1;
- /*
- * to force a interlacing of the frames send by DUT and PC
- * test tool a waiting time is injected
- */
- if (frame_count == CAN_MSG_WAIT) {
- frame_count = 0;
- millisleep(3);
- }
- }
- return 0;
- }
- static int can_echo_gen(void)
- {
- struct can_frame tx_frames[CAN_MSG_COUNT];
- struct can_frame rx_frame;
- unsigned char counter = 0;
- int send_pos = 0, recv_pos = 0, unprocessed = 0, loops = 0;
- int i;
- while (running) {
- if (unprocessed < CAN_MSG_COUNT) {
- /* still send messages */
- tx_frames[send_pos].can_dlc = CAN_MSG_LEN;
- tx_frames[send_pos].can_id = CAN_MSG_ID;
- for (i = 0; i < CAN_MSG_LEN; i++)
- tx_frames[send_pos].data[i] = counter + i;
- if (send_frame(&tx_frames[send_pos]))
- return -1;
- /* increment to be equal to expected */
- tx_frames[send_pos].can_id++;
- for (i = 0; i < CAN_MSG_LEN; i++)
- tx_frames[send_pos].data[i]++;
- send_pos++;
- if (send_pos == CAN_MSG_COUNT)
- send_pos = 0;
- unprocessed++;
- if (verbose == 1)
- echo_progress(counter);
- counter++;
- if ((counter % 33) == 0)
- millisleep(3);
- else
- millisleep(1);
- } else {
- if (recv_frame(&rx_frame))
- return -1;
- if (verbose > 1)
- print_frame(&rx_frame);
- /* compare with expected */
- compare_frame(&tx_frames[recv_pos], &rx_frame);
- loops++;
- if (test_loops && loops >= test_loops)
- break;
- recv_pos++;
- if (recv_pos == CAN_MSG_COUNT)
- recv_pos = 0;
- unprocessed--;
- }
- }
- printf("\nTest messages sent and received: %d\n", loops);
- return 0;
- }
- int main(int argc, char *argv[])
- {
- struct sockaddr_can addr;
- char *intf_name;
- int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
- int echo_gen = 0;
- int opt, err;
- signal(SIGTERM, signal_handler);
- signal(SIGHUP, signal_handler);
- signal(SIGINT, signal_handler);
- while ((opt = getopt(argc, argv, "gl:v")) != -1) {
- switch (opt) {
- case 'v':
- verbose++;
- break;
- case 'l':
- test_loops = atoi(optarg);;
- break;
- case 'g':
- echo_gen = 1;
- break;
- default:
- print_usage(basename(argv[0]));
- break;
- }
- }
- if ((argc - optind) != 1)
- print_usage(basename(argv[0]));
- intf_name = argv[optind];
- printf("interface = %s, family = %d, type = %d, proto = %d\n",
- intf_name, family, type, proto);
- if ((sockfd = socket(family, type, proto)) < 0) {
- perror("socket");
- return 1;
- }
- addr.can_family = family;
- addr.can_ifindex = if_nametoindex(intf_name);
- if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- perror("bind");
- close(sockfd);
- return 1;
- }
- if (echo_gen)
- err = can_echo_gen();
- else
- err = can_echo_dut();
- if (verbose)
- printf("Exiting...\n");
- close(sockfd);
- return err;
- }
|