附上Linux下周立功can配置文档:
1.cpp代码
Can_Control::Can_Control()
{
}
int Can_Control::can_send()
{
int stSocket_LO, stSend_LO;
struct sockaddr_can addr; //can总线的地址 同socket编程里面的 socketaddr结构体 用来设置can外设的信息
struct ifreq ifr;//接口请求结构体
struct can_frame frame[2] = {{0}}; //要发送的buffer
/* 创建socket套接字
PF_CAN 为域位 同网络编程中的AF_INET 即ipv4协议
SOCK_RAW使用的协议类型 SOCK_RAW表示原始套接字 报文头由自己创建
CAN_RAW为使用的具体协议 为can总线协议
*/
stSocket_LO = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字
strcpy(ifr.ifr_name, "can0" );
ioctl(stSocket_LO, SIOCGIFINDEX, &ifr); //指定 can0 设备
addr.can_family = AF_CAN; //协议类型
addr.can_ifindex = ifr.ifr_ifindex; //can总线外设的具体索引 类似 ip地址
bind(stSocket_LO, (struct sockaddr *)&addr, sizeof(addr));//将套接字和canbus外设进行绑定,即套接字与 can0 绑定
//禁用过滤规则,本进程不接收报文,只负责发送
setsockopt(stSocket_LO, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
//生成两个报文
frame[0].can_id = 0x11;
frame[0]. can_dlc = 1;
frame[0].data[0] = '1';
frame[1].can_id = 0x22;
frame[1]. can_dlc = 1;
frame[1].data[0] = '2';
//循环发送两个报文
while(1)
{
stSend_LO = write(stSocket_LO, &frame[0], sizeof(frame[0])); //发送 frame[0]
if(stSend_LO != sizeof(frame[0]))
{
printf("Send Error frame[0]\n!");
break; //发送错误,退出
}
sleep(1);
stSend_LO = write(stSocket_LO, &frame[1], sizeof(frame[1])); //发送 frame[1]
if(stSend_LO != sizeof(frame[0]))
{
printf("Send Error frame[1]\n!");
break;
}
sleep(1);
}
close(stSocket_LO);//关闭套接字
return 0;
}
int Can_Control::can_recv()
{
int stSocket_LO, stRecv_LO;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
struct can_filter rfilter[1];
stSocket_LO = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建套接字
strcpy(ifr.ifr_name, "can0" );
ioctl(stSocket_LO, SIOCGIFINDEX, &ifr); //指定 can0 设备
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(stSocket_LO, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与 can0 绑定
//定义接收规则,只接收表示符等于 0x11 的报文
rfilter[0].can_id = 0x11;
rfilter[0].can_mask = CAN_SFF_MASK;
//设置过滤规则
setsockopt(stSocket_LO, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
while(1)
{
stRecv_LO = read(stSocket_LO, &frame, sizeof(frame)); //接收报文
//显示报文
if(stRecv_LO > 0)
{
printf("Idata[0]=0x%x\n",frame.data[0]);
}
}
close(stSocket_LO);
return 0;
}
int Can_Control::socket_connect(const char*m_port)
{
int stSocket_LO = -1;
int ret = 0;
struct sockaddr_can canbus_addr_LO; //can总线的地址 同socket编程里面的 socketaddr结构体 用来设置can外设的信息
struct ifreq ifreq_LO; //接口请求结构体
stSocket_LO = socket(PF_CAN, SOCK_RAW, CAN_RAW);//创建套接字
if(stSocket_LO<0)
{
QMessageBox::information(NULL, QString::fromLocal8Bit("错误"), QString::fromLocal8Bit("打开CAN设备失败"));
return -1;
}
strcpy(ifreq_LO.ifr_name, "can0");//对CAN接口进行初始化,如设置CAN接口名,即当我们用ifconfig命令时显示的名字
ret=ioctl(stSocket_LO, SIOCGIFINDEX, &ifreq_LO); //指定 can设备
if(ret<0)
{
QMessageBox::information(NULL, QString::fromUtf8("错误"), QString::fromUtf8("匹配CAN设备错误"));
return -1;
}
/* 设置CAN协议 */
canbus_addr_LO.can_family = AF_CAN; //协议类型
canbus_addr_LO.can_ifindex = ifreq_LO.ifr_ifindex; //can总线外设的具体索引 类似 ip地址
ret=bind(stSocket_LO, (struct sockaddr *)&canbus_addr_LO, sizeof(canbus_addr_LO));//将套接字和canbus外设进行绑定,即套接字与 can0 绑定
if(ret<0)
{
close_socket(stSocket_LO);//关闭套接字
QMessageBox::information(NULL, QString::fromUtf8("错误"), QString::fromUtf8("绑定套接字错误"));
return -1;
}
return stSocket_LO;
}
void Can_Control::close_socket(const int sockfd)
{
if (sockfd != -1)
{
close(sockfd);
}
}
void Can_Control::set_can_filter()//设置滤波
{
const int n = 1;
struct can_filter rfilter[n];
// 过滤规则:当<received_can_id> & mask == can_id & mask时,接收报文,否则过滤掉.
// 可以同时添加多条过滤规则
// 在用来发送CAN帧的CAN_RAW套接字上不接收任何CAN帧
rfilter[0].can_id = 0x00000000;
rfilter[0].can_mask = CAN_EFF_MASK;
(void)setsockopt(send_socket_fd, SOL_CAN_RAW, CAN_RAW_FILTER, rfilter, n * sizeof(struct can_filter));
// 在用来接收CAN帧的CAN_RAW套接字上禁用接收过滤规则
(void)setsockopt(recv_socket_fd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
}
int Can_Control::send_frame( int sockfd, const void* data, const int count)
{
int ret = write(sockfd, (const char*)data, count);
if (ret != count)
{
QMessageBox::information(NULL, QString::fromUtf8("错误"), QString::fromUtf8("发送错误"));
return 1;
}
return 0;
}
int Can_Control::recv_frame( int sockfd, byte* buf, const int count, const int timeout_ms)
{
struct timeval tv_timeout;
tv_timeout.tv_sec = timeout_ms /1000;
tv_timeout.tv_usec = (timeout_ms % 1000) * 1000;
fd_set fs_read;
FD_ZERO(&fs_read);
FD_SET(sockfd, &fs_read); //如果fd == -1, FD_SET将在此阻塞
int ret = select((int)sockfd + 1, &fs_read, NULL, NULL, &tv_timeout);
if (ret == 0) // recv 超市
{
return 0;
}
if (ret < 0) // select 错误
{
return ret;
}
ret = read(sockfd, (char*)buf, count);
//ret = recv(sockfd, (char*)buf, count, 0);
if (ret <= 0)
{
return -1;
}
return ret;
}
用Can_Control类管理can的通信。
can_send()和can_recv()函数是示例函数,调用可以直接接收发送,用意在于帮助大家了解基于Socket的can通信的流程。
后面对各模块的配置函数,如链接函数负责开启can通信并进行相应配置,本例还有许多可优化的地方,欢迎大家积极参与并分享。
下面是头文件:
#ifndef CAN_CONTROL_H
#define CAN_CONTROL_H
#include <QString>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <QDebug>
#define printf qDebug
typedef __u8 byte;
static int send_socket_fd=-1 ;//接受发送套接字
static int recv_socket_fd=-1 ;
class Can_Control
{
public:
Can_Control();
int can_send();
int can_recv();
int socket_connect(const char*m_port);
void close_socket(const int sockfd);
void set_can_filter();//设置滤波
int send_frame(int sockfd, const void* data, const int count);
int recv_frame( int sockfd, byte* buf, const int count, const int timeout_ms);
//struct canfd_frame Cs_nframe; //要发送的buffer
//struct canfd_frame Rc_nframe; //要接收的buffer
//string m_candevice;//can设备号,默认can0
int stSocket;
};
#endif // CAN_CONTROL_H
用法实例:
void MainWindow::on_toolButton_4_clicked()
{
// Errormsg_Dlg *errordlg=new Errormsg_Dlg();
// errordlg->show();
struct can_frame frame[2] = {{0}}; //要发送的buffer
frame[0].can_id = 0x11;
frame[0]. can_dlc = 8;
frame[0].data[0] = 0x03;
frame[0].data[1] = 0x1a;
frame[1].can_id = 0x22;
frame[1]. can_dlc = 1;
frame[1].data[0] = 0x22;
//const byte* data, const int count
int test;
// __u8 send_frame_data[8] = {0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// memcpy(frame[0].data, send_frame_data, 8);
test=can0.socket_connect("can0");
can0.set_can_filter();
can0.send_frame(test,&frame[0],sizeof(frame[0]));//
}
void MainWindow::on_toolButton_5_clicked()
{
//Operation_records_Dlg* recorddlg=new Operation_records_Dlg();
// recorddlg->show();
struct can_frame recvframe;
byte *precvframe = (byte *)&recvframe;
const int can_frame_len = sizeof(can_frame);
int test;
int ret;
//struct can_frame frame[50];
test=can0.socket_connect("can0");
memset(precvframe, 0x00, can_frame_len);
ret=can0.recv_frame(test,precvframe,can_frame_len,5*1000);
if(ret>0)
{
QString buffer;
QByteArray temp((const char*)(recvframe.data),8);
buffer = temp.toHex();
QMessageBox::information(NULL, QString::fromUtf8("错误"), buffer);
}
}
使用按钮槽函数触发发送没有毛病,但是在接收时,需将cantest的发送定为持续的,500ms发一次,发送50次。
好像只能一次发送一包数据,如果有谁知道如何实现一次发送多包数据的还望告知,感谢!!
版权声明:本文为liuwinner原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。