bbb SOCKET CAN
系統將CAN設備作為網絡設備進行管理,因此在CAN總線應用開發方面,Linux提供了SocketCAN接口,使得CAN總線通信近似于和以太網的通信,應用程序開發接口更加通用,也更加靈活。
我們使用原始套接字與BBB的can綁定,進行通信。
1. 初始化
SocketCAN中大部分的數據結構和函數在頭文件linux/can.h 中進行了定義。CAN總線套接字的創建采用標準的網絡套接字操作來完成。網絡套接字在頭文件sys/socket.h中定義。套接字的初始化方法如下:
int s; struct sockaddr_can addr; struct ifreq ifr; s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //創建SocketCAN套接字 strcpy(ifr.ifr_name, "can0" ); ioctl(s, SIOCGIFINDEX, &ifr); //指定can0設備 addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; bind(s, (struct sockaddr *)&addr, sizeof(addr)); //將套接字與can0綁定
2. 數據發送
在數據收發的內容方面,CAN總線與標準套接字通信稍有不同,每一次通信都采用can_ frame結構體將數據封裝成幀。結構體定義如下:
struct can_frame {
canid_t can_id; //CAN標識符
__u8 can_dlc; //數據場的長度
__u8 data[8]; //數據
};
can_id為幀的標識符,如果發出的是標準幀,就使用can_id的低11位;如果為擴展幀,就使用0~28位。can_id的第29、30、31位是幀的標志位,用來定義幀的類型,定義如下:
#define CAN_EFF_FLAG 0x80000000U //擴展幀的標識 #define CAN_RTR_FLAG 0x40000000U //遠程幀的標識 #define CAN_ERR_FLAG 0x20000000U //錯誤幀的標識,用于錯誤檢查
數據發送使用write函數來實現。如果發送的數據幀(標識符為0x123)包含單個字節(0xAB)的數據,可采用如下方法進行發送:
struct can_frame frame;
frame.can_id = 0x123; //如果為擴展幀,那么frame.can_id = CAN_EFF_FLAG | 0x123;
frame.can_dlc = 1; //數據長度為1
frame.data[0] = 0xAB; //數據內容為0xAB
int nbytes = write(s, &frame, sizeof(frame)); //發送數據
if (nbytes != sizeof(frame)) //如果nbytes不等于幀長度,就說明發送失敗
printf("Error
!");
如果要發送遠程幀(標識符為0x123),可采用如下方法進行發送:
struct can_frame frame; frame.can_id = CAN_RTR_FLAG | 0x123; write(s, &frame, sizeof(frame));
3. 數據接收
數據接收使用read函數來完成,實現如下:
struct can_frame frame; int nbytes = read(s, &frame, sizeof(frame));
當然,套接字數據收發時常用的send、sendto、sendmsg以及對應的recv函數也都可以用于CAN總線數據的收發。
4. 錯誤處理
當幀接收后,可以通過判斷can_id中的CAN_ERR_FLAG位來判斷接收的幀是否為錯誤幀。如果為錯誤幀,可以通過can_id的其他符號位來判斷錯誤的具體原因。
錯誤幀的符號位在頭文件linux/can/error.h中定義。
5. 過濾規則設置
在數據接收時,系統可以根據預先設置的過濾規則,實現對報文的過濾。過濾規則使用can_filter結構體來實現,定義如下:
struct can_filter {
canid_t can_id;
canid_t can_mask;
};
過濾的規則為:
接收到的數據幀的can_id&mask==can_id&mask
通過這條規則可以在系統中過濾掉所有不符合規則的報文,使得應用程序不需要對無關的報文進行處理。在can_filter結構的can_id中,符號位CAN_INV_FILTER在置位時可以實現can_id在執行過濾前的位反轉。
用戶可以為每個打開的套接字設置多條獨立的過濾規則,使用方法如下:
structcan_filterrfilter[2];
rfilter[0].can_id=0x123;
rfilter[0].can_mask=CAN_SFF_MASK;//#defineCAN_SFF_MASK0x000007FFU
rfilter[1].can_id=0x200;
rfilter[1].can_mask=0x700;
setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,&rfilter,sizeof(rfilter));//設置規則
在極端情況下,如果應用程序不需要接收報文,可以禁用過濾規則。這樣的話,原始套接字就會忽略所有接收到的報文。在這種僅僅發送數據的應用中,可以在內核中省略接收隊列,以此減少CPU資源的消耗。禁用方法如下:
setsockopt(s,SOL_CAN_RAW,CAN_RAW_FILTER,NULL,0);//禁用過濾規則
通過錯誤掩碼可以實現對錯誤幀的過濾,例如:
can_err_mask_terr_mask=(CAN_ERR_TX_TIMEOUT|CAN_ERR_BUSOFF);
setsockopt(s,SOL_CAN_RAW,CAN_RAW_ERR_FILTER,err_mask,sizeof(err_mask));
在默認情況下,本地回環功能是開啟的,可以使用下面的方法關閉回環/開啟功能:
intloopback=0;//0表示關閉,1表示開啟(默認)
setsockopt(s,SOL_CAN_RAW,CAN_RAW_LOOPBACK,&loopback,sizeof(loopback));
在本地回環功能開啟的情況下,所有的發送幀都會被回環到與CAN總線接口對應的套接字上。默認情況下,發送CAN報文的套接字不想接收自己發送的報文,因此發送套接字上的回環功能是關閉的??梢栽谛枰臅r候改變這一默認行為:
intro=1;//0表示關閉(默認),1表示開啟
setsockopt(s,SOL_CAN_RAW,CAN_RAW_RECV_OWN_MSGS,&ro,sizeof(ro));
總結
以上是生活随笔為你收集整理的bbb SOCKET CAN的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小练习
- 下一篇: zuul中的prefix 和 strip