/******************************************************************************

版权所有 (C), 2013-2023, 科大智能电气有限公司

******************************************************************************
文 件 名   : gb104.c
版 本 号   : V1.0
生成日期   : 2022年03月23日
最近修改   :
功能描述   : 104规约实现主体
函数列表   :
修改历史   :
1.日    期   : 2022年03月23日
修改内容   : 创建文件
*******************************************************************************/
/*************************************文件包含*********************************/
#include "gb104.h"
/***************************************static函数声明*******************************/
static unsigned char GB104_GetOneFrame(CS10xHandle_t pstSelf, unsigned char *pucFramePt, unsigned short usLastLen, unsigned short *pusSearchLen);
static void GB104_DecodeOneFrame(CS10xHandle_t pstSelf, unsigned char *pucBuf) ; //解析单帧数据
/*************************************外部接口函数*****************************/
/**
* @brief    规约使用前初始化
* @param[in]  pstSelf-函数实体指针
* @param[in]  cb-发送函数指针
* @param[in]  arg-用户数据指针
* @param[in]  enType-规约类型 主从
* @param[out] 无
* @return     规约实体指针
*/
void CS10x_104Init(CS10xHandle_t pstSelf, CS10x_SendCb pcb, void *arg, CS10x_Type enType)
{
	pstSelf->eCS10x_Type     = enType;
	pstSelf->pfnSendCb           = pcb;
	pstSelf->pUsrData         = arg;
	pstSelf->pfnDecodeProcess    = GB104_DecodeProcess;
	pstSelf->pfnEncodeFrame       = GB104_EncodeFrame;
	pstSelf->pfnEncodeOther      = GB104_EncodeOther;
	pstSelf->pfnTimerManager     = GB104_TimerOut;

	if(enType == CS104_TYPE_M) //主模式注册轮询文件传输任务函数
	{
		pstSelf->pfnPollFileTransTask = PollFileTransTask;
		pstSelf->uiTransTimerMax = TRANS_TIMEOUT_MAX / TRANS_SCH_GAP;
		SetSendTask(pstSelf, TSKID_StartLink, TSK_PARM_USACT, 0); //此处需修改
	}

	/*默认初始化参数*/
	pstSelf->usYcType         = YC_TYPE_ME_NC;
	pstSelf->usYxType         = YX_TYPE_M_SP;
	pstSelf->usYkType         = YK_TYPE_C_SC;
	pstSelf->usDdType         = DD_TYPE_IT_NB;
	pstSelf->usAsduPublicAddr = 1;
	/*应用参数*/
	pstSelf->stAppParameters.iSzOfLinkAddr = 2;
	pstSelf->stAppParameters.iSzOfTypeId   = 1;
	pstSelf->stAppParameters.iSzOfVSQ      = 1;
	pstSelf->stAppParameters.iSzOfCOT      = 2;
	pstSelf->stAppParameters.iSzOfCA       = 2;
	pstSelf->stAppParameters.iSzOfIOA      = 3;
	pstSelf->stAppParameters.iLinkAddr       = 1;
	pstSelf->stAppParameters.iPublicAddr     = 1;
	/*总招对时时间*/
	pstSelf->uiSummon_Gap = 300000; /*300秒*/
	pstSelf->uiSyn_Gap    = 300000; /*300秒*/
	pstSelf->uiSend_Gap   = 100;    /*100ms*/
	/*104*/
	pstSelf->stAPCIParameters.iT0 = 10;
	pstSelf->stAPCIParameters.iT1 = 12;
	pstSelf->stAPCIParameters.iT2 = 8;
	pstSelf->stAPCIParameters.iT3 = 15;
	pstSelf->stAPCIParameters.iK = 12;
	pstSelf->stAPCIParameters.iW = 8;
	pstSelf->ucMultiFrameEn = 0; //104多帧发送使能
	pstSelf->usFaultEnable = 1; //故障事件使能
	pstSelf->ucSenSoeEa = 1; //发送SOE使能
	pstSelf->ucSenCosEa = 1; //发送COS使能
	pstSelf->ucYKEndFrame = 1; //遥控结束帧投入
	pstSelf->ucOffLineSoeReissueEn = 1;//离线SOE补发使能
	pstSelf->ucReadFileVSQ = 0; //读文件数据传输VSQ状态值
	pstSelf->ucPreSetContType = 0; /* 默认为正常参数预置流程*/
#ifdef IEC_DEBUG_MSG
	IEC_PRINT("Create IEC104 %s\n", enType == CS104_TYPE_M ? "主站" : "从站");
#endif
	return;
}

/*************************************内部调用函数*****************************/
/**
* @brief    104规约数据帧处理
* @param[in]  pstself-规约实体指针 参数
* @param[in]  pucBuf-报文数据指针 接收的报文
* @param[in]  usLen-报文长度
* @param[out] 无
* @return     无实际意义
*/
char GB104_DecodeProcess(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen)
{
	unsigned short usFramePos  = 0;   //一条报文中含有多帧104时，表示每帧起始在报文中起始位置
	unsigned short usSearchLen = 0;   //本次查找返回的报文的长度(包括错误帧)

	do   //拆分多帧报文并解析
	{
		if(GB104_GetOneFrame(pstSelf, pucBuf + usFramePos, usLen - usFramePos, &usSearchLen)) //查找单帧报文
		{
			GB104_DecodeOneFrame(pstSelf,  pstSelf->stPubBuf.pBuf); //解析单帧
			usFramePos += usSearchLen;  //报文解析起始位置更新
		}
		else
		{
			break;
		}
	} while(usFramePos < usLen);    //越界判断

	return 0;
}

/**
* @brief      查找单帧报文 并复制到公共缓冲区
* @param[in]  pstSelf-规约实体指针 包括参数与公共接收报文缓冲
* @param[in]  *pucFramePt- 接收数据全部报文指针
* @param[in]  usLastLen-接受的全部报文长度
* @param[out]  *pusSearchLen-解析单帧报文长度包括错误帧
* @return     0无有效帧       1存在有效单帧
*/
static unsigned char GB104_GetOneFrame(CS10xHandle_t pstSelf, unsigned char *pucFramePt, unsigned short usLastLen, unsigned short *pusSearchLen)
{
	if(Check_IEC_104(pucFramePt, usLastLen) == 0) //核对104报文
	{
		*pusSearchLen = usLastLen;
		return 0;
	}
	else
	{
		pstSelf->stPubBuf.usWritePtr = pucFramePt[1] + 2; //单帧报文全部长度
		memcpy(pstSelf->stPubBuf.pBuf, pucFramePt, pstSelf->stPubBuf.usWritePtr);//拷贝当前帧到公共缓存待解析
		*pusSearchLen = pstSelf->stPubBuf.usWritePtr; //更新指针偏移
	}

	return 1;
}

/**
* @brief    解析全部类型的单帧报文
* @param[in]  pstSelf-规约实体指针 包括参数与公共接收报文缓冲
* @param[in]  pucBuf-报文数据指针 接收数据分帧后的单帧报文
* @param[in]
* @param[out] 无
* @return     无
*/
static void GB104_DecodeOneFrame(CS10xHandle_t pstSelf, unsigned char *pucBuf)  //解析单帧数据
{
	unsigned char ucContolParam = 0;
	StartTimer(pstSelf, T3_TimeHandle); // receive any I,U,S frame, to start T3
	ucContolParam = pucBuf[2]; //控制帧 单帧报文第三位控制帧区分报文类型

	switch(ucContolParam & 0x03)
	{
		case FRM_I:
			GB104_Preprocessor(pstSelf); //I帧信息
			break;

		case FRM_S:
			DoSFrame(pstSelf); //确认帧信息
			break;

		case FRM_U:
			DoUFrame(pstSelf); //控制帧信息
			break;

		default:
			GB104_Preprocessor(pstSelf);
			break;
	}

	if(pstSelf->usSendNum > pstSelf->usAckSendNum && (pstSelf->usSendNum - pstSelf->usAckSendNum) >= pstSelf->stAPCIParameters.iK)
	{
		pstSelf->bContinueSendFlag = 0;
		StartTimer(pstSelf, T1_TimeHandle);

		if((pstSelf->usSendNum - pstSelf->usAckSendNum) >= 2 * pstSelf->stAPCIParameters.iK)
		{
			pstSelf->ucInitStatus = 0;

			if(pstSelf->pfnLinkClose)
			{
				pstSelf->pfnLinkClose(pstSelf->pUsrData);
			}
		}
	}
	else if((pstSelf->usSendNum < pstSelf->usAckSendNum) && (pstSelf->usSendNum + COUNTER_LIMIT - pstSelf->usAckSendNum) >= pstSelf->stAPCIParameters.iK)
	{
		pstSelf->bContinueSendFlag = 0;
		StartTimer(pstSelf, T1_TimeHandle);

		if((pstSelf->usSendNum + COUNTER_LIMIT - pstSelf->usAckSendNum) >= 2 * pstSelf->stAPCIParameters.iK)
		{
			pstSelf->ucInitStatus = 0;

			if(pstSelf->pfnLinkClose)
			{
				pstSelf->pfnLinkClose(pstSelf->pUsrData);
			}
		}
	}
	else
	{
		pstSelf->bContinueSendFlag = 1;
	}
}

/**
* @brief    104规约收到的长帧解析处理接口函数
* @param[in]  pstSelf-规约实体指针
* @param[out] 无
* @return     无
*/
void GB104_Preprocessor(CS10xHandle_t pstSelf)
{
	unsigned short usAckNum             = 0;
	unsigned short usRecvNum            = 0;
	VIec104Frame *pstReceive = (VIec104Frame *)pstSelf->stPubBuf.pBuf;

	/*未进行初始化时，不响应数据*/
	if(pstSelf->ucInitStatus != 1)
	{
		if((pstSelf->eCS10x_Type == CS104_TYPE_S) || ((pstSelf->eCS10x_Type == CS104_TYPE_M) && (pstReceive->byASDU[0] != M_EI_NA)))
		{
			return;
		}	
	}
	StartTimer(pstSelf, T2_TimeHandle); // when Receve I frame, start T2
	StopTimer(pstSelf, T1_TimeHandle);  // stop T1
	/*处理APCI信息 */
	usAckNum = IEC_MAKEWORD(pstReceive->byControl3, pstReceive->byControl4);
	usRecvNum = IEC_MAKEWORD(pstReceive->byControl1, pstReceive->byControl2);
	usAckNum >>= 1;  //最低位不是收发序列号
	usRecvNum >>= 1;
	pstSelf->usRecvNum = usRecvNum + 1;
	pstSelf->usAckSendNum = usAckNum;
	DoAckFrame(pstSelf);// 检查扰动遥测和SOE

	// 判断终端是否需要给主站回复确认帧
	if((pstSelf->usRecvNum - pstSelf->usAckRecvNum) > pstSelf->stAPCIParameters.iW)
	{
		SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0);
	}

	/*处理ASDU元素*/
	DecodeAsduMember(pstSelf, pstReceive->byASDU, pstReceive->byAPDULen - 4);
	/*处理ASDU信息体*/
	DecodeAsduInfoObj(pstSelf);
	return;
}

/**
* @brief    104规约S帧解析
* @param[in]  pstSelf-规约实体指针
* @param[out] 无
* @return     无
*/
void DoSFrame(CS10xHandle_t pstSelf)
{
	/*未进行初始化时，不响应数据*/
	if(pstSelf->ucInitStatus != 1)
	{
		return;
	}

	unsigned short usAckNum             = 0; //序列号
	VIec104Frame *pstReceive = NULL;
	pstReceive = (VIec104Frame *)pstSelf->stPubBuf.pBuf;
	StopTimer(pstSelf, T1_TimeHandle); 
	usAckNum = IEC_MAKEWORD(pstReceive->byControl3, pstReceive->byControl4);
	pstSelf->usAckSendNum = usAckNum >> 1;

	if(pstSelf->eCS10x_Type == CS104_TYPE_S)  //作为从站时
	{
		DoAckFrame(pstSelf);
		if(pstSelf->pfnAckFrameNotification)
		{
			pstSelf->pfnAckFrameNotification();
		}
	}

	return;
}

/**
* @brief    104规约U帧解析处理函数
* @param[in]  pstSelf-规约实体指针
* @param[out] 无
* @return     无
*/
void DoUFrame(CS10xHandle_t pstSelf)
{
	VIec104Frame *pstReceive = NULL;
	pstReceive = (VIec104Frame *)pstSelf->stPubBuf.pBuf;

	switch(pstReceive->byControl1)
	{
		case STARTDT_ACT: //收到启动链路
			ClearAllTaskflgs(pstSelf);
			SetSendTask(pstSelf, TSKID_StartLink, TSK_PARM_USTCON, 0);
			SetSendTask(pstSelf, TSKID_InitFinish, COT_INIT, 0);
			pstSelf->bContinueSendFlag = 1;
			pstSelf->ucInitStatus = 1;
			break;

		case STOPDT_ACT: //收到断开链路
			ClearAllTaskflgs(pstSelf);
			SetSendTask(pstSelf, TSKID_StopLink, TSK_PARM_USTCON, 0);
			break;

		case TESTFR_ACT: //收到测试

			/*仅初始化完成，响应测试帧*/
			if(pstSelf->ucInitStatus == 1)
			{
				SetSendTask(pstSelf, TSKID_UTest, TSK_PARM_USTCON, 0);
			}

			break;

		case STARTDT_CON: //启动链路响应
			StopTimer(pstSelf, T0_TimeHandle);
			pstSelf->bContinueSendFlag = 1;
			ClearTaskFlag(&pstSelf->stTaskFlags, TSKID_StartLink); //主模式复位启动链路发送标志
			break;

		case STOPDT_CON: //断开链路响应
			pstSelf->bContinueSendFlag = false;
			StopTimer(pstSelf, T0_TimeHandle);
			StopTimer(pstSelf, T1_TimeHandle);
			StopTimer(pstSelf, T2_TimeHandle);
			StopTimer(pstSelf, T3_TimeHandle);

			if(pstSelf->pfnLinkClose)
			{
				pstSelf->pfnLinkClose(pstSelf->pUsrData);
			}

			break;

		case TESTFR_CON:
			break;

		default:
			break;
	}

	return;
}

/*************104组帧接口函数*********/
/**
* @brief    104规约I帧组帧函数
* @param[in]  pstSelf-规约实体指针
* @param[out] 无
* @return     无实际意义
*/
char GB104_EncodeFrame(CS10xHandle_t pstSelf)
{
	pstSelf->stSendBuf.usReadPtr = 0;
	VIec104Frame * pstApdu = (VIec104Frame *)pstSelf->stSendBuf.pBuf;
	pstSelf->stSendBuf.usWritePtr += GB104_EncodeApci(pstSelf, FRM_I, pstApdu);
	pstSelf->stSendBuf.usWritePtr += GB10x_EncodeAsdu(pstSelf, (unsigned char *)pstApdu + pstSelf->stSendBuf.usWritePtr);
	GB104_EncodeApduLen(pstSelf, pstApdu);
	GB104_FrameTimerHdl(pstSelf, pstApdu);
	return 0;
}

/**
* @brief    104规约短帧组帧函数 U帧S帧
* @param[in]  stSelf-规约实体指针
* @param[out] 无
* @return     无实际意义
*/
char GB104_EncodeOther(CS10xHandle_t pstSelf)
{
	switch(pstSelf->byTaskFlagId)
	{
		//启动链路发起及响应
		case TSKID_StartLink:
			pstSelf->uiaTaskParam[TSKID_StartLink] = TSK_PARM_NONE;

			if(pstSelf->eCS10x_Type == CS104_TYPE_S)
			{
				SendUFrame(pstSelf, STARTDT_CON);
			}
			else if(pstSelf->eCS10x_Type == CS104_TYPE_M)
			{
				SendUFrame(pstSelf, STARTDT_ACT);
				pstSelf->usSendNum = 0;
				pstSelf->usRecvNum = 0;
				pstSelf->usAckRecvNum = 0;
				pstSelf->usAckRecvNum = 0;
				StartTimer(pstSelf, T0_TimeHandle);
			}

			break;

		//断开链路发起及响应
		case TSKID_StopLink:
			pstSelf->uiaTaskParam[TSKID_StopLink] = TSK_PARM_NONE;

			if(pstSelf->eCS10x_Type == CS104_TYPE_S)
			{
				SendUFrame(pstSelf, STOPDT_CON);
			}
			else if(pstSelf->eCS10x_Type == CS104_TYPE_M)
			{
				SendUFrame(pstSelf, STOPDT_ACT);
			}

			break;

		// TEST发起及响应
		case TSKID_UTest:
			if((pstSelf->uiaTaskParam[TSKID_UTest] & 0xFF) == TSK_PARM_USTCON)
			{
				SendUFrame(pstSelf, TESTFR_CON);
			}
			else if((pstSelf->uiaTaskParam[TSKID_UTest] & 0xFF) == TSK_PARM_USACT)
			{
				SendUFrame(pstSelf, TESTFR_ACT);
			}

			pstSelf->uiaTaskParam[TSKID_UTest] = TSK_PARM_NONE;
			break;

		//应答 S帧
		case TSKID_Ack:
			pstSelf->uiaTaskParam[TSKID_Ack] = TSK_PARM_NONE;
			GB104_SendAck(pstSelf);
			break;

		default:
			break;
	}

	return 0;
}

/**
* @brief    104规约ASDU域确认前处理函数 发送帧序号处理
* @param[in]  stSelf-规约实体指针
* @param[in]  ucFrameType-帧类型
* @param[out] 无
* @return     无
*/
unsigned short GB104_EncodeApci(CS10xHandle_t pstSelf, unsigned char ucFrameType, VIec104Frame * pstFrame)
{
	unsigned short usSendNum = 0;
	unsigned short usRecvNum = 0;
	pstSelf->usSendNum %= (MAX_FRAME_COUNTER + 1);
	pstSelf->usRecvNum %= (MAX_FRAME_COUNTER + 1);
	usSendNum = pstSelf->usSendNum << 1;
	usRecvNum = pstSelf->usRecvNum << 1;

	if(NULL == pstFrame)
	{
		return 0;
	}

	pstFrame->byStartCode = START_CODE;

	switch(ucFrameType)
	{
		case FRM_I:
			pstFrame->byControl1 = IEC_LOBYTE(usSendNum);
			pstFrame->byControl2 = IEC_HIBYTE(usSendNum);
			pstFrame->byControl3 = IEC_LOBYTE(usRecvNum);
			pstFrame->byControl4 = IEC_HIBYTE(usRecvNum);
			pstSelf->usAckRecvNum = pstSelf->usRecvNum;
			break;

		case FRM_S:
			pstFrame->byControl1 = FRM_S;
			pstFrame->byControl2 = 0;
			pstFrame->byControl3 = IEC_LOBYTE(usRecvNum);
			pstFrame->byControl4 = IEC_HIBYTE(usRecvNum);
			pstSelf->usAckRecvNum = pstSelf->usRecvNum;
			break;

		case FRM_U:
			pstFrame->byControl1 = FRM_U;
			pstFrame->byControl2 = 0;
			pstFrame->byControl3 = 0;
			pstFrame->byControl4 = 0;
			break;

		default:
			break;
	}

	return APCI_LEN;
}

/**
* @brief    104规约ASDU域确认前处理函数 发送帧序号处理
* @param[in]  stSelf-规约实体指针
* @param[in]  ucFrameType-帧类型
* @param[out] 无
* @return     无
*/
void GB104_EncodeApduLen(CS10xHandle_t pstSelf, VIec104Frame * pstApdu)
{
	pstApdu->byAPDULen = pstSelf->stSendBuf.usWritePtr - 2;
	return;
}

/**
* @brief    104规约ASDU域确认后处理函数
* @param[in]  stSelf-规约实体指针
* @param[out] 无
* @return     无
*/
void GB104_FrameTimerHdl(CS10xHandle_t pstSelf, VIec104Frame * pstApdu)
{
	if((pstApdu->byControl1 & 0x1) == FRM_I)
	{
		/*仅存储I帧*/
		// SaveSendFrame(pstSelf, pstSelf->usSendNum, pstSelf->stSendBuf.usWritePtr, pstSelf->stSendBuf.pBuf);
		StopTimer(pstSelf, T2_TimeHandle); // when send I frame, stop T2
		pstSelf->usSendNum++;

		if(pstSelf->usSendNum >= COUNTER_LIMIT)
		{
			pstSelf->usSendNum = 0;
		}

		if(pstSelf->usSendNum > pstSelf->usAckSendNum && (pstSelf->usSendNum - pstSelf->usAckSendNum) >= pstSelf->stAPCIParameters.iK)
		{
			pstSelf->bContinueSendFlag = 0;
			StartTimer(pstSelf, T1_TimeHandle);
		}
		else if((pstSelf->usSendNum < pstSelf->usAckSendNum) && (pstSelf->usSendNum + COUNTER_LIMIT - pstSelf->usAckSendNum) >= pstSelf->stAPCIParameters.iK)
		{
			pstSelf->bContinueSendFlag = 0;
			StartTimer(pstSelf, T1_TimeHandle);
		}
	}

	return;
}

/**
* @brief    104规约S帧组帧函数
* @param[in]  stSelf-规约实体指针
* @param[out] 无
* @return     无
*/
void GB104_SendAck(CS10xHandle_t pstSelf)
{
	VIec104Frame *pstApdu = (VIec104Frame *)pstSelf->stSendBuf.pBuf;
	pstSelf->stSendBuf.usWritePtr += GB104_EncodeApci(pstSelf, FRM_S, pstApdu);
	GB104_EncodeApduLen(pstSelf, pstApdu);
	GB104_FrameTimerHdl(pstSelf, pstApdu);
	StopTimer(pstSelf, T2_TimeHandle); // when send S frame, stop T2
	return;
}

/**
* @brief    104规约U帧组帧函数
* @param[in]  stSelf-规约实体指针
* @param[in]  ucType-U帧类型
* @param[out] 无
* @return     无
*/
void SendUFrame(CS10xHandle_t pstSelf, unsigned char ucType)
{
	VIec104Frame *pstApdu = (VIec104Frame *)pstSelf->stSendBuf.pBuf;
	pstSelf->stSendBuf.usWritePtr += GB104_EncodeApci(pstSelf, FRM_U, pstApdu);
	pstApdu->byControl1 |= ucType;
	GB104_EncodeApduLen(pstSelf, pstApdu);
	GB104_FrameTimerHdl(pstSelf, pstApdu);
	return;
}

/***************104规约计时******************/
/**
* @brief    104规约定时处理函数
* @param[in]  pstSelf-规约实体指针
* @param[in]  usGap-间隔时间ms
* @param[out] 无
* @return     无
*/
void GB104_TimerOut(CS10xHandle_t pstSelf, unsigned short usGap)
{
	if(pstSelf->stM_vTimer[0].bRun)
	{
		pstSelf->stM_vTimer[0].uiCounter -= usGap;

		if(pstSelf->stM_vTimer[0].uiCounter < usGap)  //建立连接超时
		{
#ifdef IEC_DEBUG_MSG
			IEC_PRINT("iec104 slave T0 timeout,close TCP!\n");
#endif
			// to do:when T1 timeout,close tcp connect
			ClearAllTaskflgs(pstSelf);
			SetSendTask(pstSelf, TSKID_StartLink, TSK_PARM_USACT, 0);

			if(pstSelf->pfnLinkClose)
			{
				pstSelf->pfnLinkClose(pstSelf->pUsrData);
			}
		}
	}

	if(pstSelf->stM_vTimer[1].bRun)
	{
		pstSelf->stM_vTimer[1].uiCounter -= usGap;

		if(pstSelf->stM_vTimer[1].uiCounter < usGap)  //发送数据超时
		{
#ifdef IEC_DEBUG_MSG
			IEC_PRINT("iec104 slave T1 timeout,close TCP!\n");
#endif
			StopTimer(pstSelf, T1_TimeHandle);

			if(pstSelf->eCS10x_Type == CS104_TYPE_M)
			{
				// to do:when T1 timeout,close tcp connect
				SetSendTask(pstSelf, TSKID_StartLink, TSK_PARM_USACT, 0);
			}
			else if(pstSelf->eCS10x_Type == CS104_TYPE_S)
			{
				pstSelf->ucInitStatus = 0; // 初始化完成状态

				if(pstSelf->pfnLinkClose)
				{
					pstSelf->pfnLinkClose(pstSelf->pUsrData);
				}
			}
		}
	}

	if(pstSelf->stM_vTimer[2].bRun)
	{
		pstSelf->stM_vTimer[2].uiCounter -= usGap;

		if(pstSelf->stM_vTimer[2].uiCounter < usGap)  //无数据报文超时给应答
		{
			// to do:when T2 timeout, send S frame
			SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0);
			StopTimer(pstSelf, T2_TimeHandle);
		}
	}

	if(pstSelf->stM_vTimer[3].bRun)
	{
		pstSelf->stM_vTimer[3].uiCounter -= usGap;

		if(pstSelf->stM_vTimer[3].uiCounter < usGap)  //无数据超时测试帧
		{
			// to do:when T3 timeout
			if(pstSelf->ucInitStatus == 1)
			{
				SetSendTask(pstSelf, TSKID_UTest, TSK_PARM_USACT, 0);
			}

			StopTimer(pstSelf, T3_TimeHandle);
		}
	}
}

/**
* @brief    停止定时计数
* @param[in]  pstSelf-规约实体指针
* @param[in]  usTimerId-定时ID
* @param[out] 无
* @return     无
*/
void StopTimer(CS10xHandle_t pstSelf, unsigned short usTimerId)
{
	if(usTimerId > T3_TimeHandle)
	{
		return;
	}

	pstSelf->stM_vTimer[usTimerId].bRun = 0;
	pstSelf->stM_vTimer[usTimerId].uiCounter = 0;
}

/**
* @brief    开始定时计数
* @param[in]  pstSelf-规约实体指针
* @param[in]  usTimerId-定时ID
* @param[out] 无
* @return     无
*/
void StartTimer(CS10xHandle_t pstSelf, unsigned short usTimerId)
{
	if(usTimerId > T3_TimeHandle)
	{
		return;
	}

	pstSelf->stM_vTimer[usTimerId].bRun = 1;

	if(usTimerId == T0_TimeHandle)
	{
		pstSelf->stM_vTimer[usTimerId].uiCounter = pstSelf->stAPCIParameters.iT0 * 1000;
	}
	else if(usTimerId == T1_TimeHandle)
	{
		pstSelf->stM_vTimer[usTimerId].uiCounter = pstSelf->stAPCIParameters.iT1 * 1000;
	}
	else if(usTimerId == T2_TimeHandle)
	{
		pstSelf->stM_vTimer[usTimerId].uiCounter = pstSelf->stAPCIParameters.iT2 * 1000;
	}
	else if(usTimerId == T3_TimeHandle)
	{
		pstSelf->stM_vTimer[usTimerId].uiCounter = pstSelf->stAPCIParameters.iT3 * 1000;
	}
}

/**
* @brief 规约格式判定
* @param pucBuf 数据指针
* @param uslen 数据长度
* @return true 符合104规约格式
* @return false 不符合
*/
bool Check_IEC_104(unsigned char* pucBuf, unsigned short uslen)
{
	if(pucBuf[0] != 0x68)     //包头必须68
	{
		return false;
	}

	if(pucBuf[1] + 2 > uslen) //缺帧
	{
		return false;
	}
	else if(pucBuf[1] + 2 < uslen) //连帧
	{
		if(pucBuf[pucBuf[1] + 2] != 0x68)   //连包 检查下一帧报文是否0x68开头
		{
			return false;
		}
	}

	return true;
}
