diff --git a/release/copy_headers.sh b/release/copy_headers.sh index 8630821..dda334a 100755 --- a/release/copy_headers.sh +++ b/release/copy_headers.sh @@ -69,5 +69,6 @@ copy_module "libcomm" "myComm.h" # 协议模块(protocol/) # ================================================================ copy_proto_module "libmodbus" "myModbus.h" +copy_proto_module "lib60870" "myIec60870.h" echo "=== done ===" diff --git a/release/src/protocol/lib60870/makefile b/release/src/protocol/lib60870/makefile new file mode 100644 index 0000000..afb96f7 --- /dev/null +++ b/release/src/protocol/lib60870/makefile @@ -0,0 +1,33 @@ +include ./../../../linux.mk +L := $(notdir $(realpath $(CURDIR)/..)) +M := lib60870 +O := $(LIB_REL)/$(M).a +S := $(SRC_ROOT_DIR)/$(L)/lib60870/src +I := -I$(SRC_ROOT_DIR)/$(L)/lib60870/inc +B := $(CURDIR)/$(M)/obj +SRCS := $(wildcard $(S)/*.c) +OBJS := $(patsubst $(S)/%.c, $(B)/%.o, $(SRCS)) +F := $(C_FLAGS) $(I) +F += -include cbb_compat.h +F += -Wno-implicit-function-declaration + +.PHONY: all +all: + @mkdir -p $(ROOT_DIR)/release/inc + @$(MAKE) $(O) + +$(O): $(OBJS) + @mkdir -p $(dir $@) + $(AR) rcs $@ $^ + @echo "[$(M)] built" + +$(B)/%.o: $(S)/%.c + @mkdir -p $(dir $@) + $(CC) $(F) -c $< -o $@ + +.PHONY: clean +clean: + rm -rf $(B) $(O) + +.PHONY: rebuild +rebuild: clean all diff --git a/release/src/protocol/makefile b/release/src/protocol/makefile index c78c1ec..52c57d5 100644 --- a/release/src/protocol/makefile +++ b/release/src/protocol/makefile @@ -1,4 +1,4 @@ -SUBDIRS := ./libmodbus +SUBDIRS := ./libmodbus ./lib60870 define make_subdir for d in $(SUBDIRS); do [ -f "$$d/makefile" ] && (cd "$$d" && make -f makefile $1) || true; done endef diff --git a/src/protocol/lib60870/inc/Asdu.h b/src/protocol/lib60870/inc/Asdu.h new file mode 100644 index 0000000..61264fa --- /dev/null +++ b/src/protocol/lib60870/inc/Asdu.h @@ -0,0 +1,283 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : ASDU.h + 版 本 号 : V1.0 + 生成日期 : 2022年04月07日 + 最近修改 : + 功能描述 : 101及104规约的公共部分ASUD域相关数据处理 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年04月07日 + 修改内容 : 创建文件 +*******************************************************************************/ +#ifndef __ASDU_H +#define __ASDU_H +/**************************************文件包含*******************************/ +#include +#include "lib60870_common.h" +#include "lib60870_public.h" +#include "lib60870_process.h" +#include "gb101.h" +/**************************************宏定义*********************************/ + +#define MAX_FLOATYC_CNT 48 +#define INTYC_MAX_CNT 80 +#define MAX_Yx_CNT 127 +#define MAX_Dd_CNT 48 +#define MAX_Param_CNT 4 +#define MAX_COS_CNT 60 +/************************************数据结构定义*****************************/ + +typedef union +{ + /*带品质描述词的单点信息*/ + struct + { + unsigned char ucSPI: 1; /*0=开 1=合*/ + unsigned char ucRES: 3; /*备用*/ + unsigned char ucBL : 1; /*0=未被锁定 1=锁定*/ + unsigned char ucSB : 1; /*0=未被取代 1=取代*/ + unsigned char ucNT : 1; /*0=当前值 1=非当前值*/ + unsigned char ucIV : 1; /*0=有效 1=无效*/ + } SIQ; + + /*带品质描述词的双点信息*/ + struct + { + unsigned char ucDPI: 2; /*0=不确定或中间状态 1=确定状态开 2=确定状态合 3=不确定*/ + unsigned char ucRES: 2; /*备用*/ + unsigned char ucBL : 1; /*0=未被锁定 1=锁定*/ + unsigned char ucSB : 1; /*0=未被取代 1=取代*/ + unsigned char ucNT : 1; /*0=当前值 1=非当前值*/ + unsigned char ucIV : 1; /*0=有效 1=无效*/ + } DIQ; + + /*品质描述词*/ + struct + { + unsigned char ucOV : 1; /*0=未溢出 1=溢出*/ + unsigned char ucRES: 3; /*备用*/ + unsigned char ucBL : 1; /*0=未被锁定 1=锁定*/ + unsigned char ucSB : 1; /*0=未被取代 1=取代*/ + unsigned char ucNT : 1; /*0=当前值 1=非当前值*/ + unsigned char ucIV : 1; /*0=有效 1=无效*/ + } QDS; + + /*继电保护设备事件的品质描述词*/ + struct + { + unsigned char ucRES: 3; /*备用*/ + unsigned char ucEI : 1; /*0=动作时间有效 1=动作时间无效*/ + unsigned char ucBL : 1; /*0=未被锁定 1=锁定*/ + unsigned char ucSB : 1; /*0=未被取代 1=取代*/ + unsigned char ucNT : 1; /*0=当前值 1=非当前值*/ + unsigned char ucIV : 1; /*0=有效 1=无效*/ + } QDP; + + /*带瞬变状态指示的值*/ + struct + { + unsigned char ucI7 : 7; /*瞬变状态*/ + unsigned char ucBS1: 1; /*0=动作时间有效 1=动作时间无效*/ + } VTI; + + + /*单命令*/ + struct + { + unsigned char ucSCS: 1; /*0=开 1=合*/ + unsigned char ucRES: 1; /*备用*/ + unsigned char ucQU : 5; /*0=无另外定义 1=短脉冲持续时间 2=长脉冲持续时间 3=持续输出*/ + unsigned char ucSE : 1; /*0=执行 1=选择*/ + } SCO; + + /*双命令*/ + struct + { + unsigned char ucDCS: 2; /*0=不允许 1=开 2=合 3=不允许*/ + unsigned char ucQU : 5; /*0=无另外定义 1=短脉冲持续时间 2=长脉冲持续时间 3=持续输出*/ + unsigned char ucSE : 1; /*0=执行 1=选择*/ + } DCO; + + /*步调节命令*/ + struct + { + unsigned char ucRCS: 2; /*0=不允许 1=降一步 2=升一步 3=不允许*/ + unsigned char ucQU : 5; /*0=无另外定义 1=短脉冲持续时间 2=长脉冲持续时间 3=持续输出*/ + unsigned char ucSE : 1; /*0=执行 1=选择*/ + } RCO; + + /*初始化原因*/ + struct + { + unsigned char ucUI7: 7; /*0=当地电源合上 1=当地手动复位 2=远方复位*/ + unsigned char ucBS1: 1; /*0=未改变当地参数初始化 1=改变当地参数初始化*/ + } COI; + + /*设定命令限定词*/ + struct + { + unsigned char ucQL: 7; /*0=缺省*/ + unsigned char ucSE: 1; /*0=执行 1=选择*/ + } QOS; + + unsigned char ucBits; +} ASDU_CMD_T; + +/**************************************数据声明******************************/ + + +/**************************************内部函数声明***************************/ +unsigned char DecodeASDUCheck(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_M_EI_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_IC_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_CI_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_CS_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_RP_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_TS_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_F_FR_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_SR_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_RR_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_RS_NA(CS10x *pstSelf); +unsigned char DecodeCheck_C_WS_NA(CS10x *pstSelf); +unsigned char DecodeCheck_M_SPDP_NA(CS10x *pstSelf); +unsigned char DecodeCheck_M_ME_NANBNC(CS10x *pstSelf); +unsigned char DecodeCheck_M_IT_NB(CS10x *pstSelf); +unsigned char DecodeCheck_M_IT_TC(CS10x *pstSelf); +unsigned char DecodeCheck_C_SCDC_NA(CS10x *pstSelf); +unsigned char DecodeCheck_M_FT_NA(CS10x *pstSelf); +unsigned char DecodeCheck_M_DPSP_TB(CS10x *pstSelf); +unsigned char DecodeCheck_F_SR_NA(CS10x *pstSelf); +unsigned char DecodeCheck_C_CD_NA(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_RS_NA_NANWANG(CS10x *pstSelf); +unsigned char DecodeCheck_C_WS_NA_YZ(CS10x *pstSelf); +unsigned char DecodeCheck_C_WS_NA_GH(CS10x *pstSelf, unsigned char *pucPayload); +unsigned char DecodeCheck_C_SP_NA(CS10x *pstSelf); +void Do_SetTime(CS10x *pstSelf, unsigned short usReason); +void Do_Summon(CS10x *pstSelf, unsigned short usReason); +void Do_DdSummon(CS10x *pstSelf, unsigned short usReason); +void Do_Reset_Process(CS10x *pstSelf, unsigned short usReason); +void Do_DataTest(CS10x *pstSelf, unsigned short usReason); +void Do_InitEnd(CS10x *pstSelf, unsigned short usReason); +void Do_Yx(CS10x *pstSelf, unsigned short usReason); +void Do_Yc(CS10x *pstSelf, unsigned short usReason); +void Do_DdNoTime(CS10x *pstSelf, unsigned short usReason); +void Do_DdWithTime(CS10x *pstSelf, unsigned short usReason); +void Do_YKPro(CS10x *pstSelf, unsigned short usReason); +void Do_SOE(CS10x *pstSelf); +void Do_FaultEvent(CS10x *pstSelf); +void Do_FilePro_Slave(CS10x *pstSelf, unsigned char ucType, unsigned char *pucBuf, unsigned short usFileDateLen); +void Do_FilePro_Master(CS10x *pstSelf, unsigned char ucType, unsigned char *pucBuf); +void Do_FilePro(CS10x *pstSelf, unsigned short usReason); +void Do_Anomaly(CS10x *pstSelf, unsigned short usReason); +void Do_ChgConst(CS10x *pstSelf, unsigned short usReason); +void Do_ReadConst(CS10x *pstSelf, unsigned short usReason); +void Do_ParamPreread(CS10x *pstSelf, unsigned short usReason); +void Do_ParamPreset(CS10x *pstSelf, unsigned short usReason); + +unsigned short CS10x_Send_Yx(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_SummonYx(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_COS(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_Yc(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_SummonYc(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ChangeYc(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_SOE(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_FaultEvent(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_DdData(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_SummonDd_Data(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_TimeDd_Data(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_SynTime(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_Summon(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_DdSummon(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ResetProcess(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_DataTest(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_InitEnd(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_FilePro(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ChgConst(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ReadConst(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ParamPreread(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_ParamPreset(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_Yk(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_DdSummon_Data(CS10x *pstSelf, unsigned int uiParam); +unsigned short CS10x_Send_Anomaly(CS10x *pstSelf, unsigned int param); +unsigned short CS10x_Send_Update(CS10x *pstSelf, unsigned int uiParam); +void Do_Update(CS10x *pstSelf, unsigned short usReason); +unsigned short GetPayloadOffset(CS10x *pstSelf); +void CheckFileDiff(CS10x *pstSelf); +unsigned short DecodeAsduMember(CS10x *pstSelf, unsigned char * pucAsdu, unsigned short usAsduSz); +unsigned short GetTaskTItype(CS10x *pstSelf, unsigned short usDataType); +/************************************外部接口函数声明*************************/ +extern unsigned short GB10x_EncodeAsdu(CS10xHandle_t pstSelf, unsigned char * pucBuf); +extern void DecodeAsduInfoObj(CS10x *pstSelf); +extern unsigned short EncodeAsdu(CS10x *pstSelf); +extern void DoAckFrame(CS10x *pstSelf); +/********************************文件传输接口**************************************/ +void Revc_ReadFS_CallDir_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //召唤目录 + +void Revc_ReadFS_AckCallDir_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //召唤目录确认 + +void Revc_ReadFS_SelectFile_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //读文件激活 + +void Revc_ReadFS_AckSelectFile_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //读文件激活确认 + +void Revc_ReadFS_CallFileSeg_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //读文件数据 + +void Revc_ReadFS_AckFileSeg_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet); //读文件数据响应 + +void Recv_WriteFS_SelectFile_S(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet); + +void Recv_WriteFS_AckSelectFile_M(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet); + +void Recv_WriteFS_DownFileSeg_S(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet, unsigned short usFileDateLen); + +void Recv_WriteFS_AckDownFileSeg_M(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet); + +unsigned short Send_ReadFS_CallDir_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_ReadFS_AckCallDir_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_ReadFS_SelectFile_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_ReadFS_AckSelectFile_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_ReadFS_CallFileSeg_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_ReadFS_AckFileSeg_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet); + +unsigned short Send_WriteFS_SelectFile_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet); + +unsigned short Send_WriteFS_AckSelectFile_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet); + +unsigned short Send_WriteFS_DownFileSeg_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet); + +unsigned short Send_WriteFS_AckDownFileSeg_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet); + +void Do_ObtainDelay(CS10x *pstSelf, unsigned short usReason); + +unsigned short CS10x_Send_ObtainDelay(CS10x *pstSelf, unsigned int uiParam); + +void Do_ParamRead_NanWang(CS10x *pstSelf, unsigned short usReason); + +unsigned short CS10x_Send_ParamRead_NanWang(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_ParamRdResponse_NanWang(CS10x *pstSelf, unsigned int uiParam); + +unsigned short CS10x_Send_ParamSolidify_NanWang(CS10x *pstSelf, unsigned int uiParam); + +void Do_ParamPreset_NanWang(CS10x *pstSelf, unsigned short usReason); + +void DoParamSolidify_NanWang(CS10x *pstSelf, unsigned short usReason); + +unsigned short CS10x_Send_ParamPreset_NanWang(CS10x *pstSelf, unsigned int uiParam); + +void Do_ParamWrite_Nanwang(CS10x *pstSelf, unsigned short usReason); + +unsigned short CS10x_Send_ParamWrite_Nanwang(CS10x *pstSelf, unsigned int uiParam); +#endif \ No newline at end of file diff --git a/src/protocol/lib60870/inc/cbb_compat.h b/src/protocol/lib60870/inc/cbb_compat.h new file mode 100644 index 0000000..fb2dda3 --- /dev/null +++ b/src/protocol/lib60870/inc/cbb_compat.h @@ -0,0 +1,25 @@ +/* + * cbb_compat.h — CBB 库兼容类型别名 + * + * CBB 库(lib60870)使用了 u8/u16/u32/s16/s32/f32/BOOL/TRUE/FALSE + * 等自定义类型/宏,这些类型在原库中依赖 ostype.h 外部定义。 + * 此处通过 gcc -include 注入,不修改 CBB 库任何源文件。 + */ +#ifndef _CBB_COMPAT_H_ +#define _CBB_COMPAT_H_ + +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef int16_t s16; +typedef int32_t s32; +typedef float f32; +typedef bool BOOL; + +#define TRUE true +#define FALSE false + +#endif /* _CBB_COMPAT_H_ */ diff --git a/src/protocol/lib60870/inc/gb101.h b/src/protocol/lib60870/inc/gb101.h new file mode 100644 index 0000000..2aeb5a5 --- /dev/null +++ b/src/protocol/lib60870/inc/gb101.h @@ -0,0 +1,106 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : gb101.h + 版 本 号 : V1.0 + 生成日期 : 2022年03月23日 + 最近修改 : + 功能描述 : gb101.c的头文件 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年03月23日 + 修改内容 : 创建文件 + +******************************************************************************/ +#ifndef __GB101_H +#define __GB101_H +/**************************************文件包含*******************************/ +#include +#include +#include "lib60870_common.h" +#include "lib60870_public.h" +#include "lib60870_process.h" +#include "Asdu.h" +/**************************************宏定义*********************************/ +#define START_CODE_101_LONG 0x68 //101规约长帧头 +#define START_CODE_101_SHORT 0x10 //101规约短帧头 +#define TAIL_CODE_101 0x16 //101规约报文尾 +#define HEAD_LEN_101 7 //101规约ASDU前的字节长度 包含控制域及2字节地址 +#define SHORT_LEN_S 5 //公共地址单字节时101短帧长度 +#define SHORT_LEN 6 //公共地址双字节时101短帧长度 +#define HEAD_TAIL_LEN 6 //101规约长帧头尾总长度 +#define HEAD_LEN 4 //101规约长帧头长度 + + +#define RESET_LINK 0 //复位链路 +#define TEST_LINK 2 //测试帧 +#define ACK_LINK 0 //确认帧 +#define DATA_SEND 3 //长帧的功能码 +#define NONE_DATA 4 //无回答数据 +#define REQUEST_LINK 9 //请求链路状态 +#define LINKSTATUS 11 //请求链路状态回复帧 +#define FCVOFF 0 //FCB位无效 +#define FCVON 1 //FCB位有效 +#define PRM_MASTER 1 //启动站 这里与主站 终端有区别 +#define PRM_SLAVE 0 //从动站 这里与主站 终端有区别 + +#define WAITTIME_101 10000 //短帧等待最大超时时间 +#define TIMEOUT 3000 //101短帧超时重发时间 +#define RESENDCNT_MAX 5 //重发次数 +#define REINITTIME 300000 //5min重发初始化 +/************************************数据结构定义*****************************/ +/** +* @brief 平衡101规约控制域定义 +*/ +typedef union +{ + struct //上行 低位在上 + { + unsigned char FC : 4; + unsigned char DFC : 1; + unsigned char RES : 1; + unsigned char PRM : 1; + unsigned char DIR : 1; + } bits_up; + + struct //下行 + { + unsigned char FC : 4; + unsigned char FCV : 1; + unsigned char FCB : 1; + unsigned char PRM : 1; + unsigned char DIR : 1; + } bits_down; + + unsigned char control; +} CONTROL101; + +/**************************************数据声明******************************/ + +/**************************************内部函数声明***************************/ +char GB101_DecodeProcess(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen); +void GB101_LongFrame(CS10xHandle_t pstSelf, unsigned char *pucFrameStart); +void GB101_ShortFrame(CS10xHandle_t pstSelf, unsigned char *pucFrameStart); +char GB101_EncodeFrame(CS10xHandle_t pstSelf); +char GB101_EncodeOther(CS10xHandle_t pstSelf); +void GB101_TimerOut(CS10xHandle_t pstSelf, unsigned short usGap); +void GB101_Resend(CS10xHandle_t pstSelf, unsigned short usGap); +void GB101_Link_Init(CS10xHandle_t pstSelf, unsigned short usGap); +unsigned short GB101_EncodeFrameHead(CS10xHandle_t pstSelf, VIec101Frame * pstFrame); +void GB101_EncodeFrameTail(CS10xHandle_t pstSelf, VIec101Frame *pstFrame); +void GB101_Summon(CS10xHandle_t pstSelf); +void GB101_TimeSyn(CS10xHandle_t pstSelf); +void GB101_Heart(CS10xHandle_t pstSelf, unsigned short usGap); +void GB101_SendAck(CS10xHandle_t pstSelf); +void GB101_SendLinkStatus(CS10xHandle_t pstSelf); +void GB101_SendResetLink(CS10xHandle_t pstSelf); +void GB101_SendRequestLink(CS10xHandle_t pstSelf); +void GB101_SendTestLink(CS10xHandle_t pstSelf); +unsigned char GB101_Control(CS10xHandle_t pstSelf, unsigned char ucPRM, unsigned char ucFCV, unsigned char ucFC); +/************************************外部接口函数声明*************************/ + +extern void CS10x_101Init(CS10xHandle_t pstSelf, CS10x_SendCb cb, void *arg, CS10x_Type enType); + +#endif \ No newline at end of file diff --git a/src/protocol/lib60870/inc/gb103.h b/src/protocol/lib60870/inc/gb103.h new file mode 100644 index 0000000..3d44901 --- /dev/null +++ b/src/protocol/lib60870/inc/gb103.h @@ -0,0 +1,353 @@ +/* + * IEC103Type.h + */ + +#ifndef IEC103TYPE_H_ +#define IEC103TYPE_H_ + +//#include "ostype.h" +#include "lib60870_common.h" + +typedef enum +{ + CS103_TYPE_S = 0, /*CS103 从*/ + CS103_TYPE_M, /*CS103 主*/ +}CS103_Type; + +enum ASDU_TYPE +{ + ASDU_1 = 0x01, + ASDU_2 = 0x02, + ASDU_10 = 0x0A, + ASDU_40 = 0x28, + ASDU_41 = 0x29, + ASDU_42 = 0x2A, + ASDU_43 = 0x2B, + ASDU_44 = 0x2C, + ASDU_45 = 0x2D, + ASDU_46 = 0x2E, + ASDU_50 = 0x32, +}; + +enum CMD_SEND +{ + CMD_RESET_CON = 1, + CMD_RESET_NUM, + CMD_RESET_TIMESTAMP, //对时 + CMD_RESET_EVENT, //复归命令 + CMD_SETTING_DOWNLOAD, //定值下载 + CMD_SETTING_MODIFY, //定值修改 + CMD_YK, //遥控功能 + CMD_GET_ALL, + CMD_GET_DATA_LV1, //获取一级数据 + CMD_GET_DATA_LV2, //获取二级数据 + CMD_GET_SINGLE_SETTING_VALUE, //获取单个条目值 + CMD_GENERAL_READ_YX_GROUP_VALUE, + CMD_GENERAL_READ_YC_GROUP_VALUE, +}; + +//标志位在报文中的位置 +#define CODE_POSI 4 //控制域 +#define TYP_POSI 6 //类型标识 +#define VSQ_POSI 7 //可变结构限定词 +#define COT_POSI 8 //传送原因 +#define ADDR_POSI 9 //设备地址 +#define FUN_POSI 10 //功能类型 +#define INF_POSI 11 //信息序号 +#define RII_POSI 12 //返回信息标识符 +#define DPI_POSI 12 //双点信息 +#define RET_POSI 13 //相对时间 表示装置启动到该元件动作的相对时间,毫秒 +#define FAN_POSI 15 //故障序号 +#define ASDU_1_TIMESTAMP 13 //ASDU1中四字节时间起始位置 +#define ASDU_2_TIMESTAMP 17 //ASDU2中四字节时间起始位置 +#define GROUP_POSI 14 //组号 +#define TNTRY_POSI 15 //条目号 +#define KOD_POSI 16 //描述的类别 +#define GDD_POSI 17 //通用分类数据描述 +#define GID_POSI 20 //通用分类标识数据 +#define NGD_POSI 13 //通用分类数据集数目 + + + +#define START_10H 0x10 //固定长度报文启动字符 +#define START_68H 0x68 //可变长度报文启动字符 +#define END_16H 0x16 //结束字符 +#define FCB_1 0x20 //帧计数位 +#define FCV_1 0x10 //帧计数有效位 +#define ACD_1 0x20 //有一级数据上送 +#define PRA_1 0x40 //启动报文位 主到从 +#define KOD_1 0x01 //描述类别 1为实际值 + +//功能码定义 +#define FNA_S2C_RESET_CON 0 //复位通信功能码 +#define FNA_S2C_RESET_NUM 7 //复位帧计数位功能码 +#define FNA_S2C_POSTDATA_3 3 //传送数据(发送/确认帧) +#define FNA_S2C_POSTDATA_4 4 //传送数据(发送/无回答帧) +#define FNA_S2C_GETDATA_LV1 10 //召唤一级数据功能码 +#define FNA_S2C_GETDATA_LV2 11 //召唤二级数据功能码 + +//ASDU号定义 +#define ASDU6_TIMESTAMP 6 // 对时 +#define ASDU7_GETALL 7 // 总召唤,遥信 +#define ASDU20_RESET 20 // 复归 +#define ASDU21_GETGROUP 21 // 总召唤,要测 +#define ASDU10_SETTING 10 // 定值 +#define ASDU20_RESET 20 // 复归 +#define ASDU21_GETGROUP 21 // 总召唤,遥测 +#define ASDU60 60 // 遥控 + +//COT传送原因定义 +//控制方向 +#define COT_S2C_TIMESTAMP 8 //时间同步 +#define COT_S2C_GETALL_START 9 //总查询(总召唤)的启动 +#define COT_S2C_REMOTE 0x0c //远方操作 +#define COT_S2C_COMMON_ORDER 0x14 //一般命令 +#define COT_S2C_GENERAL_WRITE 0x28 //通用分类写命令 +#define COT_S2C_GENERAL_READ 0x2A //通用分类读命令 + +//FUN定义 +#define FUN_GLB 0xFF //全局功能类型 +#define FUN_GEN 0xFE //通用分类服务功能类型 + + +//INF定义 +#define INF_RESET_ORDER 0x13 //复归命令,所有装置相同 +#define INF_READ_GROUP 0xF1 //读一个组的全部条目的值或者属性 +#define INF_READ_EBTRY 0xF4 //读一个条目的值或者属性 +#define INF_CONFIRM_WRITE 0xF9 //带确认的写条目 +#define INF_EXEC_WRITE 0xFA //带执行的写条目 + +#define MAX_SIZE 1024 + + +typedef struct { + u8 fcb; // 桢记数位 + u8 fcv; // 桢记数有效位 +} IEC103CodeS2C; + +typedef union +{ + u32 uValue; + f32 fValue; + u8 buf[4]; +}UnionConvert4Byte; + +typedef union +{ + s16 value; + u16 uValue; + u8 buf[2]; +}UnionConvert2Byte; + +typedef struct +{ + //通用分类标识序号GIN + u8 groupNo; //组号 + u8 entryNo; //条目号 + + //描述的类别KOD + u8 kod; //1为实际值 + + //通用分类数据描述GDD + u8 datatype; //数据类型 + u8 datasize; //数据宽度 + u8 number:7, //数目 + cont:1; //后续状态位 +}stDataUnit; //通用分类数据单元 + + +typedef struct +{ + u16 msec; //毫秒 + u8 min:6, //分钟 + res1:1, //备用 + iv:1; //IV=0为有效 =1为无效 + u8 hour:7, //小时 + su:1; //su夏时制标志 + u8 day:5, //日 + dayofweek:3; //未采用 + u8 month:4, //月 + res2:4; //备用 + u8 year:7, //年 + res3:1; //备用 +}stTime7Byte; + + + +// 带品质描述词的被测量(MEA) +typedef struct { + union { + s16 mval:13, // 带符号规一化定点数,最高位符合位,数据位占12位 + res:1, // 备用位:未用(常为0) + er:1, // 差错位:0-有效,1-无效 + ov:1; // 溢出位:0-无溢出,1-溢出 + + s16 wVal; + }mea; +}MEA; + + +/** + * \brief GetLayerSt 获取链路层状态,检测是否满足发送条件 + * \param + * + * \return + */ +typedef s32 (*CS103_SendCb) (u8 *buf, u16 usLen, void *arg); + +/** + * \brief SetValue 规约更新应用数据 + * \param + * + * \return + */ +typedef s32 (*CS103_SetValue) (u8 ucFun, u8 ucInf, f32 fVal, void *pParam); + +/** + * \brief SetStatus 规约更新应用状态 + * \param + * + * \return + */ +typedef s32 (*CS103_SetStatus) (u8 ucFun, u8 ucInf, u8 ucSt, void *pParam); + +/** + * \brief AddSOE 规约添加SOE信息 + * \param + * + * \return + */ +typedef s32 (*CS103_AddSOE) (u8 ucFun, u8 ucInf, u8 ucSt, stTime7Byte *pTime, void *pParam); + + +typedef struct { + void *pUsrData; /*用户自定义数据接口*/ + + u16 usFirstNum; + + u16 usTaskID; + VFLAGS stTaskFlags; + + IEC103CodeS2C stIEC103CodeS2C; /*103控制域主到从*/ + u8 ucAddr; /*从站地址*/ + u8 ucReSend_Num; /*重发次数*/ + u16 usReSend_Gap; /*重发间隔*/ + u32 ulSummon_Gap; /*总召间隔*/ //参数关联 + u32 ulSyn_Gap; /*同步间隔*/ //参数关联 + // u32 ulHeart_Gap; /*心跳间隔*/ //参数关联 + u32 ulSend_Gap; /*数据发送间隔参数*/ + + + // u32 ulHeart_Tcn; /* 心跳累计时间计数 */ + u32 ulSummon_Tcn; /* 定时总招时间计数 */ + u32 ulTimeSyn_Tcn; /* 定时对时时间计数 */ + + u8 usResend_Ncn; /* 重发次数计数 */ + u16 usResend_Tcn; /* 重发间隔时间计数 */ + + BOOL bIsResetConEnd; /*复位通信*/ + + BOOL bIsResetNumEnd; //复位帧计数位 + BOOL bIsGetAllEnd; //总召唤 + + u8 ucIDCount; + + u8 ucYcGroupNum; + u8 ucYxGroupNum; + + u8 ucGroupNo; + u8 ucEntryNo; + + u8 ucYkFun; + u8 ucYkInf; + u8 ucYkSE; + u8 ucYkACT; + u8 ucYkDCS; + u8 ucYkQU; + + CS10x_Send_Cb SendCb; /*数据发送接口*/ + CS10x_GetTime GetTime; /*获取事件*/ + /*对外提供数据*/ + CS103_SetValue SetValue; /*规约更新应用数据*/ + CS103_SetStatus SetStatus; /*规约更新应用状态*/ + CS103_AddSOE AddSOE; /*添加SOE信息*/ + + struct VCommBuf stRecvBuf; /*接收数据缓冲区*/ + struct VCommBuf stSendBuf; /*发送数据缓冲区*/ +}CS103; + +/** + * @brief 设置设备地址 + * + * @param self + * @param pstParam + */ +void CS103_SetAddr(CS103 *self, u8 ucAddr); + +/** + * @brief 设置总召定时间隔关联 + * + * @param self + * @param pstParam + */ +void CS103_SetSummonGap(CS103 *self, u32 ulGap); + +/** + * @brief 设置对时同步间隔关联 + * + * @param self + * @param pstParam + */ +void CS103_SetSynTimeGap(CS103 *self, u32 ulGap); + +/** + * @brief 101规约重发间隔时间参数输入 + * @param self + * @param pstParam + */ +void CS103_ResendGap(CS103 *self, u16 usGap); +/** + * @brief 101规约重发次数参数输入 + * @param self + * @param pstParam + */ +void CS103_ResendCnt(CS103 *self, u8 ucCnt); + +/** + * @brief 获取时间接口 + * + * @param self + * @param cb + */ +void CS103_GetTimeHandler(CS103 *self, CS10x_GetTime cb); + +/** + * @brief 设置接收遥测接口 + * + * @param self + * @param cb + */ +void CS103_SetValueHandler(CS103 *self, CS103_SetValue cb); + +/** + * @brief 设置接收遥信接口 + * + * @param self + * @param cb + */ +void CS103_SetStatusHandler(CS103 *self, CS103_SetStatus cb); + +/** + * @brief 设置接收SOE处理函数 + * + * @param self + * @param cb + */ +void CS103_AddSOEHandler(CS103 *self, CS103_AddSOE cb); + +CS103 *CS103_Init(CS103_SendCb cb, void *arg, CS103_Type type); +void CS103_Destory(CS103 *self); +BOOL CS103_DoRecv(CS103 *self, u8 *pBuf, u16 usLen); +void CS103_TimerHandle(CS103 *self, u16 usGap); + +#endif /* IEC103TYPE_H_ */ diff --git a/src/protocol/lib60870/inc/gb104.h b/src/protocol/lib60870/inc/gb104.h new file mode 100644 index 0000000..7ba5b94 --- /dev/null +++ b/src/protocol/lib60870/inc/gb104.h @@ -0,0 +1,75 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : gb104.h + 版 本 号 : V1.0 + 生成日期 : 2022年03月23日 + 最近修改 : + 功能描述 : gb104.c的头文件 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年03月23日 + 修改内容 : 创建文件 + +******************************************************************************/ +#ifndef __GB104_H +#define __GB104_H +/**************************************文件包含*******************************/ +#include +#include +#include "lib60870_common.h" +#include "lib60870_public.h" +#include "lib60870_process.h" +#include "Asdu.h" +/**************************************宏定义*********************************/ +#define START_CODE 0x68 +#define FRM_I 0 +#define FRM_S 1 +#define FRM_U 3 + +#define MAX_FRAME_COUNTER 0x7fff +#define COUNTER_LIMIT 0x8000 + +#define STARTDT_ACT 0x07 +#define STARTDT_CON 0x0B +#define STOPDT_ACT 0x13 +#define STOPDT_CON 0x23 +#define TESTFR_ACT 0x43 +#define TESTFR_CON 0x83 + +#define T0_TimeHandle 0 +#define T1_TimeHandle 1 +#define T2_TimeHandle 2 +#define T3_TimeHandle 3 +/************************************数据结构定义*****************************/ +/** +* @brief +*/ +/**************************************数据声明******************************/ + +/**************************************内部函数声明***************************/ +char GB104_DecodeProcess(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen); +void GB104_Preprocessor(CS10xHandle_t pstSelf); +void DoSFrame(CS10xHandle_t pstSelf); +void DoUFrame(CS10xHandle_t pstSelf); + +char GB104_EncodeFrame(CS10xHandle_t pstSelf); +char GB104_EncodeOther(CS10xHandle_t pstSelf); + +unsigned short GB104_EncodeApci(CS10xHandle_t pstSelf, unsigned char ucFrameType, VIec104Frame * pstFrame); +void GB104_EncodeApduLen(CS10xHandle_t pstSelf, VIec104Frame * pstApdu); +void GB104_FrameTimerHdl(CS10xHandle_t pstSelf, VIec104Frame * pstApdu); + +void GB104_SendAck(CS10xHandle_t pstSelf); +void SendUFrame(CS10xHandle_t pstSelf, unsigned char ucType); + +void StopTimer(CS10xHandle_t pstSelf, unsigned short usTimerId); +void StartTimer(CS10xHandle_t pstSelf, unsigned short usTimerId); +void GB104_TimerOut(CS10xHandle_t pstSelf, unsigned short usGap); +bool Check_IEC_104(unsigned char* pstBuf, unsigned short uslen); +/************************************外部接口函数声明*************************/ +extern void CS10x_104Init(CS10xHandle_t pstSelf, CS10x_SendCb cb, void *arg, CS10x_Type enType); + +#endif \ No newline at end of file diff --git a/src/protocol/lib60870/inc/lib60870_common.h b/src/protocol/lib60870/inc/lib60870_common.h new file mode 100644 index 0000000..99f9a3d --- /dev/null +++ b/src/protocol/lib60870/inc/lib60870_common.h @@ -0,0 +1,2485 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : lib60870_common.h + 版 本 号 : V1.0 + 生成日期 : 2022年04月07日 + 最近修改 : + 功能描述 : 101及104规约实现中的公共数据及外部服务接口模块 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年04月07日 + 修改内容 : 创建文件 +*******************************************************************************/ +#ifndef SRC_INC_IEC60870_COMMON_H_ +#define SRC_INC_IEC60870_COMMON_H_ + +#include "lib60870_inc.h" +#include "md5.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define COMTRADE "COMTRADE" +#define SOEPATH "HISTORY/SOE" +#define COPATH "HISTORY/CO" +#define EXVPATH "HISTORY/EXV" +#define FIXPTPATH "HISTORY/FIXPT" +#define FRZPATH "HISTORY/FRZ" +#define FLOWREVPATH "HISTORY/FLOWREV" +#define ULOGPATH "HISTORY/ULOG" +#define FAULTPATH "HISTORY/FAULT" + +#define YC_TYPE_ME_NA 0 /*正常测量值*/ +#define YC_TYPE_ME_NB 1 /*标度化值*/ +#define YC_TYPE_ME_NC 2 /*浮点遥测*/ + +#define YX_TYPE_M_SP 0 /*单点遥信*/ +#define YX_TYPE_M_DP 1 /*双点遥信*/ + +#define YK_TYPE_C_SC 0 /*单点遥控*/ +#define YK_TYPE_C_DC 1 /*双点遥控*/ + +#define DD_TYPE_IT_NB 0 /*不带时标*/ +#define DD_TYPE_IT_TC 1 /*不带时标*/ + +#define CONST_NUM_MSG 100 +#define WAVE_MAX_TIME 360000 //6min堵塞时间 +/** + * \brief 协议类型,初始化时幅值 + */ +typedef enum +{ + CS101_TYPE_S = 0, /*CS101 从*/ + CS101_TYPE_M, /*CS101 主*/ + CS104_TYPE_S, /*CS104 从*/ + CS104_TYPE_M, /*CS104 主*/ +} CS10x_Type; + +/** + * \brief 协议类型,初始化时幅值 + */ +typedef enum +{ + TSKID_ReSend = 0, /*重发标识*/ + TSKID_Anomaly, /*异常帧任务标识*/ + TSKID_RequestLink, /*101规约请求链路状态*/ + TSKID_ResetLink, /*101规约复位链路*/ + TSKID_MResponse, /*101规约链路状态响应*/ + TSKID_StartLink, /*104规约启动链路*/ + TSKID_StopLink, /*104规约断开链路*/ + TSKID_UTest, /*104规约测试U帧*/ + TSKID_Ack, /*101/104共用确认*/ + + TSKID_InitFinish, /*初始化完成*/ + TSKID_YkProcess, + TSKID_SendCOS, /*COS信息*/ + TSKID_SendSOE, /*SOE*/ + TSKID_SummonYx, /*总招遥信响应*/ + TSKID_SummonYc, /*总招遥测响应*/ + TSKID_SummonResponse, /*总招响应及总招下发共用*/ + TSKID_DdSummon, /*总招电能量及响应*/ + TSKID_DdData, /*电能量数据传输*/ + TSKID_DdTimeData, /*电能量时标数据传输*/ + TSKID_FaultSoe, /*故障事件*/ + TSKID_TimeSyn, /*时钟同步*/ + TSKID_YcDisturb, /*扰动数据*/ + TSKID_ResetProcess, /*复位进程*/ + TSKID_HeartBeat, /*心跳*/ + TSKID_DataTest, /*长帧测试*/ + TSKID_ChgConst, /*修改定值区*/ + TSKID_ReadConst, /*读取定值区*/ + TSKID_ParamPreread, /*参数读取*/ + TSKID_ParamPrewrite, + /* + * TypeID=120-126方式 目前大部分地区不使用 + */ + TSKID_DirReqByNode, /*目录读取*/ + TSKID_FileReady, /*文件就绪*/ + TSKID_NodReady, /*节点就绪*/ + TSKID_NodeData, /*节点数据响应*/ + TSKID_NodeEnd, /*节点结束*/ + TSKID_FileEnd, /*文件结束*/ + /* + * 细则中按照 210进行文件操作 + */ + TSKID_FilePro, + TSKID_UpdateStart, /*启动升级*/ + TSKID_UpdateExe, /*执行升级*/ + TSKID_DirReqByFile, /*读目录任务*/ + /* + * 南网规约 + */ + TSKID_ObtainDelay, /*延时获得命令-南网规约*/ + TSKID_ParamRead_NanWang, /*读参数命令-南网规约*/ + TSKID_ParamReadResponse_NanWang,/*读参数回复命令-南网规约*/ + TSKID_ParamPreset_NanWang, /*参数预置命令-南网规约*/ + TSKID_ParamSolidify_NanWang, /*参数固化命令-南网规约*/ + TSKID_ParamWrite_NanWang, /*参数预置/固化命令-南网规约(类型标识 55)*/ +} CS10x_TSKID; + +typedef enum +{ + FILE_ST_IDLE = 0, /*空闲*/ + FILE_ST_RD_DIR, /*读取目录*/ + FILE_ST_RD_DIR_RESPONE, /*响应目录读取*/ + FILE_ST_RD_FILE_ACT, /*读文件激活*/ + FILE_ST_RD_FILE_ACT_RESPONE, /*读文件激活确认*/ + FILE_ST_RD_FILE_DATA, /*读文件数据响应*/ + FILE_ST_RD_FILE_DATA_RESPONE, /*读文件数据传输确认*/ + FILE_ST_WR_FILE_ACT, /*写文件激活*/ + FILE_ST_WR_FILE_ACT_RESPONE, /*写文件激活确认*/ + FILE_ST_WR_FILE_DATA, /*写文件*/ + FILE_ST_WR_FILE_DATA_RESPONE, /*写文件响应*/ + FILE_ST_WR_FILE_DATA_Wait, /*文件写等待*/ +} IEC_FILE_ST; + +/** + * \brief Message type IDs + */ +#define M_DP_NA 3 //不带时标的双点信息 +#define M_SP_NA 1 //不带时标的单点信息 +#define M_ST_NA 5 //步位置信息 +#define M_BO_NA 7 //子站远动终端状态 +#define M_ME_NA 9 //测量值 +#define M_ME_NB 11 //标度化测量值 +#define M_ME_NC 13 //测量值-短浮点数 +#define M_IT_NA 15 //电能脉冲记数量 +#define M_PS_NA 20 //具有状态变位检出的成组单点信息 +#define M_ME_ND 21 //不带品质描述的测量值 +#define M_SP_TB 30 //带长时标的单点信息 +#define M_ST_TB 32 //带长时标的步位置信息 +#define M_DP_TB 31 //带长时标的双点信息 +#define M_BO_TB 33 //带长时标的32位位串 +#define M_ME_TD 34 //带长时标的测量值 +#define M_FT_NA 42 //故障事件信息 +#define C_SC_NA 45 //单点遥控命令 +#define C_DC_NA 46 //双点遥控命令 +#define C_RC_NA 47 //升降命令 +#define C_SE_NA 48 //设定命令 +#define C_SP_NA 55 //参数预置-南网(类型标识55) +#define M_EI_NA 70 //初始化结束 +#define C_IC_NA 100 //召唤命令 +#define C_CI_NA 101 //电能脉冲召唤命令 +#define C_RD_NA 102 //读数据命令 +#define C_CS_NA 103 //时钟同步命令 +#define C_TS_NA 104 //测试命令 +#define C_RP_NA 105 //复位进程命令 +#define C_CD_NA 106 //延时获得命令-南网 +#define C_RS_NA_NANWANG 108 //读参数命令-南网 +#define P_ME_NC 112 //参数预置-南网 +#define P_AC_NA 113 //参数固化-南网 +#define C_TS_TA 107 //带时标的测试命令 +#define M_FA_NA 142 //FA故障信息 +#define C_FA_SIM 143 //FA 模拟 +#define C_SR_NA 200 //切换定值区 +#define C_RS_NA 202 //读参数和定值 +#define C_RR_NA 201 //读定值区号 +#define C_WS_NA 203 //写参数和定值 +#define M_IT_NB 206 //不带时标的累计量-短浮点 +#define M_IT_TC 207 //带时标的累计量-短浮点 +#define F_FR_NA 210 //文件升级 +#define F_SR_NA 211 //软件升级 +#define ANOMALY 255 //扩展为异常帧ID + +/** + * \brief Cause Of Transmission + */ + +#define COT_PN 0x40 /*PN位 0-肯定确认 1-否认确认*/ + +#define COT_PERCYC 1 //周期/循环 +#define COT_BACK 2 //背景扫描 +#define COT_SPONT 3 //突发 +#define COT_INIT 4 //初始化 +#define COT_REQ 5 //请求或被请求 +#define COT_ACT 6 //激活 +#define COT_ACTCON 7 //激活确认 +#define COT_DEACT 8 //停止激活 +#define COT_DEACTCON 9 //停止激活确认 +#define COT_ACTTERM 10 //激活结束 +#define COT_RETREM 11 //远程命令引起的返送信息 +#define COT_RETLOC 12 //当地命令引起的返送信息 +#define COT_FILE 13 //文件传送 +#define COT_INTROGEN 20 //响应总召唤 +#define COT_INRO1 21 //响应第1组召唤 +#define COT_INRO2 22 //响应第2组召唤 +#define COT_INRO3 23 //响应第3组召唤 +#define COT_INRO4 24 //响应第4组召唤 +#define COT_INRO5 25 //响应第5组召唤 +#define COT_INRO6 26 //响应第6组召唤 +#define COT_INRO7 27 //响应第7组召唤 +#define COT_INRO8 28 //响应第8组召唤 +#define COT_INRO9 29 //响应第9组召唤 +#define COT_INRO10 30 //响应第10组召唤 +#define COT_INRO11 31 //响应第11组召唤 +#define COT_INRO12 32 //响应第12组召唤 +#define COT_INRO13 33 //响应第13组召唤 +#define COT_INRO14 34 //响应第14组召唤 +#define COT_INRO15 35 //响应第15组召唤 +#define COT_INRO16 36 //响应第16组召唤 +#define COT_REQCO1 38 //响应第1组计数量召唤 +#define COT_REQCOGCN 37 //响应计数量总召唤 +#define COT_REQCO2 39 //响应第2组计数量召唤 +#define COT_REQCO3 40 //响应第3组计数量召唤 +#define COT_REQCO4 41 //响应第4组计数量召唤 +#define COT_E_SBSTA 48 //遥控执行软压板状态错误 +#define COT_E_TIME 49 //遥控执行时间戳错误 +#define COT_E_SIGN 50 //遥控执行数字签名认证错误 +#define COT_E_TYPE 44 /**<未知的类型标识*/ +#define COT_E_REASON 45 /**<未知的传送原因*/ +#define COT_E_CADDR 46 /**<未知的ASDU公共地址*/ +#define COT_E_IADDR 47 /**<未知的信息对象地址*/ + +#define QOI 20 //总召唤 召唤限定词 +#define QCC 5 //总的请求电能量 +#define QRP 1 //进程总复位 复位进程命令限定词 +#define COI_0 0 //初始化原因 当地电源合上 +#define COI_1 1 //初始化原因 当地手动复位 +#define COI_2 2 //初始化原因 远方复位 +#define FBP 0xAA55 //测试命令限定词 + +#define YKSELECT_1 0x81 //选择合 双点加1 +#define YKSELECT_0 0x80 //选择分 双点加1 +#define YKEXCUTE_1 0x01 //执行合 双点加1 +#define YKEXCUTE_0 0x00 //执行分 双点加1 +#define YKCANCEL_1 0x01 //撤销合 双点加1 +#define YKCANCEL_0 0x00 //撤销分 双点加1 +#define YKSTOP_1 0x01 //终止合 双点加1 +#define YKSTOP_0 0x00 //终止分 双点加1 + +//#define YK_CLOSE 2 //遥控合 +//#define YK_OPEN 1 //遥控分 + +#define FILE_TRANS 2 //文件传输附加数据包类型 2表示文件传输 + +#define PARAM_CONT_1 0x01 //参数固化后续状态位1 +#define PARAM_CONT_0 0x00 //参数固化后续状态位0 +#define PARAM_CR_1 0x40 //取消预置 +#define PARAM_SE_1 0x80 //参数预置 +#define PARAM_SE_0 0x00 //参数固化 +#define READ_ALL_PARAM 0x01 //读全部参数 + +#define PARAM_ST_NONE 0x00 //无任务 +#define PARAM_ST_START 0x01 //任务开始 +#define PARAM_ST_END 0x02 //任务开始 +#define PARAM_ST_OK 0x03 //任务开始 +#define PARAM_ST_TIMEOUT 0x10 //超时 + +#define TSK_PARM_NONE 0 //无任务标识 +#define TSK_PARM_USACT 1 //U&S帧激活 101/104共用 +#define TSK_PARM_USTCON 2 //U&S帧激活确认 + +#define CONTINUE 1 //信息体地址连续 +#define DISCONTINUE 0 //信息体地址不连续 + +#define SHORT_TYPE 2 //待发送数据为短帧 +#define LONG_TYPE 1 //待发送数据为长帧 +#define RESEND_TYPE 3 //待发送数据为重发帧 +#define WAVE_TYPE 4 //启动录波任务 + +#define SETUP_SET_SUMMON 0 //设置初始化总召任务 +#define SETUP_WAIT_SUMMON 1 //等待初始化总召 +#define SETUP_OK_SUMMON 2 //总召任务结束 +#define SETUP_SET_SYN 3 //设置初始化对时 +#define SETUP_WAIT_SYN 4 //等待初始化对时 +#define SETUP_OK_SYN 5 //对时完成 + +#define WRITE_FILE_ERR_NONE 0 +#define WRITE_FILE_ERR_OTHER 1 +#define WRITE_FILE_ERR_CHECK 2 +#define WRITE_FILE_ERR_LEN 3 +#define WRITE_FILE_ERR_ID 4 + +#define WRITE_PARAM_YZ 1 +#define WRITE_PARAM_YZCON 2 +#define WRITE_PARAM_GH 3 +#define WRITE_PARAM_GHCON 4 +#define WRITE_PARAM_CA 5 +#define WRITE_PARAM_CACON 6 +#define WRITE_PARAM_NONE 0 +// #define WRITE_FILE_ERR_LEN 3 +// #define WRITE_FILE_ERR_ID 4 + +#define PARAM_READ 1 +#define PARAM_WRITE 2 +#define PARAM_IDLE 0 + +#define MASTER_TYPE 1 +#define DEV_TYPE 0 +//标志操作相关定义 +#define MAX_FLAGNO 128 //每个模块最多的标志位数 + +#define MAX_FRAME_LEN 255 +#define APCI_LEN 6 + +#define DATATYPE_YC 1 //遥测 +#define DATATYPE_YX 2 //遥信 +#define DATATYPE_Yk 3 //遥控 +#define DATATYPE_YXT 4 //带时标遥信 + +#define CURPARAMAREA 0 /*当前定值区*/ +#define MINPARAMAREA 1 /*最小定值区*/ +#define MAXPARAMAREA 2 /*最大定值区*/ + +#define IECPARAMRD 0 /*读参数定值区*/ +#define IECPARAMWT 1 /*写参数定值区*/ + +/** + * \brief 任务标识 + */ +typedef struct +{ + unsigned char ucFlag[ MAX_FLAGNO / 8 ]; /*任务数列*/ +} VFLAGS; + +typedef struct +{ + unsigned char byStartCode; + unsigned char byAPDULen; + unsigned char byControl1; + unsigned char byControl2; + unsigned char byControl3; + unsigned char byControl4; + unsigned char byASDU[MAX_FRAME_LEN - APCI_LEN]; +} VIec104Frame; + +/** +* @brief 101规约短帧格式 单字节地址 +*/ +typedef struct +{ + unsigned char ucStart; + unsigned char ucControl; + unsigned char ucAddr; + unsigned char ucCS; + unsigned char ucTail; +} VFrame10_S; + +/** +* @brief 101规约短帧格式 双字节地址 +*/ +typedef struct +{ + unsigned char ucStart; + unsigned char ucControl; + unsigned char ucAddr_L; + unsigned char ucAddr_H; + unsigned char ucCS; + unsigned char ucTail; +} VFrame10; + +/** +* @brief 101规约长帧格式 +*/ +typedef struct +{ + unsigned char ucStart1; + unsigned char ucLength1; + unsigned char ucLength2; + unsigned char ucStart2; + unsigned char ucControl; + unsigned char ucaData[MAX_FRAME_LEN - 5]; +} VFrame68; + +/** +* @brief 101规约帧格式 +*/ +typedef union +{ + VFrame10 stFrame10; + VFrame10_S stFrame10_S; + VFrame68 stFrame68; +} VIec101Frame; + +/** + * \brief 参数 + */ +typedef struct +{ + unsigned char byTskId; //任务序号 + unsigned char byTskSt; //任务状态 + unsigned char byTskRe; //任务预留 + unsigned int uiTskCot; + unsigned short usTskTcn; +} ParamTsk_st; + +/** + * \brief Parameters for the CS101/CS104 application layer + */ +typedef struct CS10x_AppLayerParameters *pCS10x_AppLayerParameters; + +struct CS10x_AppLayerParameters +{ + int iSzOfLinkAddr; /*链路地址长度 CS101*/ + int iSzOfTypeId; /* 类型长度 size of the type id (default = 1 - don't change) */ + int iSzOfVSQ; /* VSQ长度 don't change */ + int iSzOfCOT; /* 传输原因长度 size of COT (1/2 - default = 2 -> COT includes OA) */ + int iSzOfCA; /* 公共地址长度 size of common address (CA) of ASDU (1/2 - default = 2) */ + int iSzOfIOA; /* 信息体地址长度 size of information object address (IOA) (1/2/3 - default = 3) */ + int iLinkAddr; /*链路地址*/ + int iPublicAddr; /*公共地址*/ + int iMaxSzOfAsduLen; /* maximum size of the ASDU that is generated - the maximum maximum value is 249 for IEC 104 and 254 for IEC 101 */ +}; + +/** + * \brief Parameters for CS104 connections - APCI (application protocol control information) + */ +typedef struct CS104_APCIParameters *pCS104_APCIParameters; + +struct CS104_APCIParameters +{ + int iK; + int iW; + int iT0; + int iT1; + int iT2; + int iT3; +}; + +/** + * \brief 任务标识 + */ +typedef struct +{ + unsigned short usTypeID; /*类型标识符*/ + unsigned short usSQ; /*连续、离散标识*/ + unsigned short usNum; /*信息对象个数*/ + unsigned short usCot; /*传送原因*/ + unsigned int uiAddr; /*公共地址*/ + unsigned char *pucPayload; /*信息对象起始位置*/ + unsigned short usPayloadSize; /*信息对象大小*/ + unsigned short usCotH; /*传送原因高字节值*/ +} ASDU_Element; + +/** + * \brief 数据缓冲 + */ +struct VCommBuf +{ + unsigned short usBufSize; /*缓冲区大小*/ + unsigned short usReadPtr; /*读指针*/ + unsigned short usWritePtr; /*写指针*/ + int iFlag; /*控制码(主要用于发送)*/ + unsigned char *pBuf; /*缓冲区*/ +}; + +/** + * \brief 104时间计数 + */ +typedef struct +{ + bool bRun; + unsigned short usInitVal; + unsigned int uiCounter; +} VIec104Timer; + +/** + * \brief CP56Time + */ +typedef struct +{ + unsigned char ucLMs; /*毫秒低位*/ + unsigned char ucHMs; /*毫秒低位*/ + unsigned char ucMin; /*分钟*/ + unsigned char ucHour; /*小时*/ + unsigned char ucWeek; /**< week: 0-不用,n-星期n */ + unsigned char ucMonth; /*月*/ + unsigned char ucYear; /*年*/ +} __CP56Time2a; + +/** + * \brief Yx信息 + */ +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + unsigned char ucStatus; /*状态信息*/ + unsigned char ucStateType; // 单点双点 +} Yx_Info; + +/** + * \brief Yc信息 + */ +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + float fVal; /*遥测值*/ + unsigned char ucQds; +} Yc_Info; + +/** + * \brief Yk信息 + */ +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + unsigned char ucStatus; /*状态信息*/ + unsigned char ucStateType; // 单点遥控/双点遥控 + unsigned char ucYkType; // 执行/选择 +} Yk_Info; + +/** + * \brief Dd信息 + */ +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + float fVal; /*遥测值*/ +} Dd_Info; + +/** + * \brief SOE 记录信息 + */ +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + unsigned char ucStatus; /*状态位*/ + unsigned char ucStateType; // 单点双点 + __CP56Time2a stCTime; /*时间*/ +} SOE_Info; + +typedef struct +{ + unsigned int uiInfoAddr; /*信息体地址*/ + float fVal; /*遥测值*/ + __CP56Time2a stCTime; /*时间*/ +} TimeDd_Info; + +/** + * \brief SOE队列信息 + */ +#define MAX_SOE_QUEUE_SIZE 256 /*SOE缓冲记录最大个数*/ +typedef struct +{ + unsigned short usReadPrt; /*确认SOE位置*/ + unsigned short usWritePrt; /*未确认SOE位置*/ + unsigned short usCosPrt; /*COS发送位置*/ + unsigned short usSoePrt; /*SOE发送位置*/ + unsigned short usaSeq[MAX_SOE_QUEUE_SIZE]; /*104I帧序列号 用于主站确认*/ + SOE_Info staInfo[MAX_SOE_QUEUE_SIZE]; /*SOE事件信息*/ +} SOE_Queue; + +/** + * \brief 故障事件信息 + */ +#define MAX_FAULT_EVENT_SOE_SIZE 16 +#define MAX_FAULT_EVENT_YC_SIZE 16 +typedef struct +{ + unsigned short usSoeNum; // YX数量 + SOE_Info staSoe[MAX_FAULT_EVENT_SOE_SIZE]; /*SOE信息内容*/ + unsigned short usYcNum; // YC数量 + Yc_Info staYc[MAX_FAULT_EVENT_YC_SIZE]; /*YC信息内容*/ +} FAULT_EVENT_Info; + +/** + * \brief 故障事件队列信息 + */ +#define MAX_FAULT_EVENT_QUEUE_SIZE 20 /*故障事件队列大小*/ +typedef struct +{ + unsigned short usReadPrt; /*确认故障事件位置*/ + unsigned short usWritePrt; /*未确认故障事件位置*/ + unsigned short usSendPrt; /*未确认故障事件位置*/ + FAULT_EVENT_Info staFault[MAX_FAULT_EVENT_QUEUE_SIZE]; /*故障事件信息*/ +} FAULT_EVENT_Queue; + +/** + * \brief 故障事件队列信息 + */ +#define MAX_YC_DISTURB_QUEUE_SIZE 200 /*扰动遥测队列大小*/ +typedef struct +{ + unsigned short usReadPrt; /*确认故障事件位置*/ + unsigned short usWritePrt; /*未确认故障事件位置*/ + unsigned short usSendPrt; /*未确认故障事件位置*/ + Yc_Info staYc[MAX_YC_DISTURB_QUEUE_SIZE]; /*扰动遥测*/ +} YC_DISTURB_Queue; + +/** + * \brief 文件目录信息 + */ + +#define TRANS_NULL -1 //无文件需要传输 +#define TRANS_DIR 1 //传输目录 +#define TRANS_FILE 2 //传输文件 + +//文件传输对象 +typedef struct +{ + unsigned char ucCallFlag; //召唤标志 + unsigned char ucFileNameLen; //目录/文件名字长度 + unsigned char ucFileName[64]; //目录/文件名 + __CP56Time2a stStartTime; //查询起始时间 + __CP56Time2a stEndTime; //查询终止时间 +} FileObj_T; + + +//召唤目录结构特点 +typedef struct +{ + unsigned char ucFileType; //0:目录, 1:文件 + FileObj_T stFileObj; +} TRANSFILE_OBJ_T; + +typedef struct +{ + bool bAll; /*读文件时间条件使能*/ + __CP56Time2a stStartTime; /*读取文件起始位置*/ + __CP56Time2a stEndTime; /*文件大小*/ +} tIEC_FILE_TIME; + +#define TRANS_TIMEOUT_MAX 60*1000 /*最大超时时间 ms*/ +#define TRANS_SCH_GAP 10 /*任务调度执行频率 ms*/ +#define FILE_NAME_SIZE 64 +#define DIRFILE_SET_NUM 32 + +//文件传输服务操作码 +enum +{ + OR_NULL = 0, + OR_DIR_CALL = 1, //召唤目录 + OR_DIR_ACK = 2, //召唤目录确认 + OR_FILE_ACT = 3, //读文件激活 + OR_FILE_ACK = 4, //读文件激活确认 + OR_FILE_TRANSUP = 5, //读文件数据传输 + OR_FILE_TRANSUP_ACK = 6, //读文件数据响应 + OW_FILE_ACT = 7, //写文件激活 + OW_FILE_ACK = 8, //写文件激活确认 + OW_FILE_TRANS = 9, //写文件数据传输 + OW_FILE_TRANS_ACK = 10 //读文件数据响应 +}; + +#define PROT_FILE_OBJ 0 //文件服务, 文件对象 +#define PROT_DIR_OBJ 1 //文件服务, 目录对象 + +typedef struct +{ + unsigned char ucFileLen; + char caFileName[FILE_NAME_SIZE]; +} tFILE_NAME; + +typedef struct +{ + tFILE_NAME stFileName; //文件名与文件名长度 + unsigned char ucAttri; //属性 保留 + unsigned int uiId; //文件ID, 兼容底层接口添加 + unsigned int uiFileSize; //文件大小 + __CP56Time2a stTimeStamp;//文件时间 +} tDIR_FILE_INFO; + +//读取目录/文件服务 +typedef struct +{ + unsigned char ucDirLen; //根据底层读写接口, 将目录和文件分开 + char caDirName[FILE_NAME_SIZE]; + unsigned char ucFileLen; + char caFileName[FILE_NAME_SIZE]; + unsigned char ucCallFlag; //召唤标志 0: 目录下所有文件, 1:目录下满足搜索时间段的文件 + __CP56Time2a stStartTime; //查询起始时间 + __CP56Time2a stEndTime; //查询起始时间 + unsigned short usFrmNum; //目录召唤-->本帧文件数量 + unsigned short usCurNum; //目录召唤-->当前传输数量, 管理多次发送 + unsigned int uiTotalSize; //文件读取-->文件大小 + unsigned int uiOffSetSize; //文件读取-->读文件偏移量 + //文件 & 目录共性 + unsigned int uiId; //目录/文件ID + unsigned char ucFollow; //后续标志, 0: 无后续, 1: 有后续 + unsigned char ucResult; //结果描述 0:成功, 1:失败 +} tFILEDIR_RD_SET; + +//写文件 +typedef struct +{ + unsigned char ucFileLen; + char ucFileName[FILE_NAME_SIZE]; + unsigned int uiFileId; //文件ID + unsigned int uiOffSetSize; //数据段号 + unsigned int uiFileSize; //文件大小 + unsigned char ucFollow; //后续标志, 0: 无后续, 1: 有后续 + unsigned char ucResult; //0:成功 1:未知错误 2.校验和错误 3.文件长度不对应 4.文件ID 与激活 ID 不一致 +} tFILE_WD_SET; + +/********************************************/ + +typedef struct +{ + unsigned char ucType; /*类型*/ + unsigned char ucLen; /*长度*/ + union + { + unsigned char ucVal; //无符号型 + char cVal; //有符号型 + unsigned short usVal; //无符号型 + short sVal; //有符号型 + unsigned int ulVal; //无符号型 + int lVal; //有符号型 + float fVal; //浮点数 + unsigned long long ullVal; //无符号型 + long long llVal; //有符号型 + double dVal; //双精度类型 + char caBuf[64]; // + } unVal; + + unsigned int uiInfoAddr; /*信息体地址*/ +} IECPARAM_T; + +struct CS10x_t; +typedef struct CS10x_t *CS10xHandle_t; + +/** + * \brief GetLayerSt 获取链路层状态,检测是否满足发送条件 + * \param + * \return + * + */ +typedef int (*CS10x_SendCb)(unsigned char *buf, unsigned short usLen, void *arg); + +/** + * \brief SearchOneFrame 查找规约指定帧 + * \param + * \param pBuf 数据缓冲区 + * \param usLen 数据长度 + * + * \return + */ +typedef char (*CS10x_SearchOneFrame)(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen); + +/** + * \brief Preprocessor 规约预处理 根据指定的规约进行数据解析,提取ASDU数据 + * \param + * + * \return + */ +typedef int (*CS10x_Preprocessor)(CS10xHandle_t pstSelf); + +/** + * \brief GetLayerSt 获取链路层状态,检测是否满足发送条件 + * \param + * + * \return + */ +typedef int (*CS10x_Send_Cb)(unsigned char *buf, unsigned short len, void *arg); + +/** + * \brief GetLayerSt 获取链路层状态,检测是否满足发送条件 + * \param + * + * \return + */ +typedef int (*CS10x_GetLayerSt)(CS10xHandle_t pstSelf); + +/** + * \brief EncodeASDU 打包ASDU数据域 + * \param + * + * \return + */ +typedef char (*CS10x_EncodeASDU)(CS10xHandle_t pstSelf); + +/** + * \brief EncodeASDU 打包ASDU数据域 + * \param + * + * \return + */ +typedef char (*CS10x_EncodeOther)(CS10xHandle_t pstSelf); + +/** + * \brief LinkClose 关闭链路接口 + * \param + * + * \return + */ +typedef int (*CS10x_LinkClose)(void *arg); + +/** + * \brief SetValue 规约更新应用数据 + * \param + * + * \return + */ +typedef int (*CS10x_GetTime)(__CP56Time2a *pTime); + +/** + * \brief SetValue 规约更新应用数据 + * \param + * + * \return + */ +typedef int (*CS10x_SetTime)(__CP56Time2a *pTime); + +/** + * \brief SetValue 规约更新应用数据 + * \param + * + * \return + */ +typedef int (*CS10x_SetValue)(Yc_Info *pstInfo, void *pParam); + +/** + * \brief SetStatus 规约更新应用状态 + * \param + * + * \return + */ +typedef int (*CS10x_SetStatus)(Yx_Info *pstInfo, void *pParam); + +/** + * \brief SetDdValue 规约更新应用数据 + * \param + * + * \return + */ +typedef int (*CS10x_SetDdValue)(TimeDd_Info *pstInfo, void *pParam); + +/** + * \brief AddSOE 规约添加SOE信息 + * \param + * + * \return + */ +typedef int (*CS10x_AddSOE)(SOE_Info *pstInfo, void *pParam); + +/** + * \brief AddDiturbYc 规约添加遥测扰动信息 + * \param + * + * \return + */ +typedef int (*CS10x_AddDiturbYc)(Yc_Info *pstInfo, void *pParam); + +/** + * \brief GET_DiturbYc_SendNum信息 + * \param + * + * \return + */ +typedef int (*CS10x_GET_DiturbYc_SendNum)(void *pParam); + +/** + * \brief Get遥测扰动信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetDiturbYc)(Yc_Info *pstInfo, void *pParam, unsigned int usStPos); + +/** + * \brief 扰动遥测数据主动发送查询窗口 + * \param + * + * \return + */ +typedef void (*CS10x_SendDiturbYc)(CS10xHandle_t pstSelf); + +/** + * \brief 向下行设备发送确认帧 + * \param + * + * \return + */ +typedef void (*CS10x_AckFrameNotification)(void); + + +/** + * \brief 扰动遥测信息更新 + * \param + * + * \return + */ +typedef int (*CS10x_Updata_DiturbYc_Pout)(void *pParam, unsigned int Pos); + + +/** + * \brief AddFaultEvent 规约添加故障事件信息 + * \param + * + * \return + */ +typedef int (*CS10x_AddFauleEvent)(FAULT_EVENT_Info *pstInfo, void *pParam); + +/** + * \brief AddTimeDdu 规约添加电度信息 + * \param + * + * \return + */ +typedef int (*CS10x_AddTimeDdu)(TimeDd_Info *pstInfo, void *pParam); + +/** + * \brief GetSoe获取SOE信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetSOE)(SOE_Info *pstInfo, void *pParam, unsigned int usStPos); + +/** + * \brief GetSoe获取SOE信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetTimeDdu)(TimeDd_Info *pstInfo, void *pParam, unsigned int usStPos); + +/** + * \brief GetSoeSendNum信息 + * \param + * + * \return + */ +typedef int (*CS10x_GET_SOE_SendNum)(void *pParam); + + +/** + * \brief GetEventSendNum信息 + * \param + * + * \return + */ +typedef int (*CS10x_GET_Event_SendNum)(void *pParam); + +/** + * \brief GetTimeDduSendNum信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetTimeDdu_SendNum)(void *pParam); + +/** + * \brief GetSoe获取SOE信息 + * \param + * + * \return + */ +typedef int (*CS10x_Updata_SOE_Pout)(void *pParam, unsigned int Pos); + +/** + * \brief GetTimeDdu获取Dd信息 + * \param + * + * \return + */ +typedef int (*CS10x_Updata_TimeDdu_Pout)(void *pParam, unsigned int Pos); + +/** + * \brief GetFaultEvent 获取故障事件信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetFaultEvent)(FAULT_EVENT_Info *pstInfo, void *pParam, unsigned int usStPos); + +/** + * \brief GetFaultEvent_Pout 获取故障事件信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetFaultEvent_Pout)(void *pParam); + +/** + * \brief GetFaultEvent_PStart 获取故障事件信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetFaultEvent_Pin)(void *pParam); + +/** + * \brief Updata_FaultEvent_Pout 获取故障事件信息 + * \param + * + * \return + */ +typedef int (*CS10x_Updata_FaultEvent_Pout)(void *pParam, unsigned int Pos); + +/** + * \brief CS10x_SendSoeEnent Soe及Event主动发送查询窗口 + * \param + * + * \return + */ +typedef void (*CS10x_SendSoeEnent)(CS10xHandle_t pstSelf); + +/** + * \brief GetYcCountByGroup 规约获取组遥测数据个数 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * + * \return + */ +typedef int (*CS10x_GetYcCountByGroup)(unsigned short ucGroupID, void *pParam, unsigned int *StartInf, unsigned int *EndInf); + +/** + * \brief GetYcValueByGroup 规约获取组遥测数据 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * + * \return + */ +typedef int (*CS10x_GetYcValueByGroup)(unsigned short ucGroupID, unsigned short usIdx, Yc_Info *pstInfo, void *pParam); + +/** + * \brief GetYxCountByGroup 规约获取组遥信数据个数 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * + * \return + */ +typedef int (*CS10x_GetYxCountByGroup)(unsigned short ucGroupID, void *pParam, unsigned int *StartInf, unsigned int *EndInf); + +/** + * \brief GetYxStatusByGroup 规约获取组遥信数据 + * \param + * + * \return + */ +typedef int (*CS10x_GetYxStatusByGroup)(unsigned short ucGroupID, unsigned short usIdx, Yx_Info *pstInfo, void *pParam); + +/** + * \brief CS10x_GetYxPotPro Soe及Event主动发送查询窗口 + * \param + * + * \return + */ +typedef int (*CS10x_GetYxPotPro)(void *pParam, unsigned short usIdx); + +/** + * \brief GetDdCountByGroup 规约获取组遥测数据个数 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * \param ucTimeEn带时标 + * \return + */ +typedef int (*CS10x_GetDdCountByGroup)(unsigned short ucGroupID, void *pParam, unsigned int *StartInf, unsigned int *EndInf, unsigned char ucTimeEn); + +/** + * \brief GetDdValueByGroup 规约获取组遥测数据 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * \param ucTimeEn带时标 + * \return + */ +typedef int (*CS10x_GetDdValueByGroup)(unsigned short ucGroupID, unsigned short usIdx, TimeDd_Info *pstInfo, void *pParam, unsigned char ucTimeEn); + +typedef unsigned short (*CS10x_GetParamArea)(unsigned char ucType, void *pParam); + +typedef unsigned short (*CS10x_SetParamArea)(unsigned short usArea, void *pParam); + +/** + * \brief CS10x_AddIECParam 规约添加定值参数数据 + * \param ucAll + * \param ucForce + * \param ucType + * \return + */ +typedef unsigned char (*CS10x_AddIECParam)(unsigned char ucAll, unsigned char ucForce, unsigned char ucType, IECPARAM_T *pstVal, void *pParam); + +typedef unsigned char (*CS10x_RunReadIECParam)(void *pParam); + +typedef unsigned char (*CS10x_RunWriteIECParam)(void *pParam); + +/** + * \brief GetParamCount 规约获取组遥测数据个数 + * \param ucIdx 组内下标 + * + * \return + */ +typedef unsigned short (*CS10x_GetParamCount)(void *pParam); + +/** + * \brief CS10x_GetParamInfoByIndx 规约获取组遥测数据 + * \param ucIdx 组内下标 + * + * \return + */ +typedef unsigned char (*CS10x_GetParamInfoByIndx)(unsigned char ucType, unsigned short usIdx, IECPARAM_T *pstVal, void *pParam); + +/** + * \brief CS10x_GetParamInfoByInfo 规约获取组遥测数据 + * \param ucIdx 组内下标 + * + * \return + */ +//typedef int (*CS10x_GetParamInfoByInfo) (unsigned char byType,unsigned short usIfo, CONSTPARAM_Info *pstInfo, void *pParam); + +/** + * \brief CS10x_UpdateParamPosRwst 规约获取组参数点号状态数据 + * \param ucIdx 组内下标 + * + * \return + */ +//typedef void(*CS10x_UpdateParamPosRwst) (unsigned char byType,CONSTPARAM_Info *pstInfo, void *pParam); +/** + * \brief GetNumDirFile 获取目录下文件数量 + * \param caDirName 文件名 + * \param pstIecFile 条件信息 + * \return 目录文件个数 + */ +typedef int (*CS10x_GetNumDirFile)(tFILEDIR_RD_SET *pstRdSet); + +/** + * \brief ReadFile 获取目录下文件属性 + * \param pstIecFile 读取文件条件 + * \param pFileSet 文件缓冲区 + * \param ucType 获取属性类型 1-通过序号获取,0-名称获取 + * \param usItem 文件序号 + * \param caDirName 文件夹名称 + * \param caFileName 文件名称 + * \return true/false + */ +typedef bool (*CS10x_GetProDirFile)(tFILEDIR_RD_SET *pstRdSet, tDIR_FILE_INFO *pstDirFileInfo, unsigned char ucType, unsigned short usItem, void *pvInfo); + +/** + * \brief ReadFile 读取文件数据 + * \param + * + * \return + */ +typedef int (*CS10x_ReadFile)(unsigned int uiOffset, unsigned char *pBuf, unsigned short usLen, void *pvParam); + +/** + * \brief WriteFile 读取文件数据 + * \param + * + * \return + */ +typedef int (*CS10x_WriteFile)(tFILEDIR_RD_SET *pstRdSet, unsigned char *pBuf, unsigned short usLen, void *pUsrData); + +/** + * \brief SearchFileName 比对文件名 + * \param + * + * \return + */ +typedef bool (*CS10x_SearchFileName)(char *caDirName, char *caFileName, void *pUsrData); + +/** + * \brief CS10x_WriteFileCheck 查询待写入文件 + * \param + * + * \return + */ +typedef unsigned char (*CS10x_WriteFileCheck)(tFILE_WD_SET *pstWdSet, void *pvFileWrteParam, void *pUsrData); + +/** + * \brief Write 写入文件 + * \param + * + * \return + */ +typedef int (*CS10x_Write)(unsigned int uiOffset, unsigned char *pBuf, unsigned short usLen, void *pvFile, void *pUsrData); + +/** + * \brief WriteFinish 写入文件完成 + * \param + * + * \return + */ +typedef int (*CS10x_WriteFinish)(unsigned char *pucMd5, void *pvFile, void *pUsrData); + +/** + * \brief WriteFinish 写入文件完成 + * \param + * + * \return + */ +typedef int (*CS10x_UpdateProc)(unsigned short usCos, unsigned char ucSe, void *pUsrData); + +/** + * \brief ParamTaskDataProcess 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_ParamTaskDataProcess)(unsigned char byTskId, unsigned int uiParam, void *pUsrData); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_SetParamTaskst)(void *pUsrData, ParamTsk_st *pTaskst); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef bool (*CS10x_GetandClearUlogTskst)(void *pParam); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_GetParamTaskst)(void *pUsrData, ParamTsk_st *pTaskst); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_CheckParamRWSt)(CS10xHandle_t pstSelf); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_CheckUlogReadSt)(CS10xHandle_t pstSelf); + +/** + * \brief SetParamTask 设置读写参数任务 + * \param + * + * \return + */ +typedef void (*CS10x_ParamConstUpdate)(void); + + + +/** + * \brief 检查文件传输状态 + * \param + * + * \return + */ +typedef void (*CS10x_CheckFileTransferSt)(CS10xHandle_t pstSelf); + + +/** + * \brief 检查文件传输任务 + * \param + * + * \return + */ +typedef void (*CS10x_PollFileTransTask)(CS10xHandle_t pstSelf); + + +/** + * \brief 注册文件传输任务 + * \param + * + * \return + */ +typedef int (*CS10x_RegFileTransObj)(void *pUsrData, FileObj_T *FileObj, unsigned char ucFileType); + + +/** + * \brief 获取文件传输任务 + * \param + * + * \return + */ +typedef int (*CS10x_CheckTransFileObj)(tFILEDIR_RD_SET *pstRdSet, void *pUsrData); + +/** + * \brief 检测文件传输任务超时 + * \param + * + * \return + */ +typedef int (*CS10x_CheckTransTimeOut)(void *pUsrData); + +/** + * \brief 目录接收完成回调处理函数 + * \param + * + * \return + */ +typedef int (*CS10x_DirRecvFinish)(tDIR_FILE_INFO *pstDirFileSet, unsigned char ucFrmNum, unsigned char ucFollow, void *pUsrData); + + +/** + * \brief GetYcValueByGroup 规约获取组遥测数据 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * + * \return + */ +typedef int (*CS10x_Encrypt)(char *pBuf, unsigned short usLen); + +/** + * \brief GetYcValueByGroup 规约获取组遥测数据 + * \param ucGroupID 组序号 + * \param ucIdx 组内下标 + * + * \return + */ +typedef void (*CS10x_Md5Result)(unsigned char *pBuf); + +/** + * \brief 104Time Out t0~t3时间管理 + * \param + * + * \return + */ +typedef void (*CS10x_TimeManager)(CS10xHandle_t pstSelf, unsigned short usGap); + +/** + * \brief 写入复位原因 + * \param + * + * \return + */ +typedef void (*CS10x_Write_ResetCOI)(unsigned char Coi); + +/** + * \brief 读出复位原因标志 + * \param + * + * \return + */ +typedef unsigned char (*CS10x_Read_ResetCOI)(void); + +/** + * \brief 根据地址及属性获取具体信息 + * \param + * + * \return + */ +typedef int (*CS10x_GetDdValue)(int infoaddr, TimeDd_Info *DdInfo, unsigned short wType); + +/** + * \brief 遥控校验 + * \param + * + * \return + */ +typedef unsigned char (*CS10x_YkVerify)(void *pParam); + +/** + * \brief 规约更新遥控应用状态 + * \param + * + * \return + */ +typedef int (*CS10x_SetYkInfor)(Yk_Info *pstInfo, void *pParam); + +/** + * \brief 规约处理下行设备遥控应答 + * \param + * + * \return + */ +typedef int (*CS10x_SetYkAck)(unsigned char *pucYkSe, unsigned short usReason, void *pUsrData); + +/** + * \brief 规约处理下行参数定值 + * \param + * + * \return + */ +typedef int (*CS10x_SetParamInfo)(IECPARAM_T *pstVal, void *pUsrData); + +/** + * \brief 获取总召延迟时间(ms),返回0表示不延迟 + * \param pParam-用户数据指针 + * \return 延迟时间(ms),0=不延迟 + */ +typedef unsigned int (*CS10x_GetSummonSlaveDelay)(void *pParam); + + +/** + * \brief CS10x + */ +typedef struct CS10x_t +{ + /********************************************************** + *用户自定义数据 + ***********************************************************/ + void *pUsrData;/*用户自定义数据*/ + /********************************************************** + *公共配置参数 + ***********************************************************/ + CS10x_Type eCS10x_Type;/*规约类型 CS101Master CS101Slave CS104Master CS104Slave*/ + /*通用参数类*/ + struct CS10x_AppLayerParameters stAppParameters; /*规约参数*/ + bool bFbpType; /* 长帧测试限定词类型 0表示发什么回什么 1表示回复固定*/ + unsigned char ucOffLineSoeReissueEn; /*离线SOE补发使能 0链路初始化后不补发历史SOE 1链路初始化后补发历史SOE */ + unsigned char ucSenSoeEa; /* 发送SOE 带时标遥信使能*/ //参数关联 + unsigned char ucSenCosEa; /* 发送COS 不带时标遥信使能*/ //参数关联 + unsigned char ucYKEndFrame; /* 遥控结束帧投退*/ //参数关联 + unsigned char ucReadFileVSQ; /* 读文件数据传输VSQ值,部分主站无法识别0,需要投1*/ + unsigned char ucPreSetContType; /* 参数预置忽略无后续帧 0=标准规约 1=不校验后续帧,使用超时和固化进行取消*/ + unsigned short usAsduPublicAddr; /* ASDU公共地址*/ + unsigned short usYcType; /* 遥测类型*/ + unsigned short usYxType; /* 遥信类型*/ + unsigned short usYkType; /* 遥控类型*/ + unsigned short usDdType; /* 电度类型*/ + unsigned short usWaveInfoAddr; /* 录波完成点号*/ + unsigned short usFaultEnable; /* 故障事件使能*/ + unsigned int uiSummon_Gap; /* 总召间隔*/ //参数关联 + unsigned int uiESummon_Gap; /* 电能总召间隔*/ //参数关联 + unsigned int uiSyn_Gap; /* 同步间隔*/ //参数关联 + unsigned int uiHeart_Gap; /* 心跳间隔*/ //参数关联 + unsigned int uiSend_Gap; /* 数据发送间隔参数*/ + + /*运行状态类*/ + unsigned char ucSE; /* 遥控选择执行标识 0=执行 1=选择*/ + unsigned char ucQu; /* 遥控状态 0=分 1=合*/ + unsigned int ulYkAddr; /* 遥控点号*/ + unsigned int uiYxConstInfo; /* 遥信起始地址*/ //参数关联 + unsigned int uiYcConstInfo; /* 遥测起始地址*/ //参数关联 + unsigned int uiDdConstInfo; /* 电度起始地址*/ //参数关联 + + /********************************************************** + *101规约配置参数 + ***********************************************************/ + bool bDir; /* 方向位*/ + bool bSimpleInit; /* 简单初始化*/ + unsigned char ucFileAckType; /* 文件传输无应答使能 0-有应答 1-无应答*/ + unsigned char ucReSend_Num; /* 重发次数参数*/ + unsigned short usReSend_Gap; /* 超时重发间隔参数*/ + unsigned short usResetDelay; /* 复位进程延时*/ + /********************************************************** + *104规约配置参数 + ***********************************************************/ + unsigned char ucMultiFrameEn; /* 多帧使能*/ + struct CS104_APCIParameters stAPCIParameters; /*104规约参数*/ + + /********************************************************** + *函数指针 + ***********************************************************/ + /*规约区分实现函数*/ + CS10x_Send_Cb pfnSendCb; /*数据发送接口*/ + CS10x_Encrypt pfnEncrypt; /*数据是否加密*/ + CS10x_Md5Result pfnMd5ResultCb; /*更新文件md5接口*/ + CS10x_GetLayerSt pfnGetLayerSt; /*链路层状态,是否连接正常,是否可以正常发送数据*/ + CS10x_LinkClose pfnLinkClose; /**关闭链路接口*/ + CS10x_SearchOneFrame pfnDecodeProcess; /*查找响应规约数据帧函数*/ + CS10x_TimeManager pfnTimerManager; /*定时任务接口*/ + CS10x_EncodeASDU pfnEncodeFrame; /*ASDU数据打包*/ + CS10x_EncodeOther pfnEncodeOther; /*其他短帧数据打包*/ + CS10x_GetTime pfnGetTime; /*获取事件*/ + CS10x_SetTime pfnSetTime; /*设置事件*/ + CS10x_AckFrameNotification pfnAckFrameNotification; /*向下行设备发送确认帧*/ + /*对外提供数据*/ + CS10x_SetValue pfnSetValue; /*规约更新应用数据*/ + CS10x_SetStatus pfnSetStatus; /*规约更新应用状态*/ + CS10x_SetDdValue pfnSetDdValue; /*规约更新应用数据*/ + CS10x_AddSOE pfnAddSOE; /*添加SOE信息*/ + CS10x_AddFauleEvent pfnAddEvent; /*添加故障事件*/ + CS10x_AddDiturbYc pfnAddDiYcVal; /*添加扰动遥测信息*/ + CS10x_Write_ResetCOI pfnWrite_ResetCOI; /*规约写复位标志*/ + CS10x_AddTimeDdu pfnAddTimeDdu; /*添加故障事件*/ + CS10x_GetDdValue pfnGetDdValue; + CS10x_YkVerify pfnFcYkVerify; /*遥控校验*/ + CS10x_SetYkInfor pfnSetYkInfor; /*规约更新遥控应用数据*/ + CS10x_SetYkAck pfnSetYkResponse; /*规约处理下行设备遥控应答*/ + CS10x_SetParamInfo pfnSetParamInfo; /*规约处理下行设备参数定值*/ + /*向外获取数据*/ + CS10x_GetYcCountByGroup pfnGetYcCountByGroup; /*规约获取组遥测数量*/ + CS10x_GetYcValueByGroup pfnGetYcValueByGroup; /*规约获取组遥测数据*/ + CS10x_GetYxCountByGroup pfnGetYxCountByGroup; /*规约获取组遥信数量*/ + CS10x_GetYxStatusByGroup pfnGetYxStatusByGroup; /*规约获取组遥信数据*/ + CS10x_GetDdCountByGroup pfnGetDdCountByGroup; + CS10x_GetDdValueByGroup pfnGetDdValueByGroup; + CS10x_GetParamArea pfnGetParamArea; /*获取参数定值区*/ + CS10x_SetParamArea pfnSetParamArea; /*更新参数定值区*/ + CS10x_AddIECParam pfnAddIECParam; + CS10x_RunReadIECParam pfnRunReadIECParam; + CS10x_GetParamCount pfnGetParamCount; + CS10x_GetParamInfoByIndx pfnGetParamInfoByIndx; + CS10x_RunWriteIECParam pfnRunWriteIECParam; + + CS10x_GetDiturbYc pfnGetDiturbYc ; /*规约获取扰动遥测数据*/ + CS10x_GET_DiturbYc_SendNum pfnGetDiturbYc_SendNum; /*获取待发送的扰动遥测数据数量*/ + CS10x_Updata_DiturbYc_Pout pfnUpdata_DiturbYc_Pout; /*扰动数据更新*/ + + CS10x_GetSOE pfnGetSOE; /*规约获取soe数据*/ + CS10x_Updata_SOE_Pout pfnUpdata_SOE_Pout; + CS10x_GET_SOE_SendNum pfnGetSOE_SendNum; + CS10x_GetFaultEvent pfnGetFaultEvent; + CS10x_Updata_FaultEvent_Pout pfnUpdata_FaultEvent_Pout; + CS10x_GET_Event_SendNum pfnGetEvent_SendNum; + CS10x_GetTimeDdu pfnGetTimeDdu; + CS10x_Updata_TimeDdu_Pout pfnUpdata_TimeDdu_Pout; + CS10x_GetTimeDdu_SendNum pfnGetTimeDdu_SendNum; /*获取电度扰动数量*/ + CS10x_GetYxPotPro pfnGetYxPotPro; + CS10x_GetProDirFile pfnGetProDirFile; /*按条件搜索目录*/ + CS10x_GetNumDirFile pfnGetNumDirFile; /*按条件搜索目录*/ + CS10x_ReadFile pfnReadFile; /*读取文件内容*/ + void *pvFileReadParam; /*读文件指针数据*/ + + CS10x_WriteFile pfnWriteFile; /*读取文件内容*/ + CS10x_SearchFileName pfnSearchFileName; /*按名称搜索文件*/ + + CS10x_Write pfnWrite; /*写入文件内容*/ + CS10x_WriteFileCheck pfnWriteFileCheck; /*查询待写入文件*/ + CS10x_WriteFinish pfnWriteFinish; /*文件写完成*/ + void *pvFileWrteParam; /*写文件指针数据*/ + CS10x_UpdateProc pfnUpdateProc; /*升级回调函数*/ + CS10x_Read_ResetCOI pfnRead_ResetCOI; /*规约读复位标志*/ + CS10x_GetSummonSlaveDelay pfnGetSummonSlaveDelay; /*获取总召延迟时间(ms),NULL=不延迟立即上送 */ + + + /*poll查询文件升级*/ + CS10x_PollFileTransTask pfnPollFileTransTask; //查询是否有文件升级任务 + CS10x_RegFileTransObj pfnRegFileTransObj; //注册文件传输对象 + CS10x_CheckTransFileObj pfnCheckTransFileObj; //获取文件传输对象 + CS10x_CheckTransTimeOut pfnCheckTransTimeOut; //检测文件传输超时 + CS10x_DirRecvFinish pfnDealDirRecvFinish; //目录接收完成回调函数 + + tFILEDIR_RD_SET stRdSet; //目录/文件传输服务 + tFILE_WD_SET stWdSet; //写文件服务 + + /********************************************************** + *规约公共变量 + ***********************************************************/ + MD5_CTX stMd5_Ctx; /*加密MD5结果*/ + unsigned char ucaMd5_Result[16]; /*文件Md5结果*/ + struct VCommBuf stPubBuf; /*公共数据缓冲区 目前仅用做异常帧原报文保存*/ + struct VCommBuf stRecvBuf; /*接收数据缓冲区*/ + struct VCommBuf stSendBuf; /*发送数据缓冲区*/ + struct VCommBuf stSendBakBuf; /*发送数据备份区*/ + ASDU_Element stAsduElem; /*ASDU数据域内容*/ + unsigned char ucDataBackBuf[MAX_FRAME_LEN];/*数据备份缓冲区,目前用于南网参数镜像回复*/ + unsigned char ucBackLen; + + /********************************************************** + *任务管理变量 + ***********************************************************/ + VFLAGS stTaskFlags; /*任务标识 每一任务控制标志位(目前共有128位)*/ + unsigned int uiaTaskParam[MAX_FLAGNO]; // 每个任务是否需要配置任务参数 + unsigned char byTaskFlagId; + + /* + * 状态类信息 + */ + unsigned char ucInitStatus; /*规约初始化状态*/ + unsigned char ucFirstAct; /*主站时第一次初始化任务标识*/ + + unsigned int uiFrameTmCnt; /* 报文发送间隔时间计数 单位ms*/ + unsigned int uiHeart_Tcn; /* 心跳累计时间计数 */ + unsigned int uiSummon_Tcn; /* 定时总招时间计数 */ + unsigned int uiESummon_Tcn; /* 定时总招时间计数 */ + unsigned int uiTimeSyn_Tcn; /* 定时对时时间计数 */ + + unsigned short usYxSendNum; /*遥信发送个数*/ + unsigned short usYcSendNum; /*遥测发送个数*/ + unsigned short usDisTurbYcSendNum; /*扰动遥测发送个数*/ + unsigned short usDdSendNum; /*已发送电度个数*/ + + unsigned short usSoeSendNum; + unsigned short usSoeSendNoAckNum; /*Soe发送未确认数量*/ + unsigned short usCosSendNoAckNum; /*Soe发送未确认数量*/ + unsigned short usEventSendNoAckNum; /*事件发送未确认数量*/ + unsigned short usDduSendNoAckNum; /*时标电度发送未确认数量*/ + unsigned short usDiturbYcSendNoAckNum; /*扰动遥测发送未确认数量*/ + + unsigned short usSoeSendSetup; /*Soe发送步骤*/ + unsigned short usDdSummonSetup; /*电度总召回复*/ + + unsigned char ucParamFlag; /*记录参数设置读取状态标识*/ + unsigned short usParamSendNum; /*参数发送个数*/ + + unsigned char ucPmPresetFlag; /*参数预置*/ + unsigned int uiPmPresetTimeout; /*预置超时时间*/ + unsigned int uiPreSetContCount; /*参数预置后续帧逻辑判断*/ + + unsigned char ucPmPresetVsqFlag; + + unsigned char ucTransStatus; /* 文件传输状态*/ + unsigned int uiTransTimerCur; /* 文件传输定时器*/ + unsigned int uiTransTimerMax; /* 文件传输定时器*/ + bool bContinueSendFlag; /* continue send I Frame flag about K */ + + unsigned int uiSummonSlaveDelayRemain; /* 从站总召延迟剩余时间(ms),0=无延迟 */ + unsigned char ucSummonSlaveQoi; /* 从站总召延迟后使用的QOI值 */ + + /********************************************************** + *101规约变量 + ***********************************************************/ + unsigned char ucInitStep; /* 链路初始化步骤 针对101规约*/ + unsigned char ucSelf_FCB; /*我方上次的FCB值*/ + unsigned char ucRxAckFlag; /* 收到确认帧标志 针对101规约*/ + unsigned char ucRxLinkStatusFlag; /* 收到链路状态响应帧标志 针对101规约*/ + unsigned char ucRxLinkRequestFlag; /* 收到链路状态请求帧标志 针对101规约*/ + unsigned char ucRxLinkResetFlag; /* 收到链路复位帧标志 针对101规约*/ + unsigned char ucRxInitFinishFlag; /* 收到初始化完成标志 针对101规约*/ + unsigned char ucHeart_Resend_Flag; /* 心跳重发标志 */ + unsigned char ucFileTransFrame; /* 文件传输帧标识 */ + unsigned short usFileNoneAckNum; /* 文件传输未确认帧数 */ + unsigned short usResend_Ncn; /* 重发次数计数 */ + unsigned int uiResend_Tcn; /* 重发间隔时间计数 */ + unsigned int uiRelink_Tcn; /* 链路超时间隔时间计数 */ + unsigned int uiInit_Tcn; /* 101初始化中等待时间计数 */ + unsigned int uiReInit_Tcn; /* 101重新初始化间隔时间计数 */ + unsigned int uiInit_Resend_Ncn; /* 101初始化中重发次数计数 */ + /********************************************************** + *104规约变量 + ***********************************************************/ + unsigned short usSendNum; /*Send Counter */ + unsigned short usRecvNum; /*Receive Counter*/ + unsigned short usAckSendNum; /*Receive Ack Counter*/ + unsigned short usAckRecvNum; /*Have Ack Receive Counter*/ + VIec104Timer stM_vTimer[4]; /*iec104 timer for T0 T1 T2 T3*/ +} CS10x; + + + +//***************************** 规约废弃接口 ************************************// +/** + * @brief 获取时间接口(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetTimeHandler(CS10xHandle_t pstSelf, CS10x_GetTime cb); + +/** + * @brief 设置时间接口(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_SetTimeHandler(CS10xHandle_t pstSelf, CS10x_SetTime cb); + +/** + * @brief 设置计量模块接收遥测接口(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_SetValueHandler(CS10xHandle_t pstSelf, CS10x_SetValue cb); + +/** + * @brief 设置计量模块电度接口(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_SetDdValueHandler(CS10xHandle_t pstSelf, CS10x_SetDdValue cb); + +/** + * @brief 遥控操作校验(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_YkVerifyHandler(CS10xHandle_t pstSelf, CS10x_YkVerify cb); + +/** + * @brief 设置组遥测数量处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetYcCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcCountByGroup cb); + +/** + * @brief 设置组遥测值处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetYcValueByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcValueByGroup cb); + +/** + * @brief 设置组遥信数量处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetYxCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxCountByGroup cb); + +/** + * @brief 设置组遥信状态处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetYxStatusByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxStatusByGroup cb); + +/** + * @brief 扰动遥测待发送数量处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetDiturbYc_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_DiturbYc_SendNum cb); + +/** + * @brief 设置获取扰动遥测数据处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetDiturbYcHandler(CS10xHandle_t pstSelf, CS10x_GetDiturbYc cb); + +/** +* @brief 设置更新遥测扰动指针处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Updata_DiturbYc_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_DiturbYc_Pout cb); + +/** + * @brief 设置组电度数量处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetDdCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdCountByGroup cb); + +/** + * @brief 设置组电度数值处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetDdValueByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdValueByGroup cb); + +/** + * @brief 设置参数定值区获取函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetParamAreaHandler(CS10xHandle_t pstSelf, CS10x_GetParamArea cb); + +/** + * @brief 设置参数定值区更新函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_SetParamAreaHandler(CS10xHandle_t pstSelf, CS10x_SetParamArea cb); + +/** + * @brief 设置增加参数定值缓存函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_AddIECParamHandler(CS10xHandle_t pstSelf, CS10x_AddIECParam cb); + + +/** + * @brief 设置参数定值读取函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_RunReadIECParamHandler(CS10xHandle_t pstSelf, CS10x_RunReadIECParam cb); + +/** + * @brief 设置参数定值固化函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_RunWriteIECParamHandler(CS10xHandle_t pstSelf, CS10x_RunWriteIECParam cb); + +/** + * @brief 参数数量获取处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetParamCountHandler(CS10xHandle_t pstSelf, CS10x_GetParamCount cb); + +/** + * @brief 参数信息获取处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetParamInfoByIndxHandler(CS10xHandle_t pstSelf, CS10x_GetParamInfoByIndx cb); + +/** + * @brief 设置获取soe数据处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetSOEHandler(CS10xHandle_t pstSelf, CS10x_GetSOE cb); + +/** + * @brief 设置更新SOE指针待发数量函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetSOE_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_SOE_SendNum cb); + +/** + * @brief 设置更新SOE指针处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_Updata_SOE_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_SOE_Pout cb); + +/** + * @brief 获取故障事件数量处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetEvent_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_Event_SendNum cb); + +/** + * @brief 设置获取故障事件数据处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetFaultEventHandler(CS10xHandle_t pstSelf, CS10x_GetFaultEvent cb); + +/** + * @brief 设置更新故障事件处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_Updata_FaultEvent_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_FaultEvent_Pout cb); + +/** + * @brief 获取电度时间指针待发数量函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetTimeDdu_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu_SendNum cb); + +/** + * @brief 更新时标电度处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_Updata_TimeDdu_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_TimeDdu_Pout cb); + +/** + * @brief 获取时标电度数据处理函数(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetTimeDduHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu cb); + +/** + * @brief 读文件(待删除) + * + * @param pstSelf + * @param cbGetPro + * @param cbGetNum + * @param cbRead + * @param *pvParam + */ +void CS10x_FileReadOprtHandler(CS10xHandle_t pstSelf, + CS10x_GetProDirFile cbGetPro, + CS10x_GetNumDirFile cbGetNum, + CS10x_ReadFile cbRead, + void *pvParam); + +/** + * @brief 写文件(待删除) + * + * @param pstSelf + * @param cbWrite + * @param cbCheck + * @param cbFinish + * @param *pvParam + */ +void CS10x_FileWriteOprtHandler(CS10xHandle_t pstSelf, + CS10x_Write cbWrite, + CS10x_WriteFileCheck cbCheck, + CS10x_WriteFinish cbFinish, + void *pvParam); + +/** + * @brief 升级处理流程(待删除) + * + * @param pstSelf + * @param cb + */ +void CS10x_UpdateProcHandler(CS10xHandle_t pstSelf, CS10x_UpdateProc cb); + +//************************************************ 未使用接口*****************************************// +/** +* @brief 设置遥控类型(未使用) +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYkType(CS10xHandle_t pstSelf, unsigned short usType); + +/** +* @brief 设置录波完成点号关联(未使用) +* +* @param[out] pstSelf +* @param[in] usAddr +*/ +void CS10x_SetWaveInfoAddr(CS10xHandle_t pstSelf, unsigned short usAddr); + +/** + * @brief 设置接收遥信接口(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_SetStatusHandler(CS10xHandle_t pstSelf, CS10x_SetStatus cb); + +/** + * @brief 设置接收SOE处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_AddSOEHandler(CS10xHandle_t pstSelf, CS10x_AddSOE cb); + +/** + * @brief 设置故障事件处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_AddEventHandler(CS10xHandle_t pstSelf, CS10x_AddFauleEvent cb); +/** + * @brief 设置接收TimeDdu处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_AddTimeDduHandler(CS10xHandle_t pstSelf, CS10x_AddTimeDdu cb); + +/** + * @brief 设置电度信息接口(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetDdValueHandler(CS10xHandle_t pstSelf, CS10x_GetDdValue cb); + +/** + * @brief 设置扰动遥测处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_AddDiYcValueHandler(CS10xHandle_t pstSelf, CS10x_AddDiturbYc cb); + +/** + * @brief 设置遥信点点号状态处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetYxPotProHandler(CS10xHandle_t pstSelf, CS10x_GetYxPotPro cb); + +/** + * @brief 设置搜索目录获取属性处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetProDirFileHandler(CS10xHandle_t pstSelf, CS10x_GetProDirFile cb); + +/** + * @brief 设置搜索目录获取数量处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_GetNumDirFileHandler(CS10xHandle_t pstSelf, CS10x_GetNumDirFile cb); + +/** + * @brief 设置读取文件处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_ReadFileHandler(CS10xHandle_t pstSelf, CS10x_ReadFile cb); + +/** + * @brief 设置写文件处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_WriteFileHandler(CS10xHandle_t pstSelf, CS10x_WriteFile cb); + +/** + * @brief 设置文件名比对文件函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_SearchFileNameHandler(CS10xHandle_t pstSelf, CS10x_SearchFileName cb); + +/** + * @brief 设置待写入文件查询处理函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_WriteFileCheckHandler(CS10xHandle_t pstSelf, CS10x_WriteFileCheck cb); + +/** + * @brief 文件写入函数(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_WriteHandler(CS10xHandle_t pstSelf, CS10x_Write cb); + +/** + * @brief 文件写完成(未使用) + * + * @param pstSelf + * @param cb + */ +void CS10x_WriteFinishHandler(CS10xHandle_t pstSelf, CS10x_WriteFinish cb); + +/** + * @brief 设置注册文件传输任务函数(未使用) + * + * @param[out] pstSelf + * @param[in] cb +*/ +void CS10x_RegFileTransHandler(CS10xHandle_t pstSelf, CS10x_RegFileTransObj cb); + +/** + * @brief 设置获取传输文件对象函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetTransFileHandler(CS10xHandle_t pstSelf, CS10x_CheckTransFileObj cb); + +/** + * @brief 设置检测文件传输超时函数(未使用) + * + * @param self + * @param cb + */ +void CS10x_TransTimeOutHandler(CS10xHandle_t pstSelf, CS10x_CheckTransTimeOut cb); + +/** + * @brief 设置目录召唤接收完成处理函数(未使用) + * + * @param self + * @param cb + */ +void CS10x_DirRecvFinishHandler(CS10xHandle_t pstSelf, CS10x_DirRecvFinish cb); + +/** + * @brief 设置链路关闭接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_LinkCloseHandler(CS10xHandle_t pstSelf, CS10x_LinkClose cb); + +/** + * @brief 设置向下行设备发送确认帧接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_AckFrameNotificationHandler(CS10xHandle_t pstSelf, CS10x_AckFrameNotification cb); + +//*********************************** 规约参数配置函数 *************************************// +/** +* @brief 设置规约参数 +* +* @param[out] pstSelf +* @param[in] pstParam 规约参数 +*/ +void CS10x_SetAppParameters(CS10xHandle_t pstSelf, struct CS10x_AppLayerParameters *pstParam); + +/** +* @brief 设置104APCI参数 +* +* @param[out] pstSelf +* @param[in] pstParam +*/ +void CS10x_SetAPCIParameters(CS10xHandle_t pstSelf, struct CS104_APCIParameters *pstParam); + +/** +* @brief 设置遥测类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYcType(CS10xHandle_t pstSelf, unsigned short usType); + +/** +* @brief 设置遥信类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYxType(CS10xHandle_t pstSelf, unsigned short usType); + +/** +* @brief 设置电度类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetDdType(CS10xHandle_t pstSelf, unsigned short usType); + +/** +* @brief 设置总召定时间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetSummonGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** +* @brief 设置电能量总召定时间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetESummonGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** +* @brief 设置心跳间隔时间参数 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetHeartTimeGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** +* @brief 设置报文发送间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_FrameGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** + * @brief 101规约初始化类型 + * @param[out] pstSelf + * @param[in] bType + */ +void CS10x_SetInitType(CS10xHandle_t pstSelf, bool bType); + +/** + * @brief 101规约文件传输是否需要确认帧 + * @param[out] pstSelf + * @param[in] ucEn + */ +void CS10x_SetFileAckType(CS10xHandle_t pstSelf, unsigned char ucEn); + +/** +* @brief 101规约重发间隔时间参数输入 +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_ResendGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** +* @brief 101规约重发次数参数输入 +* @param[out] pstSelf +* @param[in] uiCnt +*/ +void CS10x_ResendCnt(CS10xHandle_t pstSelf, unsigned int uiCnt); + +/** +* @brief 故障事件接口使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_FaultEventEn(CS10xHandle_t pstSelf, unsigned short usEnable); + +/** +* @brief 发送SOE使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetSendSoe(CS10xHandle_t pstSelf, unsigned char ucEnable); + +/** +* @brief 发送COS使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetSendCos(CS10xHandle_t pstSelf, unsigned char ucEnable); +/** +* @brief 遥控-结束帧投退 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetYKEendFrame(CS10xHandle_t pstSelf, unsigned char ucEnable); + +/** +* @brief 离线SOE补发投退 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetOfflineSoeReissue(CS10xHandle_t pstSelf, unsigned char ucEnable); +/** +* @brief 读文件数据传输 VSQ 值:部分主站无法识别0,需要投1 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetReadFileVSQ(CS10xHandle_t pstSelf, unsigned char usEnable); + +/** +* @brief 参数预置忽略后缀帧字段 +* @param[out] pstSelf +* @param[in] ucType +*/ +void CS10x_SetPresetContType(CS10xHandle_t pstSelf, unsigned char ucType); + +/** +* @brief 104多帧数据传输设置 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetMultFrameEn(CS10xHandle_t pstSelf, unsigned char usEnable); + +/** +* @brief 设置对时同步间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetSynTimeGap(CS10xHandle_t pstSelf, unsigned int uiGap); + +/** +* @brief 设置101主站方向位 +* +* @param[out] pstSelf +* @param[in] ucMasterDirect +*/ +void CS10x_SetMasterDirect(CS10xHandle_t pstSelf, unsigned char ucMasterDirect); + +//*********************************************规约接口配置函数******************************// +/** + * @brief 设置解密接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_EncryptHandler(CS10xHandle_t pstSelf, CS10x_Encrypt cb); + +/** + * @brief 设置文件MD5接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_Md5ResultHandler(CS10xHandle_t pstSelf, CS10x_Md5Result cb); + +/** + * @brief 时间设置读取接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_TimeRWHandler(CS10xHandle_t pstSelf, CS10x_GetTime cbGetTime, CS10x_SetTime cbSetTime); + +/** + * @brief 复位原因限定词,读写函数接口 + * @param pstSelf 规约实体 + * @param Read_cb 读函数指针 + * @param Write_cb 写函数指针 + */ +void CS10x_WR_ResetHandler(CS10xHandle_t pstSelf, CS10x_Read_ResetCOI Read_cb, CS10x_Write_ResetCOI Write_cb); + +/** + * @brief 设置组遥测数量及数值处理函数 + * + * @param pstSelf + * @param cbGetYcCount,cbGetYcValue + */ +void CS10x_S_GetYcByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcCountByGroup cbGetYcCount, CS10x_GetYcValueByGroup cbGetYcValue); + +/** + * @brief 设置组遥信数量及状态处理函数 + * + * @param pstSelf + * @param cbGetYxCount,cbGetYxStatus + */ +void CS10x_S_GetYxByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxCountByGroup cbGetYxCount, CS10x_GetYxStatusByGroup cbGetYxStatus); + +/** + * @brief 设置获取扰动遥测处理函数 + * + * @param pstSelf + * @param cbGetDiturbYc,cbSendNum,cbUpdataPout + */ +void CS10x_S_DiturbYcHandler(CS10xHandle_t pstSelf, CS10x_GetDiturbYc cbGetDiturbYc, CS10x_GET_DiturbYc_SendNum cbSendNum, CS10x_Updata_DiturbYc_Pout cbUpdataPout); + +/** + * @brief 设置组电度数量及数值处理函数 + * + * @param pstSelf + * @param cbGetDdCount,cbGetDdValue + */ +void CS10x_S_GetDdByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdCountByGroup cbGetDdCount, CS10x_GetDdValueByGroup cbGetDdValue); + +/** + * @brief 设置soe处理函数 + * + * @param pstSelf + * @param cb + */ +void CS10x_S_SOEHandler(CS10xHandle_t pstSelf, CS10x_GetSOE cbGetSOE, CS10x_GET_SOE_SendNum cbSendNum, CS10x_Updata_SOE_Pout cbUpdataSOEPout); + +/** + * @brief 扰动电度处理函数 + * + * @param pstSelf + * @param cbGetTimeDdu,cbcbSendNum,cbcbUpdataPout + */ +void CS10x_S_DiturbDduHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu cbGetTimeDdu, CS10x_GetTimeDdu_SendNum cbSendNum, CS10x_Updata_TimeDdu_Pout cbUpdataPout); + +/** + * @brief 设置故障事件处理函数 + * + * @param pstSelf + * @param cbSendNum,cbGetFaultEvent,cbUpdataPout + */ +void CS10x_S_FaultEventHandler(CS10xHandle_t pstSelf, CS10x_GET_Event_SendNum cbSendNum, CS10x_GetFaultEvent cbGetFaultEvent, CS10x_Updata_FaultEvent_Pout cbUpdataPout); + +/** + * @brief 遥控操作校验 + * + * @param pstSelf + * @param cb + */ +void CS10x_S_YkVerifyHandler(CS10xHandle_t pstSelf, CS10x_YkVerify cb); + +/** + * @brief 参数定值区获取与设置接口 + * + * @param pstSelf + * @param cbGetParamArea 参数定值区获取 + * @param cbSetParamArea 参数定值区设置 + */ +void CS10x_S_ParamAreaHandler(CS10xHandle_t pstSelf, CS10x_GetParamArea cbGetParamArea, CS10x_SetParamArea cbSetParamArea); + +/** + * @brief 增加/读取/写入参数定值函数 + * + * @param pstSelf + * @param cbAddIECParam, cbReadIECParam,cbWriteIECParam + */ +void CS10x_S_IECParamHandler(CS10xHandle_t pstSelf, CS10x_AddIECParam cbAddIECParam, CS10x_RunReadIECParam cbReadIECParam, CS10x_RunWriteIECParam cbWriteIECParam); + + +/** + * @brief 参数数量及信息获取处理函数 + * + * @param pstSelf + * @param cbGetParamCount, cbGetParamInfo + */ +void CS10x_S_GetParamInfoHandler(CS10xHandle_t pstSelf, CS10x_GetParamCount cbGetParamCount, CS10x_GetParamInfoByIndx cbGetParamInfo); + +/** + * @brief 读文件 + * + * @param pstSelf + * @param cbGetPro + * @param cbGetNum + * @param cbRead + * @param *pvParam + */ +void CS10x_S_FileReadOprtHandler(CS10xHandle_t pstSelf, + CS10x_GetProDirFile cbGetPro, + CS10x_GetNumDirFile cbGetNum, + CS10x_ReadFile cbRead, + void *pvParam); + +/** + * @brief 写文件 + * + * @param pstSelf + * @param cbWrite + * @param cbCheck + * @param cbFinish + * @param *pvParam + */ +void CS10x_S_FileWriteOprtHandler(CS10xHandle_t pstSelf, + CS10x_Write cbWrite, + CS10x_WriteFileCheck cbCheck, + CS10x_WriteFinish cbFinish, + void *pvParam); + +/** + * @brief 升级 + * + * @param pstSelf + * @param cb + */ +void CS10x_S_UpdateProcHandler(CS10xHandle_t pstSelf, CS10x_UpdateProc cb); + +/** + * @brief 设置计量接口处理 + * + * @param pstSelf + * @param cbSetValue,cbSetDdValue + */ +void CS10x_M_SetDdHandler(CS10xHandle_t pstSelf, CS10x_SetValue cbSetValue, CS10x_SetDdValue cbSetDdValue); + +/** + * @brief 设置接收遥控接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_SetYkInforHandler(CS10xHandle_t pstSelf, CS10x_SetYkInfor cb); +/** + * @brief 设置下行设备遥控应答接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_SetYkAckHandler(CS10xHandle_t pstSelf, CS10x_SetYkAck cb); +/** + * @brief 设置下行设备上传参数定值接收接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_SetParamRecvHandle(CS10xHandle_t pstSelf, CS10x_SetParamInfo cb); +/** + * @brief 设置获取总召延迟时间回调接口 + * + * @param pstSelf + * @param cb + */ +void CS10x_GetSummonSlaveDelayHandler(CS10xHandle_t pstSelf, CS10x_GetSummonSlaveDelay cb); + +//***************************************内部函数*******************************// +char *GetIEC60870Version(void); +float GetStationDataSendNum(void); + +//****************************************规约公共接收函数******************************// +void CS10x_DoRecv(CS10xHandle_t pstSelf, char *pBuf, unsigned int usLength); + +//****************************************规约定时任务调度函数******************************// +void CS10x_TimerHandle(CS10xHandle_t pstSelf, unsigned short usGap); +void GetBakData(CS10xHandle_t pstSelf); +void SaveSendData(CS10xHandle_t pstSelf); + +#ifdef __cplusplus +} + +#endif + +#endif /* SRC_INC_IEC60870_COMMON_H_ */ diff --git a/src/protocol/lib60870/inc/lib60870_inc.h b/src/protocol/lib60870/inc/lib60870_inc.h new file mode 100644 index 0000000..a10e014 --- /dev/null +++ b/src/protocol/lib60870/inc/lib60870_inc.h @@ -0,0 +1,18 @@ +#ifndef __LIB60870_INC_H__ +#define __LIB60870_INC_H__ + +#include +#include +#include //字符串处理 +#include + +#define IEC_LOBYTE(w) ((unsigned char)(w)) +#define IEC_HIBYTE(w) ((unsigned char)((unsigned short)(w) >> 8)) +#define IEC_MAKEWORD(low, high) ((unsigned short)((unsigned char)(low) | (((unsigned short)((unsigned char)(high))) << 8))) + + +#ifndef IEC_PRINT +#define IEC_PRINT(fmt, args...) +#endif + +#endif diff --git a/src/protocol/lib60870/inc/lib60870_process.h b/src/protocol/lib60870/inc/lib60870_process.h new file mode 100644 index 0000000..cbf64ba --- /dev/null +++ b/src/protocol/lib60870/inc/lib60870_process.h @@ -0,0 +1,47 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : lib60870_process.h + 版 本 号 : V1.0 + 生成日期 : 2022年04月07日 + 最近修改 : + 功能描述 : lib60870_process.c的头文件 101及104规约共用流程 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年04月07日 + 修改内容 : 创建文件 + +******************************************************************************/ +#ifndef __LIB60870_PROCESS_H +#define __LIB60870_PROCESS_H +/**************************************文件包含*******************************/ +#include +#include +#include "lib60870_common.h" +#include "Asdu.h" +/**************************************宏定义*********************************/ + + +/************************************数据结构定义*****************************/ +/** +* @brief +*/ + +/**************************************数据声明******************************/ + +/**************************************内部函数声明***************************/ + +/************************************外部接口函数声明*************************/ +extern void CheckUpdate_SoeEvent(CS10xHandle_t pstSelf); +extern void CheckSOE_SendInfo(CS10xHandle_t pstSelf); +extern void CheckFaultEvent_SendInfo(CS10xHandle_t pstSelf); +extern void CheckTimeDd_SendInfo(CS10xHandle_t pstSelf); +extern void CheckDiturbYc_SendInfo(CS10xHandle_t pstSelf); +extern void CheckUpdate_DiturbYcEvent(CS10xHandle_t pstSelf); +extern void CS10x_M_Scheduled(CS10xHandle_t pstSelf, unsigned short usGap); +extern void CS10x_M_Finish(CS10xHandle_t pstSelf); +extern void PollFileTransTask(CS10xHandle_t pstSelf); +extern void CheckSummonSlaveDelay(CS10xHandle_t pstSelf, unsigned short usGap); +#endif \ No newline at end of file diff --git a/src/protocol/lib60870/inc/lib60870_public.h b/src/protocol/lib60870/inc/lib60870_public.h new file mode 100644 index 0000000..ffe2d4e --- /dev/null +++ b/src/protocol/lib60870/inc/lib60870_public.h @@ -0,0 +1,64 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : lib60870_public.h + 版 本 号 : V1.0 + 生成日期 : 2022年04月07日 + 最近修改 : + 功能描述 : lib60870_public.c的头文件 101及104规约实现中的任务管理及校验等功能 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年04月07日 + 修改内容 : 创建文件 + +******************************************************************************/ +#ifndef __LIB60870_PUBLIC_H +#define __LIB60870_PUBLIC_H +/**************************************文件包含*******************************/ +#include +#include +#include "lib60870_common.h" +/**************************************宏定义*********************************/ +#define TAG_TPYE_BOOL 1 //布尔 +#define TAG_TPYE_INT 2 //整形 +#define TAG_TPYE_STR 4 //字符串 +#define TAG_TPYE_UTINY 32 //无符号小整形 +#define TAG_TPYE_SHORT 33 //短整形 +#define TAG_TPYE_UINT 35 //无符号整形 +#define TAG_TPYE_LONG 36 //长整形 +#define TAG_TPYE_ULONG 37 //无符号长整形 +#define TAG_TPYE_FLOAT 38 //单精度浮点 +#define TAG_TPYE_DOUBLE 39 //双精度浮点 +#define TAG_TPYE_TINY 43 //小整形 +#define TAG_TPYE_USHORT 45 //无符号短整形 + +/************************************数据结构定义*****************************/ +/** +* @brief +*/ + +/**************************************数据声明*******************************/ + +/**************************************内部函数声明***************************/ + +/************************************外部接口函数声明*************************/ +extern unsigned char CS10x_SendTask(CS10xHandle_t pstSelf); +extern void SetSendTask(CS10xHandle_t pstSelf, unsigned int uiFlagNo, unsigned short usParam_low, unsigned short usParam_hig); +extern void SetTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo); +extern unsigned int GetTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo); +extern void ClearTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo); +extern int CheckClearTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo); +extern void ClearAllTaskflgs(CS10xHandle_t pstSelf); +extern unsigned char checksum_8(unsigned char *pucBuf, unsigned char ucLen); +extern int CheckParamTagAndLen(unsigned char ucTag, unsigned char ucLen); +extern unsigned char CP56Time2a_Pack2Buf(unsigned char *pucOutBuf, const __CP56Time2a *pstCp56); +extern unsigned char CP56Time2a_GetFromBuf(const unsigned char *pucInBuf, __CP56Time2a *pstCp56); +extern unsigned char IntBytes_Pack2Buf(unsigned char *pucOutBuf, unsigned int uiVal, unsigned char ucSize); +extern unsigned int IntBytes_GetFromBuf(const unsigned char *pucInBuf, unsigned char ucSize); +extern unsigned char Float_Pack2Buf(unsigned char *pucOutBuf, float fVal); +extern float Float_GetFromBuf(const unsigned char *pucInBuf); +extern unsigned char U16_Pack2Buf(unsigned char *pucOutBuf, unsigned short usVal); +extern unsigned short U16_GetFromBuf(const unsigned char *pucInBuf); +#endif diff --git a/src/protocol/lib60870/inc/md5.h b/src/protocol/lib60870/inc/md5.h new file mode 100644 index 0000000..669fd8d --- /dev/null +++ b/src/protocol/lib60870/inc/md5.h @@ -0,0 +1,75 @@ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#include + +typedef unsigned char *POINTER; +typedef uint16_t UINT2; +typedef uint32_t UINT4; + +#define MD5_BIT16 0x10 +#define MD5_BIT32 0x20 + +#define PROTO_LIST(list) list + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +typedef struct _MD5_CTX +{ + UINT4 state[4]; + UINT4 count[2]; + unsigned char buffer[64]; +} MD5_CTX; + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac);\ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#define TEST_BLOCK_LEN 1000 +#define TEST_BLOCK_COUNT 1000 + +void StartMD5(MD5_CTX * context); +void EncodeMD5(MD5_CTX * context, unsigned char * input, int len); +void GetMD5(MD5_CTX * context, unsigned char * result); +void GetMD5String(MD5_CTX * context, char * result, unsigned char mode); + +#endif //_MD5_H_ diff --git a/src/protocol/lib60870/inc/myIec60870.h b/src/protocol/lib60870/inc/myIec60870.h new file mode 100644 index 0000000..8082935 --- /dev/null +++ b/src/protocol/lib60870/inc/myIec60870.h @@ -0,0 +1,30 @@ +/** + * @file myIec60870.h + * @brief IEC 60870-5-101/103/104 协议栈统一入口 + * @details 原工程自研协议栈(科大智能,2022)。 + * 本项目不修改库源码,本文件仅作为聚合入口。 + * 调用者只需 #include "myIec60870.h" 即可获取全部 IEC 60870 接口。 + */ +#ifndef _MY_IEC60870_H_ +#define _MY_IEC60870_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "lib60870_common.h" /* 公共数据结构、回调函数类型、CS10xHandle_t */ +#include "lib60870_public.h" /* 任务管理、校验、CP56Time2a 编解码 */ +#include "lib60870_process.h" /* 协议处理主流程 */ +#include "lib60870_inc.h" /* 内部参数宏定义 */ +#include "Asdu.h" /* ASDU 域数据编解码 */ +#include "gb104.h" /* IEC 60870-5-104 协议实现 */ +#include "gb101.h" /* IEC 60870-5-101 协议实现 */ +#include "gb103.h" /* IEC 60870-5-103 协议实现 */ +#include "md5.h" /* MD5 辅助 */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MY_IEC60870_H_ */ diff --git a/src/protocol/lib60870/src/Asdu.c b/src/protocol/lib60870/src/Asdu.c new file mode 100644 index 0000000..fab5538 --- /dev/null +++ b/src/protocol/lib60870/src/Asdu.c @@ -0,0 +1,6322 @@ +/****************************************************************************** + +版权所有 (C), 2013-2023, 科大智能电气有限公司 + +****************************************************************************** +文 件 名 : ASDU.c +版 本 号 : V1.0 +生成日期 : 2022年04月07日 +最近修改 : +功能描述 : 101及104规约的公共部分ASUD域相关数据处理 +函数列表 : +修改历史 : +1.日 期 : 2022年04月07日 +修改内容 : 创建文件 +*******************************************************************************/ +/*************************************文件包含*********************************/ +#include "Asdu.h" + +/*公共地址*/ +#define ASDU_getCA IntBytes_GetFromBuf +#define ASDU_setCA IntBytes_Pack2Buf + +/*传输原因*/ +#define ASDU_getCOT IntBytes_GetFromBuf +#define ASDU_setCOT IntBytes_Pack2Buf + +/*信息体地址*/ +#define ASDU_getIOA IntBytes_GetFromBuf +#define ASDU_setIOA IntBytes_Pack2Buf + +/*归一化值*/ +#define ASDU_getNVA U16_GetFromBuf +#define ASDU_setNVA U16_Pack2Buf + +/*短浮点值*/ +#define ASDU_getSTD754 Float_GetFromBuf +#define ASDU_setSTD754 Float_Pack2Buf + +/*CP56Time2a*/ +#define ASDU_getCP56Time2a CP56Time2a_GetFromBuf +#define ASDU_setCP56Time2a CP56Time2a_Pack2Buf + +/*************************************外部接口函数*****************************/ +/** +* @brief 规约ASDU域报文构建函数 +* @param[in] pstSelf-规约实体指针 +* @param[out] pucBuf -返回组帧报文 +* @return ASDU的长度 +*/ +unsigned short GB10x_EncodeAsdu(CS10xHandle_t pstSelf, unsigned char * pucBuf) +{ + unsigned short usInfoLen = 0; + unsigned short usVsq = 0; + pucBuf[usInfoLen++] = pstSelf->stAsduElem.usTypeID; //类型标识 + + if(CONTINUE == pstSelf->stAsduElem.usSQ) + { + usVsq = (pstSelf->stAsduElem.usNum | 0x80); // VSQ + } + else + { + usVsq = pstSelf->stAsduElem.usNum; + } + + pucBuf[usInfoLen++] = usVsq; + + if(pstSelf->stAppParameters.iSzOfCOT == 1) + { + usInfoLen += ASDU_setCOT(&pucBuf[usInfoLen], pstSelf->stAsduElem.usCot, pstSelf->stAppParameters.iSzOfCOT); + } + else + { + usInfoLen += ASDU_setCOT(&pucBuf[usInfoLen], (pstSelf->stAsduElem.usCot | (pstSelf->stAsduElem.usCotH << 8)), pstSelf->stAppParameters.iSzOfCOT); + } + + usInfoLen += ASDU_setCA(&pucBuf[usInfoLen], pstSelf->stAsduElem.uiAddr, pstSelf->stAppParameters.iSzOfCA); + usInfoLen += pstSelf->stAsduElem.usPayloadSize; + return usInfoLen; +} + +/** +* @brief 规约ASDU域报文解析函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* pusPayloadSize-信息对象长度 +* @param[out] 无 +* @return 无 +*/ +void DecodeAsduInfoObj(CS10x *pstSelf) +{ + unsigned short usTypeId = 0; + unsigned short usReason = 0; + usTypeId = pstSelf->stAsduElem.usTypeID; + usReason = pstSelf->stAsduElem.usCot; + + if(DecodeASDUCheck(pstSelf, pstSelf->stAsduElem.pucPayload))//ASDU域校验 + { + return; + } + + switch(usTypeId) + { + case M_EI_NA: //初始化 + Do_InitEnd(pstSelf, usReason); + break; + + case C_IC_NA: //总召 + Do_Summon(pstSelf, usReason); + break; + + case C_CI_NA: //电能量总召 + Do_DdSummon(pstSelf, usReason); + break; + + case C_CS_NA: //对时 + Do_SetTime(pstSelf, usReason); + break; + + case C_RP_NA: //复位 + Do_Reset_Process(pstSelf, usReason); + break; + + case C_TS_NA: //测试 + Do_DataTest(pstSelf, usReason); + break; + + case C_CD_NA: //延时获得命令-南网 + Do_ObtainDelay(pstSelf, usReason); + break; + + case C_RS_NA_NANWANG: //读参数命令-南网 + Do_ParamRead_NanWang(pstSelf, usReason); + break; + + case C_SP_NA: //参数预置/固化-南网(类型标识 55) + Do_ParamWrite_Nanwang(pstSelf, usReason); + break; + + case P_ME_NC: //参数预置-南网(类型标识 112) + Do_ParamPreset_NanWang(pstSelf, usReason); + break; + + case P_AC_NA: //参数固化-南网(类型标识 113) + DoParamSolidify_NanWang(pstSelf, usReason); + break; + + case F_FR_NA: //文件 + Do_FilePro(pstSelf, usReason); + break; + + case C_SR_NA: //切换定值区 + Do_ChgConst(pstSelf, usReason); + break; + + case C_RR_NA: //读当前定值区 + Do_ReadConst(pstSelf, usReason); + break; + + case C_RS_NA: //读取当前定值区参数 + Do_ParamPreread(pstSelf, usReason); + break; + + case C_WS_NA: //下设当前定值区参数 + Do_ParamPreset(pstSelf, usReason); + break; + + case M_SP_NA: // YX + case M_DP_NA: // YX + Do_Yx(pstSelf, usReason); + break; + + case M_ME_NA: // YC + case M_ME_NB: // YC + case M_ME_NC: // YC + Do_Yc(pstSelf, usReason); + break; + + case M_IT_NB: //电度数据不带时标 + Do_DdNoTime(pstSelf, usReason); + break; + + case M_IT_TC: //电度数据带时标 + Do_DdWithTime(pstSelf, usReason); + break; + + case C_SC_NA: // YK + case C_DC_NA: // YK + Do_YKPro(pstSelf, usReason); + break; + + case M_FT_NA: //故障事件 + Do_FaultEvent(pstSelf); + break; + + case M_DP_TB: // SOE + case M_SP_TB: // SOE + Do_SOE(pstSelf); + break; + + case F_SR_NA: + Do_Update(pstSelf, usReason); + break; + + default: + Do_Anomaly(pstSelf, COT_E_TYPE); //未知ID + break; + } +} + +/** +* @brief 规约ASDU域报文组帧函数 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 数据长度 +*/ +unsigned short EncodeAsdu(CS10x *pstSelf) +{ + unsigned short usLength = 0; + pstSelf->stSendBuf.usWritePtr = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->pucPayload = &pstSelf->stSendBuf.pBuf[GetPayloadOffset(pstSelf)]; + pstAsdus->usPayloadSize = 0; + pstAsdus->uiAddr = pstSelf->stAppParameters.iPublicAddr; + + switch(pstSelf->byTaskFlagId) + { + case TSKID_SummonResponse: //总召 + usLength = CS10x_Send_Summon(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_SummonYx: + usLength = CS10x_Send_SummonYx(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_SendCOS: + usLength = CS10x_Send_COS(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_SendSOE: + usLength = CS10x_Send_SOE(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_SummonYc: + usLength = CS10x_Send_SummonYc(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_YcDisturb: //遥测扰动 + usLength = CS10x_Send_ChangeYc(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_DdSummon: //电能量召唤 + usLength = CS10x_Send_DdSummon(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_DdData: //发送电能量数据 + usLength = CS10x_Send_DdSummon_Data(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); //电度总召数据 + break; + + case TSKID_DdTimeData: //带时标电能量突发上送 + usLength = CS10x_Send_TimeDd_Data(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_TimeSyn: //时间同步 + usLength = CS10x_Send_SynTime(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ResetProcess: //复位 + usLength = CS10x_Send_ResetProcess(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_DataTest: //测试帧 + usLength = CS10x_Send_DataTest(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_InitFinish: //初始化完成 + usLength = CS10x_Send_InitEnd(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_FaultSoe: //故障事件 + usLength = CS10x_Send_FaultEvent(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_FilePro: //文件 + usLength = CS10x_Send_FilePro(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ChgConst: //切换定值区 + usLength = CS10x_Send_ChgConst(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ReadConst: //读当前定值区 + usLength = CS10x_Send_ReadConst(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamPreread: //读取当前定值区参数 + usLength = CS10x_Send_ParamPreread(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamPrewrite: //下设当前定值区参数 + usLength = CS10x_Send_ParamPreset(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_YkProcess: // YK + usLength = CS10x_Send_Yk(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_UpdateExe: + usLength = CS10x_Send_Update(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_Anomaly: //异常帧回复发送 + usLength = CS10x_Send_Anomaly(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ObtainDelay: /*延时获得命令-南网规约*/ + usLength = CS10x_Send_ObtainDelay(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamRead_NanWang: /*读参数命令-南网规约*/ + usLength = CS10x_Send_ParamRead_NanWang(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamReadResponse_NanWang: /*读参数上传命令-南网规约*/ + usLength = CS10x_Send_ParamRdResponse_NanWang(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamPreset_NanWang:/*参数预置命令-南网规约*/ + usLength = CS10x_Send_ParamPreset_NanWang(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamSolidify_NanWang: /*参数固化命令-南网规约*/ + usLength = CS10x_Send_ParamSolidify_NanWang(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + case TSKID_ParamWrite_NanWang: //预置/固化定值区参数-南网(类型标识 55) + usLength = CS10x_Send_ParamWrite_Nanwang(pstSelf, pstSelf->uiaTaskParam[pstSelf->byTaskFlagId]); + break; + + default: + break; + } + + return usLength; +} + +/** +* @brief 104/101规约解析后处理 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void DoAckFrame(CS10x *pstSelf) +{ + pstSelf->usFileNoneAckNum = 0; /* 101规约无确认帧清零*/ + CheckUpdate_DiturbYcEvent(pstSelf); + CheckUpdate_SoeEvent(pstSelf); + return; +} + +/***************************************内部函数*******************************/ +/** +* @brief ASDU域报文校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @param[out] 无 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeASDUCheck(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned char ucRet = 0;//返回校验结果; + unsigned short usTypeId = pstSelf->stAsduElem.usTypeID; + + switch(usTypeId) + { + case M_EI_NA: //初始化 + ucRet = DecodeCheck_M_EI_NA(pstSelf, pucPayload); + break; + + case C_IC_NA: //总召 + ucRet = DecodeCheck_C_IC_NA(pstSelf, pucPayload); + break; + + case C_CI_NA: //电能量总召 + ucRet = DecodeCheck_C_CI_NA(pstSelf, pucPayload); + break; + + case C_CS_NA: //对时 + ucRet = DecodeCheck_C_CS_NA(pstSelf, pucPayload); + break; + + case C_RP_NA: //复位 + ucRet = DecodeCheck_C_RP_NA(pstSelf, pucPayload); + break; + + case C_TS_NA: //测试 + ucRet = DecodeCheck_C_TS_NA(pstSelf, pucPayload); + break; + + case F_FR_NA: //文件 + ucRet = DecodeCheck_F_FR_NA(pstSelf, pucPayload); + break; + + case C_SR_NA: //切换定值区 + ucRet = DecodeCheck_C_SR_NA(pstSelf, pucPayload); + break; + + case C_RR_NA: //读当前定值区 + ucRet = DecodeCheck_C_RR_NA(pstSelf, pucPayload); + break; + + case C_RS_NA: //读取当前定值区参数 + ucRet = DecodeCheck_C_RS_NA(pstSelf); + break; + + case C_WS_NA: //下设当前定值区参数 + ucRet = DecodeCheck_C_WS_NA(pstSelf); + break; + + case M_SP_NA: // YX + case M_DP_NA: // YX + ucRet = DecodeCheck_M_SPDP_NA(pstSelf); + break; + + case M_ME_NA: // YC + case M_ME_NB: // YC + case M_ME_NC: // YC + ucRet = DecodeCheck_M_ME_NANBNC(pstSelf); + break; + + case M_IT_NB: //电度数据不带时标 + ucRet = DecodeCheck_M_IT_NB(pstSelf); + break; + + case M_IT_TC: //电度数据带时标 + ucRet = DecodeCheck_M_IT_TC(pstSelf); + break; + + case C_SC_NA: // YK + case C_DC_NA: // YK + ucRet = DecodeCheck_C_SCDC_NA(pstSelf); + break; + + case M_FT_NA: //故障事件 + ucRet = DecodeCheck_M_FT_NA(pstSelf); + break; + + case M_DP_TB: // SOE + case M_SP_TB: // SOE + ucRet = DecodeCheck_M_DPSP_TB(pstSelf); + break; + + case F_SR_NA: + ucRet = DecodeCheck_F_SR_NA(pstSelf); + break; + + case C_CD_NA: //延时获得命令-南网 + ucRet = DecodeCheck_C_CD_NA(pstSelf, pucPayload); + break; + + case C_RS_NA_NANWANG: //读参数命令-南网 + ucRet = DecodeCheck_C_RS_NA_NANWANG(pstSelf); + break; + + case P_ME_NC: //参数预置-南网 (类型标识 112) + ucRet = DecodeCheck_C_WS_NA_YZ(pstSelf); + break; + + case P_AC_NA: //参数固化-南网 + ucRet = DecodeCheck_C_WS_NA_GH(pstSelf, pucPayload); + break; + + case C_SP_NA: //参数预置/固化-南网(类型标识 55) + ucRet = DecodeCheck_C_SP_NA(pstSelf); + break; + + default: + Do_Anomaly(pstSelf, COT_E_TYPE); //未知ID + break; + } + + return ucRet; +} + +/** +* @brief 初始化校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_EI_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_INIT) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 总召校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_IC_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_ACTTERM) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 电能量总召校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_CI_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_ACTTERM) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 对时校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_CS_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_REQ && usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_ACTTERM) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 复位校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_RP_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 测试校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_TS_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 文件校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_F_FR_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + //放松条件 传输原因暂时也不判断 主站收传输原因5和6 从站收传输原因6和7 + return 0; +} + +/** +* @brief 切换定值区校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_SR_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 读当前定值区校验函数 +* @param[in] pstSelf-规约实体指针 +* pucPayload-信息对象起始指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_RR_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 读取当前定值区参数校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_RS_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 下设当前定值区参数校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_WS_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_DEACT && usReason != COT_DEACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief YX校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_SPDP_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_INTROGEN && usReason != COT_SPONT) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief YC校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_ME_NANBNC(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_INTROGEN && usReason != COT_SPONT && usReason != COT_PERCYC) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 电度数据不带时标校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_IT_NB(CS10x *pstSelf) +{ + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + return 0; +} + +/** +* @brief 电度数据带时标校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_IT_TC(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_SPONT && usReason != COT_REQCOGCN) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief YK校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_SCDC_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + unsigned int uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[0], pstSelf->stAppParameters.iSzOfIOA); + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(uiInfoAddr < 0x6001 || uiInfoAddr > 0x60FF) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if((usReason & 0x3F) != COT_ACT && (usReason & 0x3F) != COT_ACTCON && (usReason & 0x3F) != COT_DEACT && (usReason & 0x3F) != COT_DEACTCON && (usReason & 0x3F) != COT_ACTTERM) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 故障事件校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_FT_NA(CS10x *pstSelf) +{ + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + return 0; +} + +/** +* @brief SOE校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_M_DPSP_TB(CS10x *pstSelf) +{ + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + return 0; +} + +/** +* @brief //延时获得命令-南网 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_CD_NA(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_SPONT && usReason != COT_ACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 读参数-南网 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_RS_NA_NANWANG(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_DEACT) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 参数预置-南网 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_WS_NA_YZ(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_DEACT && usReason != COT_DEACTCON && usReason != COT_INTROGEN && usReason != COT_REQ) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 参数固化-南网 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_WS_NA_GH(CS10x *pstSelf, unsigned char *pucPayload) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(ASDU_getIOA(pucPayload, pstSelf->stAppParameters.iSzOfIOA)) + { + Do_Anomaly(pstSelf, COT_E_IADDR);//信息体地址错误 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_DEACT) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + + +/** +* @brief 参数预置/固化-南网(类型标识 55) +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_C_SP_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTCON && usReason != COT_DEACT && usReason != COT_DEACTCON) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 软件升级校验函数 +* @param[in] pstSelf-规约实体指针 +* @return 0 校验成功 1 校验失败 +*/ +unsigned char DecodeCheck_F_SR_NA(CS10x *pstSelf) +{ + unsigned short usReason = pstSelf->stAsduElem.usCot; //传送原因 + unsigned int uiPubAddr = pstSelf->stAsduElem.uiAddr;//公共地址 + + if((uiPubAddr != pstSelf->stAppParameters.iPublicAddr) && (uiPubAddr != 65535) && (uiPubAddr != 255)) + { + Do_Anomaly(pstSelf, COT_E_CADDR); //公共地址异常 + return 1; + } + + if(usReason != COT_ACT && usReason != COT_ACTTERM && usReason != COT_DEACT) + { + Do_Anomaly(pstSelf, COT_E_REASON); //未知传输原因 + return 1; + } + + return 0; +} + +/** +* @brief 异常帧处理接口函数 +* @param[in] pstSelf-规约实体指针 +* @param[in] usReason-传输原因即异常类型 +* @param[out] 无 +* @return 无 +*/ +void Do_Anomaly(CS10x *pstSelf, unsigned short usReason) +{ + if(pstSelf->stSendBakBuf.pBuf) + { + memcpy(pstSelf->stSendBakBuf.pBuf, pstSelf->stAsduElem.pucPayload, pstSelf->stAsduElem.usPayloadSize); //备份的ASDU域数据 + pstSelf->stSendBakBuf.usWritePtr = pstSelf->stAsduElem.usPayloadSize; + } + + SetSendTask(pstSelf, TSKID_Anomaly, usReason, pstSelf->stAsduElem.usTypeID); /*将相关ti用作参数传入,用于异常发送*/ + return; +} + +/** +* @brief 异常回复帧组帧函数 +* @param[in] pstSelf-规约实体指针 +* @param[in] uiParam-传输原因 +* @param[out] 无 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_Anomaly(CS10x *pstSelf, unsigned int uiParam) +{ + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = (unsigned short)uiParam; /* cot */ + pstAsdus->usTypeID = uiParam >> 16; /* ti */ + + if(pstSelf->stSendBakBuf.pBuf) + { + memcpy(pstAsdus->pucPayload, pstSelf->stSendBakBuf.pBuf, pstSelf->stSendBakBuf.usWritePtr); //取出备份的ASDU域数据 + pstAsdus->usPayloadSize += pstSelf->stSendBakBuf.usWritePtr; + } + else + { + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = 0; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 时间同步接收处理函数 包括收到对时命令、收到对时命令的回复命令、收到请求命令 +* @param[in] pstSelf-规约实体 +* @param[in] usReason--传输原因即异常类型 +* @param[out] 无 +* @return 无 +*/ +void Do_SetTime(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucRetuen = 0; + unsigned short usLen = 0; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + __CP56Time2a stCp56Time; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_REQ == usReason) //请求/被请求 + { + SetSendTask(pstSelf, TSKID_TimeSyn, COT_REQ, 0); + } + + if(COT_ACT == usReason) //激活 + { + ASDU_getCP56Time2a(&pstAsduInfo->pucPayload[usLen], &stCp56Time); + + if(pstSelf->pfnSetTime) + { + ucRetuen = pstSelf->pfnSetTime(&stCp56Time); + } + + if(0 == ucRetuen) //检查时间 + { + SetSendTask(pstSelf, TSKID_TimeSyn, COT_PN | COT_ACTCON, 0); + } + else + { + SetSendTask(pstSelf, TSKID_TimeSyn, COT_ACTCON, 0); + } + } + else if(COT_ACTCON == usReason) //激活确认 + { + ; + } + else if(COT_ACTTERM == usReason) //激活终止 + { + ; + } + + return; +} + + +/** +* @brief 时钟同步发送处理函数,应包含向下对时及回复对时帧 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParamusReason-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_SynTime(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = (unsigned short)uiParam; + unsigned short usSynType = (unsigned short)(uiParam >> 16); + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_CS_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + __CP56Time2a stCp56Time = {0}; + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(COT_REQ == (usReason & 0x3F)) //请求/被请求 + { + if(usSynType) //请求 + { + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], NULL); + } + else //被请求 + { + if(pstSelf->pfnGetTime) + { + pstSelf->pfnGetTime(&stCp56Time); + } + + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stCp56Time); + } + } + else if(COT_ACT == (usReason & 0x3F)) //激活 + { + if(pstSelf->pfnGetTime) + { + pstSelf->pfnGetTime(&stCp56Time); + } + + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stCp56Time); + } + else if(COT_ACTCON == (usReason & 0x3F)) //激活确认 + { + if(pstSelf->pfnGetTime) + { + pstSelf->pfnGetTime(&stCp56Time); + } + + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stCp56Time); + } + else if(COT_ACTTERM == (usReason & 0x3F)) //激活终止 + { + ; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 总召接收处理函数 +* +* @param[in] pstSelf -规约实体 +* @param[in] usReason --传输原因即异常类型 +*/ +void Do_Summon(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short usQoi = 0; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_ACT == usReason) //激活 + { + usQoi = pstAsduInfo->pucPayload[usLen++]; + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACTCON, usQoi); + } + else if(COT_ACTCON == usReason) //激活确认 + { + ; + } + else if(COT_ACTTERM == usReason) //激活终止 + { + /*需要对时优先则开始启动对时,对时结束时启动总招*/ + if(0 == pstSelf->ucFirstAct) + { + pstSelf->ucFirstAct = 1; + SetSendTask(pstSelf, TSKID_TimeSyn, COT_ACT, 0); + } + } + + return; +} + + +/** +* @brief 总召发送处理函数 +* +* @param[in] pstSelf -规约实体 +* @param[in] uiParam -传送原因 +* @return +*/ +unsigned short CS10x_Send_Summon(CS10x *pstSelf, unsigned int uiParam) +{ + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_IC_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = (unsigned short)uiParam; + unsigned short usReason = pstAsdus->usCot; + unsigned char ucQoi = (unsigned char)(uiParam >> 16); + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(COT_ACT == usReason) //激活 主站发 + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = QOI; + } + else if(COT_ACTCON == usReason || COT_ACTTERM == usReason) //激活确认及激活终止 从站发 + { + if(COT_ACTCON == usReason) + { + /* 通过回调获取延迟时间,回调未注册或返回0则不延迟直接上送 */ + if(pstSelf->pfnGetSummonSlaveDelay) + { + unsigned int uiDelay = pstSelf->pfnGetSummonSlaveDelay(pstSelf->pUsrData); + if(uiDelay > 0) + { + pstSelf->ucSummonSlaveQoi = ucQoi; + pstSelf->uiSummonSlaveDelayRemain = uiDelay; + } + else + { + SetSendTask(pstSelf, TSKID_SummonYx, COT_INTROGEN, ucQoi); + } + } + else + { + SetSendTask(pstSelf, TSKID_SummonYx, COT_INTROGEN, ucQoi); + } + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucQoi; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 升级发送处理函数 +* +* @param[in] pstSelf -规约实体 +* @param[in] usReason -传送原因 +* @return +*/ +void Do_Update(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucCtype = 0; + unsigned short usLen = 0; + ASDU_Element *pAsduInfo = &pstSelf->stAsduElem; + usLen += pstSelf->stAppParameters.iSzOfIOA; + ucCtype = pAsduInfo->pucPayload[usLen++]; + + if(pstSelf->pfnUpdateProc) + { + pstSelf->pfnUpdateProc(usReason, ucCtype, pstSelf->pUsrData); + } + + if(COT_ACT == usReason) //激活 + { + SetSendTask(pstSelf, TSKID_UpdateExe, COT_ACTCON, ucCtype); + } + else if(COT_ACTTERM == usReason) //激活终止 + { + SetSendTask(pstSelf, TSKID_UpdateExe, COT_DEACTCON, ucCtype); + } + else if(COT_DEACT == usReason) //停止激活 + { + SetSendTask(pstSelf, TSKID_UpdateExe, COT_DEACTCON, ucCtype); + } + + return; +} + +/** +* @brief 升级发送处理函数 +* +* @param[in] pstSelf -规约实体 +* @param[in] uiParam -传送原因 +* @return +*/ +unsigned short CS10x_Send_Update(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usInfoLen = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = F_SR_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = (unsigned short)uiParam; + usInfoLen = ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], 0, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += usInfoLen; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = (unsigned char)(uiParam >> 16);//Qoi + return pstAsdus->usPayloadSize; +} + +/** +* @brief 电能量总召接收处理函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +* @return +*/ +void Do_DdSummon(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_ACT == usReason) //从站 解析电能量召唤命令 + { + SetSendTask(pstSelf, TSKID_DdSummon, COT_ACTCON, 0); + } + else if(COT_ACTCON == usReason || COT_ACTTERM == usReason) //主站 + { + ; + } + + return; +} + + +/** +* @brief 电能量发送处理函数,应包含主站发送召唤命令,从站发送电能量回复报文 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_DdSummon(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_CI_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(COT_ACT == usReason) //主站发 + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = QCC; + } + else if(COT_ACTCON == usReason || COT_ACTTERM == usReason) //从站发 + { + if(COT_ACTCON == usReason) + { + SetSendTask(pstSelf, TSKID_DdData, COT_REQCOGCN, 0); //到发送电能量数据中 + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = QCC; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 不带时标电能量接收处理函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_DdNoTime(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short usDdBeginNo = 0; + unsigned short usDdNUm = pstSelf->stAsduElem.usNum; + TimeDd_Info stDdInfo = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + + if(CONTINUE == pstSelf->stAsduElem.usSQ) + { + usDdBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = 0; i < usDdNUm; i++) + { + stDdInfo.uiInfoAddr = usDdBeginNo; + stDdInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + usLen++; /*品质描述符*/ + + if(NULL != pstSelf->pfnSetDdValue) + { + pstSelf->pfnSetDdValue(&stDdInfo, pstSelf->pUsrData); + } + + usDdBeginNo++; + } + } + else + { + for(unsigned short i = 0; i < usDdNUm; i++) + { + stDdInfo.uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stDdInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + usLen++; /*品质描述符*/ + + if(NULL != pstSelf->pfnSetDdValue) + { + pstSelf->pfnSetDdValue(&stDdInfo, pstSelf->pUsrData); + } + } + } +} + +/** +* @brief 带时标的电能量数据接收处理 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_DdWithTime(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short usDdBeginNo = 0; + unsigned short usDdNUm = pstSelf->stAsduElem.usNum; + TimeDd_Info stDdInfo = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + + if(CONTINUE == pstSelf->stAsduElem.usSQ) + { + usDdBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = 0; i < usDdNUm; i++) + { + stDdInfo.uiInfoAddr = usDdBeginNo; + stDdInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + usLen++; /*品质描述符*/ + ASDU_getCP56Time2a(&pstAsduInfo->pucPayload[usLen], &stDdInfo.stCTime); + usLen += 7; + + if(COT_SPONT == usReason && NULL != pstSelf->pfnAddTimeDdu) + { + pstSelf->pfnAddTimeDdu(&stDdInfo, pstSelf->pUsrData); + } + + if(NULL != pstSelf->pfnSetDdValue) + { + pstSelf->pfnSetDdValue(&stDdInfo, pstSelf->pUsrData); + } + + usDdBeginNo++; + } + } + else + { + for(unsigned short i = 0; i < usDdNUm; i++) + { + stDdInfo.uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stDdInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + usLen++; /*品质描述符*/ + ASDU_getCP56Time2a(&pstAsduInfo->pucPayload[usLen], &stDdInfo.stCTime); + usLen += 7; + + if(COT_SPONT == usReason && NULL != pstSelf->pfnAddTimeDdu) + { + pstSelf->pfnAddTimeDdu(&stDdInfo, pstSelf->pUsrData); + } + + if(NULL != pstSelf->pfnSetDdValue) + { + pstSelf->pfnSetDdValue(&stDdInfo, pstSelf->pUsrData); + } + } + } +} + +/** +* @brief 发送电能量函数(响应主站电能量总召) +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return Asdu数据长度 +*/ +unsigned short CS10x_Send_DdSummon_Data(CS10x *pstSelf, unsigned int uiParam) +{ + const unsigned char c_ucPerSize1 = pstSelf->stAppParameters.iSzOfIOA + 5; /*不带时标:当前长度1 = 电能量对象地址长度 + 电能量对象长度(数值+品质描述词)*/ + const unsigned char c_ucPerSize2 = c_ucPerSize1 + 7; /*带时标:当前长度2 = 电能量对象地址长度 + 电能量对象长度(数值+品质描述词) + CP56Time2a长度*/ + unsigned short usDdSendTotal = 0; //不带时标总数量 + unsigned short usDdTimeSendTotal = 0; //带时标总数量 + unsigned short usSendTotal = 0; //剩余发送总数量 + unsigned short usDdSendCnt = 0; //当前发送数量 + unsigned int uiEndInforAddr = 0; //组内信息体地址尾部 暂时不用 =起始+数量 + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = M_IT_NB; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; //响应总召 + TimeDd_Info stDdInfo = {0}; + + if(NULL == pstSelf->pfnGetDdCountByGroup) + { + return 0; + } + + if(NULL == pstSelf->pfnGetDdValueByGroup) + { + return 0; + } + + usDdSendTotal = pstSelf->pfnGetDdCountByGroup(pstSelf->usDdType, pstSelf->pUsrData, &pstSelf->uiDdConstInfo, &uiEndInforAddr, 0); + usDdTimeSendTotal = pstSelf->pfnGetDdCountByGroup(pstSelf->usDdType, pstSelf->pUsrData, &pstSelf->uiDdConstInfo, &uiEndInforAddr, 1); + + if(usDdSendTotal + usDdTimeSendTotal <= pstSelf->usDdSendNum) + { + return 0; + } + + if(usDdSendTotal > pstSelf->usDdSendNum) //判断不带时标电度是否已发送完 + { + pstSelf->usDdSummonSetup = 0; //执行不带时标电度处理 + usSendTotal = usDdSendTotal - pstSelf->usDdSendNum; //不带时标剩余电度个数 + } + else + { + pstSelf->usDdSummonSetup = 1; //执行带时标电度处理 + usSendTotal = usDdTimeSendTotal - (pstSelf->usDdSendNum - usDdSendTotal); //带时标剩余电度个数 + } + + if(pstSelf->usDdSummonSetup) //带时标且电度非实时(15分钟冻结、日冻结、潮流反向冻结) + { + pstAsdus->usTypeID = M_IT_TC; //在EncodeAsdu函数中已置为M_IT_NB,带时标时更新为M_IT_TC + } + + if(0 == pstSelf->usDdSummonSetup) + { + for(unsigned short i = 0; i < usSendTotal; i++) + { + if(c_ucPerSize1 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + if(pstSelf->pfnGetDdValueByGroup(pstSelf->usDdType, pstSelf->usDdSendNum + i, &stDdInfo, pstSelf->pUsrData, 0)) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.fVal); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = 0; //品质描述词QDS + pstAsdus->usNum++; + usDdSendCnt ++; + } + else + { + break; + } + } + else + { + break; + } + } + } + else + { + if(usDdTimeSendTotal) + { + for(unsigned short i = 0; i < usSendTotal; i++) + { + if(c_ucPerSize2 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + if(pstSelf->pfnGetDdValueByGroup(pstSelf->usDdType, pstSelf->usDdSendNum - usDdSendTotal + i, &stDdInfo, pstSelf->pUsrData, 1)) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.fVal); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = 0; //品质描述词QDS + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stDdInfo.stCTime); + pstAsdus->usNum++; + usDdSendCnt ++; + } + else + { + break; + } + } + else + { + break; + } + } + } + } + + pstSelf->usDdSendNum += usDdSendCnt; //更新已发送电度数量 + + if(pstSelf->usDdSendNum == usDdTimeSendTotal + usDdSendTotal) //电度数据发送完 + { + pstSelf->usDdSendNum = 0; + SetSendTask(pstSelf, TSKID_DdSummon, COT_ACTTERM, 0); //电能量总召结束 + } + else + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, 0); + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 带时标电能量发送接口(突发上送) +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_TimeDd_Data(CS10x *pstSelf, unsigned int uiParam) +{ + const unsigned char c_ucPerSize = pstSelf->stAppParameters.iSzOfIOA + 5 + 7; /*当前长度 = 电能量对象地址长度 + 电能量对象长度(数值+品质描述词) + CP56Time2a长度*/ + unsigned short usTimeDduTotal = 0; //需要发送总数量 + unsigned short usContinue = 0; + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = M_IT_TC; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; //突变 + TimeDd_Info stDdInfo = {0}; + + if(NULL == pstSelf->pfnGetTimeDdu_SendNum) + { + return 0; + } + + if(NULL == pstSelf->pfnGetTimeDdu) + { + return 0; + } + + usTimeDduTotal = pstSelf->pfnGetTimeDdu_SendNum(pstSelf->pUsrData); + + if(usTimeDduTotal == pstSelf->usDduSendNoAckNum) + { + return 0; + } + + usTimeDduTotal -= pstSelf->usDduSendNoAckNum; + + for(unsigned short i = 0; i < usTimeDduTotal; i++) + { + if(c_ucPerSize + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + if(pstSelf->pfnGetTimeDdu(&stDdInfo, pstSelf->pUsrData, pstSelf->usDduSendNoAckNum)) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stDdInfo.fVal); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = 0; //品质描述词QDS + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stDdInfo.stCTime); + usContinue = 0; + pstAsdus->usNum++; + } + else + { + usContinue = 1; + break; + } + } + else + { + usContinue = 1; + break; + } + + pstSelf->usDduSendNoAckNum++; + } + + if(usContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, 0); + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 复位进程接收处理 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_Reset_Process(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_ACT == usReason) //从站收 + { + SetSendTask(pstSelf, TSKID_ResetProcess, COT_ACTCON, 0); + + if(NULL != pstSelf->pfnWrite_ResetCOI) + { + pstSelf->pfnWrite_ResetCOI(COI_2); //复位原因为远方复位 + } + + pstSelf->usResetDelay = 5000;//传入重启接口(规约重启) + } + else if(COT_ACTCON == usReason) //主站收 + { + ; + } + + return; +} + +/** +* @brief //复位进程发送处理函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ResetProcess(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_RP_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = QRP; + return pstAsdus->usPayloadSize; +} + +/** +* @brief //测试帧长帧解析 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_DataTest(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short usFbp = 0; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_ACT == usReason) //从站收 + { + usFbp = IEC_MAKEWORD(pstAsduInfo->pucPayload[usLen], pstAsduInfo->pucPayload[usLen + 1]); + usLen += 2; + SetSendTask(pstSelf, TSKID_DataTest, COT_ACTCON, usFbp); + } + else if(COT_ACTCON == usReason) //主站收 + { + ; + } + + return; +} + +/** +* @brief //测试帧长帧发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_DataTest(CS10x *pstSelf, unsigned int uiParam) +{ + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_TS_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = (unsigned short)uiParam; + unsigned short usFbp = (unsigned short)(uiParam >> 16); + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(pstSelf->bFbpType) //发送固定帧格式 + { + pstAsdus->usPayloadSize += IntBytes_Pack2Buf(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], FBP, 2); + } + else + { + pstAsdus->usPayloadSize += IntBytes_Pack2Buf(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], usFbp, 2); + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief //解析初始化完成帧 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_InitEnd(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_INIT == usReason) + { + CS10x_M_Finish(pstSelf); + } +} + +/** +* @brief //发送初始化完成帧 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_InitEnd(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucCoi = 0; + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = M_EI_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + + if(COT_INIT == usReason) + { + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(NULL != pstSelf->pfnRead_ResetCOI) + { + ucCoi = pstSelf->pfnRead_ResetCOI(); //复位原因为远方复位 + } + + if(ucCoi <= COI_2) + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucCoi; + } + else + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = COI_0; + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief //遥信报文解析 包括总召回复连续遥信帧及COS帧 单点及双点 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_Yx(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0;//信息体下标 + unsigned short usi = 0;//循环变量 + unsigned short usYxNUm = 0;//信息对象个数 + unsigned int uiYxBeginNo = 0;//信息体地址应为4个字节 + Yx_Info stYxInfo; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + usYxNUm = pstSelf->stAsduElem.usNum; + + if(COT_INTROGEN == usReason || COT_SPONT == usReason) //响应总召及突发 + { + if(CONTINUE == pstSelf->stAsduElem.usSQ) //点号连续 + { + //解析首个信息体地址 + uiYxBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = 0; usi < usYxNUm; usi++) + { + stYxInfo.uiInfoAddr = uiYxBeginNo; + stYxInfo.ucStatus = pstAsduInfo->pucPayload[usLen++]; + + if(NULL != pstSelf->pfnGetYxPotPro) + { + stYxInfo.ucStateType = pstSelf->pfnGetYxPotPro(pstSelf->pUsrData, stYxInfo.uiInfoAddr); + + if(!stYxInfo.ucStateType && M_DP_NA == pstAsduInfo->usTypeID) + { + stYxInfo.ucStatus -= 1; + } + } + + if(NULL != pstSelf->pfnSetStatus) + { + pstSelf->pfnSetStatus(&stYxInfo, pstSelf->pUsrData); + } + + uiYxBeginNo++; + } + } + else if(DISCONTINUE == pstSelf->stAsduElem.usSQ) //点号不连续 + { + for(usi = 0; usi < usYxNUm; usi++) + { + //信息体地址 + uiYxBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stYxInfo.uiInfoAddr = uiYxBeginNo; + stYxInfo.ucStatus = pstAsduInfo->pucPayload[usLen++]; + + if(NULL != pstSelf->pfnGetYxPotPro) + { + stYxInfo.ucStateType = pstSelf->pfnGetYxPotPro(pstSelf->pUsrData, stYxInfo.uiInfoAddr); + + if(!stYxInfo.ucStateType && M_DP_NA == pstAsduInfo->usTypeID) + { + stYxInfo.ucStatus -= 1; + } + } + + if(NULL != pstSelf->pfnSetStatus) + { + pstSelf->pfnSetStatus(&stYxInfo, pstSelf->pUsrData); + } + } + } + } + + return; +} + +/** +* @brief 响应总召的遥信报文组帧,默认连续 +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_SummonYx(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usi = 0;//循环变量 + unsigned short usQoi = 0;//召唤限定词 + unsigned short usReason = 0; + unsigned short usYxSendCnt = MAX_Yx_CNT; //最大127 + unsigned short usYxAllCnt = 0; + unsigned int uiEndInforAddr = 0; //组内信息体地址尾部 暂时不用 = 起始+数量 + unsigned char ucStateType = 0; + Yx_Info stYxInfoData = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + usQoi = (unsigned short)(uiParam >> 16); + usReason = (unsigned short)uiParam; + + if(NULL == pstSelf->pfnGetYxCountByGroup) + { + return 0; + } + + if(NULL == pstSelf->pfnGetYxStatusByGroup) + { + return 0; + } + + usYxAllCnt = pstSelf->pfnGetYxCountByGroup(usQoi, pstSelf->pUsrData, &pstSelf->uiYxConstInfo, &uiEndInforAddr); + + if(usYxAllCnt <= pstSelf->usYxSendNum) + { + pstSelf->usYxSendNum = 0; + SetSendTask(pstSelf, TSKID_SummonYc, COT_INTROGEN, usQoi); + return 0; + } + + if(usYxAllCnt - pstSelf->usYxSendNum <= usYxSendCnt) + { + usYxSendCnt = usYxAllCnt - pstSelf->usYxSendNum; + } + + /****填充总召遥信****/ + pstAsdus->usTypeID = GetTaskTItype(pstSelf, DATATYPE_YX);//无用可删除? + pstAsdus->usSQ = CONTINUE; + pstAsdus->usCot = usReason; //响应总召 + pstAsdus->usNum = 0; + + if(0 != pstSelf->pfnGetYxStatusByGroup(usQoi, pstSelf->usYxSendNum, &stYxInfoData, pstSelf->pUsrData)) // 区分单双点遥信 分开上送 + { + if(stYxInfoData.ucStateType) + { + pstAsdus->usTypeID = M_DP_NA; + ucStateType = stYxInfoData.ucStateType; + } + else + { + pstAsdus->usTypeID = M_SP_NA; + ucStateType = stYxInfoData.ucStateType; + } + } + else + { + return 0; + } + + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], pstSelf->uiYxConstInfo + pstSelf->usYxSendNum, pstSelf->stAppParameters.iSzOfIOA); + + for(usi = 0; usi < usYxSendCnt; usi++) + { + memset(&stYxInfoData, 0, sizeof(Yx_Info)); + + if(0 != pstSelf->pfnGetYxStatusByGroup(usQoi, pstSelf->usYxSendNum + usi, &stYxInfoData, pstSelf->pUsrData)) + { + if(ucStateType != stYxInfoData.ucStateType) + { + break; + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stYxInfoData.ucStatus; + pstAsdus->usNum ++; + } + else + { + break; + } + } + + pstSelf->usYxSendNum += pstAsdus->usNum; + + if(pstSelf->usYxSendNum < usYxAllCnt) + { + SetSendTask(pstSelf, TSKID_SummonYx, usReason, usQoi); + } + else + { + pstSelf->usYxSendNum = 0; + SetSendTask(pstSelf, TSKID_SummonYc, COT_INTROGEN, usQoi); + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 发送COS组帧函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_COS(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usi = 0;//循环变量 + unsigned short usReason = 0; + unsigned short usCosAllCnt = 0; + unsigned short usEncodeInfoLen = 0;//已组帧的信息体长度 + unsigned char ucStateType = 0; + unsigned char ucValid = 0; + unsigned char ucFlag = 0;//同一帧是否存在相同点号标志 + unsigned short usaInforAddr[80] = {0}; + SOE_Info stSoeInfo = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + usReason = (unsigned short)uiParam; + + if(NULL == pstSelf->pfnGetSOE) + { + return 0; + } + + usCosAllCnt = pstSelf->usSoeSendNum; + + if(usCosAllCnt <= pstSelf->usCosSendNoAckNum) //总数量不大于待确认数量 + { + return 0; + } + + usCosAllCnt = usCosAllCnt - pstSelf->usCosSendNoAckNum; //总待发送数量 + /****填充COS****/ + pstAsdus->usTypeID = GetTaskTItype(pstSelf, DATATYPE_YX); + pstAsdus->usSQ = DISCONTINUE; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; //突变 + memset(&stSoeInfo, 0, sizeof(SOE_Info)); + + for(usi = 0; usi < usCosAllCnt; usi++) + { + memset(&stSoeInfo, 0, sizeof(SOE_Info)); + + if(pstSelf->pfnGetSOE(&stSoeInfo, pstSelf->pUsrData, pstSelf->usCosSendNoAckNum)) + { + for(int j = 0;j < usi; j++)//查找同一帧是否存在同一点号 + { + if((stSoeInfo.uiInfoAddr & 0xFFFF) == usaInforAddr[j]) + { + ucFlag = 1; + break; + } + } + + if(ucFlag) + { + break; + } + + usaInforAddr[usi] = (stSoeInfo.uiInfoAddr & 0xFFFF); + + if(ucValid == 0) + { + if(stSoeInfo.ucStateType)//Cos根据Soe点Type类型分帧处理 + { + pstAsdus->usTypeID = M_DP_NA; + ucStateType = stSoeInfo.ucStateType; + } + else + { + pstAsdus->usTypeID = M_SP_NA; + ucStateType = stSoeInfo.ucStateType; + } + + ucValid = 1; + } + + if(ucStateType != stSoeInfo.ucStateType) + { + break; + } + + usEncodeInfoLen = pstAsdus->usPayloadSize + pstSelf->stAppParameters.iSzOfIOA + 1;//已组帧+地址+元素长度 + + if(usEncodeInfoLen <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + //信息体地址 + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stSoeInfo.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + //信息体元素 + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stSoeInfo.ucStatus; + pstAsdus->usNum++; + } + else + { + break; + } + } + + pstSelf->usCosSendNoAckNum++; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 遥测报文解析 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_Yc(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0;//信息体下标 + unsigned short usi = 0;//循环变量 + unsigned short usYcNUm = 0;//信息对象个数 + unsigned int uiYcBeginNo = 0;//信息体地址 + Yc_Info stYcInfo = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + usYcNUm = pstSelf->stAsduElem.usNum; + + if(COT_INTROGEN == usReason || COT_SPONT == usReason || COT_PERCYC == usReason) + { + if(CONTINUE == pstSelf->stAsduElem.usSQ) + { + //解析首个信息体地址 + uiYcBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = 0; usi < usYcNUm; usi++) + { + stYcInfo.uiInfoAddr = uiYcBeginNo; + + if(M_ME_NC == pstSelf->stAsduElem.usTypeID) //浮点型 + { + stYcInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + } + else + { + stYcInfo.fVal = (float)ASDU_getNVA(&pstAsduInfo->pucPayload[usLen]); + usLen += 2; + } + + usLen++; /*品质描述词*/ + + if(NULL != pstSelf->pfnSetValue) + { + pstSelf->pfnSetValue(&stYcInfo, pstSelf->pUsrData); + } + + if((COT_SPONT == usReason || COT_PERCYC == usReason) && NULL != pstSelf->pfnAddDiYcVal) + { + pstSelf->pfnAddDiYcVal(&stYcInfo, pstSelf->pUsrData); + } + + uiYcBeginNo++; + } + } + else if(DISCONTINUE == pstSelf->stAsduElem.usSQ) + { + for(usi = 0; usi < usYcNUm; usi++) + { + //信息体地址 + uiYcBeginNo = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stYcInfo.uiInfoAddr = uiYcBeginNo; + + if(M_ME_NC == pstSelf->stAsduElem.usTypeID) //浮点型 + { + stYcInfo.fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + } + else + { + stYcInfo.fVal = (float)ASDU_getNVA(&pstAsduInfo->pucPayload[usLen]); + usLen += 2; + } + + usLen++; /*品质描述词*/ + + if(NULL != pstSelf->pfnSetValue) + { + pstSelf->pfnSetValue(&stYcInfo, pstSelf->pUsrData); + } + + if((COT_SPONT == usReason || COT_PERCYC == usReason) && NULL != pstSelf->pfnAddDiYcVal) + { + pstSelf->pfnAddDiYcVal(&stYcInfo, pstSelf->pUsrData); + } + } + } + } + + return; +} + +/** +* @brief 总召遥测帧组帧函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_SummonYc(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usi = 0;//循环变量 + unsigned short usQoi = 0;//召唤限定词 + unsigned short usReason = 0; + unsigned short usYcSendCnt = 0; + unsigned short usYcAllCnt = 0; + unsigned short usEncodeInfoLen = 0; //已组帧的信息体长度 + unsigned int uiEndInforAddr = 0; //组内信息体地址尾部 暂时不用 =起始+数量 + unsigned short usContinue = 0; + Yc_Info stYcInfoData = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + usQoi = (unsigned short)(uiParam >> 16); + usReason = (unsigned short)uiParam; + + if(NULL == pstSelf->pfnGetYcCountByGroup) + { + return 0; + } + + if(NULL == pstSelf->pfnGetYcValueByGroup) + { + return 0; + } + + usYcAllCnt = pstSelf->pfnGetYcCountByGroup(usQoi, pstSelf->pUsrData, &pstSelf->uiYcConstInfo, &uiEndInforAddr); + + if(usYcAllCnt <= pstSelf->usYcSendNum) + { + pstSelf->usYcSendNum = 0; + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACTTERM, usQoi); + return 0; + } + + usYcAllCnt -= pstSelf->usYcSendNum; + /****填充总召遥测****/ + pstAsdus->usTypeID = GetTaskTItype(pstSelf, DATATYPE_YC); + pstAsdus->usSQ = CONTINUE; + pstAsdus->usCot = COT_INTROGEN; //响应总召 + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], pstSelf->uiYcConstInfo + pstSelf->usYcSendNum, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usNum = 0; + + for(usi = 0; usi < usYcAllCnt; usi++) + { + if(0 != pstSelf->pfnGetYcValueByGroup(usQoi, pstSelf->usYcSendNum + usi, &stYcInfoData, pstSelf->pUsrData)) + { + usEncodeInfoLen = (M_ME_NA == pstAsdus->usTypeID || M_ME_NB == pstAsdus->usTypeID) ? 2 : 4; //遥测值长度 + usEncodeInfoLen += 1;//品质描述词 QDS长度 + usEncodeInfoLen += pstAsdus->usPayloadSize;//已组帧的信息体长度 + + //填充遥测值 + if(usEncodeInfoLen <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + usContinue = 0; + + if(M_ME_NA == pstAsdus->usTypeID || M_ME_NB == pstAsdus->usTypeID) + { + //归一化值 NVA + pstAsdus->usPayloadSize += ASDU_setNVA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], (unsigned short)stYcInfoData.fVal); + } + else + { + //IEEE STD745 短浮点数 + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stYcInfoData.fVal); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stYcInfoData.ucQds;// QDS + pstAsdus->usNum++; + } + else + { + usContinue = 1; + break; + } + } + + usYcSendCnt++; + } + + pstSelf->usYcSendNum += usYcSendCnt; + + if(usContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, usQoi); + } + else + { + pstSelf->usYcSendNum = 0; + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACTTERM, usQoi); + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 变化遥测组帧函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ChangeYc(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucPerSize = 0; // 当前固定长度 + unsigned char ucLen = 0; // 遥测值长度 + unsigned short usYcAllCnt = 0; + unsigned short usContinue = 0; + unsigned short usReason = (unsigned short)uiParam; + unsigned short usQoi = (unsigned short)(uiParam >> 16); + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; // 数据与实体关联 + pstAsdus->usSQ = DISCONTINUE; // 表示信息体地址 不连续 + pstAsdus->usCot = usReason; // 突发回复 + pstAsdus->usNum = 0; // 遥测突变的数量 数值需要判断 + Yc_Info stYcInfoData = {0}; + pstAsdus->usTypeID = GetTaskTItype(pstSelf, DATATYPE_YC); + + if(NULL == pstSelf->pfnGetDiturbYc_SendNum) + { + return 0; + } + + if(NULL == pstSelf->pfnGetDiturbYc) // 从数据表中无遥测数据 则返回 + { + return 0; + } + + if(NULL == pstSelf->pfnUpdata_DiturbYc_Pout) // 更新数据池出入指针 + { + return 0; + } + + ucLen = (M_ME_NA == pstAsdus->usTypeID || M_ME_NB == pstAsdus->usTypeID) ? 2 : 4; + ucPerSize = pstSelf->stAppParameters.iSzOfIOA + ucLen + 1; // 当前长度 = 电能量对象地址长度 + 遥测值长度 + 品质描述词长度 + usYcAllCnt = pstSelf->pfnGetDiturbYc_SendNum(pstSelf->pUsrData); // 待发送的扰动遥测数据的数量 + pstSelf->usDisTurbYcSendNum = 0; + + for(unsigned short i = 0; i < usYcAllCnt; i++) + { + if(0 != pstSelf->pfnGetDiturbYc(&stYcInfoData, pstSelf->pUsrData, pstSelf->usDisTurbYcSendNum)) // 从数据表中取遥测数据 + { + if(ucPerSize + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stYcInfoData.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + + if(ucLen == 4) + { + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stYcInfoData.fVal); + } + else + { + pstAsdus->usPayloadSize += ASDU_setNVA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], (unsigned short)stYcInfoData.fVal); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stYcInfoData.ucQds;//品质描述词QDS + usContinue = 0; + pstAsdus->usNum++; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usDisTurbYcSendNum++; + } + + if(usContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, usQoi); + } + + pstSelf->pfnUpdata_DiturbYc_Pout(pstSelf->pUsrData, pstSelf->usDisTurbYcSendNum); //更新扰动数据池的出指针偏移量 + return pstAsdus->usPayloadSize; +} + +/** +* @brief 遥控从站报文解析 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_YkSlavePro(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucYkType = 0; //遥控类型 选择-执行 + unsigned char ucState = 0; //开关状态 + unsigned short usLen = 0; //信息体地址长度 + unsigned int uiYkAddr = 0; //信息体地址 + Yk_Info stInfo = {0}; //对外提供的遥控信息 + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; //接收的部分ASDU数据 待解析 + ASDU_CMD_T unYkTypeState; //遥控 类型和状态 + //从站解析遥控数据 + uiYkAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA);//地址 + usLen += pstSelf->stAppParameters.iSzOfIOA; //信息体地址位数 + unYkTypeState.ucBits = pstAsduInfo->pucPayload[usLen]; + + //遥控数据更新至大规约结构体中用于组帧 + if(C_DC_NA == pstSelf->stAsduElem.usTypeID) //双点遥控处理遥信 + { + pstSelf->usYkType = YK_TYPE_C_DC; // 1双点遥控 + ucYkType = unYkTypeState.DCO.ucSE; + ucState = unYkTypeState.DCO.ucDCS; + + if(ucState == 0 || ucState == 3) //遥信状态0 3不被允许 + { + return; + } + } + else if(C_SC_NA == pstSelf->stAsduElem.usTypeID) + { + pstSelf->usYkType = YK_TYPE_C_SC; // 0单点遥控 + ucYkType = unYkTypeState.SCO.ucSE; + ucState = unYkTypeState.SCO.ucSCS; + } + else //遥控类型标识错误则返回 + { + return; + } + + pstSelf->ucSE = ucYkType; + pstSelf->ucQu = ucState; + pstSelf->ulYkAddr = uiYkAddr; + /*遥控信息更至内部结构体中用于规约外数据处理*/ + stInfo.uiInfoAddr = uiYkAddr; // 信息体地址 + stInfo.ucStatus = ucState; //遥控状态 开合 + stInfo.ucStateType = pstSelf->usYkType ; //单点0 双点1 + + if(COT_ACT == (usReason & 0x3F)) + { + stInfo.ucYkType = ucYkType; //遥控类型 1 选择 0执行 + } + else if(COT_DEACT == (usReason & 0x3F)) + { + stInfo.ucYkType = 2; //遥控类型 1 选择 0执行 2撤销 + } + else + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_E_REASON, pstSelf->usYkType); + return; //传输原因异常不处理 + } + + /*遥控数据外部接口处理*/ + if(NULL == pstSelf->pfnSetYkInfor) + { + if(COT_ACT == (usReason & 0x3F)) + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_PN | COT_ACTCON, pstSelf->usYkType); + } + else if(COT_DEACT == (usReason & 0x3F)) + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_PN | COT_DEACTCON, pstSelf->usYkType); + } + + return; + } + + /*遥控操作校验*/ + if(pstSelf->pfnFcYkVerify) + { + if(0 == pstSelf->pfnFcYkVerify(pstSelf->pUsrData)) + { + if(COT_ACT == (usReason & 0x3F)) + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_PN | COT_ACTCON, pstSelf->usYkType); + } + else if(COT_DEACT == (usReason & 0x3F)) + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_PN | COT_DEACTCON, pstSelf->usYkType); + } + + return; + } + } + + if(NULL != pstSelf->pfnSetYkInfor) + { + pstSelf->pfnSetYkInfor(&stInfo, pstSelf->pUsrData); //规约外执行遥控任务接口 + } +} + +/** +* @brief 遥控主站报文解析 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_YkMasterPro(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucYkType = 0; //遥控类型 选择-执行 + unsigned char ucState = 0; //开关状态(不管单双点) + unsigned short usLen = 0; //信息体地址长度 + unsigned int uiYkAddr = 0; //信息体地址 + ASDU_CMD_T unYkTypeState; //遥控 类型和状态 + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; //接收的部分ASDU数据 待解析 + //主站 激活确认 停止激活确认 激活结束 + uiYkAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA);//地址 + usLen += pstSelf->stAppParameters.iSzOfIOA; //信息体地址位数 + unYkTypeState.ucBits = pstAsduInfo->pucPayload[usLen]; + + //遥控数据更新至大规约结构体中 + if(C_DC_NA == pstSelf->stAsduElem.usTypeID) //双点遥控处理遥信 + { + pstSelf->usYkType = YK_TYPE_C_DC; // 1 双点遥控 + ucYkType = unYkTypeState.DCO.ucSE; + ucState = unYkTypeState.DCO.ucDCS; + + if(ucState == 0 || ucState == 3) //遥信状态0 3不被允许 + { + return; + } + } + else if(C_SC_NA == pstSelf->stAsduElem.usTypeID) + { + pstSelf->usYkType = YK_TYPE_C_SC; // 0 单点遥控 + ucYkType = unYkTypeState.SCO.ucSE; + ucState = unYkTypeState.SCO.ucSCS; + } + else + { + return; + } + + pstSelf->ucSE = ucYkType; + pstSelf->ucQu = ucState; + pstSelf->ulYkAddr = uiYkAddr; + + if(NULL != pstSelf->pfnSetYkResponse) + { + pstSelf->pfnSetYkResponse(&pstSelf->ucSE, usReason, pstSelf->pUsrData);//规约外执行遥控任务接口 + } +} + +/** +* @brief 遥控从站发送报文组帧 +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_YkSlave(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = 0; + unsigned short usTiType = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem;; + ASDU_CMD_T unYkTypeState; //遥控 类型和状态 + //使用大结构体参数组帧 + usReason = (unsigned short)uiParam; + usTiType = (unsigned short)(uiParam >> 16); + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + unYkTypeState.QOS.ucSE = pstSelf->ucSE; + unYkTypeState.QOS.ucQL = pstSelf->ucQu; + + if(0 == usTiType) + { + pstAsdus->usTypeID = C_SC_NA; + } + else + { + pstAsdus->usTypeID = C_DC_NA; + } + + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], pstSelf->ulYkAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = unYkTypeState.ucBits ; + + /*执行成功确认 停止激活确认*/ + if((COT_ACTCON == (usReason & 0x3F) && (0 == pstSelf->ucSE)) + || COT_DEACTCON == (usReason & 0x3F) || COT_PN == (COT_PN & usReason)) + { + if(pstSelf->ucYKEndFrame) + { + SetSendTask(pstSelf, TSKID_YkProcess, COT_ACTTERM, usTiType); //激活结束帧置位 + } + } + else if(COT_ACTTERM == (usReason & 0x3F)) + { + /*遥控结束,清空遥控状态信息*/ + pstSelf->ulYkAddr = 0; + pstSelf->ucSE = 0; + pstSelf->ucQu = 0; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 遥控主站发送报文组帧 +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_YkMaster(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = 0; + unsigned short usTiType = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem;; + ASDU_CMD_T unYkTypeState; //遥控 类型和状态 + //使用大结构体参数组帧 + usReason = (unsigned short)uiParam; + usTiType = (unsigned short)(uiParam >> 16); + unYkTypeState.QOS.ucSE = pstSelf->ucSE; + unYkTypeState.QOS.ucQL = pstSelf->ucQu; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + + if(0 == usTiType) + { + pstAsdus->usTypeID = C_SC_NA; + } + else + { + pstAsdus->usTypeID = C_DC_NA; + } + + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], pstSelf->ulYkAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = unYkTypeState.ucBits; + + /*激活6 停止激活8*/ + if(COT_ACT == (usReason & 0x3F)) + { + } + else if(COT_DEACT == (usReason & 0x3F)) + { + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 遥控报文解析 +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_YKPro(CS10x *pstSelf, unsigned short usReason) +{ + CS10x_Type stType = pstSelf->eCS10x_Type; + + //从站解析 + if(CS101_TYPE_S == stType || CS104_TYPE_S == stType) + { + Do_YkSlavePro(pstSelf, usReason); + } + + //主站解析 + if(CS101_TYPE_M == stType || CS104_TYPE_M == stType) + { + Do_YkMasterPro(pstSelf, usReason); + } +} + +/** +* @brief 遥控发送报文组帧 +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_Yk(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usLen = 0; + CS10x_Type stType = pstSelf->eCS10x_Type; + + //从站组帧 + if(CS101_TYPE_S == stType || CS104_TYPE_S == stType) + { + usLen = CS10x_Send_YkSlave(pstSelf, uiParam); + } + + //主站组帧 + if(CS101_TYPE_M == stType || CS104_TYPE_M == stType) + { + usLen = CS10x_Send_YkMaster(pstSelf, uiParam); + } + + return usLen; +} + +/** +* @brief SOE报文解析函数 +* +* @param[in] pstSelf 规约实体 +*/ +void Do_SOE(CS10x *pstSelf) +{ + unsigned short usLen = 0;//信息体下标 + unsigned short usYxNUm = 0;//信息对象个数 + SOE_Info stSoeInfo = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + + if(CONTINUE == pstSelf->stAsduElem.usSQ) // SOE点号连续 + { + ; + } + else if(DISCONTINUE == pstSelf->stAsduElem.usSQ) // SOE点表不连续 + { + usYxNUm = pstSelf->stAsduElem.usNum; + + for(unsigned short i = 0; i < usYxNUm; i++) + { + //信息体地址 + stSoeInfo.uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stSoeInfo.ucStatus = pstAsduInfo->pucPayload[usLen++]; + + if(NULL != pstSelf->pfnGetYxPotPro) + { + stSoeInfo.ucStateType = pstSelf->pfnGetYxPotPro(pstSelf->pUsrData, stSoeInfo.uiInfoAddr); + + if(!stSoeInfo.ucStateType && M_DP_TB == pstAsduInfo->usTypeID) + { + stSoeInfo.ucStatus -= 1; + } + } + + //获取时标 + ASDU_getCP56Time2a(&pstAsduInfo->pucPayload[usLen], &stSoeInfo.stCTime); + usLen += 7; + + if(NULL != pstSelf->pfnAddSOE) + { + pstSelf->pfnAddSOE(&stSoeInfo, pstSelf->pUsrData); + } + + if(stSoeInfo.uiInfoAddr == pstSelf->usWaveInfoAddr && stSoeInfo.ucStatus) + { + SetSendTask(pstSelf, TSKID_DirReqByFile, 0, 0); + } + } + } +} + +/** +* @brief SOE发送组帧函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_SOE(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usSoeSendTotal = 0;//需要发送总数量 + unsigned short usEncodeInfoLen = 0;//已组帧的信息体长度 + unsigned short usSoeAllCnt = 0; + unsigned short usReason = 0; + unsigned char ucStateType = 0; + unsigned char ucValid = 0; + SOE_Info stSoeInfo = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + usReason = (unsigned short)uiParam; + + if(NULL == pstSelf->pfnGetSOE_SendNum) + { + return 0; + } + + if(NULL == pstSelf->pfnGetSOE) + { + return 0; + } + + usSoeSendTotal = pstSelf->usSoeSendNum; + + if(usSoeSendTotal == pstSelf->usSoeSendNoAckNum) + { + return 0; + } + + usSoeAllCnt = usSoeSendTotal - pstSelf->usSoeSendNoAckNum; + /****填充SOE****/ + pstAsdus->usTypeID = GetTaskTItype(pstSelf, DATATYPE_YXT);//无用可删除? + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; //突变 + memset(&stSoeInfo, 0, sizeof(SOE_Info)); + + for(unsigned short i = 0; i < usSoeAllCnt; i++) + { + if(pstSelf->pfnGetSOE(&stSoeInfo, pstSelf->pUsrData, pstSelf->usSoeSendNoAckNum)) + { + + if(ucValid == 0) + { + if(stSoeInfo.ucStateType) //SOE 根据TypeID分针 + { + pstAsdus->usTypeID = M_DP_TB; + ucStateType = stSoeInfo.ucStateType; + } + else + { + pstAsdus->usTypeID = M_SP_TB; + ucStateType = stSoeInfo.ucStateType; + } + + ucValid = 1; + } + + if(ucStateType != stSoeInfo.ucStateType) + { + break; + } + + usEncodeInfoLen = pstAsdus->usPayloadSize + pstSelf->stAppParameters.iSzOfIOA + 1 + sizeof(__CP56Time2a);//已组帧+地址+元素+时标长度 + + if(usEncodeInfoLen <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + //信息体地址 + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stSoeInfo.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + //信息体元素 + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stSoeInfo.ucStatus; + //时标 + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stSoeInfo.stCTime); + pstAsdus->usNum++; + } + else + { + break; + } + } + + pstSelf->usSoeSendNoAckNum++; + + if(pstSelf->usSoeSendNoAckNum >= pstSelf->usCosSendNoAckNum) + { + break; + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief //故障事件报文解析 +* +* @paramp[in] pstSelf 规约实体 +*/ +void Do_FaultEvent(CS10x *pstSelf) +{ + unsigned short i = 0; + unsigned short usType = 0; + unsigned short usLen = 0; + FAULT_EVENT_Info stFaultInfo = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + stFaultInfo.usSoeNum = pstAsduInfo->pucPayload[usLen++]; + usType = pstAsduInfo->pucPayload[usLen++]; + + if(stFaultInfo.usSoeNum > MAX_FAULT_EVENT_SOE_SIZE) + { + stFaultInfo.usSoeNum = MAX_FAULT_EVENT_SOE_SIZE; + } + + for(i = 0; i < stFaultInfo.usSoeNum; i++) + { + if(((pstSelf->usFaultEnable == 0 || pstSelf->usFaultEnable == 1) && pstSelf->stAppParameters.iSzOfIOA == 2) + || (pstSelf->usFaultEnable == 2)) + { + stFaultInfo.staSoe[i].uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], 2); + } + else if(((pstSelf->usFaultEnable == 0 || pstSelf->usFaultEnable == 1) && pstSelf->stAppParameters.iSzOfIOA == 3) + || (pstSelf->usFaultEnable == 3)) + { + stFaultInfo.staSoe[i].uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], 3); + } + else + { + return; + } + + usLen += pstSelf->stAppParameters.iSzOfIOA; + stFaultInfo.staSoe[i].ucStatus = pstAsduInfo->pucPayload[usLen++]; + + if(NULL != pstSelf->pfnGetYxPotPro) + { + stFaultInfo.staSoe[i].ucStateType = pstSelf->pfnGetYxPotPro(pstSelf->pUsrData, stFaultInfo.staSoe[i].uiInfoAddr); + + if(!stFaultInfo.staSoe[i].ucStateType && M_DP_TB == pstAsduInfo->usTypeID) + { + stFaultInfo.staSoe[i].ucStatus -= 1; + } + } + + ASDU_getCP56Time2a(&pstAsduInfo->pucPayload[usLen], &stFaultInfo.staSoe[i].stCTime); + usLen += 7; + } + + stFaultInfo.usYcNum = pstAsduInfo->pucPayload[usLen++]; + usType = pstAsduInfo->pucPayload[usLen++]; + + if(stFaultInfo.usYcNum > MAX_FAULT_EVENT_SOE_SIZE) + { + stFaultInfo.usYcNum = MAX_FAULT_EVENT_YC_SIZE; + } + + for(unsigned short i = 0; i < stFaultInfo.usYcNum; i++) + { + stFaultInfo.staYc[i].uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(M_ME_NC == usType) //测量值-短浮点数 + { + stFaultInfo.staYc[i].fVal = ASDU_getSTD754(&pstAsduInfo->pucPayload[usLen]); + usLen += 4; + } + else + { + stFaultInfo.staYc[i].fVal = (float)ASDU_getNVA(&pstAsduInfo->pucPayload[usLen]); + usLen += 2; + } + } + + if(NULL != pstSelf->pfnAddEvent) + { + pstSelf->pfnAddEvent(&stFaultInfo, pstSelf->pUsrData); + } +} + +/** +* @brief //故障事件发送报文组帧 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_FaultEvent(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usType = 0; + unsigned short usEventSendTotal = 0; //需要发送总数量 + FAULT_EVENT_Info stEventInfo = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = M_FT_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = (unsigned short)uiParam; //突变 + + if(!pstSelf->usFaultEnable) + { + return 0; + } + + if(NULL == pstSelf->pfnGetEvent_SendNum) + { + return 0; + } + + if(NULL == pstSelf->pfnGetFaultEvent) + { + return 0; + } + + usEventSendTotal = pstSelf->pfnGetEvent_SendNum(pstSelf->pUsrData); + + if(usEventSendTotal == pstSelf->usEventSendNoAckNum) + { + return 0; + } + + if(pstSelf->pfnGetFaultEvent(&stEventInfo, pstSelf->pUsrData, pstSelf->usEventSendNoAckNum)) + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stEventInfo.usSoeNum; + usType = GetTaskTItype(pstSelf, DATATYPE_YXT); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usType; + + for(unsigned short i = 0; i < stEventInfo.usSoeNum; i++) + { + if(pstSelf->usFaultEnable == 2 || (pstSelf->usFaultEnable == 1 && pstSelf->stAppParameters.iSzOfIOA == 2)) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stEventInfo.staSoe[i].uiInfoAddr, 2); + } + else if(pstSelf->usFaultEnable == 3 || (pstSelf->usFaultEnable == 1 && pstSelf->stAppParameters.iSzOfIOA == 3)) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stEventInfo.staSoe[i].uiInfoAddr, 3); + } + else + { + return 0; + } + + if(0 == stEventInfo.staSoe[i].ucStateType && M_DP_TB == usType) + { + stEventInfo.staSoe[i].ucStatus += 1; + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stEventInfo.staSoe[i].ucStatus; + pstAsdus->usPayloadSize += ASDU_setCP56Time2a(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &stEventInfo.staSoe[i].stCTime); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stEventInfo.usYcNum; + usType = GetTaskTItype(pstSelf, DATATYPE_YC); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usType; + + for(unsigned short i = 0; i < stEventInfo.usYcNum; i++) + { + pstAsdus->usPayloadSize += ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stEventInfo.staYc[i].uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + + if(M_ME_NC == usType) + { + pstAsdus->usPayloadSize += ASDU_setSTD754(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stEventInfo.staYc[i].fVal); + } + else + { + pstAsdus->usPayloadSize += ASDU_setNVA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], (unsigned short)stEventInfo.staYc[i].fVal); + } + } + + pstSelf->usEventSendNoAckNum++; + } + else + { + return 0; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief //规约从模式, 接收主站数据 +* +* @param[in] pstSelf 规约实体 +* @param[in] usType 操作标识 +* @param[in] pucBuf 数据缓存 +* @return +*/ +void Do_FilePro_Slave(CS10x *pstSelf, unsigned char ucType, unsigned char *pucBuf, unsigned short usFileDateLen) +{ + switch(ucType) + { + //读文件 + case FILE_ST_RD_DIR: //文件目录召唤 slave + Revc_ReadFS_CallDir_S(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_ACT: //读文件激活 slave + Revc_ReadFS_SelectFile_S(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_DATA_RESPONE: //读文件数据传输确认 slave + Revc_ReadFS_AckFileSeg_S(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + //写文件 + case FILE_ST_WR_FILE_ACT: //写文件激活 slave + Recv_WriteFS_SelectFile_S(pstSelf, pucBuf, &pstSelf->stWdSet); + break; + + case FILE_ST_WR_FILE_DATA: //写文件数据传输 slave + Recv_WriteFS_DownFileSeg_S(pstSelf, pucBuf, &pstSelf->stWdSet, usFileDateLen); + break; + + default: + //文件操作标识错误或报文解析错误 + break; + } +} + +/** +* @brief //规约主模式, 接收对下设备数据 +* +* @param[in] pstSelf 规约实体 +* @param[in] usType 操作标识 +* @param[in] pucBuf 数据缓存 +* @return +*/ +void Do_FilePro_Master(CS10x *pstSelf, unsigned char ucType, unsigned char *pucBuf) +{ + switch(ucType) + { + //读文件 + case FILE_ST_RD_DIR_RESPONE: //目录召唤确认 master + Revc_ReadFS_AckCallDir_M(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_ACT_RESPONE: //读文件激活确认 master + Revc_ReadFS_AckSelectFile_M(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_DATA: //读文件数据传输 master + Revc_ReadFS_CallFileSeg_M(pstSelf, pucBuf, &pstSelf->stRdSet); + break; + + //写文件 + case FILE_ST_WR_FILE_ACT_RESPONE: //写文件激活确认 master + Recv_WriteFS_AckSelectFile_M(pstSelf, pucBuf, &pstSelf->stWdSet); + break; + + case FILE_ST_WR_FILE_DATA_RESPONE: //写文件数据传输确认 master + Recv_WriteFS_AckDownFileSeg_M(pstSelf, pucBuf, &pstSelf->stWdSet); + break; + + default: + //文件操作标识错误或报文解析错误 + break; + } +} + + +/** +* @brief //解析文件报文 包括目录及文件 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_FilePro(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short ucType = 0; + CS10x_Type stCS10x_Type = pstSelf->eCS10x_Type; + ASDU_Element *pAsduInfo = &pstSelf->stAsduElem; + unsigned char *pucPayload = &pAsduInfo->pucPayload[0]; + usLen += pstSelf->stAppParameters.iSzOfIOA; + // usVSQ = pstSelf->stAsduElem.usSQ | pstSelf->stAsduElem.usNum; + /*if(usVSQ) //放松条件 传输原因暂时也不判断 主站收传输原因5和6 从站收传输原因6和7 + { + return; + }*/ + usLen++; //跳过附加数据包类型 02表示文件传输 其他为备用 + ucType = pucPayload[usLen++]; //操作标识 + + if(stCS10x_Type == CS101_TYPE_S || stCS10x_Type == CS104_TYPE_S) + { + Do_FilePro_Slave(pstSelf, ucType, &pucPayload[usLen], pstSelf->stAsduElem.usPayloadSize - pstSelf->stAppParameters.iSzOfIOA - 2); /*减信息体地址长度 数据包类型 操作标识104 -5 101 -4*/ + } + else if(stCS10x_Type == CS101_TYPE_M || stCS10x_Type == CS104_TYPE_M) + { + Do_FilePro_Master(pstSelf, ucType, &pucPayload[usLen]); + } + else + { + //主动模式设置错误 + } +} + +/** +* @brief 比对录波文件差异 +* +* @param[in] pstSelf 规约实体 +*/ +void CheckFileDiff(CS10x *pstSelf) +{ +#if 0 + IEC_FILE_STU *pstFile = NULL; + pstFile = &pstSelf->pstFileStu; + // IEC_FILE_STU stWaveFileSt_L; + + for(unsigned short i = 0; i < pstFile->usFileNum; i++) + { + // IEC_PRINT("%s, %s \n\r",pstFile->caDirName,pstFile->staFileInfoSet[i].caFileName); + if(false == pstSelf->pfnSearchFileName(pstFile->caDirName, pstFile->staFileInfoSet[i].caFileName, pstSelf->pUsrData)) + { + memcpy(pstFile->stTransFileInfo.caFileName, pstFile->staFileInfoSet[i].caFileName, pstFile->staFileInfoSet[i].usFileNameLen); + pstFile->stTransFileInfo.usFileNameLen = pstFile->staFileInfoSet[i].usFileNameLen; + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_FILE_ACT, 0); + return; + } + } + + pstFile->unStatus = FILE_ST_IDLE; +#endif + return; +} + + +unsigned short CS10x_Send_FilePro_Master(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus) +{ + unsigned short usMsgSize = 0; + + switch(usFileProType) + { + case FILE_ST_RD_DIR: //召唤目录 + usMsgSize = Send_ReadFS_CallDir_M(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_ACT: //读文件激活 + usMsgSize = Send_ReadFS_SelectFile_M(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_DATA_RESPONE: //读文件数据传输确认 + usMsgSize = Send_ReadFS_AckFileSeg_M(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + break; + + case FILE_ST_WR_FILE_ACT: //写文件激活 + usMsgSize = Send_WriteFS_SelectFile_M(pstSelf, usFileProType, pstAsdus, &pstSelf->stWdSet); + break; + + case FILE_ST_WR_FILE_DATA: //写文件数据传输 + usMsgSize = Send_WriteFS_DownFileSeg_M(pstSelf, usFileProType, pstAsdus, &pstSelf->stWdSet); + break; + + default: + break; + } + + return usMsgSize; +} + + +unsigned short CS10x_Send_FilePro_Slave(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus) +{ + unsigned short usMsgSize = 0; + + switch(usFileProType) + { + case FILE_ST_RD_DIR_RESPONE: //召唤目录响应 + usMsgSize = Send_ReadFS_AckCallDir_S(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_ACT_RESPONE: //读文件激活确认 + usMsgSize = Send_ReadFS_AckSelectFile_S(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + break; + + case FILE_ST_RD_FILE_DATA: //读文件数据传输 + usMsgSize = Send_ReadFS_CallFileSeg_S(pstSelf, usFileProType, pstAsdus, &pstSelf->stRdSet); + + /*101规约无确认文件传输功能*/ + if(pstSelf->eCS10x_Type == CS101_TYPE_S && usMsgSize > 0 && pstSelf->ucFileAckType == 1) + { + pstSelf->ucFileTransFrame = 1; /* 正在进行文件传输*/ + pstSelf->usFileNoneAckNum++; /* 未确认传输帧累加*/ + } + + break; + + case FILE_ST_WR_FILE_ACT_RESPONE: //写文件激活确认 + usMsgSize = Send_WriteFS_AckSelectFile_S(pstSelf, usFileProType, pstAsdus, &pstSelf->stWdSet); + break; + + case FILE_ST_WR_FILE_DATA_RESPONE: //写文件数据传输确认 + usMsgSize = Send_WriteFS_AckDownFileSeg_S(pstSelf, usFileProType, pstAsdus, &pstSelf->stWdSet); + break; + + default: + break; + } + + return usMsgSize; +} + +/** +* @brief //文件操作发送接口函数 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_FilePro(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usFileProType = (unsigned short)uiParam; + CS10x_Type stCS10x_Type = pstSelf->eCS10x_Type;; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = F_FR_NA; + pstAsdus->usSQ = 0; + + if(pstSelf->ucReadFileVSQ) + { + pstAsdus->usNum = 1; //解决部分部分主站无法识别VSQ=0的情况 + } + else + { + pstAsdus->usNum = 0; // vsq=0; 1表示无效 + } + + if(stCS10x_Type == CS101_TYPE_S || stCS10x_Type == CS104_TYPE_S) + { + return CS10x_Send_FilePro_Slave(pstSelf, usFileProType, pstAsdus); + } + else if(stCS10x_Type == CS101_TYPE_M || stCS10x_Type == CS104_TYPE_M) + { + return CS10x_Send_FilePro_Master(pstSelf, usFileProType, pstAsdus); + } + else + { + //主动模式设置错误 + } + + return 0; +} + + +/** +* @brief 接收切换定值区命令接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传输原因 +*/ +void Do_ChgConst(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usArea = 0; + unsigned short usLen = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(COT_ACT == usReason) //从站收 + { + usArea = IEC_MAKEWORD(pstAsdus->pucPayload[usLen], pstAsdus->pucPayload[usLen + 1]); + + if(NULL == pstSelf->pfnSetParamArea) + { + return; + } + + pstSelf->pfnSetParamArea(usArea, pstSelf->pUsrData); + SetSendTask(pstSelf, TSKID_ChgConst, COT_ACTCON, 0); + } + else if(COT_ACTCON == usReason) + { + usArea = IEC_MAKEWORD(pstAsdus->pucPayload[usLen], pstAsdus->pucPayload[usLen + 1]); + /*添加主模式读取成功返回函数*/ + } +} + +/** +* @brief 切换定值区命令发送接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ChgConst(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usArea = 0; + unsigned short usInfoLen = 0; + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_SR_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + usInfoLen = ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], 0, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += usInfoLen; + + if(COT_ACT == usReason) //激活 + { + if(pstSelf->pfnGetParamArea) + { + usArea = pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + } + else if(COT_ACTCON == usReason) //激活确认 + { + if(pstSelf->pfnGetParamArea) + { + usArea = pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 读定值区接收接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_ReadConst(CS10x *pstSelf, unsigned short usReason) +{ + if(COT_ACT == usReason) //从站收 + { + SetSendTask(pstSelf, TSKID_ReadConst, COT_ACTCON, 0); + } + else if(COT_ACTCON == usReason) + { + } +} + +/** +* @brief 读参数定值区发送接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return Asdu数据长度 +*/ +unsigned short CS10x_Send_ReadConst(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usArea = 0; + unsigned short usInfoLen = 0; + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_RR_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + usInfoLen = ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], 0, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += usInfoLen; + + if(COT_ACT == usReason) //激活 + { + } + else if(COT_ACTCON == usReason) //激活确认 + { + if(pstSelf->pfnGetParamArea) + { + usArea = pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + usArea = pstSelf->pfnGetParamArea(MINPARAMAREA, pstSelf->pUsrData); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + usArea = pstSelf->pfnGetParamArea(MAXPARAMAREA, pstSelf->pUsrData); + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + } + else + { + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usArea >> 8; + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 参数定值读取接收接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_ParamPreread(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucPi = 0; + unsigned short usLen = 0; + unsigned short usParamArea = 0; + unsigned int uiInfoAddr = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + IECPARAM_T stIecParam = {0}; + usParamArea = IEC_MAKEWORD(pstAsdus->pucPayload[usLen], pstAsdus->pucPayload[usLen + 1]); + usLen += 2; + + /*判断定值区*/ + if(pstSelf->pfnGetParamArea && usParamArea == pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData)) + { + } + + if(COT_ACT == usReason) //从站收 + { + /*读取后不允许固化,公用缓冲区*/ + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + + if(pstAsdus->usNum) + { + for(unsigned short i = 0; i < pstAsdus->usNum; i++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + + if(pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; /*追加缓存*/ + } + } + else + { + if(pstSelf->pfnAddIECParam) + { + /*读取所有参数*/ + pstSelf->pfnAddIECParam(1, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + } + + // pstSelf->ucParamFlag = 0; /*104多帧一起时可能存在问题,采用追加的方式实现,在响应完成后清零*/ + if(pstSelf->pfnRunReadIECParam) + { + pstSelf->pfnRunReadIECParam(pstSelf->pUsrData); + } + } + else if(COT_ACTCON == usReason) + { + /*作为主站时,暂时不添加*/ + ucPi = pstAsdus->pucPayload[usLen++]; + + for(unsigned short i = 0; i < pstAsdus->usNum; i++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + stIecParam.ucType = pstAsdus->pucPayload[usLen++]; + stIecParam.ucLen = pstAsdus->pucPayload[usLen++]; + + if(CheckParamTagAndLen(stIecParam.ucType, stIecParam.ucLen) == false) + { + return; + } + + if(stIecParam.ucLen) + { + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + } + + /*添加通知参数接收函数*/ + if(pstSelf->pfnSetParamInfo) + { + pstSelf->pfnSetParamInfo(&stIecParam,pstSelf->pUsrData); + } + } + + if((ucPi & PARAM_CONT_1) == 0) //无后续帧,置任务状态 + { + /*通知接收完成*/ + } + } +} + +/** +* @brief 参数定值读取发送接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return Asdu数据长度 +*/ +unsigned short CS10x_Send_ParamPreread(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucTxNum = 0;/*本次发送个数*/ + unsigned short usArea = 0; + unsigned short usContinue = 0; + unsigned short usTotalNum = 0;/*缓冲数据个数*/ + unsigned short usReason = (unsigned short)uiParam; + unsigned short usReadParamType = (unsigned short)(uiParam >> 16); + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_RS_NA; + pstAsdus->usSQ = 0; + pstAsdus->usCot = usReason; + + if(pstSelf->pfnGetParamArea) + { + usArea = pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize ++] = IEC_LOBYTE(usArea);//当前定值区号:低 + pstAsdus->pucPayload[pstAsdus->usPayloadSize ++] = IEC_HIBYTE(usArea);//当前定值区号:高 + if(usReadParamType)//读全部参数 + { + pstAsdus->usNum = 0; + return pstAsdus->usPayloadSize; + } + + if(NULL == pstSelf->pfnGetParamCount) + { + return 0; + } + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_ACT == usReason) //激活 + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); //获取总数量 + + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + ucTxNum++; + usContinue = 0; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + + if(!ucTxNum) + { + return 0; + } + } + else if(COT_ACTCON == usReason) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); //获取总数量 + pstAsdus->usPayloadSize++; //是否后续帧及数据帧数量后面填充 + + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 2 + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucType; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucLen; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + usContinue = 0; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + + if(usContinue) + { + pstAsdus->pucPayload[2] = PARAM_CONT_1; /*PI参数特征表示为1:有后续*/ + } + else + { + pstAsdus->pucPayload[2] = 0; /*PI参数特征表示为1:无后续*/ + } + } + + if(usContinue == 0) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; /*无后续帧时,不进行追加,其他条件下可以进行参数追加,解决连帧问题*/ + } + else + { + SetSendTask(pstSelf, TSKID_ParamPreread, usReason, 0); /*继续执行发送任务*/ + } + + pstAsdus->usNum = ucTxNum; /*VSQ赋值*/ + return pstAsdus->usPayloadSize; +} + +/** +* @brief 参数定值写接口接收处理接口(参数预置、固化、取消) +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_ParamPreset(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucPi = 0; + unsigned short usi = 0; + unsigned short usArea = 0; + unsigned short usLen = 0; + unsigned int uiInfoAddr = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + IECPARAM_T stIecParam = {0}; + usArea = IEC_MAKEWORD(pstAsdus->pucPayload[usLen], pstAsdus->pucPayload[usLen + 1]); + + if(pstSelf->pfnGetParamArea && usArea == pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData)) + { + } + + usLen += 2; + ucPi = pstAsdus->pucPayload[usLen++]; + + if(COT_ACT == usReason) //从站收 + { + if(ucPi & PARAM_SE_1) //参数预置 + { + pstSelf->ucPmPresetFlag = 1; + pstSelf->uiPmPresetTimeout = 180000; /*最长固化时间*/ + + if(pstAsdus->usNum == 0) + { + return; + } + + /*首次预置时,清除发送序号*/ + if(pstSelf->ucParamFlag == 0) + { + pstSelf->usParamSendNum = 0; + } + + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + stIecParam.ucType = pstAsdus->pucPayload[usLen++]; + stIecParam.ucLen = pstAsdus->pucPayload[usLen++]; + + if(CheckParamTagAndLen(stIecParam.ucType, stIecParam.ucLen) == false) + { + return; + } + + if(stIecParam.ucLen) + { + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + } + + if(NULL != pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMWT, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; + } + + pstSelf->uiPreSetContCount = 10000; /* 10S无参数预置则判定为参数预置结束 */ + + /*配置参数时无后续帧则之间认定无后续,否则使用超时+固化参数进行状态更新*/ + if(pstSelf->ucPreSetContType == 0) + { + /*一帧参数小于5个时,自动认定为最后一帧数据,主要用于山东一体化运维不固化*/ + if(pstAsdus->usNum < 5 || (ucPi & PARAM_CONT_1) == PARAM_CONT_0) + { + pstSelf->ucParamFlag = 0; + } + } + + SetSendTask(pstSelf, TSKID_ParamPrewrite, COT_ACTCON, PARAM_SE_1); + } + else + { + pstSelf->ucParamFlag = 0; /*重置首次添加标识*/ + unsigned char ucFlag = 0; + + if(pstSelf->ucPreSetContType) + { + pstSelf->usParamSendNum = 0; + } + + if(0 == (ucPi & PARAM_CR_1)) // VSQ 为0,参数固化 + { + /*预置后才允许固化*/ + if(pstSelf->ucPmPresetFlag && pstSelf->pfnRunWriteIECParam) + { + ucFlag = pstSelf->pfnRunWriteIECParam(pstSelf->pUsrData); + } + } + + if(ucFlag) + { + SetSendTask(pstSelf, TSKID_ParamPrewrite, COT_ACTCON, 0); /*预置成功*/ + } + else + { + SetSendTask(pstSelf, TSKID_ParamPrewrite, COT_PN | COT_ACTCON, 0); /*预置失败,终止命令*/ + } + + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + } + } + else if(COT_ACTCON == usReason) + { + if(ucPi & PARAM_SE_1) //参数预置 + { + if((ucPi & PARAM_CONT_1) == PARAM_CONT_0) + { + SetSendTask(pstSelf,TSKID_ParamPrewrite,COT_ACT,PARAM_SE_0); + } + + } + else + { + if(ucPi & PARAM_CR_1) //取消预置 + { + } + else //参数固化 + { + SetSendTask(pstSelf,TSKID_ParamPreread,COT_ACT,READ_ALL_PARAM); + } + } + + return; // 收到预置命令 + } + else if(COT_DEACT == usReason) + { + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + pstSelf->ucParamFlag = 0; + + if((ucPi & (PARAM_SE_1 | PARAM_CR_1)) == PARAM_CR_1) + { + SetSendTask(pstSelf, TSKID_ParamPrewrite, COT_DEACTCON, PARAM_CR_1); + } + + return; + } + else if(COT_DEACTCON == usReason) + { + /*停止激活确认*/ + } +} + +/** +* @brief 参数定值写接口发送组包处理 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamPreset(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucCont = 0; + unsigned char ucPi = 0; + unsigned char ucTxNum = 0; + unsigned short usTotalNum = 0; + unsigned short usi = 0; + unsigned short usArea = 0; + unsigned short usReason = (unsigned short)uiParam; + unsigned short usPi = (unsigned short)(uiParam >> 16); /*参数*/ + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_WS_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; + + if(pstSelf->pfnGetParamArea) + { + usArea = pstSelf->pfnGetParamArea(CURPARAMAREA, pstSelf->pUsrData); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize ++] = IEC_LOBYTE(usArea); + pstAsdus->pucPayload[pstAsdus->usPayloadSize ++] = IEC_HIBYTE(usArea); + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_ACT == usReason) + { + if(PARAM_SE_1 & usPi) //对子设备进行参数预置 + { + ucPi = PARAM_SE_1; + pstAsdus->usPayloadSize++; // PI标识位置 + + if(NULL == pstSelf->pfnGetParamCount) + { + return 0; + } + + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); //获取总数量 + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 2 + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucType; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucLen; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen); + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + ucCont = 0; + + if(pstSelf->ucParamFlag == 1) + { + ucCont = 1; + } + } + else + { + ucCont = 1; + } + } + + pstSelf->usParamSendNum++; + } + + if(ucCont) + { + ucPi |= PARAM_CONT_1; + SetSendTask(pstSelf, pstSelf->byTaskFlagId, COT_ACT, PARAM_SE_1); + } + + if(ucCont == 0 || pstSelf->usParamSendNum == usTotalNum) + { + pstSelf->usParamSendNum = 0; + } + + pstAsdus->usNum = ucTxNum; + pstAsdus->pucPayload[2] = ucPi; + } + else + { + if(PARAM_CR_1 & usPi) //取消预置 + { + ucPi |= PARAM_CR_1; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucPi; + } + else //参数固化 + { + ucPi = 0; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucPi; + } + } + } + else if(COT_ACTCON == usReason || (COT_PN | COT_ACTCON) == usReason) //回复主站参数预置数据 + { + if(PARAM_SE_1 == usPi) + { + ucPi = PARAM_SE_1; + pstAsdus->usPayloadSize++; + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 2 + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucType; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stIecParam.ucLen; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen); + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + + /*缓存中无数据,不进行后续发送*/ + if(ucCont) + { + ucPi |= PARAM_CONT_1; + SetSendTask(pstSelf, pstSelf->byTaskFlagId, COT_ACTCON, PARAM_SE_1); + } + + /*主方向有后续,本帧返回带后续帧*/ + if(pstSelf->ucParamFlag == 1 && pstSelf->ucPreSetContType == 0) + { + ucPi |= PARAM_CONT_1; + } + + /*主方向无后续帧且发送完成时,清除*/ + if(pstSelf->ucParamFlag == 0 && (ucCont == 0 || pstSelf->usParamSendNum == usTotalNum)) + { + pstSelf->usParamSendNum = 0; + } + + pstAsdus->usNum = ucTxNum; + pstAsdus->pucPayload[2] = ucPi; + } + else + { + ucPi = 0; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucPi; + } + } + else if(COT_DEACT == usReason) + { + ; + } + else if(COT_DEACTCON == usReason) + { + if((usPi & (PARAM_SE_1 | PARAM_CR_1)) == PARAM_CR_1) //取消预置 + { + ucPi |= PARAM_CR_1; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucPi; + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief Set the 101/104 Asdu Payload site +* +* @param[in] pstSelf 规约实体 +* @return 组包长度 +*/ +unsigned short GetPayloadOffset(CS10x *pstSelf) +{ + unsigned short usPos = 0; + + if(CS101_TYPE_S == pstSelf->eCS10x_Type || CS101_TYPE_M == pstSelf->eCS10x_Type) + { + usPos = 5 + pstSelf->stAppParameters.iSzOfLinkAddr + pstSelf->stAppParameters.iSzOfCA + pstSelf->stAppParameters.iSzOfCOT + 2; + } + else + { + usPos = APCI_LEN + 2 + pstSelf->stAppParameters.iSzOfCA + pstSelf->stAppParameters.iSzOfCOT; + } + + return usPos; +} + +/** +* @brief Get the Asdu Info object +* +* @param[in] pstSelf 规约实体 +** pucPayload-信息对象起始指针 +* pusPayloadSize-信息对象长度 +*/ +unsigned short DecodeAsduMember(CS10x *pstSelf, unsigned char * pucAsdu, unsigned short usAsduSz) +{ + unsigned short usLen = 0; + pstSelf->stAsduElem.usTypeID = pucAsdu[usLen++]; + pstSelf->stAsduElem.usSQ = pucAsdu[usLen] >> 7; + pstSelf->stAsduElem.usNum = pucAsdu[usLen++] & 0x7F; + + if(1 == pstSelf->stAppParameters.iSzOfCOT) + { + pstSelf->stAsduElem.usCot = pucAsdu[usLen]; + usLen += 1; + } + else + { + pstSelf->stAsduElem.usCot = IEC_MAKEWORD(pucAsdu[usLen], pucAsdu[usLen + 1]); + pstSelf->stAsduElem.usCotH = pucAsdu[usLen + 1]; + usLen += 2; + } + + pstSelf->stAsduElem.usCot = pstSelf->stAsduElem.usCot & 0xFF; /*仅处理低字节数据,不处理高字节数据*/ + + if(1 == pstSelf->stAppParameters.iSzOfCA) //公共地址字节数 + { + pstSelf->stAsduElem.uiAddr = pucAsdu[usLen++]; + } + else + { + pstSelf->stAsduElem.uiAddr = IEC_MAKEWORD(pucAsdu[usLen], pucAsdu[usLen + 1]); + usLen += 2; + } + + pstSelf->stAsduElem.pucPayload = pucAsdu + usLen; // ASDU信息体起始指针 + pstSelf->stAsduElem.usPayloadSize = usAsduSz - usLen; // ASDU域长度 + return usLen; +} + +/** +* @brief Get the Task TI type object +* +* @param[in] pstSelf 规约实体 +* @param[in] usDataType +* @return usTiType数据TI类型 +*/ +unsigned short GetTaskTItype(CS10x *pstSelf, unsigned short usDataType) +{ + unsigned short usTiType = 0; + + if(DATATYPE_YC == usDataType) + { + switch(pstSelf->usYcType) + { + case YC_TYPE_ME_NA: + usTiType = M_ME_NA; + break; + + case YC_TYPE_ME_NB: + usTiType = M_ME_NB; + break; + + case YC_TYPE_ME_NC: + usTiType = M_ME_NC; + break; + + default: + usTiType = M_ME_NA; + break; + } + } + else if(DATATYPE_YX == usDataType) + { + switch(pstSelf->usYxType) + { + case YX_TYPE_M_SP: + usTiType = M_SP_NA; + break; + + case YX_TYPE_M_DP: + usTiType = M_DP_NA; + break; + + default: + usTiType = M_SP_NA; + break; + } + } + else if(DATATYPE_YXT == usDataType) + { + switch(pstSelf->usYxType) + { + case YX_TYPE_M_SP: + usTiType = M_SP_TB; + break; + + case YX_TYPE_M_DP: + usTiType = M_DP_TB; + break; + + default: + usTiType = M_SP_TB; + break; + } + } + + return usTiType; +} + +/**********************文件传输扩展接口************************/ + +/** +* @brief 召唤目录===>接收 +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_CallDir_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usLen = 0; + memset(pstRdSet, 0x00, sizeof(tFILEDIR_RD_SET)); + pstSelf->ucTransStatus = FILE_ST_RD_DIR_RESPONE; //文件目录召唤响应 + memcpy(&pstRdSet->uiId, &pucBuf[usLen], 4); + usLen += 4; //目录ID 4字节 + //文件名 + pstRdSet->ucDirLen = pucBuf[usLen++]; + memcpy(pstRdSet->caDirName, &pucBuf[usLen], pstRdSet->ucDirLen); + usLen += pstRdSet->ucDirLen; + //召唤目录条件 + pstRdSet->ucCallFlag = pucBuf[usLen++]; + CP56Time2a_GetFromBuf(&pucBuf[usLen], &pstRdSet->stStartTime); + usLen += 7; + CP56Time2a_GetFromBuf(&pucBuf[usLen], &pstRdSet->stEndTime); + + //查询目录下文件数量 + if(NULL != pstSelf->pfnGetNumDirFile) + { + pstRdSet->usFrmNum = pstSelf->pfnGetNumDirFile(pstRdSet); + } + + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_DIR_RESPONE, 0); +} + +/** +* @brief 召唤目录确认===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_AckCallDir_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usLen = 0; + unsigned char ucLastFrmFlag = 0; + tDIR_FILE_INFO stDirFileSet = {0}; + pstSelf->ucTransStatus = FILE_ST_RD_DIR_RESPONE; + pstRdSet->usFrmNum = 0; + + if(0 == pucBuf[usLen++]) // 0-成功;1-失败 + { + usLen += 4; //目录ID 4字节 + pstRdSet->ucFollow = pucBuf[usLen++]; //后续标志 + pstRdSet->usFrmNum = pucBuf[usLen++]; //本帧文件数量 + + for(unsigned short i = 0; i < pstRdSet->usFrmNum; i++) + { + stDirFileSet.stFileName.ucFileLen = pucBuf[usLen++];//名称长度 + memcpy(stDirFileSet.stFileName.caFileName, &pucBuf[usLen], stDirFileSet.stFileName.ucFileLen);//名称 + usLen += stDirFileSet.stFileName.ucFileLen; + stDirFileSet.ucAttri = pucBuf[usLen++]; //属性 + memcpy(&stDirFileSet.uiFileSize, &pucBuf[usLen], 4);//大小 + usLen += 4; + CP56Time2a_GetFromBuf(&pucBuf[usLen], &stDirFileSet.stTimeStamp);//时间 + usLen += 7; + pstRdSet->usCurNum++; + if((i == pstRdSet->usFrmNum - 1) && (pstRdSet->ucFollow == 0)) + { + ucLastFrmFlag = 1; + } + + if(pstSelf->pfnDealDirRecvFinish != NULL) + { + pstSelf->pfnDealDirRecvFinish(&stDirFileSet, pstRdSet->usCurNum, ucLastFrmFlag, pstSelf->pUsrData); + } + + } + + if(0 == pstRdSet->ucFollow) //无后续帧 数据结束,判断是否需要 + { + pstSelf->ucTransStatus = FILE_ST_IDLE; + pstSelf->uiTransTimerCur = 0; + pstRdSet->usCurNum = 0; + } + } +} + +/** +* @brief 读文件激活===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_SelectFile_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usLen = 0; + tDIR_FILE_INFO stDirFileInfo = {0}; + + if(pstSelf->ucTransStatus < FILE_ST_RD_DIR_RESPONE) + { + return; + } + + pstSelf->ucTransStatus = FILE_ST_RD_FILE_ACT; //读文件激活 + pstRdSet->ucFileLen = pucBuf[usLen++]; + memcpy(pstRdSet->caFileName, &pucBuf[usLen], pstRdSet->ucFileLen); + + if(NULL != pstSelf->pfnGetProDirFile) + { + pstSelf->pfnGetProDirFile(pstRdSet, &stDirFileInfo, PROT_FILE_OBJ, 0, pstSelf->pvFileReadParam); + } + + pstRdSet->uiTotalSize = stDirFileInfo.uiFileSize; //给读文件数据传输用 + pstRdSet->uiOffSetSize = 0; //读文件激活将文件偏移量复位 + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_FILE_ACT_RESPONE, 0); +} + +/** +* @brief 读文件激活确认===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_AckSelectFile_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usLen = 0; + tFILE_NAME stFileName; + memset(&stFileName, 0x00, sizeof(tFILE_NAME)); + + if(pstSelf->ucTransStatus < FILE_ST_RD_FILE_ACT) + { + return; + } + + pstSelf->ucTransStatus = FILE_ST_RD_FILE_ACT_RESPONE; + + if(0 == pucBuf[usLen++]) // 0-成功;1-失败 + { + memset(&stFileName, 0, sizeof(tFILE_NAME)); + stFileName.ucFileLen = pucBuf[usLen++]; //文件名长度 + memcpy(stFileName.caFileName, &pucBuf[usLen], stFileName.ucFileLen); + usLen += stFileName.ucFileLen + 4; //跳过文件标识 + + if(pstRdSet->ucFileLen == stFileName.ucFileLen && + 0 == strcmp(pstRdSet->caFileName, stFileName.caFileName)) + { + memcpy(&pstRdSet->uiTotalSize, &pucBuf[usLen], 4); + usLen += 4; + pstSelf->uiTransTimerCur = 0; + } + } +} + +/** +* @brief 读文件数据传输===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_CallFileSeg_M(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usLen = 0; + unsigned char ucChecksum = 0; + unsigned char ucDataLen = 0; + ASDU_Element *pstAsduInfo; + pstAsduInfo = &pstSelf->stAsduElem; + + if(pstSelf->ucTransStatus < FILE_ST_RD_FILE_ACT_RESPONE) + { + return; + } + + pstSelf->ucTransStatus = FILE_ST_RD_FILE_DATA; + usLen += 4; //文件标识 + memcpy(&pstRdSet->uiOffSetSize, &pucBuf[usLen], 4); + usLen += 4; //文件传输偏移 + pstRdSet->ucFollow = pucBuf[usLen++]; //有无后续 1字节 + ucDataLen = pstAsduInfo->usPayloadSize - usLen - 6; + ucChecksum = checksum_8(&pucBuf[usLen], ucDataLen); + + if(ucChecksum == pstAsduInfo->pucPayload[pstAsduInfo->usPayloadSize - 1]) + { + if(pstSelf->pfnWriteFile != NULL) + { + pstSelf->pfnWriteFile(pstRdSet, &pucBuf[usLen], ucDataLen, pstSelf->pUsrData); + } + } + + if(pstRdSet->ucFollow == 0) + { + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_FILE_DATA_RESPONE, 0); + pstSelf->ucTransStatus = FILE_ST_IDLE; //文件传输完成 + pstSelf->uiTransTimerCur = 0; + } +} + + +/** +* @brief 读文件数据传输确认===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstRdSet 文件信息及传输状态 +* @return +*/ +void Revc_ReadFS_AckFileSeg_S(CS10x *pstSelf, unsigned char *pucBuf, tFILEDIR_RD_SET *pstRdSet) +{ + if(pstSelf->ucTransStatus < FILE_ST_RD_FILE_DATA) + { + return; + } + + pstSelf->ucTransStatus = FILE_ST_RD_FILE_DATA_RESPONE; +} + +/** +* @brief 写文件激活===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstWdSet 文件信息及传输状态 +* @return +*/ +void Recv_WriteFS_SelectFile_S(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet) +{ + unsigned short usLen = 0; + pstSelf->ucTransStatus = FILE_ST_WR_FILE_ACT; + memset(pstWdSet->ucFileName, 0, FILE_NAME_SIZE); + pstWdSet->ucFileLen = pucBuf[usLen++]; + memcpy(pstWdSet->ucFileName, &pucBuf[usLen], pstWdSet->ucFileLen); + usLen += pstWdSet->ucFileLen; + memcpy(&pstWdSet->uiFileId, &pucBuf[usLen], 4); + usLen += 4; //文件ID + memcpy(&pstWdSet->uiFileSize, &pucBuf[usLen], 4); + usLen += 4; //文件大小 + pstWdSet->ucResult = 0; + + /*检测是否可以写入文件*/ + if(pstSelf->pfnWriteFileCheck) + { + pstWdSet->ucResult = pstSelf->pfnWriteFileCheck(pstWdSet, pstSelf->pvFileWrteParam, pstSelf->pUsrData); + } + + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_WR_FILE_ACT_RESPONE, 0); + /*重置md5*/ + StartMD5(&pstSelf->stMd5_Ctx); +} + +/** +* @brief 写文件激活确认===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstWdSet 文件信息及传输状态 +* @return +*/ +void Recv_WriteFS_AckSelectFile_M(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet) +{ + unsigned short usLen = 0; + tFILE_WD_SET stWdAck = {0}; //对下从设备响应的写文件激活确认 + + if(pstSelf->ucTransStatus < FILE_ST_WR_FILE_ACT) + { + return; + } + + memset(&stWdAck, 0x00, sizeof(tFILE_WD_SET)); + pstSelf->ucTransStatus = FILE_ST_WR_FILE_ACT_RESPONE; + + if(0 == pucBuf[usLen++]) // 0-成功;1-失败, //默认传输文件目录正确 + { + stWdAck.ucFileLen = pucBuf[usLen++]; //文件名长度 + memcpy(stWdAck.ucFileName, &pucBuf[usLen], stWdAck.ucFileLen); + usLen += stWdAck.ucFileLen; + memcpy(&stWdAck.uiFileId, &pucBuf[usLen], 4); + usLen += 4; //文件标识 + memcpy(&stWdAck.uiFileSize, &pucBuf[usLen], 4); + usLen += 4; + + // + if(pstWdSet->ucFileLen == stWdAck.ucFileLen && (0 == strcmp(pstWdSet->ucFileName, stWdAck.ucFileName)) && + pstWdSet->uiFileId == stWdAck.uiFileId && pstWdSet->uiFileSize == stWdAck.uiFileSize) + { + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_WR_FILE_DATA, 0); + } + else + { + //从设备响应写文件激活, 与写文件激活信息不一致 + } + } +} + +/** +* @brief 写文件数据传输===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstWdSet 文件信息及传输状态 +* @return +*/ +void Recv_WriteFS_DownFileSeg_S(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet, unsigned short usFileDateLen) +{ + unsigned char ucContinue = 0; + unsigned char ucChecksum = 0; + unsigned char ucDataLen = 0; + unsigned short usLen = 0; + unsigned int uiCurFileId = 0; + pstSelf->ucTransStatus = FILE_ST_WR_FILE_DATA; + //usLen = 0; + memcpy(&uiCurFileId, &pucBuf[usLen], 4); + usLen += 4; //文件标识 + + if(uiCurFileId != pstWdSet->uiFileId) + { + pstWdSet->ucResult = WRITE_FILE_ERR_ID; + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_WR_FILE_DATA_RESPONE, 0); + return; + } + + memcpy(&pstWdSet->uiOffSetSize, &pucBuf[usLen], 4); + usLen += 4; //文件标识 + ucContinue = pucBuf[usLen++]; //有无后续 1字节 + ucDataLen = usFileDateLen - usLen - 1 ; + ucChecksum = checksum_8(&pucBuf[usLen], ucDataLen); + + if(ucChecksum == pucBuf[usLen + ucDataLen]) + { + /*计算MD5*/ + EncodeMD5(&pstSelf->stMd5_Ctx, &pucBuf[usLen], ucDataLen); + // pstSelf->WriteFile(pstFile->caDirName, pstFile->stTransFileInfo.caFileName, pstFile->uiFileOffset, &pAsduInfo->pucPayload[usLen], ucDataLen, pstSelf->pUsrData); + + if(pstSelf->pfnWrite) + { + pstSelf->pfnWrite(pstWdSet->uiOffSetSize, &pucBuf[usLen], ucDataLen, pstSelf->pvFileWrteParam, pstSelf->pUsrData); + } + } + else + { + // pstFile->stTransFileInfo.ucAttr = WRITE_FILE_ERR_CHECK; + pstWdSet->ucResult = WRITE_FILE_ERR_CHECK; + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_WR_FILE_DATA_RESPONE, 0); + return; + } + + if(ucContinue == 0) + { + /*MD5结果计算*/ + GetMD5(&pstSelf->stMd5_Ctx, pstSelf->ucaMd5_Result); + + if(pstSelf->pfnMd5ResultCb) + { + pstSelf->pfnMd5ResultCb(pstSelf->ucaMd5_Result); + } + + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_WR_FILE_DATA_RESPONE, 0); + + if(pstSelf->pfnWriteFinish) + { + pstSelf->pfnWriteFinish(pstSelf->ucaMd5_Result, pstSelf->pvFileWrteParam, pstSelf->pUsrData); + } + + pstWdSet->ucResult = WRITE_FILE_ERR_NONE; + } +} + +/** +* @brief 写文件数据传输确认===>接收 +* +* @param[in] pstSelf 规约实体 +* @param[in] pucBuf 数据缓存 +* @param[out] pstWdSet 文件信息及传输状态 +* @return +*/ +void Recv_WriteFS_AckDownFileSeg_M(CS10x *pstSelf, unsigned char *pucBuf, tFILE_WD_SET *pstWdSet) +{ + if(pstSelf->ucTransStatus < FILE_ST_WR_FILE_DATA) + { + return; + } + + pstSelf->ucTransStatus = FILE_ST_WR_FILE_DATA_RESPONE; + pstSelf->uiTransTimerCur = 0; +} + +/** +* @brief 召唤目录<===发送 +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_CallDir_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize; + unsigned char *pucPayload; + usPayloadSize = &pstAsdus->usPayloadSize; + pucPayload = &pstAsdus->pucPayload[0]; + pstSelf->ucTransStatus = FILE_ST_RD_DIR; //读取目录 + pstSelf->uiTransTimerCur = 0; //定时器 + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_DIR; //操作标识 + (*usPayloadSize) += 4; + pucPayload[(*usPayloadSize)++] = pstRdSet->ucDirLen; //目录ID + memcpy(&pucPayload[(*usPayloadSize)], pstRdSet->caDirName, pstRdSet->ucDirLen); + (*usPayloadSize) += pstRdSet->ucDirLen; + pucPayload[(*usPayloadSize)++] = pstRdSet->ucCallFlag;// 召唤标志, 0: 读取目录下所有文件, 1: 目录下满足搜索时间段的文件 + (*usPayloadSize) += CP56Time2a_Pack2Buf(&pucPayload[(*usPayloadSize)], &pstRdSet->stStartTime); + (*usPayloadSize) += CP56Time2a_Pack2Buf(&pucPayload[(*usPayloadSize)], &pstRdSet->stEndTime); + return (*usPayloadSize); +} + +/** +* @brief 召唤目录响应<===发送 +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_AckCallDir_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned char caBuf[256] = {0}; + unsigned short usi = 0; + unsigned short usInfoLen = 0; + unsigned short usContinue = 0; + unsigned short usIDataLen = 0; + unsigned short usAsduFileflg = 0; + unsigned short usFileSendNum_Local = 0; + unsigned short usFileSendNum_Total = 0; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + tDIR_FILE_INFO stDirFileInfo = {0}; + pstSelf->ucTransStatus = FILE_ST_RD_DIR_RESPONE; //开始回复文件目录状态 + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_DIR_RESPONE; //操作标识 + pucPayload[(*usPayloadSize)++] = 0x00; //结果描述成功 + memcpy(&pucPayload[(*usPayloadSize)], &pstRdSet->uiId, 4); //目录ID + (*usPayloadSize) += 4; + usFileSendNum_Total = pstRdSet->usFrmNum - pstRdSet->usCurNum; //剩余待发送文件数量 + usAsduFileflg = (*usPayloadSize); + (*usPayloadSize) += 2; //先跳过后续帧与本帧数量 + // pucPayload[(*usPayloadSize)++] = usContinue; //有无后续 + // pucPayload[(*usPayloadSize)++] = usFileSendNum; //本帧数量 + + for(usi = 0; usi < usFileSendNum_Total; usi++) + { + memset(caBuf, 0, 256); + usIDataLen = 0; + + if(NULL != pstSelf->pfnGetProDirFile) + { + pstSelf->pfnGetProDirFile(pstRdSet, &stDirFileInfo, PROT_DIR_OBJ, pstRdSet->usCurNum, pstSelf->pvFileReadParam); + } + + caBuf[usIDataLen++] = stDirFileInfo.stFileName.ucFileLen; + memcpy(&caBuf[usIDataLen], stDirFileInfo.stFileName.caFileName, stDirFileInfo.stFileName.ucFileLen); + usIDataLen += stDirFileInfo.stFileName.ucFileLen; + caBuf[usIDataLen++] = stDirFileInfo.ucAttri; //文件属性备用 + memcpy(&caBuf[usIDataLen], &stDirFileInfo.uiFileSize, 4); + usIDataLen += 4; + memcpy(&caBuf[usIDataLen], &stDirFileInfo.stTimeStamp, 7); + usIDataLen += 7; + + if(usIDataLen + (*usPayloadSize) <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + memcpy(&pucPayload[(*usPayloadSize)], caBuf, usIDataLen); + (*usPayloadSize) += usIDataLen; + usContinue = 0; + pstRdSet->usCurNum++; + usFileSendNum_Local++; + } + else + { + usContinue = 1; + break; + } + } + + pucPayload[usAsduFileflg] = usContinue; //有无后续 + pucPayload[usAsduFileflg + 1] = usFileSendNum_Local; //本帧数量 + + if(usContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usFileProType, 0); + } + + return (*usPayloadSize); +} + + +/** +* @brief 读文件激活<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_SelectFile_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize; + unsigned char *pucPayload; + pstSelf->ucTransStatus = FILE_ST_RD_FILE_ACT; //读文件激活 + pstSelf->uiTransTimerCur = 0; + usPayloadSize = &pstAsdus->usPayloadSize; + pucPayload = &pstAsdus->pucPayload[0]; + pstAsdus->usCot = COT_ACT; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_FILE_ACT; //操作标识 + pucPayload[(*usPayloadSize)++] = pstRdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], pstRdSet->caFileName, pstRdSet->ucFileLen); + (*usPayloadSize) += pstRdSet->ucFileLen; + return (*usPayloadSize); +} + +/** +* @brief 读文件激活确认<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_AckSelectFile_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + pstSelf->ucTransStatus = FILE_ST_RD_FILE_ACT_RESPONE; //开始文件激活状态 + pstAsdus->usCot = COT_ACTCON; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_FILE_ACT_RESPONE; //操作标识 + pucPayload[(*usPayloadSize)++] = 0x00; //结果描述成功 + pucPayload[(*usPayloadSize)++] = pstRdSet->ucFileLen; //文件名长度 + memcpy(&pucPayload[(*usPayloadSize)], pstRdSet->caFileName, pstRdSet->ucFileLen); + (*usPayloadSize) += pstRdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], &pstRdSet->uiId, 4); + (*usPayloadSize) += 4; //文件ID + memcpy(&pucPayload[(*usPayloadSize)], &pstRdSet->uiTotalSize, 4); + (*usPayloadSize) += 4; //文件大小 + SetSendTask(pstSelf, pstSelf->byTaskFlagId, FILE_ST_RD_FILE_DATA, 0); + return (*usPayloadSize); +} + + +/** +* @brief 读文件数据传输<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_CallFileSeg_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned char pucBuf[256] = {0}; + unsigned short usInfoLen = 0; + unsigned short usFileSendLen = 0; + unsigned short usContinue = 0; + unsigned int uiMaxFileSendLen = 200; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + pstSelf->ucTransStatus = FILE_ST_RD_FILE_DATA; //开始数据传输状态 + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_FILE_DATA; //操作标识 + memcpy(&pucPayload[(*usPayloadSize)], &pstRdSet->uiId, 4); + (*usPayloadSize) += 4; //文件ID + memcpy(&pucPayload[(*usPayloadSize)], &pstRdSet->uiOffSetSize, 4); + (*usPayloadSize) += 4; + uiMaxFileSendLen = pstSelf->stAppParameters.iMaxSzOfAsduLen - usInfoLen - 12; + if(pstRdSet->uiOffSetSize > pstRdSet->uiTotalSize) + { + return 0; + } + + if(NULL != pstSelf->pfnReadFile) + { + usFileSendLen = pstSelf->pfnReadFile(pstRdSet->uiOffSetSize, pucBuf, uiMaxFileSendLen, pstSelf->pvFileReadParam); + } + + /*文件读取异常*/ + if(0 == usFileSendLen) + { + return 0; + } + + if(pstRdSet->uiOffSetSize + usFileSendLen < pstRdSet->uiTotalSize) + { + usContinue = 1; + } + else + { + usContinue = 0; + usFileSendLen = pstRdSet->uiTotalSize - pstRdSet->uiOffSetSize; + } + + pucPayload[(*usPayloadSize)++] = usContinue; + memcpy(&pucPayload[(*usPayloadSize)], pucBuf, usFileSendLen); + (*usPayloadSize) += usFileSendLen; + pucPayload[(*usPayloadSize)++] = checksum_8(pucBuf, usFileSendLen); + pstRdSet->uiOffSetSize += usFileSendLen; + + if(usContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, FILE_ST_RD_FILE_DATA, 0); + } + + return (*usPayloadSize); +} + +/** +* @brief 读文件数据传输确认<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstRdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_ReadFS_AckFileSeg_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILEDIR_RD_SET *pstRdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_FILE_DATA_RESPONE; //操作标识 + (*usPayloadSize) += 9; + + if(0 == strcmp(pstRdSet->caDirName, COMTRADE)) //仅仅COMTRADE才比对录波文件 + { + CheckFileDiff(pstSelf); + + if(pstAsdus->usTypeID != 0xD2) + { + pstAsdus->usTypeID = 0xD2; + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_RD_FILE_DATA_RESPONE; //操作标识 + (*usPayloadSize) += 9; + } + } + else + { + pstSelf->ucTransStatus = FILE_ST_IDLE; + pstSelf->uiTransTimerCur = 0; + } + + return (*usPayloadSize); +} + + +/** +* @brief 写文件激活<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstWdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_WriteFS_SelectFile_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize; + unsigned char *pucPayload; + pstSelf->ucTransStatus = FILE_ST_WR_FILE_ACT; //写文件激活 + pstSelf->uiTransTimerCur = 0; + usPayloadSize = &pstAsdus->usPayloadSize; + pucPayload = &pstAsdus->pucPayload[0]; + pstAsdus->usCot = COT_ACT; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_WR_FILE_ACT; //操作标识 + //pucPayload[(*usPayloadSize)++] = pstFileWdSet->ucResult; //?????????? + pucPayload[(*usPayloadSize)++] = pstWdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], pstWdSet->ucFileName, pstWdSet->ucFileLen); + (*usPayloadSize) += pstWdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileId, 4); + (*usPayloadSize) += 4; //文件ID + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileSize, 4); + (*usPayloadSize) += 4; + return (*usPayloadSize); +} + + +/** +* @brief 写文件激活确认<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstWdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_WriteFS_AckSelectFile_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + pstSelf->ucTransStatus = FILE_ST_WR_FILE_ACT_RESPONE; //开始数据传输状态 + pstAsdus->usCot = COT_ACTCON; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_WR_FILE_ACT_RESPONE; //操作标识 + pucPayload[(*usPayloadSize)++] = pstWdSet->ucResult; //文件描述成功 + pucPayload[(*usPayloadSize)++] = pstWdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], pstWdSet->ucFileName, pstWdSet->ucFileLen); + (*usPayloadSize) += pstWdSet->ucFileLen; + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileId, 4); + (*usPayloadSize) += 4; + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileSize, 4); + (*usPayloadSize) += 4; + return (*usPayloadSize); +} + + +/** +* @brief 写文件数据传输<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstWdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_WriteFS_DownFileSeg_M(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet) +{ + unsigned char pucBuf[200] = {0}; + unsigned char ucContinue = 0; + unsigned char ucChecksum = 0; + unsigned short usInfoLen = 0; + unsigned short usFileSendLen = 0; + unsigned int uiMaxFileSendLen = 200; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + pstAsdus->usCot = COT_ACT; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_WR_FILE_DATA; //操作标识 + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileId, 4); + (*usPayloadSize) += 4; + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiOffSetSize, 4); + (*usPayloadSize) += 4; + + if(pstWdSet->uiOffSetSize > pstWdSet->uiFileSize) + { + return 0; + } + + //memcpy(pstSlaveFileStu->caDirName,pstFile->caDirName,IEC_FILE_NAME_SIZE); + //memcpy(pstSlaveFileStu->caFileName,pstFile->stTransFileInfo.caFileName,IEC_FILE_NAME_SIZE); + usFileSendLen = pstSelf->pfnReadFile(pstWdSet->uiOffSetSize, pucBuf, uiMaxFileSendLen, (void *)pstSelf->pvFileReadParam); + + if(pstWdSet->uiOffSetSize + usFileSendLen < pstWdSet->uiFileSize) + { + ucContinue = 1; + } + else + { + ucContinue = 0; + usFileSendLen = pstWdSet->uiFileSize - pstWdSet->uiOffSetSize; + } + + pucPayload[(*usPayloadSize)++] = ucContinue; + memcpy(&pucPayload[(*usPayloadSize)], pucBuf, usFileSendLen); + (*usPayloadSize) += usFileSendLen; + ucChecksum = checksum_8(pucBuf, usFileSendLen); + pucPayload[(*usPayloadSize)++] = ucChecksum; + pstWdSet->uiOffSetSize += usFileSendLen; + + if(ucContinue) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usFileProType, 0); + } + else + { + pstWdSet->uiOffSetSize = 0; + } + + pstSelf->uiTransTimerCur = 0; + return (*usPayloadSize); +} + + +/** +* @brief 写文件数据传输确认<===发送 +* +* @param[in] pstSelf 规约实体 +* @param[in] usFileProType +* @param[out] pstAsdus +* @param[in] pstWdSet 文件信息及传输状态 +* @return +*/ +unsigned short Send_WriteFS_AckDownFileSeg_S(CS10x *pstSelf, unsigned short usFileProType, ASDU_Element *pstAsdus, tFILE_WD_SET *pstWdSet) +{ + unsigned short usInfoLen = 0; + unsigned short *usPayloadSize = &pstAsdus->usPayloadSize; + unsigned char *pucPayload = &pstAsdus->pucPayload[0]; + + if(pstSelf->ucTransStatus < FILE_ST_WR_FILE_DATA) + { + return 0; + } + + pstSelf->ucTransStatus = FILE_ST_WR_FILE_DATA_RESPONE; //开始数据传输状态 + pstAsdus->usCot = COT_REQ; + usInfoLen = ASDU_setIOA(&pucPayload[(*usPayloadSize)], 0, pstSelf->stAppParameters.iSzOfIOA); + (*usPayloadSize) += usInfoLen; + pucPayload[(*usPayloadSize)++] = FILE_TRANS; //数据包类型文件传输 + pucPayload[(*usPayloadSize)++] = FILE_ST_WR_FILE_DATA_RESPONE; //操作标识 + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiFileId, 4); + (*usPayloadSize) += 4; + memcpy(&pucPayload[(*usPayloadSize)], &pstWdSet->uiOffSetSize, 4); + (*usPayloadSize) += 4; //数据段号 + pucPayload[(*usPayloadSize)++] = pstWdSet->ucResult; //写文件错误类型0-成功 + return (*usPayloadSize); +} + +/** +* @brief 延时获得命令接收处理 +* @param[in] pstSelf-规约实体 +* @param[in] usReason--传输原因 +* @param[out] 无 +* @return 无 +*/ +void Do_ObtainDelay(CS10x *pstSelf, unsigned short usReason) +{ + if(COT_ACT == usReason) //激活 + { + SetSendTask(pstSelf, TSKID_ObtainDelay, COT_ACTCON, 0); + } + + return; +} + +/** +* @brief 延时获得命令发送处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam usReason-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ObtainDelay(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = (unsigned short)uiParam; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_CD_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + __CP56Time2a stCp56Time; + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(COT_ACTCON == (usReason & 0x3F)) //激活确认 + { + if(pstSelf->pfnGetTime) + { + pstSelf->pfnGetTime(&stCp56Time); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stCp56Time.ucLMs; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = stCp56Time.ucHMs; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 南网参数定值读取接收接口 +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_ParamRead_NanWang(CS10x *pstSelf, unsigned short usReason) +{ + unsigned short usLen = 0; + unsigned short usQoi = 0; + unsigned int uiInfoAddr = 0; + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsduInfo = &pstSelf->stAsduElem; + usQoi = pstAsduInfo->pucPayload[pstSelf->stAsduElem.usPayloadSize - 1]; + + if(COT_ACT == usReason && usQoi == 0x14) //激活 + { + /*读取后不允许固化,公用缓冲区*/ + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + SetSendTask(pstSelf, TSKID_ParamRead_NanWang, COT_ACTCON, usQoi); + + if(pstSelf->pfnAddIECParam) + { + /*读取所有参数*/ + pstSelf->pfnAddIECParam(1, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + } + else if(COT_ACT == usReason) + { + /*读取后不允许固化,公用缓冲区*/ + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + + if(pstAsduInfo->usNum) + { + if(pstAsduInfo->usSQ == 1) + { + pstSelf->ucPmPresetVsqFlag = 1; + uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + + for(unsigned short i = 0; i < pstAsduInfo->usNum; i++) + { + stIecParam.uiInfoAddr = uiInfoAddr; + uiInfoAddr++; + + if(pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; /*追加缓存*/ + } + } + else if(pstAsduInfo->usSQ == 0) + { + for(unsigned short i = 0; i < pstAsduInfo->usNum; i++) + { + uiInfoAddr = ASDU_getIOA(&pstAsduInfo->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + usLen += 4; + stIecParam.uiInfoAddr = uiInfoAddr; + + if(pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; /*追加缓存*/ + } + } + } + else + { + if(pstSelf->pfnAddIECParam) + { + /*读取所有参数*/ + pstSelf->pfnAddIECParam(1, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + } + + SetSendTask(pstSelf, TSKID_ParamRead_NanWang, COT_ACTCON, 0); + } +} + + +/** +* @brief 南网读参数命令发送处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParamusReason-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamRead_NanWang(CS10x *pstSelf, unsigned int uiParam) +{ + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_RS_NA_NANWANG; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = (unsigned short)uiParam; + unsigned short usReason = pstAsdus->usCot; + unsigned char ucQoi = (unsigned char)(uiParam >> 16); + unsigned char ucTxNum = 0;/*本次发送个数*/ + unsigned short usContinue = 0; + unsigned short usTotalNum = 0;/*缓冲数据个数*/ + IECPARAM_T stIecParam = {0}; + + if(pstSelf->ucPmPresetVsqFlag == 1) + { + pstSelf->ucPmPresetVsqFlag = 0; + pstAsdus->usSQ = 1; + } + + if(NULL == pstSelf->pfnGetParamCount) + { + return 0; + } + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_ACTCON == usReason || COT_ACTTERM == usReason) //激活确认及激活终止 从站发 + { + if(ucQoi == 0x14) + { + pstAsdus->usPayloadSize += ASDU_setIOA(pstAsdus->pucPayload, 0, pstSelf->stAppParameters.iSzOfIOA); + + if(COT_ACTCON == usReason) + { + SetSendTask(pstSelf, TSKID_ParamReadResponse_NanWang, COT_INTROGEN, 6); + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucQoi; + } + else + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); //获取总数量 + + if(pstAsdus->usSQ) + { + pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + usContinue = 0; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + } + else + { + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + usContinue = 0; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + } + + if(usContinue == 0) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; /*无后续帧时,不进行追加,其他条件下可以进行参数追加,解决连帧问题*/ + } + else + { + SetSendTask(pstSelf, TSKID_ParamRead_NanWang, usReason, 0); /*继续执行发送任务*/ + } + + pstAsdus->usNum = ucTxNum; /*VSQ赋值*/ + return pstAsdus->usPayloadSize; + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 读参数传输命令发送处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamRdResponse_NanWang(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucTxNum = 0;/*本次发送个数*/ + unsigned short usContinue = 0; + unsigned short usTotalNum = 0;/*缓冲数据个数*/ + unsigned short usReason = (unsigned short)uiParam; + unsigned char ucQpm = (unsigned char)(uiParam >> 16); + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = P_ME_NC; + pstAsdus->usSQ = 1; + pstAsdus->usCot = usReason; + + if(NULL == pstSelf->pfnGetParamCount) + { + return 0; + } + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_INTROGEN == usReason && ucQpm == 0x06) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); //获取总数量 + pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen - 1) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + ucTxNum++; + usContinue = 0; + } + else + { + usContinue = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = ucQpm; /*PI参数特征表示为1:有后续*/ + } + + if(usContinue == 0) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; /*无后续帧时,不进行追加,其他条件下可以进行参数追加,解决连帧问题*/ + SetSendTask(pstSelf, TSKID_ParamRead_NanWang, COT_ACTTERM, 0x14); + } + else + { + SetSendTask(pstSelf, TSKID_ParamReadResponse_NanWang, usReason, ucQpm); /*继续执行发送任务*/ + } + + pstAsdus->usNum = ucTxNum; /*VSQ赋值*/ + return pstAsdus->usPayloadSize; +} + +/** +* @brief 南网参数预置命令接收处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam-传输原因 +* @return ASDU数据长度 +*/ +void Do_ParamPreset_NanWang(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucRet = 0; + unsigned char ucQpm = 0; + unsigned short usi = 0; + unsigned short usLen = 0; + unsigned int uiInfoAddr = 0; + unsigned char *pucMsgBuf = &pstSelf->ucDataBackBuf[0]; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + IECPARAM_T stIecParam = {0}; + ucQpm = pstAsdus->pucPayload[pstSelf->stAsduElem.usPayloadSize - 1]; + + if((COT_ACT == usReason || COT_DEACT == usReason) && ucQpm == 0x09) //从站收 + { + if(COT_ACT == usReason) + { + pstSelf->ucPmPresetFlag = 1; + pstSelf->uiPmPresetTimeout = 180000; + } + else if(COT_DEACT == usReason) + { + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + pstSelf->ucParamFlag = 0; + } + + if(pstAsdus->usNum == 0) + { + return; + } + + /*首次预置时,清除发送序号*/ + if(pstSelf->ucParamFlag == 0) + { + pstSelf->usParamSendNum = 0; + } + + stIecParam.ucType = TAG_TPYE_FLOAT; + stIecParam.ucLen = 4; + + if(pstAsdus->usSQ) + { + pstSelf ->ucPmPresetVsqFlag = 1; + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + stIecParam.uiInfoAddr = uiInfoAddr; + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + + if(NULL != pstSelf->pfnAddIECParam) + { + ucRet = pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMWT, &stIecParam, pstSelf->pUsrData); + + if(ucRet == 0) + { + break; + } + } + + uiInfoAddr++; + pstSelf->ucParamFlag = 1; + } + } + else + { + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + + if(NULL != pstSelf->pfnAddIECParam) + { + ucRet = pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMWT, &stIecParam, pstSelf->pUsrData); + + if(ucRet == 0) + { + break; + } + } + + pstSelf->ucParamFlag = 1; + } + } + + if(ucRet == 1) + { + if(COT_ACT == usReason) + { + SetSendTask(pstSelf, TSKID_ParamPreset_NanWang, COT_ACTCON, ucQpm); + } + else if(COT_DEACT == usReason) + { + SetSendTask(pstSelf, TSKID_ParamPreset_NanWang, COT_DEACTCON, ucQpm); + } + } + else + { + if(COT_ACT == usReason) + { + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + } + + pstSelf->ucBackLen = pstSelf->stAsduElem.usPayloadSize; + memcpy(pucMsgBuf, &pstAsdus->pucPayload[0], pstSelf->stAsduElem.usPayloadSize); + SetSendTask(pstSelf, TSKID_ParamPreset_NanWang, COT_PN | COT_ACTCON, ucQpm); + } + } +} + + +/** +* @brief 南网参数预置命令/读参数上传发送处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamPreset_NanWang(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned char ucCont = 0; + unsigned char ucTxNum = 0; + unsigned short usTotalNum = 0; + unsigned short usi = 0; + unsigned short usReason = (unsigned short)uiParam; + unsigned short usQpm = (unsigned short)(uiParam >> 16); /*参数*/ + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = P_ME_NC; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; + + if(pstSelf ->ucPmPresetVsqFlag == 1) + { + pstSelf ->ucPmPresetVsqFlag = 0; + pstAsdus->usSQ = 1; + } + else + { + pstAsdus->usSQ = 0; + } + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_ACTCON == usReason || COT_DEACTCON == usReason || COT_SPONT == usReason) //回复主站参数预置数据 + { + if(usQpm == 0x09) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + if(pstAsdus->usSQ) + { + pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(4 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen - 1) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + else + { + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 4 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen - 1) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + } + else if(COT_SPONT == usReason && usQpm == 0x06) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 4 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen - 1) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + + /*缓存中无数据,不进行后续发送*/ + if(ucCont) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, usQpm); + } + + /*主方向无后续帧且发送完成时,清除pstSelf->ucParamFlag == 0 &&*/ + if((ucCont == 0 || pstSelf->usParamSendNum == usTotalNum)) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; + } + + pstAsdus->usNum = ucTxNum; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQpm; + } + else if((COT_PN | COT_ACTCON) == usReason) + { + if(pstAsdus->usSQ) + { + pstAsdus->usNum = (pstSelf->ucBackLen - pstSelf->stAppParameters.iSzOfIOA - 1) / 4; + } + else + { + pstAsdus->usNum = (pstSelf->ucBackLen - 1) / (pstSelf->stAppParameters.iSzOfIOA + 4); + } + + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], &pstSelf->ucDataBackBuf[0], pstSelf->ucBackLen); + pstAsdus->usPayloadSize += pstSelf->ucBackLen; + pstSelf->ucParamFlag = 0; + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 南网参数固化命令接收处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam-传输原因 +* @return ASDU数据长度 +*/ +void DoParamSolidify_NanWang(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucQpa = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + ucQpa = pstAsdus->pucPayload[pstSelf->stAsduElem.usPayloadSize - 1]; + + if(COT_ACT == usReason && ucQpa == 0x01) //从站收 + { + pstSelf->ucParamFlag = 0; /*重置首次添加标识*/ + unsigned char ucFlag = 0; + + /*预置后才允许固化*/ + if(pstSelf->ucPmPresetFlag && pstSelf->pfnRunWriteIECParam) + { + ucFlag = pstSelf->pfnRunWriteIECParam(pstSelf->pUsrData); + } + + if(ucFlag) + { + SetSendTask(pstSelf, TSKID_ParamSolidify_NanWang, COT_ACTCON, 0x01); /*固化成功*/ + } + else + { + SetSendTask(pstSelf, TSKID_ParamSolidify_NanWang, COT_PN | COT_ACTCON, 0x01); /*固化失败,终止命令*/ + } + + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + } +} + +/** +* @brief 南网参数固化命令发送处理函数 +* +* @param[in] pstSelf -规约实体指针 +* @param[in] uiParam-传输原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamSolidify_NanWang(CS10x *pstSelf, unsigned int uiParam) +{ + unsigned short usReason = (unsigned short)uiParam; + unsigned short usQpa = (unsigned short)(uiParam >> 16); + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = P_AC_NA; + pstAsdus->usSQ = 0; + pstAsdus->usNum = 1; + pstAsdus->usCot = usReason; + + if(COT_ACTCON == usReason || (COT_PN | COT_ACTCON) == usReason) //回复主站参数预置数据 + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], 0x00, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQpa; + + if(usReason == COT_ACTCON) + { + SetSendTask(pstSelf, TSKID_ParamPreset_NanWang, COT_SPONT, 0x06); + } + } + + return pstAsdus->usPayloadSize; +} + +/** +* @brief 参数定值写接口接收处理接口(参数预置、固化、取消) +* +* @param[in] pstSelf 规约实体 +* @param[in] usReason 传送原因 +*/ +void Do_ParamWrite_Nanwang(CS10x *pstSelf, unsigned short usReason) +{ + unsigned char ucQos = 0; + unsigned short usi = 0; + unsigned short usLen = 0; + unsigned int uiInfoAddr = 0; + unsigned char ucFlag = 0; + unsigned short usTotalNum = 0; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + IECPARAM_T stIecParam = {0}; + + if(pstAsdus->usNum == 0) + { + return; + } + + ucQos = pstAsdus->pucPayload[pstSelf->stAsduElem.usPayloadSize - 1]; + + if(COT_ACT == usReason || COT_DEACT == usReason) //从站收 + { + if((ucQos & PARAM_SE_1) == PARAM_SE_1) //参数预置 + { + if(COT_ACT == usReason) + { + pstSelf->ucPmPresetFlag = 1; + pstSelf->uiPmPresetTimeout = 180000; + } + else if(COT_DEACT == usReason) + { + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + pstSelf->ucParamFlag = 0; + } + + stIecParam.ucType = TAG_TPYE_FLOAT; + stIecParam.ucLen = 4; + + /*首次预置时,清除发送序号*/ + if(pstSelf->ucParamFlag == 0) + { + pstSelf->usParamSendNum = 0; + } + + if(pstAsdus -> usSQ) + { + pstSelf ->ucPmPresetVsqFlag = 1; + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + stIecParam.uiInfoAddr = uiInfoAddr; + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + usLen ++; + + if(NULL != pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMWT, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; + uiInfoAddr++; + } + } + else + { + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + memcpy(stIecParam.unVal.caBuf, &pstAsdus->pucPayload[usLen], stIecParam.ucLen); + usLen += stIecParam.ucLen; + usLen ++; + + if(NULL != pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMWT, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; + } + } + + if(COT_ACT == usReason) + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_ACTCON, PARAM_SE_1); + } + else if(COT_DEACT == usReason) + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_DEACTCON, PARAM_SE_1); + } + } + else + { + stIecParam.ucType = TAG_TPYE_FLOAT; + stIecParam.ucLen = 4; + + if(pstSelf->ucPmPresetFlag) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + if(usTotalNum != pstAsdus->usNum) + { + return; + } + + if(pstAsdus -> usSQ) + { + pstSelf ->ucPmPresetVsqFlag = 1; + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, 0, &stIecParam, pstSelf->pUsrData); + + if(uiInfoAddr != stIecParam.uiInfoAddr) //固化若分多帧发送,只处理最后一帧 + { + return; + } + + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = 0; i < pstAsdus->usNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, i, &stIecParam, pstSelf->pUsrData)) + { + if(memcmp(&pstAsdus->pucPayload[usLen], stIecParam.unVal.caBuf, 4) != 0) + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_PN | COT_ACTCON, 0); + return; + } + + usLen += 4; + usLen ++; + } + } + } + else + { + for(unsigned short i = 0; i < pstAsdus->usNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, i, &stIecParam, pstSelf->pUsrData)) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + + if(uiInfoAddr != stIecParam.uiInfoAddr) + { + return; + } + + usLen += pstSelf->stAppParameters.iSzOfIOA; + + if(memcmp(&pstAsdus->pucPayload[usLen], stIecParam.unVal.caBuf, 4) != 0) + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_PN | COT_ACTCON, 0); + return; + } + + usLen += 4; + usLen ++; + } + } + } + + if(pstSelf->pfnRunWriteIECParam) + { + ucFlag = pstSelf->pfnRunWriteIECParam(pstSelf->pUsrData); + + if(ucFlag) + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_ACTCON, 0); /*固化成功*/ + } + else + { + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_PN | COT_ACTCON, 0); /*固化失败,终止命令*/ + } + } + + pstSelf->uiPmPresetTimeout = 0; + } + else + { + stIecParam.ucType = TAG_TPYE_FLOAT; + stIecParam.ucLen = 4; + + if(pstAsdus -> usSQ) + { + pstSelf ->ucPmPresetVsqFlag = 1; + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + stIecParam.uiInfoAddr = uiInfoAddr; + usLen += stIecParam.ucLen; + usLen ++; + + if(NULL != pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; + uiInfoAddr++; + } + } + else + { + for(usi = 0; usi < pstAsdus->usNum; usi++) + { + uiInfoAddr = ASDU_getIOA(&pstAsdus->pucPayload[usLen], pstSelf->stAppParameters.iSzOfIOA); + usLen += pstSelf->stAppParameters.iSzOfIOA; + stIecParam.uiInfoAddr = uiInfoAddr; + usLen += stIecParam.ucLen; + usLen ++; + + if(NULL != pstSelf->pfnAddIECParam) + { + pstSelf->pfnAddIECParam(0, pstSelf->ucParamFlag, IECPARAMRD, &stIecParam, pstSelf->pUsrData); + } + + pstSelf->ucParamFlag = 1; + } + } + + SetSendTask(pstSelf, TSKID_ParamWrite_NanWang, COT_PN | COT_ACTCON, 0); /*固化失败,终止命令*/ + } + } + } +} + +/** +* @brief 参数定值写接口发送组包处理 +* +* @param[in] pstSelf 规约实体 +* @param[in] uiParam 传送原因 +* @return ASDU数据长度 +*/ +unsigned short CS10x_Send_ParamWrite_Nanwang(CS10x * pstSelf, unsigned int uiParam) +{ + unsigned char ucCont = 0; + unsigned char ucTxNum = 0; + unsigned short usTotalNum = 0; + unsigned short usi = 0; + unsigned short usReason = (unsigned short)uiParam; + unsigned short usQos = (unsigned short)(uiParam >> 16); /*参数*/ + IECPARAM_T stIecParam = {0}; + ASDU_Element *pstAsdus = &pstSelf->stAsduElem; + pstAsdus->usTypeID = C_SP_NA; + + if(pstSelf ->ucPmPresetVsqFlag == 1) + { + pstSelf ->ucPmPresetVsqFlag = 0; + pstAsdus->usSQ = 1; + } + else + { + pstAsdus->usSQ = 0; + } + + pstAsdus->usNum = 0; + pstAsdus->usCot = usReason; + + if(NULL == pstSelf->pfnGetParamInfoByIndx) + { + return 0; + } + + if(COT_ACTCON == usReason || COT_DEACTCON == usReason) //回复主站参数预置数据 + { + if(PARAM_SE_1 == usQos) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + if(pstAsdus->usSQ) + { + pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(5 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + else + { + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMWT, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 5 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + } + else if(PARAM_SE_0 == usQos) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + if(pstAsdus->usSQ) + { + pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, usi, &stIecParam, pstSelf->pUsrData)) + { + if(5 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + else + { + for(usi = pstSelf->usParamSendNum; usi < usTotalNum; usi++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, usi, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + 5 + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, 4); + pstAsdus->usPayloadSize += 4; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; + } + } + } + + /*缓存中无数据,不进行后续发送*/ + if(ucCont) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, usQos); + } + + /*主方向无后续帧且发送完成时,清除*/ + if(ucCont == 0 || (pstSelf->usParamSendNum == usTotalNum)) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; + } + } + else if((COT_PN | COT_ACTCON) == usReason) + { + usTotalNum = pstSelf->pfnGetParamCount(pstSelf->pUsrData); + + if(pstAsdus->usSQ) + { + pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, pstSelf->usParamSendNum, &stIecParam, pstSelf->pUsrData); + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(1 + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + } + else + { + for(unsigned short i = pstSelf->usParamSendNum; i < usTotalNum; i++) + { + if(pstSelf->pfnGetParamInfoByIndx(IECPARAMRD, i, &stIecParam, pstSelf->pUsrData)) + { + if(pstSelf->stAppParameters.iSzOfIOA + stIecParam.ucLen + pstAsdus->usPayloadSize <= pstSelf->stAppParameters.iMaxSzOfAsduLen) + { + ASDU_setIOA(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.uiInfoAddr, pstSelf->stAppParameters.iSzOfIOA); + pstAsdus->usPayloadSize += pstSelf->stAppParameters.iSzOfIOA; + memcpy(&pstAsdus->pucPayload[pstAsdus->usPayloadSize], stIecParam.unVal.caBuf, stIecParam.ucLen);/*复制当前参数值*/ + pstAsdus->usPayloadSize += stIecParam.ucLen; + pstAsdus->pucPayload[pstAsdus->usPayloadSize++] = usQos; + ucTxNum++; + ucCont = 0; + } + else + { + ucCont = 1; + break; + } + } + + pstSelf->usParamSendNum++; /*参数发送个数*/ + } + } + + /*缓存中无数据,不进行后续发送*/ + if(ucCont) + { + SetSendTask(pstSelf, pstSelf->byTaskFlagId, usReason, 0); + } + + /*主方向无后续帧且发送完成时,清除*/ + if(ucCont == 0 || pstSelf->usParamSendNum == usTotalNum) + { + pstSelf->usParamSendNum = 0; + pstSelf->ucParamFlag = 0; + } + } + + pstAsdus->usNum = ucTxNum; + return pstAsdus->usPayloadSize; +} \ No newline at end of file diff --git a/src/protocol/lib60870/src/gb101.c b/src/protocol/lib60870/src/gb101.c new file mode 100644 index 0000000..a061970 --- /dev/null +++ b/src/protocol/lib60870/src/gb101.c @@ -0,0 +1,1158 @@ +/****************************************************************************** + +版权所有 (C), 2013-2023, 科大智能电气有限公司 + +****************************************************************************** +文 件 名 : gb101.c +版 本 号 : V1.0 +生成日期 : 2022年03月23日 +最近修改 : +功能描述 : 101规约实现主体 +函数列表 : +修改历史 : +1.日 期 : 2022年03月23日 +修改内容 : 创建文件 +******************************************************************************/ +/*************************************文件包含*********************************/ +#include "gb101.h" + +/***************************************static函数声明*******************************/ +static void GB101_SendShortX(CS10xHandle_t pstSelf, unsigned char ucPRM, unsigned char ucFC); +static unsigned char GB101_SearchOneFrame(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen, unsigned short *pusFramePos); +static void GB101_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_101Init(CS10xHandle_t pstSelf, CS10x_SendCb pcb, void *arg, CS10x_Type enType) +{ + pstSelf->eCS10x_Type = enType; //主站从站 + pstSelf->pfnSendCb = pcb; + pstSelf->pUsrData = arg; + pstSelf->pfnDecodeProcess = GB101_DecodeProcess; + pstSelf->pfnEncodeFrame = GB101_EncodeFrame; + pstSelf->pfnEncodeOther = GB101_EncodeOther; + pstSelf->pfnTimerManager = GB101_TimerOut; + /*默认初始化参数*/ + 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 = 2; + pstSelf->stAppParameters.iLinkAddr = 1; + pstSelf->stAppParameters.iPublicAddr = 1; + /*总招对时时间*/ + pstSelf->uiSummon_Gap = 300000; /*300秒*/ + pstSelf->uiSyn_Gap = 300000; /*300秒*/ + pstSelf->uiSend_Gap = 100; /*100ms*/ + pstSelf->uiHeart_Gap = 90000; /*90秒*/ + pstSelf->uiESummon_Gap = 60000; /*60秒*/ + /*重发参数*/ + pstSelf->usReSend_Gap = 5000; /*1秒*/ + pstSelf->ucReSend_Num = 5; + pstSelf->bSimpleInit = 1; // 简单初始化 + pstSelf->ucFileAckType = 0; // 文件传输要求确认 + pstSelf->usFaultEnable = 1; //故障事件使能 + pstSelf->ucSenSoeEa = 1; //发送SOE使能 + pstSelf->ucSenCosEa = 1; //发送COS使能 + pstSelf->ucYKEndFrame = 1; //遥控结束帧投入 + pstSelf->ucOffLineSoeReissueEn = 1;//离线SOE补发使能 + pstSelf->ucReadFileVSQ = 0; //读文件数据传输VSQ状态值 + pstSelf->bDir = 1; + pstSelf->ucPreSetContType = 0; /* 默认为正常参数预置流程*/ +#ifdef IEC_DEBUG_MSG + IEC_PRINT("Create IEC101 %s\n", enType == CS101_TYPE_M ? "主站" : "从站"); +#endif + return; +} + +/*************************************内部调用函数*****************************/ +/** +* @brief 101规约数据帧处理 +* @param[in] pstSelf-规约实体指针 +* @param[in] pucBuf-报文数据指针 +* @param[in] usLen-报文长度 +* @param[out] 无 +* @return 规约实体指针 +*/ +char GB101_DecodeProcess(CS10xHandle_t pstSelf, unsigned char *pucBuf, unsigned short usLen) +{ + unsigned short usFramePos = 0;//一条报文中含有多帧101时,表示每帧起始在报文中起始位置 + unsigned short usSearchLen = 0;//本次查找报文的长度(包括错误帧) + + // to do :proc ASDUs 拆分多帧并解析 + do + { + if(GB101_SearchOneFrame(pstSelf, pucBuf + usFramePos, usLen - usFramePos, &usSearchLen)) //查找单帧 + { + break; + } + + GB101_DecodeOneFrame(pstSelf, pstSelf->stPubBuf.pBuf);//解析单帧 + usFramePos += usSearchLen; + } while(usFramePos < usLen); //越界判断 + + return 0; +} + +/** +* @brief 101规约查找单帧 +* @param[in] pstSelf-规约实体指针 +* @param[in] pucFramePt-当前帧报文数据指针 +* @param[in] usLastLen-多帧报文剩余长度 +* @param[out] pusSearchLen-本次查找报文的长度(包括错误帧) +* @return 0 正常查找 1 异常越界 +*/ +static unsigned char GB101_SearchOneFrame(CS10xHandle_t pstSelf, unsigned char *pucFramePt, unsigned short usLastLen, unsigned short *pusSearchLen) +{ + unsigned char ucRet = 0;//返回判断0 正常查找 1 异常越界 + unsigned char ucFlag = 0;//寻找单帧成功标志 0 成功 1 失败 + unsigned char ucSum = 0; //校验码 + unsigned char ucCS_Pos = 0; //长帧校验位下标 + unsigned short usAddr = 0; //链路地址 + unsigned short usSearchLen = 0;//本次查找报文的长度(包括错误帧) + VFrame10_S stFrame10_S = {0};//101短帧格式(单字节地址) + VFrame10 stFrame10 = {0}; //101短帧格式(双字节地址) + VFrame68 stFrame68 = {0}; //101长帧格式 + + do + { + if(pucFramePt[0] == START_CODE_101_SHORT) // 101短帧 短帧起始都一样 + { + if(pstSelf->stAppParameters.iSzOfLinkAddr == 1) + { + if(usSearchLen + SHORT_LEN_S > usLastLen) //越界判断 + { + ucRet = 1; + break; + } + + stFrame10_S.ucControl = pucFramePt[1];//控制域 + stFrame10_S.ucAddr = pucFramePt[2];//地址域 + stFrame10_S.ucCS = pucFramePt[3];//校验和 + stFrame10_S.ucTail = pucFramePt[4];//结束符 + ucSum = checksum_8(&stFrame10_S.ucControl, 2); + + if((stFrame10_S.ucCS == ucSum) && (stFrame10_S.ucTail == TAIL_CODE_101) && ((stFrame10_S.ucAddr == pstSelf->stAppParameters.iLinkAddr) || (stFrame10_S.ucAddr == 255))) + { + memcpy(pstSelf->stPubBuf.pBuf, pucFramePt, SHORT_LEN_S);//拷贝当前帧到公共缓存待解析 + pstSelf->stPubBuf.usWritePtr = SHORT_LEN_S; + usSearchLen += SHORT_LEN_S; + ucFlag = 1; + break;//当前帧格式正确结束遍历,外层解析当前帧 + } + else + { + usSearchLen += 1; + pucFramePt += 1; + + if(usSearchLen + SHORT_LEN > usLastLen) + { + ucRet = 1; + break; + } + } + } + else + { + if(usSearchLen + SHORT_LEN > usLastLen) //越界判断 + { + ucRet = 1; + break; + } + + stFrame10.ucControl = pucFramePt[1];//控制域 + stFrame10.ucAddr_L = pucFramePt[2];//地址域 + stFrame10.ucAddr_H = pucFramePt[3];//地址域 + stFrame10.ucCS = pucFramePt[4];//校验和 + stFrame10.ucTail = pucFramePt[5];//结束符 + ucSum = checksum_8(&stFrame10.ucControl, 3); + usAddr = stFrame10.ucAddr_H; + usAddr = ((usAddr << 8) & 0xff00) + stFrame10.ucAddr_L; + + if((stFrame10.ucCS == ucSum) && (stFrame10.ucTail == TAIL_CODE_101) && ((usAddr == pstSelf->stAppParameters.iLinkAddr) || (usAddr == 65535))) + { + memcpy(pstSelf->stPubBuf.pBuf, pucFramePt, SHORT_LEN);//拷贝当前帧到公共缓存待解析 + pstSelf->stPubBuf.usWritePtr = SHORT_LEN; + usSearchLen += SHORT_LEN; + ucFlag = 1; + break;//当前帧格式正确结束遍历,外层解析当前帧 + } + else + { + usSearchLen += 1; + pucFramePt += 1; + + if(usSearchLen + SHORT_LEN > usLastLen) + { + ucRet = 1; + break; + } + } + } + } + else if(pucFramePt[0] == START_CODE_101_LONG) // 101长帧 + { + stFrame68.ucLength1 = pucFramePt[1]; + stFrame68.ucLength2 = pucFramePt[2]; + stFrame68.ucStart2 = pucFramePt[3]; + stFrame68.ucControl = pucFramePt[4]; + memcpy(stFrame68.ucaData, &pucFramePt[5], stFrame68.ucLength1 - 1 + 2); //不包括控制域,包括校验、结束子符 + + if((stFrame68.ucLength1 == stFrame68.ucLength2) && (stFrame68.ucLength1 <= 249) && (stFrame68.ucStart2 == START_CODE_101_LONG)) + { + if(usSearchLen + stFrame68.ucLength1 + HEAD_TAIL_LEN > usLastLen) //越界判断 + { + ucRet = 1; + break; + } + + if(pstSelf->stAppParameters.iSzOfLinkAddr == 1) + { + ucSum = checksum_8(&stFrame68.ucControl, stFrame68.ucLength1); + ucCS_Pos = stFrame68.ucLength1 - 1; + + if((stFrame68.ucaData[ucCS_Pos] == ucSum) && (stFrame68.ucaData[ucCS_Pos + 1] == TAIL_CODE_101) && ((stFrame68.ucaData[0] == pstSelf->stAppParameters.iLinkAddr) || (stFrame68.ucaData[0] == 255))) + { + pstSelf->stPubBuf.usWritePtr = stFrame68.ucLength1 + HEAD_TAIL_LEN; + memcpy(pstSelf->stPubBuf.pBuf, pucFramePt, pstSelf->stPubBuf.usWritePtr);//拷贝当前帧到公共缓存待解析 + usSearchLen += pstSelf->stPubBuf.usWritePtr; + ucFlag = 1; + break;//当前帧格式正确结束遍历,外层解析当前帧 + } + else + { + usSearchLen += 1; + pucFramePt += 1; + } + } + else + { + ucSum = checksum_8(&stFrame68.ucControl, stFrame68.ucLength1); + usAddr = stFrame68.ucaData[1]; + usAddr = ((usAddr << 8) & 0xff00) + stFrame68.ucaData[0]; + ucCS_Pos = stFrame68.ucLength1 - 1; + + if((stFrame68.ucaData[ucCS_Pos] == ucSum) && (stFrame68.ucaData[ucCS_Pos + 1] == TAIL_CODE_101) && ((usAddr == pstSelf->stAppParameters.iLinkAddr) || (usAddr == 65535))) + { + pstSelf->stPubBuf.usWritePtr = stFrame68.ucLength1 + HEAD_TAIL_LEN; + memcpy(pstSelf->stPubBuf.pBuf, pucFramePt, pstSelf->stPubBuf.usWritePtr);//拷贝当前帧到公共缓存待解析 + usSearchLen += pstSelf->stPubBuf.usWritePtr; + ucFlag = 1; + break;//当前帧格式正确结束遍历,外层解析当前帧 + } + else + { + usSearchLen += 1; + pucFramePt += 1; + } + } + } + else + { + usSearchLen += 1; + pucFramePt += 1; + } + } + else + { + usSearchLen += 1; + pucFramePt += 1; + } + } while(usSearchLen < usLastLen); //越界判断 + + if(ucFlag != 1) + { + ucRet = 1; + } + + *pusSearchLen = usSearchLen;//参数返回本次查找长度 + return ucRet; +} + +/** +* @brief 101规约解析单帧 +* @param[in] pstSelf-规约实体指针 +* @param[in] pucBuf-报文数据指针 +* @param[out] 无 +* @return 无 +*/ +static void GB101_DecodeOneFrame(CS10xHandle_t pstSelf, unsigned char *pucBuf) +{ + if(pucBuf[0] == START_CODE_101_SHORT) // 101短帧 + { + GB101_ShortFrame(pstSelf, pucBuf); + } + else if(pucBuf[0] == START_CODE_101_LONG) // 101长帧 + { + GB101_LongFrame(pstSelf, pucBuf); + } +} + +/** +* @brief 101规约收到的长帧解析处理接口函数 +* @param[in] pstSelf-规约实体指针 +pucFrameStart-当前帧首指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_LongFrame(CS10xHandle_t pstSelf, unsigned char *pucFrameStart) +{ + unsigned char ucLen = 0; //控制域加地址域的长度 + VIec101Frame *pstRcvFrame = (VIec101Frame *)pucFrameStart; + + if(pstSelf->stAppParameters.iSzOfLinkAddr > 2) + { + return; + } + + /* 长帧直接认为初始化完成,保证现场数据正常上送 + * 目前南瑞等主站会存在初始化过程发送总招或者对 + * 时等相关数据,可能导致流程不正常 */ + pstSelf->ucInitStatus = 1; + ucLen += pstSelf->stAppParameters.iSzOfLinkAddr; + ucLen++; + //切换到ASDU域起始指针 + pucFrameStart += ucLen + HEAD_LEN; /*规约头报文长度*/ + //长帧也认为是数据确认 + DoAckFrame(pstSelf); + pstSelf->usResend_Ncn = 0; + pstSelf->uiResend_Tcn = 0; + pstSelf->uiHeart_Tcn = 0; + SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0); // 101规约长帧都要回复确认帧 + /*处理ASDU元素*/ + DecodeAsduMember(pstSelf, pucFrameStart, pstRcvFrame->stFrame68.ucLength1 - ucLen); + /*处理ASDU信息体*/ + DecodeAsduInfoObj(pstSelf); + return; +} + +/** +* @brief 101规约短帧解析处理接口函数 +* @param[in] pstSelf-规约实体指针 +pucFrameStart-当前帧首指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_ShortFrame(CS10xHandle_t pstSelf, unsigned char *pucFrameStart) +{ + CONTROL101 unControl;//控制域联合体 + VIec101Frame *pstRcvFrame = (VIec101Frame *)pucFrameStart; + pstSelf->uiHeart_Tcn = 0; + unControl.control = pstRcvFrame->stFrame10.ucControl; + + switch(unControl.bits_down.FC) //根据功能码判断 + { + case RESET_LINK: //收到复位链路帧 及确认帧 两个功能码一样需要从PRM位进行区分 + if(unControl.bits_down.PRM == PRM_MASTER) //启动站发来的帧是复位链路帧 + { + pstSelf->ucRxLinkResetFlag = 1; + pstSelf->ucSelf_FCB = 0; // 收到复位链路帧后FCB位清0 + } + else //从动站发来的是确认帧 + { + pstSelf->ucRxAckFlag = 1; + pstSelf->usResend_Ncn = 0; + pstSelf->uiResend_Tcn = 0; + // CheckUpdate_DiturbYcEvent(pstSelf); + // CheckUpdate_SoeEvent(pstSelf); //更新SOE及故障事件已发送指针 + DoAckFrame(pstSelf); + + if(pstSelf->pfnAckFrameNotification) + { + pstSelf->pfnAckFrameNotification(); + } + } + + break; + + case TEST_LINK: + + /*初始化链路完成才可以相应测试帧*/ + if(pstSelf->ucInitStatus == 1) + { + SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0); //发送确认帧 + } + + break; + + case NONE_DATA: + break; + + case REQUEST_LINK: //收到请求链路帧 + pstSelf->ucRxLinkRequestFlag = 1; + pstSelf->ucInitStatus = 0; + break; + + case LINKSTATUS: //收到链路状态帧 + pstSelf->ucRxLinkStatusFlag = 1; + break; + + default: + break; + } + + return; +} + +/** +* @brief 101规约组建ASDU域接口函数 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 0-成功 -1-失败 +*/ +char GB101_EncodeFrame(CS10xHandle_t pstSelf) +{ +#define MAX_FILE_NONE_ACK_SIEZ 32 /* 最大不带确认帧个数 按照100ms一帧, 32帧相当于3200ms 和主站正反向隔离时间相当 */ + pstSelf->stSendBuf.usReadPtr = 0; + pstSelf->stSendBuf.usWritePtr = 0; + VIec101Frame * pstFrame = (VIec101Frame *)pstSelf->stSendBuf.pBuf; + pstSelf->stSendBuf.usWritePtr += GB101_EncodeFrameHead(pstSelf, pstFrame); + pstSelf->stSendBuf.usWritePtr += GB10x_EncodeAsdu(pstSelf, (unsigned char *)pstFrame + pstSelf->stSendBuf.usWritePtr); + GB101_EncodeFrameTail(pstSelf, pstFrame); + + /* 文件传输不带确认帧时,且无确认不超过最大帧时,可以继续发送后续帧*/ + if((pstSelf->ucFileAckType == 1 && pstSelf->ucFileTransFrame == 1 && + pstSelf->usFileNoneAckNum < MAX_FILE_NONE_ACK_SIEZ)) + { + pstSelf->ucFileTransFrame = 0; + } + else + { + pstSelf->uiResend_Tcn = pstSelf->usReSend_Gap; // 重发超时计数赋值 + } + + return 0; +} + +/** +* @brief 101规约组建短帧域接口函数 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 0-成功 -1-失败 +*/ +char GB101_EncodeOther(CS10xHandle_t pstSelf) +{ + switch(pstSelf->byTaskFlagId) + { + case TSKID_Ack: //应答帧 + GB101_SendAck(pstSelf); + break; + + case TSKID_ResetLink: //发送复位链路 + GB101_SendResetLink(pstSelf); + break; + + case TSKID_RequestLink://发送请求链路状态 + GB101_SendRequestLink(pstSelf); + break; + + case TSKID_MResponse: //响应请求链路状态 + GB101_SendLinkStatus(pstSelf); + break; + + case TSKID_HeartBeat: //短帧心跳帧 + GB101_SendTestLink(pstSelf); + break; + } + + return 0; +} + +/** +* @brief 101规约定时处理函数 +* @param[in] pstSelf-规约实体指针 +* @param[in] usGap-间隔时间ms +* @param[out] 无 +* @return 无 +*/ +void GB101_TimerOut(CS10xHandle_t pstSelf, unsigned short usGap) +{ + GB101_Heart(pstSelf, usGap); + GB101_Resend(pstSelf, usGap); + GB101_Link_Init(pstSelf, usGap); + return; +} + +/** +* @brief 101规约长帧重发处理函数 +* @param[in] pstSelf-规约实体指针 +* @param[in] usGap-间隔时间ms +* @param[out] 无 +* @return 无 +*/ +void GB101_Resend(CS10xHandle_t pstSelf, unsigned short usGap) +{ + /* 仅链路正常时需要进行数据重发*/ + if(pstSelf->ucInitStatus == 1 && pstSelf->uiResend_Tcn >= usGap) + { + pstSelf->uiResend_Tcn -= usGap; + + if(pstSelf->uiResend_Tcn < usGap) + { + pstSelf->uiResend_Tcn = 0; + + if(pstSelf->usResend_Ncn < pstSelf->ucReSend_Num) //重发次数未到最大限度 + { + SetSendTask(pstSelf, TSKID_ReSend, TSK_PARM_USACT, 0); + pstSelf->usResend_Ncn++; + pstSelf->uiResend_Tcn = pstSelf->usReSend_Gap; //重发超时计数赋值 + } + else + { + pstSelf->usResend_Ncn = 0; + //重新启动链路 + ClearAllTaskflgs(pstSelf); + } + } + } + else + { + pstSelf->uiResend_Tcn = 0; + } + + return; +} + + +/** +* @brief 101规约心跳帧 非定时,无数据持续时间超时才发送 +* @param[in] pstSelf-规约实体指针 +* @param[in] usGap-间隔时间ms +* @param[out] 无 +* @return 无 +*/ +void GB101_Heart(CS10xHandle_t pstSelf, unsigned short usGap) +{ + if(pstSelf->ucInitStatus && pstSelf->eCS10x_Type == CS101_TYPE_M) //链路初始化完成 + { + pstSelf->uiHeart_Tcn += usGap; + + if(pstSelf->uiHeart_Tcn >= pstSelf->uiHeart_Gap) //到心跳发送时间 + { + pstSelf->uiHeart_Tcn = 0; + SetSendTask(pstSelf, TSKID_HeartBeat, TSK_PARM_USACT, 0); + + if(pstSelf->usReSend_Gap * pstSelf->ucReSend_Num < pstSelf->uiHeart_Gap) //参数保护 重发时间一定小于心跳时间 + { + pstSelf->uiResend_Tcn = pstSelf->usReSend_Gap; //重发超时计数赋值 + pstSelf->ucHeart_Resend_Flag = 1; + } + } + + if(pstSelf->ucHeart_Resend_Flag) + { + //心跳重发处理 + if(pstSelf->uiResend_Tcn >= usGap) //与长帧重发共用标志 + { + pstSelf->uiResend_Tcn -= usGap; + + if(pstSelf->uiResend_Tcn < usGap) + { + pstSelf->uiResend_Tcn = 0; + + if(pstSelf->usResend_Ncn < pstSelf->ucReSend_Num) //重发次数未到最大限度 + { + SetSendTask(pstSelf, TSKID_HeartBeat, TSK_PARM_USACT, 0); + pstSelf->usResend_Ncn++; + pstSelf->uiResend_Tcn = pstSelf->usReSend_Gap; //重发超时计数赋值 + } + else //超过最大次数 + { + pstSelf->usResend_Ncn = 0; + pstSelf->ucHeart_Resend_Flag = 0; + //重新启动链路 + ClearAllTaskflgs(pstSelf); + } + } + } + else //收到确认 + { + pstSelf->uiResend_Tcn = 0; + pstSelf->ucHeart_Resend_Flag = 0; + } + } + } + else + { + pstSelf->uiHeart_Tcn = 0; + pstSelf->ucHeart_Resend_Flag = 0; + } + + return; +} + +/** +* @brief 101规约握手流程接口函数 定时调用 +* @param[in] pstSelf-规约实体指针 +* @param[in] usGap-间隔时间ms +* @param[out] 无 +* @return 无 +*/ +void GB101_Link_Init(CS10xHandle_t pstSelf, unsigned short usGap) +{ + if(pstSelf->ucInitStatus) //链路初始化完成 + { + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + pstSelf->ucRxInitFinishFlag = 0; + pstSelf->ucInitStep = 0; + return; + } + + //间隔时间计数 + if(pstSelf->uiInit_Tcn >= usGap) + { + pstSelf->uiInit_Tcn -= usGap; + } + else + { + pstSelf->uiInit_Tcn = 0; + } + + if(pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站端时主动发送握手帧 + { + //作为主站的握手流程 + switch(pstSelf->ucInitStep) + { + case 0: //发送请求链路 + if(pstSelf->uiInit_Resend_Ncn >= RESENDCNT_MAX) + { + pstSelf->ucInitStep = 0xff; //握手异常 + } + else + { + SetSendTask(pstSelf, TSKID_RequestLink, TSK_PARM_USACT, 0); + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucInitStatus = 0; + pstSelf->uiInit_Tcn = TIMEOUT; + pstSelf->uiInit_Resend_Ncn++; + pstSelf->ucInitStep++; + } + + break; + + case 1: //等待请求链路回复帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxLinkStatusFlag) //收到请求链路响应帧 + { + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucInitStep++; + } + } + else + { + pstSelf->ucInitStep--; + } + + break; + + case 2: //发送复位链路帧 + if(pstSelf->uiInit_Resend_Ncn >= RESENDCNT_MAX) + { + pstSelf->ucInitStep = 0xff; //握手异常 + } + else + { + SetSendTask(pstSelf, TSKID_ResetLink, TSK_PARM_USACT, 0); //发送复位链路帧 + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->uiInit_Tcn = TIMEOUT; + pstSelf->uiInit_Resend_Ncn++; + pstSelf->ucInitStep++; + } + + break; + + case 3: //等待复位链路确认帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxAckFlag) //收到确认帧 + { + pstSelf->ucRxAckFlag = 0; + pstSelf->uiInit_Tcn = WAITTIME_101; + pstSelf->uiInit_Resend_Ncn = 0; + + if(pstSelf->bSimpleInit) //简单初始化 + { + pstSelf->ucInitStep = 6; //直接到初始化完成等待中去 + } + else + { + pstSelf->ucInitStep++; + // pstSelf->ucRxLinkRequestFlag = 0; + } + } + } + else + { + pstSelf->ucInitStep--; + } + + break; + + case 4: //等待从站发出的链路状态请求帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxLinkRequestFlag) //收到从站的链路状态请求帧 + { + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + SetSendTask(pstSelf, TSKID_MResponse, TSK_PARM_USACT, 0); //发送请求链路状态响应帧 + pstSelf->uiInit_Tcn = WAITTIME_101; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucInitStep++; + } + } + else + { + pstSelf->ucInitStep = 0xff; + } + + break; + + case 5: //等待从站发出的复位链路帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxLinkResetFlag) //收到从站的复位链路帧 + { + pstSelf->ucRxLinkResetFlag = 0; + pstSelf->ucRxInitFinishFlag = 0; + SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0); //发送确认帧 + pstSelf->uiInit_Tcn = WAITTIME_101; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucInitStep++; + } + } + else + { + pstSelf->ucInitStep = 0xff; + } + + break; + + case 6: //等待从站发出的初始化完成帧 + if(pstSelf->uiInit_Tcn) + { + // if(pstSelf->ucRxInitFinishFlag) //收到从站的初始化完成报文 + // { + // pstSelf->ucInitStatus = 1; //初始化结束 + // pstSelf->uiInit_Tcn = 0; + // pstSelf->uiInit_Resend_Ncn = 0; + // pstSelf->ucRxLinkStatusFlag = 0; + // pstSelf->ucRxLinkRequestFlag = 0; + // pstSelf->ucRxAckFlag = 0; + // pstSelf->ucRxLinkResetFlag = 0; + // pstSelf->ucRxInitFinishFlag = 0; + // } + } + else + { + pstSelf->ucInitStep = 0xff; + } + + break; + + case 0xff: + default: + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + pstSelf->ucRxInitFinishFlag = 0; + pstSelf->uiReInit_Tcn ++; + + if(pstSelf->uiReInit_Tcn >= REINITTIME) + { + pstSelf->uiReInit_Tcn = 0; + pstSelf->ucInitStep = 0; + } + + break; + } + } + else if(pstSelf->eCS10x_Type == CS101_TYPE_S) + { + //作为从站的握手流程 + if(pstSelf->ucRxLinkRequestFlag) //收到主站的请求链路状态帧 + { + //重新启动链路 + ClearAllTaskflgs(pstSelf); + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + pstSelf->ucInitStatus = 0; + SetSendTask(pstSelf, TSKID_MResponse, TSK_PARM_USACT, 0); //发送请求链路状态响应帧 + pstSelf->uiInit_Tcn = WAITTIME_101; + pstSelf->ucInitStep = 1; //到等待主站的复位链路帧中去 + } + + switch(pstSelf->ucInitStep) + { + case 0: //等待主站发送请求链路状态帧 一直等待,无超时计数 + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + break; + + case 1: //等待主站发送复位链路帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxLinkResetFlag) //收到主站的复位链路帧 + { + pstSelf->ucRxLinkResetFlag = 0; + SetSendTask(pstSelf, TSKID_Ack, TSK_PARM_USACT, 0); //发送确认帧 + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->uiInit_Tcn = 0; + + if(pstSelf->bSimpleInit) //简单初始化直接发送初始化完成帧 + { + pstSelf->ucInitStep = 6; + SetSendTask(pstSelf, TSKID_InitFinish, COT_INIT, 0); // ASDU中未实现初始化完成功能,参数3暂时不用 + pstSelf->ucRxAckFlag = 0; + } + else + { + pstSelf->uiInit_Tcn = TIMEOUT; + pstSelf->ucInitStep++; + } + } + } + else + { + pstSelf->ucInitStep = 0xff; + } + + break; + + case 2: //从站向主站发送请求链路状态帧 + if(pstSelf->uiInit_Resend_Ncn >= RESENDCNT_MAX) + { + pstSelf->ucInitStep = 0xff; //握手异常 + } + else + { + SetSendTask(pstSelf, TSKID_RequestLink, TSK_PARM_USACT, 0); + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->uiInit_Tcn = TIMEOUT; + pstSelf->uiInit_Resend_Ncn++; + pstSelf->ucInitStep++; + } + + break; + + case 3: //等待主站的链路状态回复帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxLinkStatusFlag) //收到主站的请求链路响应帧 + { + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucInitStep++; + } + } + else + { + pstSelf->ucInitStep--; + } + + break; + + case 4: //从站向主站发送复位链路帧 + if(pstSelf->uiInit_Resend_Ncn >= RESENDCNT_MAX) + { + pstSelf->ucInitStep = 0xff; //握手异常 + } + else + { + SetSendTask(pstSelf, TSKID_ResetLink, TSK_PARM_USACT, 0); //发送复位链路帧 + pstSelf->ucRxAckFlag = 0; + pstSelf->uiInit_Tcn = TIMEOUT; + pstSelf->uiInit_Resend_Ncn++; + pstSelf->ucInitStep++; + } + + break; + + case 5: //等待确认帧 + if(pstSelf->uiInit_Tcn) + { + if(pstSelf->ucRxAckFlag) //收到确认帧 + { + pstSelf->ucRxAckFlag = 0; + pstSelf->bContinueSendFlag = true; + SetSendTask(pstSelf, TSKID_InitFinish, COT_INIT, 0); // ASDU中未实现初始化完成功能,参数3暂时不用 + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucInitStep++; + } + } + else + { + pstSelf->ucInitStep--; + } + + break; + + case 6: + if(pstSelf->ucRxAckFlag) //收到确认帧 + { + pstSelf->ucInitStatus = 1; //初始化结束 + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + // pstSelf->ucRxInitFinishFlag = 0; + } + + break; + + case 0xff: + default: + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + // pstSelf->ucRxInitFinishFlag = 0; + break; + } + } + + return; +} + +/** +* @brief 101规约ASDU域确认前处理函数 仅针对长帧 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +unsigned short GB101_EncodeFrameHead(CS10xHandle_t pstSelf, VIec101Frame * pstFrame) +{ + unsigned short usLen = 0; + pstFrame->stFrame68.ucStart1 = START_CODE_101_LONG; + pstFrame->stFrame68.ucStart2 = START_CODE_101_LONG; + pstFrame->stFrame68.ucControl = GB101_Control(pstSelf, PRM_MASTER, FCVON, DATA_SEND); //长帧发送都是作为启动站 + + if(pstSelf->stAppParameters.iSzOfLinkAddr == 1) //链路地址一个字节 + { + pstFrame->stFrame68.ucaData[0] = pstSelf->stAppParameters.iLinkAddr & 0xff; + usLen = HEAD_LEN_101 - 1; + } + else // 2 + { + pstFrame->stFrame68.ucaData[0] = pstSelf->stAppParameters.iLinkAddr & 0xff; + pstFrame->stFrame68.ucaData[1] = (pstSelf->stAppParameters.iLinkAddr >> 8) & 0xff; + usLen = HEAD_LEN_101; + } + + return usLen; +} + +/** +* @brief 101规约ASDU域确认后处理函数 仅针对101长帧 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_EncodeFrameTail(CS10xHandle_t pstSelf, VIec101Frame *pstFrame) +{ + unsigned char ucCheckSum = 0; //校验和 + pstFrame->stFrame68.ucLength1 = pstSelf->stSendBuf.usWritePtr - 4; + pstFrame->stFrame68.ucLength2 = pstSelf->stSendBuf.usWritePtr - 4; + ucCheckSum = checksum_8(&pstFrame->stFrame68.ucControl, pstSelf->stSendBuf.usWritePtr - 4); + pstFrame->stFrame68.ucaData[pstSelf->stSendBuf.usWritePtr - 5] = ucCheckSum; + pstFrame->stFrame68.ucaData[pstSelf->stSendBuf.usWritePtr - 4] = TAIL_CODE_101; + pstSelf->stSendBuf.usWritePtr += 2; + return; +} + +/** +* @brief 101确认帧组帧 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_SendAck(CS10xHandle_t pstSelf) +{ + GB101_SendShortX(pstSelf, PRM_SLAVE, ACK_LINK); + return; +} + +/** +* @brief 101响应请求链路状态帧回复 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_SendLinkStatus(CS10xHandle_t pstSelf) +{ + GB101_SendShortX(pstSelf, PRM_SLAVE, LINKSTATUS); + return; +} + +/** +* @brief 101发送复位链路 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_SendResetLink(CS10xHandle_t pstSelf) +{ + GB101_SendShortX(pstSelf, PRM_MASTER, RESET_LINK); + return; +} + +/** +* @brief 101发送请求链路 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_SendRequestLink(CS10xHandle_t pstSelf) +{ + GB101_SendShortX(pstSelf, PRM_MASTER, REQUEST_LINK); + return; +} + +/** +* @brief 101发送测试链路 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void GB101_SendTestLink(CS10xHandle_t pstSelf) +{ + GB101_SendShortX(pstSelf, PRM_MASTER, TEST_LINK); + return; +} + +/** +* @brief 101短帧复用接口 +* @param[in] pstSelf-规约实体指针 +* @param[in] ucPRM-启动站 从动站 +* @param[in] ucFC-功能码 +* @return 无 +*/ +static void GB101_SendShortX(CS10xHandle_t pstSelf, unsigned char ucPRM, unsigned char ucFC) +{ + VIec101Frame *pstSendFrame = NULL; + pstSelf->stSendBuf.usWritePtr = 0; + memset(pstSelf->stSendBuf.pBuf, 0, pstSelf->stSendBuf.usBufSize); + pstSendFrame = (VIec101Frame *)pstSelf->stSendBuf.pBuf; + pstSendFrame->stFrame10.ucStart = START_CODE_101_SHORT; + pstSendFrame->stFrame10.ucControl = GB101_Control(pstSelf, ucPRM, FCVOFF, ucFC); + + if(pstSelf->stAppParameters.iSzOfLinkAddr == 1) //链路地址一个字节 + { + pstSendFrame->stFrame10_S.ucAddr = pstSelf->stAppParameters.iLinkAddr & 0xff; + pstSendFrame->stFrame10_S.ucCS = checksum_8(&pstSendFrame->stFrame10.ucControl, 2); + pstSendFrame->stFrame10_S.ucTail = TAIL_CODE_101; + pstSelf->stSendBuf.usWritePtr = SHORT_LEN_S; + } + else // 2 + { + pstSendFrame->stFrame10.ucAddr_L = pstSelf->stAppParameters.iLinkAddr & 0xff; + pstSendFrame->stFrame10.ucAddr_H = (pstSelf->stAppParameters.iLinkAddr >> 8) & 0xff; + pstSendFrame->stFrame10.ucCS = checksum_8(&pstSendFrame->stFrame10.ucControl, 3); + pstSendFrame->stFrame10.ucTail = TAIL_CODE_101; + pstSelf->stSendBuf.usWritePtr = SHORT_LEN; + } + + return; +} + +/** +* @brief 101规约控制域赋值函数 +* @param[in] pstSelf-规约实体指针 +* @param[in] ucPRM-启动站 从动站 +* @param[in] ucFCV-表征FCB是否有效 +* @param[in] ucFC-功能码 +* @param[out] 无 +* @return 无 +*/ +unsigned char GB101_Control(CS10xHandle_t pstSelf, unsigned char ucPRM, unsigned char ucFCV, unsigned char ucFC) +{ + CONTROL101 unControl_101; + memset(&unControl_101, 0, sizeof(CONTROL101)); + + if(pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站时 + { + unControl_101.bits_down.DIR = pstSelf->bDir; + unControl_101.bits_down.PRM = ucPRM; + unControl_101.bits_down.FCV = ucFCV; + unControl_101.bits_down.FC = ucFC; + + if(ucFCV) // FCB有效 FCV为0的时候,不翻转也不清0 + { + // FCB位翻转 + if(pstSelf->ucSelf_FCB) + { + unControl_101.bits_down.FCB = 0; + pstSelf->ucSelf_FCB = 0; // + } + else + { + unControl_101.bits_down.FCB = 1; + pstSelf->ucSelf_FCB = 1; + } + } + + /*else //FCB无效 + { + unControl_101.bits_down.FCB = 0; + //pstSelf->ucSelf_FCB = 0; //无效时清除标志位 + }*/ + } + else //作为从站时 + { + unControl_101.bits_up.DIR = pstSelf->bDir; + unControl_101.bits_up.PRM = ucPRM; + //unControl_101.bits_up.RES = 0; + unControl_101.bits_up.DFC = ucFCV; // DFC暂时未处理 + unControl_101.bits_up.FC = ucFC; + + if(ucFCV) // FCB有效 FCV为0的时候,不翻转也不清0 + { + // FCB位翻转 + if(pstSelf->ucSelf_FCB) + { + unControl_101.bits_up.RES = 0; + pstSelf->ucSelf_FCB = 0; // + } + else + { + unControl_101.bits_up.RES = 1; + pstSelf->ucSelf_FCB = 1; + } + } + } + + return unControl_101.control; +} + diff --git a/src/protocol/lib60870/src/gb103.c b/src/protocol/lib60870/src/gb103.c new file mode 100644 index 0000000..727ac1e --- /dev/null +++ b/src/protocol/lib60870/src/gb103.c @@ -0,0 +1,1085 @@ +#include +#include +#include "lib60870_public.h" +#include "gb103.h" + +#define CS103_BUF_SIZE 512 + +u8 CS103_CmdYK(CS103 *self, u8 *pBuf); +u8 CS103_CmdGetAll(CS103 *self, u8 *pBuf); +u8 CS103_CmdSetTime(CS103 *self, u8 *pBuf); +u8 CS103_CmdFixedData(CS103 *self, u8 *pBuf, u8 ucCode); +BOOL CS103_FixedData(CS103 *self, const u8 *pBuf, u16 usLen); +BOOL CS103_VariableData(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU1(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU5(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU10(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU40(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU41(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU44(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU50(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU60(CS103 *self, const u8 *pBuf, u16 usLen); +void CS103_ASDU10AllValue(CS103 *self, const u8 *pBuf, u32 usLen); + +/** + * @brief 规约使用前初始化 + * @param[in] cb-发送函数指针 + * @param[in] arg-用户数据指针 + * @param[in] type-规约类型 主从 + * @param[out] 无 + * @return 规约实体指针 + */ +CS103 *CS103_Init(CS103_SendCb cb, void *arg, CS103_Type type) +{ + u8 *pchar = NULL; + + CS103 *pcs103 = calloc(1, sizeof(CS103)); + if (NULL == pcs103) + { + return NULL; + } + + pchar = malloc(CS103_BUF_SIZE); + + if (NULL != pchar) + { + pcs103->stRecvBuf.usBufSize = CS103_BUF_SIZE; + pcs103->stRecvBuf.pBuf = pchar; + } + else + { + goto destory; + } + + pchar = malloc(CS103_BUF_SIZE); + + if (NULL != pchar) + { + pcs103->stSendBuf.usBufSize = CS103_BUF_SIZE; + pcs103->stSendBuf.pBuf = pchar; + } + else + { + goto destory; + } + + pcs103->SendCb = cb; + pcs103->pUsrData = arg; + + pcs103->ucAddr = 1; + pcs103->ucReSend_Num = 10; //重发次数 + pcs103->usReSend_Gap = 5000; //重发间隔默认值 + pcs103->ulSummon_Gap = 120000; //总招默认值 + pcs103->ulSyn_Gap = 300000; //对时默认值 + + SetTaskFlag(&pcs103->stTaskFlags, CMD_RESET_NUM); + + return pcs103; + +destory: + + if (pcs103) + { + if (pcs103->stRecvBuf.pBuf) + { + free(pcs103->stRecvBuf.pBuf); + pcs103->stRecvBuf.pBuf = NULL; + } + if (pcs103->stSendBuf.pBuf) + { + free(pcs103->stSendBuf.pBuf); + pcs103->stSendBuf.pBuf = NULL; + } + + free(pcs103); + pcs103 = NULL; + } + + return NULL; +} + +/* + * @brief 规约实体销毁 + * @param[self] 规约实体 + */ +void CS103_Destory(CS103 *self) +{ + if (self) + { + if (self->stRecvBuf.pBuf) + { + free(self->stRecvBuf.pBuf); + } + if (self->stSendBuf.pBuf) + { + free(self->stSendBuf.pBuf); + } + free(self); + } +} + +/** + * @brief 设置设备地址 + * + * @param self + * @param pstParam + */ +void CS103_SetAddr(CS103 *self, u8 ucAddr) +{ + self->ucAddr = ucAddr; +} + +/** + * @brief 设置总召定时间隔关联 + * + * @param self + * @param pstParam + */ +void CS103_SetSummonGap(CS103 *self, u32 ulGap) +{ + self->ulSummon_Gap = ulGap; +} + +/** + * @brief 设置对时同步间隔关联 + * + * @param self + * @param pstParam + */ +void CS103_SetSynTimeGap(CS103 *self, u32 ulGap) +{ + self->ulSyn_Gap = ulGap; +} + +/** + * @brief 101规约重发间隔时间参数输入 + * @param self + * @param pstParam + */ +void CS103_ResendGap(CS103 *self, u16 usGap) +{ + self->usReSend_Gap = usGap; +} +/** + * @brief 101规约重发次数参数输入 + * @param self + * @param pstParam + */ +void CS103_ResendCnt(CS103 *self, u8 ucCnt) +{ + self->ucReSend_Num = ucCnt; +} + +/** + * @brief 获取时间接口 + * + * @param self + * @param cb + */ +void CS103_GetTimeHandler(CS103 *self, CS10x_GetTime cb) +{ + self->GetTime = cb; +} + +/** + * @brief 设置接收遥测接口 + * + * @param self + * @param cb + */ +void CS103_SetValueHandler(CS103 *self, CS103_SetValue cb) +{ + self->SetValue = cb; +} + +/** + * @brief 设置接收遥信接口 + * + * @param self + * @param cb + */ +void CS103_SetStatusHandler(CS103 *self, CS103_SetStatus cb) +{ + self->SetStatus = cb; +} + +/** + * @brief 设置接收SOE处理函数 + * + * @param self + * @param cb + */ +void CS103_AddSOEHandler(CS103 *self, CS103_AddSOE cb) +{ + self->AddSOE = cb; +} + + +void CS103_SetYkTask(CS103 *self, u8 ucFun, u8 ucInf, u8 ucSE, u8 ucACT, u8 ucQU, u8 ucDCS) +{ + if (!self->stIEC103CodeS2C.fcv) + { + return; + } + self->ucYkFun = ucFun; + self->ucYkInf = ucInf; + self->ucYkSE = ucSE; + self->ucYkACT = ucACT; + self->ucYkQU = ucQU; + self->ucYkDCS = ucDCS; + SetTaskFlag(&self->stTaskFlags, CMD_YK); +} + +/** + * @brief 103规约处理函数接口 + * @param self 规约实体 + * @param pBuf 接收缓冲 + * @param usLen 接收数据长度 + */ +BOOL CS103_DoRecv(CS103 *self, u8 *pBuf, u16 usLen) +{ + if (usLen < 5) + { + return FALSE; + } + if (START_10H == pBuf[0]) //固定长度报文(固定五个字节) + { + CS103_FixedData(self, pBuf, usLen); // 处理定长数据 + } + else if (START_68H == pBuf[0]) //可变长报文(最少14个字节) + { + if (!CS103_VariableData(self, pBuf, usLen)) // 处理可变长数据 + { + return FALSE; + } + } + else + { + return FALSE; + } + return TRUE; +} + +/** + * @brief 103规约数据发送 + * @param self 规约实体 + */ +void CS103_SendHandler(CS103 *self) +{ + if(self->ulSend_Gap) + { + return; + } + + if (0 == self->usTaskID) + { + self->stSendBuf.usWritePtr = 0; + self->usResend_Ncn = 0; //重复次数重置 + + if (GetTaskFlag(&self->stTaskFlags, CMD_RESET_CON)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_RESET_CON); + self->usTaskID = CMD_RESET_CON; + + memset(&self->stIEC103CodeS2C, 0, sizeof(IEC103CodeS2C)); //重置FCB FCV + + u8 code = PRA_1 | 0 | 0 | FNA_S2C_RESET_CON; + self->stSendBuf.usWritePtr = CS103_CmdFixedData(self, self->stSendBuf.pBuf, code); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_RESET_NUM)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_RESET_NUM); + self->usTaskID = CMD_RESET_NUM; + + memset(&self->stIEC103CodeS2C, 0, sizeof(IEC103CodeS2C)); //重置FCB FCV + + u8 code = PRA_1 | 0 | 0 | FNA_S2C_RESET_NUM; + self->stSendBuf.usWritePtr = CS103_CmdFixedData(self, self->stSendBuf.pBuf, code); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_YK)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_YK); + self->usTaskID = CMD_YK; + self->stSendBuf.usWritePtr = CS103_CmdYK(self, self->stSendBuf.pBuf); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_RESET_TIMESTAMP)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_RESET_TIMESTAMP); + self->usTaskID = CMD_RESET_TIMESTAMP; + self->stSendBuf.usWritePtr = CS103_CmdSetTime(self, self->stSendBuf.pBuf); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_GET_ALL)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_GET_ALL); + self->usTaskID = CMD_GET_ALL; + self->stSendBuf.usWritePtr = CS103_CmdGetAll(self, self->stSendBuf.pBuf); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV1)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV1); + self->usTaskID = CMD_GET_DATA_LV1; + u8 code = PRA_1 | self->stIEC103CodeS2C.fcb | self->stIEC103CodeS2C.fcv | FNA_S2C_GETDATA_LV1; + self->stSendBuf.usWritePtr = CS103_CmdFixedData(self, self->stSendBuf.pBuf, code); + } + else if (GetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2)) + { + ClearTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2); + self->usTaskID = CMD_GET_DATA_LV2; + u8 code = PRA_1 | self->stIEC103CodeS2C.fcb | self->stIEC103CodeS2C.fcv | FNA_S2C_GETDATA_LV2; + self->stSendBuf.usWritePtr = CS103_CmdFixedData(self, self->stSendBuf.pBuf, code); + } + + } + + if (self->usTaskID) + { + if (self->usResend_Ncn < self->ucReSend_Num) + { + self->usResend_Ncn++; + self->usResend_Tcn = self->usReSend_Gap; + if (self->stSendBuf.usWritePtr) + { + if (self->SendCb) + { + self->SendCb(self->stSendBuf.pBuf, self->stSendBuf.usWritePtr, self->pUsrData); + } + + self->ulSend_Gap = 800; + self->stSendBuf.usWritePtr = 0; + } + + if(CMD_RESET_TIMESTAMP == self->usTaskID) + { + self->usTaskID = 0; + self->usResend_Ncn = 0; // 重复清零 + self->usResend_Tcn = 0; // 重发间隔清零 + + self->ulSend_Gap = 100; + } + } + else + { + //重置链路 + if (CMD_RESET_CON == self->usTaskID || CMD_RESET_NUM == self->usTaskID) + { + SetTaskFlag(&self->stTaskFlags, CMD_RESET_CON); + } + else + { + SetTaskFlag(&self->stTaskFlags, CMD_RESET_NUM); + } + self->usTaskID = 0; // 任务关闭 + self->usResend_Ncn = 0; // 重复清零 + self->usResend_Tcn = 0; // 重发间隔清零 + } + } +} + +/** + * @brief 103规约时间处理函数 + * @param self 规约实体 + * @param usGap 时间间隔 + */ +void CS103_TimerHandle(CS103 *self, u16 usGap) +{ + if (self->usResend_Tcn) + { + if (self->usResend_Tcn < usGap) + { + self->usResend_Tcn = 0; + } + else + { + self->usResend_Tcn -= usGap; + } + } + + if (self->ulSend_Gap) + { + if (self->ulSend_Gap < usGap) + { + self->ulSend_Gap = 0; + } + else + { + self->ulSend_Gap -= usGap; + } + } + + /*重发间隔*/ + if (0 == self->usResend_Tcn) + { + CS103_SendHandler(self); + } + + if (self->stIEC103CodeS2C.fcv) + { + self->ulSummon_Tcn += usGap; + if (self->ulSummon_Tcn > self->ulSummon_Gap) + { + self->ulSummon_Tcn = 0; + // SetTaskFlag(&self->stTaskFlags, CMD_GET_ALL); + } + + self->ulTimeSyn_Tcn += usGap; + if (self->ulTimeSyn_Tcn > self->ulSyn_Gap) + { + self->ulTimeSyn_Tcn = 0; + SetTaskFlag(&self->stTaskFlags, CMD_RESET_TIMESTAMP); + } + } +} + +/** + * @brief 103规约遥控 + * @param self 规约实体 + * @param pBuf 缓冲 + */ +u8 CS103_CmdYK(CS103 *self, u8 *pBuf) +{ + u8 usLen = 4; + pBuf[0] = START_68H; + pBuf[3] = START_68H; + pBuf[usLen++] = PRA_1 | self->stIEC103CodeS2C.fcb | self->stIEC103CodeS2C.fcv | FNA_S2C_POSTDATA_3; + pBuf[usLen++] = self->ucAddr; + pBuf[usLen++] = ASDU60; + pBuf[usLen++] = 0x01; // vsq + pBuf[usLen++] = COT_S2C_REMOTE; //总召唤 + pBuf[usLen++] = self->ucAddr; + pBuf[usLen++] = self->ucYkFun; // FUN + pBuf[usLen++] = self->ucYkFun; + pBuf[usLen++] = (self->ucYkSE << 7) | (self->ucYkACT << 6) | (self->ucYkQU << 2) | (self->ucYkDCS); + pBuf[usLen++] = 0; + pBuf[1] = usLen - 4; + pBuf[2] = usLen - 4; + pBuf[usLen] = checksum_8(&pBuf[4], usLen - 4); + usLen++; + pBuf[usLen++] = END_16H; + return usLen; +} + +/** + * @brief 103规约总召唤 + * @param self 规约实体 + * @param pBuf 缓冲 + */ +u8 CS103_CmdGetAll(CS103 *self, u8 *pBuf) +{ + u8 usLen = 4; + pBuf[0] = START_68H; + pBuf[3] = START_68H; + pBuf[usLen++] = PRA_1 | self->stIEC103CodeS2C.fcb | self->stIEC103CodeS2C.fcv | FNA_S2C_POSTDATA_3; + pBuf[usLen++] = self->ucAddr; + pBuf[usLen++] = ASDU7_GETALL; + pBuf[usLen++] = 0x81; // vsq + pBuf[usLen++] = COT_S2C_GETALL_START; //总召唤 + pBuf[usLen++] = self->ucAddr; + pBuf[usLen++] = FUN_GLB; // FUN + pBuf[usLen++] = 0x00; + pBuf[usLen++] = 4; + pBuf[1] = usLen - 4; + pBuf[2] = usLen - 4; + pBuf[usLen] = checksum_8(&pBuf[4], usLen - 4); + usLen++; + pBuf[usLen++] = END_16H; + return usLen; +} + +/** + * @brief 103规约对时指令 + * @param self 规约实体 + * @param pBuf 缓冲 + */ +u8 CS103_CmdSetTime(CS103 *self, u8 *pBuf) +{ + u8 usLen = 4; + pBuf[0] = START_68H; + pBuf[3] = START_68H; + pBuf[usLen++] = PRA_1 | FNA_S2C_POSTDATA_4; + pBuf[usLen++] = 0xFF; + pBuf[usLen++] = ASDU6_TIMESTAMP; + pBuf[usLen++] = 0x81; // vsq + pBuf[usLen++] = COT_S2C_TIMESTAMP; //时钟同步 + pBuf[usLen++] = 0xFF; + pBuf[usLen++] = FUN_GLB; // FUN + pBuf[usLen++] = 0x00; + + /*获取系统时间*/ + if (NULL != self->GetTime) + { + __CP56Time2a Cp56Time; + memset(&Cp56Time, 0, sizeof(__CP56Time2a)); + self->GetTime(&Cp56Time); + + pBuf[usLen++] = Cp56Time.ucLMs; + pBuf[usLen++] = Cp56Time.ucHMs; + pBuf[usLen++] = Cp56Time.ucMin & 0x3F; + pBuf[usLen++] = Cp56Time.ucHour & 0x1F; + pBuf[usLen++] = Cp56Time.ucWeek & 0x1F; + pBuf[usLen++] = Cp56Time.ucMonth; + pBuf[usLen++] = Cp56Time.ucYear; + } + else + { + usLen += 7; + } + + pBuf[1] = usLen - 4; + pBuf[2] = usLen - 4; + pBuf[usLen] = checksum_8(&pBuf[4], usLen - 4); + usLen++; + pBuf[usLen++] = END_16H; + return usLen; +} + +/** + * @brief 103规约短帧封装 + * @param self 规约实体 + * @param pBuf 缓冲 + * @param ucCode 功能码 + */ +u8 CS103_CmdFixedData(CS103 *self, u8 *pBuf, u8 ucCode) +{ + pBuf[0] = START_10H; + pBuf[1] = ucCode; + pBuf[2] = self->ucAddr; + pBuf[3] = pBuf[1] + pBuf[2]; + pBuf[4] = END_16H; + + return 5; +} + +/* + * @brief: 处理接收到的固定长度报文 + * @Param: pData 解析数据开始地址 + * @Param: dataLen 解析数据长度 + * @Return: 解析成功或失败 + */ +BOOL CS103_FixedData(CS103 *self, const u8 *pBuf, u16 usLen) +{ + self->stIEC103CodeS2C.fcb ^= FCB_1; + self->stIEC103CodeS2C.fcv = FCV_1; + + self->usResend_Tcn = 0; + self->ulSend_Gap = 0; + + //通信复位的确认处理 + if (CMD_RESET_CON == self->usTaskID || CMD_RESET_NUM == self->usTaskID) + { + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV1); + self->usTaskID = 0; + return TRUE; + } + + //判断是否有一级数据上送,有则继续召唤一级数据,没有则召唤二级数据 + if ((pBuf[1] & ACD_1) == ACD_1) + { + if(++self->usFirstNum > 5) + { + self->usFirstNum = 0; + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2); + } + else + { + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV1); + } + } + else + { + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2); + } + + if (CMD_GET_DATA_LV2 == self->usTaskID && (pBuf[1] & 0x0F) == 9) //从站没有所召唤的数据 + { + } + self->usTaskID = 0; + return TRUE; +} + +/* + * @Desc: 处理接收到的可变长度报文 + * @Param: pData 解析数据开始地址 + * @Param: dataLen 解析数据长度 + * @Return: 解析成功或失败 + */ +BOOL CS103_VariableData(CS103 *self, const u8 *pBuf, u16 usLen) +{ + self->stIEC103CodeS2C.fcv = FCV_1; + self->stIEC103CodeS2C.fcb ^= FCB_1; + self->usResend_Tcn = 0; + self->ulSend_Gap = 0; + u8 asduType = pBuf[6]; // asdu类型 + + // if ((CMD_GET_DATA_LV1 == self->usTaskID) && (5 == asduType)) //复位通信或复位帧计数位一级数据召唤 + // { + // if ((pBuf[4] & ACD_1) != ACD_1) + // { + // if (!self->bIsResetConEnd) + // { + // self->bIsResetConEnd = TRUE; //复位通信单元完成 + // SetTaskFlag(self->stTaskFlags, CMD_RESET_NUM); + // self->usTaskID = 0; + // return TRUE; + // } + + // if (!self->bIsResetNumEnd) + // { + // self->bIsResetNumEnd = TRUE; //复位帧计数位完成 + // // self->usTaskID = CMD_GET_ALL; //复位帧计数位 + // SetTaskFlag(self->stTaskFlags, CMD_GET_ALL); + // self->usTaskID = 0; + // return TRUE; + // } + // } + // return TRUE; + // } + + //判断是否有一级数据上送,有则继续召唤一级数据,没有则召唤二级数据 + if ((pBuf[4] & ACD_1) == ACD_1) + { + if(++self->usFirstNum > 5) + { + self->usFirstNum = 0; + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2); + } + else + { + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV1); + } + } + else + { + SetTaskFlag(&self->stTaskFlags, CMD_GET_DATA_LV2); + } + + switch (asduType) + { + case 1: + CS103_ASDU1(self, pBuf, usLen); + break; + case 5: + CS103_ASDU5(self, pBuf, usLen); + // self->ucIDCount++; + // if (self->ucIDCount > 2) + // { + // self->ucIDCount = 0; + // SetTaskFlag(&self->stTaskFlags, CMD_RESET_TIMESTAMP); + // SetTaskFlag(&self->stTaskFlags, CMD_GET_ALL); + // } + break; + case 10: + CS103_ASDU10(self, pBuf, usLen); + break; + case 40: + CS103_ASDU40(self, pBuf, usLen); + break; + case 41: + CS103_ASDU41(self, pBuf, usLen); + break; + case 44: + CS103_ASDU44(self, pBuf, usLen); + break; + case 50: + CS103_ASDU50(self, pBuf, usLen); + break; + case 60: + CS103_ASDU60(self, pBuf, usLen); + break; + default: + break; + } + + self->usTaskID = 0; + return TRUE; +} + +/* + * @Desc: 解析ASDU1遥信变位上送 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU1(CS103 *self, const u8 *pBuf, u16 usLen) +{ + // u8 code = pBuf[CODE_POSI]; + u8 clientAddr = pBuf[ADDR_POSI]; + u8 fun = pBuf[FUN_POSI]; + u8 inf = pBuf[INF_POSI]; + u8 dpi = pBuf[DPI_POSI]; + + dpi -= 1; + + stTime7Byte Time4Byte; + memset(&Time4Byte, 0, sizeof(stTime7Byte)); + memcpy(&Time4Byte, pBuf + ASDU_1_TIMESTAMP, 4); //取四字节时间 + + IEC_PRINT("addr:%d fun:%d inf:%03d dpi:%d %d:%d:%d\n", clientAddr, fun, inf, dpi, Time4Byte.hour, Time4Byte.min, Time4Byte.msec); + + // if(0 == dpi|| 1 == dpi) + // { + // if (self->AddSOE) + // { + // self->AddSOE(fun, inf, dpi, &Time4Byte, self->pUsrData); + // } + // } +} + +/* + * @Desc: 解析ASDU5 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU5(CS103 *self, const u8 *pBuf, u16 usLen) +{ + // u8 code = pBuf[CODE_POSI]; + // u8 clientAddr = pBuf[ADDR_POSI]; + // u8 fun = pBuf[FUN_POSI]; + // u8 inf = pBuf[INF_POSI]; + u8 cot = pBuf[COT_POSI]; + + if(5 == cot) + { + SetTaskFlag(&self->stTaskFlags, CMD_RESET_TIMESTAMP); + // SetTaskFlag(&self->stTaskFlags, CMD_GET_ALL); + } + +} + +/* + * @Desc: 解析通用分类数据响应(读目录,读一个组的描述,读一个组的值) + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU10(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 fun = pBuf[FUN_POSI]; + u8 inf = pBuf[INF_POSI]; + + if ((FUN_GEN == fun) && (0xF0 == inf)) //通用分类数据响应命令(装置响应的读目录) + { + } + else if ((FUN_GEN == fun) && (INF_READ_GROUP == inf)) //通用分类数据响应命令(读一个组的描述或值) + { + CS103_ASDU10AllValue(self, pBuf, usLen); + } + else if ((FUN_GEN == fun) && (INF_READ_EBTRY == inf)) //通用分类数据响应命令(读一个条目的描述或值) + { + CS103_ASDU10AllValue(self, pBuf, usLen); + } + else if ((FUN_GEN == fun) && (INF_CONFIRM_WRITE == inf)) //带确认的写条目响应 + { + CS103_ASDU10AllValue(self, pBuf, usLen); + } + else if ((FUN_GEN == fun) && (INF_EXEC_WRITE == inf)) //带执行的写条目响应 + { + // u8 rii = pBuf[RII_POSI]; + } + + self->usTaskID = 0; + return; +} + +/* + * @Desc: 解析ASDU40上送变位遥信 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU40(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 clientAddr = pBuf[5]; + u8 fun = pBuf[10]; + u8 inf = pBuf[11]; + u8 siq = pBuf[12]; //带品质描述的单点信息字节 + BOOL bValue = FALSE; + + if (siq & 0x80) //无效 + { + return; + } + if (0x01 & siq) + { + bValue = TRUE; // true为合,false为分 + } + + IEC_PRINT("addr:%d fun:%d inf:%03d val:%d\n", clientAddr, fun, inf, bValue); //构造103地址 + + if (self->SetStatus) + { + self->SetStatus(fun, inf, bValue, self->pUsrData); + } +} + +/* + * @Desc: 解析ASDU44上送SOE + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU41(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 clientAddr = pBuf[5]; + u8 fun = pBuf[10]; + u8 inf = pBuf[11]; + u8 siq = pBuf[12]; //带品质描述的单点信息字节 + // u8 ucHour, ucMin; + // u16 usMs; + + stTime7Byte stTime; + + BOOL bValue = FALSE; + + if (siq & 0x80) //无效 + { + return; + } + if (0x01 & siq) + { + bValue = TRUE; // true为合,false为分 + } + + stTime.msec = pBuf[13] + (pBuf[14] << 8); + stTime.min = pBuf[15] & 0x3F; + stTime.hour = pBuf[16] & 0x7F; + + IEC_PRINT("addr:%d fun:%d inf:%03d val:%d\n", clientAddr, fun, inf, bValue); //构造103地址 + + if (self->SetStatus) + { + self->SetStatus(fun, inf, bValue, self->pUsrData); + } + + if (self->AddSOE) + { + self->AddSOE(fun, inf, bValue, &stTime, self->pUsrData); + } +} + +void CS103_ASDU42(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 vsq = pBuf[VSQ_POSI]; + u8 clientAddr = pBuf[ADDR_POSI]; + u8 fun = pBuf[FUN_POSI]; + ; + u8 inf = pBuf[INF_POSI]; + u8 dpiNum = vsq & 0x7F; // 信息元个数 + + for (u8 i = 0; i < dpiNum; ++i) + { + u8 dpi = pBuf[DPI_POSI + i]; //品质描述的双点信息 + + if (!((dpi == 0x01) || (dpi == 0x02))) //当前值无效 dpi为2位数组,值=0/3为无意义,值=1为分,值=2为合 + { + continue; + } + + IEC_PRINT("addr:%d fun:%d inf:%03d dpi:%d\n", clientAddr, fun, inf, dpi); //构造103地址 + } +} + +/* + * @Desc: 解析ASDU44上送全遥信 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU44(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 clientAddr = pBuf[5]; + u8 vsq = pBuf[7]; + u8 fun = pBuf[10]; + u8 inf = pBuf[11]; + u8 scdNum = vsq & 0x7F; // 信息元个数 + BOOL bValue = FALSE; + + for (u8 i = 0; i < scdNum; ++i) + { + //信息元 + u8 pScd = pBuf[12 + i * 5]; + u8 qds = pBuf[16 + i * 5]; //品质描述字节 + if (qds & 0x80) //当前值无效 + { + ++inf; + continue; + } + if (0x01 & pScd) + { + bValue = TRUE; // true为合,false为分 + } + IEC_PRINT("addr:%d fun:%d inf:%03d val:%d\n", clientAddr, fun, inf, bValue); //构造103地址 + + if (self->SetStatus) + { + self->SetStatus(fun, inf, bValue, self->pUsrData); + } + ++inf; + } +} + +/* + * @Desc: 解析ASDU50遥测上送 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU50(CS103 *self, const u8 *pBuf, u16 usLen) +{ + u8 vsq = pBuf[VSQ_POSI]; + u8 clientAddr = pBuf[ADDR_POSI]; + u8 fun = pBuf[FUN_POSI]; + u8 inf = pBuf[INF_POSI]; + u8 scdNum = vsq & 0x7F; // 信息元个数 + s16 sVal = 0; + f32 fVal = 0.0f; + for (u8 i = 0; i < scdNum; ++i) + { + //信息元 + u8 qds = pBuf[12 + i * 2]; + u16 tmpValue = pBuf[12 + i * 2] + (pBuf[13 + i * 2] << 8); + if (qds & 0x02) //当前值无效 + { + ++inf; + continue; + } + + if (tmpValue & 0x8000) //负数 + { + sVal = (tmpValue >> 3) - 1; //减一 + sVal = ~sVal & 0x1fff; //取反取原码 + fVal = (float)(0 - sVal) * 12 / 4095; + } + else + { + if (tmpValue & 0x01) + fVal = (float)((tmpValue >> 3) + 4095) * 12.0 / 4095.0; //溢出 + else + fVal = (float)(tmpValue >> 3) * 12.0 / 4095.0; + } + + // value = (flag?(-tmpValue):tmpValue)*GetRateByPrivateAddr(addr); + IEC_PRINT("addr:%d fun:%d inf:%03d qds:%d val:%f\n", clientAddr, fun, inf, qds, fVal); //构造103地址 + if (self->SetValue) + { + self->SetValue(fun, inf, fVal, self->pUsrData); + } + ++inf; + } +} + +/* + * @Desc: 解析ASDU60遥控功能 + * @param: self 规约实体 + * @Param: pBuf 开始地址 + * @Param: usLen 开始地址 + */ +void CS103_ASDU60(CS103 *self, const u8 *pBuf, u16 usLen) +{ + // u8 vsq = pBuf[VSQ_POSI]; + // u8 clientAddr = pBuf[ADDR_POSI]; + u8 fun = pBuf[FUN_POSI]; + u8 inf = pBuf[INF_POSI]; + // u8 ucCot = pBuf[COT_POSI]; + u8 ucDcc = pBuf[12]; + // u8 ucRII = pBuf[13]; + + u8 ucSE = (ucDcc & 0x80) ? 1:0; + u8 ucAct = (ucDcc & 0x40) ? 1:0; + u8 ucQu = (ucDcc & 0x3C) >> 2; + u8 ucDcs = ucDcc & 0x03; + + /*遥控选择*/ + if(1 == ucSE && 0 == ucAct) + { + /*选择成功执行任务*/ + CS103_SetYkTask(self, fun, inf, 0, 0, ucQu, ucDcs); + } + /*遥控执行*/ + else if(0 == ucSE && 0 == ucAct) + { + + } + /*遥控撤销*/ + else if(1 == ucSE && 1 == ucAct) + { + + } +} +void CS103_ASDU10AllValue(CS103 *self, const u8 *pBuf, u32 usLen) +{ + // u8 code = pBuf[CODE_POSI]; + u8 clientAddr = pBuf[ADDR_POSI]; + u8 ngdNum = pBuf[NGD_POSI] & 0x3F; // 返回的数据个数 + u16 offset = 0; //数据的偏移量 + + for (u8 i = 0; i < ngdNum; ++i) + { + stDataUnit dataUnit; + memcpy(&dataUnit, pBuf + GROUP_POSI + offset, sizeof(stDataUnit)); + + IEC_PRINT("addr:%d group:%d entry:%03d ", clientAddr, dataUnit.groupNo, dataUnit.entryNo); //构造103地址 + + //不是遥信或者遥测数据 + // if (self->ucYcGroupNum != dataUnit.groupNo && self->ucYxGroupNum != dataUnit.groupNo) + // { + // break; + // } + + UnionConvert4Byte convertUnion4Byte; + UnionConvert2Byte convertUnion2Byte; + switch (dataUnit.datatype) + { + case 3: // 2字节无符号整形 + memcpy(convertUnion2Byte.buf, pBuf + GID_POSI + offset, dataUnit.datasize); + IEC_PRINT("%u\n", convertUnion2Byte.uValue); + break; + + case 7: //短实数 + memcpy(convertUnion4Byte.buf, pBuf + GID_POSI + offset, dataUnit.datasize); + IEC_PRINT("%.4f\n", convertUnion4Byte.fValue); + break; + + case 9: //双点描述 dpi=1为分,=2为和 0和3无意义 + if (!(((pBuf + GID_POSI + offset)[0] == 0x01) || ((pBuf + GID_POSI + offset)[0] == 0x02))) + { + break; + } + IEC_PRINT("%d\n", ((pBuf + GID_POSI + offset)[0] - 1) & 0x01); + break; + + case 10: //单点描述 siq=0为分,=1为和 + if (!(((pBuf + GID_POSI + offset)[0] == 0x00) || ((pBuf + GID_POSI + offset)[0] == 0x01))) + { + break; + } + IEC_PRINT("%d\n", (pBuf + GID_POSI + offset)[0] & 0x01); + break; + + case 12: //带品质描述词的被测值 + //信息元 + // u8 qds = valueStr[0]; + // u16 tmpValue = valueStr[0]; + // f32 value = 0.0f; + // if(qds & 0x02) //当前值无效 + // { + // continue; + // } + // + // BOOL flag = (tmpValue & 0x8000) ? TRUE: FALSE; //是否为负数 + // tmpValue = ~tmpValue; + // tmpValue &= 0xfff8; //品质位置0 + // tmpValue &= 0x7ff8; //符号位置0 + // tmpValue >>= 3; + // tmpValue += 1; + // value = (flag?(-tmpValue):tmpValue)*GetRateByPrivateAddr(addr); + // sprintf(tagTemp.pdata, "%.4f", value); + IEC_PRINT("\n"); + break; + default: + IEC_PRINT("\n"); + break; + } + offset = offset + dataUnit.datasize + 6; //通用分类数据单元占6个字节 + } +} diff --git a/src/protocol/lib60870/src/gb104.c b/src/protocol/lib60870/src/gb104.c new file mode 100644 index 0000000..b825f38 --- /dev/null +++ b/src/protocol/lib60870/src/gb104.c @@ -0,0 +1,747 @@ +/****************************************************************************** + +版权所有 (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; +} diff --git a/src/protocol/lib60870/src/lib60870_common.c b/src/protocol/lib60870/src/lib60870_common.c new file mode 100644 index 0000000..a31bc0a --- /dev/null +++ b/src/protocol/lib60870/src/lib60870_common.c @@ -0,0 +1,1634 @@ +/****************************************************************************** + +版权所有 (C), 2013-2023, 科大智能电气有限公司 + +****************************************************************************** +文 件 名 : lib60870_common.c +版 本 号 : V1.0 +生成日期 : 2022年04月07日 +最近修改 : +功能描述 : 101及104规约实现中的公共数据及服务接口模块 +函数列表 : +修改历史 : +1.日 期 : 2022年04月07日 +修改内容 : 创建文件 +*******************************************************************************/ +/*************************************文件包含*********************************/ +#include "lib60870_common.h" +#include "lib60870_public.h" +#include "lib60870_process.h" + +//*************************************外部接口函数*****************************// +const char gs_acIEC60870Ver[32] = "IECVer2.01.069_260612"; +float g_fStationDataSendNum = 0; //主站通信发送数据量 + + + +//*********************************** 规约废弃接口 *************************************// +/** +* @brief 获取时间接口(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetTimeHandler(CS10xHandle_t pstSelf, CS10x_GetTime cb) +{ + pstSelf->pfnGetTime = cb; +} + +/** +* @brief 设置时间接口(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetTimeHandler(CS10xHandle_t pstSelf, CS10x_SetTime cb) +{ + pstSelf->pfnSetTime = cb; +} + +/** +* @brief 设置计量模块遥测接口(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetValueHandler(CS10xHandle_t pstSelf, CS10x_SetValue cb) +{ + pstSelf->pfnSetValue = cb; +} + +/** +* @brief 设置计量模块电度接口(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetDdValueHandler(CS10xHandle_t pstSelf, CS10x_SetDdValue cb) +{ + pstSelf->pfnSetDdValue = cb; +} + +/** +* @brief 遥控操作校验(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_YkVerifyHandler(CS10xHandle_t pstSelf, CS10x_YkVerify cb) +{ + pstSelf->pfnFcYkVerify = cb; +} + +/** +* @brief 设置组遥测数量处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetYcCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcCountByGroup cb) +{ + pstSelf->pfnGetYcCountByGroup = cb; +} + +/** +* @brief 设置组遥测数值处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetYcValueByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcValueByGroup cb) +{ + pstSelf->pfnGetYcValueByGroup = cb; +} + +/** +* @brief 设置组遥信数量处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetYxCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxCountByGroup cb) +{ + pstSelf->pfnGetYxCountByGroup = cb; +} + +/** +* @brief 设置组遥信状态处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetYxStatusByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxStatusByGroup cb) +{ + pstSelf->pfnGetYxStatusByGroup = cb; +} + +/** +* @brief 设置组电度数量处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetDdCountByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdCountByGroup cb) +{ + pstSelf->pfnGetDdCountByGroup = cb; +} + +/** +* @brief 设置组电度数值处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetDdValueByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdValueByGroup cb) +{ + pstSelf->pfnGetDdValueByGroup = cb; +} + +/** +* @brief 设置获取扰动遥测数据处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetDiturbYcHandler(CS10xHandle_t pstSelf, CS10x_GetDiturbYc cb) +{ + pstSelf->pfnGetDiturbYc = cb; +} + +/** +* @brief 设置更新遥测扰动待发数量(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetDiturbYc_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_DiturbYc_SendNum cb) +{ + pstSelf->pfnGetDiturbYc_SendNum = cb; +} + +/** +* @brief 设置更新遥测扰动指针处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Updata_DiturbYc_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_DiturbYc_Pout cb) +{ + pstSelf->pfnUpdata_DiturbYc_Pout = cb; +} + +/** +* @brief 获取参数定值区函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetParamAreaHandler(CS10xHandle_t pstSelf, CS10x_GetParamArea cb)//待删除 +{ + pstSelf->pfnGetParamArea = cb; +} + +/** +* @brief 设置参数定值区函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetParamAreaHandler(CS10xHandle_t pstSelf, CS10x_SetParamArea cb)//待删除 +{ + pstSelf->pfnSetParamArea = cb; +} + +/** +* @brief 增加参数定值函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AddIECParamHandler(CS10xHandle_t pstSelf, CS10x_AddIECParam cb)//待删除 +{ + pstSelf->pfnAddIECParam = cb; +} + +/** +* @brief 读取参数定值函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_RunReadIECParamHandler(CS10xHandle_t pstSelf, CS10x_RunReadIECParam cb)//待删除 +{ + pstSelf->pfnRunReadIECParam = cb; +} + +/** +* @brief 写入参数定值函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_RunWriteIECParamHandler(CS10xHandle_t pstSelf, CS10x_RunWriteIECParam cb)//待删除 +{ + pstSelf->pfnRunWriteIECParam = cb; +} + +/** +* @brief 获取Param数量处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetParamCountHandler(CS10xHandle_t pstSelf, CS10x_GetParamCount cb) +{ + pstSelf->pfnGetParamCount = cb; +} + +/** +* @brief 获取Param信息处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetParamInfoByIndxHandler(CS10xHandle_t pstSelf, CS10x_GetParamInfoByIndx cb) +{ + pstSelf->pfnGetParamInfoByIndx = cb; +} + +/** +* @brief 设置获取soe数据处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetSOEHandler(CS10xHandle_t pstSelf, CS10x_GetSOE cb) +{ + pstSelf->pfnGetSOE = cb; +} + +/** +* @brief 设置更新SOE指针处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Updata_SOE_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_SOE_Pout cb) +{ + pstSelf->pfnUpdata_SOE_Pout = cb; +} + +/** +* @brief 设置更新SOE指针待发数量(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetSOE_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_SOE_SendNum cb) +{ + pstSelf->pfnGetSOE_SendNum = cb; +} + +/** +* @brief 设置更新Event指针待发数量(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetEvent_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GET_Event_SendNum cb) +{ + pstSelf->pfnGetEvent_SendNum = cb; +} + +/** +* @brief 设置获取故障事件数据处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetFaultEventHandler(CS10xHandle_t pstSelf, CS10x_GetFaultEvent cb) +{ + pstSelf->pfnGetFaultEvent = cb; +} + +/** +* @brief 设置更新故障事件处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Updata_FaultEvent_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_FaultEvent_Pout cb) +{ + pstSelf->pfnUpdata_FaultEvent_Pout = cb; +} + +/** +* @brief 获取TimeDdu数据处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetTimeDduHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu cb) +{ + pstSelf->pfnGetTimeDdu = cb; +} + +/** +* @brief 设置更新TimeDdu指针处理函数(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Updata_TimeDdu_PoutHandler(CS10xHandle_t pstSelf, CS10x_Updata_TimeDdu_Pout cb) +{ + pstSelf->pfnUpdata_TimeDdu_Pout = cb; +} + +/** +* @brief 设置更新TimeDdu指针待发数量(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetTimeDdu_SendNumHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu_SendNum cb) +{ + pstSelf->pfnGetTimeDdu_SendNum = cb; +} + +/* +* Prototype : CS10x_S_FileReadOprtHandler +* Description : 读取文件相关操作 +* @param[in] : CS10xHandle_t pstSelf +* @param[in] : CS10x_GetProDirFile cbGetPro +* @param[in] : CS10x_GetNumDirFile cbGetNum +* @param[in] : CS10x_ReadFile cbRead +* @param[in] : void *pvParam +* @param[out] : None +* @Return : +* +* +* +* History : +* 1.Date : 2023/3/7 +* Author : wqw +* Modification : Created function +* +*/ +void CS10x_FileReadOprtHandler(CS10xHandle_t pstSelf, + CS10x_GetProDirFile cbGetPro, + CS10x_GetNumDirFile cbGetNum, + CS10x_ReadFile cbRead, + void *pvParam) //待删除 +{ + pstSelf->pfnGetProDirFile = cbGetPro; + pstSelf->pfnGetNumDirFile = cbGetNum; + pstSelf->pfnReadFile = cbRead; + pstSelf->pvFileReadParam = pvParam; +} + + + +/* +* Prototype : CS10x_S_FileWriteOprtHandler +* Description : 写文件接口 +* @param[in] : CS10xHandle_t pstSelf +* @param[in] : CS10x_Write cbWrite +* @param[in] : CS10x_WriteFileCheck cbCheck +* @param[in] : CS10x_WriteFinish cbFinish +* @param[in] : void *pvParam +* @param[out] : None +* @Return : +* +* +* +* History : +* 1.Date : 2023/3/7 +* Author : wqw +* Modification : Created function +* +*/ +void CS10x_FileWriteOprtHandler(CS10xHandle_t pstSelf, + CS10x_Write cbWrite, + CS10x_WriteFileCheck cbCheck, + CS10x_WriteFinish cbFinish, + void *pvParam)//待删除 +{ + pstSelf->pfnWriteFileCheck = cbCheck; + pstSelf->pfnWrite = cbWrite; + pstSelf->pfnWriteFinish = cbFinish; + pstSelf->pvFileWrteParam = pvParam; +} + +/** +* @brief 升级处理流程(待删除) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_UpdateProcHandler(CS10xHandle_t pstSelf, CS10x_UpdateProc cb) +{ + pstSelf->pfnUpdateProc = cb; +} + +//*********************************************未使用接口******************************// +/** +* @brief 设置遥控类型(未使用) +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYkType(CS10xHandle_t pstSelf, unsigned short usType) +{ + pstSelf->usYkType = usType; + + if(pstSelf->usYkType > YK_TYPE_C_DC) + { + pstSelf->usYkType = YK_TYPE_C_SC; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("遥控类型:%s\n", pstSelf->usYkType == YK_TYPE_C_SC ? "单点" : "双点"); +#endif +} + +/** +* @brief 设置录波完成点号关联(未使用) +* +* @param[out] pstSelf +* @param[in] usAddr +*/ +void CS10x_SetWaveInfoAddr(CS10xHandle_t pstSelf, unsigned short usAddr) +{ + pstSelf->usWaveInfoAddr = usAddr; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("录波关联点号:%d\n", pstSelf->usWaveInfoAddr); +#endif +} + +/** +* @brief 设置搜索目录处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetProDirFileHandler(CS10xHandle_t pstSelf, CS10x_GetProDirFile cb) +{ + pstSelf->pfnGetProDirFile = cb; +} + +/** +* @brief 设置搜索目录处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetNumDirFileHandler(CS10xHandle_t pstSelf, CS10x_GetNumDirFile cb) +{ + pstSelf->pfnGetNumDirFile = cb; +} + +/** +* @brief 设置读取文件处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_ReadFileHandler(CS10xHandle_t pstSelf, CS10x_ReadFile cb) +{ + pstSelf->pfnReadFile = cb; +} + +/** +* @brief 设置写文件处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_WriteFileHandler(CS10xHandle_t pstSelf, CS10x_WriteFile cb) +{ + pstSelf->pfnWriteFile = cb; +} + +/** +* @brief 设置文件名比对文件函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SearchFileNameHandler(CS10xHandle_t pstSelf, CS10x_SearchFileName cb) +{ + pstSelf->pfnSearchFileName = cb; +} + + +/** +* @brief 设置文件名比对文件函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_WriteFileCheckHandler(CS10xHandle_t pstSelf, CS10x_WriteFileCheck cb) +{ + pstSelf->pfnWriteFileCheck = cb; +} + +/** +* @brief 文件写入函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_WriteHandler(CS10xHandle_t pstSelf, CS10x_Write cb) +{ + pstSelf->pfnWrite = cb; +} + +/** +* @brief 文件写完成(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_WriteFinishHandler(CS10xHandle_t pstSelf, CS10x_WriteFinish cb) +{ + pstSelf->pfnWriteFinish = cb; +} + +/** +* @brief 设置链路关闭接口(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_LinkCloseHandler(CS10xHandle_t pstSelf, CS10x_LinkClose cb) +{ + pstSelf->pfnLinkClose = cb; +} + +/** +* @brief 设置向下行设备发送确认帧接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AckFrameNotificationHandler(CS10xHandle_t pstSelf, CS10x_AckFrameNotification cb) +{ + pstSelf->pfnAckFrameNotification = cb; +} + +/** +* @brief 设置接收遥信接口(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetStatusHandler(CS10xHandle_t pstSelf, CS10x_SetStatus cb) +{ + pstSelf->pfnSetStatus = cb; +} + +/** +* @brief 设置接收SOE处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AddSOEHandler(CS10xHandle_t pstSelf, CS10x_AddSOE cb) +{ + pstSelf->pfnAddSOE = cb; +} + +/** +* @brief 设置故障事件处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AddEventHandler(CS10xHandle_t pstSelf, CS10x_AddFauleEvent cb) +{ + pstSelf->pfnAddEvent = cb; +} + +/** +* @brief 设置遥测扰动处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AddDiYcValueHandler(CS10xHandle_t pstSelf, CS10x_AddDiturbYc cb) +{ + pstSelf->pfnAddDiYcVal = cb; +} + +/** +* @brief 设置带时标电度处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_AddTimeDduHandler(CS10xHandle_t pstSelf, CS10x_AddTimeDdu cb) +{ + pstSelf->pfnAddTimeDdu = cb; +} + +/** +* @brief 设置组电度数量处理函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetDdValueHandler(CS10xHandle_t pstSelf, CS10x_GetDdValue cb) +{ + pstSelf->pfnGetDdValue = cb; +} + +/** +* @brief 设置获取遥信点点号属性操作接口(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetYxPotProHandler(CS10xHandle_t pstSelf, CS10x_GetYxPotPro cb) +{ + pstSelf->pfnGetYxPotPro = cb; +} + +/** + * @brief 设置注册文件传输任务函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_RegFileTransHandler(CS10xHandle_t pstSelf, CS10x_RegFileTransObj cb) +{ + pstSelf->pfnRegFileTransObj = cb; +} + +/** + * @brief 设置获取传输文件对象函数(未使用) +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_GetTransFileHandler(CS10xHandle_t pstSelf, CS10x_CheckTransFileObj cb) +{ + pstSelf->pfnCheckTransFileObj = cb; +} + +/** + * @brief 设置检测文件传输超时函数(未使用) + * + * @param self + * @param cb + */ +void CS10x_TransTimeOutHandler(CS10xHandle_t pstSelf, CS10x_CheckTransTimeOut cb) +{ + pstSelf->pfnCheckTransTimeOut = cb; +} + +/** + * @brief 设置目录召唤接收完成处理函数(未使用) + * + * @param self + * @param cb + */ +void CS10x_DirRecvFinishHandler(CS10xHandle_t pstSelf, CS10x_DirRecvFinish cb) +{ + pstSelf->pfnDealDirRecvFinish = cb; +} + +//***************************************内部函数*******************************// + +/** +* @brief GetIEC60870Version +* 获取IEC60870规约版本 +* @return char* +*/ +char *GetIEC60870Version(void) +{ + return (char *)gs_acIEC60870Ver; +} + +/** +* @brief 获取发送数据量 +*/ +float GetStationDataSendNum(void) +{ + return g_fStationDataSendNum; +} + +//*********************************** 规约参数配置函数 *************************************// +/** +* @brief 设置规约参数 +* +* @param[out] pstSelf +* @param[in] pstParam 规约参数 +*/ +void CS10x_SetAppParameters(CS10xHandle_t pstSelf, struct CS10x_AppLayerParameters *pstParam) +{ + memcpy(&pstSelf->stAppParameters, pstParam, sizeof(struct CS10x_AppLayerParameters)); + + if(pstSelf->stAppParameters.iSzOfLinkAddr > 2 || pstSelf->stAppParameters.iSzOfLinkAddr < 1) + { + pstSelf->stAppParameters.iSzOfLinkAddr = 2; + } + + pstSelf->stAppParameters.iSzOfTypeId = 1; + pstSelf->stAppParameters.iSzOfVSQ = 1; + + if(pstSelf->stAppParameters.iSzOfCOT > 2 || pstSelf->stAppParameters.iSzOfCOT < 1) + { + pstSelf->stAppParameters.iSzOfCOT = 2; + } + + if(pstSelf->stAppParameters.iSzOfCA > 2 || pstSelf->stAppParameters.iSzOfCA < 1) + { + pstSelf->stAppParameters.iSzOfCA = 2; + } + + if(pstSelf->stAppParameters.iSzOfIOA > 3 || pstSelf->stAppParameters.iSzOfIOA < 2) + { + pstSelf->stAppParameters.iSzOfIOA = 2; + } + + if(CS101_TYPE_S == pstSelf->eCS10x_Type || CS101_TYPE_M == pstSelf->eCS10x_Type) + { + if(pstSelf->stAppParameters.iMaxSzOfAsduLen > 240) + { + pstSelf->stAppParameters.iMaxSzOfAsduLen = 240; + } + } + else + { + if(pstSelf->stAppParameters.iMaxSzOfAsduLen > 243) + { + pstSelf->stAppParameters.iMaxSzOfAsduLen = 243; + } + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("规约应用参数 链路长度:%d 传输原因长度:%d 公共地址长度:%d 信息体地址长度:%d 故障事件使能:%d\n", pstSelf->stAppParameters.iSzOfLinkAddr, + pstSelf->stAppParameters.iSzOfCOT, pstSelf->stAppParameters.iSzOfCA, pstSelf->stAppParameters.iSzOfIOA, pstSelf->usFaultEnable); +#endif +} + +/** +* @brief 设置104APCI参数 +* +* @param[out] pstSelf +* @param[in] pstParam +*/ +void CS10x_SetAPCIParameters(CS10xHandle_t pstSelf, struct CS104_APCIParameters *pstParam) +{ + memcpy(&pstSelf->stAPCIParameters, pstParam, sizeof(struct CS104_APCIParameters)); + + if(pstSelf->stAPCIParameters.iK < 1 || pstSelf->stAPCIParameters.iK > 1000) // 参数K + { + pstSelf->stAPCIParameters.iK = 12; + } + + if(pstSelf->stAPCIParameters.iW < 1 || pstSelf->stAPCIParameters.iW > 1000) // 参数W 连续接收w帧后 须发送确认帧 + { + pstSelf->stAPCIParameters.iW = 8; + } + + if(pstSelf->stAPCIParameters.iK < pstSelf->stAPCIParameters.iW) // 参数 k > w + { + pstSelf->stAPCIParameters.iK = 12; + pstSelf->stAPCIParameters.iW = 8; + } + + if(pstSelf->stAPCIParameters.iT0 < 2 || pstSelf->stAPCIParameters.iT0 > 200) // 参数T0 主站和子站TCP最大允许连接时间 + { + pstSelf->stAPCIParameters.iT0 = 10; + } + + if(pstSelf->stAPCIParameters.iT1 < 2 || pstSelf->stAPCIParameters.iT1 > 200) // 参数T1 发送方发送I/U帧时,在T1时间内接收确认 + { + pstSelf->stAPCIParameters.iT1 = 12; + } + + if(pstSelf->stAPCIParameters.iT2 < 2 || pstSelf->stAPCIParameters.iT2 > 200) // 参数T2 接收方接收报文后 T2时间内发送确认帧 + { + pstSelf->stAPCIParameters.iT2 = 8; + } + + if(pstSelf->stAPCIParameters.iT3 < 2 || pstSelf->stAPCIParameters.iT3 > 200) // 参数T3 T3时间内未接收到报文 则发送测试帧 + { + pstSelf->stAPCIParameters.iT3 = 15; + } + + if(pstSelf->stAPCIParameters.iT1 < pstSelf->stAPCIParameters.iT2) // 参数 T1>T2 + { + pstSelf->stAPCIParameters.iT1 = 12; + pstSelf->stAPCIParameters.iT2 = 8; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("APCI参数 t0:%d t1:%d t2:%d t3:%d k:%d w:%d\n", pstSelf->stAPCIParameters.iT0, pstSelf->stAPCIParameters.iT1, + pstSelf->stAPCIParameters.iT2, pstSelf->stAPCIParameters.iT3, pstSelf->stAPCIParameters.iK, pstSelf->stAPCIParameters.iW); +#endif +} + +/** +* @brief 设置遥测类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYcType(CS10xHandle_t pstSelf, unsigned short usType) +{ + pstSelf->usYcType = usType; + + if(pstSelf->usYcType > YC_TYPE_ME_NC) + { + pstSelf->usYcType = YC_TYPE_ME_NC; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("遥测类型:%s\n", pstSelf->usYcType == YC_TYPE_ME_NA ? "整形" : pstSelf->usYcType == YC_TYPE_ME_NB ? "归一化" + : "浮点"); +#endif +} + +/** +* @brief 设置遥信类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetYxType(CS10xHandle_t pstSelf, unsigned short usType) +{ + pstSelf->usYxType = usType; + + if(pstSelf->usYxType > YX_TYPE_M_DP) + { + pstSelf->usYxType = YX_TYPE_M_SP; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("遥信类型:%s\n", pstSelf->usYxType == YX_TYPE_M_SP ? "单点" : "双点"); +#endif +} + +/** +* @brief 设置电度类型 +* +* @param[out] pstSelf +* @param[in] usType +*/ +void CS10x_SetDdType(CS10xHandle_t pstSelf, unsigned short usType) +{ + pstSelf->usDdType = usType; + + if(pstSelf->usDdType > DD_TYPE_IT_TC) + { + pstSelf->usDdType = DD_TYPE_IT_NB; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("电度类型:%s\n", pstSelf->usDdType == DD_TYPE_IT_TC ? "带时标" : "不带时标"); +#endif +} + +/** +* @brief 设置总召定时间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetSummonGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->uiSummon_Gap = uiGap; + + if(pstSelf->uiSummon_Gap < 15000) + { + pstSelf->uiSummon_Gap = 600000; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("总招间隔:%d秒\n", pstSelf->uiSummon_Gap / 1000); +#endif +} + +/** +* @brief 设置电能量总召定时间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetESummonGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->uiESummon_Gap = uiGap; + + if(pstSelf->uiESummon_Gap < 15000) + { + pstSelf->uiESummon_Gap = 60000; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("总招间隔:%d秒\n", pstSelf->uiESummon_Gap / 1000); +#endif +} + +/** +* @brief 设置心跳间隔时间参数 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetHeartTimeGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->uiHeart_Gap = uiGap; + + if(pstSelf->uiHeart_Gap < 15000) + { + pstSelf->uiHeart_Gap = 90000; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("心跳间隔:%d秒\n", pstSelf->uiHeart_Gap / 1000); +#endif +} + +/** +* @brief 设置报文发送间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_FrameGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->uiSend_Gap = uiGap; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("帧间隔:%dms\n", pstSelf->uiSend_Gap); +#endif +} + +/** + * @brief 101规约初始化类型 + * @param[out] pstSelf + * @param[in] bType + */ +void CS10x_SetInitType(CS10xHandle_t pstSelf, bool bType) +{ + pstSelf->bSimpleInit = bType; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("初始化链路类型:%d\n", pstSelf->bSimpleInit); +#endif +} + +/** + * @brief 101规约文件传输是否需要确认帧 + * @param[out] pstSelf + * @param[in] ucEn + */ +void CS10x_SetFileAckType(CS10xHandle_t pstSelf, unsigned char ucEn) +{ + pstSelf->ucFileAckType = ucEn; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("101规约文件传输是否需要确认帧:%d\n", pstSelf->ucFileAckType); +#endif +} + +/** +* @brief 101规约重发间隔时间参数输入 +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_ResendGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->usReSend_Gap = uiGap; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("重发间隔:%d秒\n", pstSelf->usReSend_Gap / 1000); +#endif +} + +/** +* @brief 101规约重发次数参数输入 +* @param[out] pstSelf +* @param[in] uiCnt +*/ +void CS10x_ResendCnt(CS10xHandle_t pstSelf, unsigned int uiCnt) +{ + pstSelf->ucReSend_Num = uiCnt; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("重发次数:%d秒\n", pstSelf->ucReSend_Num); +#endif +} + +/** +* @brief 故障事件接口使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_FaultEventEn(CS10xHandle_t pstSelf, unsigned short usEnable) +{ + if(usEnable > 3) + { + return; + } + + pstSelf->usFaultEnable = usEnable; +#ifdef IEC_DEBUG_MSG + IEC_PRINT("故障事件使能:%d\n", pstSelf->usFaultEnable); +#endif +} + +/** +* @brief 发送SOE使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetSendSoe(CS10xHandle_t pstSelf, unsigned char ucEnable) +{ + pstSelf->ucSenSoeEa = ucEnable; +} + +/** +* @brief 发送COS使能 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetSendCos(CS10xHandle_t pstSelf, unsigned char ucEnable) +{ + pstSelf->ucSenCosEa = ucEnable; +} + +/** +* @brief 遥控-结束帧投退 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetYKEendFrame(CS10xHandle_t pstSelf, unsigned char ucEnable) +{ + pstSelf->ucYKEndFrame = ucEnable; +} + +/** +* @brief 离线SOE补发投退 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetOfflineSoeReissue(CS10xHandle_t pstSelf, unsigned char ucEnable) +{ + pstSelf->ucOffLineSoeReissueEn = ucEnable; +} + +/** +* @brief 读文件数据传输VSQ值设置 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetReadFileVSQ(CS10xHandle_t pstSelf, unsigned char usEnable) +{ + pstSelf->ucReadFileVSQ = usEnable; +} + +/** +* @brief 参数预置忽略后缀帧字段 +* @param[out] pstSelf +* @param[in] ucType +*/ +void CS10x_SetPresetContType(CS10xHandle_t pstSelf, unsigned char ucType) +{ + pstSelf->ucPreSetContType = ucType; +} + +/** +* @brief 104多帧数据传输设置 +* @param[out] pstSelf +* @param[in] usEnable +*/ +void CS10x_SetMultFrameEn(CS10xHandle_t pstSelf, unsigned char usEnable) +{ + pstSelf->ucMultiFrameEn = usEnable; +} + +/** +* @brief 设置对时同步间隔关联 +* +* @param[out] pstSelf +* @param[in] uiGap +*/ +void CS10x_SetSynTimeGap(CS10xHandle_t pstSelf, unsigned int uiGap) +{ + pstSelf->uiSyn_Gap = uiGap; + + if(pstSelf->uiSyn_Gap < 60000) + { + pstSelf->uiSyn_Gap = 180000; + } + +#ifdef IEC_DEBUG_MSG + IEC_PRINT("对时间隔:%d秒\n", pstSelf->uiSyn_Gap / 1000); +#endif +} + + +/** +* @brief 设置101主站方向位 +* +* @param[out] pstSelf +* @param[in] ucMasterDirect +*/ +void CS10x_SetMasterDirect(CS10xHandle_t pstSelf, unsigned char ucMasterDirect) +{ + pstSelf->bDir = ucMasterDirect; +} + +//*********************************************规约公共接收函数******************************// +/* +* @brief 公共接收函数 +* @param[out] pstSelf 规约实体 +* @param[in] pcBuf 接收数据 +* @param[in] uiLen 接收长度 +*/ +void CS10x_DoRecv(CS10xHandle_t pstSelf, char *pcBuf, unsigned int uiLen) +{ + /*数据拷贝*/ + if(uiLen <= pstSelf->stRecvBuf.usBufSize) + { + pstSelf->stRecvBuf.usWritePtr = uiLen; + } + else + { + pstSelf->stRecvBuf.usWritePtr = pstSelf->stRecvBuf.usBufSize; + } + + pstSelf->stRecvBuf.usReadPtr = 0; + memcpy(pstSelf->stRecvBuf.pBuf, pcBuf, pstSelf->stRecvBuf.usWritePtr); + + /*解帧处理*/ + if(pstSelf->pfnDecodeProcess) + { + pstSelf->pfnDecodeProcess(pstSelf, (unsigned char *)pstSelf->stRecvBuf.pBuf, pstSelf->stRecvBuf.usWritePtr); + } +} + +//*********************************************规约定时任务调度函数******************************// +/* +* @brief 规约定时任务 +* @param[out] pstSelf 规约实体 +* @param[in] usGap 时间间隔 +*/ +void CS10x_TimerHandle(CS10xHandle_t pstSelf, unsigned short usGap) +{ + unsigned short usFrameType = 0; + unsigned short usIFrameNum = 0; + + /*104时允许多帧数据发在一个packet进行发送, 多帧发送使能时单帧最大发送个数最大为4*/ + if((pstSelf->eCS10x_Type == CS104_TYPE_S) && (pstSelf->ucMultiFrameEn == 1)) + { + usIFrameNum = 4; + } + + /*公共的处理都统一在此处进行调用*/ + CS10x_M_Scheduled(pstSelf, usGap); + + if(NULL != pstSelf->pfnTimerManager) + { + pstSelf->pfnTimerManager(pstSelf, usGap); + } + + /* 检查从站总召延迟,到期后触发遥信/遥测上送 */ + CheckSummonSlaveDelay(pstSelf, usGap); + + /*参数预置超时时间管理*/ + if(pstSelf->uiPmPresetTimeout) + { + if(pstSelf->uiPmPresetTimeout > usGap) + { + pstSelf->uiPmPresetTimeout -= usGap; + } + else + { + pstSelf->uiPmPresetTimeout = 0; + pstSelf->ucPmPresetFlag = 0; + } + } + + /* 针对部分主站分帧时,无后续帧超时处理*/ + if(pstSelf->uiPreSetContCount) + { + if(pstSelf->uiPreSetContCount > usGap) + { + pstSelf->uiPreSetContCount -= usGap; + } + else + { + pstSelf->uiPreSetContCount = 0; + pstSelf->ucParamFlag = 0; + } + } + + //报文发送间隔 + if(pstSelf->uiSend_Gap) + { + if(pstSelf->uiFrameTmCnt > usGap) + { + pstSelf->uiFrameTmCnt -= usGap; + return; + } + else + { + pstSelf->uiFrameTmCnt = 0; + } + } + + CheckSOE_SendInfo(pstSelf); + CheckFaultEvent_SendInfo(pstSelf); + CheckTimeDd_SendInfo(pstSelf); + CheckDiturbYc_SendInfo(pstSelf); + pstSelf->stPubBuf.usWritePtr = 0; + + do + { + pstSelf->stSendBuf.usWritePtr = 0; + /*进行任务执行和ASDU域封装,无ASDU域数据直接封装*/ + usFrameType = CS10x_SendTask(pstSelf); + + if(LONG_TYPE == usFrameType) + { + if((0 != EncodeAsdu(pstSelf)) && (NULL != pstSelf->pfnEncodeFrame)) + { + pstSelf->pfnEncodeFrame(pstSelf); + } + } + else if((SHORT_TYPE == usFrameType) && (NULL != pstSelf->pfnEncodeOther)) + { + pstSelf->pfnEncodeOther(pstSelf); + } + else if(RESEND_TYPE == usFrameType) + { + GetBakData(pstSelf); //获取备份数据 + } + + /*实际数据发送接口*/ + if(pstSelf->stSendBuf.usWritePtr) + { + if(LONG_TYPE == usFrameType) + { + SaveSendData(pstSelf); + } + if(pstSelf->pfnEncrypt) + { + pstSelf->stSendBuf.usWritePtr = pstSelf->pfnEncrypt((char *)pstSelf->stSendBuf.pBuf, pstSelf->stSendBuf.usWritePtr); + } + + memcpy(pstSelf->stPubBuf.pBuf + pstSelf->stPubBuf.usWritePtr, pstSelf->stSendBuf.pBuf, pstSelf->stSendBuf.usWritePtr); + pstSelf->stPubBuf.usWritePtr += pstSelf->stSendBuf.usWritePtr; + + /*预留最大加密数据缓冲*/ + if(pstSelf->stPubBuf.usBufSize < pstSelf->stPubBuf.usWritePtr + 300) + { + break; + } + } + else + { + break; + } + } + while(usIFrameNum--); + + /*发送数据 数据缓冲存在且发送接口存在时*/ + if(pstSelf->stPubBuf.usWritePtr && pstSelf->pfnSendCb) + { + pstSelf->uiFrameTmCnt = pstSelf->uiSend_Gap; + pstSelf->pfnSendCb(pstSelf->stPubBuf.pBuf, pstSelf->stPubBuf.usWritePtr, pstSelf->pUsrData); + g_fStationDataSendNum += pstSelf->stPubBuf.usWritePtr;//发送数据量累加 + } +} + +/** +* @brief 数据发送缓存 +* +* @param[out] pstSelf +* @return +*/ +void SaveSendData(CS10xHandle_t pstSelf) +{ + if(pstSelf->stSendBakBuf.pBuf) + { + pstSelf->stSendBakBuf.usWritePtr = pstSelf->stSendBuf.usWritePtr; + memcpy(pstSelf->stSendBakBuf.pBuf, pstSelf->stSendBuf.pBuf, pstSelf->stSendBakBuf.usWritePtr); + } +} + +/** +* @brief 获取缓存数据至发送 +* +* @param[out] pstSelf +* @return +*/ +void GetBakData(CS10xHandle_t pstSelf) +{ + if(pstSelf->stSendBakBuf.pBuf) + { + pstSelf->stSendBuf.usWritePtr = pstSelf->stSendBakBuf.usWritePtr; + memcpy(pstSelf->stSendBuf.pBuf, pstSelf->stSendBakBuf.pBuf, pstSelf->stSendBuf.usWritePtr); + } + + return; +} + +//*********************************************规约接口配置函数******************************// + +/** +* @brief 设置解密接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_EncryptHandler(CS10xHandle_t pstSelf, CS10x_Encrypt cb) +{ + pstSelf->pfnEncrypt = cb; +} + +/** +* @brief 设置文件MD5接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_Md5ResultHandler(CS10xHandle_t pstSelf, CS10x_Md5Result cb) +{ + pstSelf->pfnMd5ResultCb = cb; +} + +/** +* @brief 时间读取设置接口 +* +* @param[out] pstSelf +* @param[in] cbGetTime +cbSetTime +*/ +void CS10x_TimeRWHandler(CS10xHandle_t pstSelf, CS10x_GetTime cbGetTime, CS10x_SetTime cbSetTime) +{ + pstSelf->pfnGetTime = cbGetTime; + pstSelf->pfnSetTime = cbSetTime; +} + +/** +* @brief 复位原因限定词,读写函数接口 +* @param[out] pstSelf 规约实体 +* @param[in] Read_cb 读函数指针 +* @param[in] Write_cb 写函数指针 +*/ +void CS10x_WR_ResetHandler(CS10xHandle_t pstSelf, CS10x_Read_ResetCOI Read_cb, CS10x_Write_ResetCOI Write_cb) +{ + pstSelf->pfnRead_ResetCOI = Read_cb; + pstSelf->pfnWrite_ResetCOI = Write_cb; +} + +/** +* @brief 设置组遥测数量及数值处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetYcCount +* cbGetYcValue +*/ +void CS10x_S_GetYcByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYcCountByGroup cbGetYcCount, CS10x_GetYcValueByGroup cbGetYcValue) +{ + pstSelf->pfnGetYcCountByGroup = cbGetYcCount; + pstSelf->pfnGetYcValueByGroup = cbGetYcValue; +} + +/** +* @brief 设置组遥信数量及状态处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetYxCount +* cbGetYxStatus +*/ +void CS10x_S_GetYxByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetYxCountByGroup cbGetYxCount, CS10x_GetYxStatusByGroup cbGetYxStatus) +{ + pstSelf->pfnGetYxCountByGroup = cbGetYxCount; + pstSelf->pfnGetYxStatusByGroup = cbGetYxStatus; +} + +/** +* @brief 设置组电度数量及数值处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetDdCount +* cbGetDdValue +*/ +void CS10x_S_GetDdByGroupHandler(CS10xHandle_t pstSelf, CS10x_GetDdCountByGroup cbGetDdCount, CS10x_GetDdValueByGroup cbGetDdValue) +{ + pstSelf->pfnGetDdCountByGroup = cbGetDdCount; + pstSelf->pfnGetDdValueByGroup = cbGetDdValue; +} + +/** +* @brief 设置扰动遥测处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetDiturbYc,cbSendNum,cbUpdataPout +*/ +void CS10x_S_DiturbYcHandler(CS10xHandle_t pstSelf, CS10x_GetDiturbYc cbGetDiturbYc, CS10x_GET_DiturbYc_SendNum cbSendNum, CS10x_Updata_DiturbYc_Pout cbUpdataPout) +{ + pstSelf->pfnGetDiturbYc = cbGetDiturbYc; + pstSelf->pfnGetDiturbYc_SendNum = cbSendNum; + pstSelf->pfnUpdata_DiturbYc_Pout = cbUpdataPout; +} + +/** +* @brief 设置soe处理函数 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_S_SOEHandler(CS10xHandle_t pstSelf, CS10x_GetSOE cbGetSOE, CS10x_GET_SOE_SendNum cbSendNum, CS10x_Updata_SOE_Pout cbUpdataSOEPout) +{ + pstSelf->pfnGetSOE = cbGetSOE; + pstSelf->pfnGetSOE_SendNum = cbSendNum; + pstSelf->pfnUpdata_SOE_Pout = cbUpdataSOEPout; +} + +/** +* @brief 扰动电度处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetTimeDdu,cbcbSendNum,cbcbUpdataPout +*/ +void CS10x_S_DiturbDduHandler(CS10xHandle_t pstSelf, CS10x_GetTimeDdu cbGetTimeDdu, CS10x_GetTimeDdu_SendNum cbSendNum, CS10x_Updata_TimeDdu_Pout cbUpdataPout) +{ + pstSelf->pfnGetTimeDdu = cbGetTimeDdu; + pstSelf->pfnGetTimeDdu_SendNum = cbSendNum; + pstSelf->pfnUpdata_TimeDdu_Pout = cbUpdataPout; +} + +/** +* @brief 设置故障事件处理函数 +* +* @param[out] pstSelf +* @param[in] cbSendNum,cbGetFaultEvent,cbUpdataPout +*/ +void CS10x_S_FaultEventHandler(CS10xHandle_t pstSelf, CS10x_GET_Event_SendNum cbSendNum, CS10x_GetFaultEvent cbGetFaultEvent, CS10x_Updata_FaultEvent_Pout cbUpdataPout) +{ + pstSelf->pfnGetEvent_SendNum = cbSendNum; + pstSelf->pfnGetFaultEvent = cbGetFaultEvent; + pstSelf->pfnUpdata_FaultEvent_Pout = cbUpdataPout; +} + +/** + * @brief 遥控操作校验 + * + * @param pstSelf + * @param cb + */ +void CS10x_S_YkVerifyHandler(CS10xHandle_t pstSelf, CS10x_YkVerify cb) +{ + pstSelf->pfnFcYkVerify = cb; +} + +/** + * @brief 参数定值区获取与设置接口 + * + * @param pstSelf + * @param cbGetParamArea 参数定值区获取 + * @param cbSetParamArea 参数定值区设置 + */ +void CS10x_S_ParamAreaHandler(CS10xHandle_t pstSelf, CS10x_GetParamArea cbGetParamArea, CS10x_SetParamArea cbSetParamArea) +{ + pstSelf->pfnGetParamArea = cbGetParamArea; + pstSelf->pfnSetParamArea = cbSetParamArea; +} + +/** + * @brief 增加/读取/写入参数定值函数 + * + * @param pstSelf + * @param cbAddIECParam, cbReadIECParam,cbWriteIECParam + */ +void CS10x_S_IECParamHandler(CS10xHandle_t pstSelf, CS10x_AddIECParam cbAddIECParam, CS10x_RunReadIECParam cbReadIECParam, CS10x_RunWriteIECParam cbWriteIECParam) +{ + pstSelf->pfnAddIECParam = cbAddIECParam; + pstSelf->pfnRunReadIECParam = cbReadIECParam; + pstSelf->pfnRunWriteIECParam = cbWriteIECParam; +} + +/** +* @brief 参数数量及信息获取处理函数 +* +* @param[out] pstSelf +* @param[in] cbGetParamCount, cbGetParamInfo +*/ +void CS10x_S_GetParamInfoHandler(CS10xHandle_t pstSelf, CS10x_GetParamCount cbGetParamCount, CS10x_GetParamInfoByIndx cbGetParamInfo) +{ + pstSelf->pfnGetParamCount = cbGetParamCount; + pstSelf->pfnGetParamInfoByIndx = cbGetParamInfo; +} + +/** + * @brief 读文件 + * + * @param pstSelf + * @param cbGetPro + * @param cbGetNum + * @param cbRead + * @param *pvParam + */ +void CS10x_S_FileReadOprtHandler(CS10xHandle_t pstSelf, + CS10x_GetProDirFile cbGetPro, + CS10x_GetNumDirFile cbGetNum, + CS10x_ReadFile cbRead, + void *pvParam) +{ + pstSelf->pfnGetProDirFile = cbGetPro; + pstSelf->pfnGetNumDirFile = cbGetNum; + pstSelf->pfnReadFile = cbRead; + pstSelf->pvFileReadParam = pvParam; +} + +/** + * @brief 写文件 + * + * @param pstSelf + * @param cbWrite + * @param cbCheck + * @param cbFinish + * @param *pvParam + */ +void CS10x_S_FileWriteOprtHandler(CS10xHandle_t pstSelf, + CS10x_Write cbWrite, + CS10x_WriteFileCheck cbCheck, + CS10x_WriteFinish cbFinish, + void *pvParam) +{ + pstSelf->pfnWriteFileCheck = cbCheck; + pstSelf->pfnWrite = cbWrite; + pstSelf->pfnWriteFinish = cbFinish; + pstSelf->pvFileWrteParam = pvParam; +} + +/** +* @brief 升级处理流程 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_S_UpdateProcHandler(CS10xHandle_t pstSelf, CS10x_UpdateProc cb) +{ + pstSelf->pfnUpdateProc = cb; +} + +/** +* @brief 设置计量接口处理 +* +* @param[out] pstSelf +* @param[in] cbSetValue +cbSetDdValue +*/ +void CS10x_M_SetDdHandler(CS10xHandle_t pstSelf, CS10x_SetValue cbSetValue, CS10x_SetDdValue cbSetDdValue) +{ + pstSelf->pfnSetValue = cbSetValue; + pstSelf->pfnSetDdValue = cbSetDdValue; +} + +/** +* @brief 设置接收遥控接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetYkInforHandler(CS10xHandle_t pstSelf, CS10x_SetYkInfor cb) +{ + pstSelf->pfnSetYkInfor = cb; +} + +/** +* @brief 设置下行设备遥控应答接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetYkAckHandler(CS10xHandle_t pstSelf, CS10x_SetYkAck cb) +{ + pstSelf->pfnSetYkResponse = cb; +} + +/** +* @brief 设置下行设备上传参数定值接收接口 +* +* @param[out] pstSelf +* @param[in] cb +*/ +void CS10x_SetParamRecvHandle(CS10xHandle_t pstSelf, CS10x_SetParamInfo cb) +{ + pstSelf->pfnSetParamInfo = cb; +} + +/** + * @brief 设置获取总召延迟时间回调接口 + * + * @param[out] pstSelf + * @param[in] cb + */ +void CS10x_GetSummonSlaveDelayHandler(CS10xHandle_t pstSelf, CS10x_GetSummonSlaveDelay cb) +{ + pstSelf->pfnGetSummonSlaveDelay = cb; +} + diff --git a/src/protocol/lib60870/src/lib60870_process.c b/src/protocol/lib60870/src/lib60870_process.c new file mode 100644 index 0000000..252d1d9 --- /dev/null +++ b/src/protocol/lib60870/src/lib60870_process.c @@ -0,0 +1,440 @@ +/****************************************************************************** + +版权所有 (C), 2013-2023, 科大智能电气有限公司 + +****************************************************************************** +文 件 名 : lib60870_process.c +版 本 号 : V1.0 +生成日期 : 2022年04月07日 +最近修改 : +功能描述 : 101及104规约实现中的公共流程实现模块 +函数列表 : +修改历史 : +1.日 期 : 2022年04月07日 +修改内容 : 创建文件 +*******************************************************************************/ +/*************************************文件包含*********************************/ +#include "lib60870_process.h" + +/***************************************数据定义*******************************/ + +/*************************************外部接口函数*****************************/ +/** +* @brief 更新数据池中故障事件及SOE指针 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckUpdate_SoeEvent(CS10xHandle_t pstSelf) +{ + if(pstSelf->usSoeSendNoAckNum) + { + if(NULL != pstSelf->pfnUpdata_SOE_Pout) + { + pstSelf->pfnUpdata_SOE_Pout(pstSelf->pUsrData, pstSelf->usSoeSendNoAckNum); + pstSelf->usCosSendNoAckNum -= pstSelf->usSoeSendNoAckNum; + pstSelf->usSoeSendNoAckNum = 0; + } + } + + if(pstSelf->usEventSendNoAckNum) + { + if(NULL != pstSelf->pfnUpdata_FaultEvent_Pout) + { + pstSelf->pfnUpdata_FaultEvent_Pout(pstSelf->pUsrData, pstSelf->usEventSendNoAckNum); + pstSelf->usEventSendNoAckNum = 0; + } + } + + if(pstSelf->usDduSendNoAckNum) + { + if(NULL != pstSelf->pfnUpdata_TimeDdu_Pout) + { + pstSelf->pfnUpdata_TimeDdu_Pout(pstSelf->pUsrData, pstSelf->usDduSendNoAckNum); + pstSelf->usDduSendNoAckNum = 0; + } + } +} + +/** +* @brief 更新数据池中扰动遥测指针 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckUpdate_DiturbYcEvent(CS10xHandle_t pstSelf) +{ + if(pstSelf->usDiturbYcSendNoAckNum) + { + if(NULL != pstSelf->pfnUpdata_DiturbYc_Pout) + { + pstSelf->pfnUpdata_DiturbYc_Pout(pstSelf->pUsrData, pstSelf->usDiturbYcSendNoAckNum); + pstSelf->usDiturbYcSendNoAckNum = 0; + } + } +} + +/** +* @brief 检查数据池中SOE待发送数量 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckSOE_SendInfo(CS10xHandle_t pstSelf) +{ + if(pstSelf->eCS10x_Type == CS104_TYPE_M || pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站时直接返回 + { + return; + } + + if(NULL == pstSelf->pfnGetSOE_SendNum) + { + return; + } + + /* 链路未初始化完成,不进行任务调度*/ + if(1 != pstSelf->ucInitStatus) + { + pstSelf->usSoeSendSetup = 0; + return; + } + + /*cos-soe处理*/ + pstSelf->usSoeSendNum = pstSelf->pfnGetSOE_SendNum(pstSelf->pUsrData); + + if(0 == pstSelf->usSoeSendSetup) + { + if(pstSelf->ucOffLineSoeReissueEn) + { + pstSelf->usCosSendNoAckNum = pstSelf->usSoeSendNum; + } + else + { + pstSelf->pfnUpdata_SOE_Pout(pstSelf->pUsrData, pstSelf->usSoeSendNum); + pstSelf->usSoeSendNum = 0; + pstSelf->usCosSendNoAckNum = 0; + } + pstSelf->usSoeSendSetup = 1; + } + + if(pstSelf->usSoeSendNum) + { + if(pstSelf->usSoeSendNum != pstSelf->usSoeSendNoAckNum) + { + if(pstSelf->usSoeSendNum > pstSelf->usCosSendNoAckNum) + { + // 发送SOE/COS使能参数 + if(pstSelf->ucSenCosEa == 0) + { + pstSelf->usCosSendNoAckNum = pstSelf->usSoeSendNum; + } + else + { + SetSendTask(pstSelf, TSKID_SendCOS, COT_SPONT, 0); //正常发送COS + } + } + else + { + // 发送SOE/COS使能参数 + pstSelf->usCosSendNoAckNum = pstSelf->usSoeSendNum; + + if(pstSelf->ucSenSoeEa == 0) + { + pstSelf->usSoeSendNoAckNum = pstSelf->usSoeSendNum; + } + else + { + SetSendTask(pstSelf, TSKID_SendSOE, COT_SPONT, 0); //正常发送SOE + } + } + } + } + else + { + pstSelf->usSoeSendNoAckNum = 0; + pstSelf->usCosSendNoAckNum = 0; + } +} + +/** +* @brief 检查数据池中故障事件待发送数量 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckFaultEvent_SendInfo(CS10xHandle_t pstSelf) +{ + unsigned short usEventSendNum = 0; + + if(pstSelf->eCS10x_Type == CS104_TYPE_M || pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站时直接返回 + { + return; + } + + if(NULL == pstSelf->pfnGetEvent_SendNum) + { + return; + } + + /* 链路未初始化完成,不进行任务调度*/ + if(1 != pstSelf->ucInitStatus) + { + return; + } + + /* 故障事件处理*/ + if(pstSelf->usFaultEnable) + { + usEventSendNum = pstSelf->pfnGetEvent_SendNum(pstSelf->pUsrData); + + if(usEventSendNum) + { + if(usEventSendNum != pstSelf->usEventSendNoAckNum) + { + SetSendTask(pstSelf, TSKID_FaultSoe, COT_SPONT, 0); // 第一次重启补发SOE + } + } + else + { + pstSelf->usEventSendNoAckNum = 0; + } + } +} + +/** +* @brief 检查数据池中电度待发送数量 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckTimeDd_SendInfo(CS10xHandle_t pstSelf) +{ + unsigned short usTimeDdSendNum = 0; + + if(pstSelf->eCS10x_Type == CS104_TYPE_M || pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站时直接返回 + { + return; + } + + if(NULL == pstSelf->pfnGetTimeDdu_SendNum) + { + return; + } + + /* 链路未初始化完成,不进行任务调度*/ + if(1 != pstSelf->ucInitStatus) + { + return; + } + + /* 电度数据处理*/ + usTimeDdSendNum = pstSelf->pfnGetTimeDdu_SendNum(pstSelf->pUsrData); + + if(usTimeDdSendNum) + { + if(usTimeDdSendNum != pstSelf->usDduSendNoAckNum) + { + SetSendTask(pstSelf, TSKID_DdTimeData, COT_SPONT, 0); // 第一次重启补发SOE + } + } + else + { + pstSelf->usDduSendNoAckNum = 0; + } +} + + +/** +* @brief 检查数据池中扰动遥测待发送数量 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CheckDiturbYc_SendInfo(CS10xHandle_t pstSelf) +{ + unsigned short usDiturbYcSendNum = 0; + + if(pstSelf->eCS10x_Type == CS104_TYPE_M || pstSelf->eCS10x_Type == CS101_TYPE_M) //作为主站时直接返回 + { + return; + } + + if(NULL == pstSelf->pfnGetDiturbYc_SendNum) + { + return; + } + + usDiturbYcSendNum = pstSelf->pfnGetDiturbYc_SendNum(pstSelf->pUsrData); //获取数据表中待发的数量 + + if(usDiturbYcSendNum) + { + /*未初始化完成,直接清空缓冲*/ + if((0 == pstSelf->ucInitStatus) && (NULL != pstSelf->pfnUpdata_DiturbYc_Pout)) + { + pstSelf->pfnUpdata_DiturbYc_Pout(pstSelf->pUsrData, usDiturbYcSendNum); + } + else + { + SetSendTask(pstSelf, TSKID_YcDisturb, COT_SPONT, 0); //正常发送扰动遥测 + } + } +} + +/** +* @brief 检查是否有读取任务 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void PollFileTransTask(CS10xHandle_t pstSelf) +{ + int ret; + + if(NULL == pstSelf->pfnCheckTransFileObj || + NULL == pstSelf->pfnCheckTransTimeOut) + { + return ; + } + + if(GetTaskFlag(&pstSelf->stTaskFlags, TSKID_StartLink) + || pstSelf->bContinueSendFlag == false) + { + //IEC_PRINT("主模式下, 存在U帧激活任务, 直接返回\n"); + return ; + } + + if(pstSelf->ucTransStatus != FILE_ST_IDLE) //主模式每次传输目录/文件完成, 置位传输状态 + { + ret = pstSelf->pfnCheckTransTimeOut(pstSelf->pUsrData); + + if(ret < 0) + { + return ; + } + else + { + pstSelf->ucTransStatus = FILE_ST_IDLE; + ClearTaskFlag(&pstSelf->stTaskFlags, TSKID_FilePro);// 直接清空上次文件传输任务 + } + } + + ret = pstSelf->pfnCheckTransFileObj(&pstSelf->stRdSet, pstSelf->pUsrData); + + if(ret == TRANS_DIR) + { + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_DIR, 0); + pstSelf->ucTransStatus = FILE_ST_RD_DIR; + } + else if(ret == TRANS_FILE) + { + SetSendTask(pstSelf, TSKID_FilePro, FILE_ST_RD_FILE_ACT, 0); + pstSelf->ucTransStatus = FILE_ST_RD_FILE_ACT; + } + else + { + } +} + +/** +* @brief 设置M端对S端初始化后总召及对时处理 +* @param[in] pstSelf-规约实体指针 +* @param[out] 无 +* @return 无 +*/ +void CS10x_M_Scheduled(CS10xHandle_t pstSelf, unsigned short usGap) +{ + if(CS104_TYPE_M == pstSelf->eCS10x_Type || CS101_TYPE_M == pstSelf->eCS10x_Type) //主站 + { + if(pstSelf->uiSummon_Gap) //总召间隔 + { + pstSelf->uiSummon_Tcn += usGap; + + if(pstSelf->uiSummon_Tcn >= pstSelf->uiSummon_Gap) + { + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACT, 0); + pstSelf->uiSummon_Tcn = 0; + } + } + + if(pstSelf->uiESummon_Gap) //总召间隔 + { + pstSelf->uiESummon_Tcn += usGap; + + if(pstSelf->uiESummon_Tcn >= pstSelf->uiESummon_Gap) + { + SetSendTask(pstSelf, TSKID_DdSummon, COT_ACT, 0); + pstSelf->uiESummon_Tcn = 0; + } + } + + if(pstSelf->uiSyn_Gap) //同步间隔 + { + pstSelf->uiTimeSyn_Tcn += usGap; + + if(pstSelf->uiTimeSyn_Tcn >= pstSelf->uiSyn_Gap) + { + pstSelf->uiTimeSyn_Tcn = 0; + SetSendTask(pstSelf, TSKID_TimeSyn, COT_ACT, 0); + } + } + + if(pstSelf->pfnPollFileTransTask != NULL) + { + pstSelf->pfnPollFileTransTask(pstSelf); + } + } +} + +/** +* @brief 检查从站总召延迟计数,延迟到期后触发遥信/遥测上送 +* @param[in] pstSelf-规约实体指针 +* @param[in] usGap-本次定时器间隔(ms) +* @return 无 +*/ +void CheckSummonSlaveDelay(CS10xHandle_t pstSelf, unsigned short usGap) +{ + if(pstSelf->uiSummonSlaveDelayRemain == 0) + { + return; + } + + if(pstSelf->uiSummonSlaveDelayRemain > usGap) + { + pstSelf->uiSummonSlaveDelayRemain -= usGap; + } + else + { + /* 延迟时间到,触发遥信上送 */ + pstSelf->uiSummonSlaveDelayRemain = 0; + SetSendTask(pstSelf, TSKID_SummonYx, COT_INTROGEN, pstSelf->ucSummonSlaveQoi); + } +} + +/** +* @brief 接收到初始化完成标识 +* @return 无 +*/ +void CS10x_M_Finish(CS10xHandle_t pstSelf) +{ + pstSelf->ucInitStatus = 1; + + /*101主站模式*/ + if(CS101_TYPE_M == pstSelf->eCS10x_Type) //主站 + { + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACT, 0); + pstSelf->ucInitStatus = 1; + pstSelf->uiInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + } + else if(CS104_TYPE_M == pstSelf->eCS10x_Type) + { + SetSendTask(pstSelf, TSKID_SummonResponse, COT_ACT, 0); + pstSelf->ucInitStatus = 1; + } +} + +/***************************************内部函数*******************************/ diff --git a/src/protocol/lib60870/src/lib60870_public.c b/src/protocol/lib60870/src/lib60870_public.c new file mode 100644 index 0000000..b318cb5 --- /dev/null +++ b/src/protocol/lib60870/src/lib60870_public.c @@ -0,0 +1,788 @@ +/****************************************************************************** + + 版权所有 (C), 2013-2023, 科大智能电气有限公司 + + ****************************************************************************** + 文 件 名 : lib60870_public.c + 版 本 号 : V1.0 + 生成日期 : 2022年04月07日 + 最近修改 : + 功能描述 : 101及104规约实现中的任务管理及校验等功能 + 函数列表 : + 修改历史 : + 1.日 期 : 2022年04月07日 + 修改内容 : 创建文件 +*******************************************************************************/ +/*************************************文件包含*********************************/ +#include "lib60870_public.h" + +/***************************************数据定义*******************************/ + +/*************************************外部接口函数*****************************/ +/** + * @brief 规约发送任务调度 + * @param[in] pstSelf-规约实体指针 + * @param[out] 无 + * @return 任务执行结果 + */ +unsigned char CS10x_SendTask(CS10xHandle_t pstSelf) +{ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ReSend)) //重发标识 + { + pstSelf->byTaskFlagId = TSKID_ReSend; + return RESEND_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_Anomaly)) //异常帧 + { + pstSelf->byTaskFlagId = TSKID_Anomaly; + return LONG_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_Ack)) //回复应答帧 + { + pstSelf->byTaskFlagId = TSKID_Ack; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_RequestLink)) // 101规约请求链路状态 + { + pstSelf->byTaskFlagId = TSKID_RequestLink; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ResetLink)) // 101规约重置链路 + { + pstSelf->byTaskFlagId = TSKID_ResetLink; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_MResponse)) // 101规约链路状态回复帧 + { + pstSelf->byTaskFlagId = TSKID_MResponse; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_HeartBeat)) // 101规约心跳 + { + pstSelf->byTaskFlagId = TSKID_HeartBeat; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_StartLink)) // 104规约启动链路 + { + pstSelf->byTaskFlagId = TSKID_StartLink; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_StopLink)) // 104规约断开链路 + { + pstSelf->byTaskFlagId = TSKID_StopLink; + return SHORT_TYPE; + } + + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_UTest)) // 104规约U帧TEST + { + pstSelf->byTaskFlagId = TSKID_UTest; + return SHORT_TYPE; + } + + /*规约不允许发送长帧,则直接返回*/ + if(CS104_TYPE_S == pstSelf->eCS10x_Type || CS104_TYPE_M == pstSelf->eCS10x_Type) + { + if(false == pstSelf->bContinueSendFlag) + { + return 0; + } + } + else + { + if(pstSelf->uiResend_Tcn) + { + return 0; + } + } + + /*初始化完成*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_InitFinish)) + { + pstSelf->byTaskFlagId = TSKID_InitFinish; + return LONG_TYPE; + } + + /*遥控命令报文*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_YkProcess)) + { + pstSelf->byTaskFlagId = TSKID_YkProcess; + return LONG_TYPE; + } + + /*COS信息*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_SendCOS)) + { + pstSelf->byTaskFlagId = TSKID_SendCOS; + return LONG_TYPE; + } + + /*事件顺序记录 SOE*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_SendSOE)) + { + pstSelf->byTaskFlagId = TSKID_SendSOE; + return LONG_TYPE; + } + + /* 总招遥信响应遥信 */ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_SummonYx)) + { + pstSelf->byTaskFlagId = TSKID_SummonYx; + return LONG_TYPE; + } + + /* 总招遥测响应遥测 */ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_SummonYc)) + { + pstSelf->byTaskFlagId = TSKID_SummonYc; + return LONG_TYPE; + } + + /*总召响应*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_SummonResponse)) + { + pstSelf->byTaskFlagId = TSKID_SummonResponse; + return LONG_TYPE; + } + + /* 故障事件 */ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_FaultSoe)) + { + pstSelf->byTaskFlagId = TSKID_FaultSoe; + return LONG_TYPE; + } + + /*时钟同步报文*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_TimeSyn)) + { + pstSelf->byTaskFlagId = TSKID_TimeSyn; + return LONG_TYPE; + } + + /*扰动数据*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_YcDisturb)) + { + pstSelf->byTaskFlagId = TSKID_YcDisturb; + return LONG_TYPE; + } + + /*延时获得命令*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ObtainDelay)) + { + pstSelf->byTaskFlagId = TSKID_ObtainDelay; + return LONG_TYPE; + } + + /*复位进程*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ResetProcess)) + { + pstSelf->byTaskFlagId = TSKID_ResetProcess; + return LONG_TYPE; + } + + /*文件数据响应*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_FilePro)) + { + pstSelf->byTaskFlagId = TSKID_FilePro; + return LONG_TYPE; + } + + /*电能量数据发送*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_DdData)) + { + pstSelf->byTaskFlagId = TSKID_DdData; + return LONG_TYPE; + } + + /*总召电能量*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_DdSummon)) + { + pstSelf->byTaskFlagId = TSKID_DdSummon; + return LONG_TYPE; + } + + /*总召电能量*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_DdTimeData)) + { + pstSelf->byTaskFlagId = TSKID_DdTimeData; + return LONG_TYPE; + } + + /*修改参数定值区*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ChgConst)) + { + pstSelf->byTaskFlagId = TSKID_ChgConst; + return LONG_TYPE; + } + + /*读取参数定值区*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ReadConst)) + { + pstSelf->byTaskFlagId = TSKID_ReadConst; + return LONG_TYPE; + } + + /*读取定值参数*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamPreread)) + { + pstSelf->byTaskFlagId = TSKID_ParamPreread; + return LONG_TYPE; + } + + /*读取定值参数-南网*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamRead_NanWang)) + { + pstSelf->byTaskFlagId = TSKID_ParamRead_NanWang; + return LONG_TYPE; + } + + /*设置定值参数*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamPrewrite)) + { + pstSelf->byTaskFlagId = TSKID_ParamPrewrite; + return LONG_TYPE; + } + + /*写参数定值-南网(类型标识 55)*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamWrite_NanWang)) + { + pstSelf->byTaskFlagId = TSKID_ParamWrite_NanWang; + return LONG_TYPE; + } + + /*读定值参数响应传输-南网*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamReadResponse_NanWang)) + { + pstSelf->byTaskFlagId = TSKID_ParamReadResponse_NanWang; + return LONG_TYPE; + } + + /*参数预置-南网*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamPreset_NanWang)) + { + pstSelf->byTaskFlagId = TSKID_ParamPreset_NanWang; + return LONG_TYPE; + } + + /*固化定值参数-南网*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_ParamSolidify_NanWang)) + { + pstSelf->byTaskFlagId = TSKID_ParamSolidify_NanWang; + return LONG_TYPE; + } + + /*启动升级*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_UpdateStart)) + { + pstSelf->byTaskFlagId = TSKID_UpdateStart; + return LONG_TYPE; + } + + /*执行升级*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_UpdateExe)) + { + pstSelf->byTaskFlagId = TSKID_UpdateExe; + return LONG_TYPE; + } + + /*长帧测试*/ + if(CheckClearTaskFlag(&pstSelf->stTaskFlags, TSKID_DataTest)) + { + pstSelf->byTaskFlagId = TSKID_DataTest; + return LONG_TYPE; + } + + return 0; +} + +/** + * @brief 置规约发送任务接口函数 + * @param[in] pstSelf-规约实体指针 + * @param[in] uiFlagNo-任务ID + * @param[in] usParam_low-传递参数低2字节,一般是指cot usParam_hig 传递参数高2字节 一般指报文尾部的限定词 + * @param[out] 无 + * @return 无 + */ +void SetSendTask(CS10xHandle_t pstSelf, unsigned int uiFlagNo, unsigned short usParam_low, unsigned short usParam_hig) +{ + SetTaskFlag(&pstSelf->stTaskFlags, uiFlagNo); + pstSelf->uiaTaskParam[uiFlagNo] = usParam_hig; + pstSelf->uiaTaskParam[uiFlagNo] = (pstSelf->uiaTaskParam[uiFlagNo] << 16) + usParam_low; + return; +} + +/*************************************************************** +* @brief SetTaskFlag + 设置标志,将pFlags缓冲区内的第FlagNo个位置位成1 +* @param[in] pstFlags 标志缓冲区首址 + uiFlagNo 标记号 +* @return +***************************************************************/ +void SetTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo) +{ + unsigned int uiByteNo = 0; // FlagNo所处的字节号 + unsigned int uiBitNo = 0; // FlagNo在字节内所处的位号 + + if(uiFlagNo >= MAX_FLAGNO) //越界 + { + return; + } + + uiByteNo = uiFlagNo >> 3; + uiBitNo = uiFlagNo & 0x7; + // pstFlags->Flag[uiByteNo] |= aBitSelect[uiBitNo]; + pstFlags->ucFlag[uiByteNo] |= (1 << uiBitNo); +} + +/*************************************************************** +* @brief GetTaskFlag + 获取pFlags缓冲区内的第FlagNo个位置的状态位 +* @param[in] pstFlags 标志缓冲区首址 + uiFlagNo 标记号 +* @return 标志状态,1 有效,0 无效 +***************************************************************/ +unsigned int GetTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo) +{ + // 设置每个模块的标志 + unsigned int uiByteNo = 0; // FlagNo所处的字节号 + unsigned int uiBitNo = 0; // FlagNo在字节内所处的位号 + unsigned char *pucFlag = (unsigned char *)pstFlags; // + uiByteNo = uiFlagNo >> 3; //第5到8位 + uiBitNo = uiFlagNo & 7; //取低三位 + return (pucFlag[uiByteNo] & (1 << uiBitNo)); +} + +/*************************************************************** +* @brief ClearTaskFlag + 清除标志,将pFlags缓冲区内的第FlagNo个位置位成0 +* @param[in] pstFlags 标志缓冲区首址 + uiFlagNo 标记号 +* @return +***************************************************************/ +void ClearTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo) +{ + unsigned int uiByteNo = 0; + unsigned int uiBitNo = 0; + + if(uiFlagNo >= MAX_FLAGNO) + { + return; + } + + uiByteNo = uiFlagNo >> 3; + uiBitNo = uiFlagNo & 0x7; + pstFlags->ucFlag[uiByteNo] &= ~(1 << uiBitNo); +} + +/*************************************************************** +* @brief CheckClearTaskFlag + 检查清除任务标志,若任务标志第dwFlagNo位有效,将其清除 + 然后返回1,否则返回0 +* @param[in] pstFlags 标志缓冲区首址 +* uiFlagNo 标记号 +* @return 1 任务标志第uiFlagNo位有效 + 0 任务标志第uiFlagNo位无效 +***************************************************************/ +int CheckClearTaskFlag(VFLAGS *pstFlags, unsigned int uiFlagNo) +{ + if(!GetTaskFlag(pstFlags, uiFlagNo)) + { + return 0; + } + + ClearTaskFlag(pstFlags, uiFlagNo); + return 1; +} + +/** + * @brief 清除所有任务接口 + * @param[in] pstSelf + * @param[out] 无 + * @return 无 + */ +void ClearAllTaskflgs(CS10xHandle_t pstSelf) +{ + pstSelf->stRecvBuf.usWritePtr = 0; + pstSelf->stRecvBuf.usReadPtr = 0; + pstSelf->stSendBuf.usWritePtr = 0; + pstSelf->stSendBuf.usReadPtr = 0; + memset(&pstSelf->stTaskFlags, 0, sizeof(VFLAGS)); //任务 + memset(pstSelf->uiaTaskParam, 0, MAX_FLAGNO * sizeof(unsigned short)); //任务参数 + pstSelf->byTaskFlagId = 0; + pstSelf->ucInitStatus = 0; // 初始化完成状态 + pstSelf->ucFirstAct = 0; + pstSelf->uiFrameTmCnt = 0; + pstSelf->uiHeart_Tcn = 0; + pstSelf->uiSummon_Tcn = 0; + pstSelf->uiESummon_Tcn = 0; + pstSelf->uiTimeSyn_Tcn = 0; + pstSelf->usYxSendNum = 0; + pstSelf->usYcSendNum = 0; + pstSelf->usDisTurbYcSendNum = 0; + pstSelf->usDdSendNum = 0; + pstSelf->usSoeSendNum = 0; + pstSelf->usSoeSendNoAckNum = 0; /*Soe发送未确认数量*/ + pstSelf->usCosSendNoAckNum = 0; + pstSelf->usEventSendNoAckNum = 0; /*事件发送未确认数量*/ + pstSelf->usDduSendNoAckNum = 0; + pstSelf->usDiturbYcSendNoAckNum = 0; + pstSelf->usSoeSendSetup = 0; + pstSelf->usDdSummonSetup = 0; + pstSelf->ucParamFlag = 0; + pstSelf->usParamSendNum = 0; + pstSelf->ucPmPresetFlag = 0; + pstSelf->uiPmPresetTimeout = 0; + pstSelf->ucTransStatus = 0; + pstSelf->uiTransTimerCur = 0; + pstSelf->uiTransTimerMax = 0; + pstSelf->bContinueSendFlag = 0; + pstSelf->ucInitStep = 0; + pstSelf->ucSelf_FCB = 0; + pstSelf->ucRxAckFlag = 0; + pstSelf->ucRxLinkStatusFlag = 0; + pstSelf->ucRxLinkRequestFlag = 0; + pstSelf->ucRxLinkResetFlag = 0; + pstSelf->ucRxInitFinishFlag = 0; + pstSelf->ucHeart_Resend_Flag = 0; + pstSelf->ucFileTransFrame = 0; + pstSelf->usFileNoneAckNum = 0; + pstSelf->usResend_Ncn = 0; + pstSelf->uiResend_Tcn = 0; + pstSelf->uiRelink_Tcn = 0; + pstSelf->uiInit_Tcn = 0; + pstSelf->uiReInit_Tcn = 0; + pstSelf->uiInit_Resend_Ncn = 0; + pstSelf->usSendNum = 0; /*Send Counter */ + pstSelf->usRecvNum = 0; /*Receive Counter*/ + pstSelf->usAckSendNum = 0; /*Receive Ack Counter*/ + pstSelf->usAckRecvNum = 0; /*Have Ack Receive Counter*/ + pstSelf->stM_vTimer[0].bRun = 0; + pstSelf->stM_vTimer[1].bRun = 0; + pstSelf->stM_vTimer[2].bRun = 0; + pstSelf->stM_vTimer[3].bRun = 0; + pstSelf->uiSummonSlaveDelayRemain = 0; + pstSelf->ucSummonSlaveQoi = 0; +} + +/** + * @brief 8位校验和计算函数 + * @param[in] pucBuf-数据指针 + * @param[in] ucLen-数据长度 + * @param[out] 无 + * @return 校验和 + */ +unsigned char checksum_8(unsigned char *pucBuf, unsigned char ucLen) +{ + unsigned char ucSum = 0; + unsigned char uci = 0; + + for(uci = 0; uci < ucLen; uci++) + { + ucSum += pucBuf[uci]; + } + + ucSum = ucSum & 0xff; + return ucSum; +} + +/** + * @brief Check比对Tag类型与长度关系 + * + * @param ucTag + * @param ucLen + * @return int + */ +int CheckParamTagAndLen(unsigned char ucTag, unsigned char ucLen) +{ + bool bResult = true; + + switch(ucTag) + { + case TAG_TPYE_BOOL: + case TAG_TPYE_TINY: + case TAG_TPYE_UTINY: + if(ucLen != 1) + { + bResult = false; + } + + break; + + case TAG_TPYE_SHORT: + case TAG_TPYE_USHORT: + if(ucLen != 2) + { + bResult = false; + } + + break; + + case TAG_TPYE_INT: + case TAG_TPYE_UINT: + case TAG_TPYE_FLOAT: + if(ucLen != 4) + { + bResult = false; + } + + break; + + case TAG_TPYE_LONG: + case TAG_TPYE_ULONG: + case TAG_TPYE_DOUBLE: + if(ucLen != 8) + { + bResult = false; + } + + break; + + case TAG_TPYE_STR: + if(ucLen > 64) + { + bResult = false; + } + + break; + + default: + bResult = false; + break; + } + + return bResult; +} + +/* + * Prototype : CP56Time2a_Pack2Buf + * Description : 打包Cp56时间到缓冲 + * @param[in] : unsigned char *pucOutBuf + * @param[in] : const __CP56Time2a *pstCp56 + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/6 + * Author : wqw + * Modification : Created function + * + */ +unsigned char CP56Time2a_Pack2Buf(unsigned char *pucOutBuf, const __CP56Time2a *pstCp56) +{ + if(NULL == pstCp56) + { + memset(pucOutBuf, 0, 7); + } + else + { + pucOutBuf[0] = pstCp56->ucLMs; + pucOutBuf[1] = pstCp56->ucHMs; + pucOutBuf[2] = pstCp56->ucMin; + pucOutBuf[3] = pstCp56->ucHour; + pucOutBuf[4] = pstCp56->ucWeek; + pucOutBuf[5] = pstCp56->ucMonth; + pucOutBuf[6] = pstCp56->ucYear; + } + + return 7; +} + +/* + * Prototype : CP56Time2a_GetFromBuf + * Description : 从缓冲解析Cp56时间 + * @param[in] : const unsigned char *pucInBuf + * @param[in] : __CP56Time2a *pstCp56 + * @param[out] : None + * @Return : 0=失败 1=成功 + * + * + * + * History : + * 1.Date : 2023/6/6 + * Author : wqw + * Modification : Created function + * + */ +unsigned char CP56Time2a_GetFromBuf(const unsigned char *pucInBuf, __CP56Time2a *pstCp56) +{ + if(NULL == pstCp56) + { + return 0; + } + + pstCp56->ucLMs = pucInBuf[0]; + pstCp56->ucHMs = pucInBuf[1]; + pstCp56->ucMin = pucInBuf[2]; + pstCp56->ucHour = pucInBuf[3]; + pstCp56->ucWeek = pucInBuf[4]; + pstCp56->ucMonth = pucInBuf[5]; + pstCp56->ucYear = pucInBuf[6]; + return 1; +} + +/* + * Prototype : IntBytes_Pack2Buf + * Description : 按字节数打包Int数据 + * @param[in] : unsigned char *pucOutBuf + * @param[in] : unsigned int uiVal + * @param[in] : unsigned char ucSize + * @param[out] : None + * @Return : 封装字节数量 + * + * + * + * History : + * 1.Date : 2023/6/6 + * Author : wqw + * Modification : Created function + * + */ +unsigned char IntBytes_Pack2Buf(unsigned char *pucOutBuf, unsigned int uiVal, unsigned char ucSize) +{ + if(0 == ucSize || ucSize > 4) + { + return 0; + } + + for(unsigned char i = 0; i < ucSize; i++) + { + pucOutBuf[i] = uiVal; + uiVal >>= 8; + } + + return ucSize; +} + +/* + * Prototype : IntBytes_GetFromBuf + * Description : 按照字节大小从缓冲中获取Int数据 + * @param[in] : const unsigned char *pucInBuf + * @param[in] : unsigned char ucSize + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/6 + * Author : wqw + * Modification : Created function + * + */ +unsigned int IntBytes_GetFromBuf(const unsigned char *pucInBuf, unsigned char ucSize) +{ + unsigned int uiVal = 0; + + if(0 == ucSize || ucSize > 4) + { + return 0; + } + + for(unsigned char i = 0; i < ucSize; i++) + { + uiVal |= ((unsigned int)pucInBuf[i] << (i * 8)); + } + + return uiVal; +} + +/* + * Prototype : Float_Pack2Buf + * Description : 打包浮点数到缓冲 + * @param[in] : unsigned char *pucOutBuf + * @param[in] : float fVal + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/12 + * Author : wqw + * Modification : Created function + * + */ +unsigned char Float_Pack2Buf(unsigned char *pucOutBuf, float fVal) +{ + memcpy(pucOutBuf, &fVal, 4); + return 4; +} + +/* + * Prototype : Float_GetFromBuf + * Description : 缓冲获取浮点数 + * @param[in] : const unsigned char *pucInBuf + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/12 + * Author : wqw + * Modification : Created function + * + */ +float Float_GetFromBuf(const unsigned char *pucInBuf) +{ + float fVal = 0; + memcpy(&fVal, pucInBuf, 4); + return fVal; +} + +/* + * Prototype : U16_Pack2Buf + * Description : 打包无符号短整型到缓冲 + * @param[in] : unsigned char *pucOutBuf + * @param[in] : unsigned short usVal + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/12 + * Author : wqw + * Modification : Created function + * + */ +unsigned char U16_Pack2Buf(unsigned char *pucOutBuf, unsigned short usVal) +{ + memcpy(pucOutBuf, &usVal, 2); + return 2; +} + +/* + * Prototype : U16_GetFromBuf + * Description : 从缓冲获取无符号短整型 + * @param[in] : const unsigned char *pucInBuf + * @param[out] : None + * @Return : + * + * + * + * History : + * 1.Date : 2023/6/12 + * Author : wqw + * Modification : Created function + * + */ +unsigned short U16_GetFromBuf(const unsigned char *pucInBuf) +{ + unsigned short usVal = 0; + memcpy(&usVal, pucInBuf, 2); + return usVal; +} + + + +/***************************************内部函数*******************************/ diff --git a/src/protocol/lib60870/src/md5.c b/src/protocol/lib60870/src/md5.c new file mode 100644 index 0000000..8d13d7d --- /dev/null +++ b/src/protocol/lib60870/src/md5.c @@ -0,0 +1,347 @@ +//#include +#include +#include +#include +#include +#include +#include "md5.h" + +static void MD5Transform PROTO_LIST((UINT4 [4], unsigned char [64])); +static void MD5_memcpy PROTO_LIST((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST((POINTER, int, unsigned int)); +static void MD5Init PROTO_LIST((MD5_CTX *)); +static void MD5Update PROTO_LIST((MD5_CTX *, unsigned char *, unsigned int)); +static void MD5Final PROTO_LIST((unsigned char [16], MD5_CTX *)); +static void Encode PROTO_LIST((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST((UINT4 *, unsigned char *, unsigned int)); + +static unsigned char PADDING[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static void MD5Init(MD5_CTX *context) +{ + context->count[0] = context->count[1] = 0; + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +static void MD5Update( + MD5_CTX *context, /* context */ + unsigned char *input, /* input block */ + unsigned int inputLen /* length of input block */ +) +{ + unsigned int i, index, partLen; + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + if((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + { + context->count[1]++; + } + + context->count[1] += ((UINT4)inputLen >> 29); + partLen = 64 - index; + + if(inputLen >= partLen) + { + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform(context->state, context->buffer); + + for(i = partLen; i + 63 < inputLen; i += 64) + { + MD5Transform(context->state, &input[i]); + } + + index = 0; + } + else + { + i = 0; + } + + MD5_memcpy + ((POINTER)&context->buffer[index], (POINTER)&input[i], + inputLen - i); +} + +static void MD5Final( + unsigned char digest[16], /* message digest */ + MD5_CTX *context /* context */ +) +{ + unsigned char bits[8] = {0}; + unsigned int index = 0, padLen = 0; + Encode(bits, context->count, 8); + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update(context, PADDING, padLen); + MD5Update(context, bits, 8); + Encode(digest, context->state, 16); + MD5_memset((POINTER)context, 0, sizeof(*context)); +} + +static void MD5Transform( + UINT4 state[4], + unsigned char block[64] +) +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + Decode(x, block, 64); + /* Round 1 */ + FF(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + /* Round 2 */ + GG(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + /* Round 3 */ + HH(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + /* Round 4 */ + II(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + MD5_memset((POINTER)x, 0, sizeof(x)); +} + +static void Encode( + unsigned char *output, + UINT4 *input, + unsigned int len +) +{ + unsigned int i, j; + + for(i = 0, j = 0; j < len; i++, j += 4) + { + output[j] = (unsigned char)(input[i] & 0xff); + output[j + 1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j + 2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j + 3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +static void Decode( + UINT4 *output, + unsigned char *input, + unsigned int len +) +{ + unsigned int i = 0, j = 0; + + for(i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j + 1]) << 8) | + (((UINT4)input[j + 2]) << 16) | (((UINT4)input[j + 3]) << 24); +} + +static void MD5_memcpy( + POINTER output, + POINTER input, + unsigned int len +) +{ + unsigned int i = 0; + + for(i = 0; i < len; i++) + { + output[i] = input[i]; + } +} + +static void MD5_memset( + POINTER output, + int value, + unsigned int len +) +{ + unsigned int i = 0; + + for(i = 0; i < len; i++) + { + ((char *)output)[i] = (char)value; + } +} + +void StartMD5(MD5_CTX *context) +{ + MD5Init(context); +} + +void EncodeMD5(MD5_CTX *context, unsigned char *input, int len) +{ + MD5Update(context, input, len); +} + +void GetMD5(MD5_CTX *context, unsigned char *result) +{ + if(result == NULL) + { + return; + } + + MD5Final(result, context); +} + +void GetMD5String(MD5_CTX *context, char *result, unsigned char mode) +{ + unsigned char digest[16] = {0}; + char output1[33] = {0}; + + if(result == NULL) + { + return; + } + + MD5Final(digest, context); + + for(int i = 0; i < 16; i++) + { + sprintf(&(output1[2 * i]), "%02x", (unsigned char)digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char)(digest[i] << 4)); + } + + if(mode == MD5_BIT32) + for(int i = 0; i < 32; i++) + { + result[i] = output1[i]; + } + else if(mode == MD5_BIT16) + for(int i = 0; i < 16; i++) + { + result[i] = output1[8 + i]; + } +} + +/* */ +#if 0 +char *MD5String(char *string) +{ + MD5_CTX context = {0}; + unsigned char digest[16] = {0}; + char output1[33] = {0}; + static char output[33] = {""}; + unsigned int len = strlen(string); + int i = 0; + MD5Init(&context); + MD5Update(&context, (unsigned char *)string, len); + MD5Final(digest, &context); + + for(i = 0; i < 16; i++) + { + sprintf(&(output1[2 * i]), "%02x", (unsigned char)digest[i]); + sprintf(&(output1[2 * i + 1]), "%02x", (unsigned char)(digest[i] << 4)); + } + + for(i = 0; i < 32; i++) + { + output[i] = output1[i]; + } + + return output; +} + +static void StringAddOne(char *orstring) +{ + unsigned int len = 0; + int i = 0, n = 0; + len = strlen(orstring); + n = len - 1; + + for(i = n; i >= 0; i--) + { + if(orstring[i] == '9') + { + orstring[i] = 'A'; + break; + } + else if(orstring[i] == 'Z') + { + orstring[i] = 'a'; + break; + } + else if(orstring[i] == 'z') + { + orstring[i] = '0'; + continue; + } + else + { + orstring[i] += 1; + } + + break; + } +} + +bool MD5Check(char *md5string, char *string) +{ + return strcmp(md5string, MD5String(string)) == 0; +} + +#endif \ No newline at end of file