【c++基础】测试SocketCAN的收发功能

前言

 

CAN收发的过程

基本编程模板的流程为:
(1)创建套接字socket
(2)指定can设备号
(3)绑定bind
(4)如果是发送,就禁用过滤;如果是接受就设置过滤条件
(5)对套接字的fd进行read,write操作实现收发功能;

code

/*
 * cantest.c
 *
 *  Created on: 2017-5-16
 *      Author: simon
 */

#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>


int main(int argc, char *argv[])
{
    int s, nbytes;
    char *array[2] = {"-r", "-s"};
    struct sockaddr_can addr;
    struct ifreq ifr;
    struct can_frame frame;
    struct can_filter rfilter[1];


    /* handle (optional) flags first */
    if(argc != 3) {
        fprintf(stderr, "Usage:  %s <-r> <can interface name> for receiving\nor <-s> <can interface name> for sending\n", argv[0]);
        exit(1);
    }
    /* create socket */
    if ((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
    {
        perror("Create socket failed");
        exit(-1);
    }

    /* set up can interface */
    strcpy(ifr.ifr_name, argv[2]);
    printf("can port is %s\n",ifr.ifr_name);
    /* assign can device */
    ioctl(s, SIOCGIFINDEX, &ifr);
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    /* bind can device */
    if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("Bind can device failed\n");
        close(s);
        exit(-2);
    }

    /* configure receiving */
    if(!strcmp(argv[1],array[0]))
    {
        /* set filter for only receiving packet with can id 0x1F */
        rfilter[0].can_id = 0x1F;
        rfilter[0].can_mask = CAN_SFF_MASK;
        if(setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)) < 0)
        {
            perror("set receiving filter error\n");
            close(s);
            exit(-3);
        }
        /* keep reading */
        while(1){
            nbytes = read(s, &frame, sizeof(frame));
            if(nbytes > 0)
            {
                printf("%s ID=%#x data length=%d\n", ifr.ifr_name, frame.can_id, frame.can_dlc);
                for (int i=0; i < frame.can_dlc; i++)
                    printf("%#x ", frame.data[i]);
                printf("\n");
            }
        }
    }
    /* configure sending */
    else if(!strcmp(argv[1],array[1]))
    {
        /* configure can_id and can data length */
        frame.can_id = 0x1F;
        frame.can_dlc = 8;
        printf("%s ID=%#x data length=%d\n", ifr.ifr_name, frame.can_id, frame.can_dlc);
        /* prepare data for sending: 0x11,0x22...0x88 */
        for (int i=0; i<8; i++)
        {
            frame.data[i] = ((i+1)<<4) | (i+1);
            printf("%#x ", frame.data[i]);
        }
        printf("Sent out\n");
        /* Sending data */
        if(write(s, &frame, sizeof(frame)) < 0)
        {
            perror("Send failed");
            close(s);
            exit(-4);
        }
    }
    /* wrong parameter input situation */
    else
    {
        printf("wrong parameter input\n");
    }

    close(s);
    return 0;
}
View Code

CMakeLists.txt

cmake_minimum_required(VERSION 3.3)
project(cantest LANGUAGES C)
set(CMAKE_BUILD_TYPE Release)

set(INCLUDE_DIRS include)
include_directories (${INCLUDE_DIRS})

set(LIBS_DIRS)
link_directories(${LIBS_DIRS})

set(LIBS)
link_libraries(${LIBS})

aux_source_directory(src SRC_DIRS)
add_executable(${PROJECT_NAME} ${SRC_DIRS})
target_link_libraries(${PROJECT_NAME} ${LIBS})
install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_SOURCE_DIR}/cmake/make_uninstall.cmake")
View Code

run

~/workspace/cantest/build$ ./cantest -s vcan0
can port is vcan0
vcan0 ID=0x1f data length=8
0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 Sent out

但是运行-r的时候,一直没有反应。。。。

~/workspace/cantest/build$ ./cantest -r vcan0
can port is vcan0

但是,如果同时运行-s,则-r可以接收到信息。不知道是什么原因。。。。

~/workspace/cantest/build$ ./cantest -r vcan0
can port is vcan0
nbytes: 16
vcan0 ID=0x1f data length=8
0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 
nbytes: 16
vcan0 ID=0x1f data length=8
0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 

应该是接收程序被阻塞,等待接收数据,接收到数据之后等待下一次的数据。。。但是为什么ioctl和bind前后的debug信息不能显示呢??难道是多线程之类的。。。。

update 20220718

基于TX2板子,使用CAN分析仪和调试工具测试CAN通信;

1)运行测试程序,-s可以正常发送数据,不论can0和can1;

2)同时运行-r和-s,可以正常发送和接收,但是CAN调试工具只有接收的TX2发送的数据;

3)通过CAN调试工具发送数据,-r不能接收到;

4)can0端口-s可以发送数据,但是CAN调试工具没有看到接收数据,同时-r can0也没有接收到数据,可能can0端口硬件有问题;

5)TX2端运行candump can1,然后CAN调试工具发送报文,TX2端可以接收到数据,但是can0端口没有接收到数据;

 总结,can1可以在TX2和CAN调试工具之间使用cansend、candump收发,且重启也没有影响;而can0没有反应;

can1使用cantest程序可以完成收发,同时CAN调试工具也可以接收,但是调试工具发送数据,程序不能接收到数据;

而can0使用程序只能发送,程序和调试工具都不能接收,且调试工具发送数据,程序也不能接收;

 奇怪的是,最开始的时候使用cansend和candump却没有反应。。。。

 问题

CANoe发送(CAN2上的所有信号,包括速度和FS+LANE),TX2程序接收(CAN2上的所有信号,包括速度和FS+LANE),同时TX2程序发送(FS+LANE),问题是,这样的话,一个CAN口同时接收和发送同一个信号,肯定会发生冲突的,所以出错了。。。
可以在CANoe中过滤掉不需要接收的数据,然后再发送到TX2;

 

 

 

参考

1. SocketCAN_test_receive_send;

2. 一个简单的Linux下的socket程序

posted on 2020-06-19 17:52  鹅要长大  阅读(2363)  评论(0编辑  收藏  举报

导航