linux can socket 编程

目录

1. linux 下can编程使用socket,在进行can编程之前需要先用命令设置好can的参数

2.程序使用三个线程实现

3.设置CAN配置参数的命令和简单测试命令


1. linux 下can编程使用socket,在进行can编程之前需要先用命令设置好can的参数

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

 注意:先设置CAN的参数,在ifconfig can up。

2.程序使用三个线程实现

        主线程初始化can socketCAN发送接收buffer 然后创建 CAN发送和接收线程,CAN发送线程检查CAN发送buffer里面是否包含待发送的can报文,CAN接收线程把报文存储到CAN的接收buffer 里面。注:usleep(0) 是主动让出接收发送时机。以下是具体代码实现。

#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);
        }
    }

}


收发现象:

3.设置CAN配置参数的命令和简单测试命令

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数据

猜你喜欢

转载自blog.csdn.net/klp1358484518/article/details/132152525