2015年4月20日 星期一

CANBUS 發送與接收使用Socket CAN

參考文件 https://www.kernel.org/doc/Documentation/networking/can.txt
中文參考 http://blog.csdn.net/yuanlulu/article/details/7220060

控制器區域網路 (Controller Area Network, 簡稱 CAN 或 CANbus)
一種通訊協定,主要應用在汽車、工控領域。
目前版本CAN 2.0A與CAN 2.0B ,B是A的擴充。2.0B 的ID長度占29bit, 2.0A 的ID長度占11bit

節點架構


CAN Controller 通常內建於MCU內(也有獨立的ex: SJA1000),會在外接Transceiver(ex:ISO1050)轉成類比訊號。

CAN封包格式


寫基本的CAN,只需要注意仲裁欄位、控制欄位、資料欄位

Field nameLength (bits)Purpose
Start-of-frame1Denotes the start of frame transmission
Identifier (green)11A (unique) identifier which also represents the message priority
Remote transmission request (RTR)1Must be dominant (0) for data frames and recessive (1) for remote request frames (see Remote Frame, below)
Identifier extension bit (IDE)1Must be dominant (0) for base frame format with 11-bit identifiers
Reserved bit (r0)1Reserved bit. Must be dominant (0), but accepted as either dominant or recessive.
Data length code (DLC) (yellow)4Number of bytes of data (0–8 bytes)[a]
Data field (red)0–64 (0-8 bytes)Data to be transmitted (length in bytes dictated by DLC field)
CRC15Cyclic redundancy check
CRC delimiter1Must be recessive (1)
ACK slot1Transmitter sends recessive (1) and any receiver can assert a dominant (0)
ACK delimiter1Must be recessive (1)
End-of-frame (EOF)7Must be recessive (1)
CAN BUS的操作可以如同使用SOCKET。
參考Linux下範例 candsend.c   candump.c
看完除了會can 的發送與接收,也可以學到命令列參數使用方法 (function: getopt_long)

以下簡單範例:
Setting :
    struct can_frame frame;
    struct ifreq ifr;
    struct sockaddr_can addr;
    char *interface = "can0";
    int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;

    s = socket(family, type, proto)
    strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
    if (ioctl(s, SIOCGIFINDEX, &ifr)) {
        perror("CAN ioctl");
        return 1;
    }
    addr.can_family = family;
    addr.can_ifindex = ifr.ifr_ifindex;

    if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("CAN bind");
        return 1;
    }
Send :
//sendcanbus();
            frame.can_id = 0x0321;
            frame.can_dlc = 4;
            frame.data[0] = 0;
            frame.data[1] = 1;
            frame.data[2] = 2;
            frame.data[3] = 3;

            ret = send(s,&frame,sizeof(frame),0);
Read :
            //dropt the timeout packets
            while(nbytes = recvfrom(s,&frame,sizeof(struct can_frame),0,(struct sockaddr*)&addr,&len)>=0)
            {
                printf("\r\nrecvfrom nbytes %d",nbytes);
                memcpy(b,&frame,sizeof(frame));
                for (i=0 ; i < sizeof(struct can_frame) ; i++)
                {
                    printf(" 0x%x ",b[i]);
                }
                usleep(10000);//
            }