#include "CM_Com.h"
#include "PFM_Log.h"
#include "CM_Memory.h"
#include "CM_Time.h"
#include "CM_Convert.h"

#if QNX
#include <sys/neutrino.h> /* ThreadCtl BMP绑定CPU*/
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#endif
#define COM1 "/dev/ser1"
#define COM2 "/dev/ser2"
#define COM3 "/dev/ser3"
#define COM4 "/dev/ser4"

#define COM485 "/dev/ser4"

#define COMMAXNUM (2u)

static STRUCT_QNX_FD g_COM[COMMAXNUM] = { {-1,COM3,},{-1,COM4,} };
static CM_UINT16 CM_ComSend(CM_UINT8 comId, IN CM_UINT8* pbuf, CM_UINT16 len);
static CM_INT32 CM_ComRev(CM_UINT8 comId, CM_UINT8* pbuf, CM_UINT16 len);
static ENUM_CM_RETURN CM_ComSendFFFE(CM_UINT8 comId, IN CM_UINT8* pbuf, CM_UINT16 len);
static CM_UINT16 CM_Com_DataRecv(CM_UINT8 comId,OUT CM_UINT8* pBuf, IN CM_UINT32 BufSize);
/**
* @brief 串口数据清空
*/
static ENUM_CM_RETURN CM_Com_Clear(STRUCT_QNX_FD* pCtrl);

/**
* @brief 串口初始化函数
* @param nSpeed 波特率
* @param nBits 数据位
* @details 波特率一般为115200, 数据位一般为8
* @return 返回成功或失败
*/
ENUM_CM_RETURN CM_COM_INIT(CM_UINT32 nSpeed, CM_UINT32 nBits)
{
#if QNX
	/*- 变量初始化 */
	ENUM_CM_RETURN rtnValue = ENUM_CM_FALSE;
	ENUM_CM_RETURN rt_temp = ENUM_CM_FALSE;/*临时返回值*/
	CM_BOOL rv = 0;
	CM_UINT8 rtnFlag = 0u;
	CM_UINT8 i = 0u;
	struct termios options;
	for (i = 0u; i < COMMAXNUM; i++)
	{
		/*- 打开串口*/
		g_COM[i].fd = open(g_COM[i].addr, O_RDWR | O_NOCTTY);/*O_NONBLOCK 非阻塞式 O_NDELAY阻塞式*/
		/*- 如果打开成功，则*/
		if (-1 != g_COM[i].fd)
		{
			rtnFlag++;
			rt_temp = CM_Memset(&options, 0u, sizeof(options), sizeof(options));
			CM_ASSERT(ENUM_CM_TRUE == rt_temp, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_1);
			/*- 获取原有的串口属性的配置*/
			rv = tcgetattr(g_COM[i].fd, &options);
			if (0 != rv)
			{
				MSCP_LOG_MSG("tcgetattr() failed\n");
			}

			options.c_lflag &= ~(ICANON | ECHO | ECHOE);
			/*- CREAD 开启串行数据接收，CLOCAL并打开本地连接模式*/
			options.c_cflag |= CLOCAL | CREAD;
			/*- 先使用CSIZE做位屏蔽*/
			options.c_cflag &= ~CSIZE;

			/*- 传输据位参数*/
			switch (nBits)
			{
			case 5u:
				options.c_cflag |= CS5;
				/*- 跳出 */
				break;
			case 6u:
				options.c_cflag |= CS6;
				/*- 跳出 */
				break;
			case 7u:
				options.c_cflag |= CS7;
				/*- 跳出 */
				break;
			case 8u:
				options.c_cflag |= CS8;
				/*- 跳出 */
				break;
			default:
				CM_ASSERT(0, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_2);
				/*- 跳出 */
				break;
			}
			/*- 无奇偶校验位*/
			options.c_cflag &= ~PARENB;

			/*- slove 0a -> 0d 0a*/
			options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
			options.c_oflag &= ~(ONLCR | OCRNL | ONOCR | ONLRET);

			/*- slove 0x11 0x13*/
			options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);

			/*- slove others*/
			options.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
			options.c_oflag &= ~OPOST;
			options.c_cflag |= CLOCAL | CREAD;
			options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);

			/*- 设置波特率*/
			switch (nSpeed)
			{
			case 2400u:
				(void)cfsetispeed(&options, B2400);
				(void)cfsetospeed(&options, B2400);
				/*- 跳出 */
				break;
			case 4800u:
				(void)cfsetispeed(&options, B4800);
				(void)cfsetospeed(&options, B4800);
				/*- 跳出 */
				break;
			case 9600u:
				(void)cfsetispeed(&options, B9600);
				(void)cfsetospeed(&options, B9600);
				/*- 跳出 */
				break;
			case 115200u:
				(void)cfsetispeed(&options, B115200);
				(void)cfsetospeed(&options, B115200);
				/*- 跳出 */
				break;
			default:
				CM_ASSERT(0, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_3);
				/*- 跳出 */
				break;
			}
			/*- 设置一位停止位 */
			options.c_cflag &= ~CSTOPB;
			/*- 非规范模式读取时的超时时间 */
			options.c_cc[VTIME] = 0u;
			/*- 非规范模式读取时的最小字符数 */
			options.c_cc[VMIN] = 0u;

			/*- tcflush清空终端未完成的输入/输出请求及数据；TCIFLUSH表示清空正收到的数据，且不读取出来 */
			(void)tcflush(g_COM[i].fd, TCIFLUSH);
			if ((tcsetattr((int)g_COM[i].fd, (int)TCSANOW, &options)) != 0)
			{
				MSCP_LOG_MSG("com:%d tcsetattr failed\n", i);
				CM_ASSERT(0, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_4);
			}
			/*初始化成功*/
			else
			{
				/*设置串口号*/
				g_COM[i].Num = i;
				/*初始化FFFE解析结构体*/
				rt_temp = CM_FFFEInit(&g_COM[i].prtclFFFEStru, (COM_UART_BUF_SIZE*COM_UART_MSG_NUM_MAX));
				CM_ASSERT(ENUM_CM_TRUE == rt_temp, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_1, TSCP_DARK_ASSERT_5);
			}
		}
		else
		{
			/*- 无处理*/
		}
	}
    return rtnValue;
#else
    return ENUM_CM_TRUE;
#endif
}
/**
* @brief 串口临机接收线程初始化函数
* @return 无
*/
void CM_Com_RcvOtherThreadInit(void)
{
	ENUM_CM_RETURN rt_temp = ENUM_CM_FALSE;/*临时返回值*/
	CM_BOOL threadrtn = CM_FALSE;
	/*初始化接收队列*/
	rt_temp = CM_MQ_Init(&g_COM[0].MsgQ, (CM_UINT16)COM_UART_MSG_NUM_MAX, (CM_UINT16)COM_UART_BUF_SIZE);
	CM_ASSERT(ENUM_CM_TRUE == rt_temp, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_1);
	/*初始化接收线程*/
	threadrtn = CM_Thread_Create((CM_THREAD_T*)NULL, (CM_THREAD_FUNC_T)t_ComUartRcvThread, "Uart_T", 0, CM_TASK_PRIORITY_80, (CM_Thread_Arg_Struct_T*)(&g_COM[0]));
	MSCP_LOG_MSG("RcvOtherThreadInit:0x%x\r\n",threadrtn);
	CM_ASSERT(CM_TRUE == threadrtn, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_2);
	rt_temp = CM_Com_Clear(&g_COM[0]);
	CM_ASSERT(ENUM_CM_TRUE == rt_temp, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_2, TSCP_DARK_ASSERT_3);
}
/**
* @brief 串口发送函数
* @param comId
* @param pbuf 缓冲区
* @param len 长度
* @return 返回成功或失败
*/
static CM_UINT16 CM_ComSend(CM_UINT8 comId, IN CM_UINT8* pbuf, CM_UINT16 len)
{
	/*- 变量初始化*/
	CM_INT32 ret = 0;
	CM_UINT16 rtnval = 0u;
	if (NULL != pbuf)
	{
		/*TODO 判断返回值*/
		/*lseek(g_COM[comId].fd, 0 , SEEK_SET);*/
		/*如果返回成功-ret返回的是长度*/
		ret = write((int)g_COM[comId].fd, pbuf, (size_t)len);
		if(0 == ret)
		{
			rtnval = 0u;
		}
		else
		{
			rtnval = 1u;
		}
	}
	else
	{
		MSCP_LOG_MSG("com[%d] = %d add %s\r\n",comId,ret,g_COM[comId].addr);
	}
	return rtnval;
}

/**
* @brief 串口接收函数
* @param comId
* @param pbuf 缓冲区
* @param len 长度
* @return 返回成功或失败
*/
static CM_INT32 CM_ComRev(CM_UINT8 comId, CM_UINT8* pbuf, CM_UINT16 len)
{

	CM_INT32  ret = 0;
	fd_set   rset;
	int rv;
	if (NULL != pbuf)
	{
		/*如果返回成功*/
		FD_ZERO(&rset);
		FD_SET(g_COM[comId].fd, &rset);
		rv = select(g_COM[comId].fd + 1, &rset, NULL, NULL, NULL);
		if (rv < 0)
		{
			MSCP_LOG_MSG("select() failed\n");

		}
		else if (rv == 0)
		{
			MSCP_LOG_MSG("select() time out!\n");
		}
		else
		{

			ret = read((int)g_COM[comId].fd, pbuf, (size_t)len);
		}
	}
	else
	{

	}
	return ret;
}
/**
* @brief 串口使用FFFE发送函数
* @param comId
* @param pbuf 缓冲区
* @param len 长度
* @return 返回成功或失败
*/
static ENUM_CM_RETURN CM_ComSendFFFE(CM_UINT8 comId, IN CM_UINT8* pbuf, CM_UINT16 len)
{
	/*- 变量初始化*/
	ENUM_CM_RETURN rtnValue = ENUM_CM_FALSE;
	CM_UINT16 ret = 0u;
	CM_UINT16 fffeLen = 0u;
	CM_UINT8 fffebuf[COM_UART_BUF_SIZE] = { 0u };
	if (NULL != pbuf)
	{
		/*添加FFFE*/
		rtnValue = CM_FFFECode(pbuf, (CM_UINT16)len, fffebuf, &fffeLen);
		if(ENUM_CM_TRUE == rtnValue)
		{
			ret = CM_ComSend(comId,fffebuf,fffeLen);
			if(1u == ret)
			{
				rtnValue = ENUM_CM_TRUE;
				MSCP_LOG_MSG("COM:%d SendSuccess\n",comId);
			}
			else
			{
				rtnValue = ENUM_CM_FALSE;
				MSCP_LOG_MSG("COM:%d SendFail(%d)!\n",comId,ret);
			}
		}
		else
		{
			rtnValue = ENUM_CM_FALSE;
			MSCP_LOG_MSG("COM:%d FFFECodeFail!\n",comId);
			/* nothing to do */
		}
	}
	else
	{
		rtnValue = ENUM_CM_FALSE;
		/* nothing to do */
	}
return rtnValue;
}
/**
* @brief 串口数据接收
* @param comId 串口号
* @param pBuf 接收报文指针
* @param BufSize 接收报文缓冲区大小
* @return 接收报文长度
* - 正整数 接收报文长度
* - 0 接收失败
*/
static CM_UINT16 CM_Com_DataRecv(CM_UINT8 comId,OUT CM_UINT8* pBuf, IN CM_UINT32 BufSize)
{
    /*- 变量初始化 */
    CM_UINT16 len = (CM_UINT16)((BufSize > 65535u) ? (65535u) : (BufSize));
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    CM_UINT8 buf[COM_UART_BUF_SIZE] = { 0u };  /* 接收缓冲区 */
    /*- 从接收线程获取输入报文 */
    rt = CM_MQ_Read(&g_COM[comId].MsgQ, buf, &len);
    /*- 是否获取成功 */
    if (rt == ENUM_CM_TRUE)
    {
        /*- 输出接收数据 */
    	(void)CM_Memcpy((void*)pBuf, (CM_SIZE_T)BufSize, buf, (CM_SIZE_T)len);
    }
    else
    {
        /*- 接收长度为0 */
        len = 0u;
    }
    /*- 返回接收长度 */
    return len;
}
/**
* @brief 串口数据清空
* @param pCtrl 串口号
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
static ENUM_CM_RETURN CM_Com_Clear(STRUCT_QNX_FD* pCtrl)
{
	return CM_MQ_Clear(&pCtrl->MsgQ);
}

/**
* @brief 串口本机数据发送
* @param pBuf 接收报文指针
* @param BufSize 接收报文缓冲区大小
* @return 接收报文长度
* - 正整数 接收报文长度
* - 0 接收失败
*/
ENUM_CM_RETURN CM_Com_LocalDataSend(OUT CM_UINT8* pBuf, IN CM_UINT16 BufSize)
{
	ENUM_CM_RETURN rtnval = ENUM_CM_FALSE;
	CM_INT32 cmpval = 0xff;
	CM_UINT8 RcvBuf[2000] = {0u};
	ENUM_CM_RETURN Rcvrtn = ENUM_CM_FALSE;
	rtnval = CM_ComSendFFFE(0u,pBuf,BufSize);
	/*发送成功进入回读自检*/
	if(ENUM_CM_TRUE == rtnval)
	{
		/*串口数据接收*/
		Rcvrtn = CM_Com_LocalDataRecv(RcvBuf,BufSize);
		MSCP_LOG_MSG("CM_Com_LocalDataRecv 0x%x:%d,%d \r\n",Rcvrtn,RcvBuf[0],RcvBuf[1]);
		/*本地串口数据回读比较*/
		cmpval = CM_Memcmp(RcvBuf,pBuf,(CM_SIZE_T)BufSize);
		if((0 == cmpval) && (ENUM_CM_TRUE == Rcvrtn))
		{
			rtnval = ENUM_CM_TRUE;
		}
		else
		{
			rtnval = ENUM_CM_FALSE;
			MSCP_LOG_MSG("LocalDataSendCM_Memcmp fail!!! \r\n");
		}
	}
	else
	{
		rtnval = ENUM_CM_FALSE;
	}

    return rtnval;
}
/**
* @brief 串口本机数据接收
* @param pBuf 接收报文指针
* @param BufSize 接收报文缓冲区大小
* @return 接收报文长度
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_Com_LocalDataRecv(OUT CM_UINT8* pBuf, IN CM_UINT16 BufSize)
{
	/*- 变量初始化 */
	ENUM_CM_RETURN rtnValue = ENUM_CM_FALSE;
	CM_UINT8 buf[COM_UART_BUF_SIZE] = { 0u };  /* 接收缓冲区 */
	CM_INT32 ret = 0;
	CM_UINT8 data = 0u;
	CM_UINT32 len = 0u;            /* 数据长度 */
	CM_UINT64 now_time = 0u;
	CM_UINT64 start_time = CM_GetTick();
	/*- 循环执行接收线程 */
	do
	{
		/*从串口接收数据*/
		ret = CM_ComRev((CM_UINT8)g_COM[1u].Num,&data,(CM_UINT16)1u);
		/*- 是否收到有效报文 */
		if(1 == ret)
		{
			rtnValue = CM_FFFEDecode(&g_COM[1u].prtclFFFEStru,data,buf,&len);
			/*接收到完整包写入接收队列*/
			if(ENUM_CM_TRUE == rtnValue)
			{
				(void)CM_Memcpy(pBuf,(CM_SIZE_T)BufSize,buf,(CM_SIZE_T)len);
				/*- 跳出 */
				break;
			}
			else
			{
				/* nothing to do */
			}
		}
		else
		{
			MSCP_LOG_MSG("COM:1 rx fail %d!!\n",ret);
			/* nothing to do */
		}
		now_time = CM_GetTick();
	}while((now_time - start_time) < (10u*1000u*1000u));

    return rtnValue;
}
/**
* @brief 串口临机数据接收
* @param pBuf 接收报文指针
* @param BufSize 接收报文缓冲区大小
* @return 接收报文长度
* - 正整数 接收报文长度
* - 0 接收失败
*/
CM_UINT16 CM_Com_OtherDataRecv(OUT CM_UINT8* pBuf, IN CM_UINT32 BufSize)
{
	return (CM_UINT16)CM_Com_DataRecv(0u,pBuf,BufSize);
}
/**
* @brief 串口临机数据清空
* @param 无
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_Com_OtherDataClear(void)
{
	return CM_Com_Clear(&g_COM[0]);
}
/**
* @brief 串口接收线程
* @param arg 指向STRU_CFM_TIME_CTRL的指针
* @return 线程函数返回值（实际永远不会返回）
* @details
* 创建本线程之前应先做好串口初始化，并输入串口号
* 本线程将以非阻塞方式接收串口数据，并解析FFFE协议存入接收队列
* @see ::
* @see ::
*/
CM_THREAD_FUNC_T t_ComUartRcvThread(IN CM_Thread_Arg_Struct_T* arg)
{
    /*- 变量初始化 */
	STRUCT_QNX_FD* pCtrl = (STRUCT_QNX_FD*)arg;  /* 线程参数 */
	ENUM_CM_RETURN rtnValue = ENUM_CM_FALSE;
    CM_UINT8 buf[COM_UART_BUF_SIZE] = { 0u };  /* 接收缓冲区 */
    CM_INT32 ret = 0;
    CM_UINT8 data = 0u;
    CM_UINT32 len = 0u;            /* 数据长度 */
    MSCP_LOG_MSG("COM:%d Recv Service Start\n",pCtrl->Num);
#if QNX
    void* pmask = NULL;

    /*- 本线程锁定在 A53 core 1 */
    pmask = (void*)(0x01u|0x02u);
    (void)ThreadCtl(_NTO_TCTL_RUNMASK, pmask);

#endif
    /*- 循环执行接收线程 */
    while (1)
    {
    	CM_RE_ASSERT(1, COM_MODE, DARK_FAULT_CODE_FUN_ORDER_6, TSCP_DARK_ASSERT_1);
    	/*从串口接收数据*/
    	ret = CM_ComRev((CM_UINT8)pCtrl->Num,&data,(CM_UINT16)1u);
    	/*- 是否收到有效报文 */
    	if(1 == ret)
    	{
    		rtnValue = CM_FFFEDecode(&pCtrl->prtclFFFEStru,data,&buf[6u],&len);
    		/*接收到完整包写入接收队列*/
    		if(ENUM_CM_TRUE == rtnValue)
    		{
    			/*- 保存通信数据 */
    			CM_LongToChar((CM_UINT32)(CM_GetTick()/CM_UNSIGNED_MILLION), buf);
    			len += 6u;
    			rtnValue = CM_MQ_Write(&pCtrl->MsgQ, buf, (CM_UINT16)len);
				/*- 数据保存是否成功 */
				if (ENUM_CM_TRUE == rtnValue)
				{
					;
				}
				else
				{
					/*- 防御性清空*/
					MSCP_LOG_MSG("COM:%d  rx overflow(msgLen=%d)\n", pCtrl->Num, len);
					(void)CM_Com_Clear(pCtrl);
				}
    		}
    		else
			{
				/* nothing to do */
			}
    	}
    	else
    	{
    		MSCP_LOG_MSG("COM:%d  rx fail %d!!\n", pCtrl->Num,ret);
    		/* nothing to do */
    	}
    }
    return NULL;
}
