/********************************************************************
版权所有： 
文件版本： V1.00
文件名称： can_board.c
生成日期： 2020年4月20日
作    者：    oujie
使用范围：

功    能：通过协议与can子板通信处理程序（非硬件确定canid）
更新信息：
更新日志1：
修改者:
修改日期:
修改内容:
修改原因:
*********************************************************************/
/*------------------------------- 头文件 --------------------------------------
*/
#include "head.h"

#ifndef CAN_DISABLE
#ifdef CAN_SLAVE_BOARD
const CAN_BOARD_NAME can_board_name[] = 
{
	{BOARD_TYPE_METERING, "计量板"}
};

#define CAN_NAME_NUM    	(sizeof(can_board_name)/sizeof(can_board_name[0]))


struct can_board_res    can_board[CAN_BOARD_NUM];
u8    can_board_enable;


int get_line_string(char* src_buf, char* dst_buf, u16 len)
{
	u16 i = 0;
	
	while(i < len)
	{
		if(strncmp(&src_buf[i], "\r\n", 2) == 0)
			return (i+2);
		dst_buf[i] = src_buf[i];
		i++;
	}
	return -1;
}

//读n行字符串
int get_part_line(char* src_buf, char* dst_buf, u16 n, u16 line_max)
{
	int len = 0; 
	int i = 0;
	int total_len = 0;

	while(i < n)
	{
		len = get_line_string(src_buf+total_len, dst_buf + i*line_max, line_max);
		if(len == -1)
			break;
		total_len += len;
		i++;
	}
	return i;
}

void Hex2Str( const char *sSrc,  char *sDest, int nSrcLen )
{
    int  i;
    char szTmp[3];
 
    for( i = 0; i < nSrcLen; i++ )
    {
        sprintf( szTmp, "%02X", (unsigned char) sSrc[i] );
        memcpy( &sDest[i * 2], szTmp, 2 );
    }
    return ;
}
 
//十六进制字符串转换为字节流
int HexStr2Bytes(const char* pSrc, unsigned char* pDst, int nSrcLength)   
{   
    int i;
	
    for (i = 0; i < nSrcLength; i += 2)   
    {   
        // 输出高4位   
        if ((*pSrc >= '0') && (*pSrc <= '9'))   
        {   
            *pDst = (*pSrc - '0') << 4;   
        }   
        else   
        {   
            *pDst = (*pSrc - 'A' + 10) << 4;   
        }   
		
        pSrc++;   
		
        // 输出低4位   
        if ((*pSrc>='0') && (*pSrc<='9'))   
        {   
            *pDst |= *pSrc - '0';   
        }   
        else   
        {   
            *pDst |= *pSrc - 'A' + 10;   
        }   
		
        pSrc++;   
        //TRACE("%s",pSrc);   
        pDst++;   
        //TRACE("%s",pDst);   
    }   
	// 返回目标数据长度   
	rt_printf("\r\n");
    return (nSrcLength / 2);   
} 



/******************************************************************************
函数名称：	equ_init_can_file_res
函数版本：	01.00
创建作者：	xxxxxx
创建日期：	2020-04-21
函数说明：	从can板卡资源文件装载can板卡资源。
参数说明：
返回值：	
	0：		成功
	其它：	失败
修改记录：	
*/
u32 chipid[3] = {0};
u32 chipid_hex[3] = {0};

int equ_init_can_file_res(void)
{
	u32 len;
	u8 *buf;
	char* ppos1;
	char* ppos2;
//	u8 line_buf[128] = {0};
	u8 dst_buf[CAN_BOARD_NUM+1][128] = {{0}};
	u8 num, str_len, line_num;
	u8 i = 0;
#ifdef CAN_BOARD_DEBUG
	u8 j = 0;
#endif
	int pfile;
	loff_t pos;
	int slot;
	u8 id_len;

	// 打开文件
	pfile = rt_file_open("/app/data/can_brd.csv",O_RDONLY ,0);
	if(IS_ERR(pfile))
	{
		rt_printf("未找到can_brd.csv文件\r\n");
		return -1;
	}

	// 得到文件长度
	len = rt_file_getfile_size(pfile);
	
	// 分配内存
	buf = rt_malloc(len);
	if((buf) == NULL)
	{
		rt_file_close(pfile,0);
		return -2; 	
	}

	// 读出内容
	pos = 0;
	if(rt_file_read(pfile,buf,len,&pos) != len)
	{
		rt_file_close(pfile,0);
		rt_free(buf);
		return -3;
	}

	// 关闭文件
	rt_file_close(pfile,0);
#ifdef CAN_BOARD_DEBUG
	rt_printf("读can_brd.csv\r\n");
#endif
	num = get_part_line(buf, (char*)dst_buf, CAN_BOARD_NUM+1, sizeof(dst_buf[0]));
	line_num = (num > CAN_BOARD_NUM) ? CAN_BOARD_NUM : num;
#ifdef CAN_BOARD_DEBUG
	rt_printf("行数=%d\r\n", num);
	rt_printf("用于匹配行数=%d\r\n", line_num);
#endif
	#if 1
	for(i=1; i<line_num; i++)//i=1,从第二行获取
	{
#ifdef CAN_BOARD_DEBUG
		rt_printf("%s\r\n",&dst_buf[i][0]);
#endif
		str_len = strlen((char*)&dst_buf[i][0]);
		if(strncmp(&dst_buf[i][0], "ID", 2) == 0)
		{
#ifdef CAN_BOARD_DEBUG
			rt_printf("找到匹配行=%d\r\n", i);
#endif
			ppos1 = strchr((char*)&dst_buf[i][0], ',');
			if(ppos1)
			{
				ppos1++;
				ppos2 = strchr(ppos1, ',');
				if(ppos2)
				{
					id_len = (u32)ppos2 - (u32)ppos1;
#ifdef CAN_BOARD_DEBUG
					rt_printf("id_len=%d\r\n", id_len);
#endif
					if (id_len > (sizeof(can_board[i-1].chip_id)*2))
					{
						rt_printf("第%d行 ID号过长，不能超过32个字符串\r\n", i);
						continue;
					}
					memset(can_board[i-1].chip_id, 0, sizeof(can_board[i-1].chip_id));
					HexStr2Bytes(ppos1, (u8*)can_board[i-1].chip_id, id_len);
#ifdef CAN_BOARD_DEBUG
					for(j=0; j<CHIP_ID_SIZE; j++)
						rt_printf("chip_id[%d]=%x\r\n", j, can_board[i-1].chip_id[j]);	
#endif
				}
				else
					continue;
			}
			else
				continue;
			ppos2 = strchr(ppos1, ',');
			if(ppos2)
			{
				slot = atoi(ppos2+1);
				if(slot >= 0)
				{
					can_board[i-1].slot = slot;
					can_board[i-1].file_have = 1;
					can_board_enable = 1;
#ifdef CAN_BOARD_DEBUG
					rt_printf("can_board[%d].slot=%d\r\n", i-1, can_board[i-1].slot);	
#endif	
				}
				else
					rt_printf("文件板卡号有误\r\n");
			}
			else
				continue;	
		}


#if 0
		for(k=0; k<sizeof(can_board[0].chip_id); k++)
			rt_printf("chip_id[%d]=%d ", k, can_board[i-1].chip_id[k]);
		rt_printf("\r\n");
		rt_printf("can_board[%d].slot=%d\r\n", i-1, can_board[i-1].slot);
#endif
	}
	#endif

	return 0;

}


/******************************************************************************
函数名称：	equ_get_can_slot
函数版本：	01.00
创建作者：	oujie
创建日期：	2020-08-08
函数说明：	通过子板的chipid查找插槽号。
参数说明：
	chip_id	子板id。
	id_size id大小
返回值：	插槽号
修改记录：	
*/
 struct can_board_res* equ_get_can_slot(u8 give_slot, u8 type, u8* chip_id, u8 id_size)
{
	u32 i;

	for(i=0; i<CAN_BOARD_NUM; i++)
	{
		if(can_board[i].file_have && ((give_slot != can_board[0].slot)
		|| (give_slot == 0) || (give_slot == 0xff))) //子板应答卡号为0，需要从发，防止子板复位
		{
			if(memcmp((u8*)can_board[i].chip_id, chip_id, id_size) == 0)
			{
				rt_printf("和文件中的ID匹配\r\n");
				return &can_board[i];
			}
		}
	}	
	return NULL;
}

u8 is_can_slot_valid(u8 i)
{
 	return can_board[i].given_slot;
}

u8 get_can_slot(u8 i)
{
 	return can_board[i].slot;
}

void can_id_printf(void)
{
	u8 i;
	char buf[64] = {0};
	char* name = NULL;

	for(i=0; i<CAN_BOARD_NUM; i++)
	{
		if(can_board[i].given_slot)
		{
			Hex2Str((const char*)can_board[i].chip_id, buf, CHIP_ID_SIZE*4);
			name = get_can_name(can_board[i].type);
			if(name)
				rt_printf("\r\nCAN子板%d：名称    ：%s\r\n", i+1, name);
			else
				rt_printf("\r\nCAN子板%d：名称   ：无\r\n", i+1);
			rt_printf("           ID     ：%s\r\n", buf);
			rt_printf("           板卡号 ：%d\r\n", can_board[i].slot);
		}
		else
			rt_printf("CAN子板%d：无\r\n", i+1);
	}	
}

char* get_can_name(u8 type)
{
	u8 i;
	
	for(i=0; i<CAN_NAME_NUM; i++)
	{
		if(type == can_board_name[i].type)
			return can_board_name[i].name;
	}
	return NULL;
}

int get_can_type_from_slot(u8 slot)
{
	u8 i;
	
	for(i=0; i<CAN_BOARD_NUM; i++)
	{
		if(can_board[i].slot == slot)
		{
			if(can_board[i].type)
			{
				return can_board[i].type;
			}
			else
			{
				return -1;
			}
		}
	}
	return -1;	
}


void can_brd_error_set(void)
{
	u8 i;
	
	for(i=0; i<CAN_BOARD_NUM; i++)
	{
		if(BOARD_TYPE_METERING == can_board[i].type)
		{
			if(can_board[i].slot)
			{
			#if defined CAN_SLAVE_BOARD && defined METERING_ENERGY	
				if(soe_check(EV_CAN_METERING_ERR)==false) 
				{
					soe_record_ev(EV_CAN_METERING_ERR, 1, can_board[i].slot,0,0 );
				}	
			#endif				
			}
		}
	}	
}

void can_brd_error_clear(u8 slot)
{
	u8 type;

	type = get_can_type_from_slot(slot);
	if(BOARD_TYPE_METERING == type)
	{
	#if defined CAN_SLAVE_BOARD && defined METERING_ENERGY	
		if(soe_check(EV_CAN_METERING_ERR)==true) 
		{
			soe_record_ev(EV_CAN_METERING_ERR, 0, slot,0,0 );
		}
	#endif	
	}
}

#endif
#endif

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

















