linux socket can程序cantool

最近寫了個自認爲不錯的基於linux socket can程序,主要功能:

  1. 程序具備全部CAN功能,包括CAN標準幀/擴展幀接收與發送、CAN總線錯誤判斷、環回等功能
  2. 適用基於LINUX SOCKET機制實現的CAN接口,可用於嵌入式LINUX的CAN測試
  3. 程序採用標準LINUX命令行參數選項形式,接受用戶參數

現把源碼進行分享

功能介紹

SOCKET CAN工具程序 – Ver1.0 Build Nov 20 2015, COPYRIGHT (C) 2015 reille @ http://velep.com/

介紹:
本SOCKET CAN程序具備全部CAN功能,包括CAN標準幀/擴展幀接收與發送、CAN總線錯誤判斷、環回等功能
適用基於LINUX SOCKET機制實現的CAN接口,可用於嵌入式LINUX中的CAN測試程序
程序採用標準LINUX命令行參數選項形式,接受用戶參數

用法: ./cantool [選項]…

選項:
-p, –port=CAN接口號 指定CAN接口號,從1開始, 默認爲 1(即CAN1接口)
-b, –baud=波特率 指定CAN通訊波特率,單位Kbps,默認爲 250 Kbps
可用波特率:5,10,20,40,50,80,100,125,200,250,400,500,666,800,1000

-i, –frame-id=幀ID 指定CAN發送幀ID(Hex格式), 默認爲1801F456
-d, –data=數據 指定CAN發送幀數據, 默認爲:00 01 FF FF FF FF FF FF,字節數據間以空格隔開
-f, –freq=間隔 指定CAN幀發送間隔,單位ms, 默認爲250ms, 最小值爲1ms
-t, –times=次數 指定CAN幀發送次數, 默認爲0次
-s, 指定CAN發送幀爲標準幀, 默認爲發送擴展幀
-I, 幀ID每發送一幀遞增, 默認不遞增
-g, 發送數據每發送一幀遞增, 默認不遞增
-l, 發送數據時本地環回, 默認不環回

–help 顯示此幫助信息並退出

注意,以下CAN幀ID作爲系統使用:
0x00000001 – TX timeout (by netdevice driver)
0x00000002 – lost arbitration / data[0]
0x00000004 – controller problems / data[1]
0x00000008 – protocol violations / data[2..3]
0x00000010 – transceiver status / data[4]
0x00000020 – received no ACK on transmission
0x00000040 – bus off
0x00000080 – bus error (may flood!)
0x00000100 – controller restarted

使用 Ctrl^C 組合鍵結束程序運行

部分源碼

int main(int argc, char **argv)
{
    S_CanFrame sendframe, recvframe;
    byte *psendframe = (byte *)&sendframe;
    byte *precvframe = (byte *)&recvframe;
    u_canframe_data_t *psend_data = (u_canframe_data_t *)sendframe.data;
    const int can_frame_len = sizeof(S_CanFrame); 

    pid_t pid = -1;
    int   status;

    int  ret = 0;
    char buf[128] = {0};
    bool carry_bit = false;// 進位標誌

    int segment_id;//id for shared memo


    if (parse_options(argc, argv))
    {
        usage();    return  0;
    }

    if (!find_can(port))
    {
        sprintf(buf, "\n\t錯誤:CAN%d設備不存在\n\n", port + 1);
        panic(buf);
        return  -1;
    }

    close_can(port);// 必須先關閉CAN,才能成功設置CAN波特率
    set_bitrate(port, bitrate);// 操作CAN之前,先要設置波特率
    open_can(port, bitrate);

    send_socket_fd = socket_connect(port);
    recv_socket_fd = socket_connect(port);
    //printf("send_socket_fd = %d, recv_socket_fd = %d\n", send_socket_fd, recv_socket_fd);
    if (send_socket_fd < 0 || send_socket_fd < 0)
    {
        disconnect(&send_socket_fd);
        disconnect(&recv_socket_fd);
        panic("\n\t打開socket can錯誤\n\n");
        return  -1;
    }
    set_can_filter();
    set_can_loopback(send_socket_fd, lp);

    printf_head();

    memset(&sendframe, 0x00, sizeof(sendframe));
    memset(&recvframe, 0x00, sizeof(recvframe));

    if (extended_frame) // 指定發送幀類型:擴展幀或標準幀
    {
        sendframe.can_id = (send_frame_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
    } 
    else
    {
        sendframe.can_id = (send_frame_id & CAN_SFF_MASK);
    }
    sendframe.can_dlc = dlc;
    memcpy(sendframe.data, send_frame_data, dlc);

    
    segment_id = shmget(IPC_PRIVATE, sizeof(int), S_IRUSR | S_IWUSR);// allocate memo
    pframeno = (int *)shmat(segment_id, NULL, 0);// attach the memo
    if (pframeno == NULL)
    {
        panic("\n\t創建共享內存失敗\n\n");
        return  -1;
    }
    *pframeno = 1;

    run = true;

    pid = fork();
    if(pid == -1) 
    { 
        panic("\n\t創建進程失敗\n\n");
        return  -1;
    }
    else if(pid == 0) // 子進程,用於發送CAN幀
    {
        while (run && (send_frame_times > 0))
        {
            ret = send_frame(send_socket_fd, (char *)&sendframe, sizeof(sendframe));
            printf_frame(sendframe.can_id & CAN_EFF_MASK, sendframe.data, sendframe.can_dlc, 
                ((sendframe.can_id & CAN_EFF_FLAG) ? true : false),
                ret > 0 ? true : false, 
                true);
            delay_ms(send_frame_freq_ms);

            if (send_frame_id_inc_en)
            {
                sendframe.can_id++;
                if (extended_frame)
                {
                    sendframe.can_id = (sendframe.can_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
                } 
                else
                {
                    sendframe.can_id = (sendframe.can_id & CAN_SFF_MASK);
                }
            }

            if (send_frame_data_inc_en && dlc > 0)
            {
                if (dlc > 4 && psend_data->s.dl == ((__u32)0xFFFFFFFF))
                {
                    carry_bit = true;// 發生進位
                }
                psend_data->s.dl++;

                if (dlc <= 4)
                {
                    if (psend_data->s.dl >= (1 << (dlc * 8)))
                    {
                        psend_data->s.dl = 0;
                    }
                }
                else if (dlc <= 8)
                {
                    if (carry_bit)
                    {
                        psend_data->s.dh++;
                        if (psend_data->s.dh >= (1 << ((dlc - 4) * 8)))
                        {
                            psend_data->s.dh = 0;
                        }

                        carry_bit = false;
                    }
                }
            }

            send_frame_times--;
        }

        exit(0);
    }
    else // 父進程,接收CAN幀
    {
        install_sig();

        while (run)
        {
            memset(precvframe, 0x00, can_frame_len);
            ret = recv_frame(recv_socket_fd, precvframe, can_frame_len, 5 * 1000);
            if (ret > 0)
            {
                printf_frame(recvframe.can_id & CAN_EFF_MASK, recvframe.data, recvframe.can_dlc, 
                    ((recvframe.can_id & CAN_EFF_FLAG) ? true : false),
                    true, 
                    false);
            }
        }

        while(((pid = wait(&status)) == -1) && (errno == EINTR))
        {
            delay_ms(10);
        }
    }

    disconnect(&send_socket_fd);
    disconnect(&recv_socket_fd);

    shmdt(pframeno);// detach memo
    shmctl(segment_id, IPC_RMID, NULL);// remove

    return  0;
}
使用示例

程序源碼

下載地址:linux socket can程序cantool

如果覺得好用,記得給個好評!

» 文章出處: reille博客—http://velep.com , 如果沒有特別聲明,文章均爲reille博客原創作品
» 鄭重聲明: 原創作品未經允許不得轉載,如需轉載請聯繫reille#qq.com(#換成@)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章