纯C++写的、Linux下 的CAN报文发送、接收类

发布时间:2023年12月20日

commonToolkits_global.h?

#ifndef COMMONTOOLKITS_GLOBAL_H
#define COMMONTOOLKITS_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(COMMONTOOLKITS_LIBRARY)
#  define COMMONTOOLKITS_EXPORT Q_DECL_EXPORT
#else
#  define COMMONTOOLKITS_EXPORT Q_DECL_IMPORT
#endif

#endif // COMMONTOOLKITS_GLOBAL_H

cansocketlinux.h

#ifndef _CANSOCKET_H
#define _CANSOCKET_H

// The order of the following includes is mandatory, because some
// distributions use sa_family_t in can.h without including socket.h
#include <sys/socket.h>
#include <sys/uio.h>
#include <linux/can.h>
#include <sys/time.h>
#include "commonToolkits_global.h"
#include <string>
#include <vector>


struct CanFrame
{
    uint32_t frameId;      // 帧id
    uint8_t dataLen{0};    // 帧数据包长度
    uint8_t data[8]{0};    // 存放can帧的数据包缓冲区
};


class COMMONTOOLKITS_EXPORT CanSocket
{
public:
    CanSocket(const std::string &name, bool bInit = false);

    ~CanSocket();

   void initCan();  // 初始化can,主要是设置波特率
 
    bool open();    // 打开can
    void close();   // 关闭can

    bool writeFrame(const CanFrame& frame); // 发送can数据到can总线

    std::vector<CanFrame> readSocket();     // 获取CAN总线的数据包
public:
    bool getState() {
        if(canSocket == -1) {
            return false;
        }
        return true;
    }

private:
    bool connectSocket();

    sockaddr_can m_address;
    char m_ctrlmsg[CMSG_SPACE(sizeof(timeval)) + CMSG_SPACE(sizeof(__u32))];

    int canSocket = -1;
    std::string canSocketName;
    bool canFdOptionEnabled = false;
    std::string errMsg;
};

cansocketlinux.cpp?


#include "cansocketlinux.h"
#include "memory.h"
#include "stddef.h"
#include <string>
#include "qglobal.h"

#include <linux/can/raw.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include<linux/sockios.h>

const std::string CAN0_OPEN = "ifconfig can0 up";
const std::string CAN0_CLOSE = "ifconfig can0 down";
const std::string CAN0_CONFIG = "ip link set can0 type can bitrate 250000 triple-sampling on";

const std::string CAN1_OPEN = "ifconfig can1 up";
const std::string CAN1_CLOSE = "ifconfig can1 down";
const std::string CAN1_CONFIG = "ip link set can1 type can bitrate 250000 triple-sampling on";

void CanSocket::initCan()
{
      system(CAN0_CONFIG.data());
      system(CAN0_OPEN.data());
   
      system(CAN1_CONFIG.data());
      system(CAN1_OPEN.data());
   
}

CanSocket::CanSocket(const std::string &name, bool bInit = false):
    canSocketName(name)
{
    if(bInit)
    {
        initCan();
    }
}

CanSocket::~CanSocket()
{
    close();
}

bool CanSocket::open()
{
    if (canSocket == -1) {
        if (!connectSocket()) {
            close(); // sets UnconnectedState
            return false;
        }
    }
    return true;
}

void CanSocket::close()
{
    ::close(canSocket);
    canSocket = -1;
}

bool CanSocket::writeFrame(const CanFrame &frame)
{
    if (canSocket== -1)
        return false;

    if(frame.dataLen > 8) {
        return false;
    }
    canid_t canId = frame.frameId;
    canId |= CAN_EFF_FLAG;

    int64_t bytesWritten = 0;

    can_frame sendframe;
    ::memset(&sendframe, 0, sizeof(sendframe));
    sendframe.can_dlc = frame.dataLen;
    sendframe.can_id = canId;
    ::memcpy(sendframe.data, frame.data, sendframe.can_dlc);

    bytesWritten = ::write(canSocket, &sendframe, sizeof(sendframe));


    if (bytesWritten < 0) {
        return false;
    }

    return true;
}

std::vector<CanFrame> CanSocket::readSocket()
{
    std::vector<CanFrame> newFrames;

    for (;;) {
        struct can_frame frame;

        const int bytesReceived = ::read(canSocket, &frame, sizeof(frame));

        if (bytesReceived != sizeof(frame)) {
            break;
        }

        struct timeval timeStamp;
        if (ioctl(canSocket, SIOCGSTAMP, &timeStamp) < 0) {
            ::memset(&timeStamp, 0, sizeof(timeStamp));
        }

        CanFrame bufferedFrame;
        bufferedFrame.frameId = (frame.can_id & CAN_EFF_MASK);
        bufferedFrame.dataLen = frame.can_dlc;
        if(frame.can_dlc > 8) {
            continue;
        }
        memcpy(bufferedFrame.data, frame.data, frame.can_dlc);

        newFrames.push_back(std::move(bufferedFrame));
    }
    return newFrames;
}

bool CanSocket::connectSocket()
{
    struct ifreq interface;

    if ((canSocket = socket(PF_CAN, SOCK_RAW | SOCK_NONBLOCK, CAN_RAW)) < 0) {
        //errMsg = errno;
        return false;
    }

    int loopback = 0;
    setsockopt(canSocket, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
    strcpy(interface.ifr_name, canSocketName.data());
    if (ioctl(canSocket, SIOCGIFINDEX, &interface) < 0) {
        //errMsg = errno;
        return false;
    }

    m_address.can_addr.tp.rx_id = 0;
    m_address.can_addr.tp.tx_id = 0;
    m_address.can_family  = AF_CAN;
    m_address.can_ifindex = interface.ifr_ifindex;

    if (bind(canSocket, (struct sockaddr *)(&m_address), sizeof(m_address))  < 0) {
        //qDebug("%s", qt_error_string(errno).toLatin1().data());
        //errMsg = std::string(qt_error_string(errno).toLocal8Bit().constData());
        return false;
    }

    return true;
}

说明:

  • 仅仅用到了Qtcore,如果你不想依赖Qt,可以把代码中qt的全部去掉,其实qt的东西也不多。
  • initCan()用于初始化CAN的波特率。一般波特率设置在开机自启动的脚本中;也可以通过构造函数的第二个设置为true,让程序来设置CAN波特率。
  • initCan只初始化了can0、can1两路,且波特率设置为250k,可以跟你自身需求,更改这些属性。
  • 主要接口功能见头文件注释。
文章来源:https://blog.csdn.net/danshiming/article/details/135075832
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。