Loading... 之前因个人爱好,开发了个MCCB的调试工具,现在用不到了,不忍放硬盘吃灰,就拿出来分享一下。 # 一.整体结构 采用Qt开发。 基于RS485串口总线通信。 采用占有式,占用485总线。 # 二.基本定义 ## 1.基础信息定义 ```c++ #pragma once #include <stdint.h> #include <type_traits> #include <QString> #define Mccb_XD_Name "Mccb_XD" #define Mccb_Normal_Name "Mccb_Normal" #define Mccb_Ptlk_Name "Mccb_ElPro" #define Packet_Max_Length 300 #define CMD_READ_DATA 0x11 #define CMD_READ_DATA_NEXT 0x12 #define CMD_READ_COMM_ADDR 0x13 #define CMD_WRITE_DATA 0x14 #define CMD_WRITE_COMM_ADDR 0x15 #define CMD_READ_ALARM 0x19 #define CMD_CTRL 0x1C #define Event_Record_Max 1 namespace Mccb { template <typename Enumeration> auto EnumtoValue(Enumeration const value) -> typename std::underlying_type<Enumeration>::type { return static_cast<typename std::underlying_type<Enumeration>::type>(value); } //返回值 enum class retack :int32_t { PacketNotOver = 0, //帧结构 packetErr, PacketSumCheckErr, packetOk, OkNoNext, //帧内容 OkNeedNext, UpdatePacketErr, RemoteCtrlErr, CommSpeedChangeErr, PasswordErr, NoneRequestData, illegalData, }; //A.2.1 当前变量 enum class DI : uint32_t { /*电压*/ Ua = 0x02010100, Ub = 0x02010200, Uc = 0x02010300, U = 0x0201FF00, /*电流*/ Ia = 0x02020100, Ib = 0x02020200, Ic = 0x02020300, I = 0x0202FF00, /*当前剩余电流*/ IresidualNowMaxPhase = 0x02900000, //当前剩余电流最大相 IresidualNow = 0x02900100, //当前剩余电流值 Iresidual = 0x0290FF00, /*当前额定剩余电流定值*/ Iei_residual = 0x02910100, Iet_residual = 0x02910200, Ie_residual = 0x0291FF00, /*电流*/ IwDirect = 0x02920100, Iwa = 0x02920200, Iwb = 0x02920300, Iwc = 0x02920400, Iw = 0x0292FF00, /*电能*/ Et = 0x00010000, //当前正向有功总电能 EtSub = 0x00020000, Ea = 0x00150000, ESuba = 0x00160000, Eb = 0x00290000, ESubb = 0x002A0000, Ec = 0x003D0000, ESubc = 0x003E0000, /*有功功率*/ Pt = 0x02030000, Pa = 0x02030100, Pb = 0x02030200, Pc = 0x02030300, P = 0x0203FF00, /*无功功率*/ Qt = 0x02040000, Qa = 0x02040100, Qb = 0x02040200, Qc = 0x02040300, Q = 0x0204FF00, /*功率因数*/ Pft = 0x02060000, Pfa = 0x02060100, Pfb = 0x02060200, Pfc = 0x02060300, Pf = 0x0206FF00, /*谐波*/ HVa_1 = 0x020A0101, HVb_1 = 0x020A0201, HVc_1 = 0x020A0301, HAa_1 = 0x020B0101, HAb_1 = 0x020B0201, HAc_1 = 0x020B0301, /*频率 温度*/ Hz = 0x02800002, Tin = 0x02800007, T_1 = 0x0280000B, T_2 = 0x0280000C, T_3 = 0x0280000D, T_4 = 0x0280000E, T_5 = 0x0280000F, T_6 = 0x02800010, T_7 = 0x02800011, T_8 = 0x02800012, HzT = 0x028000FF, //A.2.2 累计记录 ResetNum = 0x03300100, //数据清零总次数 TotalTripNum = 0x03810000, //总跳闸次数 IresidualUnTripNum = 0x03810001, //剩余电流闭锁跳闸次数 IresidualProtTripNum = 0x03810002, //剩余电流保护跳闸次数 OverloadProtTripNum = 0x03810003, //过载保护跳闸次数 HighVProtTripNum = 0x03810004, //过压保护跳闸次数 HandyTripNum = 0x03810005, //手动跳闸次数 LossZeroProtTripNum = 0x03810006, //缺零保护跳闸次数 TestTripNum = 0x03810007, //试验跳闸次数(远程、按键) SCDProtTripNum = 0x03810008, //短路短延时跳闸次数 SIProtTripNum = 0x03810009, //短路瞬时跳闸次数 LowVProtTripNum = 0x0381000A, //欠压保护跳闸次数 LossVProtTripNum = 0x0381000B, //缺相保护跳闸次数 TripNum = 0x038100FF, //跳闸数据块 TotalRunTime = 0x03810101, //断路器运行时间总累计 AbnormalOccurNum = 0x03810201, //异常告警发生/恢复新增次数 ProtectionDropNum = 0x03810202, //保护功能退出/恢复新增次数 HPowerOffNum = 0x03810203, //高压线路失/复电新增次数 BrokerChangeNum = 0x03810204, //闸位状态变化新增次数 SelfInspectionNum = 0x03810205, //自检事件新增次数 ProtectedEventNum = 0x03810206, //保护动作事件新增次数 EventNum = 0x038102FF, //事件数据块 //A.2.3 日最大值、最小值记录 /*最大值*/ IresidualDayMax_1 = 0x03820001, UaDayMax_1 = 0x03820101, UbDayMax_1 = 0x03820201, UcDayMax_1 = 0x03820301, IaDayMax_1 = 0x03820701, IbDayMax_1 = 0x03820801, IcDayMax_1 = 0x03820901, /*最小值*/ IresidualDayMin_1 = 0x03830001, UaDayMin_1 = 0x03830101, UbDayMin_1 = 0x03830201, UcDayMin_1 = 0x03830301, IaDayMin_1 = 0x03830701, IbDayMin_1 = 0x03830801, IcDayMin_1 = 0x03830901, Residual_1 = 0x03840101, //剩余电流曲线记录块(参见附录C,每日96点分成2段记录块) SelfInspectionEvent_1 = 0x038D0001, //断路器自检事件记录 ProtectedEvent_1 = 0x038E0001, //保护动作事件记录 ProtectionDropEvent_1 = 0x038F0001, //保护功能投退事件记录 BrokerChangeEvent_1 = 0x03910001, //闸位变化事件记录 AlarmEvent_1 = 0x03920001, //告警事件记录 HPowerOffEvent_1 = 0x03930001, //高压失/复电事件记录 /*定时冻结*/ TimerFrozenTime_1 = 0x05000001, TimerFrozenESub_1 = 0x05000101, TimerFrozenERev_1 = 0x05000201, TimerFrozen_1 = 0x0500FF01, /*瞬时冻结*/ InstFrozenTime_1 = 0x05010001, InstFrozenESub_1 = 0x05010101, InstFrozenERev_1 = 0x05010201, InstFrozen_1 = 0x0501FF01, /*时间*/ Date = 0x04000101, Time = 0x04000102, /*固有参数*/ CommAddr = 0x04000401, //通信地址 DevNum = 0x04000402, //设备号 AssetNum = 0x04000403, //资产管理编码 Ue = 0x04000404, //额定电压 In = 0x04000405, //额定电流/基本电流(In) Inm = 0x04000406, //最大(壳架)电流(Inm) DevModel = 0x0400040B, //设备型号 ProductTime = 0x0400040C, //生产日期 ProtVer = 0x0400040D, //协议版本号 ManuID = 0x0400040E, //厂家工厂代码 FirewareVer = 0x0400040F, //厂家固件版本号 HardwareVer = 0x04000410, //厂家硬件版本号 Ieris = 0x04000411, //额定剩余电流动作值参数组 Ierts = 0x04000412, //额定极限不驱动时间参数组 AutoRecloseTime = 0x04000414, //自动重合闸时间范围 ResidualFeatures = 0x04000415, //剩余电流动作特性(A型或AC型) InstalledPhase = 0x04000416, //安装相位别(只适用单相断路器) RunState_1 = 0x04000501, RunState_2 = 0x04000502, RunState = 0x040005FF, CommSpeed = 0x04000703, PassWord_1 = 0x04000C01, PassWord_2 = 0x04000C02, PassWord_3 = 0x04000C03, CtrlWord_1 = 0x04001001, CtrlWord_2 = 0x04001002, CtrlWord_3 = 0x04001003, CtrlWord_4 = 0x04001004, CtrlWord_5 = 0x04001005, CtrlWord = 0x040010FF, ResidualOverSV = 0x04001101, //剩余电流超限报警整定值(弃用) ResidualAWarningSV = 0x04001104, //剩余电流预警限值(缺省为60%) ResidualTWarningSV = 0x04001105, //剩余电流超预警/超限限值持续时长(缺省为60s) ResidualSV = 0x040011FF, //剩余电流整定参数块 TimerSelfInspectionTime = 0x04001201, //定时自检整定时间 TimerSelfInspection = 0x040012FF, //定时自检整定参数块 OverVoltageSV = 0x04001301, //过电压整定值 LowVoltageSV = 0x04001302, //欠电压整定值 LossVoltageSV = 0x04001303, //断相电压整定值 /*<!----xx增加内容 2021.07.08*/ OverVoltageReplaySV = 0x04001304, //过压返回整定值 LowVoltageReplaySV = 0x04001305, //欠压返回整定值 OverVoltageTimeSV = 0x04001306, //过压保护动作延时时间设定值 OverVoltageReplayTimeSV = 0x04001307, //过压保护返回延时时间设定值 LowVoltageTimeSV = 0x04001308, //欠压保护动作延时时间设定值 LowVoltageReplayTimeSV = 0x04001309, //欠压保护返回延时时间设定值 /*------->*/ VoltageParam = 0x040013FF, //电压整定参数块 Ir1SV = 0x04001401, //额定电流整定值过载保护动作电流Ir1 IoSV = 0x04001402, //负荷电流超限报警整定值(﹡0.1In)(弃用) T1SV = 0x04001403, //过载保护动作时间t1 /*<!----湘电增加内容 2021.07.08*/ Ir2SV = 0x04001404, //短路短延时动作电流Ir2 (*Ir1) T2SV = 0x04001405, //短路短延时动作时间t2 ItSV = 0x04001406, //0反时限+定时限,1为定时限 Ir3SV = 0x04001407, //短路瞬时电流Ir3 (*Ir1) T3SV = 0x04001408, //短路瞬时延时动作时间t3 /*------->*/ IParam = 0x040014FF, //电流整定参数块 /*<!----xx增加内容 2021.07.08*/ TempSV = 0x04001601, //温度保护动作设定值 TempTimeSV = 0x04001602, //温度保护动作延时时间设定值 TempReplaySV = 0x04001603, //温度保护返回设定值 TempReplayTimeSV = 0x04001604, //温度保护返回延时时间设定值 TempProt = 0x040016FF, //温度保护参数块 /*------->*/ AppRemoteBreake = 0x06010101, //预约远程跳闸控制(0-99) CancelRemoteBreake = 0x06010102, //取消远程跳闸控制 AppRemoteClose = 0x06010201, //预约远程合闸控制(0-99) CancelRemoteClose = 0x06010202, //取消远程合闸控制 AppMonitorBreake = 0x06010301, //预约模拟试跳控制(0-99) CancelMonitorBreake = 0x06010302, //取消模拟试跳控制 AppSelfInspection = 0x06010401, //预约自检 CancelSelfInspection = 0x06010402, //取消预约自检 RequestRemoteUpdate = 0x0F0F0F01, //主站升级数据发送请求 RemoteUpdateData = 0x0F0F0F02, //主站下发数据帧 RemoteUpdateFinished = 0x0F0F0F03, //主站发送完成帧,DATA=55H,表示确认升级;DATA=AAH,表示放弃升级; }; #pragma pack(1) typedef struct _commspeed { uint8_t Reserve : 2; //保留 uint8_t bps9600 : 1; uint8_t bps4800 : 1; uint8_t bps2400 : 1; uint8_t Reserve1 : 3; //保留 } commspeed; #pragma pack() typedef struct _MqttData { uint32_t dataIndex; QString Value; uint64_t Time; }MqttData; typedef struct _MqttSendData { QString Name; QString Value; uint64_t Time; }MqttSendData; enum class OpType { Idle, Read, Write, ReadCommAddr, WriteCommAddr, Frozen, BroadcastTime, WriteCommSpeed, WritePassword, ExceptAlarm, DataErase, Command, Update }; typedef struct _cmd_t { OpType type; uint32_t di; }cmd_t; enum class param_ope_state { waitingDownload = 0, waitingResponce, Success, Fail, }; typedef struct _param_ope_t { param_t paramInfo; QString paramValue; //时间 uint8_t opeCode[4]; param_ope_state paramDownloadState = param_ope_state::waitingDownload; }param_ope; typedef struct _ctrl_cmd_t { uint32_t ctrl_di; uint8_t ctrl_time_data; uint8_t ctrl_time_type; uint8_t opcode[4]; }ctrl_cmd; } ``` ## 2.MCCB设备定义 ### 2.1接口定义 ```c++ #pragma once #include "MccbDefine.h" #include <QObject> #include <qmap.h> #include <QList> #include <qqueue.h> using namespace Mccb; #define Ten2Hex(c) ((c) / 10 * 16 + (c) % 10) //十进制转十六进制 #define Hex2Ten(c) ((c) / 16 * 10 + (c) % 16) //十六进制转十进制 #define TimeNow ((uint64_t)QDateTime::currentDateTime().toSecsSinceEpoch()) //获取当前时间 class MccbBase : public QObject { Q_OBJECT public: MccbBase(uint8_t* addr,QString devType,QObject *parent=nullptr); ~MccbBase(); QString GetType() {return m_DevTye;} //状态轮询 virtual quint16 StateLooper(uint8_t* buffer) =0; //字节解析 virtual retack MessageHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen) =0; //后续帧字节解析 virtual uint16_t MessageNextBufferHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen, uint8_t* nextBuf) =0; //控制 virtual bool ctrlCommand(QString cmdName, uint8_t* opcode, QString timedata, QString timeType) =0; virtual QString getParam(QString paramName) =0; virtual void callAllYc()=0; virtual void callAllYx()=0; virtual void callAllSum() = 0; virtual void callAllExt() = 0; virtual void callAllParam() = 0; //参数 virtual bool paramChange(QString paramName, QString paramValue,uint8_t* opcode)=0; /*公共功能函数*/ QString GetAddr() { return Utils::Char2Hex_Reverse(m_Address,6); } void AddCmd2Que(const cmd_t& c); /*基础功能函数*/ static QString getErrMsg(retack word); static retack isPacketFrame(const uint8_t* buf, uint16_t len); static uint16_t getPacketLen(const uint8_t* buf, uint16_t len); static uint8_t calcSum(const uint8_t* pDest, uint16_t len); static QString getSlaveAddr(const uint8_t* buf, uint16_t len); static float parseBCDValue(uint8_t* pBuf, uint8_t len, float factor); static uint32_t parseBCDValue_u(uint8_t* pBuf, uint8_t len); static uint64_t time_int8u2int64(uint8_t* time); static QString parseEventCot(uint8_t _cot); static uint32_t parseEventCot2Int(uint8_t _cot); static QString PaseAscii(char* data, uint8_t len); //************************************ // Method: ParamPack // FullName: Utils::ParamPack // Access: public // Returns: QByteArray // Qualifier: 将参数值转为QByteArray // Parameter: QString 原始字符串值 // Parameter: uint8_t 目标参数类型,1:BCD编码,2:Ascii编码,3:bin二进制数据 // Parameter: uint8_t 目标数据长度 // Parameter: uint8_t 小数点位数,只有目标参数类型为BCD编码时使用 //************************************ static QByteArray ParamPack(QString str, uint8_t dataType, uint8_t dataLen, uint8_t ratoNum = 0); enum class Cot :uint8_t { PTLK_PreAlm = 0b00001, //剩余电流预警 PTLK_Alm = 0b00010, //剩余电流告警 PTUV_Zero_Alm = 0b00100, //缺零告警 PTOC_Ovld_Alm = 0b00101, //过载告警 PTOC_Dly_Alm = 0b00110, //短路短延时告警 PIOC_Alm = 0b10110, //短路瞬时告警 PTUV_Loss_Alm = 0b00111, //缺相告警 PTUV_Alm = 0b01000, //欠压告警 PTOV_Alm = 0b01001, //过压告警 PG_Alm = 0b01010, //接地告警 Temp_Alm = 0b10100, //温度保护告警 RREC_Lock = 0b01111, //重合闸闭锁 RREC_Op = 0b11000, //重合闸动作 PwrOff_On = 0b01011, //停/复电 SwOn_Failure = 0b10001, //合闸失败告警 SwOff_Failure = 0b10111, //跳闸失败 Ct_Fault = 0b10000, //互感器故障 LocalManual_Op = 0b10010, //手动 SetChange = 0b10011, //设置更改 SoftRemoteCtrl_Op = 0b11110, //软遥控 HardRemoteCtrl_Op = 0b11101, //硬遥控 RemoteTest = 0b01101, //远程试验 LocalKeyTest = 0b01110 //按键试验 }; Q_ENUM(Cot) enum class func_code : uint8_t { Reserve = 0, //保留 Broadcast_Time = 0b01000, //广播校时 Read_Data = 0b10001, //读数据 Read_Data_Next = 0b10010, //读后续数据 Read_Data_Comm = 0b10011, //读通信地址 Write_Data = 0b10100, //写数据 Write_Data_Comm = 0b10101, //写通信地址 Write_Data_Frozen = 0x16, //冻结命令 Write_Data_Speed = 0b10111, //写通信速率 Write_Data_PassWord = 0b11000, //写密码 Dev_Alarm = 0b11001, //设备告警 Dev_Alarm_Reply = 0b11010, //设备告警应答 Dev_Event_Reset = 0b11011, //事件清零 Dev_Ctrl = 0b11100, //设备控制 Dev_Update = 0b11101, //软件升级 }; Q_ENUM(func_code) public: uint32_t m_overTimes = 0; bool callYc = false; bool callYx = false; bool callParam = false; bool callSum = false; bool callExt = false; protected: QMap<QString, uint32_t>Transfer; uint8_t m_Address[6]; uint8_t nextIndex = 0; QQueue<cmd_t> m_cmd_que; //MccbTime_t m_MccbTime; //QList<param_t>m_paramList; QQueue<param_ope>m_paramOpeVec; QQueue<ctrl_cmd>m_ctrlCmdVer; QString m_DevTye; DevDefineInfo* m_pDevDefineInfo; Q_SIGNALS: void updateValue(QString addr, QList<MqttData>& data); void updateYxValue(QString addr, QList<MqttData>& data); void updateParamsValue(QString addr, QList<MqttData>& data); }; ``` ```c++ #include "MccbBase.h" #include <qlist.h> #include <QMetaEnum> #include <QDateTime> using namespace Utils; #pragma execution_character_set("utf-8") QStringList errMsgDefine = {"PacketNotOver","packetErr", "PacketSumCheckErr", "OkNoNext", "OkNeedNext", "UpdatePacketErr", "RemoteCtrlErr", "CommSpeedChangeErr", "PasswordErr", "NoneRequestData", "illegalData"}; QMap< uint8_t,uint32_t> CotIndex = { {0b00001,1101},{0b00010,1102},{0b00100,1103},{0b00101,1104}, {0b00110,1105},{0b10110,1106},{0b00111,1107},{0b01000,1108}, {0b01001,1109},{0b01010,1110},{0b10100,1111},{0b01111,1113}, {0b11000,1114},{0b01011,1201},{0b10001,1301},{0b10111,1302}, {0b10000,1303},{0b10010,1401},{0b10011,1402},{0b11110,1403}, {0b11101,1404},{0b01101,1405},{0b01110,1406} }; MccbBase::MccbBase(uint8_t* addr, QString devType, QObject* parent) : QObject(parent) { if (addr == nullptr) memset(m_Address, 0, 6); else memcpy(m_Address, addr, 6); m_DevTye = devType; } MccbBase::~MccbBase() { } void MccbBase::AddCmd2Que(const cmd_t& c) { bool b = false; for (auto it : m_cmd_que) { if (it.di == c.di && it.type == c.type) { b = true; break; } } if (!b) { m_cmd_que.enqueue(c); } } QString MccbBase::getErrMsg(retack word) { auto k = EnumtoValue(word); if (k >= errMsgDefine.count()) return "UndefineErr"; return errMsgDefine[k]; } //报文结构判断 retack MccbBase::isPacketFrame(const uint8_t* buf, uint16_t len) { retack ret = retack::packetOk; if (buf[0] != 0x68) return retack::packetErr; if (len < 10) return retack::PacketNotOver; if (buf[7] != 0x68) return retack::packetErr; uint8_t dataLen = buf[9]; uint16_t packetLen = dataLen + 12; if (len < packetLen) return retack::PacketNotOver; if (buf[packetLen - 1] != 0x16) //结束字符判断 return retack::packetErr; if (calcSum(&buf[0], packetLen - 2) != buf[packetLen - 2]) //和校验判断 return retack::PacketSumCheckErr; return retack::packetOk; } uint16_t MccbBase::getPacketLen(const uint8_t* buf, uint16_t len) { auto frame = isPacketFrame(buf, len); if (frame == retack::packetOk || frame == retack::PacketSumCheckErr) return buf[9] + 12; return 0; } uint8_t MccbBase::calcSum(const uint8_t* pDest, uint16_t len) { uint8_t sum = 0; while (len--&&pDest) { sum += *pDest; pDest++; } return sum; } QString MccbBase::getSlaveAddr(const uint8_t* buf, uint16_t len) { uint8_t addr[6] = "\0"; memcpy(addr, &buf[1], 6); return Char2Hex_Reverse(addr, 6); } //BCD码解析 float MccbBase::parseBCDValue(uint8_t* pBuf, uint8_t len, float factor) { if (pBuf == nullptr || len <= 0 || len > 4) { return -1.0; } bool isNegative = (pBuf[len - 1] >> 7) == 1 ? true : false; pBuf[len - 1] &= 0x7F; //转为int32 int32_t value = 0; for (int i = 0; i < len; i++) { if (i == 0) value += Hex2Ten(pBuf[i]); else if (i == 1) value += 100 * Hex2Ten(pBuf[i]); else if (i == 2) value += 10000 * Hex2Ten(pBuf[i]); else if (i == 3) value += 1000000 * Hex2Ten(pBuf[i]); } if (!isNegative) return factor * ((float)value); else return -1.0 * factor * ((float)value); } uint32_t MccbBase::parseBCDValue_u(uint8_t* pBuf, uint8_t len) { if (pBuf == nullptr || len <= 0 || len > 4) { return 0; } //转为int32 uint32_t value = 0; for (int i = 0; i < len; i++) { if (i == 0) value += Hex2Ten(pBuf[i]); else if (i == 1) value += 100 * Hex2Ten(pBuf[i]); else if (i == 2) value += 10000 * Hex2Ten(pBuf[i]); else if (i == 3) value += 1000000 * Hex2Ten(pBuf[i]); } return value; } uint64_t MccbBase::time_int8u2int64(uint8_t* data) { //uint8_t tmp[6] = "0"; /*for (int i = 0; i < 6; i++) { tmp[i] = data[i] / 16 * 10 + data[i] % 16; }*/ //转换为格式化文本 QString time = QString("%1-%2-%3 %4:%5:%6") .arg(Hex2Ten(data[5]) + 2000, 4) .arg(Hex2Ten(data[4]), 2, 10, QChar('0')) .arg(Hex2Ten(data[3]), 2, 10, QChar('0')) .arg(Hex2Ten(data[2]), 2, 10, QChar('0')) .arg(Hex2Ten(data[1]), 2, 10, QChar('0')) .arg(Hex2Ten(data[0]), 2, 10, QChar('0')); QDateTime dateTime; return (uint64_t)dateTime.fromString(time, "yyyy-MM-dd hh:mm:ss").toSecsSinceEpoch(); } QString MccbBase::parseEventCot(uint8_t _cot) { QMetaEnum metaE = QMetaEnum::fromType<Cot>(); if (metaE.valueToKey(_cot) == nullptr) return QString(""); return QString(metaE.valueToKey(_cot)); } uint32_t MccbBase::parseEventCot2Int(uint8_t _cot) { if (CotIndex.contains(_cot)) return CotIndex[_cot & 0b11111]; return 0; } QString MccbBase::PaseAscii(char* data, uint8_t len) { return QString::fromLatin1(data, len).trimmed(); } QByteArray MccbBase::ParamPack(QString str, uint8_t dataType, uint8_t dataLen, uint8_t ratoNum /*= 0*/) { QByteArray byte; if (dataLen <= 0 || dataType <= 0 || dataType >= 4) return byte; uint8_t* buffer = new uint8_t[dataLen]; str = str.trimmed(); switch (dataType) { case 1: //BCD码 { memset(buffer, 0, dataLen); uint64_t udata = 0; bool isNegative = false; if (!str.contains('.')) //确保数据精度 { int64_t f = str.toLongLong(); while (ratoNum > 0) { f *= 10; ratoNum--; } isNegative = f < 0 ? true : false; udata = (isNegative == true) ? (uint64_t)(0 - f) : (uint64_t)f; } else { double f = str.toFloat(); //小数点位置移动 while (ratoNum > 0) { f *= 10; ratoNum--; } isNegative = f < 0 ? true : false; udata = (isNegative == true) ? (uint64_t)(0 - f) : (uint64_t)f; } //bool isNegative = f < 0 ? true : false; uint8_t index = 0; //按字节处理 while (index < dataLen) { uint64_t tmpData = udata / 100; buffer[index] = Ten2Hex(udata - 100*tmpData); udata = tmpData; index++; if (tmpData == 0) break; } //负数位处理 if (isNegative) buffer[dataLen - 1] |= 0x80; byte = QByteArray((const char*)buffer, dataLen); break; } case 2: { //空格占位 memset(buffer, 0x20, dataLen); auto tmpByte = str.toLatin1(); memcpy(buffer, tmpByte.data(), tmpByte.length()<dataLen?tmpByte.length():dataLen); byte = QByteArray((char*)buffer, dataLen); break; } case 3: { if (dataLen == 1) { buffer[0] = str.toShort() & 0xFF; byte = QByteArray((char*)buffer, dataLen); } break; } default: break; } delete[] buffer; return byte; } ``` ### 2.2 子类定义 ```c++ #pragma once #include "MccbBase.h" #include <QList> class Mccb_XD : public MccbBase { Q_OBJECT public: Mccb_XD(uint8_t* addr, QString devType, QObject* parent); ~Mccb_XD(); quint16 StateLooper(uint8_t* buffer) override; retack MessageHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen) override; uint16_t MessageNextBufferHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen, uint8_t* nextBuf) override; //控制 bool ctrlCommand(QString cmdName, uint8_t* opcode, QString timedata, QString timeType) override; //参数 bool paramChange(QString paramName, QString paramValue, uint8_t* opcode)override; QString getParam(QString paramName)override; void callAllYc()override; void callAllYx()override; void callAllSum()override; void callAllExt()override; void callAllParam()override; //QString GetType()override { return Mccb_XD_Name; } uint32_t getOverTimes() { return m_overTimes; } private: uint16_t packetFrame(uint8_t* buf, uint8_t c,uint8_t len); //组包 uint16_t readData(uint8_t* buf, uint32_t di); uint16_t readDataNext(uint8_t* buf, uint32_t di); uint16_t writeData(uint8_t* buf, param_ope p); uint16_t readParam(uint8_t* buf, uint32_t di); uint16_t writeParam(uint8_t* buf, uint32_t di, QString paramValue); uint16_t writeParam(uint8_t* buf, uint32_t di, uint8_t* paramValue, uint8_t paramLen); uint16_t readCommAddr(uint8_t* buf); uint16_t writeCommAddr(uint8_t* buf, uint8_t* addr); uint16_t frozenCmd(uint8_t* buf, uint8_t* timeData, uint8_t* addr = nullptr); uint16_t timeBroadcast(uint8_t* buf); uint16_t changeCommSpeed(uint8_t* buf, commspeed speed); uint16_t changePassword(uint8_t* buf, uint32_t di, uint8_t* newPassword); uint16_t readAlarm(uint8_t* buf); uint16_t dataReset(uint8_t* buf, uint32_t di); uint16_t cmdAction(uint8_t* buf, ctrl_cmd &cmd); uint16_t updateAction(uint8_t* buf, uint32_t di, uint8_t* fileData, uint8_t len); //解包 retack readDataHandler(uint8_t* buf, uint8_t len); retack readDataNextHandler(uint8_t* buf, uint8_t len); retack readCommAddrHandler(uint8_t* buf, uint8_t len); retack writeSpeedHandler(uint8_t* buf, uint8_t len); retack changePasswordHandler(uint8_t* buf, uint8_t len); retack readAlarmHandler(uint8_t* buf, uint8_t len); retack dataResetHandler(uint8_t* buf, uint8_t len); retack eventHandler(uint32_t di,uint8_t* buf, uint8_t len, QList<MqttData>&); //状态字、控制字 -- 解析 bool getStateWordStr(uint8_t word, uint8_t type, std::string name[], std::string value[]); bool getCtrlWordStr(uint8_t word, uint8_t type, std::string name[], std::string value[]); bool getBrokerChangeStr(uint8_t word, uint8_t type, std::string name[], std::string value[]); bool getAlarmStr(uint8_t word, std::string name[], std::string value[]); uint32_t getCotIndex(uint8_t cot); private: uint8_t m_NextIndex = 0; //uint8_t m_Address[6] = "\0"; uint8_t m_PassWord_0[4] = { 0 }; uint8_t m_PassWord_1[4] = { 0 }; uint8_t m_PassWord_2[4] = { 0 }; uint8_t m_OperatorCode[4] = { 0 }; QString m_AddrStr; uint32_t m_NowParamDI = 0; uint32_t g_AlamAddrs[25] = { 1101,1102,1103,1104,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1201,1301,1302,1303,1304,1401,1402,1403,1404,1405,1406 }; }; ``` ```c++ #include "Mccb_XD.h" #include "Utils.h" #include <QDebug> #include <QDateTime> #include <QMetaEnum> #define Packet_Max_Length 300 #define CMD_READ_DATA 0x11 #define CMD_READ_DATA_NEXT 0x12 #define CMD_READ_COMM_ADDR 0x13 #define CMD_WRITE_DATA 0x14 #define CMD_WRITE_COMM_ADDR 0x15 #define CMD_READ_ALARM 0x19 //#define Event_Record_Max 1 using namespace Utils; #pragma execution_character_set("utf-8") Mccb_XD::Mccb_XD(uint8_t* addr, QString devType, QObject* parent) : MccbBase(addr, devType, parent) { m_AddrStr = Char2Hex_Reverse(addr, 6); m_pDevDefineInfo = nullptr; for (auto &it : CfgHlp->DevLists) { if (it.devAddr == m_AddrStr) { m_pDevDefineInfo = break; } } if (m_pDevDefineInfo == nullptr) { qCritical() << "can't get DevDefineInfo!!!"; exit(0); } } Mccb_XD::~Mccb_XD() { } quint16 Mccb_XD::StateLooper(uint8_t* buffer) { if (buffer == nullptr) return 0; uint16_t buffLen = 0; uint64_t now = TimeNow; if (m_ctrlCmdVer.count() > 0) { auto cmd = m_ctrlCmdVer.dequeue(); qInfo() << " \t下发控制指令->DI:" << QString::number(cmd.ctrl_di, 16)<<"\ttime:" << (int)cmd.ctrl_time_data<<"\ttimeType:" << (int)cmd.ctrl_time_type; buffLen = cmdAction(buffer,cmd); } else if (m_paramOpeVec.size() > 0) { auto p = m_paramOpeVec.dequeue(); buffLen = writeData(buffer, p); m_NowParamDI = p.paramInfo.DI; } else if (m_cmd_que.size() > 0) { auto cmd = m_cmd_que.dequeue(); switch (cmd.type) { case OpType::Read: buffLen = readData(buffer, cmd.di); break; case OpType::Write: //buffLen = writeData(buffer, cmd.di); break; case OpType::ReadCommAddr: buffLen = readCommAddr(buffer); break; case OpType::WriteCommAddr: break; case OpType::Frozen: break; case OpType::BroadcastTime: break; case OpType::WriteCommSpeed: break; case OpType::WritePassword: break; case OpType::ExceptAlarm: break; case OpType::DataErase: break; case OpType::Command: break; case OpType::Update: break; default: break; } } //周期召测 MccbTime_t* m_MccbTime = &m_pDevDefineInfo->MccbTimeDefine; if (m_MccbTime != nullptr) { if (now - m_MccbTime->lastcallYx > m_MccbTime->callYx) { callAllYx(); m_MccbTime->lastcallYx = now; } if (now - m_MccbTime->lastcallYc > m_MccbTime->callYc) { callAllYc(); m_MccbTime->lastcallYc = now; } if (now - m_MccbTime->lastcallParam > m_MccbTime->callParam) { callAllParam(); m_MccbTime->lastcallParam = now; } if (now - m_MccbTime->lastcallSum > m_MccbTime->callSum) { callAllSum(); m_MccbTime->lastcallSum = now; } if (now - m_MccbTime->lastcallExt > m_MccbTime->callExt) { callAllExt(); m_MccbTime->lastcallExt = now; } } return buffLen; } retack Mccb_XD::MessageHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen) { if (len <= 1) return retack::packetErr; QMetaEnum metaE = QMetaEnum::fromType<func_code>(); if (metaE.valueToKey(buf[0] & 0b11111) == nullptr) { qWarning() << "Func_Code err:" << (int)(buf[0] & 0b11111); return retack::packetErr; } func_code funcode = (func_code)(buf[0]&0b11111); uint8_t pLen = buf[1]; if (len != pLen + 2) return retack::packetErr; if (buf[0]>>6) { //异常应答 } retack ret; //-0x33 for (int i = 2; i < len;i++) { buf[i] = buf[i] - 0x33; } switch (funcode) { case func_code::Reserve: qDebug() << "reserve func_code:" << (int)EnumtoValue(funcode); ret = retack::OkNoNext; break; case func_code::Read_Data: qDebug() << "读数据返回"; ret = readDataHandler(&buf[2], pLen); break; case func_code::Read_Data_Next: qDebug() << "读后续数据返回"; ret = readDataNextHandler(&buf[2], pLen); break; case func_code::Read_Data_Comm: qDebug() << "读通信地址返回"; ret = readCommAddrHandler(&buf[2], pLen); break; case func_code::Write_Data: { qDebug() << metaE.valueToKey(buf[0] & 0b11111); if (pLen == 0) { ret = retack::OkNoNext; qDebug() << "success,freash param:"<<QString::number(m_NowParamDI,16); AddCmd2Que({ OpType::Read,m_NowParamDI }); m_NowParamDI = 0; } else { ret = retack::packetErr; qDebug() << "错误!"; } //临时处理 ret = retack::OkNoNext; break; } case func_code::Write_Data_Frozen: case func_code::Write_Data_Comm: case func_code::Dev_Ctrl: case func_code::Dev_Update: qDebug() << metaE.valueToKey(buf[0] & 0b11111); if (pLen == 0) { ret = retack::OkNoNext; qDebug() << "成功!"; } else { ret = retack::packetErr; qDebug() << "错误!"; } //临时处理 ret = retack::OkNoNext; break; case func_code::Write_Data_Speed: qDebug() << "写通信速率返回"; ret = writeSpeedHandler(&buf[2], pLen); break; case func_code::Write_Data_PassWord: qDebug() << "写密码返回"; ret = changePasswordHandler(&buf[2], pLen); break; case func_code::Dev_Alarm: qDebug() << "读异常告警返回"; ret = readAlarmHandler(&buf[2], pLen); break; case func_code::Dev_Alarm_Reply: qDebug() << "非双工模式,不支持该指令"<< (int)EnumtoValue(funcode); ret = retack::OkNoNext; break; case func_code::Dev_Event_Reset: qDebug() << "事件重置返回"; ret = dataResetHandler(&buf[2], pLen); break; default: qDebug() << "未知控制码" << (int)EnumtoValue(funcode); ret = retack::OkNoNext; break; } if (buf[0] >> 7) m_NextIndex++; else m_NextIndex = 0; return ret; } //************************************ // Method: MessageNextBufferHandler // FullName: Mccb_XD::MessageNextBufferHandler // Access: public // Returns: uint16_t // Qualifier: NextRead组帧 // Parameter: uint8_t * buf // Parameter: uint16_t len // Parameter: uint16_t & realPacketLen // Parameter: uint8_t * nextBuf 读下一帧报文 //************************************ uint16_t Mccb_XD::MessageNextBufferHandler(uint8_t* buf, uint16_t len, uint16_t& realPacketLen, uint8_t* nextBuf) { return uint16_t(); } bool Mccb_XD::ctrlCommand(QString cmdName, uint8_t* opcode, QString timedata,QString timeType) { node_t* p_param = nullptr; if (m_pDevDefineInfo == nullptr) { qWarning() << "empty dev define info."; return false; } for (auto& it : m_pDevDefineInfo->nodes.devCtrl) { if (it.name == cmdName) { p_param = break; } } //QStringList cmdNameLists = { "TZ_Order","TZ_Cansel","HZ_Order","HZ_Cansel","TZ_Test_Order","TZ_Test_Cansel","Test_Order","Test_Cansel" }; //uint32_t di[] = { 0x06010101,0x06010102,0x06010201,0x06010202,0x06010301,0x06010302,0x06010401,0x06010402 }; if (p_param == nullptr) { qWarning() << "unknown ctrl command name:" << cmdName; return false; } if (cmdName.isEmpty() || opcode == nullptr) { qWarning() << "ctrl param is null."; return false; } ctrl_cmd cmd; cmd.ctrl_di = p_param->DI; cmd.ctrl_time_data = timedata.toUShort() & 0xFF; cmd.ctrl_time_type = (timeType == "03") ? 03 : 02; memcpy(cmd.opcode, opcode, 4); m_ctrlCmdVer.enqueue(cmd); return true; } bool Mccb_XD::paramChange(QString paramName, QString paramValue, uint8_t* opcode) { if(paramName.isEmpty()||paramValue.isEmpty() || opcode == nullptr) return false; bool b = false; param_ope p; for (auto it:m_pDevDefineInfo->nodes.devParam) { if (it.name == paramName) { b = true; p.paramInfo = it; memcpy(p.opeCode, opcode, 4); break; } } if (b) { p.paramValue = paramValue; m_paramOpeVec.enqueue(p); return true; } else { qWarning() << "unknown param info:" << paramName << "\t" << paramValue; return false; } } QString Mccb_XD::getParam(QString paramName) { return QString(); } void Mccb_XD::callAllYc() { if (m_pDevDefineInfo != nullptr) { for (auto it : m_pDevDefineInfo->nodes.devYc) { if (it.DI > 0) { AddCmd2Que({ OpType::Read,it.DI }); } } } /*AddCmd2Que({ OpType::Read,EnumtoValue(DI::U)}); AddCmd2Que({ OpType::Read,EnumtoValue(DI::I) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Iresidual) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ie_residual) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Iw) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Et) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::EtSub) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ea) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ESuba) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Eb) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ESubb) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ec) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ESubc) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::P) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Q) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Pf) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::HzT) });*/ } void Mccb_XD::callAllYx() { if (m_pDevDefineInfo != nullptr) { for (auto it : m_pDevDefineInfo->nodes.devYx) { if (it.DI > 0) { AddCmd2Que({ OpType::Read,it.DI }); } } } //AddCmd2Que({ OpType::Read,EnumtoValue(DI::RunState) }); //AddCmd2Que({ OpType::,EnumtoValue(DI::U) }); } void Mccb_XD::callAllSum() { if (m_pDevDefineInfo != nullptr) { for (auto it : m_pDevDefineInfo->nodes.devSum) { if (it.DI > 0) { AddCmd2Que({ OpType::Read,it.DI }); } } } /*AddCmd2Que({ OpType::Read,EnumtoValue(DI::ResetNum) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::TripNum) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::TotalRunTime) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::EventNum) });*/ } void Mccb_XD::callAllExt() { if (m_pDevDefineInfo != nullptr) { for (auto it : m_pDevDefineInfo->nodes.devExt) { if (it.DI > 0) { AddCmd2Que({ OpType::Read,it.DI }); } } } } void Mccb_XD::callAllParam() { if (m_pDevDefineInfo != nullptr) { for (auto it : m_pDevDefineInfo->nodes.devParam) { if (it.DI > 0) { AddCmd2Que({ OpType::Read,it.DI }); } } } /*AddCmd2Que({ OpType::Read,EnumtoValue(DI::Date) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Time) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::CommAddr) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::DevNum) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::AssetNum) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ue) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::In) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Inm) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::DevModel) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProductTime) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProtVer) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ManuID) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::FirewareVer) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::HardwareVer) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ieris) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::Ierts) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::AutoRecloseTime) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ResidualFeatures) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::InstalledPhase) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::CommSpeed) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::PassWord_1) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::PassWord_2) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::PassWord_3) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::CtrlWord) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::ResidualSV) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::TimerSelfInspection) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::VoltageParam) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::IParam) }); AddCmd2Que({ OpType::Read,EnumtoValue(DI::TempProt) });*/ } uint16_t Mccb_XD::packetFrame(uint8_t* buf, uint8_t c, uint8_t len) { uint8_t data[Packet_Max_Length] = "\0"; data[0] = 0x68; memcpy(&data[1], m_Address, 6); data[7] = 0x68; data[8] = c; data[9] = len; for (auto i = 0; i < len; i++) { data[10 + i] = buf[i] + 0x33; } data[10 + len] = calcSum(data, 10 + len); data[11 + len] = 0x16; memset(buf, 0, Packet_Max_Length); memcpy(buf, data, 12 + len); return 12 + len; } //************************************ // Method: readData // FullName: Mccb_XD::readData // Access: private // Returns: uint16_t // Qualifier: 读数据 // Parameter: uint8_t * buf 数据帧 // Parameter: di di //************************************ uint16_t Mccb_XD::readData(uint8_t* buf, uint32_t di) { memcpy(buf, &di, sizeof(DI)); return packetFrame(buf, CMD_READ_DATA, 4); } uint16_t Mccb_XD::readDataNext(uint8_t* buf, uint32_t di) { memcpy(buf, &di, sizeof(DI)); buf[4] = m_NextIndex; return packetFrame(buf, CMD_READ_DATA_NEXT, 5); } uint16_t Mccb_XD::writeData(uint8_t* buf, param_ope p) { memcpy(buf, &p.paramInfo.DI, 4); memcpy(&buf[4], m_PassWord_0, 4); memcpy(&buf[8], p.opeCode, 4); auto byte = MccbBase::ParamPack(p.paramValue, p.paramInfo.Type, p.paramInfo.Len, p.paramInfo.dotNum); if (byte.length() > 0) { memcpy(&buf[12], byte.data(), byte.length()); } return packetFrame(buf, CMD_WRITE_DATA, 12+ byte.length()); } uint16_t Mccb_XD::readParam(uint8_t* buf, uint32_t di) { return 0; } uint16_t Mccb_XD::writeParam(uint8_t* buf, uint32_t di, QString paramValue) { return 0; } uint16_t Mccb_XD::writeParam(uint8_t* buf, uint32_t di, uint8_t* paramValue, uint8_t paramLen) { return 0; } uint16_t Mccb_XD::readCommAddr(uint8_t* buf) { buf[0] = 0; return packetFrame(buf, CMD_READ_COMM_ADDR, 0); } uint16_t Mccb_XD::writeCommAddr(uint8_t* buf, uint8_t* addr) { memcpy(buf, addr, 6); return packetFrame(buf, CMD_WRITE_COMM_ADDR, 6); } uint16_t Mccb_XD::frozenCmd(uint8_t* buf, uint8_t* timeData, uint8_t* addr /*= nullptr*/) { return 0; } uint16_t Mccb_XD::timeBroadcast(uint8_t* buf) { return 0; } uint16_t Mccb_XD::changeCommSpeed(uint8_t* buf, commspeed speed) { return 0; } uint16_t Mccb_XD::changePassword(uint8_t* buf, uint32_t di, uint8_t* newPassword) { return 0; } uint16_t Mccb_XD::readAlarm(uint8_t* buf) { buf[0] = 0; return packetFrame(buf, CMD_READ_ALARM, 0); } uint16_t Mccb_XD::dataReset(uint8_t* buf, uint32_t di) { return 0; } uint16_t Mccb_XD::cmdAction(uint8_t* buf, ctrl_cmd& cmd) { memcpy(buf, &cmd.ctrl_di, 4); memcpy(&buf[4], m_PassWord_0, 4); memcpy(&buf[8], cmd.opcode, 4); if ((cmd.ctrl_di & 0x1) == 0) { return packetFrame(buf, CMD_CTRL, 12); } else { buf[12] = cmd.ctrl_time_data; buf[13] = cmd.ctrl_time_type; return packetFrame(buf, CMD_CTRL, 14); } } uint16_t Mccb_XD::updateAction(uint8_t* buf, uint32_t di, uint8_t* fileData, uint8_t len) { return 0; } Mccb::retack Mccb_XD::readDataHandler(uint8_t* buf, uint8_t len) { if (len <= 4) return retack::packetErr; DI di; memcpy(&di, buf, 4); uint64_t nowTimeStamp = QDateTime::currentDateTime().toSecsSinceEpoch(); QList<MqttData> tmpMqttData; switch (di) { case DI::Ua: { float Ua = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 1,QString::number(Ua,'f',1) ,nowTimeStamp}); qDebug() << "Ua:" << Ua; break; } case DI::Ub: { float Ub = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2,QString::number(Ub,'f',1) ,nowTimeStamp }); qDebug() << "Ub:" << Ub; break; } case DI::Uc: { float Uc = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 3,QString::number(Uc,'f',1) ,nowTimeStamp }); qDebug() << "Uc:" << Uc; break; } case DI::U: { float Ua = MccbBase::parseBCDValue(&buf[4], 2, 0.1); float Ub = MccbBase::parseBCDValue(&buf[6], 2, 0.1); float Uc = MccbBase::parseBCDValue(&buf[8], 2, 0.1); tmpMqttData.push_back({ 1,QString::number(Ua,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 2,QString::number(Ub,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 3,QString::number(Uc,'f',1) ,nowTimeStamp }); qDebug() << "Ua:" << Ua << "\tUb:" << Ub << "\tUc:" << Uc; break; } case DI::Ia: { float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 4,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "Ia:" << Ia; break; } case DI::Ib: { float Ib = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 5,QString::number(Ib,'f',1) ,nowTimeStamp }); qDebug() << "Ib:" << Ib; break; } case DI::Ic: { float Ic = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 6,QString::number(Ic,'f',1) ,nowTimeStamp }); qDebug() << "Ic:" << Ic; break; } case DI::I: { float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); float Ib = MccbBase::parseBCDValue(&buf[7], 3, 0.1); float Ic = MccbBase::parseBCDValue(&buf[10], 3, 0.1); tmpMqttData.push_back({ 4,QString::number(Ia,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 5,QString::number(Ib,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 6,QString::number(Ic,'f',1) ,nowTimeStamp }); qDebug() << "Ia:" << Ia << "\tIb:" << Ib << "\tIc:" << Ic; break; } case DI::IresidualNowMaxPhase: { auto phase = buf[4]; if (phase == 0x1) { qDebug() << "当前剩余电流最大相:A相"; tmpMqttData.push_back({ 7,"1" ,nowTimeStamp }); } else if (phase == 0x2) { qDebug() << "当前剩余电流最大相:B相"; tmpMqttData.push_back({ 7,"2",nowTimeStamp }); } else if (phase == 0x3) { qDebug() << "当前剩余电流最大相:C相"; tmpMqttData.push_back({ 7,"3",nowTimeStamp }); } else { qWarning() << "当前剩余电流最大相:未知值->" << (uint32_t)phase; tmpMqttData.push_back({ 7,"0",nowTimeStamp }); } break; } case DI::IresidualNow: { float Ia = MccbBase::parseBCDValue(&buf[4], 2, 1.0); tmpMqttData.push_back({ 8,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前剩余电流值:" << Ia; break; } case DI::Iresidual: { auto phase = buf[4]; if (phase == 0x1) { qDebug() << "当前剩余电流最大相:A相"; tmpMqttData.push_back({ 7,"1" ,nowTimeStamp }); } else if (phase == 0x2) { qDebug() << "当前剩余电流最大相:B相"; tmpMqttData.push_back({ 7,"2" ,nowTimeStamp }); } else if (phase == 0x3) { qDebug() << "当前剩余电流最大相:C相"; tmpMqttData.push_back({ 7,"3" ,nowTimeStamp }); } else { qWarning() << "当前剩余电流最大相:未知值->" << (uint32_t)phase; tmpMqttData.push_back({ 7,"0" ,nowTimeStamp }); } float Ia = MccbBase::parseBCDValue(&buf[5], 2, 1.0); tmpMqttData.push_back({ 8,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前剩余电流值:" << Ia; break; } case DI::Iei_residual: { float Ia = MccbBase::parseBCDValue(&buf[4], 2, 1.0); tmpMqttData.push_back({ 9,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前额定剩余电流动作值:" << Ia; break; } case DI::Iet_residual: { float t = MccbBase::parseBCDValue(&buf[4], 2, 1.0); tmpMqttData.push_back({ 10,QString::number(t,'f',1) ,nowTimeStamp }); qDebug() << "当前额定极限不驱动时间:" << t; break; } case DI::Ie_residual: { float Ia = MccbBase::parseBCDValue(&buf[4], 2, 1.0); float t = MccbBase::parseBCDValue(&buf[6], 2, 1.0); tmpMqttData.push_back({ 9,QString::number(Ia,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 10,QString::number(t,'f',1) ,nowTimeStamp }); qDebug() << "当前额定剩余电流动作值:" << Ia << "\t当前额定极限不驱动时间:" << t; break; } case DI::IwDirect: { auto phaseDirect = buf[4]; tmpMqttData.push_back({ 11,QString::number(phaseDirect) ,nowTimeStamp }); qDebug() << "当前三相的电流(功率)方向:" << (uint32_t)phaseDirect; break; } case DI::Iwa: { float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 12,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前A相电流值:" << Ia; break; } case DI::Iwb: { float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 13,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前B相电流值:" << Ia; break; } case DI::Iwc: { float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 14,QString::number(Ia,'f',1) ,nowTimeStamp }); qDebug() << "当前C相电流值:" << Ia; break; } case DI::Iw: { auto phaseDirect = buf[4]; tmpMqttData.push_back({ 11,QString::number(phaseDirect) ,nowTimeStamp }); float Ia = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 12,QString::number(Ia,'f',1) ,nowTimeStamp }); float Ib = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 13,QString::number(Ib,'f',1) ,nowTimeStamp }); float Ic = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 14,QString::number(Ic,'f',1) ,nowTimeStamp }); qDebug() << "当前A相电流值:" << Ia << "\t当前B相电流值:" << Ib << "\t当前C相电流值:" << Ic << "当前三相的电流(功率)方向:" << (uint32_t)phaseDirect; ; break; } case DI::Et: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 15,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)正向有功总电能:" << Ia; break; } case DI::EtSub: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 16,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)反向有功总电能:" << Ia; break; } case DI::Ea: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 17,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)A相正向有功总电能:" << Ia; break; } case DI::ESuba: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 18,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)A相反向有功总电能:" << Ia; break; } case DI::Eb: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 19,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)B相正向有功总电能:" << Ia; break; } case DI::ESubb: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 20,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)B相反向有功总电能:" << Ia; break; } case DI::Ec: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 21,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)C相正向有功总电能:" << Ia; break; } case DI::ESubc: { float Ia = MccbBase::parseBCDValue(&buf[4], 4, 0.01); tmpMqttData.push_back({ 22,QString::number(Ia,'f',2) ,nowTimeStamp }); qDebug() << "(当前)C相反向有功总电能:" << Ia; break; } case DI::Pt: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 23,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时总有功功率:" << data; break; } case DI::Pa: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 24,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时A相有功功率:" << data; break; } case DI::Pb: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 25,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时B相有功功率:" << data; break; } case DI::Pc: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 26,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时C相有功功率:" << data; break; } case DI::P: { float pt = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 23,QString::number(pt,'f',3) ,nowTimeStamp }); float pa = MccbBase::parseBCDValue(&buf[7], 3, 0.001); tmpMqttData.push_back({ 24,QString::number(pa,'f',3) ,nowTimeStamp }); float pb = MccbBase::parseBCDValue(&buf[10], 3, 0.001); tmpMqttData.push_back({ 25,QString::number(pb,'f',3) ,nowTimeStamp }); float pc = MccbBase::parseBCDValue(&buf[13], 3, 0.001); tmpMqttData.push_back({ 26,QString::number(pc,'f',3) ,nowTimeStamp }); qDebug() << "瞬时总有功功率:" << pt << "\t瞬时A相有功功率:" << pa << "\t瞬时B相有功功率:" << pb << "\t瞬时C相有功功率:" << pc; break; } case DI::Qt: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 27,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时总无功功率:" << data; break; } case DI::Qa: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 28,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时A相无功功率:" << data; break; } case DI::Qb: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 29,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时B相无功功率:" << data; break; } case DI::Qc: { float data = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 30,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "瞬时C相无功功率:" << data; break; } case DI::Q: { float Qt = MccbBase::parseBCDValue(&buf[4], 3, 0.001); tmpMqttData.push_back({ 27,QString::number(Qt,'f',3) ,nowTimeStamp }); float Qa = MccbBase::parseBCDValue(&buf[7], 3, 0.001); tmpMqttData.push_back({28,QString::number(Qa,'f',3) ,nowTimeStamp }); float Qb = MccbBase::parseBCDValue(&buf[10], 3, 0.001); tmpMqttData.push_back({ 29,QString::number(Qb,'f',3) ,nowTimeStamp }); float Qc = MccbBase::parseBCDValue(&buf[13], 3, 0.001); tmpMqttData.push_back({ 30,QString::number(Qc,'f',3) ,nowTimeStamp }); qDebug() << "瞬时总无功功率:" << Qt << "\t瞬时A相无功功率:" << Qa << "\t瞬时B相无功功率:" << Qb << "\t瞬时C相无功功率:" << Qc; break; } case DI::Pft: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.001); tmpMqttData.push_back({ 31,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "功率因数总:" << data; break; } case DI::Pfa: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.001); tmpMqttData.push_back({ 32,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "A相功率因数:" << data; break; } case DI::Pfb: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.001); tmpMqttData.push_back({ 33,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "B相功率因数:" << data; break; } case DI::Pfc: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.001); tmpMqttData.push_back({ 34,QString::number(data,'f',3) ,nowTimeStamp }); qDebug() << "C相功率因数:" << data; break; } case DI::Pf: { float Pft = MccbBase::parseBCDValue(&buf[4], 2, 0.001); tmpMqttData.push_back({ 31,QString::number(Pft,'f',3) ,nowTimeStamp }); float Pfa = MccbBase::parseBCDValue(&buf[6], 2, 0.001); tmpMqttData.push_back({ 32,QString::number(Pfa,'f',3) ,nowTimeStamp }); float Pfb = MccbBase::parseBCDValue(&buf[8], 2, 0.001); tmpMqttData.push_back({ 33,QString::number(Pfb,'f',3) ,nowTimeStamp }); float Pfc = MccbBase::parseBCDValue(&buf[10], 2, 0.001); tmpMqttData.push_back({ 34,QString::number(Pfc,'f',3) ,nowTimeStamp }); qDebug() << "功率因数总:" << Pft << "\tA相功率因数:" << Pfa << "\tB相功率因数:" << Pfb << "\tC相功率因数:" << Pfc; break; } case DI::Hz: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.01); tmpMqttData.push_back({ 35,QString::number(data,'f',2) ,nowTimeStamp }); qDebug() << "电网频率:" << data; break; } case DI::Tin: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 36,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "开关内温度:" << data; break; } case DI::T_1: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 37,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度1:" << data; break; } case DI::T_2: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 38,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度2:" << data; break; } case DI::T_3: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 39,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度3:" << data; break; } case DI::T_4: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 40,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度4:" << data; break; } case DI::T_5: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 41,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度5:" << data; break; } case DI::T_6: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 42,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度6:" << data; break; } case DI::T_7: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 43,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度7:" << data; break; } case DI::T_8: { float data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 44,QString::number(data,'f',1) ,nowTimeStamp }); qDebug() << "温度8:" << data; break; } case DI::HzT: { float Hz = MccbBase::parseBCDValue(&buf[4], 2, 0.01); float Tin = MccbBase::parseBCDValue(&buf[6], 2, 0.1); float T_1 = MccbBase::parseBCDValue(&buf[8], 2, 0.1); float T_2 = MccbBase::parseBCDValue(&buf[10], 2, 0.1); float T_3 = MccbBase::parseBCDValue(&buf[12], 2, 0.1); float T_4 = MccbBase::parseBCDValue(&buf[14], 2, 0.1); float T_5 = MccbBase::parseBCDValue(&buf[16], 2, 0.1); float T_6 = MccbBase::parseBCDValue(&buf[18], 2, 0.1); float T_7 = MccbBase::parseBCDValue(&buf[20], 2, 0.1); float T_8 = MccbBase::parseBCDValue(&buf[22], 2, 0.1); tmpMqttData.push_back({ 35,QString::number(Hz,'f',2) ,nowTimeStamp }); tmpMqttData.push_back({ 36,QString::number(Tin,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 37,QString::number(T_1,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 38,QString::number(T_2,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 39,QString::number(T_3,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 40,QString::number(T_4,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 41,QString::number(T_5,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 42,QString::number(T_6,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 43,QString::number(T_7,'f',1) ,nowTimeStamp }); tmpMqttData.push_back({ 44,QString::number(T_8,'f',1) ,nowTimeStamp }); qDebug() << "电网频率:" << Hz << "\t开关内温度" << Tin << "\t温度1:" << T_1 << "\t温度2:" << T_2 << "\t温度3:" << T_3 << "\t温度4:" << T_4 << "\t温度5:" << T_5 << "\t温度6:" << T_6 << "\t温度7:" << T_7 << "\t温度8:" << T_8; break; } case DI::ResetNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 3); tmpMqttData.push_back({ 4001,QString::number(data) ,nowTimeStamp }); qDebug() << "数据清零总次数:" << data; break; } case DI::TotalTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4002,QString::number(data) ,nowTimeStamp }); qDebug() << "总跳闸次数:" << data; break; } case DI::IresidualUnTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4003,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流闭锁跳闸次数:" << data; break; } case DI::IresidualProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4004,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流保护跳闸次数:" << data; break; } case DI::OverloadProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4005,QString::number(data) ,nowTimeStamp }); qDebug() << "过载保护跳闸次数:" << data; break; } case DI::HighVProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4006,QString::number(data) ,nowTimeStamp }); qDebug() << "过压保护跳闸次数:" << data; break; } case DI::HandyTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4007,QString::number(data) ,nowTimeStamp }); qDebug() << "手动跳闸次数:" << data; break; } case DI::LossZeroProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4008,QString::number(data) ,nowTimeStamp }); qDebug() << "缺零保护跳闸次数:" << data; break; } case DI::TestTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4009,QString::number(data) ,nowTimeStamp }); qDebug() << "试验跳闸次数(远程、按键):" << data; break; } case DI::SCDProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4010,QString::number(data) ,nowTimeStamp }); qDebug() << "短路短延时跳闸次数:" << data; break; } case DI::SIProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4011,QString::number(data) ,nowTimeStamp }); qDebug() << "短路瞬时跳闸次数:" << data; break; } case DI::LowVProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4012,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压保护跳闸次数:" << data; break; } case DI::LossVProtTripNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 4013,QString::number(data) ,nowTimeStamp }); qDebug() << "缺相保护跳闸次数:" << data; break; } case DI::TripNum: //跳闸次数参数模块 { QString tmpDI[12] = { "CSWI_OpOpn_OpCnt","LOCLK_OpCntRs","PTLK_OpCntRs","PTOC_Ovld_OpCntRs","PHIZ_OpCntRs","CSWI_OpOpn_Mnl_OpCnt","PTZERO_Loss_OpCntRs","CSWI_OpOpn_Tst_OpCnt","PTOC_Dly_OpCntRs","PIOC_OpCntRs","PTUV_OpCntRs","PTUV_Loss_OpCntRs"}; qDebug() << "***跳闸次数参数模块***"; for (unsigned int i = 0; i < 12; i++) { uint32_t data = 0; if (i == 0) { data = MccbBase::parseBCDValue_u(&buf[4 + i * 2], 3); } else { data = MccbBase::parseBCDValue_u(&buf[4 + i * 2], 2); } tmpMqttData.push_back({ 4001 + i,QString::number(data) ,nowTimeStamp }); qDebug() << "name:" << tmpDI[i] << "\tValue:" << data; } break; } case DI::TotalRunTime: { auto data = MccbBase::parseBCDValue_u(&buf[4], 4); tmpMqttData.push_back({ 4014,QString::number(data) ,nowTimeStamp }); qDebug() << "断路器运行时间总累计:" << data; break; } case DI::AbnormalOccurNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4015,QString::number(data) ,nowTimeStamp }); qDebug() << "异常告警发生/恢复新增次数:" << data; break; } case DI::ProtectionDropNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4016,QString::number(data) ,nowTimeStamp }); qDebug() << "保护功能退出/恢复新增次数:" << data; break; } case DI::HPowerOffNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4017,QString::number(data) ,nowTimeStamp }); qDebug() << "高压线路失/复电新增次数:" << data; break; } case DI::BrokerChangeNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4018,QString::number(data) ,nowTimeStamp }); qDebug() << "闸位状态变化新增次数:" << data; break; } case DI::SelfInspectionNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4019,QString::number(data) ,nowTimeStamp }); qDebug() << "自检事件新增次数:" << data; break; } case DI::ProtectedEventNum: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 4020,QString::number(data) ,nowTimeStamp }); qDebug() << "保护动作事件新增次数:" << data; break; } case DI::EventNum: { auto data_1 = MccbBase::parseBCDValue_u(&buf[4], 1); auto data_2 = MccbBase::parseBCDValue_u(&buf[5], 1); auto data_3 = MccbBase::parseBCDValue_u(&buf[6], 1); auto data_4 = MccbBase::parseBCDValue_u(&buf[7], 1); auto data_5 = MccbBase::parseBCDValue_u(&buf[8], 1); auto data_6 = MccbBase::parseBCDValue_u(&buf[9], 1); tmpMqttData.push_back({ 59,QString::number(data_1) ,nowTimeStamp }); tmpMqttData.push_back({ 60,QString::number(data_2) ,nowTimeStamp }); tmpMqttData.push_back({ 61,QString::number(data_3) ,nowTimeStamp }); tmpMqttData.push_back({ 62,QString::number(data_4) ,nowTimeStamp }); tmpMqttData.push_back({ 63,QString::number(data_5) ,nowTimeStamp }); tmpMqttData.push_back({ 64,QString::number(data_6) ,nowTimeStamp }); qDebug() << "异常告警发生/恢复新增次数:" << data_1 << "\t保护功能退出/恢复新增次数:" << data_2 << "\t高压线路失/复电新增次数:" << data_3 << "\t闸位状态变化新增次数:" << data_4 << "\t自检事件新增次数:" << data_5 << "\t保护动作事件新增次数:" << data_6; break; } case DI::Date: { auto date = QString("{%1}年{%2}月{%3}日{%4}周").arg( 2000 + Hex2Ten(buf[7]),4).arg( Hex2Ten(buf[6]),2).arg( Hex2Ten(buf[5]),2).arg (Hex2Ten(buf[4]),2); tmpMqttData.push_back({ 2001,date ,nowTimeStamp }); qDebug() << "当前日期:" << date; break; } case DI::Time: { auto date = QString("{%1}时{%2}分{%3}秒").arg(Hex2Ten(buf[6])).arg(Hex2Ten(buf[5])).arg(Hex2Ten(buf[4])); tmpMqttData.push_back({ 2002,date ,nowTimeStamp }); qDebug() << "当前时间:" << date; break; } case DI::CommAddr: { uint8_t addr[6] = "\0"; memcpy(addr, &buf[4], 6); auto strAddr = Char2Hex_Reverse(addr, 6); tmpMqttData.push_back({ 2003,strAddr ,nowTimeStamp }); qDebug() << "通信地址:" << strAddr; break; } case DI::DevNum: { uint8_t addr[6] = "\0"; memcpy(addr, &buf[4], 6); auto strAddr = Char2Hex_Reverse(addr, 6); tmpMqttData.push_back({ 2004,strAddr ,nowTimeStamp }); qDebug() << "设备号:" << strAddr; break; } case DI::AssetNum: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 32); tmpMqttData.push_back({ 2005,strAddr ,nowTimeStamp }); qDebug() << "资产管理编码:" << strAddr; break; } case DI::Ue: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 6); tmpMqttData.push_back({ 2006,strAddr ,nowTimeStamp }); qDebug() << "额定电压:" << strAddr; break; } case DI::In: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 6); tmpMqttData.push_back({ 2007,strAddr ,nowTimeStamp }); qDebug() << "额定电流:" << strAddr; break; } case DI::Inm: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 6); tmpMqttData.push_back({ 2008,strAddr ,nowTimeStamp }); qDebug() << "最大(壳架)电流(Inm):" << strAddr; break; } case DI::DevModel: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 10); tmpMqttData.push_back({ 2009,strAddr ,nowTimeStamp }); qDebug() << "设备型号:" << strAddr; break; } case DI::ProductTime: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 10); tmpMqttData.push_back({ 2010,strAddr ,nowTimeStamp }); qDebug() << "生产日期:" << strAddr; break; } case DI::ProtVer: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 16); tmpMqttData.push_back({ 2011,strAddr ,nowTimeStamp }); qDebug() << "协议版本号:" << strAddr; break; } case DI::ManuID: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 24); tmpMqttData.push_back({ 2012,strAddr ,nowTimeStamp }); qDebug() << "厂家工厂代码:" << strAddr; break; } case DI::FirewareVer: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 32); tmpMqttData.push_back({ 2013,strAddr ,nowTimeStamp }); qDebug() << "厂家固件版本号:" << strAddr; break; } case DI::HardwareVer: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 32); tmpMqttData.push_back({ 2014,strAddr ,nowTimeStamp }); qDebug() << "厂家硬件版本号:" << strAddr; break; } case DI::Ieris: { uint8_t addr[20] = "\0"; //TODO:解析 memcpy(addr, &buf[4], 20); auto strAddr = Char2Hex_Reverse(addr, 20); tmpMqttData.push_back({ 2015,strAddr ,nowTimeStamp }); qDebug() << "额定剩余电流动作值参数组:" << strAddr; break; } case DI::Ierts: { uint8_t addr[10] = "\0"; //TODO:解析 memcpy(addr, &buf[4], 10); auto strAddr = Char2Hex_Reverse(addr, 10); tmpMqttData.push_back({ 2016,strAddr ,nowTimeStamp }); qDebug() << "额定极限不驱动时间参数组:" << strAddr; break; } case DI::AutoRecloseTime: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 24); tmpMqttData.push_back({ 2017,strAddr ,nowTimeStamp }); qDebug() << "自动重合闸时间范围:" << strAddr; break; } case DI::ResidualFeatures: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 24); qDebug() << "剩余电流动作特性(A型或AC型):" << strAddr; break; } case DI::InstalledPhase: { auto strAddr = MccbBase::PaseAscii((char*)&buf[4], 10); tmpMqttData.push_back({ 2019,strAddr ,nowTimeStamp }); qDebug() << "安装相位别(只适用单相断路器):" << strAddr; break; } case DI::RunState_1: { uint8_t state1 = buf[4]; int b = 0; if (((state1 >> 5) & 0b11) == 0b01) b = 1; tmpMqttData.push_back({ 1001,QString::number(b) ,nowTimeStamp }); auto index = MccbBase::parseEventCot2Int(state1 & 0b11111); qDebug() << "状态字1:" << state1; qDebug() << "开关位置:" << (b == 1 ? "合" : "分"); if (index > 0) { tmpMqttData.push_back({ index,"1" ,nowTimeStamp}); qDebug() << "跳闸、告警原因:" << MccbBase::parseEventCot(state1 & 0b11111); /*for (int i = 0; i < 25; i++) { if(g_AlamAddrs[i]==index) continue; tmpMqttData.push_back({ g_AlamAddrs[i],"0" ,nowTimeStamp }); }*/ } break; } case DI::RunState_2: { uint8_t state2 = buf[4]; qDebug() << "状态字2:" << state2; int b = 0; for (unsigned int i = 2; i <= 7;i++) { b = 0; if (((state2 >> i) & 0x1) == 1)//保护动作标志 b = 1; tmpMqttData.push_back({ 1000+i,QString::number(b) ,nowTimeStamp }); if (b) qDebug() << 1000 + i << ":" << b; } if (((state2 >> 2) & 0x1) == 1)//保护动作 { qDebug() << "保护动作标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProtectedEvent_1) + i }); } } if (((state2 >> 3) & 0x1) == 1)//高压线路失复电 { qDebug() << "高压线路失复电标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::HPowerOffEvent_1) + i }); } } if (((state2 >> 4) & 0x1)== 1)//保护功能退出/恢复 { qDebug() << "保护功能退出/恢复标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProtectionDropEvent_1) + i }); } } if (((state2 >> 5) & 0x1) == 1)//闸位变化 { qDebug() << "闸位变化标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::BrokerChangeEvent_1) + i }); } } if (((state2 >> 6) & 0x1) == 1)//异常告警 { qDebug() << "异常告警标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::AlarmEvent_1) + i }); } } if (((state2 >> 7) & 0x1 )== 1)//自检事件 { qDebug() << "自检事件标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::SelfInspectionEvent_1) + i }); } } break; } case DI::RunState: { uint8_t state1 = buf[4]; uint8_t state2 = buf[5]; int b = 0; if (((state1 >> 5) & 0b11 )== 0b01) b = 1; tmpMqttData.push_back({ 1001,QString::number(b) ,nowTimeStamp }); auto index = MccbBase::parseEventCot2Int(state1 & 0b11111); qDebug() << "状态字1:" << state1; qDebug() << "开关位置:" << (b == 1 ? "合" : "分"); if (index > 0) { tmpMqttData.push_back({ index,"1" ,nowTimeStamp }); qDebug() << "跳闸、告警原因:" << MccbBase::parseEventCot(state1 & 0b11111); /*for (int i = 0; i < 25; i++) { if(g_AlamAddrs[i]==index) continue; tmpMqttData.push_back({ g_AlamAddrs[i],"0" ,nowTimeStamp }); }*/ } qDebug() << "状态字2:" << state2; for (unsigned int i = 2; i <= 7; i++) { b = 0; if (((state2 >> i) & 0x1 )== 1)//保护动作标志 b = 1; tmpMqttData.push_back({ 1000 + i,QString::number(b) ,nowTimeStamp }); if (b) { qDebug() << 1000 + i << ":" << b; } } if (((state2 >> 2) & 0x1 )== 1)//保护动作 { qDebug() << "保护动作标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProtectedEvent_1) + i }); } } if (((state2 >> 3) & 0x1 )== 1)//高压线路失复电 { qDebug() << "高压线路失复电标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::HPowerOffEvent_1) + i }); } } if (((state2 >> 4) & 0x1) == 1)//保护功能退出/恢复 { qDebug() << "保护功能退出/恢复标志,抄读"; for (auto i = 0; i < Event_Record_Max+2; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::ProtectionDropEvent_1) + i }); } } if (((state2 >> 5) & 0x1 )== 1)//闸位变化 { qDebug() << "闸位变化标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::BrokerChangeEvent_1) + i }); } } if (((state2 >> 6) & 0x1 )== 1)//异常告警 { qDebug() << "异常告警标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::AlarmEvent_1) + i }); } } if (((state2 >> 7) & 0x1) == 1)//自检事件 { qDebug() << "自检事件标志,抄读"; for (auto i = 0; i < Event_Record_Max; i++) { AddCmd2Que({ OpType::Read,EnumtoValue(DI::SelfInspectionEvent_1) + i }); } } break; } case DI::CommSpeed: { qDebug() << "通信波特率特征字(0-9):" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2020,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::PassWord_1: { auto data = MccbBase::parseBCDValue_u(&buf[4], 4); tmpMqttData.push_back({ 2021,QString::number(data) ,nowTimeStamp }); memcpy(m_PassWord_0, &buf[4], 4); qDebug() << "0级密码:" << data; break; } case DI::PassWord_2: { auto data = MccbBase::parseBCDValue_u(&buf[4], 4); tmpMqttData.push_back({ 2022,QString::number(data) ,nowTimeStamp }); qDebug() << "1级密码:" << data; memcpy(m_PassWord_1, &buf[4], 4); break; } case DI::PassWord_3: { auto data = MccbBase::parseBCDValue_u(&buf[4], 4); tmpMqttData.push_back({ 2023,QString::number(data) ,nowTimeStamp }); qDebug() << "2级密码:" << data; memcpy(m_PassWord_2, &buf[4], 4); break; } case DI::CtrlWord_1: { qDebug() << "控制字1:" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2024,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::CtrlWord_2: { qDebug() << "控制字2:" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2025,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::CtrlWord_3: { qDebug() << "控制字3:" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2026,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::CtrlWord_4: { qDebug() << "控制字4:" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2027,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::CtrlWord_5: { qDebug() << "控制字5:" << (uint32_t)buf[4]; tmpMqttData.push_back({ 2028,QString::number(buf[4]) ,nowTimeStamp }); break; } case DI::CtrlWord: { qDebug() << "控制字1:" << (uint32_t)buf[4]; qDebug() << "控制字2:" << (uint32_t)buf[5]; qDebug() << "控制字3:" << (uint32_t)buf[6]; qDebug() << "控制字4:" << (uint32_t)buf[7]; qDebug() << "控制字5:" << (uint32_t)buf[8]; for (unsigned int i = 4; i < 9; i++) { tmpMqttData.push_back({ 2020+i,QString::number(buf[i]) ,nowTimeStamp }); } break; } case DI::ResidualOverSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2029,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流超限报警整定值(弃用):" << data; break; } case DI::ResidualAWarningSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2030,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流预警限值(缺省为60%):" << data; break; } case DI::ResidualTWarningSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2031,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流超预警/超限限值持续时长(缺省为60s):" << data; break; } case DI::ResidualSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2029,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流超限报警整定值(弃用):" << data; data = MccbBase::parseBCDValue_u(&buf[6], 1); tmpMqttData.push_back({ 2030,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流预警限值(缺省为60%):" << data; data = MccbBase::parseBCDValue_u(&buf[7], 1); tmpMqttData.push_back({ 2031,QString::number(data) ,nowTimeStamp }); qDebug() << "剩余电流超预警/超限限值持续时长(缺省为60s):" << data; break; } case DI::TimerSelfInspectionTime: case DI::TimerSelfInspection: { auto data = MccbBase::parseBCDValue_u(&buf[4], 3); tmpMqttData.push_back({ 2032,QString::number(data) ,nowTimeStamp }); qDebug() << "定时自检整定时间:" << data; break; } case DI::OverVoltageSV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2033,QString::number(data) ,nowTimeStamp }); qDebug() << "过电压整定值:" << data; break; } case DI::LowVoltageSV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2034,QString::number(data) ,nowTimeStamp }); qDebug() << "欠电压整定值:" << data; break; } case DI::LossVoltageSV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2035,QString::number(data) ,nowTimeStamp }); qDebug() << "断相电压整定值:" << data; break; } case DI::OverVoltageReplaySV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2036,QString::number(data) ,nowTimeStamp }); qDebug() << "过压返回整定值:" << data; break; } case DI::LowVoltageReplaySV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2037,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压返回整定值:" << data; break; } case DI::OverVoltageTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2038,QString::number(data) ,nowTimeStamp }); qDebug() << "过压保护动作延时时间设定值:" << data; break; } case DI::OverVoltageReplayTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2039,QString::number(data) ,nowTimeStamp }); qDebug() << "过压保护返回延时时间设定值:" << data; break; } case DI::LowVoltageTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2040,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压保护动作延时时间设定值:" << data; break; } case DI::LowVoltageReplayTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2041,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压保护返回延时时间设定值:" << data; break; } case DI::VoltageParam: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2033,QString::number(data) ,nowTimeStamp }); qDebug() << "过电压整定值:" << data; data = MccbBase::parseBCDValue(&buf[6], 2, 0.1); tmpMqttData.push_back({ 2034,QString::number(data) ,nowTimeStamp }); qDebug() << "欠电压整定值:" << data; data = MccbBase::parseBCDValue(&buf[8], 2, 0.1); tmpMqttData.push_back({ 2035,QString::number(data) ,nowTimeStamp }); qDebug() << "断相电压整定值:" << data; data = MccbBase::parseBCDValue(&buf[10], 2, 0.1); tmpMqttData.push_back({ 2036,QString::number(data) ,nowTimeStamp }); qDebug() << "过压返回整定值:" << data; data = MccbBase::parseBCDValue(&buf[12], 2, 0.1); tmpMqttData.push_back({ 2037,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压返回整定值:" << data; data = MccbBase::parseBCDValue_u(&buf[14], 1); tmpMqttData.push_back({ 2038,QString::number(data) ,nowTimeStamp }); qDebug() << "过压保护动作延时时间设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[15], 1); tmpMqttData.push_back({ 2039,QString::number(data) ,nowTimeStamp }); qDebug() << "过压保护返回延时时间设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[16], 1); tmpMqttData.push_back({ 2040,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压保护动作延时时间设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[17], 1); tmpMqttData.push_back({ 2041,QString::number(data) ,nowTimeStamp }); qDebug() << "欠压保护返回延时时间设定值:" << data; break; } case DI::Ir1SV: { auto data = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 2042,QString::number(data) ,nowTimeStamp }); qDebug() << "额定电流整定值过载保护动作电流Ir1:" << data; break; } case DI::IoSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2043,QString::number(data) ,nowTimeStamp }); qDebug() << "负荷电流超限报警整定值(﹡0.1In)(弃用):" << data; break; } case DI::T1SV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 1); tmpMqttData.push_back({ 2045,QString::number(data) ,nowTimeStamp }); qDebug() << "过载保护动作时间t1:" << data; break; } case DI::Ir2SV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2046,QString::number(data) ,nowTimeStamp }); qDebug() << "短路短延时动作电流Ir2 (*Ir1):" << data; break; } case DI::T2SV: { auto data = MccbBase::parseBCDValue(&buf[4], 1, 0.1); tmpMqttData.push_back({ 2047,QString::number(data) ,nowTimeStamp }); qDebug() << "短路短延时动作时间t2:" << data; break; } case DI::ItSV: { auto data = buf[4]; tmpMqttData.push_back({ 2048,QString::number(data) ,nowTimeStamp }); if (data == (uint8_t)0) { qDebug() << "反时限"; } else if (data == (uint8_t)1) { qDebug() << "定时限"; } else { qWarning() << "定/反时限,未定义:"<<data<< ",说明:0反时限,1定时限"; } break; } case DI::Ir3SV: { auto data = MccbBase::parseBCDValue(&buf[4], 2, 0.1); tmpMqttData.push_back({ 2049,QString::number(data) ,nowTimeStamp }); qDebug() << "短路瞬时电流Ir3 (*Ir1):" << data; break; } case DI::T3SV: { auto data = MccbBase::parseBCDValue(&buf[4], 1, 0.1); tmpMqttData.push_back({ 2050,QString::number(data) ,nowTimeStamp }); qDebug() << "短路瞬时延时动作时间t3:" << data; break; } case DI::IParam: { auto data = MccbBase::parseBCDValue(&buf[4], 3, 0.1); tmpMqttData.push_back({ 2042,QString::number(data) ,nowTimeStamp }); qDebug() << "额定电流整定值过载保护动作电流Ir1:" << data; data = MccbBase::parseBCDValue_u(&buf[7], 1); tmpMqttData.push_back({ 2043,QString::number(data) ,nowTimeStamp }); qDebug() << "负荷电流超限报警整定值(﹡0.1In)(弃用):" << data; data = MccbBase::parseBCDValue_u(&buf[8], 1); tmpMqttData.push_back({ 2045,QString::number(data) ,nowTimeStamp }); qDebug() << "过载保护动作时间t1:" << data; data = MccbBase::parseBCDValue(&buf[9], 2, 0.1); tmpMqttData.push_back({ 2046,QString::number(data) ,nowTimeStamp }); qDebug() << "短路短延时动作电流Ir2 (*Ir1):" << data; data = MccbBase::parseBCDValue(&buf[11], 1, 0.1); tmpMqttData.push_back({ 2047,QString::number(data) ,nowTimeStamp }); qDebug() << "短路短延时动作时间t2:" << data; data = buf[12]; tmpMqttData.push_back({ 2048,QString::number(data) ,nowTimeStamp }); if (data == (uint8_t)0) { qDebug() << "反时限"; } else if (data == (uint8_t)1) { qDebug() << "定时限"; } else { qWarning()<<"定/反时限,未定义:" << data << ",说明:0反时限,1定时限"; } data = MccbBase::parseBCDValue(&buf[13], 2, 0.1); tmpMqttData.push_back({ 2049,QString::number(data) ,nowTimeStamp }); qDebug() << "短路瞬时电流Ir3 (*Ir1):" << data; data = MccbBase::parseBCDValue(&buf[15], 1, 0.1); tmpMqttData.push_back({ 2050,QString::number(data) ,nowTimeStamp }); qDebug() << "短路瞬时延时动作时间t3:" << data; break; } case DI::TempSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2051,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护动作设定值:" << data; break; } case DI::TempTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2052,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护动作延时时间设定值:" << data; break; } case DI::TempReplaySV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2053,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护返回设定值:" << data; break; } case DI::TempReplayTimeSV: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2054,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护返回延时时间设定值:" << data; break; } case DI::TempProt: { auto data = MccbBase::parseBCDValue_u(&buf[4], 2); tmpMqttData.push_back({ 2050,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护动作设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[6], 2); tmpMqttData.push_back({ 2051,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护动作延时时间设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[8], 2); tmpMqttData.push_back({ 2052,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护返回设定值:" << data; data = MccbBase::parseBCDValue_u(&buf[10], 2); tmpMqttData.push_back({ 2053,QString::number(data) ,nowTimeStamp }); qDebug() << "温度保护返回延时时间设定值:" << data; break; } default: { auto _di = EnumtoValue(di); //TODO: // 事件解析 if (_di >= 0x038D0001 && _di <= 0x038D000A ||(_di >= 0x038E0001 && _di <= 0x038E000A) || (_di >= 0x038F0001 && _di <= 0x038F0050) || (_di >= 0x03910001 && _di <= 0x0391000A) || (_di >= 0x03920001 && _di <= 0x0392000A) || (_di >= 0x03930001 && _di <= 0x0393000A)) { auto ret = eventHandler(_di,&buf[4], len - 4, tmpMqttData); } //谐波 //A.2.3 日最大值、最小值记录 //冻结数据 break; } } emit updateValue(m_AddrStr, tmpMqttData); return retack::packetOk; } Mccb::retack Mccb_XD::readDataNextHandler(uint8_t* buf, uint8_t len) { uint8_t seq = buf[len - 1]; return readDataHandler(buf,len); } Mccb::retack Mccb_XD::readCommAddrHandler(uint8_t* buf, uint8_t len) { if (len == 6) { uint8_t addr[6] = "\0"; memcpy(addr, buf, 6); qDebug() << "readCommAddr:" << Char2Hex_Reverse(addr, 6); QList<MqttData> tmpMqttData; tmpMqttData.push_back({ 2003,Char2Hex_Reverse(addr, 6),TimeNow}); emit updateValue(m_AddrStr, tmpMqttData); return retack::OkNoNext; } return retack::packetErr; } Mccb::retack Mccb_XD::writeSpeedHandler(uint8_t* buf, uint8_t len) { return retack::packetOk; } Mccb::retack Mccb_XD::changePasswordHandler(uint8_t* buf, uint8_t len) { return retack::packetOk; } Mccb::retack Mccb_XD::readAlarmHandler(uint8_t* buf, uint8_t len) { return retack::packetOk; } Mccb::retack Mccb_XD::dataResetHandler(uint8_t* buf, uint8_t len) { return retack::packetOk; } Mccb::retack Mccb_XD::eventHandler(uint32_t _di, uint8_t* buf, uint8_t len,QList<MqttData>&tmpData) { if (_di >= 0x038D0001 && _di <= 0x038D000A)/*断路器自检事件记录*/ { if (len < 8) return retack::packetErr; auto checkSuccess = (buf[1] == 0x11) ? true : false; auto checkFault = (buf[1] == 0x00) ? true : false; auto checkTime = MccbBase::time_int8u2int64(&buf[1]); auto RemoteCheck = (buf[7] == 0x1B) ? true : false; auto LocalCheck = (buf[7] == 0x10B) ? true : false; tmpData.push_back({ 1601,QString::number(LocalCheck) ,checkTime }); tmpData.push_back({ 1602,QString::number(RemoteCheck) ,checkTime }); tmpData.push_back({ 1603,QString::number(checkSuccess) ,checkTime }); tmpData.push_back({ 1604,QString::number(checkFault) ,checkTime }); qDebug() << "断路器自检:" << Utils::getJsonTime(checkTime); qDebug() << "断路器自检方式:" << ((RemoteCheck==true)?"远程\t":"null\t") << ((LocalCheck == true) ? "就地" : "null"); qDebug() << "断路器自检结果:" << ((checkSuccess == true) ? "成功\t" : "null\t") << ((checkFault == true) ? "失败" : "null"); } else if (_di >= 0x038E0001 && _di <= 0x038E000A)/*保护动作事件记录*/ { if (len < 8) return retack::packetErr; auto cot = getCotIndex(buf[0]); auto phase = buf[1]; auto time = MccbBase::time_int8u2int64(&buf[2]); if (cot > 0) { tmpData.push_back({ cot,QString::number(1) ,time }); } qDebug() << "保护动作:" << Utils::getJsonTime(time); qDebug() << "相别:" << (int)phase; qDebug() << "原因:" << (int)buf[0]; } else if (_di >= 0x038F0001 && _di <= 0x038F0050)/*保护功能投退事件记录*/ { if (len < 8) return retack::packetErr; auto cot =0b1111&( buf[6]>>4); auto time = MccbBase::time_int8u2int64(&buf[0]); auto type = buf[7]; uint32_t index = 0; switch (cot) { case 0b0001: index = 1501; break; case 0b1000: index = 1502; break; case 0b0100: index = 1503; break; case 0b0011: index = 1504; break; case 0b0010: index = 1505; break; case 0b0111: index = 1506; break; case 0b0110: index = 1507; break; case 0b0101: index = 1508; break; default: break; } if (index > 0) { tmpData.push_back({ index,QString::number(1) ,time }); } qDebug() << "保护功能投退:" << Utils::getJsonTime(time); qDebug() << "就地/远程:" << type << "\t" << ((type == 0x1B) ? "远方" : "就地"); qDebug() << "原因:" << (int)buf[0]; } else if (_di >= 0x03910001 && _di <= 0x0391000A)/*闸位变化事件记录*/ { if (len < 9) return retack::packetErr; auto state = buf[0]; auto cot = getCotIndex(buf[1]); auto phase = buf[2]; auto time = MccbBase::time_int8u2int64(&buf[3]); //tmpData.push_back({ 1001,QString::number(state) ,time }); if (cot > 0) { tmpData.push_back({ cot,QString::number(1) ,time }); } qDebug() << "闸位变化:" << Utils::getJsonTime(time); qDebug() << "相别:" << (int)phase; qDebug() << "原因:" << (int)buf[1]; qDebug() << "状态:" << (int)buf[0]; } else if (_di >= 0x03920001 && _di <= 0x0392000A)/*告警事件记录*/ { if (len < 9) return retack::packetErr; auto state = buf[0]; auto cot = getCotIndex(buf[1]); auto phase = buf[2]; auto time = MccbBase::time_int8u2int64(&buf[3]); //tmpData.push_back({ 1001,QString::number(state) ,time }); if (cot > 0) { tmpData.push_back({ cot,QString::number(1) ,time }); } qDebug() << "告警事件:" << Utils::getJsonTime(time); qDebug() << "相别:" << (int)phase; qDebug() << "原因:" << (int)buf[1]; qDebug() << "状态:" << (int)buf[0]; } else if (_di >= 0x03930001 && _di <= 0x0393000A)/*高压失/复电事件记录*/ { if (len < 12) return retack::packetErr; auto startTime = MccbBase::time_int8u2int64(&buf[0]); auto endTime = MccbBase::time_int8u2int64(&buf[0]); if (endTime != 0) { tmpData.push_back({ 1003,QString::number(0) ,endTime }); qDebug() << "高压复电:" << Utils::getJsonTime(endTime); } else if (startTime != 0) { tmpData.push_back({ 1003,QString::number(1) ,startTime }); qDebug() << "高压失电:" << Utils::getJsonTime(startTime); } } return retack::packetOk; } bool Mccb_XD::getStateWordStr(uint8_t word, uint8_t type, std::string name[], std::string value[]) { return false; } bool Mccb_XD::getCtrlWordStr(uint8_t word, uint8_t type, std::string name[], std::string value[]) { return false; } bool Mccb_XD::getBrokerChangeStr(uint8_t word, uint8_t type, std::string name[], std::string value[]) { return false; } bool Mccb_XD::getAlarmStr(uint8_t word, std::string name[], std::string value[]) { return false; } uint32_t Mccb_XD::getCotIndex(uint8_t cot) { uint32_t index = 0; cot &= 0b11111; switch (cot) { case 0b00001: index = 1101; break; case 0b00010: index = 1102; break; case 0b00100: index = 1103; break; case 0b00101: index = 1104; break; case 0b00110: index = 1105; break; case 0b10110: index = 1106; break; case 0b00111: index = 1107; break; case 0b01000: index = 1108; break; case 0b01001: index = 1109; break; case 0b01010: index = 1110; break; case 0b10100: index = 1111; break; //case 0b0001: // index = 1112; // break; case 0b01111: index = 1113; break; case 0b11000: index = 1114; break; default: break; } return index; } ``` # 三.总线管理类 总线管理类维护一个占有方信息,占有超时或主动释放,将可选取新的占有设备。 ```c++ //占有方信息 typedef struct _placeHolder { QString ownerAddr; //占有方地址 quint64 startTime; //开始时间 const quint64 lastingTime = 3000; //持续时间,毫秒 bool keepHolding; //是否继续保持占有 bool needNext; //等待后续报文 quint8 nextIndex; //后续帧序号 }placeHolder; ``` ```c++ //串口总线管理 class SerialBusManager : public QObject { Q_OBJECT public: SerialBusManager(QObject *parent = nullptr); ~SerialBusManager(); bool RegisterMccb(const QString& addr,MccbBase* mccb); //注册MCCB设备 MccbBase* UnRegisterMccb(const QString& addr); // MccbBase* GetMccb(const QString& addr); // bool OpenSerial(const QString& portName,qint32 baudRate,QSerialPort::DataBits dataBits, QSerialPort::FlowControl flowCtrol,QSerialPort::Parity parity,QSerialPort::StopBits stopBits,bool showOriginPacket = false); bool OpenSerial(bool showOriginPacket = false); private: bool WriteDataToSerialPort(QByteArray data); bool PacketParseHandler(); private: SerialPortHelper* m_serialPortManager; QMap<QString, MccbBase* > m_MccbProducMap; placeHolder m_PlaceHolder; bool m_ShowOriginPacket; QByteArray m_recvBuffer; QMutex m_Mutex; QThread *m_SerialPortThread; public slots: void SerialPortReadyReadSlot(); void SerialPorterrorOccurredSlot(QSerialPort::SerialPortError error); void SerialPortAboutToClose(); void doWork(); void timerUpdateSlot(); void UpdateMccbDataSlot(QString addr, QList<MqttData>& data); signals: void SerialBusExitSignal(); }; ``` ```c++ #include "SerialBusManager.h" #include <QtSerialPort/qserialportinfo.h> #include <QtSerialPort/qserialport.h> #include <qdebug.h> #include <qdatetime.h> #include <QTimer> #pragma execution_character_set("utf-8") SerialBusManager::SerialBusManager(QObject *parent) : QObject(parent) { m_PlaceHolder.keepHolding = false; m_ShowOriginPacket = true; } SerialBusManager::~SerialBusManager() { } bool SerialBusManager::RegisterMccb(const QString& addr, MccbBase* mccb) { if (m_MccbProducMap.find(addr) == m_MccbProducMap.end() && mccb != nullptr) { qDebug() << "Register mccb:" << addr; m_MccbProducMap[addr] = mccb; return true; } qWarning() << "Register mccb:" << addr << ",已存在或 mccb==nullptr"; return false; } MccbBase* SerialBusManager::UnRegisterMccb(const QString& addr) { if (m_MccbProducMap.find(addr) != m_MccbProducMap.end()) { qDebug() << "Unregister mccb:" << addr; auto ptr = m_MccbProducMap[addr]; m_MccbProducMap.remove(addr); return ptr; } qWarning() << "Unregister mccb:" << addr << ",不存在"; return nullptr; } MccbBase* SerialBusManager::GetMccb(const QString& addr) { if (m_MccbProducMap.find(addr) != m_MccbProducMap.end()) { auto ptr = m_MccbProducMap[addr]; return ptr; } return nullptr; } bool SerialBusManager::OpenSerial(bool showOriginPacket /*= false*/) { m_serialPortManager = new SerialPortHelper; m_SerialPortThread = new QThread; m_serialPortManager->moveToThread(m_SerialPortThread); m_SerialPortThread->start(); m_serialPortManager->OpenOport(showOriginPacket); m_serialPortManager->Init(); connect(m_serialPortManager->m_SerialPort, &QSerialPort::readyRead, this, &SerialBusManager::SerialPortReadyReadSlot); connect(m_serialPortManager->m_SerialPort, &QSerialPort::errorOccurred, this, &SerialBusManager::SerialPorterrorOccurredSlot); connect(m_serialPortManager->m_SerialPort, &QSerialPort::aboutToClose, this, &SerialBusManager::SerialPortAboutToClose); return true; } void SerialBusManager::doWork() { qDebug() << "Open Serial"; OpenSerial(true); m_recvBuffer = QByteArray(); qDebug() << "SerialBusManager::run START! Now ThreadID:" << QThread::currentThread(); /*QTimer* time = new QTimer(this); connect(time, &QTimer::timeout, this, &SerialBusManager::timerUpdateSlot); time->start(100);*/ while (!CfgHlp->GlobleExist) { //包解析 PacketParseHandler(); auto nowTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); //判断通道是否被占有 if (m_PlaceHolder.keepHolding) { if (nowTime - m_PlaceHolder.startTime >= m_PlaceHolder.lastingTime) { if (m_MccbProducMap.find(m_PlaceHolder.ownerAddr) != m_MccbProducMap.end()) { //连续超时计数 m_MccbProducMap[m_PlaceHolder.ownerAddr]->m_overTimes++; } m_PlaceHolder.keepHolding = false; m_PlaceHolder.ownerAddr = ""; } } //通道空闲处理 if (!m_PlaceHolder.keepHolding && m_MccbProducMap.size() > 0) { for (auto pMccb : m_MccbProducMap) { if (pMccb == nullptr) continue; uint8_t buffer[280]="\0"; //状态轮询 auto len = pMccb->StateLooper(buffer); if (len > 0) { WriteDataToSerialPort(QByteArray((const char*)buffer, len)); m_PlaceHolder.keepHolding = true; m_PlaceHolder.ownerAddr = pMccb->GetAddr(); m_PlaceHolder.startTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); break; } else if (pMccb->callYc) { pMccb->callAllYc(); pMccb->callYc = false; } else if (pMccb->callYx) { pMccb->callAllYx(); pMccb->callYx = false; } else if (pMccb->callParam) { pMccb->callAllParam(); pMccb->callParam = false; } else if (pMccb->callSum) { pMccb->callAllSum(); pMccb->callSum = false; } else if (pMccb->callExt) { pMccb->callAllExt(); pMccb->callExt = false; } } } QEventLoop loop; QTimer::singleShot(100, &loop, SLOT(quit())); loop.exec(); } qDebug() << "SerialBusManager::run END!"; m_SerialPortThread->wait(2000); } void SerialBusManager::timerUpdateSlot() { PacketParseHandler(); auto nowTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); if (m_PlaceHolder.keepHolding) { if (nowTime - m_PlaceHolder.startTime >= m_PlaceHolder.lastingTime) { m_PlaceHolder.keepHolding = false; m_PlaceHolder.ownerAddr = ""; } } if (!m_PlaceHolder.keepHolding && m_MccbProducMap.size() > 0) { uint8_t buffer[280] = "\0"; for (auto pMccb : m_MccbProducMap) { if (pMccb == nullptr) continue; memset(buffer, 0, 280); auto len = pMccb->StateLooper(buffer); if (len > 0) { WriteDataToSerialPort(QByteArray((const char*)buffer, len)); m_PlaceHolder.keepHolding = true; m_PlaceHolder.ownerAddr = pMccb->GetAddr(); m_PlaceHolder.startTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); } else if (pMccb->callYc) { pMccb->callAllYc(); pMccb->callYc = false; } } } } void SerialBusManager::UpdateMccbDataSlot(QString addr, QList<MqttData>& data) { for (auto it : data) { /*保存到总表*/ auto p = CfgHlp->m_DataSet.find({ addr,it.dataIndex }); if (p == CfgHlp->m_DataSet.end()) { qWarning() << "unknow data info while update data:" << addr << it.dataIndex; continue; } DataNode& p_ = const_cast<DataNode&>(*p); p_.nodeValue.setValue(it.Value); p_.updateTime = it.Time; ///*保存到分表*/ //for (auto &dev : CfgHlp->DevLists) //{ // if (dev.devAddr == addr) // { // } //} } //auto tmp = CfgHlp->m_DataSet.find({ "350201112158",2 }); //qDebug() << tmp->nodeValue.toString() << "\t" << tmp->updateTime; } bool SerialBusManager::WriteDataToSerialPort(QByteArray data) { if (m_serialPortManager == nullptr || m_serialPortManager->m_SerialPort == nullptr ||data.length()<=0) return false; if (m_ShowOriginPacket) qInfo() << "Send:" << data.toHex(); auto retLen = m_serialPortManager->m_SerialPort->write(data); if (retLen == -1) { qCritical() << "while write char* to serilPort,err occured." << m_serialPortManager->m_SerialPort->errorString(); return false; } else if (retLen < data.length()) { qCritical() << QString("while write char* to serilPort,lost some data=>realWrite/MaxWrite:%1/%2").arg(retLen).arg(data.length()); return false; } m_serialPortManager->m_SerialPort->waitForBytesWritten(); return true; } bool SerialBusManager::PacketParseHandler() { while (m_recvBuffer.length() > 0) { //报文结构判断 auto frameRet = MccbBase::isPacketFrame((uint8_t*)m_recvBuffer.data(), m_recvBuffer.length()); switch (frameRet) { case Mccb::retack::packetErr: //m_Mutex.lock(); m_recvBuffer.remove(0, 1); //m_Mutex.unlock(); break; case Mccb::retack::packetOk: { //获取设备地址 auto addr = MccbBase::getSlaveAddr((uint8_t*)m_recvBuffer.data(), m_recvBuffer.length()); //获取MCCB指针 auto pMccb = GetMccb(addr); if (pMccb != nullptr) { uint16_t packetLen = 0; uint8_t tmpBuffer[500] = "\0"; memcpy(tmpBuffer, &((uint8_t*)m_recvBuffer.data())[8], m_recvBuffer.length() - 10); //报文解析 auto parseRet = pMccb->MessageHandler(tmpBuffer, m_recvBuffer.length()-10, packetLen); switch (parseRet) { case Mccb::retack::packetErr: //qWarning() << "packet data Err."; break; case Mccb::retack::OkNoNext: case Mccb::retack::packetOk: m_PlaceHolder.keepHolding = false; m_PlaceHolder.ownerAddr = ""; if (m_MccbProducMap.find(m_PlaceHolder.ownerAddr) != m_MccbProducMap.end()) { //连续超时计数 m_MccbProducMap[m_PlaceHolder.ownerAddr]->m_overTimes = 0; } break; case Mccb::retack::OkNeedNext: { uint8_t buf[1024] = "\0"; auto nextLen = pMccb->MessageNextBufferHandler((uint8_t*)m_recvBuffer.data(), m_recvBuffer.length(), packetLen, buf); if (nextLen > 0) { if (WriteDataToSerialPort(QByteArray((const char*)buf, nextLen))) { m_PlaceHolder.keepHolding = true; m_PlaceHolder.startTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); if (m_PlaceHolder.ownerAddr != addr) m_PlaceHolder.ownerAddr = addr; break; } } qWarning() << "need next send failed."; m_PlaceHolder.keepHolding = false; m_PlaceHolder.ownerAddr = ""; if (m_MccbProducMap.find(m_PlaceHolder.ownerAddr) != m_MccbProducMap.end()) { //连续超时计数 m_MccbProducMap[m_PlaceHolder.ownerAddr]->m_overTimes = 0; } break; } case Mccb::retack::UpdatePacketErr: case Mccb::retack::RemoteCtrlErr: case Mccb::retack::CommSpeedChangeErr: case Mccb::retack::PasswordErr: case Mccb::retack::NoneRequestData: case Mccb::retack::illegalData: { m_PlaceHolder.keepHolding = false; m_PlaceHolder.ownerAddr = ""; qWarning() << "ErrMsg:" << MccbBase::getErrMsg(parseRet); break; } default: break; } } else { //qWarning() << QString("unknow mccb addr:%1").arg(addr); } } case Mccb::retack::PacketSumCheckErr: { auto len = MccbBase::getPacketLen((const uint8_t*)m_recvBuffer.data(), m_recvBuffer.length()); if (len > m_recvBuffer.length()) { len = m_recvBuffer.length(); } if (m_ShowOriginPacket) qInfo() << "完整帧:" << QByteArray(m_recvBuffer.data(), len).toHex(); //m_Mutex.lock(); m_recvBuffer.remove(0, len); //m_Mutex.unlock(); break; } default: return false; break; } } return false; } void SerialBusManager::SerialPortReadyReadSlot() { auto b = m_serialPortManager->m_SerialPort->readAll(); if (b.length() <= 0) return; /*if (m_ShowOriginPacket) qDebug() << "Recv:" << b.toHex();*/ //m_Mutex.lock(); m_recvBuffer.append(b.data(), b.length()); //m_Mutex.unlock(); } void SerialBusManager::SerialPorterrorOccurredSlot(QSerialPort::SerialPortError error) { qWarning() << "SerialPorterrorOccurred:" << m_serialPortManager->m_SerialPort->errorString(); m_serialPortManager->m_SerialPort->clearError(); } void SerialBusManager::SerialPortAboutToClose() { qWarning() << "***SerialPortAboutToClose***"; } ``` # 四.效果       最后修改:2022 年 05 月 08 日 10 : 09 PM © 允许规范转载