linux can socket programming

Table of contents

1. Can programming under Linux uses socket. Before performing can programming, you need to set the parameters of can with commands.

2. The program is implemented using three threads

3. Commands to set CAN configuration parameters and simple test commands


1. Can programming under Linux uses socket. Before performing can programming, you need to set the parameters of can with commands.

# 在/etc/rc.local
ip link set can0 type can bitrate 250000 # 设置CAN0波特率250k
ip link set can1 type can bitrate 250000 # 设置CAN1波特率250k
ifconfig can0 up # 打开 can0
ifconfig can1 up # 打开 can0
/sbin/getty -n -l /home/root/auto_log_in.sh 115200 ttymxc0 # 开机自动登录脚本auto_log_in.sh里面: /bin/login -f root

 Note: Set CAN parameters first, then ifconfig can up.

2. The program is implemented using three threads

        The main thread initializes the can socket and the CAN send and receive buffer and then creates the CAN sending and receiving threads . The CAN sending thread checks whether the CAN sending buffer contains the CAN message to be sent, and the CAN receiving thread stores the message in the CAN receiving buffer. Note: usleep(0) actively gives up the opportunity to receive and send. The following is the specific code implementation.

#ifndef __CAN_DRIVER_H
#define __CAN_DRIVER_H
/*
struct can_frame {
	canid_t can_id;//CAN 标识符 
	__u8 can_dlc;//数据场的长度 
	__u8 data[8];//数据 
};
*/

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <signal.h>

/*定义can缓存区大小*/
#define CAN_FRAME_BUFFER_SIZE 1024
/*定义缓冲区结构体*/
typedef struct CAN_BUFFER{
    struct can_frame frame_buf[CAN_FRAME_BUFFER_SIZE];
    unsigned int out;
    unsigned int in;
}can_buf_struct;

/*can 0发送函数 填充数据到发送缓存区*/
int can0_tx(struct can_frame *fram);
/*can 0接受函数 从接收缓存区获取接收到的CAN一帧数据*/
int can0_rx(struct can_frame *fram);
/*打印 can_frame  帧数据内容*/
void print_can_frame(struct can_frame *frame);
int can_rx_tx_init(void);

#endif

#include "can_driver.h"
#define  CAN_ZERO "can0"

#define debug_print printf

static volatile can_buf_struct can0_rx_buf;
static volatile can_buf_struct can0_tx_buf;
static pthread_mutex_t can0_lock;
static pthread_t thread_read_id=0;
static pthread_t thread_write_id=0;
static int sockfd = -1;

static void * can0_send(void *v);
static void * can0_recive(void *v);
static void pthread_quit_slot(int sig);

/*can 0发送函数 填充数据到发送缓存区*/
int can0_tx(struct can_frame *fram)
{
    int ret=0;
//    debug_print("can0_tx in = %d out = %d\r\n",can0_tx_buf.in,can0_tx_buf.out);
    memcpy(&can0_tx_buf.frame_buf[can0_tx_buf.in],
            fram,sizeof(struct can_frame));
    can0_tx_buf.in++;
    if(can0_tx_buf.in>=CAN_FRAME_BUFFER_SIZE){
        can0_tx_buf.in = 0;
    }
    if(can0_tx_buf.in==can0_tx_buf.out){
        debug_print("can0_tx_buf fill \r\n");
    }

//    pthread_mutex_lock(&can0_lock);
    // send frame to can 0
//    ret = write(sockfd, fram, sizeof(struct can_frame));
//    pthread_mutex_unlock(&can0_lock);
    return 0;
}

/*can 0接受函数 从接收缓存区获取接收到的CAN一帧数据*/
int can0_rx(struct can_frame *fram)
{
    if(can0_rx_buf.in==can0_rx_buf.out){
        return -1;
    }else{
        memcpy(fram,&can0_rx_buf.frame_buf[can0_rx_buf.out],sizeof(struct can_frame));

        can0_rx_buf.out++;
        if(can0_rx_buf.out>=CAN_FRAME_BUFFER_SIZE){
            can0_rx_buf.out = 0;
        }
    }
	return 0;
}

/*can0 初始化函数*/


static void can_rx_tx_release(int sig)
{
    (void)sig;
    if(thread_read_id>0)pthread_kill(thread_read_id,SIGQUIT);
    if(thread_write_id>0)pthread_kill(thread_write_id,SIGQUIT);
    if(thread_read_id)pthread_join(thread_read_id,NULL);
    if(thread_write_id)pthread_join(thread_write_id,NULL);
    if(sockfd>0)close(sockfd);
}

int can_rx_tx_init(void)
{
	struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};

    int ret;

    can0_rx_buf.in = 0;
    can0_rx_buf.out = 0;
    can0_tx_buf.in = 0;
    can0_tx_buf.out = 0;
    pthread_mutex_init(&can0_lock,NULL);
    /* 打开套接字 */
    sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(0 > sockfd) {
        perror("socket error");
		debug_print("socket error");
        exit(EXIT_FAILURE);
    }
	
    /* 指定can0设备 */
    strcpy(ifr.ifr_name, CAN_ZERO);
    ioctl(sockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    /* 将can0与套接字进行绑定 */
    ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
    if (0 > ret) {
        perror("bind error");
		debug_print("bind error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    ret = pthread_create(&thread_read_id, NULL,can0_recive, &sockfd);
	if (0 > ret) {
		debug_print(" read pthread_create fail\r\n");	
	}
    ret = pthread_create(&thread_write_id, NULL,can0_send, &sockfd);
	if (0 > ret) {
		debug_print(" write pthread_create fail\r\n");	
	}

    signal(SIGQUIT,can_rx_tx_release);
	return 0;
}


/*私有函数 can0发送缓冲区数据*/
static void * can0_send(void *v)
{
    int *p = v;
    int sockfd = *p;
    int ret=0;
    //= (int)(*v);
    struct can_frame *frame;
    signal(SIGQUIT,pthread_quit_slot);
    while(1){
//        debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);

        if(can0_tx_buf.in==can0_tx_buf.out){
//            debug_print("can0_tx_buf empty \r\n");
        }else{
            debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);
            frame = &can0_tx_buf.frame_buf[can0_tx_buf.out];
            can0_tx_buf.out++;
            if(can0_tx_buf.out >= CAN_FRAME_BUFFER_SIZE){
                can0_tx_buf.out = 0;
            }
            pthread_mutex_lock(&can0_lock);
            // send frame to can 0
            ret = write(sockfd, frame, sizeof(struct can_frame));
            pthread_mutex_unlock(&can0_lock);
            if(ret!=sizeof(struct can_frame)){
                debug_print("send can frame error\r\n");
            }
        }
        usleep(0);
    }
    return NULL;
}

/*私有函数 can0接收数据到缓冲区*/
static void * can0_recive(void *v)
{
    int *p = v;
    int sockfd = *p;
    int ret=0;
    struct can_frame frame;
    signal(SIGQUIT,pthread_quit_slot);
    while(1){
        pthread_mutex_lock(&can0_lock);
        ret = read(sockfd, &frame, sizeof(struct can_frame));
        pthread_mutex_unlock(&can0_lock);

        if (0 > ret) {
            debug_print("read can frame error %s,%d",__FUNCTION__,__LINE__);
//            break;
        }else{
            debug_print("%s,%d\r\n",__FUNCTION__,__LINE__);
            memcpy(&can0_rx_buf.frame_buf[can0_rx_buf.in],&frame,sizeof(struct can_frame));
            can0_rx_buf.in++;
            if(can0_rx_buf.in >= CAN_FRAME_BUFFER_SIZE){
              can0_rx_buf.in = 0;
            }
            if(can0_rx_buf.in==can0_rx_buf.out){
                debug_print("can0_rx_buf fill \r\n");
            }
            usleep(0);
//            print_can_frame(&frame);
        }
    }
    return NULL;
}

static void pthread_quit_slot(int sig)
{
    (void)sig;
    pthread_exit(0);
}

/*打印 can_frame  帧数据内容*/
void print_can_frame(struct can_frame *frame)
{
    /* 校验帧格式 */
    if (frame->can_id & CAN_EFF_FLAG)	//扩展帧
        printf("扩展帧 <0x%08x> ",frame->can_id & CAN_EFF_MASK);
	else		//标准帧
        printf("标准帧 <0x%03x> ",frame->can_id & CAN_SFF_MASK);

 	/* 校验帧类型:数据帧还是远程帧 */
    if (frame->can_id & CAN_RTR_FLAG) {
        debug_print("remote request\n");
        return ;
    }
	/* 打印数据长度 */
    printf("[%d] ", frame->can_dlc);
	/* 打印数据 */
    for (int i = 0; i < frame->can_dlc; i++)
        printf("%02x ", frame->data[i]);
    printf("\n");
}



//static void pthread_write_quit_slot(int sig)
//{
//    pthread_kill(thread_read_id,SIG_QUIT);
//    pthread_join(thread_read_id);
//    pthread_exit(0);
//}







#include "can_driver.h"
#define CAN_NUMBER "can0"

int main(void)
{

    static unsigned int count=0,c2;
    struct can_frame fram;
    fram.can_dlc = 8;
    can_rx_tx_init();
    while(1){

        if(can0_rx(&fram)>=0)
        {
//            print_can_frame(&fram);


            fram.data[0] = count++;
            fram.data[0] = c2--;
            fram.can_id += count;
            can0_tx(&fram);
        }
    }

}


Receive phenomenon:

3. Commands to set CAN configuration parameters and simple test commands

ifconfig -a     # 可以查到当前can网络 can0 can1,包括收发包数量、是否有错误等。
ip link set can0 up type can bitrate 800000     # 设置can0的波特率为800kbps,CAN网络波特率最大值为1Mbps
ip link set can0 up type can bitrate 800000 loopback on     # 设置回环模式,自发自收,用于测试是硬件是否正常,loopback不一定支持
ip link set can0 down #关闭can0 网络 down换为 up则打开can0
cansend can0 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88     # 发送默认ID为0x1的can标准帧,数据为0x11 22 33 44 55 66 77 88 每次最大8个byte
cansend can0 -i 0x800 0x11 0x22 0x33 0x44 0x55 0x66 0x77 0x88 -e     # -e 表示扩展帧,CAN_ID最大29bit,标准帧CAN_ID最大11bit -i表示CAN_ID 0x800
cansend can0 -i 0x02 0x11 0x12 --loop=20    # --loop 表示发送20个包
candump can0    #接收CAN0数据

Guess you like

Origin blog.csdn.net/klp1358484518/article/details/132152525
Recommended