| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808 |
- #include "iec104masterqt.h"
- #include <QDateTime>
- #include <QHostAddress>
- #include <QtEndian>
- #include <cstdlib>
- #include <cstring>
- IEC104MasterQt::IEC104MasterQt(QObject *parent)
- : QObject(parent), m_socket(new QTcpSocket(this)), m_connected(false),
- m_rxCounter(0), m_txCounter(0), m_lastAckRx(0), m_lastAckTx(0), m_t0(30), m_t1(15), m_t2(10), m_t3(20), m_k(12), m_w(8),
- nasdu(1)
- {
- // Setup timers
- m_timerT1 = new QTimer(this);
- m_timerT2 = new QTimer(this);
- m_timerT3 = new QTimer(this);
- // m_timerT1->setSingleShot(true);
- // m_timerT2->setSingleShot(true);
- // m_timerT3->setSingleShot(false);
- // Connect socket signals
- connect(m_socket, &QTcpSocket::connected, this, &IEC104MasterQt::onSocketConnected);
- connect(m_socket, &QTcpSocket::disconnected, this, &IEC104MasterQt::onSocketDisconnected);
- connect(m_socket, &QTcpSocket::readyRead, this, &IEC104MasterQt::onSocketReadyRead);
- // 兼容不同Qt版本的错误信号连接
- #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
- // Qt 5.15+ 使用 errorOccurred
- connect(m_socket, &QTcpSocket::errorOccurred, this, &IEC104MasterQt::onSocketError);
- #else
- // Qt 5.15 之前使用 error
- connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SLOT(onSocketError(QAbstractSocket::SocketError)));
- #endif
- // Connect timer signals
- bool status=connect(m_timerT1, SIGNAL(timeout()), this, SLOT(onTimerT1Timeout()));
- status = connect(m_timerT2, SIGNAL(timeout()), this, SLOT(onTimerT2Timeout()));
- status = connect(m_timerT3, SIGNAL(timeout()), this, SLOT(onTimerT3Timeout()));
- status = false;
- //m_timerT3->start(m_t3 * 1000);
- }
- IEC104MasterQt::~IEC104MasterQt()
- {
- closeLink();
- }
- bool IEC104MasterQt::openLink()
- {
- if (m_connected)
- {
- emit logMessage("Already connected");
- return true;
- }
- emit logMessage(QString("Connecting to %1:%2").arg(m_serverIP).arg(m_port));
- m_socket->connectToHost(m_serverIP, m_port);
- return true;
- }
- void IEC104MasterQt::closeLink()
- {
- if (m_connected)
- {
- sendStopDT();
- }
- m_socket->disconnectFromHost();
- m_connected = false;
- emit connectionStatusChanged(false);
- m_timerT1->stop();
- m_timerT2->stop();
- m_timerT3->stop();
- }
- void IEC104MasterQt::setConnectionParameters(const QString &serverIP, int port)
- {
- m_serverIP = serverIP;
- m_port = port;
- }
- bool IEC104MasterQt::sendStartDT()
- {
- return sendUMessage(0x07); // STARTDT ACT
- }
- bool IEC104MasterQt::sendStopDT()
- {
- return sendUMessage(0x13); // STOPDT ACT
- }
- bool IEC104MasterQt::sendTestFR()
- {
- return sendUMessage(0x43); // TESTFR ACT
- }
- bool IEC104MasterQt::sendInterrogation(int asdu, int group)
- {
- QByteArray data;
- data.append(static_cast<char>(0x64)); // type
- data.append(static_cast<char>(0x01)); // qual
- data.append(static_cast<char>(0x06)); // cause
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(asdu & 0xFF));
- data.append(static_cast<char>((asdu >> 8) & 0xFF));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(20 + group));
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendASDUMessage(const QByteArray &data)
- {
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendUMessage(int command)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send U message");
- return false;
- }
- APCI apci;
- apci.start = 0x68;
- apci.len = 0x04;
- apci.field1 = 0x03 | command;
- apci.field2 = 0;
- apci.field3 = 0;
- apci.field4 = 0;
- QByteArray data(reinterpret_cast<const char *>(&apci), sizeof(apci));
- qint64 bytesWritten = m_socket->write(data);
- if (bytesWritten == sizeof(apci))
- {
- emit dataSent(data);
- emit logMessage(QString("Sent U message: %1").arg(toHexString(data).constData()));
- return true;
- }
- else
- {
- emit logMessage("Failed to send U message");
- return false;
- }
- }
- bool IEC104MasterQt::sendSMessage()
- {
- if (!m_connected)
- {
- return false;
- }
- APCI apci;
- apci.start = 0x68;
- apci.len = 0x04;
- apci.field1 = 0x01;
- apci.field2 = 0;
- apci.field3 = m_rxCounter & 0xFE;
- apci.field4 = (m_rxCounter >> 8) & 0xFF;
- QByteArray data(reinterpret_cast<const char *>(&apci), sizeof(apci));
- if (m_socket->write(data) == sizeof(apci))
- {
- emit dataSent(data);
- emit logMessage(QString("Sent S message: %1").arg(toHexString(data).constData()));
- return true;
- }
- return false;
- }
- bool IEC104MasterQt::sendIMessage(const QByteArray &asduData)
- {
- if (!m_connected)
- {
- return false;
- }
- QByteArray buffer;
- buffer.resize(sizeof(APCI) + asduData.size());
- APCI *apci = reinterpret_cast<APCI *>(buffer.data());
- apci->start = 0x68;
- apci->len = 0x04 + asduData.size();
- apci->field1 = m_txCounter & 0xFE;
- apci->field2 = (m_txCounter >> 8) & 0xFF;
- apci->field3 = m_rxCounter & 0xFE;
- apci->field4 = (m_rxCounter >> 8) & 0xFF;
- memcpy(buffer.data() + sizeof(APCI), asduData.constData(), asduData.size());
- if (m_socket->write(buffer) == buffer.size())
- {
- emit dataSent(buffer);
- emit logMessage(QString("Sent I message: %1").arg(toHexString(buffer).constData()));
- m_txCounter += 2;
- return true;
- }
- return false;
- }
- void IEC104MasterQt::onSocketConnected()
- {
- m_connected = true;
- emit connectionStatusChanged(true);
- emit logMessage("Socket connected successfully");
- // Start data transfer
- sendStartDT();
- // 使用单次定时器确保在事件循环中执行
- //QTimer::singleShot(10, this, &IEC104MasterQt::delayedStartT3Timer);
- // Start supervision timer
- m_timerT3->start(m_t3 * 1000);
- // if (!m_timerT3->isActive())
- // {
- // m_timerT3->start(3000);
- // }
- }
- void IEC104MasterQt::onSocketDisconnected()
- {
- m_connected = false;
- emit connectionStatusChanged(false);
- emit logMessage("Socket disconnected");
- m_timerT1->stop();
- m_timerT2->stop();
- m_timerT3->stop();
- }
- void IEC104MasterQt::onSocketReadyRead()
- {
- QByteArray data = m_socket->readAll();
- emit dataReceived(data);
- emit logMessage(QString("Received data: %1").arg(toHexString(data).constData()));
- processReceivedData(data);
- }
- void IEC104MasterQt::onSocketError(QAbstractSocket::SocketError error)
- {
- Q_UNUSED(error)
- emit logMessage(QString("Socket error: %1").arg(m_socket->errorString()));
- if (m_connected)
- {
- m_connected = false;
- emit connectionStatusChanged(false);
- }
- }
- void IEC104MasterQt::onTimerT1Timeout()
- {
- emit logMessage("T1 timeout - No confirmation received");
- closeLink();
- }
- void IEC104MasterQt::onTimerT2Timeout()
- {
- sendSMessage();
- //m_timerT2->start(m_t2 * 1000);
- }
- void IEC104MasterQt::onTimerT3Timeout()
- {
- if (m_connected)
- {
- sendTestFR();
- //m_timerT3->start(m_t3 * 1000);
- }
- }
- void IEC104MasterQt::delayedStartT3Timer()
- {
- if (m_connected && m_timerT3) {
- if (m_timerT3->isActive()) {
- m_timerT3->stop();
- }
- m_timerT3->start(m_t3 * 1000);
- emit logMessage(QString("T3 timer started via delayed call, active: %1, interval: %2ms")
- .arg(m_timerT3->isActive()).arg(m_t3 * 1000));
- }
- }
- void IEC104MasterQt::processReceivedData(const QByteArray &data)
- {
- int index = 0;
- while (index < data.size())
- {
- if (static_cast<unsigned char>(data[index]) == 0x68)
- {
- if (index + 1 < data.size())
- {
- int length = static_cast<unsigned char>(data[index + 1]);
- if (index + length + 2 <= data.size())
- {
- QByteArray frame = data.mid(index, length + 2);
- const APCI *apci = reinterpret_cast<const APCI *>(frame.constData());
- int formatType = apci->field1 & 0x03;
- if (formatType == 0 || formatType == 2)
- { // I format
- //m_timerT3->stop(); // Reset test timer
- int revSendNum = (apci->field2 << 8) | apci->field1;
- m_rxCounter = revSendNum;
- m_lastAckTx = (apci->field4 << 8) | apci->field3;
- sendSMessage();
- QByteArray asduData = frame.mid(sizeof(APCI));
- decodeIMessage(asduData);
- }
- else if (formatType == 3)
- { // U format
- //m_timerT3->stop(); // Reset test timer
- processFormatU(*apci);
- m_lastAckTx = (apci->field4 << 8) | apci->field3;
- }
- index += length + 2;
- continue;
- }
- }
- }
- index++;
- }
- }
- void IEC104MasterQt::decodeIMessage(const QByteArray &data)
- {
- if (data.size() < 6)
- return;
- const ASDU_header *header = reinterpret_cast<const ASDU_header *>(data.constData());
- int num = header->qual & 0x7F;
- bool seq = (header->qual & 0x80) != 0;
- int cause = header->tx_cause_1;
- int asdu = (header->commom_asdu_2 << 8) | header->commom_asdu_1;
- emit logMessage(QString("ASDU Address=%1, TypeID=%2, Count=%3, Cause=%4")
- .arg(asdu)
- .arg(header->type)
- .arg(num)
- .arg(cause));
- int pos = sizeof(ASDU_header);
- switch (header->type)
- {
- case 1:
- { // Single-point information (遥信)
- if (seq)
- {
- if (pos + sizeof(SP104) <= data.size())
- {
- const SP104 *sp = reinterpret_cast<const SP104 *>(data.constData() + pos);
- int address = (sp->addr2 << 16) | (sp->addr1 << 8) | sp->addr0;
- updateEquipmentStatus(address, sp->siq.spi, 0);
- emit logMessage(QString("SP %1: %2").arg(address).arg(sp->siq.spi));
- pos += sizeof(SP104);
- // Process subsequent SIQ values in sequence
- while (pos < data.size())
- {
- const SIQ104 *siq = reinterpret_cast<const SIQ104 *>(data.constData() + pos);
- address++;
- updateEquipmentStatus(address, siq->spi, 0);
- emit logMessage(QString("SP %1: %2").arg(address).arg(siq->spi));
- pos++;
- }
- }
- }
- else
- {
- while (pos + sizeof(SP104) <= data.size())
- {
- const SP104 *sp = reinterpret_cast<const SP104 *>(data.constData() + pos);
- int address = (sp->addr2 << 16) | (sp->addr1 << 8) | sp->addr0;
- updateEquipmentStatus(address, sp->siq.spi, 0);
- emit logMessage(QString("SP %1: %2").arg(address).arg(sp->siq.spi));
- pos += sizeof(SP104);
- }
- }
- if (cause == 3)
- {
- sendSMessage();
- }
- }
- break;
- case 3:
- { // Double-point information without time tag (双点信息,不带时标)
- if (seq)
- {
- // 序列方式(地址连续)
- if (pos + sizeof(DP104) <= data.size())
- {
- const DP104* dp = reinterpret_cast<const DP104*>(data.constData() + pos);
- int address = (dp->addr2 << 16) | (dp->addr1 << 8) | dp->addr0;
- // 解析双点状态
- int status = 0;
- switch (dp->diq.dpi) {
- case 1: status = 1; break; // 分
- case 2: status = 2; break; // 合
- case 0: status = 0; break; // 中间状态
- case 3: status = 4; break; // 不确定状态
- }
- updateEquipmentStatus(address, status, 1);
- emit logMessage(QString("DP %1: %2 (DPI=%3)").arg(address).arg(status).arg(dp->diq.dpi));
- pos += sizeof(DP104);
- // 处理后续的双点信息(序列方式)
- while (pos < data.size())
- {
- const DIQ104* diq = reinterpret_cast<const DIQ104*>(data.constData() + pos);
- address++;
- int subsequentStatus = 0;
- switch (diq->dpi) {
- case 1: subsequentStatus = 1; break;
- case 2: subsequentStatus = 2; break;
- case 0: subsequentStatus = 0; break;
- case 3: subsequentStatus = 4; break;
- }
- updateEquipmentStatus(address, subsequentStatus, 1);
- emit logMessage(QString("DP %1: %2 (DPI=%3)").arg(address).arg(subsequentStatus).arg(diq->dpi));
- pos++;
- }
- }
- }
- else
- {
- // 非序列方式(独立地址)
- while (pos + sizeof(DP104) <= data.size())
- {
- const DP104* dp = reinterpret_cast<const DP104*>(data.constData() + pos);
- int address = (dp->addr2 << 16) | (dp->addr1 << 8) | dp->addr0;
- // 解析双点状态
- int status = 0;
- switch (dp->diq.dpi) {
- case 1: status = 1; break; // 分
- case 2: status = 2; break; // 合
- case 0: status = 0; break; // 中间状态
- case 3: status = 4; break; // 不确定状态
- }
- updateEquipmentStatus(address, status, 1);
- emit logMessage(QString("DP %1: %2 (DPI=%3)").arg(address).arg(status).arg(dp->diq.dpi));
- pos += sizeof(DP104);
- }
- }
- if (cause == 3) {
- sendSMessage(); // 发送确认帧
- }
- break;
- }
- break;
- case 9:
- { // Measured value, normalized value (规一化测量值)
- while (pos + 5 <= data.size())
- { // 地址3字节 + 值2字节 + QDS1字节
- const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data.constData() + pos);
- int address = (ptr[2] << 16) | (ptr[1] << 8) | ptr[0];
- // 规一化值 (2字节,有符号)
- short normalizedValue = (ptr[4] << 8) | ptr[3];
- float value = normalizedValue; // 可根据需要转换为实际工程值
- QDS104 qds;
- memcpy(&qds, ptr + 5, sizeof(QDS104));
- updateMeasuredValue(address, value, !qds.iv, qds.ov, qds.bl, qds.sb);
- emit logMessage(QString("Normalized Value %1: %2, Valid: %3")
- .arg(address)
- .arg(value)
- .arg(!qds.iv));
- pos += 6; // 3字节地址 + 2字节值 + 1字节QDS
- }
-
- }
- break;
- case 13:
- { // Measured value, short floating point value (短浮点数测量值)
- while (pos + sizeof(SFP104) <= data.size())
- {
- const SFP104 *sfp = reinterpret_cast<const SFP104 *>(data.constData() + pos);
- int address = (sfp->addr2 << 16) | (sfp->addr1 << 8) | sfp->addr0;
- float value = bytesToFloat(sfp->val);
- updateMeasuredValue(address, value, !sfp->qds.iv, sfp->qds.ov, sfp->qds.bl, sfp->qds.sb);
- emit logMessage(QString("Short Float %1: %2, Valid: %3, Overflow: %4")
- .arg(address)
- .arg(value)
- .arg(!sfp->qds.iv)
- .arg(sfp->qds.ov));
- pos += sizeof(SFP104);
- }
-
- }
- break;
- case 30:
- { // Single-point information with time tag (带时标遥信)
- while (pos + sizeof(SP104_T) <= data.size())
- {
- const SP104_T *spt = reinterpret_cast<const SP104_T *>(data.constData() + pos);
- int address = (spt->addr2 << 16) | (spt->addr1 << 8) | spt->addr0;
- updateEquipmentStatus(address, spt->siq.spi, 0);
- emit logMessage(QString("SP with time %1: %2").arg(address).arg(spt->siq.spi));
- pos += sizeof(SP104_T);
- }
- if (cause == 3)
- {
- sendSMessage();
- }
-
- }
- break;
- case 31:
- { // Double-point information with time tag (带时标双点遥信)
- while (pos + sizeof(SP104_T) <= data.size())
- {
- const SP104_T *spt = reinterpret_cast<const SP104_T *>(data.constData() + pos);
- int address = (spt->addr2 << 16) | (spt->addr1 << 8) | spt->addr0;
- int nStatus = 0;
- if (spt->siq.spi && !spt->siq.rs1)
- {
- nStatus = 1;
- } // 1 0分
- else if (!spt->siq.spi && spt->siq.rs1)
- {
- nStatus = 2;
- } // 0 1合
- else if (spt->siq.spi && spt->siq.rs1)
- {
- nStatus = 4;
- } // 11不确定状态
- else
- {
- nStatus = 0;
- } //
- updateEquipmentStatus(address, nStatus, 1);
- emit logMessage(QString("DP with time %1: %2 %3").arg(address).arg(spt->siq.spi).arg(spt->siq.rs1));
- pos += sizeof(SP104_T);
- }
- if (cause == 3)
- {
- sendSMessage();
- }
-
- }
- break;
- case 35:
- { // Measured value, scaled value with time tag CP56Time2a (带时标的标度化值)
- while (pos + sizeof(ScaledValueWithTime) <= data.size())
- {
- const ScaledValueWithTime* svt = reinterpret_cast<const ScaledValueWithTime*>(data.constData() + pos);
- int address = (svt->addr2 << 16) | (svt->addr1 << 8) | svt->addr0;
- // 标度化值(2字节有符号整数)
- short scaledValue = (svt->value_high << 8) | svt->value_low;
- float value = static_cast<float>(scaledValue); // 可根据实际标度转换为工程值
- // 解析时标
- QDateTime timestamp = cp56TimeToDateTime(svt->time);
- // 更新测量值(带时标)
- QMutexLocker locker(&m_statusMutex);
- MeasuredValue mv;
- mv.value = value;
- mv.valid = !svt->qds.iv;
- mv.overflow = svt->qds.ov;
- mv.blocked = svt->qds.bl;
- mv.substituted = svt->qds.sb;
- mv.timestamp = timestamp; // 使用报文中的时标
- m_measuredValues[address] = mv;
- emit measuredValueUpdated(address, value, !svt->qds.iv);
- emit logMessage(QString("Scaled Value with time %1: %2, Valid: %3, Time: %4")
- .arg(address)
- .arg(value)
- .arg(!svt->qds.iv)
- .arg(timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz")));
- pos += sizeof(ScaledValueWithTime);
- }
- break;
- }
- case 36:
- { // Measured value, short float point value w/CP56Time2a (带时标短浮点数)
- while (pos + sizeof(SFP104_T) <= data.size())
- {
- const SFP104_T *sfpt = reinterpret_cast<const SFP104_T *>(data.constData() + pos);
- int address = (sfpt->addr2 << 16) | (sfpt->addr1 << 8) | sfpt->addr0;
- float value = bytesToFloat(sfpt->val);
- QDateTime timestamp = cp56TimeToDateTime(sfpt->time);
- updateMeasuredValue(address, value, !sfpt->qds.iv, sfpt->qds.ov, sfpt->qds.bl, sfpt->qds.sb);
- emit logMessage(QString("Short Float with time %1: %2, Valid: %3, Time: %4")
- .arg(address)
- .arg(value)
- .arg(!sfpt->qds.iv)
- .arg(timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz")));
- pos += sizeof(SFP104_T);
- }
-
- }
- break;
- // 新增:遥控命令确认
- case 45: // Single command (单命令)
- case 46: // Double command (双命令)
- case 59:
- processControlCommand(header, data.mid(pos), cause);
- break;
- // 新增:设值命令确认
- case 50: // Setpoint command, normalized value (设点命令规范化值)
- case 51: // Setpoint command, normalized value with time tag
- //case 100: // Setpoint command, short floating point value (设点命令短浮点数)
- processSetpointCommand(header, data.mid(pos), cause);
- break;
- case 140: // Setpoint command, normalized value with time tag
- {
- if (sizeof(ER140_Head) <= data.size())
- {
- const ER140_Head *spt = reinterpret_cast<const ER140_Head *>(data.constData());
- // 信息对象地址
- int msgadder = (spt->msgadder3 << 16) | (spt->msgadder2 << 8) | spt->msgadder1;
- // 装置地址 -- 四遥表中装置地址
- int eqpmtadder = (spt->eqpmtadder2 << 8) | spt->eqpmtadder1;
- // 信息序号
- int msgid = (spt->addr2 << 8) | spt->addr1;
- // 双点信息 合2 分1
- int dpvalue = spt->dpvalue;
- // 相对时间
- int dsTime = (spt->dsTime2 << 8) | spt->dsTime1;
- // 故障序号
- int erid = (spt->erid2 << 8) | spt->erid1;
- // 时标
- QDateTime timestamp = cp56TimeToDateTime(spt->time);
- // 故障电量个数
- int erNum = spt->num;
- QString strTemp = QString("ER with timer Type: %1; msgadder: %2; eqpmtadder: %3; msgid: %4; dpvalue: %5; erid: %6; erNum: 57")
- .arg(spt->head.type)
- .arg(msgadder)
- .arg(eqpmtadder)
- .arg(msgid)
- .arg(dpvalue)
- .arg(erid)
- .arg(erNum);
- emit logMessage(strTemp);
- pos = sizeof(ER140_Head);
- int nIndex = 0;
- while (pos + sizeof(ER140_Data) + sizeof(unsigned char) <= data.size())
- {
- const ER140_Data *spt1 = reinterpret_cast<const ER140_Data *>(data.constData() + pos);
- QString strReset = "ER_Data" + QString::number(nIndex) + "/" + QString::number(spt->num) + " subType=" + QString::number(spt1->ERType);
- QString strData = "";
- pos += sizeof(ER142_Data);
- int nErIndex = (spt1->Num2 << 8) | spt1->Num1;
- strData = " nErIndex = " + QString::number(nErIndex);
- strReset += strData;
- switch (spt1->ERType)
- {
- case 1:
- case 2:
- {
- unsigned char pCharData = 0;
- memcpy(&pCharData, data.constData() + pos, sizeof(unsigned char));
- strData = QString::number(pCharData);
- pos += sizeof(unsigned char);
- }
- break;
- case 3:
- case 4:
- {
- unsigned char Data1[2] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 2);
- int value = (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- pos += sizeof(unsigned char) * 2;
- }
- break;
- case 5:
- case 6:
- case 7:
- {
- unsigned char Data1[4] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 4);
- if (spt1->ERType == 7)
- {
- float value = bytesToFloat(Data1);
- strData = QString::number(value);
- }
- else
- {
- int value = (Data1[3] << 24) | (Data1[2] << 16) | (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- }
- pos += sizeof(unsigned char) * 4;
- }
- break;
- case 8:
- {
- char Data1[8] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 8);
- strData = QString::fromLocal8Bit(Data1, 8);
- pos += sizeof(unsigned char) * 8;
- }
- break;
- }
- // pos += sizeof(unsigned char)*8;
- strReset.append(" Data=" + strData);
- emit logMessage(strReset);
- nIndex++;
- }
- }
- }
- break;
- case 142: // Setpoint command, normalized value with time tag
- {
- if (sizeof(ER142_Head) <= data.size())
- {
- const ER142_Head *spt = reinterpret_cast<const ER142_Head *>(data.constData());
- int eqpmtadder = (spt->eqpmtadder2 << 8) | spt->eqpmtadder1;
- int ERID = (spt->addr2 << 8) | spt->addr1;
- int eventnum = spt->evetnum;
- QString strTemp = QString("ER with timer Type: %1; eqpmtadder: %2; msgid: %3; eventnum: %4").arg(spt->head.type).arg(eqpmtadder).arg(ERID).arg(eventnum);
- emit logMessage(strTemp);
- pos = sizeof(ER142_Head);
- int nIndex = 0;
- while (pos + sizeof(ER142_Data) + sizeof(unsigned char) <= data.size())
- {
- const ER142_Data *spt1 = reinterpret_cast<const ER142_Data *>(data.constData() + pos);
- QString strReset = "ER_Data" + QString::number(nIndex) + "/" + QString::number(spt->ernum) + " subType=" + QString::number(spt1->ERType);
- QString strData = "";
- pos += sizeof(ER142_Data);
- int nErIndex = (spt1->Num2 << 8) | spt1->Num1;
- strData = " nErIndex = " + QString::number(nErIndex);
- strReset += strData;
- switch (spt1->ERType)
- {
- case 1:
- case 2:
- {
- unsigned char pCharData = 0;
- memcpy(&pCharData, data.constData() + pos, sizeof(unsigned char));
- strData = QString::number(pCharData);
- pos += sizeof(unsigned char);
- }
- break;
- case 3:
- case 4:
- {
- unsigned char Data1[2] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 2);
- int value = (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- pos += sizeof(unsigned char) * 2;
- }
- break;
- case 5:
- case 6:
- case 7:
- {
- unsigned char Data1[4] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 4);
- if (spt1->ERType == 7)
- {
- float value = bytesToFloat(Data1);
- strData = QString::number(value);
- }
- else
- {
- int value = (Data1[3] << 24) | (Data1[2] << 16) | (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- }
- pos += sizeof(unsigned char) * 4;
- }
- break;
- case 8:
- {
- char Data1[8] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 8);
- strData = QString::fromLocal8Bit(Data1, 8);
- pos += sizeof(unsigned char) * 8;
- }
- break;
- }
- // pos += sizeof(unsigned char)*8;
- strReset.append(" Data=" + strData);
- emit logMessage(strReset);
- nIndex++;
- }
- }
- }
- break;
- case 143: // Setpoint command, normalized value with time tag
- {
- if (sizeof(ER143_Head) <= data.size())
- {
- const ER143_Head *spt = reinterpret_cast<const ER143_Head *>(data.constData());
- // 信息对象地址
- int msgadder = (spt->msgadder3 << 16) | (spt->msgadder2 << 8) | spt->msgadder1;
- // 装置地址
- int eqpmtadder = (spt->eqpmtadder2 << 8) | spt->eqpmtadder1;
- // 故障序号
- int ERID = (spt->addr2 << 8) | spt->addr1;
- int NGD = spt->ngd; // 大循环的范围
- // 时间
- QString strTimeData = "";
- pos = sizeof(ER143_Head);
- for (int nIndex = 0; nIndex < NGD; nIndex++)
- {
- int nEventNum = 0;
- if (msgadder == 0)
- {
- const ER143_SData *SData = reinterpret_cast<const ER143_SData *>(data.constData() + pos);
- pos += sizeof(ER143_LData);
- int nTimeData = (SData->nTime[1] << 8) | SData->nTime[0];
- nEventNum = SData->nNumber;
- strTimeData = "DTime=" + QString::number(nTimeData) + "ms";
- }
- else
- {
- const ER143_LData *SData = reinterpret_cast<const ER143_LData *>(data.constData() + pos);
- pos += sizeof(ER143_LData);
- int nTimeData = (SData->nTime[3] << 24) | (SData->nTime[2] << 16) | (SData->nTime[1] << 8) | SData->nTime[0];
- nEventNum = SData->nNumber;
- strTimeData = "DTime=" + QString::number(nTimeData) + "ms";
- }
- emit logMessage("Event" + QString::number(nIndex) + " " + strTimeData);
- for (int subIndex = 0; subIndex < nEventNum; subIndex++)
- {
- const ER143_Data *spt1 = reinterpret_cast<const ER143_Data *>(data.constData() + pos);
- QString strReset = "ER_Data" + QString::number(subIndex) + "/" + nEventNum + " subType=" + QString::number(spt1->ERType);
- QString strData = "";
- pos += sizeof(ER143_Data);
- int nErIndex = (spt1->Num2 << 8) | spt1->Num1;
- strData = " nErIndex = " + QString::number(nErIndex);
- strReset += strData;
- switch (spt1->ERType)
- {
- case 1:
- case 2:
- {
- unsigned char pCharData = 0;
- memcpy(&pCharData, data.constData() + pos, sizeof(unsigned char));
- strData = QString::number(pCharData);
- pos += sizeof(unsigned char);
- }
- break;
- case 3:
- case 4:
- {
- unsigned char Data1[2] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 2);
- int value = (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- pos += sizeof(unsigned char) * 2;
- }
- break;
- case 5:
- case 6:
- case 7:
- {
- unsigned char Data1[4] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 4);
- if (spt1->ERType == 7)
- {
- float value = bytesToFloat(Data1);
- strData = QString::number(value);
- }
- else
- {
- int value = (Data1[3] << 24) | (Data1[2] << 16) | (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- }
- pos += sizeof(unsigned char) * 4;
- }
- break;
- case 8:
- {
- char Data1[8] = {0};
- memcpy(Data1, data.constData() + pos, sizeof(unsigned char) * 8);
- strData = QString::fromLocal8Bit(Data1, 8);
- pos += sizeof(unsigned char) * 8;
- }
- break;
- }
- strReset.append(" Data=" + strData);
- emit logMessage(strReset);
- }
- }
- QString strTemp = QString("ER with timer Type: %1; msgadder: %2;eqpmtadder: %3; ERID: %4; NGD: %5").arg(spt->head.type).arg(msgadder).arg(eqpmtadder).arg(ERID).arg(NGD);
- emit logMessage(strTemp);
- }
- }
- break;
- case 100: { // Interrogation command (总召)
- if (cause == 7) { // 激活确认
- emit logMessage("Interrogation activation confirmation received");
- // 可以在这里触发数据处理或状态更新
- }
- else if (cause == 10) { // 激活终止
- sendSMessage();
- emit logMessage("Interrogation activation termination received");
- // 总召唤完成,可以在这里发送完成信号
- //emit interrogationCompleted(true);
- }
- else if (cause == 47) { // 命令出错
- emit logMessage("Interrogation command error");
- //emit interrogationCompleted(false);
- }
- break;
- }
- case 145://定值返回数据处理
- {
- FixValueCommand(header, data.mid(pos), cause);
- }
- break;
- case F_FR_NA_1: // 文件准备就绪
- processFileReady(header, data.mid(pos), cause);
- break;
- case F_SR_NA_1: // 节准备就绪
- processSectionReady(header, data.mid(pos), cause);
- break;
- case F_SC_NA_1: // 文件召唤/选择
- processFileCall(header, data.mid(pos), cause);
- break;
- case F_LS_NA_1: // 最后的节/段
- processLastSection(header, data.mid(pos), cause);
- break;
- case F_AF_NA_1: // 认可文件/段
- processFileAck(header, data.mid(pos), cause);
- break;
- case F_SG_NA_1: // 段
- processFileSegment(header, data.mid(pos), cause);
- break;
- case F_DR_NA_1: // 目录
- processDirectory(header, data.mid(pos), cause);
- break;
- default:
- emit logMessage(QString("Unhandled ASDU type: %1").arg(header->type));
- break;
- }
- }
- // 字节序列转换为浮点数
- float IEC104MasterQt::bytesToFloat(const unsigned char *bytes)
- {
- // IEC 104使用小端字节序
- uint32_t temp = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
- return *reinterpret_cast<float *>(&temp);
- }
- // CP56Time2a时间格式转换为QDateTime
- QDateTime IEC104MasterQt::cp56TimeToDateTime(const unsigned char *timeData)
- {
- // CP56Time2a格式:
- // 字节1-2: 毫秒(0-59999)
- // 字节3: 分钟(0-59)
- // 字节4: 小时(0-23)
- // 字节5: 日期(bit0-4:日, bit5-7:星期)
- // 字节6: 月(0-12)
- // 字节7: 年(0-99, 相对于2000年)
- int milliseconds = (timeData[1] << 8) | timeData[0];
- int seconds = milliseconds / 1000;
- milliseconds = milliseconds % 1000;
- int minutes = timeData[2] & 0x3F; // 去除RES1和RES2位
- int hours = timeData[3] & 0x1F; // 去除RES位
- int day = timeData[4] & 0x1F;
- int month = timeData[5] & 0x0F;
- int year = timeData[6] & 0x7F + 2000;
- QDate date(year, month, day);
- QTime time(hours, minutes, seconds, milliseconds);
- return QDateTime(date, time, Qt::UTC); // IEC 104使用UTC时间
- }
- QByteArray IEC104MasterQt::dateTimeToCp56Time2a(const QDateTime &dateTime)
- {
- QByteArray cp56Time(7, 0);
- // 转换为本地时区(104规约通常使用本地时间)
- QDateTime localDateTime = dateTime.toLocalTime();
- // 获取时间组件
- QDate date = localDateTime.date();
- QTime time = localDateTime.time();
- // 字节1-2:毫秒(低字节在前)
- int milliseconds = time.msec() + time.second() * 1000;
- cp56Time[0] = static_cast<char>(milliseconds & 0xFF); // 低字节
- cp56Time[1] = static_cast<char>((milliseconds >> 8) & 0xFF); // 高字节
- // 字节3:分钟
- cp56Time[2] = static_cast<char>(time.minute() & 0x3F); // 只取低6位
- // 字节4:小时
- cp56Time[3] = static_cast<char>(time.hour() & 0x1F); // 只取低5位
- // 字节5:月的日期(1-31)
- cp56Time[4] = static_cast<char>(date.day() & 0x1F); // 只取低5位
- // 字节6:星期(位0-2) + 月的索引(位4-7)
- int dayOfWeek = date.dayOfWeek(); // 1=周一, 7=周日
- if (dayOfWeek == 7)
- dayOfWeek = 0; // 104规约中0表示周日
- else
- dayOfWeek--; // 调整为0-6
- int month = date.month() - 1; // 月份索引(0-11)
- cp56Time[5] = static_cast<char>((month << 4) | (dayOfWeek & 0x07));
- // 字节7:年(0-99,相对于2000年)
- int year = date.year() - 2000;
- cp56Time[6] = static_cast<char>(year & 0x7F);
- return cp56Time;
- }
- void IEC104MasterQt::updateEquipmentStatus(int address, int status, int nSingle)
- {
- QMutexLocker locker(&m_statusMutex);
- m_equipmentStatus[address] = status;
- emit equipmentStatusUpdated(address, status, nSingle);
- }
- void IEC104MasterQt::updateMeasuredValue(int address, float value, bool valid,
- bool overflow, bool blocked, bool substituted)
- {
- QMutexLocker locker(&m_statusMutex);
- MeasuredValue mv;
- mv.value = value;
- mv.valid = valid;
- mv.overflow = overflow;
- mv.blocked = blocked;
- mv.substituted = substituted;
- mv.timestamp = QDateTime::currentDateTime();
- m_measuredValues[address] = mv;
- emit measuredValueUpdated(address, value, valid);
- }
- QMap<int, MeasuredValue> IEC104MasterQt::getMeasuredValues() const
- {
- QMutexLocker locker(&m_statusMutex);
- return m_measuredValues;
- }
- QMap<int, QMap<int, QMap<int, FixDataValue> > > IEC104MasterQt::getFixDataValues() const
- {
- QMutexLocker locker(&m_statusMutex);
- return m_fixValues;
- }
- QByteArray IEC104MasterQt::toHexString(const QByteArray &data)
- {
- QByteArray result;
- for (int i = 0; i < data.size(); ++i)
- {
- if (i > 0)
- result.append(' ');
- result.append(QByteArray::number(static_cast<unsigned char>(data[i]), 16).right(2).rightJustified(2, '0'));
- }
- return result;
- }
- void IEC104MasterQt::processFormatU(const APCI &apci)
- {
- int command = apci.field1;
- switch (command)
- {
- case 0x07: // STARTDT CON
- emit logMessage("Received STARTDT confirmation");
- break;
- case 0x0B: // STOPDT CON
- emit logMessage("Received STOPDT confirmation");
- break;
- case 0x13: // STOPDT ACT
- emit logMessage("Received STOPDT ACT");
- // 应该回复 STOPDT CON
- sendUMessage(0x23);
- break;
- case 0x23: // STOPDT CON
- emit logMessage("Received STOPDT confirmation");
- break;
- case 0x43: // TESTFR CON
- emit logMessage("Received TESTFR confirmation");
- // 应该回复 TESTFR CON
- sendUMessage(0x83);
- break;
- case 0x83: // TESTFR CON
- emit logMessage("Received TESTFR confirmation");
- break;
- default:
- emit logMessage(QString("Unknown U format command: 0x%1").arg(command, 2, 16, QLatin1Char('0')));
- break;
- }
- }
- QString IEC104MasterQt::getDataValue(int &nPos, const QByteArray &data, int nType)
- {
- QString strData="";
- switch (nType)
- {
- case 1:
- case 2:
- {
- unsigned char pCharData = 0;
- memcpy(&pCharData, data.constData() + nPos, sizeof(unsigned char));
- strData = QString::number(pCharData);
- nPos += sizeof(unsigned char);
- }
- break;
- case 3:
- case 4:
- {
- unsigned char Data1[2] = {0};
- memcpy(Data1, data.constData() + nPos, sizeof(unsigned char) * 2);
- int value = (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- nPos += sizeof(unsigned char) * 2;
- }
- break;
- case 5:
- case 6:
- case 7:
- {
- unsigned char Data1[4] = {0};
- memcpy(Data1, data.constData() + nPos, sizeof(unsigned char) * 4);
- if (nType == 7)
- {
- float value = bytesToFloat(Data1);
- strData = QString::number(value);
- }
- else
- {
- int value = (Data1[3] << 24) | (Data1[2] << 16) | (Data1[1] << 8) | Data1[0];
- strData = QString::number(value);
- }
- nPos += sizeof(unsigned char) * 4;
- }
- break;
- case 8:
- {
- char Data1[8] = {0};
- memcpy(Data1, data.constData() + nPos, sizeof(unsigned char) * 8);
- strData = QString::fromLocal8Bit(Data1, 8);
- nPos += sizeof(unsigned char) * 8;
- }
- break;
- }
- return strData;
- }
- QString IEC104MasterQt::Data2Value(int &nPos, const QByteArray &data, int nType)
- {
- if (nPos < 0 || nPos >= data.size()) {
- return QString();
- }
- switch (nType) {
- case TYPE_UI8: {
- if (nPos + 1 > data.size()) return QString();
- quint8 value = static_cast<quint8>(data.at(nPos));
- nPos += 1;
- return QString::number(value);
- }
- case TYPE_I8: {
- if (nPos + 1 > data.size()) return QString();
- qint8 value = static_cast<qint8>(data.at(nPos));
- nPos += 1;
- return QString::number(value);
- }
- case TYPE_UI16: {
- if (nPos + 2 > data.size()) return QString();
- quint16 value = *reinterpret_cast<const quint16*>(data.constData() + nPos);
- value = qFromLittleEndian(value);
- nPos += 2;
- return QString::number(value);
- }
- case TYPE_I16: {
- if (nPos + 2 > data.size()) return QString();
- qint16 value = *reinterpret_cast<const qint16*>(data.constData() + nPos);
- value = qFromLittleEndian(value);
- nPos += 2;
- return QString::number(value);
- }
- case TYPE_UI32: {
- if (nPos + 4 > data.size()) return QString();
- quint32 value = *reinterpret_cast<const quint32*>(data.constData() + nPos);
- value = qFromLittleEndian(value);
- nPos += 4;
- return QString::number(value);
- }
- case TYPE_I32: {
- if (nPos + 4 > data.size()) return QString();
- qint32 value = *reinterpret_cast<const qint32*>(data.constData() + nPos);
- value = qFromLittleEndian(value);
- nPos += 4;
- return QString::number(value);
- }
- case TYPE_F32: {
- if (nPos + 4 > data.size()) return QString();
- // 使用手动字节交换方法处理浮点数
- unsigned char Data1[4] = {0};
- memcpy(Data1, data.constData() + nPos, sizeof(unsigned char) * 4);
- float value = bytesToFloat(Data1);
- nPos += 4;
- return QString::number(value);
- }
- case TYPE_S64: {
- if (nPos + 8 > data.size()) return QString();
- char Data1[8] = {0};
- memcpy(Data1, data.constData() + nPos, sizeof(unsigned char) * 8);
- nPos += sizeof(unsigned char) * 8;
- // 注意:浮点数的字节序处理需要特别小心
- // 这里假设系统字节序与数据字节序一致,实际使用时可能需要手动转换
- nPos += 8;
- return QString::fromLocal8Bit(Data1, 8);
- }
- default:
- return QString();
- }
- }
- bool IEC104MasterQt::Value2Data(QByteArray &data, int nType, const QString &strData)
- {
- bool ok = false;
- switch (nType) {
- case TYPE_UI8: {
- quint8 value = static_cast<quint8>(strData.toUShort(&ok));
- if (ok) {
- data.append(static_cast<char>(value));
- }
- break;
- }
- case TYPE_I8: {
- qint8 value = static_cast<qint8>(strData.toShort(&ok));
- if (ok) {
- data.append(static_cast<char>(value));
- }
- break;
- }
- case TYPE_UI16: {
- quint16 value = static_cast<quint16>(strData.toUShort(&ok));
- if (ok) {
- quint16 leValue = qToLittleEndian(value);
- data.append(reinterpret_cast<const char*>(&leValue), 2);
- }
- break;
- }
- case TYPE_I16: {
- qint16 value = static_cast<qint16>(strData.toShort(&ok));
- if (ok) {
- qint16 leValue = qToLittleEndian(value);
- data.append(reinterpret_cast<const char*>(&leValue), 2);
- }
- break;
- }
- case TYPE_UI32: {
- quint32 value = strData.toUInt(&ok);
- if (ok) {
- quint32 leValue = qToLittleEndian(value);
- data.append(reinterpret_cast<const char*>(&leValue), 4);
- }
- break;
- }
- case TYPE_I32: {
- qint32 value = strData.toInt(&ok);
- if (ok) {
- qint32 leValue = qToLittleEndian(value);
- data.append(reinterpret_cast<const char*>(&leValue), 4);
- }
- break;
- }
- case TYPE_F32: {
- float value = strData.toFloat(&ok);
- if (ok) {
- // 将浮点数转换为小端序字节数组
- union {
- float f;
- quint8 b[4];
- } converter;
- converter.f = value;
- // 小端序:先存低位字节
- data.append(static_cast<char>(converter.b[0]));
- data.append(static_cast<char>(converter.b[1]));
- data.append(static_cast<char>(converter.b[2]));
- data.append(static_cast<char>(converter.b[3]));
- }
- break;
- }
- case TYPE_S64: {
- char value[8] ="";
- if (strData.size()!=8) {
- memcpy(value,strData.toLocal8Bit(),sizeof(value));
- data.append(reinterpret_cast<const char*>(&value), 8);
- }
- }
- default:
- ok = false;
- break;
- }
- return ok;
- }
- bool IEC104MasterQt::sendSingleCommand(int commonAddress, int objectAddress, bool command, bool selectExecute)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send single command");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x2D)); // 类型: 45-单命令, 46-双命令
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x06)); // 传送原因: 6-激活, 8-停止激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 命令值
- unsigned char commandValue = command ? 0x01 : 0x00;
- if (selectExecute)
- {
- // QOC (命令质量)
- data.append(static_cast<char>(commandValue+0x80)); // 通常命令
- }
- else
- {
- data.append(static_cast<char>(commandValue));
- }
- // if (selectExecute)
- // {
- // // QOC (命令质量)
- // data.append(static_cast<char>(0x80)); // 通常命令
- // }
- // else
- {
- data.append(static_cast<char>(0x00));
- }
- emit logMessage(QString("Sending single command: Address=%1, Command=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(command ? "ON" : "OFF")
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::SinglePoint;
- cmd.value = command;
- cmd.commonAddress = commonAddress;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- // 新增:发送双点命令
- bool IEC104MasterQt::sendDoubleCommand(int commonAddress, int objectAddress, int command, bool selectExecute)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send double command");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(selectExecute ? 0x2E : 0x2F)); // 类型: 46-双命令, 47-双命令停止激活
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(selectExecute ? 0x06 : 0x08)); // 传送原因: 6-激活, 8-停止激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 双点命令值 (1-分, 2-合)
- unsigned char commandValue = static_cast<unsigned char>(command & 0x03);
- data.append(static_cast<char>(commandValue));
- // QOC (命令质量)
- data.append(static_cast<char>(0x00)); // 通常命令
- emit logMessage(QString("Sending double command: Address=%1, Command=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(command)
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::DoublePoint;
- cmd.value = (command == 2); // 转换为bool: 1=false, 2=true
- cmd.commonAddress = commonAddress;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- // 新增:发送双点命令
- bool IEC104MasterQt::sendDoubleCommand2(int commonAddress, int objectAddress, int command, bool selectExecute,bool isRun)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send double command");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x3B)); //
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- if (selectExecute)
- {
- data.append(static_cast<char>(isRun ? 0x06 : 0x08)); // 传送原因: 6-激活,7-确认 8-停止激活
- }
- else
- {
- data.append(static_cast<char>(isRun ? 0x06 : 0x08)); // 传送原因: 6-激活,7-确认 8-停止激活
- }
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 双点命令值 (1-分, 2-合)
- if (selectExecute)
- {
- unsigned char commandValue = static_cast<unsigned char>(command & 0x03);
- data.append(static_cast<char>(commandValue)+0x80);
- }else
- {
- unsigned char commandValue = static_cast<unsigned char>(command & 0x03);
- data.append(static_cast<char>(commandValue));
- }
- // QOC (命令质量)
- // data.append(static_cast<char>(0x00)); // 通常命令
- // 时标
- QDateTime timestamp = QDateTime::currentDateTime();
- QByteArray date = dateTimeToCp56Time2a(timestamp);
- data.append(date);
- emit logMessage(QString("Sending double command: Address=%1, Command=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(command)
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::DoublePoint;
- cmd.value = (command == 2); // 转换为bool: 1=false, 2=true
- cmd.commonAddress = commonAddress;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendDoubleCommand3(int commonAddress, int nEqpmtID, int objectAddress, int command, bool selectExecute /*= true*/, bool isRun /*= true*/)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send double command");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x3B)); // 类型: 46-双命令, 47-双命令停止激活
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(isRun ? 0x06 : 0x08)); // 传送原因: 6-激活, 8-停止激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>(( nEqpmtID ) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 双点命令值 (1-分, 2-合)
- if (selectExecute)
- {
- unsigned char commandValue = static_cast<unsigned char>(command & 0x03);
- //data.append(static_cast<char>(commandValue) + 0x80);
- data.append(static_cast<char>(commandValue));
- }
- else
- {
- unsigned char commandValue = static_cast<unsigned char>(command & 0x03);
- data.append(static_cast<char>(commandValue));
- }
- // QOC (命令质量)
- // data.append(static_cast<char>(0x00)); // 通常命令
- // 时标
- QDateTime timestamp = QDateTime::currentDateTime();
- QByteArray date = dateTimeToCp56Time2a(timestamp);
- data.append(date);
- emit logMessage(QString("Sending double command: Address=%1, Command=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(command)
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::DoublePoint;
- cmd.value = (command == 2); // 转换为bool: 1=false, 2=true
- cmd.commonAddress = commonAddress;
- cmd.EqpmtAddress = nEqpmtID;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- bool IEC104MasterQt::getFixAreaValue(int commonAddress,int objectAddress,int nEqpmtID)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x91)); // 类型: 145
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x05)); // 传送原因: 3突发
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //装置地址
- data.append(static_cast<char>(nEqpmtID & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((nEqpmtID >> 8) & 0xFF)); // 公共地址高字节
- data.append(static_cast<char>(0xF1)); // 信息序号(INF)
- data.append(static_cast<char>(0x00));//返回信息标识
- data.append(static_cast<char>(0x01));//通用分类数据集数目
- data.append(static_cast<char>(0x00));//通用标识序号
- data.append(static_cast<char>(0x01));//通用标识序号
- data.append(static_cast<char>(0x00));//描述类别
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(commonAddress)
- .arg(objectAddress)
- .arg(nEqpmtID));
- return sendIMessage(data);
- }
- bool IEC104MasterQt::getFixValue(int commonAddress,int objectAddress,int nEqpmtID)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- m_FixData.clear(); //清除前一次记录
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x91)); // 类型: 145
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x05)); // 传送原因: 3突发
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //装置地址
- data.append(static_cast<char>(nEqpmtID & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((nEqpmtID >> 8) & 0xFF)); // 公共地址高字节
- //data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0xF1)); // 信息序号(INF)
- data.append(static_cast<char>(0x00));//返回信息标识
- data.append(static_cast<char>(0x01));//通用分类数据集数目 NGD
- data.append(static_cast<char>(0x01));//通用标识序号 GIN组
- data.append(static_cast<char>(0x00));//通用标识序号 GIN条目
- data.append(static_cast<char>(0x00));//通用标识序号 KOD
- data.append(static_cast<char>(0x03));//数据类型 3
- data.append(static_cast<char>(0x01));//数据大小 1
- data.append(static_cast<char>(0x01));//数据序号 1
- data.append(static_cast<char>(0x00));//描述类别 GID
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(commonAddress)
- .arg(objectAddress)
- .arg(nEqpmtID));
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendFixAreaValueCommand(FixAreaCommandType nType, int commonAddress,int objectAddress,int nEqpmtID,int nFixArea)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x91)); // 类型: 145
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x05)); // 传送原因: 3突发
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //装置地址
- data.append(static_cast<char>(nEqpmtID & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((nEqpmtID >> 8) & 0xFF)); // 公共地址高字节
- if(nType == FixAreaCommandType::FixAreaCommandType_Preset)
- data.append(static_cast<char>(0xF9)); // 信息序号(INF)
- else if(nType == FixAreaCommandType::FixAreaCommandType_Execut)
- data.append(static_cast<char>(0xFA)); // 信息序号(INF)
- else if(nType == FixAreaCommandType::FixAreaCommandType_Revoke)
- data.append(static_cast<char>(0xFB)); // 信息序号(INF)
- else
- data.append(static_cast<char>(0xF9)); // 信息序号(INF)
- data.append(static_cast<char>(0x00));//返回信息标识
- data.append(static_cast<char>(0x01));//通用分类数据集数目 NGD
- data.append(static_cast<char>(0x00));//通用标识序号 GIN组
- data.append(static_cast<char>(0x01));//通用标识序号 GIN条目
- data.append(static_cast<char>(0x00));//通用标识序号 KOD
- data.append(static_cast<char>(0x03));//数据类型 3
- data.append(static_cast<char>(0x01));//数据大小 1
- data.append(static_cast<char>(0x01));//数据序号 1
- data.append(static_cast<char>((nFixArea + 1) & 0xFF));//描述类别 GID 区号+1
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(commonAddress)
- .arg(objectAddress)
- .arg(nEqpmtID));
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendPresetFixValueCommand(int commonAddress,int objectAddress,int nEqpmtID, int nFixArea,int nIndex,int nType, QString &msg)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- QByteArray heasData;
- // ASDU头
- heasData.append(static_cast<char>(0x91)); // 类型: 145
- heasData.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- heasData.append(static_cast<char>(0x05)); // 传送原因: 3突发
- heasData.append(static_cast<char>(0x00));
- heasData.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- heasData.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- heasData.append(static_cast<char>(objectAddress & 0xFF));
- heasData.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- heasData.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //装置地址
- heasData.append(static_cast<char>(nEqpmtID & 0xFF)); // 公共地址低字节
- heasData.append(static_cast<char>((nEqpmtID >> 8) & 0xFF)); // 公共地址高字节
- heasData.append(static_cast<char>(0xF9)); // 信息序号(INF)
- heasData.append(static_cast<char>(0x00));//返回信息标识
- // 先改值
- QByteArray ginData;
- bool ret = Value2Data(ginData,nType,msg);
- int ginDatalenth = 4; //需要根据类型计算
- #if 1
- //data.append(static_cast<char>(0x9D));//通用分类数据集数目 NGD
- int nPos = 0;
- while (nPos < m_FixData.size())
- {
- // 取出数据类型定义
- const P_145_Area *ptrArea = reinterpret_cast<const P_145_Area *>(m_FixData.constData() + nPos);
- // 定值序号
- nPos+=sizeof (P_145_Area);
- if(ptrArea->GINnum == nIndex)
- {
- m_FixData.replace(nPos, ginDatalenth, ginData); // 替换前4个字节
- break;
- }
- // 添加偏移
- QString strData=Data2Value(nPos,m_FixData,ptrArea->FixValueType);
- }
- //截取发送
- nPos = 0;
- int startPos = 0;
- int length = 0;
- int cunot = 0;
- int index = 0;
- bool isLast;
- QByteArray fixData;
- while (nPos < m_FixData.size())
- {
- index++;
- // 取出数据类型定义
- const P_145_Area *ptrArea = reinterpret_cast<const P_145_Area *>(m_FixData.constData() + nPos);
- startPos = nPos;
- // 计算偏移
- nPos+=sizeof (P_145_Area);
- QString strData=Data2Value(nPos,m_FixData,ptrArea->FixValueType);
- length = nPos - startPos; //单个定值包长度
- // 拷贝
- if (startPos + length <= m_FixData.size()) {
- for (int i = 0; i < length; ++i) {
- fixData.append(m_FixData[startPos + i]);
- }
- isLast = true;
- }
- //满20个打包发送
- if ( index % 20 == 0)
- {
- QByteArray sendData;
- sendData.append(heasData);
- if(cunot == 0)
- {
- sendData.append(static_cast<char>(0x94));
- cunot = 1;
- }
- else
- {
- sendData.append(static_cast<char>(0xd4));
- cunot = 0;
- }
- sendData.append(fixData);
- sendIMessage(sendData);
- fixData.clear();
- isLast = false;
- }
- }
- if (isLast)
- {
- QByteArray sendData;
- sendData.append(heasData);
- sendData.append(static_cast<char>(0x01));
- sendData.append(fixData);
- sendIMessage(sendData);
- fixData.clear();
- isLast = false;
- }
- #else
- data.append(static_cast<char>(0x01));//通用分类数据集数目 NGD
- data.append(static_cast<char>((nFixArea + 1) & 0xFF));//通用标识序号 GIN组 区号+1
- data.append(static_cast<char>(nIndex));//通用标识序号 GIN条目
- data.append(static_cast<char>(0x00));//通用标识序号 KOD
- data.append(static_cast<char>(0x03));//数据类型 3
- data.append(static_cast<char>(0x01));//数据大小 1
- data.append(static_cast<char>(0x01));//数据序号 1
- data.append(ginData);//描述类别 GID 定值
- #endif
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(commonAddress)
- .arg(objectAddress)
- .arg(nEqpmtID));
- //return sendIMessage(data);
- return true;
- }
- bool IEC104MasterQt::sendSetFixValueCommand(FixAreaCommandType nType, int commonAddress,int objectAddress,int nEqpmtID,int nFixArea)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x91)); // 类型: 145
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x05)); // 传送原因: 3突发
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //装置地址
- data.append(static_cast<char>(nEqpmtID & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((nEqpmtID >> 8) & 0xFF)); // 公共地址高字节
- if(nType == FixAreaCommandType::FixAreaCommandType_Execut)
- data.append(static_cast<char>(0xFA)); // 信息序号(INF)
- else if(nType == FixAreaCommandType::FixAreaCommandType_Revoke)
- data.append(static_cast<char>(0xFB)); // 信息序号(INF)
- else
- data.append(static_cast<char>(0x00)); // 信息序号(INF)
- data.append(static_cast<char>(0x00));//返回信息标识
- data.append(static_cast<char>(0x01));//通用分类数据集数目 NGD
- data.append(static_cast<char>((nFixArea + 1) & 0xFF));//通用标识序号 GIN组 区号+1
- data.append(static_cast<char>(0x00));//通用标识序号 GIN条目
- data.append(static_cast<char>(0x00));//通用标识序号 KOD
- data.append(static_cast<char>(0x03));//数据类型 3
- data.append(static_cast<char>(0x01));//数据大小 1
- data.append(static_cast<char>(0x01));//数据序号 1
- data.append(static_cast<char>((nFixArea + 1) & 0xFF));//描述类别 GID 区号+1
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(commonAddress)
- .arg(objectAddress)
- .arg(nEqpmtID));
- return sendIMessage(data);
- }
- //时钟同步
- bool IEC104MasterQt::sendTimeSynchronizationCommand()
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- int commonAddress = 1;
- int objectAddress = 0;
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(0x67)); // 类型: 103
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(0x06)); // 传送原因: 6激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- //CP56Time2a
- // 时标
- QDateTime timestamp = QDateTime::currentDateTime();
- QByteArray date = dateTimeToCp56Time2a(timestamp);
- data.append(date);
- return sendIMessage(data);
- }
- // 新增:发送浮点设值命令
- bool IEC104MasterQt::sendFloatSetpoint(int commonAddress, int objectAddress, float value, bool selectExecute)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send float setpoint");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(selectExecute ? 0x32 : 0x33)); // 类型: 50-设点命令规范化值, 51-设点命令规范化值停止激活
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(selectExecute ? 0x06 : 0x08)); // 传送原因: 6-激活, 8-停止激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 规一化值
- short normalizedValue = floatToNormalized(value);
- data.append(static_cast<char>(normalizedValue & 0xFF));
- data.append(static_cast<char>((normalizedValue >> 8) & 0xFF));
- // QOS (设值命令质量)
- data.append(static_cast<char>(0x00)); // 通常命令
- emit logMessage(QString("Sending normalized setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(value)
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::FloatSetpoint;
- cmd.setpoint = value;
- cmd.commonAddress = commonAddress;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- // 新增:发送短浮点数设值命令
- bool IEC104MasterQt::sendSetpointCommandNormalized(int commonAddress, int objectAddress, float value, bool selectExecute)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot send setpoint command");
- return false;
- }
- QByteArray data;
- // ASDU头
- data.append(static_cast<char>(selectExecute ? 0x64 : 0x65)); // 类型: 100-设点命令短浮点数, 101-设点命令短浮点数停止激活
- data.append(static_cast<char>(0x01)); // 可变结构限定词: 1个信息对象
- data.append(static_cast<char>(selectExecute ? 0x06 : 0x08)); // 传送原因: 6-激活, 8-停止激活
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF)); // 公共地址低字节
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF)); // 公共地址高字节
- // 信息对象地址
- data.append(static_cast<char>(objectAddress & 0xFF));
- data.append(static_cast<char>((objectAddress >> 8) & 0xFF));
- data.append(static_cast<char>((objectAddress >> 16) & 0xFF));
- // 短浮点数值
- QByteArray floatBytes = floatToBytes(value);
- data.append(floatBytes);
- // QOS (设值命令质量)
- data.append(static_cast<char>(0x00)); // 通常命令
- emit logMessage(QString("Sending float setpoint: Address=%1, Value=%2, SelectExecute=%3")
- .arg(objectAddress)
- .arg(value)
- .arg(selectExecute));
- // 保存待确认的命令
- if (selectExecute)
- {
- QMutexLocker locker(&m_commandMutex);
- ControlCommand cmd;
- cmd.address = objectAddress;
- cmd.type = ControlCommandType::FloatSetpoint;
- cmd.setpoint = value;
- cmd.commonAddress = commonAddress;
- cmd.timestamp = QDateTime::currentDateTime();
- m_pendingCommands[objectAddress] = cmd;
- }
- return sendIMessage(data);
- }
- bool IEC104MasterQt::sendSingleCommand2(int commonAddress, int objectAddress, bool command, bool selectExecute /*= true*/, bool isRun /*= true*/)
- {
- }
- // 新增:处理遥控命令确认
- void IEC104MasterQt::processControlCommand(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < 4)
- return; // 至少需要地址3字节 + 命令值1字节 + QOC1字节
- const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data.constData());
- int objectAddress = (ptr[2] << 16) | (ptr[1] << 8) | ptr[0];
- unsigned char commandValue = ptr[3];
- QMutexLocker locker(&m_commandMutex);
- if (m_pendingCommands.contains(objectAddress))
- {
- ControlCommand cmd = m_pendingCommands[objectAddress];
- switch (cause)
- {
- case 7: // 激活确认
- emit logMessage(QString("Control command activation confirmed: Address=%1")
- .arg(objectAddress));
- emit controlCommandConfirmed(objectAddress, true, "Activation confirmed");
- if (cmd.type== ControlCommandType::SinglePoint)
- {
- sendSingleCommand(cmd.commonAddress, cmd.address, cmd.value ? 1 : 0, false);
- }
- else if (cmd.type == ControlCommandType::DoublePoint)
- {
- sendDoubleCommand2(cmd.commonAddress, cmd.address, cmd.value ? 2 : 1, false);
- }
- m_pendingCommands.remove(objectAddress);
- break;
- case 9: // 激活终止
- m_pendingCommands.remove(objectAddress);
- emit logMessage(QString("Control command activation terminated: Address=%1")
- .arg(objectAddress));
- emit controlCommandConfirmed(objectAddress, true, "Activation terminated");
- break;
- case 47: // 命令出错
- m_pendingCommands.remove(objectAddress);
- emit logMessage(QString("Control command error: Address=%1")
- .arg(objectAddress));
- emit controlCommandConfirmed(objectAddress, false, "Command error");
- break;
- default:
- emit logMessage(QString("Unknown control command cause: %1").arg(cause));
- break;
- }
- }
- }
- // 新增:处理设值命令确认
- void IEC104MasterQt::processSetpointCommand(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < 6)
- return; // 至少需要地址3字节 + 值2字节 + QOS1字节
- const unsigned char *ptr = reinterpret_cast<const unsigned char *>(data.constData());
- int objectAddress = (ptr[2] << 16) | (ptr[1] << 8) | ptr[0];
- QMutexLocker locker(&m_commandMutex);
- if (m_pendingCommands.contains(objectAddress))
- {
- ControlCommand cmd = m_pendingCommands[objectAddress];
- switch (cause)
- {
- case 7: // 激活确认
- emit logMessage(QString("Setpoint command activation confirmed: Address=%1")
- .arg(objectAddress));
- emit setpointCommandConfirmed(objectAddress, true, "Activation confirmed");
- break;
- case 9: // 激活终止
- m_pendingCommands.remove(objectAddress);
- emit logMessage(QString("Setpoint command activation terminated: Address=%1")
- .arg(objectAddress));
- emit setpointCommandConfirmed(objectAddress, true, "Activation terminated");
- break;
- case 47: // 命令出错
- m_pendingCommands.remove(objectAddress);
- emit logMessage(QString("Setpoint command error: Address=%1")
- .arg(objectAddress));
- emit setpointCommandConfirmed(objectAddress, false, "Command error");
- break;
- default:
- emit logMessage(QString("Unknown setpoint command cause: %1").arg(cause));
- break;
- }
- }
- }
- // 新增:发送命令激活终止
- void IEC104MasterQt::sendCommandActivationTermination(int type, int commonAddress, int objectAddress)
- {
- // 根据命令类型发送停止激活命令
- switch (type)
- {
- case 45: // 单命令
- sendSingleCommand(commonAddress, objectAddress, false, false);
- break;
- case 46: // 双命令
- sendDoubleCommand(commonAddress, objectAddress, 0, false);
- break;
- case 50: // 设点命令规范化值
- sendFloatSetpoint(commonAddress, objectAddress, 0.0f, false);
- break;
- case 100: // 设点命令短浮点数
- sendSetpointCommandNormalized(commonAddress, objectAddress, 0.0f, false);
- break;
- default:
- emit logMessage(QString("Unknown command type for termination: %1").arg(type));
- break;
- }
- }
- void IEC104MasterQt::FixValueCommand(const ASDU_header *header, const QByteArray &data, int cause)
- {
- //信息序号
- if (data.size() < 6)
- return; // 至少需要地址3字节 + 值2字节 + QOS1字节
- int nPos=sizeof(P_EP_145);
- const P_EP_145 *ptr = reinterpret_cast<const P_EP_145 *>(data.constData());
- int nEqpmtID=(ptr->eqpmtadder2 << 8) | ptr->eqpmtadder1;
- switch(ptr->msgID)
- {
- case FixValueType::GetFixAll:
- {
- bool isFixArea = false;
- while (nPos < data.size())
- {
- // 取出数据类型定义
- const P_145_Area *ptrArea = reinterpret_cast<const P_145_Area *>(data.constData() + nPos);
- // 取出数据
- nPos+=sizeof (P_145_Area);
- QString strData=Data2Value(nPos,data,ptrArea->FixValueType);
- updateFixValue(nEqpmtID, ptrArea->GIN, ptrArea->GINnum, ptrArea->FixValueType, strData);
- if(strData.isEmpty())
- isFixArea = true;
- }
- //将定值数据记录下来
- if(!isFixArea)
- {
- int startPos = sizeof(P_EP_145);
- int length = data.size() - startPos;
- if (startPos + length <= data.size()) {
- for (int i = 0; i < length; ++i) {
- m_FixData.append(data[startPos + i]);
- }
- }
- }
- }
- break;
- case FixValueType::SetFixValue:
- {
- }
- break;
- case FixValueType::RunFixValue:
- {
- }
- break;
- case FixValueType::CancelFixValue:
- {
- }
- break;
- }
- }
- void IEC104MasterQt::updateFixValue(int nEqpmtID,int nAreaID, int nAddress, int nType, QString strData)
- {
- QMutexLocker locker(&m_statusMutex);
- FixDataValue mv;
- mv.nEqpmtId = nEqpmtID;
- mv.nAddr = nAddress;
- mv.nType = nType;
- mv.strData = strData;;
- mv.timestamp = QDateTime::currentDateTime();
- auto iters=m_fixValues.find(nEqpmtID);
- if (iters==m_fixValues.end())
- {
- QMap<int,QMap<int,FixDataValue>> mlistData;
- iters=m_fixValues.insert(nEqpmtID,mlistData);
- }
- auto iter=iters->find(nAreaID);
- if(iter==iters->end())
- {
- QMap<int,FixDataValue> mlistData;
- iter=iters->insert(nAreaID,mlistData);
- }
- iter->insert(nAddress,mv);
- }
- // 新增:浮点数转换为字节序列
- QByteArray IEC104MasterQt::floatToBytes(float value)
- {
- QByteArray bytes(4, 0);
- uint32_t temp = *reinterpret_cast<uint32_t *>(&value);
- // IEC 104使用小端字节序
- bytes[0] = static_cast<char>(temp & 0xFF);
- bytes[1] = static_cast<char>((temp >> 8) & 0xFF);
- bytes[2] = static_cast<char>((temp >> 16) & 0xFF);
- bytes[3] = static_cast<char>((temp >> 24) & 0xFF);
- return bytes;
- }
- // 新增:浮点数转换为规一化值
- short IEC104MasterQt::floatToNormalized(float value, float scale)
- {
- // 将浮点数转换为规一化值 (-1.0 到 1.0 映射到 -32768 到 32767)
- float normalized = value / scale;
- if (normalized > 1.0f)
- normalized = 1.0f;
- if (normalized < -1.0f)
- normalized = -1.0f;
- return static_cast<short>(normalized * 32767.0f);
- }
- // 添加文件传输处理函数实现
- void IEC104MasterQt::processFileReady(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < sizeof(FileReady)) return;
- const FileReady *fr = reinterpret_cast<const FileReady*>(data.constData());
- //QString fileName = bytesToFileName(&fr->name1);
- int num = fr->name1;
- QString fileName = QString::number(num);
- int fileSize = bytesToFileSize(&fr->length1);
- bool ready = (fr->ready_status == 0);
- emit logMessage(QString("File ready: %1, Size: %2, Ready: %3")
- .arg(fileName).arg(fileSize).arg(ready));
- emit fileReadyReceived(fileName, fileSize, ready);
- // 更新文件传输状态
- QMutexLocker locker(&m_fileMutex);
- if (m_fileTransfers.contains(fileName)) {
- FileTransferInfo &info = m_fileTransfers[fileName];
- info.fileSize = fileSize;
- info.status = ready ? FTS_Success : FTS_NotReady;
- info.lastUpdate = QDateTime::currentDateTime();
- }
- }
- void IEC104MasterQt::processSectionReady(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < sizeof(SectionReady)) return;
- const SectionReady *sr = reinterpret_cast<const SectionReady*>(data.constData());
- //QString fileName = bytesToFileName(&sr->name1);
- int num = sr->name1;
- QString fileName = QString::number(num);
- int section = sr->section_name;
- int sectionSize = bytesToFileSize(&sr->length1);
- bool ready = (sr->ready_status == 0);
- emit logMessage(QString("Section ready: %1, Section: %2, Size: %3, Ready: %4")
- .arg(fileName).arg(section).arg(sectionSize).arg(ready));
- emit sectionReadyReceived(fileName, section, sectionSize, ready);
- }
- void IEC104MasterQt::processFileSegment(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < 6) return; // 至少需要文件名和节名
- const unsigned char *ptr = reinterpret_cast<const unsigned char*>(data.constData());
- //QString fileName = bytesToFileName(ptr+3); //有3个字节
- int num = ptr[3];
- QString fileName = QString::number(num);
- int section = ptr[5];
- int length = ptr[6];
- int datalen = data.size()-7;
- // 段数据从第6字节开始
- QByteArray segmentData = data.mid(7,length);
- emit logMessage(QString("File segment: %1, Section: %2, Data size: %3")
- .arg(fileName).arg(section).arg(segmentData.size()));
- // 保存段数据
- QMutexLocker locker(&m_fileMutex);
- if (m_fileTransfers.contains(fileName)) {
- FileTransferInfo &info = m_fileTransfers[fileName];
- //info.fileData.append(segmentData);
- //如果该节已经存在,追加数据
- if(info.fileDataMap.contains(section))
- {
- info.fileDataMap[section].append(segmentData);
- }
- else
- {
- info.fileDataMap.insert(section, segmentData);
- }
- info.currentSection = section;
- info.lastUpdate = QDateTime::currentDateTime();
- emit fileSegmentReceived(fileName, section, segmentData);
- }
- }
- //召唤目录
- void IEC104MasterQt::processDirectory(const ASDU_header *header, const QByteArray &data, int cause)
- {
- int pos = 3;
- QList<QString> fileList;
- while (pos + 16 <= data.size()) { // 每个目录项9字节
- const unsigned char *ptr = reinterpret_cast<const unsigned char*>(data.constData() + pos);
- int fileNameID = (ptr[1]<< 8) | ptr[0];
- int fileSize = bytesToFileSize(ptr + 2);
- QDateTime timestamp = cp56TimeToDateTime(ptr+6);
- fileList.append(QString("%1 (%2 bytes) Time=%3").arg(QString::number(fileNameID)).arg(fileSize).arg(timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz")));
- pos += 16;
- emit logMessage(QString("Directory entry: %1, Size: %2 Time=%3").arg(QString::number(fileNameID)).arg(fileSize).arg(timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz")));
- }
- emit directoryReceived(fileList);
- }
- // 添加其他文件传输处理函数(简化实现)
- void IEC104MasterQt::processFileCall(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < sizeof(FileCall)) return;
- const FileCall *fc = reinterpret_cast<const FileCall*>(data.constData());
- QString fileName = bytesToFileName(&fc->name1);
- int section = fc->section_name;
- int qualifier = fc->qualifier;
- QString qualifierStr;
- switch (qualifier) {
- case FTRQ_SelectFile: qualifierStr = "Select File"; break;
- case FTRQ_RequestFile: qualifierStr = "Request File"; break;
- case FTRQ_SelectSection: qualifierStr = "Select Section"; break;
- case FTRQ_RequestSection: qualifierStr = "Request Section"; break;
- case FTRQ_Directory: qualifierStr = "Directory"; break;
- default: qualifierStr = "Unknown"; break;
- }
- emit logMessage(QString("File call: %1, Section: %2, Qualifier: %3")
- .arg(fileName).arg(section).arg(qualifierStr));
- }
- //节最后段数据接收后校验数据
- void IEC104MasterQt::processLastSection(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < sizeof(LastSection)) return;
- const LastSection *ls = reinterpret_cast<const LastSection*>(data.constData());
- //QString fileName = bytesToFileName(&ls->name1);
- int num = ls->name1;
- QString fileName = QString::number(num);
- int section = ls->section_name;
- int lsq = ls->last_section;
- int checksum = ls->checksum;
- emit logMessage(QString("fileName: %1, Current Section: %2, lsq: %3, Checksum: 0x%4")
- .arg(fileName).arg(section).arg(lsq).arg(checksum, 4, 16, QLatin1Char('0')));
- // 文件传输完成
- QMutexLocker locker(&m_fileMutex);
- if (m_fileTransfers.contains(fileName)) {
- FileTransferInfo &info = m_fileTransfers[fileName];
- info.status = FTS_Success;
- info.lastUpdate = QDateTime::currentDateTime();
- // 计算校验和验证
- quint16 calculatedChecksum = 0;
- int nsectionData = 0;
- if(lsq == SCQ_StopSelect) //所选节传输完毕
- {
- if (info.fileDataMap.contains(section)) {
- const QByteArray sectionData = info.fileDataMap[section];
- for (int i = 0; i < sectionData.size(); i++) {
- calculatedChecksum += static_cast<quint8>(sectionData[i]);
- }
- nsectionData = sectionData.size();
- emit logMessage(QString("calculatedCheck fileData SIZE: %1, fileData: %2").arg(sectionData.size()).arg(toHexString(sectionData).constData()));
- }
- }
- else if(lsq == SCQ_SelectFile) //所选文件传输完毕
- {
- for (auto it = info.fileDataMap.constBegin(); it != info.fileDataMap.constEnd(); ++it) {
- const QByteArray& sectionData = it.value();
- for (int i = 0; i < sectionData.size(); i++) {
- calculatedChecksum += static_cast<quint8>(sectionData[i]);
- }
- nsectionData += sectionData.size();
- }
- }
- calculatedChecksum &= 0x00FF;
- bool checksumValid = (calculatedChecksum == checksum);
- if (checksumValid) {
- emit fileTransferCompleted(fileName, section, lsq, true, "File transfer completed successfully");
- emit logMessage(QString("File transfer completed: %1, Size: %2 bytes, Checksum valid")
- .arg(fileName).arg(nsectionData));
- } else {
- emit fileTransferCompleted(fileName, section, lsq, false,
- QString("Checksum error: expected 0x%1, got 0x%2")
- .arg(checksum, 4, 16, QLatin1Char('0'))
- .arg(calculatedChecksum, 4, 16, QLatin1Char('0')));
- emit logMessage(QString("File transfer checksum error: %1").arg(fileName));
- }
- }
- }
- void IEC104MasterQt::processFileAck(const ASDU_header *header, const QByteArray &data, int cause)
- {
- if (data.size() < sizeof(FileAck)) return;
- const FileAck *fa = reinterpret_cast<const FileAck*>(data.constData());
- QString fileName = bytesToFileName(&fa->name1);
- int section = fa->section_name;
- int ackStatus = fa->ack_status;//限定词?
- QString statusStr = (ackStatus == 0) ? "Accepted" : "Rejected";
- emit logMessage(QString("File acknowledgement: %1, Section: %2, Status: %3")
- .arg(fileName).arg(section).arg(statusStr));
- // 如果被拒绝,更新文件传输状态
- if (ackStatus != 0) {
- QMutexLocker locker(&m_fileMutex);
- if (m_fileTransfers.contains(fileName)) {
- FileTransferInfo &info = m_fileTransfers[fileName];
- info.status = FTS_AccessDenied;
- info.lastUpdate = QDateTime::currentDateTime();
- emit fileTransferCompleted(fileName, section, ackStatus, false, "File transfer rejected by remote");
- }
- }
- }
- // 文件传输公共接口实现
- bool IEC104MasterQt::requestDirectory(int commonAddress,int msgAddress)
- {
- QByteArray data;
- data.append(static_cast<char>(F_SC_NA_1)); // 类型
- data.append(static_cast<char>(0x01)); // 可变结构限定词
- data.append(static_cast<char>(0x05)); // 传送原因
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- // 文件名全0表示目录请求
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(0x00)); // 节名
- data.append(static_cast<char>(0x02)); // 限定词
- //请求目录
- emit logMessage("Requesting directory...");
- return sendIMessage(data);
- }
- //选择文件
- bool IEC104MasterQt::selectFile(int commonAddress,int msgAddress, const QString &fileName)
- {
- QByteArray data;
- data.append(static_cast<char>(F_SC_NA_1));
- data.append(static_cast<char>(0x01));
- data.append(static_cast<char>(0x0D));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- //data.append(nameBytes);
- data.append(static_cast<char>(fileName.toInt() & 0xFF));
- data.append(static_cast<char>((fileName.toInt() >> 8) & 0xFF));
- data.append(static_cast<char>(0x00)); // 节名
- data.append(static_cast<char>(SCQ_SelectFile));
- emit logMessage(QString("Selecting file: %1").arg(fileName));
- // 初始化文件传输状态
- QMutexLocker locker(&m_fileMutex);
- FileTransferInfo info;
- info.fileName = fileName;
- info.startTime = QDateTime::currentDateTime();
- info.status = FTS_Success;
- m_fileTransfers[fileName] = info;
- return sendIMessage(data);
- }
- //请求文件
- bool IEC104MasterQt::requestFile(int commonAddress,int msgAddress, const QString &fileName)
- {
- QByteArray data;
- data.append(static_cast<char>(F_SC_NA_1));
- data.append(static_cast<char>(0x01));
- data.append(static_cast<char>(0x0D));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- //data.append(nameBytes);
- data.append(static_cast<char>(fileName.toInt() & 0xFF));
- data.append(static_cast<char>((fileName.toInt() >> 8) & 0xFF));
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(FTRQ_RequestFile));
- emit logMessage(QString("Requesting file: %1").arg(fileName));
- return sendIMessage(data);
- }
- //请求段数据
- bool IEC104MasterQt::requestSection(int commonAddress,int msgAddress, const QString &fileName, int section)
- {
- if (!m_connected) {
- emit logMessage("Not connected, cannot request section");
- return false;
- }
- QByteArray data;
- data.append(static_cast<char>(F_SC_NA_1)); // 类型
- data.append(static_cast<char>(0x01)); // 可变结构限定词
- data.append(static_cast<char>(0x0D)); // 传送原因
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- //data.append(nameBytes);
- data.append(static_cast<char>(fileName.toInt() & 0xFF));
- data.append(static_cast<char>((fileName.toInt() >> 8) & 0xFF));
- data.append(static_cast<char>(section)); // 节名
- data.append(static_cast<char>(SCQ_RequesSection)); // 限定词
- emit logMessage(QString("Requesting section: %1, Section: %2").arg(fileName).arg(section));
- return sendIMessage(data);
- }
- //认可段数据
- bool IEC104MasterQt::acceptSection(int commonAddress,int msgAddress, const QString &fileName, int section, int lsq)
- {
- if (!m_connected) {
- emit logMessage("Not connected, cannot request section");
- return false;
- }
- QByteArray data;
- data.append(static_cast<char>(F_AF_NA_1)); // 类型
- data.append(static_cast<char>(0x01)); // 可变结构限定词
- data.append(static_cast<char>(0x0D)); // 传送原因
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- //data.append(nameBytes);
- data.append(static_cast<char>(fileName.toInt() & 0xFF));
- data.append(static_cast<char>((fileName.toInt() >> 8) & 0xFF));
- data.append(static_cast<char>(section)); // 节名
- data.append(static_cast<char>(lsq)); // 限定词 确认段
- emit logMessage(QString("Requesting section: %1, Section: %2").arg(fileName).arg(section));
- return sendIMessage(data);
- }
- // 工具函数实现
- QString IEC104MasterQt::bytesToFileName(const unsigned char *bytes)
- {
- char name[5] = {0};
- for (int i = 0; i < 2; i++) {
- name[i] = bytes[i];
- }
- return QString::fromLocal8Bit(name).trimmed();
- }
- QByteArray IEC104MasterQt::fileNameToBytes(const QString &fileName)
- {
- QByteArray bytes(2, 0);
- QByteArray nameBytes = fileName.toLocal8Bit();
- for (int i = 0; i < qMin(2, nameBytes.size()); i++) {
- bytes[i] = nameBytes[i];
- }
- return bytes;
- }
- int IEC104MasterQt::bytesToFileSize(const unsigned char *bytes)
- {
- return (bytes[0]) | (bytes[1] << 8);
- }
- QByteArray IEC104MasterQt::fileSizeToBytes(int fileSize)
- {
- QByteArray bytes(2, 0);
- bytes[0] = static_cast<char>(fileSize & 0xFF);
- bytes[1] = static_cast<char>((fileSize >> 8) & 0xFF);
- return bytes;
- }
- QMap<QString, FileTransferInfo> IEC104MasterQt::getFileTransfers() const
- {
- QMutexLocker locker(&m_fileMutex);
- return m_fileTransfers;
- }
- bool IEC104MasterQt::acknowledgeFile(int commonAddress,int msgAddress, const QString &fileName, bool accept)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot acknowledge file");
- return false;
- }
- QByteArray data;
- data.append(static_cast<char>(F_AF_NA_1)); // 类型
- data.append(static_cast<char>(0x01)); // 可变结构限定词
- data.append(static_cast<char>(0x07)); // 传送原因
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- data.append(nameBytes);
- data.append(static_cast<char>(0x00)); // 节名
- data.append(static_cast<char>(accept ? 0 : 1)); // 认可状态: 0=接受, 1=拒绝
- emit logMessage(QString("Acknowledge file: %1, Accept: %2").arg(fileName).arg(accept));
- return sendIMessage(data);
- }
- bool IEC104MasterQt::acknowledgeSection(int commonAddress,int msgAddress, const QString &fileName, int section, bool accept)
- {
- if (!m_connected)
- {
- emit logMessage("Not connected, cannot acknowledge section");
- return false;
- }
- QByteArray data;
- data.append(static_cast<char>(F_AF_NA_1)); // 类型
- data.append(static_cast<char>(0x01)); // 可变结构限定词
- data.append(static_cast<char>(0x07)); // 传送原因
- data.append(static_cast<char>(0x00));
- data.append(static_cast<char>(commonAddress & 0xFF));
- data.append(static_cast<char>((commonAddress >> 8) & 0xFF));
- // 信息对象地址
- data.append(static_cast<char>(msgAddress & 0xFF));
- data.append(static_cast<char>((msgAddress >> 8) & 0xFF));
- data.append(static_cast<char>((msgAddress >> 16) & 0xFF));
- QByteArray nameBytes = fileNameToBytes(fileName);
- data.append(nameBytes);
- data.append(static_cast<char>(section)); // 节名
- data.append(static_cast<char>(accept ? 0 : 1)); // 认可状态: 0=接受, 1=拒绝
- emit logMessage(QString("Acknowledge section: %1, Section: %2, Accept: %3")
- .arg(fileName).arg(section).arg(accept));
- return sendIMessage(data);
- }
|