From: Michal Sojka Date: Wed, 29 Oct 2014 14:06:04 +0000 (+0100) Subject: Other candump implementations X-Git-Url: http://rtime.felk.cvut.cz/gitweb/sojka/can-syscalls-examples.git/commitdiff_plain/4b9866da12e09d55dddcfc52365482981bfe350a Other candump implementations --- 4b9866da12e09d55dddcfc52365482981bfe350a diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..03908db --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +CFLAGS = -g -O2 -Wall + +SRCS = $(wildcard *.c) +BINS = $(SRCS:%.c=%) + +all: $(BINS) + +%: %.c common.h + $(CC) $(CFLAGS) -o $@ $< diff --git a/candump-mmap.c b/candump-mmap.c new file mode 100644 index 0000000..1032473 --- /dev/null +++ b/candump-mmap.c @@ -0,0 +1,100 @@ +/**************************************************************/ +/* CAN system calls example */ +/* Author: Michal Sojka, Czech Technical University in Prague */ +/* License: Public domain */ +/**************************************************************/ + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* the L2 protocols */ +#include +#include +#include +#include + +#define FRAME_SIZE 128 +#define BLOCK_SIZE 4096 +#define BLOCK_NR 2 +#define FRAME_NR (BLOCK_NR*(BLOCK_SIZE/FRAME_SIZE)) + +void *rx_ring_buffer; +int hdrlen; +int current; + +int init_mmap_socket(const char *dev) +{ + int sock; + struct sockaddr_ll addr; + struct ifreq ifr; + + sock = CHECK(socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))); + + int val = TPACKET_V2; + CHECK(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &val, sizeof(val))); + socklen_t len = sizeof(hdrlen); + CHECK(getsockopt(sock, SOL_PACKET, PACKET_HDRLEN, &hdrlen, &len)); + + strncpy (ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + CHECK(ioctl(sock, SIOCGIFINDEX, &ifr)); + + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_ALL); + addr.sll_ifindex = ifr.ifr_ifindex; + + CHECK(bind(sock, (struct sockaddr *)&addr, sizeof(struct sockaddr_ll))); + + struct tpacket_req req = { + .tp_block_size = BLOCK_SIZE, + .tp_frame_size = FRAME_SIZE, + .tp_block_nr = BLOCK_NR, + .tp_frame_nr = FRAME_NR, + }; + CHECK(setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (char *)&req, sizeof(req))); + + rx_ring_buffer = (char*)CHECKPTR(mmap(0, BLOCK_SIZE*BLOCK_NR, PROT_READ|PROT_WRITE, MAP_SHARED, sock, 0)); + + current = 0; + return sock; +} + +void can_rx_mmap(int sock) +{ + volatile struct tpacket2_hdr *hdr = rx_ring_buffer + current*FRAME_SIZE; + + while (hdr->tp_status == TP_STATUS_KERNEL) { + struct pollfd pfd = {.fd = sock, .revents = 0, + .events = POLLIN|POLLRDNORM|POLLERR }; + /* Wait for a message to arrive. If the task wake-up + * overhead is too high, poll() can be commented out + * and the application will busy-wait here. */ + CHECK(poll(&pfd, 1, -1)); + } + + struct can_frame *cf = (void*)hdr + hdr->tp_mac; + printf("Frame #%d received\n", current); + print_can_frame(cf); + hdr->tp_status = 0; /* Mark the frame as processed */ + + current = (current + 1) % FRAME_NR; +} + +int main(int argc, char *argv[]) +{ + const char *dev; + int sock; + + dev = candump_parse_args(argc, argv); + + sock = init_mmap_socket(dev); + + while (1) + can_rx_mmap(sock); +} diff --git a/candump-read.c b/candump-read.c new file mode 100644 index 0000000..173fa3f --- /dev/null +++ b/candump-read.c @@ -0,0 +1,63 @@ +/**************************************************************/ +/* CAN system calls example */ +/* Author: Michal Sojka, Czech Technical University in Prague */ +/* License: Public domain */ +/**************************************************************/ + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include + +int init_read_socket(const char *dev) +{ + int sock; + struct sockaddr_can addr; + struct ifreq ifr; + + sock = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW)); + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + if (-1 == ioctl(sock, SIOCGIFINDEX, &ifr)) { + perror(dev); + exit(1); + } + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + CHECK(bind(sock, (struct sockaddr *)&addr, sizeof(addr))); + + return sock; +} + +void can_read(int sock) +{ + struct can_frame cf; + int ret = read(sock, &cf, sizeof(cf)); + + if (ret != sizeof(cf)) { + perror("read"); + exit(1); + } + + print_can_frame(&cf); +} + +int main(int argc, char *argv[]) +{ + const char *dev; + int sock; + + dev = candump_parse_args(argc, argv); + + sock = init_read_socket(dev); + + while (1) + can_read(sock); +} diff --git a/candump-recvmmsg.c b/candump-recvmmsg.c new file mode 100644 index 0000000..2b44993 --- /dev/null +++ b/candump-recvmmsg.c @@ -0,0 +1,79 @@ +/**************************************************************/ +/* CAN system calls example */ +/* Author: Michal Sojka, Czech Technical University in Prague */ +/* License: Public domain */ +/**************************************************************/ + +#define _GNU_SOURCE + +#include "common.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MMSG_MAX 64 + +struct mmsghdr msgs[MMSG_MAX]; +struct iovec iovecs[MMSG_MAX]; +char bufs[MMSG_MAX][sizeof(struct can_frame)]; + +int init_recvmmsg_socket(const char *dev) +{ + int sock; + struct sockaddr_can addr; + struct ifreq ifr; + int i; + + sock = CHECK(socket(PF_CAN, SOCK_RAW, CAN_RAW)); + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); + if (-1 == ioctl(sock, SIOCGIFINDEX, &ifr)) { + perror(dev); + exit(1); + } + + addr.can_family = AF_CAN; + addr.can_ifindex = ifr.ifr_ifindex; + + CHECK(bind(sock, (struct sockaddr *)&addr, sizeof(addr))); + + memset(msgs, 0, sizeof(msgs)); + memset(iovecs, 0, sizeof(iovecs)); + for (i = 0; i < MMSG_MAX; i++) { + iovecs[i].iov_base = bufs[i]; + iovecs[i].iov_len = sizeof(struct can_frame); + msgs[i].msg_hdr.msg_iov = &iovecs[i]; + msgs[i].msg_hdr.msg_iovlen = 1; + } + + return sock; +} + +void can_recvmmsg(int sock) +{ + int i; + int received = CHECK(recvmmsg(sock, msgs, MMSG_MAX, MSG_WAITFORONE, NULL)); + + printf("Received %d CAN frames in one system call\n", received); + for (i = 0; i < received; i++) + print_can_frame((struct can_frame*)bufs[i]); +} + +int main(int argc, char *argv[]) +{ + const char *dev; + int sock; + + dev = candump_parse_args(argc, argv); + + sock = init_recvmmsg_socket(dev); + + while (1) + can_recvmmsg(sock); +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..8d7f3ab --- /dev/null +++ b/common.h @@ -0,0 +1,46 @@ +/**************************************************************/ +/* CAN system calls example */ +/* Author: Michal Sojka, Czech Technical University in Prague */ +/* License: Public domain */ +/**************************************************************/ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include +#include + +#define STRINGIFY(val) #val +#define TOSTRING(val) STRINGIFY(val) + +/** + * Evaluate expression cmd and if its value is -1, print an error + * message with perror(). + * + * @return Result of cmd evaluation + */ +#define CHECK(cmd) ({ int ret = (cmd); if (ret == -1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ret; }) +#define CHECKPTR(cmd) ({ void *ptr = (cmd); if (ptr == (void*)-1) { perror(#cmd " line " TOSTRING(__LINE__)); exit(1); }; ptr; }) + +char *candump_parse_args(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + exit(1); + } + return argv[1]; +} + +void print_can_frame(const struct can_frame *cf) +{ + int i; + + printf("%#010x [%d]", cf->can_id, cf->can_dlc); + for (i = 0; i < cf->can_dlc; i++) + printf(" %02x", cf->data[i]); + printf("\n"); +} + + +#endif