X-Git-Url: http://rtime.felk.cvut.cz/gitweb/sojka/can-utils.git/blobdiff_plain/afa14f102dfd8f1f17f512e2aa3c6b0e9883626d..HEAD:/cangen.c diff --git a/cangen.c b/cangen.c index 898068b..db4c803 100644 --- a/cangen.c +++ b/cangen.c @@ -1,7 +1,3 @@ -/* - * $Id$ - */ - /* * cangen.c - CAN frames generator for testing purposes * @@ -41,7 +37,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * - * Send feedback to + * Send feedback to * */ @@ -87,6 +83,9 @@ void print_usage(char *prg) "- default: %d ms)\n", DEFAULT_GAP); fprintf(stderr, " -e (generate extended frame mode " "(EFF) CAN frames)\n"); + fprintf(stderr, " -f (generate CAN FD CAN frames)\n"); + fprintf(stderr, " -R (send RTR frame)\n"); + fprintf(stderr, " -m (mix -e -f -R frames)\n"); fprintf(stderr, " -I (CAN ID" " generation mode - see below)\n"); fprintf(stderr, " -L (CAN data length code (dlc)" @@ -95,6 +94,8 @@ void print_usage(char *prg) " generation mode - see below)\n"); fprintf(stderr, " -p (poll on -ENOBUFS to write frames" " with ms)\n"); + fprintf(stderr, " -n (terminate after CAN frames " + "- default infinite)\n"); fprintf(stderr, " -i (ignore -ENOBUFS return values on" " write() syscalls)\n"); fprintf(stderr, " -x (disable local loopback of " @@ -130,34 +131,46 @@ void sigterm(int signo) int main(int argc, char **argv) { - unsigned long gap = DEFAULT_GAP; + double gap = DEFAULT_GAP; unsigned long polltimeout = 0; unsigned char ignore_enobufs = 0; unsigned char extended = 0; + unsigned char canfd = 0; + unsigned char mix = 0; unsigned char id_mode = MODE_RANDOM; unsigned char data_mode = MODE_RANDOM; unsigned char dlc_mode = MODE_RANDOM; unsigned char loopback_disable = 0; unsigned char verbose = 0; + unsigned char rtr_frame = 0; + int count = 0; + int mtu, maxdlen; uint64_t incdata = 0; + int incdlc = 0; + unsigned char fixdata[CANFD_MAX_DLEN]; int opt; int s; /* socket */ struct pollfd fds; struct sockaddr_can addr; - static struct can_frame frame; + static struct canfd_frame frame; int nbytes; int i; struct ifreq ifr; struct timespec ts; + struct timeval now; + + /* set seed value for pseudo random numbers */ + gettimeofday(&now, NULL); + srandom(now.tv_usec); signal(SIGTERM, sigterm); signal(SIGHUP, sigterm); signal(SIGINT, sigterm); - while ((opt = getopt(argc, argv, "ig:eI:L:D:xp:vh?")) != -1) { + while ((opt = getopt(argc, argv, "ig:efmI:L:D:xp:n:vRh?")) != -1) { switch (opt) { case 'i': @@ -165,13 +178,22 @@ int main(int argc, char **argv) break; case 'g': - gap = strtoul(optarg, NULL, 10); + gap = strtod(optarg, NULL); break; case 'e': extended = 1; break; + case 'f': + canfd = 1; + break; + + case 'm': + mix = 1; + canfd = 1; /* to switch the socket into CAN FD mode */ + break; + case 'I': if (optarg[0] == 'r') { id_mode = MODE_RANDOM; @@ -190,7 +212,7 @@ int main(int argc, char **argv) dlc_mode = MODE_INCREMENT; } else { dlc_mode = MODE_FIX; - frame.can_dlc = atoi(optarg)%9; + frame.len = atoi(optarg) & 0xFF; /* is cut to 8 / 64 later */ } break; @@ -201,7 +223,7 @@ int main(int argc, char **argv) data_mode = MODE_INCREMENT; } else { data_mode = MODE_FIX; - if (hexstring2candata(optarg, &frame)) { + if (hexstring2data(optarg, fixdata, CANFD_MAX_DLEN)) { printf ("wrong fix data definition\n"); return 1; } @@ -216,10 +238,22 @@ int main(int argc, char **argv) loopback_disable = 1; break; + case 'R': + rtr_frame = 1; + break; + case 'p': polltimeout = strtoul(optarg, NULL, 10); break; + case 'n': + count = atoi(optarg); + if (count < 1) { + print_usage(basename(argv[0])); + return 1; + } + break; + case '?': case 'h': default: @@ -235,29 +269,15 @@ int main(int argc, char **argv) } ts.tv_sec = gap / 1000; - ts.tv_nsec = (gap % 1000) * 1000000; - - if (id_mode == MODE_FIX) { + ts.tv_nsec = (long)(((long long)(gap * 1000000)) % 1000000000ll); - /* recognize obviously missing commandline option */ - if ((frame.can_id > 0x7FF) && !extended) { - printf("The given CAN-ID is greater than 0x7FF and " - "the '-e' option is not set.\n"); - return 1; - } - - if (extended) - frame.can_id &= CAN_EFF_MASK; - else - frame.can_id &= CAN_SFF_MASK; + /* recognize obviously missing commandline option */ + if (id_mode == MODE_FIX && frame.can_id > 0x7FF && !extended) { + printf("The given CAN-ID is greater than 0x7FF and " + "the '-e' option is not set.\n"); + return 1; } - if (extended) - frame.can_id |= CAN_EFF_FLAG; - - if ((data_mode == MODE_INCREMENT) && !frame.can_dlc) - frame.can_dlc = 1; /* min dlc value for incr. data */ - if (strlen(argv[optind]) >= IFNAMSIZ) { printf("Name of CAN device '%s' is too long!\n\n", argv[optind]); return 1; @@ -290,6 +310,34 @@ int main(int argc, char **argv) &loopback, sizeof(loopback)); } + if (canfd) { + int enable_canfd = 1; + + /* check if the frame fits into the CAN netdevice */ + if (ioctl(s, SIOCGIFMTU, &ifr) < 0) { + perror("SIOCGIFMTU"); + return 1; + } + + if (ifr.ifr_mtu != CANFD_MTU) { + printf("CAN interface ist not CAN FD capable - sorry.\n"); + return 1; + } + + /* interface is ok - try to switch the socket into CAN FD mode */ + if (setsockopt(s, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &enable_canfd, sizeof(enable_canfd))){ + printf("error when enabling CAN FD support\n"); + return 1; + } + + /* ensure discrete CAN FD length values 0..8, 12, 16, 20, 24, 32, 64 */ + frame.len = can_dlc2len(can_len2dlc(frame.len)); + } else { + /* sanitize CAN 2.0 frame length */ + if (frame.len > 8) + frame.len = 8; + } + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; @@ -302,47 +350,76 @@ int main(int argc, char **argv) while (running) { - if (id_mode == MODE_RANDOM) { - - frame.can_id = random(); + if (count && (--count == 0)) + running = 0; - if (extended) { - frame.can_id &= CAN_EFF_MASK; - frame.can_id |= CAN_EFF_FLAG; - } else - frame.can_id &= CAN_SFF_MASK; + if (canfd){ + mtu = CANFD_MTU; + maxdlen = CANFD_MAX_DLEN; + } else { + mtu = CAN_MTU; + maxdlen = CAN_MAX_DLEN; } - if (dlc_mode == MODE_RANDOM) { + if (id_mode == MODE_RANDOM) + frame.can_id = random(); - frame.can_dlc = random() & 0xF; + if (extended) { + frame.can_id &= CAN_EFF_MASK; + frame.can_id |= CAN_EFF_FLAG; + } else + frame.can_id &= CAN_SFF_MASK; + + if (rtr_frame && !canfd) + frame.can_id |= CAN_RTR_FLAG; - if (frame.can_dlc & 8) - frame.can_dlc = 8; /* for about 50% of the frames */ + if (dlc_mode == MODE_RANDOM) { - if ((data_mode == MODE_INCREMENT) && !frame.can_dlc) - frame.can_dlc = 1; /* min dlc value for incr. data */ + if (canfd) + frame.len = can_dlc2len(random() & 0xF); + else { + frame.len = random() & 0xF; + if (frame.len & 8) + frame.len = 8; /* for about 50% of the frames */ + } } + if (data_mode == MODE_INCREMENT && !frame.len) + frame.len = 1; /* min dlc value for incr. data */ + if (data_mode == MODE_RANDOM) { /* that's what the 64 bit alignment of data[] is for ... :) */ *(unsigned long*)(&frame.data[0]) = random(); *(unsigned long*)(&frame.data[4]) = random(); + + /* omit extra random number generation for CAN FD */ + if (canfd && frame.len > 8) { + memcpy(&frame.data[8], &frame.data[0], 8); + memcpy(&frame.data[16], &frame.data[0], 16); + memcpy(&frame.data[32], &frame.data[0], 32); + } } + if (data_mode == MODE_FIX) + memcpy(frame.data, fixdata, CANFD_MAX_DLEN); + + /* set unused payload data to zero like the CAN driver does it on rx */ + if (frame.len < maxdlen) + memset(&frame.data[frame.len], 0, maxdlen - frame.len); + if (verbose) { printf(" %s ", argv[optind]); if (verbose > 1) - fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0); + fprint_long_canframe(stdout, &frame, "\n", (verbose > 2)?1:0, maxdlen); else - fprint_canframe(stdout, &frame, "\n", 1); + fprint_canframe(stdout, &frame, "\n", 1, maxdlen); } resend: - nbytes = write(s, &frame, sizeof(struct can_frame)); + nbytes = write(s, &frame, mtu); if (nbytes < 0) { if (errno != ENOBUFS) { perror("write"); @@ -362,7 +439,7 @@ resend: } else enobufs_count++; - } else if (nbytes < sizeof(struct can_frame)) { + } else if (nbytes < mtu) { fprintf(stderr, "write: incomplete CAN frame\n"); return 1; } @@ -371,24 +448,20 @@ resend: if (nanosleep(&ts, NULL)) return 1; - if (id_mode == MODE_INCREMENT) { - + if (id_mode == MODE_INCREMENT) frame.can_id++; - if (extended) { - frame.can_id &= CAN_EFF_MASK; - frame.can_id |= CAN_EFF_FLAG; - } else - frame.can_id &= CAN_SFF_MASK; - } - if (dlc_mode == MODE_INCREMENT) { - frame.can_dlc++; - frame.can_dlc %= 9; + incdlc++; - if ((data_mode == MODE_INCREMENT) && !frame.can_dlc) - frame.can_dlc = 1; /* min dlc value for incr. data */ + if (canfd && !mix) { + incdlc &= 0xF; + frame.len = can_dlc2len(incdlc); + } else { + incdlc %= 9; + frame.len = incdlc; + } } if (data_mode == MODE_INCREMENT) { @@ -398,6 +471,13 @@ resend: for (i=0; i<8 ;i++) frame.data[i] = (incdata >> i*8) & 0xFFULL; } + + if (mix) { + i = random(); + extended = i&1; + canfd = i&2; + rtr_frame = ((i&12) == 12); /* reduce RTR frames to 1/4 */ + } } if (enobufs_count)