123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- /*
- * Copyright (c) 2016-2018 UAVCAN Team
- *
- * Distributed under the MIT License, available in the file LICENSE.
- *
- */
- // This is needed to enable necessary declarations in sys/
- #ifndef _GNU_SOURCE
- # define _GNU_SOURCE
- #endif
- #include <net/if.h>
- #include "socketcan.h"
- #include <poll.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <linux/can.h>
- #include <errno.h>
- #include <stdlib.h>
- /// Returns the current errno as negated int16_t
- static int16_t getErrorCode()
- {
- const int out = -abs(errno);
- if (out < 0)
- {
- if (out >= INT16_MIN)
- {
- return (int16_t)out;
- }
- else
- {
- return INT16_MIN;
- }
- }
- else
- {
- assert(false); // Requested an error when errno is zero?
- return INT16_MIN;
- }
- }
- int16_t socketcanInit(SocketCANInstance* out_ins, const char* can_iface_name)
- {
- const size_t iface_name_size = strlen(can_iface_name) + 1;
- if (iface_name_size > IFNAMSIZ)
- {
- goto fail0;
- }
- const int fd = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW); // NOLINT
- if (fd < 0)
- {
- goto fail0;
- }
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
- memcpy(ifr.ifr_name, can_iface_name, iface_name_size);
- const int ioctl_result = ioctl(fd, SIOCGIFINDEX, &ifr);
- if (ioctl_result < 0)
- {
- goto fail1;
- }
- struct sockaddr_can addr;
- memset(&addr, 0, sizeof(addr));
- addr.can_family = AF_CAN;
- addr.can_ifindex = ifr.ifr_ifindex;
- const int bind_result = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
- if (bind_result < 0)
- {
- goto fail1;
- }
- out_ins->fd = fd;
- return 0;
- fail1:
- (void)close(fd);
- fail0:
- return getErrorCode();
- }
- int16_t socketcanClose(SocketCANInstance* ins)
- {
- const int close_result = close(ins->fd);
- ins->fd = -1;
- return (int16_t)((close_result == 0) ? 0 : getErrorCode());
- }
- int16_t socketcanTransmit(SocketCANInstance* ins, const CanardCANFrame* frame, int32_t timeout_msec)
- {
- struct pollfd fds;
- memset(&fds, 0, sizeof(fds));
- fds.fd = ins->fd;
- fds.events |= POLLOUT;
- const int poll_result = poll(&fds, 1, timeout_msec);
- if (poll_result < 0)
- {
- return getErrorCode();
- }
- if (poll_result == 0)
- {
- return 0;
- }
- if (((uint32_t)fds.revents & (uint32_t)POLLOUT) == 0)
- {
- return -EIO;
- }
- struct can_frame transmit_frame;
- memset(&transmit_frame, 0, sizeof(transmit_frame));
- transmit_frame.can_id = frame->id; // TODO: Map flags properly
- transmit_frame.can_dlc = frame->data_len;
- memcpy(transmit_frame.data, frame->data, frame->data_len);
- const ssize_t nbytes = write(ins->fd, &transmit_frame, sizeof(transmit_frame));
- if (nbytes < 0)
- {
- return getErrorCode();
- }
- if ((size_t)nbytes != sizeof(transmit_frame))
- {
- return -EIO;
- }
- return 1;
- }
- int16_t socketcanReceive(SocketCANInstance* ins, CanardCANFrame* out_frame, int32_t timeout_msec)
- {
- struct pollfd fds;
- memset(&fds, 0, sizeof(fds));
- fds.fd = ins->fd;
- fds.events |= POLLIN;
- const int poll_result = poll(&fds, 1, timeout_msec);
- if (poll_result < 0)
- {
- return getErrorCode();
- }
- if (poll_result == 0)
- {
- return 0;
- }
- if (((uint32_t)fds.revents & (uint32_t)POLLIN) == 0)
- {
- return -EIO;
- }
- struct can_frame receive_frame;
- const ssize_t nbytes = read(ins->fd, &receive_frame, sizeof(receive_frame));
- if (nbytes < 0)
- {
- return getErrorCode();
- }
- if ((size_t)nbytes != sizeof(receive_frame))
- {
- return -EIO;
- }
- if (receive_frame.can_dlc > CAN_MAX_DLEN) // Appeasing Coverity Scan
- {
- return -EIO;
- }
- out_frame->id = receive_frame.can_id; // TODO: Map flags properly
- out_frame->data_len = receive_frame.can_dlc;
- memcpy(out_frame->data, &receive_frame.data, receive_frame.can_dlc);
- return 1;
- }
- int socketcanGetSocketFileDescriptor(const SocketCANInstance* ins)
- {
- return ins->fd;
- }
|