IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    linux socket can程序cantool

    reille发表于 2015-11-20 09:18:40
    love 0

    最近写了个自认为不错的基于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;
    }

    使用示例

    cantool使用示例

    cantool使用示例

    程序源码

    下载地址:linux socket can程序cantool

    如果觉得好用,记得给个好评!

    您可能也喜欢:

    linux中让程序在后台运行

    使用eclipse SDK开发嵌入式linux应用程序——eclipse的C/C++开发环境安装与配置

    atmel9260上linux socketcan MCP2515调试笔记即CAN总线调试总结

    Linux kernel路由机制分析(下)

    动画演示10个有趣但毫无用处的Linux命令
    无觅
    » 本文地址: http://velep.com/archives/1177.html
    » 文章出处: reille博客—http://velep.com , 如果没有特别声明,文章均为reille博客原创作品
    » 郑重声明: 原创作品未经允许不得转载,如需转载请联系reille#qq.com(#换成@)
    分享到:
    推荐阅读相关文章:
    • TCP Server处理多Client请求的方法—非阻塞accept与select
    • 联想E430C和WINDOW 7
    • undefined reference to `_WinMain@16’问题
    • linux backtrace()详细使用说明,分析Segmentation fault
    • 一个PTHREAD_STACK_MIN宏定义引出的头文件包含问题
    • linux性能分析工具oprofile的安装与使用
    • linux下统计代码执行时间
    • 心仪已久的树莓派终于到手了


沪ICP备19023445号-2号
友情链接