/******************************************************************************
版权所有：	
文件名称：	flexcan.c
文件版本：	01.01
创建作者:	sunxi
创建日期：	2025-09-28
功能说明：	FLEXCAN驱动
其它说明：
修改记录：
*/
/*------------------------------- 头文件 --------------------------------------
*/
#include "bspconfig.h"
#include "rt_printf.h"
#include "ustimer.h"
#include "rt.h"
#include "flexcan.h"
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/prctl.h>
#include <unistd.h>

#ifdef BSP_CAN_ENABLE

 
/*------------------------------- 宏定义 --------------------------------------
*/

#define CAN_FIFO

// 优先级
#define CAN_PRIO_MAX					4

// 短帧BUF
#define CAN_FRAME_NUM					256 // CAN短帧BUF数量
#define CAN_FRAME_LEN					16  // CAN短帧BUF长度
#define CAN_FRAME_HEAD_LEN				8	// CAN短帧帧头长度
#define CAN_FRAME_DATA_LEN				8	// CAN短帧数据长度

// 长帧BUF
#define CAN_LONGFRAME_NUM				16	// CAN长帧BUF数量
#define CAN_LONGFRAME_LEN				CAN_FRAME_LEN_MAX	// CAN长帧BUF长度
#define CAN_LONGFRAME_HEAD_LEN			4   // CAN长帧头长度
#define CAN_LONGFRAME_DATA_LEN			(CAN_LONGFRAME_LEN-CAN_LONGFRAME_HEAD_LEN)   // CAN长帧数据长度

// 帧标志,数字越小，优先级越高
#define CAN_FRAME_SINGLE				0 // 单帧（既是起始帧，又是结束帧）
#define CAN_FRAME_END					1 // 结束帧
#define CAN_FRAME_MIDDLE				2 // 中间帧
#define CAN_FRAME_BEGIN					3 // 开始帧

//帧ID中各个域的位偏移
#define CAN_FRAME_OFFSET_SN				0    // 帧序号偏移
#define CAN_FRAME_OFFSET_MARK			6    // 帧标志偏移
#define CAN_FRAME_OFFSET_SRC			8    // 帧源地址偏移
#define CAN_FRAME_OFFSET_DST			12   // 帧目的地址偏移
#define CAN_FRAME_OFFSET_TYPE			16   // 帧类型偏移
#define CAN_FRAME_OFFSET_PRIOR			23 	 // 帧优先级偏移(帧优先级是帧类型的高2位)
#define CAN_FRAME_OFFSET_LEN			16   // 帧长度偏移

#define CAN_FRAME_MASK_SN				0X3F // 帧序号屏蔽位
#define CAN_FRAME_MASK_MARK				0X03 // 帧标志屏蔽位
#define CAN_FRAME_MASK_SRC				0X0F // 帧源地址屏蔽位
#define CAN_FRAME_MASK_DST				0X0F // 帧目的地址屏蔽位
#define CAN_FRAME_MASK_TYPE				0XFF // 帧类型屏蔽位
#define CAN_FRAME_MASK_PRIOR			0X03 // 帧优先级屏蔽位(帧优先级是帧类型的高2位)
#define CAN_FRAME_MASK_LEN				0X0F // 帧长度屏蔽位


//缓冲区为空	  
#define CAN_BUF_EMPTY(ring)		((ring)->head == (ring)->tail)
//缓冲区满
#define CAN_BUF_FULL(ring, size)		(((unsigned char)((ring)->head - (ring)->tail))==((unsigned char)(size-1)))
//缓冲区剩余空间
#define CAN_BUF_SPACE(ring, size)      (((unsigned char)((ring)->tail - (ring)->head) -1) & (unsigned char)(size-1))


//强制中断寄存器
#define REG_MCF_INTFRCL1	(*( volatile unsigned int*)(0xFC04C014))

// 调试开关
// #define CAN_DEBUG
#ifdef CAN_DEBUG
# define can_printf(x...) rt_printf(x)
#else
# define can_printf(x...)
#endif


// 打印报文
#ifdef CAN_DEBUG
# define can_print_mem(x...) print_mem_time(x)
#else
# define can_print_mem(x...)
#endif

/*------------------------------ 类型结构 -------------------------------------
*/
typedef enum
{
	CAN_1,
	CAN_2,
	CAN_RES
}can_type;

//CANFD 基地址
static unsigned int g_rt_canfd_baseaddr[RT_CAN_NUM][RT_CAN_DEV_TYPE]=
{
	{RT_M_CAN0, RT_M_RAM0, RT_M_TOP0, RT_M_DMA0},
	{RT_M_CAN1, RT_M_RAM1, RT_M_TOP1, RT_M_DMA1},
	{RT_M_CAN2, RT_M_RAM2, RT_M_TOP2, RT_M_DMA2},
	{RT_M_CAN3, RT_M_RAM3, RT_M_TOP3, RT_M_DMA3},

};

// 保证所有结构的大小都是4的倍数
//长帧缓冲区
struct can_longframe_buf
{
	unsigned char head;//头位置
	unsigned char tail;//尾位置
	unsigned char reserverd[2];
	unsigned char buf[CAN_LONGFRAME_NUM][CAN_LONGFRAME_LEN];
};

//缓冲区描述符
struct can_buf
{
	unsigned char head;			//头位置
	unsigned char tail;			//尾位置
	unsigned char frameno;     	//帧序号  
	unsigned char reserverd;
	unsigned char buf[CAN_FRAME_NUM][CAN_FRAME_LEN];
};


//CAN统计信息数据结构
struct can_dev_stats{
	uint32_t rx_shortframes;	//接收短帧数
	uint32_t tx_shortframes;	//发送短帧数
	uint32_t rx_longframes;	//接收长帧数
	uint32_t tx_longframes;	//发送长帧数
	uint32_t rx_dropped;		//接收缓冲区满溢出次数 
	uint32_t tx_dropped;		//发送缓冲区满溢出次数 
	uint32_t hw_bus_errors;
	uint32_t overrun;
	uint32_t max_mbcnt;		//统计最大的未处理的MB个数
	uint32_t max_proctime;		//处理MB的最大时间	
};


#if 0
//短帧描述符
struct can_shortframe_des
{
	unsigned char info;
	unsigned char flag1;
	unsigned char srcaddr;
	unsigned char dstaddr;
	unsigned char frameno;
	unsigned char data[8];
	unsigned char reserved[3];	
};
#endif


//时间戳差值数据结构
struct can_timestamp
{
	unsigned short timestamp; //时间戳差值，该差值是指当前时间戳与有数据的MB的时间戳差值
	short caniflg_bit;		  //MB下标即是那一个MB	
};

//flexcan 设备数据结构
struct can_dev
{	
	int can_sock;
	uint32_t no;
	uint32_t base_addr;
	
	struct can_dev_stats stats;			//网络统计信息
	
	struct can_timestamp ts[CAN_MB]; //记录各时间戳差值
	struct can_buf tx_buf[CAN_PRIO_MAX];						//发送缓冲区
	struct can_buf rx_buf[CAN_PRIO_MAX];						//接收缓冲区
	struct can_longframe_buf longframe_buf_rx[CAN_PRIO_MAX];	//接收长帧缓冲区
};


/* Message type access macros.*/
#define FLEXCAN_SET_MODE_RETRIES  255

/* Message Buffer 0  configure as Tx */
#define SEND_BUF		15
#define SEND_BUF_BIT	(1<<SEND_BUF)

/* Structure of the message buffer */
struct can_mb 
{
	volatile u32	can_dlc;
	volatile u32	can_id;
	u8				data[8];
};

struct can_regs 
{

	volatile u32  canmcr;           /* FLEXCAN 0x00 */
	volatile u32  canctrl;          /* FLEXCAN 0x04 */
	volatile u32  cantimer;         /* FLEXCAN 0x08 */
	volatile u32  reserved1;
	volatile u32  canrxgmsk;        /* FLEXCAN 0x10 */
	volatile u32  canrx14msk;       /* FLEXCAN 0x14 */
	volatile u32  canrx15msk;       /* FLEXCAN 0x18 */
	volatile u32  canerrcnt;        /* FLEXCAN 0x1C */
	volatile u32  canerrstat;       /* FLEXCAN 0x20 */
	volatile u32  reserved2;
	volatile u32  canimask;         /* FLEXCAN 0x28 */
	volatile u32  reserved3;
	volatile u32  caniflg;          /* FLEXCAN 0x30 */

	volatile u32  reserved4[19];
	struct  can_mb cantxfg[CAN_MB];
	volatile u32  reserved5[448];
	volatile u32 rximr[CAN_MB];

};

/* @clock_src:
	1 = The FLEXCAN clock source is the onchip Bus Clock.
	0 = The FLEXCAN clock source is the chip Oscillator Clock.*/
struct can_platform_data 
{
	unsigned int clock_src; /* FLEXCAN_CLKSRC_BUS or FLEXCAN_CLKSRC_XTAL */
	unsigned int clock_frq; /* can ref. clock, in Hz */
};


/*------------------------------ 全局变量 -------------------------------------
*/
//flexcan设备
int g_can_fd = -1;
static int bexit = 0;
static u8 g_can_tx_call[CAN_BUS_NUM] = {0};
pthread_t can_tid[CAN_BUS_NUM];
pthread_t can_tid_s[CAN_BUS_NUM];
unsigned g_can_mapped_size;
void *g_can_map_base[CAN_BUS_NUM], *g_can_virt_addr[CAN_BUS_NUM]; 

static struct can_dev g_can_dev[CAN_BUS_NUM] __attribute__ ((aligned(4)));

FN_CAN_RECV_CALLBACK g_can_recv_callback;

u8 g_app_buf_tx[CAN_PRIO_MAX][CAN_FRAME_LEN_MAX];	//应用可根据优先级申请的长帧缓冲区

extern int g_print_can;
extern int g_print_can_monitor;

/*------------------------------ 函数声明 -------------------------------------
*/
static void can_soft_recv_data(int sock);
static int _can_set_reset_mode(struct can_dev *dev);
static int _can_set_normal_mode(struct can_dev *dev);
static int _can_set_bittiming(struct can_dev *dev);
static void _can_chipset_init(struct can_dev *dev, int clock_src);

static void _can_app_tx(int _no);
static void _can_app_rx(struct can_dev *dev, struct can_frame *frame);

void _can_isr_0(void);
void _can_isr_1(void);
void _can_isr_err_0(void);
void _can_isr_err_1(void);
int  _can_irq_force(int no);
int _can_irq_clear(int no);
int _can_irq_is_force(int no);

/*------------------------------ 内部函数 -------------------------------------
*/
static int can_soft_send(int sock, struct can_frame frame)
{
	int nbytes;
	int wlen = sizeof(struct can_frame);
	int times = 2;

	while(times --) 
	{
	    nbytes = write(sock, &frame, wlen);
	    if (nbytes != wlen)
	    {
	    	// rt_printf("Send Error frame(nbytes:%d, wlen:%d)\n", nbytes, wlen);
			usleep(200);
	        continue;
	    }
	    else
	    {
	    	//printf("Send frame(nbytes:%d, wlen:%d)\n", nbytes, wlen);
	        return (0);
	    }
	}

	return -1;
}

static int can_send_data(can_type type, unsigned char *buf, int len)
{
    int i, j;
    int cnt;
    int sock;
    int ret = 0;
    struct can_frame frame;

    if(type == CAN_1)
    {
		// DEMO
        sock = g_can_dev[0].can_sock;
        frame.can_id = 0x100;
    }
    else {
		// DEMO
        sock = g_can_dev[1].can_sock;
        frame.can_id = 0x101;
    }

    for(i = 0; i < len; i += 8)
    {
        cnt = len - i;

        if(cnt > 8)
            frame.can_dlc =  8;
        else
            frame.can_dlc = cnt;

        for(j=0; j<frame.can_dlc; j++)
        {
            frame.data[j] = buf[i+j];
        }

        if(can_soft_send(sock, frame) < 0)
        {
            ret = -1;
            break;
        }
    }

    return ret;
}

static void *can_proc_send(void *arg)
{
	int sock = *(int *)arg;

	int index = g_can_dev[0].can_sock == sock ? 0 : 1;
	if (index == 0) {
		prctl(PR_SET_NAME, "can_send_func0");
	} else {
		prctl(PR_SET_NAME, "can_send_func1");
	}

	while(!bexit)
    {
		if(main_mod_is_exit())
		{
			break;
		}

		switch (index) {
		case 0:
		// can_send_data(CAN_1, (unsigned char *)"hello stm32", strlen("hello stm32") - 1);
		_can_app_tx(0);
		break;

		case 1:
		_can_app_tx(1);
		// can_send_data(CAN_2, (unsigned char *)"hello stm32", strlen("hello stm32") - 1);
		break;

		default:
		break;
		}
		// xenomai内核中此处usleep(10)创建第二个线程会出问题
		// 延时太短导致CPU占用？改为1ms就正常了需验证动作时间 
		usleep(1000);
	}

}

static void *can_proc_recv(void *arg)
{
    int nready;
    int maxfd;
    fd_set readfds;
    int sock = *(int *)arg;

    FD_ZERO(&readfds);
    FD_SET(sock, &readfds);
    maxfd = sock;

	int index = g_can_dev[0].can_sock == sock ? 0 : 1;
	if (index == 0) {
		prctl(PR_SET_NAME, "can_rev_func0");
	} else {
		prctl(PR_SET_NAME, "can_rev_func1");
	}
	
    while(!bexit)
    {
		if(main_mod_is_exit())
		{
			break;
		}

        nready = select(maxfd+1, &readfds, NULL, NULL, NULL);
        if(nready < 0)
        {
            perror("can select");
            break;
        }
        else if(nready == 0)
        {
            continue;
        }

        /* data is ready */
        if(FD_ISSET(sock, &readfds))
        {
            can_soft_recv_data(sock);
        }
        else { ; }
    }
}

static int can_open(char *can_name)
{
	struct ifreq ifr;
    struct sockaddr_can addr;
	int sock;
	int ret = -1;
	int loopback = 0;
//	struct can_filter rfilter[1];
	
    /* open socket */
    sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(sock < 0)
    {
        return ret;
    }
	
    strcpy(ifr.ifr_name, can_name);
    if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
    {
        goto err_can_open;
    }
	addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
  //  fcntl(sock, F_SETFL, O_NONBLOCK);
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        goto err_can_open;
    }

	//close loopback
	setsockopt(sock, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
/*
	rfilter[0].can_id = 0x12;
	rfilter[0].can_mask = CAN_SFF_MASK;
	setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
*/
	return sock;

err_can_open:
	close(sock);	
    return ret;
}

static int can_soft_recv(int sock, struct can_frame *frame)
{
	int nbytes;

	nbytes = read(sock, frame, sizeof(struct can_frame));
	if(nbytes)
	{
		;//printf("[can_recv]dlc = %d, nbytes = %d\n", frame->can_dlc, nbytes);
	}

	return nbytes;
}

static void can_soft_recv_data(int sock)
{
    static unsigned char tail = 0;
    int i;
    int can_id;
    unsigned char can_dlc;
    unsigned char *data;
    struct can_frame frame;
    int index = g_can_dev[0].can_sock == sock ? 0 : 1;

    if(can_soft_recv(sock, &frame) < 0)
        return ;


    frame.can_id = frame.can_id&CAN_EFF_MASK; 
    can_dlc = frame.can_dlc;
    data = frame.data;

    // printf("CAN%d dlc = %d, can_id = %x\ndata:", index,frame.can_dlc, frame.can_id);
    // for(i=0; i<frame.can_dlc; i++)
    //     printf("0x%02x ", frame.data[i]);
    // printf("\n");

	_can_app_rx(&g_can_dev[index],&frame);

}

/*------------------------------ 外部函数 -------------------------------------
外部函数供其它实体文件引用，必须仔细检查传入参数的合法性.
*/
int can_init(void)
{
    struct can_dev *dev; 
    int i;
	off_t target;
	unsigned page_size, offset_in_page;
    unsigned width = 8 * sizeof(int);

	g_can_mapped_size = page_size = sysconf(_SC_PAGESIZE);
    offset_in_page = (unsigned)target & (page_size - 1);
    if (offset_in_page + width > page_size) {
		/* This access spans pages.
		 * Must map two pages to make it possible: */
		g_can_mapped_size *= 2;
	}

	g_can_fd = open("/dev/mem",  O_RDWR | O_SYNC);
    if (g_can_fd < 0)  
    {
        printf("open(/dev/mem) failed.\n");    
        return -1;
    }
    fflush(stdout);

	//初始化缓冲区
	memset(g_can_dev,0,sizeof(g_can_dev));
	
	for(i=0; i<CAN_BUS_NUM; i++)
	{
		dev = &g_can_dev[i];
		dev->no = i;
		target = g_rt_canfd_baseaddr[i][0];

		if(i==0)
		{
			/* CAN0 */
			g_can_map_base[i] = mmap (NULL, g_can_mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_can_fd, target & ~(off_t)(page_size - 1));
			if (g_can_map_base[i] == (void *)-1)
			{
				printf ("can[%d] dev null pointer!\n", i);
			}
			else
			{
				printf ("BSP can[%d] map Successfull!\n", i);
			}
			fflush(stdout);
			
			dev->base_addr = g_can_map_base[i];
				
		}
		else 
		{
			/* CAN1 */
			g_can_map_base[i] = mmap (NULL, g_can_mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, g_can_fd, target & ~(off_t)(page_size - 1));
			if (g_can_map_base[i] == (void *)-1)
			{
				printf ("can[%d] dev null pointer!\n", i);
			}
			else
			{
				printf ("BSP can[%d] map Successfull!\n", i);
			}
			fflush(stdout);
			
			dev->base_addr = g_can_map_base[i];
			
		}
		
		/* set chip into reset mode */
		_can_set_reset_mode(dev);
		_can_set_bittiming(dev);

		// 申请实时中断
		if(i == 0)
		{
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 0,CFG_INT_LEVEL_CAN,_can_isr_0,"can_isr_0");
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 1,CFG_INT_LEVEL_CAN,_can_isr_err_0,"can_isr_err_00");
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 3,CFG_INT_LEVEL_CAN,_can_isr_err_0,"can_isr_err_01");
		}
		else
		{
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 4,CFG_INT_LEVEL_CAN,_can_isr_1,"can_isr_1");
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 5,CFG_INT_LEVEL_CAN,_can_isr_err_1,"can_isr_err_10");
			rt_request_irq(CFG_CAN_VECTOR_BEGIN + 7,CFG_INT_LEVEL_CAN,_can_isr_err_1,"can_isr_err_11");
		}

		// 获取CAN设备句柄
		if (i == 0) {
			g_can_dev[i].can_sock = can_open("can0");
		} else {
			g_can_dev[i].can_sock = can_open("can1");
		}

		// 创建CAN设备接收线程
		if (0 != pthread_create(&can_tid[i], NULL, can_proc_recv, (void *)&g_can_dev[i].can_sock))
		{
			return -2;
		}

		// 创建CAN设备发送线程
		if (0 != pthread_create(&can_tid_s[i], NULL, can_proc_send, (void *)&g_can_dev[i].can_sock))
		{
			return -3;
		}

		/* init and start flexcan */
		_can_chipset_init(dev, 0);
		_can_set_normal_mode(dev);		
	}

	return 0;	
}


int can_exit(void)
{
	int i = 0;
	// exit can recv thread
	bexit = 1;
	for (i = 0; i < CAN_BUS_NUM; i++) {
		pthread_join(can_tid[i], NULL);
		pthread_join(can_tid_s[i], NULL);

		if (g_can_map_base[i]) {
			if (munmap(g_can_map_base, g_can_mapped_size) == -1) {
				printf("can[%d] dev munmap failed!", i);
				return -1;
			}
		}

		if (g_can_dev[i].can_sock >= 0) {
			close(g_can_dev[i].can_sock);
		}
	}

	if (g_can_fd >= 0)
    {
        close(g_can_fd);
        g_can_fd = -1;
    }
	
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 0);
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 1);
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 3);
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 4);
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 5);
	rt_free_irq(CFG_CAN_VECTOR_BEGIN + 7);

	return 0;
}


int can_regester_recv_callback(FN_CAN_RECV_CALLBACK fn)
{
	g_can_recv_callback = fn;

	return 0;
}

u8 * can_request_tx_buf(u8 type)
{
	int prior;
	
	//提取优先级
	prior=(type >> 6 ) & CAN_FRAME_MASK_PRIOR; 

	return g_app_buf_tx[prior];
}

int can_send(u32 no,u8 *buf)
{
 	struct can_dev *dev; 
	struct can_mb *pfm; 
	
	int i,sf_num,sf_len ;
	int frame_mark; 		// 帧标识
	unsigned char prior;	//应用优先级
	unsigned char *p;

	u32 len;

	// 检查参数
	if(no >= CAN_BUS_NUM)
	{
		return -1;
	}
	if(buf == NULL)
	{
		return -2;
	}

	// 检查地址
	if(buf[1]>= CAN_BUS_ADDR_NUM || buf[2] >= CAN_BUS_ADDR_NUM)
	{
		return -5;
	}
	// 检查长度
	len = buf[3];
	if(len >  CAN_LONGFRAME_DATA_LEN)
	{
		return -6;
	}

	dev = &g_can_dev[no];
	
	//提取优先级
	prior=(buf[0] >> 6 ) & CAN_FRAME_MASK_PRIOR; 

	// 将长帧转换为短帧
	//计算需要分为多少帧短帧	
	sf_num=(len + CAN_FRAME_DATA_LEN - 1)/CAN_FRAME_DATA_LEN;	
	if(sf_num == 0)
	{
		sf_num = 1;
	}
	
	//空间够吗？	
	if(CAN_BUF_SPACE(&dev->tx_buf[prior], CAN_FRAME_NUM) < sf_num)
	{
		//发送溢出次数
		dev->stats.tx_dropped++;
		return -7;
	}	

	// 打印报文
	if(g_print_can)
	{
		print_msg("TX_CAN:",buf,len+CAN_LONGFRAME_HEAD_LEN);
	}
	
	//帧序号递加
	dev->tx_buf[prior].frameno++;

	i=0;
	p= buf + CAN_LONGFRAME_HEAD_LEN;
	while(i<sf_num)
	{
		// 短帧数据长度
		sf_len = len>=CAN_FRAME_DATA_LEN?CAN_FRAME_DATA_LEN:len;

		// 帧标识
		if(sf_num == 1)
		{
			frame_mark = CAN_FRAME_SINGLE;
		}
		else
		{
			if(i == 0)
			{
				frame_mark = CAN_FRAME_BEGIN;
			}
			else if(i == (sf_num - 1))
			{
				frame_mark = CAN_FRAME_END ;
			}
			else
			{
				frame_mark = CAN_FRAME_MIDDLE;
			}
		}
		
		//指向当前头位置缓冲区
		pfm=(struct can_mb *)dev->tx_buf[prior].buf[dev->tx_buf[prior].head];
		
		//结构信息
		pfm->can_dlc=sf_len;//MB_CNT_CODE(0x08)|(1 << 21)|(1 << 22)|(sf_len << 16) 

		// 帧ID
		pfm->can_id=  (buf[0] << CAN_FRAME_OFFSET_TYPE)
					| (buf[1] << CAN_FRAME_OFFSET_DST)
					| (buf[2] << CAN_FRAME_OFFSET_SRC)
					| (frame_mark << CAN_FRAME_OFFSET_MARK)
					| (dev->tx_buf[prior].frameno & CAN_FRAME_MASK_SN);

		// 数据
		memcpy(pfm->data, p, sf_len);
		len -= sf_len;	//剩余多少数据
		p   += sf_len;	//调整数据指针

		//头下标往后移
		dev->tx_buf[prior].head++;
		
		//下一短帧	
		i++;
	}

	//统计发送长帧
	dev->stats.tx_longframes++;	

	// 启动发送
	_can_irq_force(no);

	return (buf[3] + CAN_LONGFRAME_HEAD_LEN);		
}


int can_recv(u32 no,u8 *buf,u32 len)
{
	 struct can_dev *dev; 
	int i;
	int framelen;

	// 检查参数
	if(no >= CAN_BUS_NUM)
	{
		return -1;
	}
	if(buf == NULL)
	{
		return -2;
	}

	dev = &g_can_dev[no];
	
	//从0优先级开始，读取接收缓冲区的数据
	for(i=0;i<CAN_PRIO_MAX;i++)
	{
		//对应的长帧缓冲区没有长帧
		if(CAN_BUF_EMPTY(&dev->longframe_buf_rx[i]))
			continue;
	
 		//长帧长度
		framelen=dev->longframe_buf_rx[i].buf[dev->longframe_buf_rx[i].tail][CAN_LONGFRAME_HEAD_LEN - 1] + CAN_LONGFRAME_HEAD_LEN;

		//拷贝数据到用户空间			
		if(framelen <= len)	
		{
			memcpy(buf, dev->longframe_buf_rx[i].buf[dev->longframe_buf_rx[i].tail], framelen);
			
			//调整尾位置				
			dev->longframe_buf_rx[i].tail = (dev->longframe_buf_rx[i].tail+1) & (CAN_LONGFRAME_NUM-1);		
		}
		else
		{
			rt_printf("can_recv:framelen=%d, len=%d\r\n",framelen,len);
			framelen=-3;		
		}
	
		return framelen;			
	}
	

	return 0;
}


int can_stat(void)
{
	int i=0;
	
	rt_printf("flexcan communicate stat\r\n");
	for(i=0;i<CAN_BUS_NUM;i++)
	{
		rt_printf("flexcan%d:\r\n",i);
		rt_printf("tx_longframes:\t%u\r\n",g_can_dev[i].stats.tx_longframes);
		rt_printf("rx_longframes:\t%u\r\n",g_can_dev[i].stats.rx_longframes);
		rt_printf("tx_shortframes:\t%u\r\n",g_can_dev[i].stats.tx_shortframes);
		rt_printf("rx_shortframes:\t%u\r\n",g_can_dev[i].stats.rx_shortframes);
		rt_printf("tx_dropped:\t%u\r\n",g_can_dev[i].stats.tx_dropped);	
		rt_printf("rx_dropped:\t%u\r\n",g_can_dev[i].stats.rx_dropped);
		rt_printf("hw_bus_errors:\t%u\r\n",g_can_dev[i].stats.hw_bus_errors);
		rt_printf("overrun:\t%u\r\n",g_can_dev[i].stats.overrun);
	}
	
	return 0;	
	
}


int can_stat_reset(void)
{
	int i=0;
	
	for(i=0;i<CAN_BUS_NUM;i++)
	{
		memset(&g_can_dev[i].stats,0,sizeof(g_can_dev[i].stats));
	}

	return 0;
}


/*------------------------------ 内部函数 -------------------------------------
内部函数以下划线‘_’开头，不需要检查参数的合法性.
*/
/******************************************************************************
函数名称：	_can_set_reset_mode
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	复位FLEXCAN 
参数说明：	
		dev: flexcan 设备	 
			 				
返回值：成功返回0，失败返回1	 
修改记录：	
*/
static int _can_set_reset_mode(struct can_dev *dev)
{
	// TODO: ocean

	return 1;
}

/******************************************************************************
函数名称：	_can_set_normal_mode
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	设置正常模式 
参数说明：	
		dev: flexcan 设备	 
			 				
返回值：成功返回0，失败返回1		 
修改记录：	
*/
static int _can_set_normal_mode(struct can_dev *dev)
{
	// TODO: ocean
	
	return 1;
}


/******************************************************************************
函数名称：	_can_set_bittiming
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	波特率设置函数 

使用外部晶振50M
配置为500K:
	reg = CANCTRL_PRESDIV(9) | CANCTRL_RJW(0); 
	reg |= (CANCTRL_PROPSEG(2) | 
		CANCTRL_PSEG1(3) |
		CANCTRL_PSEG2(1) |
		CANCTRL_SAMP(0)); 
	regs->canctrl |= reg;		
配置为1M:	
	reg = CANCTRL_PRESDIV(4) | CANCTRL_RJW(0); 
	reg |= (CANCTRL_PROPSEG(3) | 
		CANCTRL_PSEG1(2) |
		CANCTRL_PSEG2(1) |
		CANCTRL_SAMP(0)); 
	regs->canctrl |= reg;	
参数说明：	
			dev: flexcan 设备	 
			 				
返回值：	返回0 
修改记录：	
*/
static int _can_set_bittiming(struct can_dev *dev)
{
	/* Clear the old bittiming */
	char cmd_buf[256] = {0x00};
	sprintf(cmd_buf, "ip link set can%d down", dev->no);
	system(cmd_buf);

	/* 设置队列宽度 */ 
	memset(cmd_buf, 0, sizeof(cmd_buf));
	sprintf(cmd_buf, "ip link set can%d qlen %d", dev->no, 100);
	system(cmd_buf);

	/* 配置波特率为1M */
	memset(cmd_buf, 0, sizeof(cmd_buf));
	sprintf(cmd_buf, "ip link set can%d type can bitrate %d loopback off restart-ms %d", dev->no, 1000000, 100);
	system(cmd_buf);

	/* 启动can设备 */
	memset(cmd_buf, 0, sizeof(cmd_buf));
	sprintf(cmd_buf, "ip link set can%d up", dev->no);
	system(cmd_buf);
	return 0;
}


/******************************************************************************
函数名称：	_can_chipset_init
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	初始化flexcan 
参数说明：	
			dev: flexcan 设备
			clock_src: 时钟源,0表示外部晶振，1表示内部总线时钟		 
			 				
返回值：	 
修改记录：	
*/
/*
 * initialize flexcan:
 *   - set clock source
 *   - set output mode
 *   - set baudrate
 *   - enable interrupts
 *   - start operating mode
 */
static void _can_chipset_init(struct can_dev *dev, int clock_src)
{

}

static void _can_app_tx(int _no)
{
	int sock;
	int i=0;
	struct can_mb *pfm;
	struct can_frame frame;

	struct can_dev *dev = &g_can_dev[_no];

	// if(g_can_tx_call[_no] == 0)  
		// return;
		
	// g_can_tx_call[_no] = 0;

	for(i=0;i<CAN_PRIO_MAX;i++)
	{
		//对应优先级的缓冲区是否有数据
		if(CAN_BUF_EMPTY(&dev->tx_buf[i]))
		{
			continue;
		}

		//当前位置的缓冲区
		pfm=(struct can_mb *)dev->tx_buf[i].buf[dev->tx_buf[i].tail];

		frame.can_id  = pfm->can_id|CAN_EFF_FLAG;	// 使用扩展帧ID
		frame.can_dlc = pfm->can_dlc;
		memcpy(frame.data,pfm->data,sizeof(frame.data));

		sock = g_can_dev[_no].can_sock;
		if(can_soft_send(sock, frame) < 0)
		{
			rt_printf("%s send err!\r\n", __func__);
			break;
		}

		//调整尾指针
		dev->tx_buf[i].tail++; 
		
		//统计发送短帧总数加一
		dev->stats.tx_shortframes++;
	}
}

/******************************************************************************
函数名称：	_can_int_tx
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	flexcan发送处理 
参数说明：	
			dev: flexcan 设备	 
			 				
返回值：  
修改记录：	
*/
static void _can_int_tx(struct can_dev *dev)
{
	int i=0;
	struct can_mb *pfm;
	int txbuf = SEND_BUF;
	volatile struct can_regs *regs = (volatile struct can_regs *)dev->base_addr;	
	
	for(i=0;i<CAN_PRIO_MAX;i++)
	{
		int j=0;
		unsigned int  code=0;
		
		//对应优先级的缓冲区是否有数据
		if(CAN_BUF_EMPTY(&dev->tx_buf[i]))
		{
			continue;
		}
		
		//当前位置的缓冲区
		pfm=(struct can_mb *)dev->tx_buf[i].buf[dev->tx_buf[i].tail];
		
		//检查是否可以发送. code==8说明上一次成功发送完毕，code==0是第一次将CODE配置0了即是MB_CNT_CODE(0)
		code= (regs->cantxfg[txbuf].can_dlc >> 24) & 0x0F;
		if(!((code==8) || (code==0)))
		{ 
			//rt_printf("bus is busy\r\n");
			break;
		}
		
		//写数据到寄存器
		regs->cantxfg[txbuf].can_dlc=pfm->can_dlc;
		regs->cantxfg[txbuf].can_id=pfm->can_id;

		for(j=0;j<8;j++)
		{
			regs->cantxfg[txbuf].data[j]=pfm->data[j];	
		}
		
		/*Control/status word to hold Tx MB active */
		regs->cantxfg[txbuf].can_dlc |= MB_CNT_CODE(0x0c);

		//调整尾指针
		dev->tx_buf[i].tail++; 
		
		//统计发送短帧总数加一
		dev->stats.tx_shortframes++;
 
		break;
	}	
}


/******************************************************************************
函数名称：	_can_frame_short2long
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	短帧组长帧 
参数说明：	
			dev: flexcan 设备
			prior: 优先级	 
			 				
返回值：  
修改记录：	
*/
static int _can_frame_short2long(struct can_dev *dev, int prior)
{
	static unsigned char pos_rec[CAN_FRAME_NUM];
	int pos_index;
	int i,len,is_deal;
	struct can_mb *pfm;
	struct can_mb *pfmtmp;
	unsigned char *pd,*p;
	unsigned char tmppos=dev->rx_buf[prior].head-1;
	unsigned char srcaddr;
	unsigned char dstaddr;
	unsigned char frameno;
	unsigned char frame_type;
	unsigned char frame_len;
	unsigned int frame_mark;
	unsigned char srcaddrtmp;
	unsigned char dstaddrtmp;
	unsigned char framenotmp;	
	unsigned char frame_type_tmp;

	//结束帧指针
	pfm=(struct can_mb *)dev->rx_buf[prior].buf[tmppos];
	
	srcaddr=(pfm->can_id >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC;
	dstaddr=(pfm->can_id >> CAN_FRAME_OFFSET_DST) & CAN_FRAME_MASK_DST;
	frameno=pfm->can_id & CAN_FRAME_MASK_SN;
	frame_type=(unsigned char)(pfm->can_id >> CAN_FRAME_OFFSET_TYPE) & CAN_FRAME_MASK_TYPE;
	frame_len = pfm->can_dlc & CAN_FRAME_MASK_LEN;//(pfm->can_dlc >> CAN_FRAME_OFFSET_LEN) & CAN_FRAME_MASK_LEN;

	// 查找起始帧
	pos_index = 0;
	for(i=0;i<CAN_FRAME_NUM;i++)
	{
		// 短帧
		pfmtmp=(struct can_mb *)dev->rx_buf[prior].buf[tmppos];
		frame_mark = (pfmtmp->can_id >> CAN_FRAME_OFFSET_MARK)& CAN_FRAME_MASK_MARK;
		srcaddrtmp = (pfmtmp->can_id >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC;
		dstaddrtmp = (pfmtmp->can_id >> CAN_FRAME_OFFSET_DST) & CAN_FRAME_MASK_DST;
		framenotmp = pfmtmp->can_id & CAN_FRAME_MASK_SN;		
		frame_type_tmp = (unsigned char)(pfmtmp->can_id >> CAN_FRAME_OFFSET_TYPE) & CAN_FRAME_MASK_TYPE;
		
		// 是要找的短帧
		if((srcaddr == srcaddrtmp ) && ( dstaddr==dstaddrtmp) && (frameno==framenotmp) && (frame_type == frame_type_tmp))
		{
			// 记录短帧位置
			pos_rec[pos_index++] = tmppos;
			
			// 找到起始帧
			if((frame_mark  == CAN_FRAME_BEGIN) || (frame_mark == CAN_FRAME_SINGLE) )	
			{
				break;
			}
		}			
		
		// 前一短帧
		tmppos--;
	}

	if(pos_index == 0)
	{
		rt_printf("_can_frame_short2long:pos_index=%d\r\n",pos_index);
		dev->stats.rx_dropped++;
		return -1;
	}
	if(i == CAN_FRAME_NUM)
	{
	#if 0
		rt_printf("_can_frame_short2long:i=%d,pos_index=%d.\r\n",i,pos_index);
	#endif
		dev->stats.rx_dropped++;
		return -11;
	}

	// 检查长度
	len = frame_len + (pos_index - 1)*CAN_FRAME_DATA_LEN;
	if(len > CAN_LONGFRAME_DATA_LEN)
	{
		rt_printf("_can_frame_short2long:i=%d\r\n",i);
		dev->stats.rx_dropped++;
		return -2;
	} 
	
	//长帧缓冲区首指针	
	pd=dev->longframe_buf_rx[prior].buf[dev->longframe_buf_rx[prior].head];
	p = pd;
	
	// 长帧头
	p[0] = (pfmtmp->can_id >> CAN_FRAME_OFFSET_TYPE);
	p[1] = dstaddrtmp;
	p[2] = srcaddrtmp;
	p[3] = len;

	// 长帧数据
	p += CAN_LONGFRAME_HEAD_LEN;
	while(pos_index--)
	{
		len = pos_index == 0 ? frame_len : 8;
		pfmtmp=(struct can_mb *)dev->rx_buf[prior].buf[pos_rec[pos_index]];
		memcpy(p, pfmtmp->data, len);

		// 置帧空标志
		pfmtmp->can_dlc = 0;

		p+=8;
	}

	// 打印报文
	if(g_print_can)
	{
		print_msg("RX_CAN:",pd,pd[3] + CAN_LONGFRAME_HEAD_LEN);
	}

	// 回调处理此长帧
	is_deal = 0;
	if(g_can_recv_callback)
	{
		is_deal = g_can_recv_callback(dev->no,pd);
	}

	// 如果此长帧没有处理，调整头位置
	if(is_deal != 1)
	{
		if(CAN_BUF_SPACE(&dev->longframe_buf_rx[prior], CAN_LONGFRAME_NUM) == 0)
		{
			dev->stats.rx_dropped++;
			rt_printf("长帧溢出\r\n");
		}
		else
		{
			dev->longframe_buf_rx[prior].head=(dev->longframe_buf_rx[prior].head+1) & (CAN_LONGFRAME_NUM-1);
		}

		// 唤醒主循环处理此长帧
		mainloop_wakeup();
	}

	return 0;
}


/******************************************************************************
函数名称：	_can_int_rx
函数版本：	01.01
创建作者：	xxxxxx
创建日期：	2010-09-25 
函数说明：	flexcan接收中断处理 
参数说明：	
			dev: flexcan 设备
			i: 表示第几个接收MB	 
			 				
返回值：  
修改记录：	
*/
void _can_bus_monitor(u8 *buf)
{
	static s8 str[128];
	s8 *p;
	int i;

	sprintf(str,"CAN_RS:");
	p = str + 7;
	for(i=0;i<16;i++)
	{
		sprintf(p,"%02x ",buf[i]);
		p += 3;
	}

	sprintf(p,"\r\n");

	rt_printf(str);
	
}

static void _can_app_rx(struct can_dev *dev, struct can_frame *frame)
{
	struct can_mb *pfm;
	
	int ctrl = frame->can_dlc;
	int canid= frame->can_id;
	u32 prior=(canid >> CAN_FRAME_OFFSET_PRIOR) & 0x03;
	u32 srcaddr = (canid >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC;
	int k;

	// 取短帧BUF
	pfm=(struct can_mb *)dev->rx_buf[prior].buf[dev->rx_buf[prior].head];
	if(pfm->can_dlc)
	{
	#if 0
		print_mem("CAN_BUF_FULL: ",(u8*)pfm,16);
	#endif
		dev->stats.overrun++;
	}
	
	// 得到内容
	pfm->can_dlc = ctrl;
	pfm->can_id = frame->can_id;
	for (k = 0; k < 8; k++)
		pfm->data[k] = frame->data[k];

	// 如果总线监视，打印短帧
	if(g_print_can_monitor)
	{
		_can_bus_monitor((u8*)pfm);
	}

	// 如果是自己发送的帧，直接返回
	if(srcaddr == 0)
	{
		// 置帧空标志
		pfm->can_dlc = 0;
		return;
	}
	
	//统计接收短帧总数
	dev->stats.rx_shortframes++;
	
	//调整当前位置
	dev->rx_buf[prior].head++;	

	//是结束帧就开始组长帧
	if(((canid >> CAN_FRAME_OFFSET_MARK) & CAN_FRAME_MASK_MARK) < 0x02)
	{		
		//统计接收长帧总数
		dev->stats.rx_longframes++;
		
		//短帧组长帧
		_can_frame_short2long(dev, prior);
	}
}


static void _can_int_rx(struct can_dev *dev, int i)
{
	volatile struct can_regs *regs =  (volatile struct can_regs *)dev->base_addr;
	struct can_mb *mb =  (struct can_mb *)&regs->cantxfg[i];
	struct can_mb *pfm;
	
	int ctrl = mb->can_dlc;
	int canid=mb->can_id;
	u32 prior=(canid >> CAN_FRAME_OFFSET_PRIOR) & 0x03;
	u32 srcaddr = (canid >> CAN_FRAME_OFFSET_SRC) & CAN_FRAME_MASK_SRC;
	int k;

	// 取短帧BUF
	pfm=(struct can_mb *)dev->rx_buf[prior].buf[dev->rx_buf[prior].head];
	if(pfm->can_dlc)
	{
	#if 0
		print_mem("CAN_BUF_FULL: ",(u8*)pfm,16);
	#endif
		dev->stats.overrun++;
	}
	
	// 得到内容
	pfm->can_dlc = ctrl;
	pfm->can_id = mb->can_id;
	for (k = 0; k < 8; k++)
		pfm->data[k] =\
		regs->cantxfg[i].data[k];

	// 如果总线监视，打印短帧
	if(g_print_can_monitor)
	{
		_can_bus_monitor((u8*)pfm);
	}

	// 如果是自己发送的帧，直接返回
	if(srcaddr == 0)
	{
		// 置帧空标志
		pfm->can_dlc = 0;
		return;
	}
	
	//统计接收短帧总数
	dev->stats.rx_shortframes++;
	
	//调整当前位置
	dev->rx_buf[prior].head++;	

	//是结束帧就开始组长帧
	if(((canid >> CAN_FRAME_OFFSET_MARK) & CAN_FRAME_MASK_MARK) < 0x02)
	{		
		//统计接收长帧总数
		dev->stats.rx_longframes++;
		
		//短帧组长帧
		_can_frame_short2long(dev, prior);
	}
}


 void _can_isr(int no)
{
	struct can_dev *dev = &g_can_dev[no];
	volatile struct can_regs *regs =  (volatile struct can_regs *)dev->base_addr;
		
	u32 oflags;


	// 得到中断标志
	oflags = regs->caniflg;

	// 处理发送软中断
	if(_can_irq_is_force(no))
	{
		// 应用程序启动发送
		oflags |= SEND_BUF_BIT;
		_can_irq_clear(no);
	}

	// 检查发送标志
	if(oflags & SEND_BUF_BIT)
	{
		// 清发送中断
		regs->caniflg = SEND_BUF_BIT;
		oflags &= (~SEND_BUF_BIT);
		// 发送一帧
		_can_int_tx(dev);
	}

	// 处理接收中断	
	// 硬件overrun
	if(oflags & 0x80)
	{
		dev->stats.overrun++;
	}

	// 接收一帧
	if(oflags & 0x20)
	{
		_can_int_rx(dev,0);
	}

	// 清接收中断标志
	regs->caniflg = oflags;		

	return ;
}


void _can_isr_err(int no)
{
	struct can_dev *dev = &g_can_dev[no];
	volatile struct can_regs *regs = (struct can_regs *)dev->base_addr;

	u32 errstate = regs->canerrstat;
	regs->canerrstat = errstate;

	dev->stats.hw_bus_errors++;//统计出错信息
		
	return ;		
}


void _can_isr_0(void)
{
	
_can_isr(0);
}
void _can_isr_1(void)
{
	
_can_isr(1);
}


void _can_isr_err_0(void)
{
	
_can_isr_err(0);
}
void _can_isr_err_1(void)
{
	
_can_isr_err(1);
}


int  _can_irq_force(int no)
{
#ifdef __KERNEL__
	uint32_t flags;

	no *= 4;
	rt_irq_save(flags);
	REG_MCF_INTFRCL1 |= 1 << no;
	rt_irq_restore(flags);	
#else
	g_can_tx_call[no] = 1;
#endif
	return 0;
}


int _can_irq_clear(int no)
{
	uint32_t flags;
	
	no *= 4;
	
	rt_irq_save(flags);
	REG_MCF_INTFRCL1 &= ~(1 << no);
	rt_irq_restore(flags);	

	return 0;
}

int _can_irq_is_force(int no)
{
	no *= 4;

	if(REG_MCF_INTFRCL1 & (1 << no))
	{
		return 1;
	}
	else
	{
		return 0;

	}
}


/*------------------------------ 测试函数 -------------------------------------
一个实体文件必须带一个本模块的测试函数来进行单元测试，如果的确不方便在本模块中
进行单元测试，必须在此注明实际的测试位置（例如在哪个实体文件中使用哪个测试函数）.
*/
#define LOOP_BEGIN 	1
int can_test(void)
{
	static unsigned char buf_tx[CAN_LONGFRAME_LEN],buf_rx[CAN_LONGFRAME_LEN];
	static unsigned char loop = LOOP_BEGIN;
	static uint32_t us0 = 0,err_count=0;
	
	uint32_t us1;
	int i;
	int len_tx,len_rx;

	// 1S调用一次
	us1 = ustimer_get_origin();
	if(us1 - us0 < USTIMER_SEC*10)
	{

		return 0;
	}
	us0 = us1;
 	
	// 发送一帧
	memset(buf_tx,0,sizeof(buf_tx));
	buf_tx[0] = loop;
	buf_tx[1] = 1;
	buf_tx[2] = 2;
	buf_tx[3] = loop;
	
	for(i=0; i<buf_tx[3]; i++)
	{
		buf_tx[CAN_LONGFRAME_HEAD_LEN + i] = i;
	}
	len_tx = can_send(0,buf_tx);
//	len_tx = can_send(1,buf_tx);

	// 延时5ms
	ustimer_delay(USTIMER_MS*50);
	
	// 接收一帧
	memset(buf_rx,0,sizeof(buf_rx));
	len_rx = can_recv(0,buf_rx,256);

	if((len_tx == len_rx) && (memcmp(buf_tx,buf_rx,len_tx) == 0))
	{
		rt_printf("can_test ok(%03d,err_count=%d):[len_tx=%d,len_rx=%d]\r\n",loop,err_count,len_tx,len_rx);
	}
	else
	{
		err_count++;
		rt_printf("can_test err(%03d,err_count=%d):[len_tx=%d,len_rx=%d]\r\n",loop,err_count,len_tx,len_rx);
	//	can_print_mem("TX:",buf_tx,len_tx);
	//	can_print_mem("RX:",buf_rx,len_rx);
	}

//	loop++;
	if(loop > CAN_LONGFRAME_DATA_LEN)
	{
		loop = LOOP_BEGIN;

	}
	

	return 0;
}

#endif
/*------------------------------ 文件结束 -------------------------------------
*/

