sweeper_200/src/base/mc/src/can_driver.cpp

176 lines
3.9 KiB
C++

#include "mc/can_driver.h"
#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <poll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <thread>
CANDriver::CANDriver() = default;
CANDriver::~CANDriver() { close(); }
bool CANDriver::open(const std::string& interface)
{
if (running) return false;
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sockfd < 0)
{
perror("socket");
return false;
}
struct ifreq ifr;
std::strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0)
{
perror("ioctl");
::close(sockfd);
return false;
}
struct sockaddr_can addr{};
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sockfd, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0)
{
perror("bind");
::close(sockfd);
return false;
}
// 设置为非阻塞
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
running = true;
receiveThread = std::thread(&CANDriver::receiveThreadFunc, this);
return true;
}
void CANDriver::close()
{
if (!running) return;
running = false;
if (receiveThread.joinable()) receiveThread.join();
if (sockfd >= 0)
{
::close(sockfd);
sockfd = -1;
}
}
bool CANDriver::sendFrame(const CANFrame& frame)
{
if (!running) return false;
struct can_frame raw_frame{};
raw_frame.can_id = frame.id;
if (frame.ext) raw_frame.can_id |= CAN_EFF_FLAG;
if (frame.rtr) raw_frame.can_id |= CAN_RTR_FLAG;
raw_frame.can_dlc = frame.dlc;
std::memcpy(raw_frame.data, frame.data, frame.dlc);
if (write(sockfd, &raw_frame, sizeof(raw_frame)) != sizeof(raw_frame))
{
perror("write");
return false;
}
return true;
}
void CANDriver::setReceiveCallback(ReceiveCallback callback, void* userData)
{
this->callback = callback;
this->userData = userData;
}
bool CANDriver::setFilter(const std::vector<can_filter>& filters)
{
if (!running) return false;
filters_ = filters;
return applyFilters();
}
bool CANDriver::addFilter(const can_filter& filter)
{
filters_.push_back(filter);
return applyFilters();
}
bool CANDriver::addFilters(const std::vector<can_filter>& filters)
{
filters_.insert(filters_.end(), filters.begin(), filters.end());
return applyFilters();
}
bool CANDriver::applyFilters()
{
if (!running) return false;
if (filters_.empty())
{
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, nullptr, 0);
return true;
}
if (setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, filters_.data(), filters_.size() * sizeof(can_filter)) < 0)
{
perror("setsockopt");
return false;
}
return true;
}
void CANDriver::receiveThreadFunc()
{
struct can_frame raw_frame;
struct pollfd fds;
fds.fd = sockfd;
fds.events = POLLIN;
while (running)
{
int ret = poll(&fds, 1, 100); // 等待最多100ms
if (ret < 0)
{
perror("poll");
continue;
}
else if (ret == 0)
{
// 超时无数据,可继续
continue;
}
ssize_t nbytes = read(sockfd, &raw_frame, sizeof(raw_frame));
if (nbytes == sizeof(raw_frame) && callback)
{
CANFrame frame;
frame.id = raw_frame.can_id & CAN_EFF_MASK;
frame.ext = !!(raw_frame.can_id & CAN_EFF_FLAG);
frame.rtr = !!(raw_frame.can_id & CAN_RTR_FLAG);
frame.dlc = raw_frame.can_dlc;
memcpy(frame.data, raw_frame.data, raw_frame.can_dlc);
// 调用回调函数,处理接收到的帧
callback(frame, userData);
}
}
}