#ifndef C315_PROTOCOL_H #define C315_PROTOCOL_H #pragma once #include "GlobalHead.h" #include "AlarmDefine.h" #include #include #pragma pack(push, 1) #define FRAME_HEADER_315 "qknet" //帧头 #define FRAME_TYPE_HEARTBEAT 0x0F //心跳帧 #define FRAME_TYPE_DATA 0x8F //数据帧 #define FRAME_TAIL_315 0xFFFFFFFF //帧尾 //与JHD系统的通信协议 #define PROTOCAL_CODE 0x02 //协议码 #define PROTOCAL_DATAVERSION 0x01 //数据版本 //命令帧 应答帧 主动上送帧 回执帧等 enum FRAME_KIND { CMD = 0, RECV, SEND, BACK, GENERAL }; //scz 2022.11.09 新增 待补全 enum class E_315_PROTOCOL_TYPE : uint8_t { ACTIVE_KEEP = 0, //心跳包 E_315_PROTOCOL_0x23 = 0x23, //缺口配置 道岔缺口 E_315_PROTOCOL_0x26 = 0x26, //道岔缺口数值 E_315_PROTOCOL_0x27 = 0x27, //道岔缺口报警、预警及图像视频信息 E_315_PROTOCOL_0x29 = 0x29, //道岔缺口最新图像 E_315_PROTOCOL_0x32 = 0x32, //历史图像信息列表 E_315_PROTOCOL_0x2A = 0x2A, //历史图像信息 E_315_PROTOCOL_0x2E = 0x2E, //视频信息列表 E_315_PROTOCOL_0x2F = 0x2F, //视频文件 E_315_PROTOCOL_0x22 = 0x22, //1DQJ、区段状态信息 E_315_PROTOCOL_0x25 = 0x25, //油压曲线 E_315_PROTOCOL_0x24 = 0x24, //油位及缺口采集设备状态信息 E_315_PROTOCOL_0x30 = 0x30, //视频流信息 E_315_PROTOCOL_0x31 = 0x31, //请求命令时转辙机的定反位状态 //E_315_PROTOCOL_0x40 = 0x40, //全行程受力信息 全行程子系统占用 //E_315_PROTOCOL_0x41 = 0x41, //全行程最新值 //E_315_PROTOCOL_0x42 = 0x42, //服务端回执主动推送的全行程最新值. //E_315_PROTOCOL_0x43 = 0x43, //全行程预报警信息 //E_315_PROTOCOL_0x44 = 0x44, //服务端回执主动推送预报警信息 //E_315_PROTOCOL_0x45 = 0x45, //测试历史数据 //E_315_PROTOCOL_0x46 = 0x46, //查询曲线时间信息 //E_315_PROTOCOL_0x47 = 0x47, //查询曲线数据 //E_315_PROTOCOL_0x48 = 0x48, //服务端回执主动推送曲线数据 E_315_PROTOCOL_0x50 = 0x50, //受力配置信息 受力监测子系统 E_315_PROTOCOL_0x51 = 0x51, //受力最新值 E_315_PROTOCOL_0x52 = 0x52, //服务端回执主动推送的受力最新值 E_315_PROTOCOL_0x53 = 0x53, //受力预报警信息 E_315_PROTOCOL_0x54 = 0x54, //服务端回执主动推送预报警信息 E_315_PROTOCOL_0x55 = 0x55, //测试历史数据 E_315_PROTOCOL_0x56 = 0x56, //查询曲线时间信息 E_315_PROTOCOL_0x57 = 0x57, //查询曲线数据 E_315_PROTOCOL_0x58 = 0x58, //服务端回执主动推送曲线数据 //E_315_PROTOCOL_0x60 = 0x60, //框架配置信息 道岔框架系统 //E_315_PROTOCOL_0x61 = 0x61, //框架最新值 //E_315_PROTOCOL_0x62 = 0x62, //服务端回执主动推送的框架最新值 //E_315_PROTOCOL_0x63 = 0x63, //框架预报警信息 //E_315_PROTOCOL_0x64 = 0x64, //服务端回执主动推送预报警信息 //E_315_PROTOCOL_0x65 = 0x65, //测试历史数据 //E_315_PROTOCOL_0x66 = 0x66, //查询曲线时间信息 //E_315_PROTOCOL_0x67 = 0x67, //查询曲线数据 //E_315_PROTOCOL_0x68 = 0x68, //服务端回执主动推送曲线数据 }; //协议头 typedef struct CPTL_Head { BYTE sHead[5]; //帧头5B BYTE byProtocolCode; //协议码1B BYTE byDataVersion; //数据版本1B BYTE byFrameType; //帧类型1B DWORD dwFrameLen; //帧内容长度4B }CPTL_HEAD, * PCPTL_HEAD; enum class TIEDA_VAL_STATE : uint8_t { TVS_POLL = 0x00,//为轮询值,日常采集 TVS_MOVEING = 0x01,//扳动过程采集值 TVS_AFTER_MOVE = 0x02, //为扳动后采集值 TVS_PASSING = 0x03, //过车过程中采集值 TVS_AFTER_PASS = 0x04, //过车后采集值 }; enum class TIEDA_VAL_SYMBOL : uint8_t { TVS_POSITIVE_NUMBER = 0x00, TVS_MINUS_NUMBER = 0x01, }; //铁大采集值 /* 采用3字节定义一个采集值,D0~D15:采集数值,D16~D19:采集精度,D20~D22:值状态,D23:值正负。 采集精度:1=表示精度为1,即采集数值为实际的采集值. 2=表示精度为10,表示采集数值为实际采集值*10. 3=表示精度为100,表示表示采集数值为实际采集值*100. 4=表示精度为1000,表示表示采集数值为实际采集值*1000. 5=表示精度为0.1,表示表示采集数值为实际采集值/10. 6=表示精度为0.01,表示表示采集数值为实际采集值/100. 7=表示精度为0.001,表示表示采集数值为实际采集值/1000. 值状态:0=表示为轮询值,日常采集 1=表示扳动过程采集值 2=表示为扳动后采集值 3=表示过车过程中采集值 4=表示过车后采集值 值正负:0=正值 1=负值. 0xFFFFFF表示无效值,采集传感器故障、超量程异常、通讯丢失等; 当处于某状态时(例如扳动中,此时缺口值无效),状态值为1,精度不变,采集值填0xFFFF,表示在该状态下,采集值无意义; 例如: 采集值 byte val[3]={ 0x81,0x00,0x23}; 表示采集值为0x0081, 精度为3(100),状态为2(扳动后),正负为0(正值),实际值为(1.29f); 采集值 byte val[3]={ 0x81,0x00,0xA5}; 表示值为0x0081, 精度为5(0.1),状态为2(扳动后),正负为1(负值),实际值为-1290;*/ union TIEDA_ACQ_VALUE { //uint8_t value[3]; struct { uint16_t v; //值 默认 实际采集值/10 uint8_t precision : 4; //精度 默认5 TIEDA_VAL_STATE state : 3; //状态 TIEDA_VAL_SYMBOL symbol : 1; //符号 }; TIEDA_ACQ_VALUE(int32_t a, TIEDA_VAL_STATE b, uint8_t d = 5) { symbol = TIEDA_VAL_SYMBOL::TVS_POSITIVE_NUMBER; if (a <= -INVLID_VAL || a >= INVLID_VAL) { v = USHORT_MAX; } else if (a < 0) { a = -a; symbol = TIEDA_VAL_SYMBOL::TVS_MINUS_NUMBER; } precision = d; if (d == 5) v = a / 10; else v = a; state = b; } TIEDA_ACQ_VALUE(int a) { if (a == INT_MIN) memset(this, 0xff, 3); } TIEDA_ACQ_VALUE() { v = 0; precision = 5; state = TIEDA_VAL_STATE::TVS_POLL; symbol = TIEDA_VAL_SYMBOL::TVS_POSITIVE_NUMBER; } float tovalue() { BYTE* val = (BYTE*)this; if (val[0] == 0xFF && val[1] == 0xFF && val[2] == 0xFF) return INT_MIN; float n = v; if (symbol == TIEDA_VAL_SYMBOL::TVS_MINUS_NUMBER) n *= -1; switch (precision) { case 2: n /= 10.0; break; case 3: n /= 100.0; break; case 4: n /= 1000.0; break; case 5: n *= 10.0; break; case 6: n *= 100.0; break; case 7: n *= 1000.0; break; default: break; } return n; } string tostring() { float n = tovalue(); if (n == INT_MIN) return "无效值"; string msg; switch (state) { case TIEDA_VAL_STATE::TVS_POLL: msg = "日常采集:"; break; case TIEDA_VAL_STATE::TVS_MOVEING: msg = "扳动过程采集:"; break; case TIEDA_VAL_STATE::TVS_AFTER_MOVE: msg = "扳动后采集:"; break; case TIEDA_VAL_STATE::TVS_PASSING: msg = "过车中采集:"; break; case TIEDA_VAL_STATE::TVS_AFTER_PASS: msg = "过车后采集:"; break; default: break; } msg += to_string(n); return msg; } }; //道岔缺口配置信息(315) 命令码:0x23 typedef struct { BYTE cmdid; //命令码:0x23 WORD cfgcnt; //配置数 LPVOID lpcfg; //转辙机配置i }StGapCfgRes; //转辙机配置 typedef struct { BYTE nlen; //转辙机名称长度 LPSTR lpname; //转辙机名称 BYTE stype; //转辙机类型 WORD sid; //转辙机ID WORD cnt; //采集信息个数 LPWORD lpinfo; //采集信息类型 }StSwitchCfg; //道岔缺口配置信息 end //曲线信息 typedef struct { BYTE cmdid; //命令码:0x46/0x56/0x66 DWORD starttime; //开始时间 DWORD endtime; //结束时间 WORD cnt; //牵引点数目 LPVOID lpcfg; //牵引点配置 }StCurveCfgRes; //配置 typedef struct { WORD sid; //转辙机ID }StTractionCfg; //配置 typedef struct { WORD sid; //转辙机ID WORD cnt; //记录数目 LPVOID lpcrecord;//记录 }StTractionCfg1; //配置 typedef struct { DWORD time; //结束时间 }StTractionCfg11; //配置信息 end //配置信息 typedef struct { BYTE cmdid; //命令码:0x40/0x50/0x60 WORD cnt; //配置个数 LPVOID lpcfg; //配置信息 }StNodeCfgRes; typedef struct { BYTE namelen; //牵引点名称长度 LPSTR lpname; //牵引点名称 WORD sid; //牵引点ID BYTE cnt; //采集信息个数 WORD lpinfo[0]; //采集信息类型 }StNodeInfo; //配置 typedef struct { WORD acqTypeID; //采集信息类型码 }StNodeAcqCfg; struct NodeConfig { CString strNodeName; WORD wNodeID; std::vector vecAcqTypeID; }; struct NodeRealData { DWORD dwAcqTime; WORD wNodeID; BYTE byFixInvert; //定反位 std::vector vecAcqTypeID; std::vector vecStatus; std::vector vecAcqData; }; struct stQueryAlarm { BYTE cmdid; //命令码:0x43/0x53/0x63 DWORD starttime; //开始时间 DWORD endtime; //结束时间 WORD wNodeID; //牵引点ID =0xffff时表示查询所有设备 WORD wAlarmType; //报警类型 =0xffff时表示查询所有报警 }; struct stAlarmItem { WORD wNodeID; BYTE byAlarmType; //报警状态 DWORD time; //报警时间 DWORD dwRestoreTime; //恢复时间 WORD wAlarmType; //报警类型 //BYTE cbAlarmValue[3];//报警值 TIEDA_ACQ_VALUE sAlarmValue; //报警值 //BYTE cbRefValue[3]; //参考值 TIEDA_ACQ_VALUE sRefValue; //参考值 WORD wSuggestID; //维护建议ID }; //配置 struct stQueryHisDataItem { WORD wNodeID; //牵引点ID WORD acqTypeID; //采集信息类型码 }; struct stQueryHisData { BYTE cmdid; //命令码:0x45/0x55/0x65 DWORD starttime; //开始时间 DWORD endtime; //结束时间 WORD cnt; //数量 WORD lpinfo[0]; //采集信息类型 }; struct stQueryHisCurveList { BYTE cmdid; //命令码:0x46/0x56/0x66 DWORD starttime; //开始时间 DWORD endtime; //结束时间 WORD cnt; //数量 WORD lpinfo[0]; //采集信息类型 }; struct stQueryHisCurve { BYTE cmdid; //命令码:0x46/0x56/0x66 WORD wNodeID; //牵引点ID DWORD time; //时间 }; struct stHisStaticValue { DWORD dwStartTime; //起始时间 std::vector> vctAcqData; }; //心跳数据 typedef struct { DWORD hbtime; //时间: 4B的unix时间用于时钟同步 BYTE filldata[3]; //填充3个字节的0xFF }StHeartBeat315; #pragma pack(pop) typedef std::map MapTimeInt; typedef MapTimeInt::iterator MapTimeIntItor; class CCSM315Protocol { public: CCSM315Protocol(int nDataVersion/*CLinkAdmin* pLinkAdmin, const char* strLogName*/); virtual ~CCSM315Protocol(); static void InitFrmHead12B(BYTE* pBuf, BYTE frmtype, BYTE datVer); static void InitFrmHead12B(CPTL_HEAD* pHead, BYTE frmtype, BYTE datVer); static void InitFrmHead12B(C315CommData& CommData, BYTE frmtype, BYTE datVer); //buf:缓冲区 size:缓冲区大小 len:取出的数据长度 static BOOL GetFrameData(LPBYTE& buf, int& size, int& len); static std::string GetStrFromData(const BYTE* buf, int dwLen); public: static E_315_PROTOCOL_TYPE GetProtocolType(BYTE* pBuf, WORD wDataSize); static BOOL IsReceiptProtocol(E_315_PROTOCOL_TYPE e); static BOOL GetResendProtocol(E_315_PROTOCOL_TYPE e, int& nReSendCount, int& nReSendInterval); public: static BOOL Parse(StHeartBeat315&, LPVOID, int); //接收解析 public: static BOOL RecvParse(StGapCfgRes& data, LPVOID buf, int len); static BOOL RecvParse(StCurveCfgRes& data, LPVOID buf, int len, FRAME_KIND&e); //组装数据 public: static BOOL DataSerialize(BYTE byProtocalCMD, const std::vector& vecConfig, C315CommData& CommData); static BOOL DataSerialize(BYTE byProtocalCMD, const std::vector& vecConfig, C315CommData& CommData); static BOOL DataSerialize(BYTE byProtocalCMD, bool bPush, WORD wEqpNO, BYTE byFixOrNot, const std::vector& vctAcqType, const std::vector& vctData, const std::vector& vctStatus, const CTime& atime, C315CommData& CommData); //static BOOL DataSerialize(BYTE byProtocalCMD, bool bPush, int no, // WORD wIdx, int num, const std::vector& vctData0, // const std::vector& vctData1, const std::vector& vctData2, // DWORD atime, C315CommData& CommData); //static BOOL DataSerialize(BYTE byProtocalCMD, BYTE byFixOrNot, bool bPush, int no, WORD wEqpNO, int num, // const MapTimeIntItor& map00, const MapTimeIntItor& map01, // const MapTimeIntItor& map10, const MapTimeIntItor& map11, // const MapTimeIntItor& map20, const MapTimeIntItor& map21, // time_t time, C315CommData& CommData); static BOOL DataSerialize(BYTE byProtocalCMD, BYTE byFixOrNot, bool bPush, int no, WORD wEqpNO, int num, std::map* mapData[], time_t tmStartSecond, time_t tmEndSecond, C315CommData& CommData); static BOOL DataSerialize(BYTE byProtocalCMD, bool bPush, int no, const std::vector& vctAlarm, C315CommData& CommData); static BOOL DataSerialize(BYTE byProtocalCMD, const std::map>& mapData, C315CommData& CommData); ////first:makelong(牵引点, 采集码) second.first:采集时间 vector:采集数据列表 pair:偏移时间和采集值 static BOOL DataSerialize(BYTE byProtocalCMD, const std::map& mapData, C315CommData& CommData); public: static BOOL Release(StGapCfgRes&); static BOOL Release(StCurveCfgRes&, FRAME_KIND& e); private: static int m_CSMCmdRegion_DataVersion; }; #endif // !C315_PROTOCOL_H