]> rtime.felk.cvut.cz Git - sojka/can-syscalls-examples.git/commitdiff
Other candump implementations
authorMichal Sojka <sojkam1@fel.cvut.cz>
Wed, 29 Oct 2014 14:06:04 +0000 (15:06 +0100)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Wed, 29 Oct 2014 14:06:04 +0000 (15:06 +0100)
Makefile [new file with mode: 0644]
candump-mmap.c [new file with mode: 0644]
candump-read.c [new file with mode: 0644]
candump-recvmmsg.c [new file with mode: 0644]
common.h [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
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 (file)
index 0000000..1032473
--- /dev/null
@@ -0,0 +1,100 @@
+/**************************************************************/
+/* CAN system calls example                                  */
+/* Author: Michal Sojka, Czech Technical University in Prague */
+/* License: Public domain                                    */
+/**************************************************************/
+
+#include "common.h"
+
+#include <linux/can.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <linux/if_packet.h>
+#include <net/ethernet.h> /* the L2 protocols */
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <sys/mman.h>
+#include <poll.h>
+
+#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 (file)
index 0000000..173fa3f
--- /dev/null
@@ -0,0 +1,63 @@
+/**************************************************************/
+/* CAN system calls example                                  */
+/* Author: Michal Sojka, Czech Technical University in Prague */
+/* License: Public domain                                    */
+/**************************************************************/
+
+#include "common.h"
+
+#include <linux/can.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+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 (file)
index 0000000..2b44993
--- /dev/null
@@ -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 <linux/can.h>
+#include <net/if.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#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 (file)
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 <linux/can.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#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 <CAN interface>\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