/******************************************************************************
版权所有：	文件名称：	mb.c
文件名称：	mb.c
文件版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
功能说明：	邮箱驱动
其它说明：
修改记录：
*/
#include "bspconfig.h"
#include "bsp.h"
#include "mb.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <pthread.h>
#include <stdbool.h>

#define CO_IOCTL_GET_REG	1
#define CO_IOCTL_SET_REG	2
#define CO_IOCTL_EXECUTE	3
#define CO_IOCTL_GET_DATA	4
#define CO_IOCTL_SET_DATA	5
#define CO_IOCTL_GET_CONFIGS	6
#define CO_IOCTL_SET_PC		7

#ifndef CO_MB_FIFO_SIZE
#define CO_MB_FIFO_SIZE		32//经测试，只能这么大的buf
#endif

struct co_io {
	uint8_t meta;
	uint16_t metadata;
	uint32_t data[CO_MB_FIFO_SIZE - 1];
	uint8_t len;
};

struct mb_co {
    char                    *name;
    pthread_t               thread_id;
    int                     fd_co; 
    struct co_io            coio;
};

static struct mb_co *pmb;


static inline void dmsg_u8(uint8_t *data, int length, char *str)
{
	int i, j;
	int tmp;

	printf("%s:\n", str);
	for (i = 0; i < (length / 16); i++)
	{
		for (j = 0; j < 16; j++)
			printf("%02x ", data[i * 16 + j]);
		printf("\n");
	}
	tmp = (length / 16) * 16;
	for (i = 0; i < (length % 16); i++)
		printf("%02x ", data[tmp + i]);
	if (length % 16)
		printf("\n");
}


/******************************************************************************
函数名称：	mb_write
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	向邮箱写入数据.
参数说明：	
cmd：命令号
data：写入数据
len:写入数据长度，注意： 如果转入2个uint32_t的数据，那么长度为2，不是8.

返回值：	成功返回0, 失败返回-1
修改记录：	

！！！！！！！！！ 注意： 如果转入2个uint32_t的数据，那么长度为2，不是8.

*/
int mb_write(uint16_t cmd, uint32_t *data, uint8_t len)
{
	return 0;//noted by ygl: 邮箱功能暂时不实现 
	int i;
	int ret;
	struct mb_co *co = NULL;

	if(pmb == NULL)
		return -1;

	if(data == NULL)
		return -1;

	if(len > (CO_MB_FIFO_SIZE - 1))
		return -1;

	co = pmb;

	for (i = 0; i < len; i++)
	   co->coio.data[i] = data[i];

/*
meta =0时，metadata无效，对方收不到metadata值。
meta =为非0时，metadata置数，对方也收到metadata值。
*/
	/* ipc message parameters */
	co->coio.meta = 1;//noted by sunxi: 与裸核，约定为1
	co->coio.metadata = cmd;
	co->coio.len = len;

#if 0	
	for (i = 0; i < co->coio.len; i++)
		printf("%04X ", co->coio.data[i]);
	printf("\r\n");
#endif
	
	ret = ioctl(co->fd_co, CO_IOCTL_SET_DATA, &co->coio);
	if (ret)
		printf("send to %s failed, ret = %d\n",co->name, ret);

	return 0;
}


/******************************************************************************
函数名称：	mb_notice_time_update
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	用邮箱告知时间更新了
参数说明：	

返回值：	成功返回0, 失败返回-1
修改记录：	

*/
int mb_notice_time_update(void)
{

    int ret;
	uint32_t data[31];

	data[0] = MB_CMD_TIME;
	data[1] = MB_CMD_TIME;

	ret = mb_write(MB_CMD_TIME, data, 2);
	if(ret<0)
		printf("mb_write fail!!! ret= %d\n", ret);

	return ret;
}

/******************************************************************************
函数名称：	mb_notice_freqTr_update
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	用邮箱告知频率跟踪更新了
参数说明：	

返回值：	成功返回0, 失败返回-1
修改记录：	

*/
int mb_notice_freqTr_update(void)
{

    int ret;
	uint32_t data[31];

	data[0] = MB_CMD_FREQTR;
	data[1] = MB_CMD_FREQTR;

	ret = mb_write(MB_CMD_FREQTR, data, 2);
	if(ret<0)
		printf("mb_write fail!!! ret= %d\n", ret);

	return ret;
}

/******************************************************************************
函数名称：	mb_notice_RfV_update
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	用邮箱告知AD7616参考电压范围更新了
参数说明：	
no：第n片7616

返回值：	成功返回0, 失败返回-1
修改记录：	

*/
int mb_notice_RfV_update(uint8_t no)
{

    int ret;
	uint32_t data[31];

	data[0] = no;
	data[1] = no;

	ret = mb_write(MB_CMD_RfV, data, 2);
	if(ret<0)
		printf("mb_write fail!!! ret= %d\n", ret);

	return ret;
}


static int co_mb_open(struct mb_co *co, char *name)
{
    int fd_co;


    printf("open co mb dev %s\n", name);

    fd_co = open(name, O_RDWR);
    if (!fd_co) {
        printf("open co dev failed\n");
        return -1;	
    }

    co->name  = name;
    co->fd_co = fd_co;


	return 0;

}


static void *thread_co_test(void *arg)
{
    struct mb_co *co = pmb;
    //int i;
    int ret;


    
    while (1) {

	  sleep(1);

#if 0	  
	  crc++;
  
		 for (i = 0; i < (CO_MB_FIFO_SIZE - 1); i++)
			data[i] = i+crc;

		ret = mb_write(MB_CMD_TIME, data, 31);
		if(ret<0)
			printf("send to %s failed, ret = %d\n",co->name, ret);

#endif

		ret = mb_notice_time_update();
		if(ret<0)
			printf("send to %s failed, ret = %d\n",co->name, ret);	  


	  
    }
    printf("thread co exit\r\n");    
    pthread_exit(NULL);
}


//测试代码
void mb_test(void)
{
	int ret;
	
	if((ret = pthread_create(&pmb->thread_id, NULL, thread_co_test, pmb)) == 0)
		printf("thread co0 create success\r\n");
	else
		printf("thread co0 create fail ret=%d\r\n", ret);

}



/******************************************************************************
函数名称：	mb_init
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	mb初始化.
参数说明：	
					无					
返回值：	成功返回0, 失败返回-1
修改记录：	
*/
int mb_init(void)
{
//	int ret;
	pmb = malloc(sizeof(struct mb_co));

	memset(pmb, 0, sizeof(struct mb_co));


	if(co_mb_open(pmb, "/dev/arv-shmem")) {
		printf("open mb error\r\n");
		return -1;
	}

	
	//mb_test();//sunxi for test


	

	return 0;	
}

/******************************************************************************
函数名称：	mb_exit
函数版本：	01.01
创建作者：	sunxi
创建日期：	2022-05-17
函数说明：	mb反初始化.
参数说明：	
					无					
返回值：	总是返回0.
修改记录：	
*/
int mb_exit(void)
{
	if(pmb)
	{
		if(pmb->fd_co)
		 	close(pmb->fd_co);
	}

	return 0;
}




 
 
 
 
