| | |
| | | |
| | | int CHsmsPassive::addCollectionEvent(unsigned int CEID, const char* name, const char* desc, const std::vector<unsigned int>& rptids) |
| | | { |
| | | if (getEvent((unsigned short)CEID) != nullptr) { |
| | | if (getEvent((unsigned int)CEID) != nullptr) { |
| | | return -1; |
| | | } |
| | | auto* pEvent = new SERVO::CCollectionEvent(CEID, name, desc, const_cast<std::vector<unsigned int>&>(rptids)); |
| | |
| | | m_collectionEvents.clear(); |
| | | } |
| | | |
| | | SERVO::CCollectionEvent* CHsmsPassive::getEvent(unsigned short CEID) |
| | | SERVO::CCollectionEvent* CHsmsPassive::getEvent(unsigned int CEID) |
| | | { |
| | | for (auto item : m_collectionEvents) { |
| | | if (item->getEventId() == CEID) { |
| | |
| | | replySelectedEquipmentStatusData(pMessage); |
| | | } |
| | | else if (nStream == 1 && pHeader->function == 11) { |
| | | replyStatusVariableNamelistRequest(pMessage); |
| | | // [EAP_MAPPING][S1F11] Status Variable namelist request -> S1F12. |
| | | // If customer requires swapping SV/DV mapping, this is one of the two switch points. |
| | | // Swap target with S1F21 branch below. |
| | | // replyStatusVariableNamelistRequest(pMessage); |
| | | replyDataVariableNamelistRequest(pMessage); |
| | | } |
| | | else if (nStream == 1 && pHeader->function == 21) { |
| | | replyDataVariableNamelistRequest(pMessage); |
| | | // [EAP_MAPPING][S1F21] Data Variable namelist request -> S1F22. |
| | | // If customer requires swapping SV/DV mapping, this is one of the two switch points. |
| | | // Swap target with S1F11 branch above. |
| | | // replyDataVariableNamelistRequest(pMessage); |
| | | replyStatusVariableNamelistRequest(pMessage); |
| | | } |
| | | else if (nStream == 1 && pHeader->function == 23) { |
| | | replyCollectionEventNamelistRequest(pMessage); |
| | |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 4, pRecv->getHeader()->systemBytes); |
| | | ASSERT(pMessage); |
| | | |
| | | unsigned char SVU1 = 0; |
| | | unsigned short SVID = 0; |
| | | std::vector<unsigned int> reqIds; |
| | | ISECS2Item* pBody = pRecv->getBody(); |
| | | if (pBody == nullptr || pBody->getType() != SITYPE::L) { |
| | | pMessage->getBody()->addU1Item(SVU1, "SV"); |
| | | goto MYREPLY; |
| | | } |
| | | if (!pBody->getSubItemU2(0, SVID)) { |
| | | // also accept I2 or U4 to be tolerant with host implementations |
| | | if (!pBody->getSubItemI2(0, (short&)SVID)) { |
| | | unsigned int svidU4 = 0; |
| | | if (!pBody->getSubItemU4(0, svidU4)) { |
| | | pMessage->getBody()->addU1Item(SVU1, "SV"); |
| | | goto MYREPLY; |
| | | } |
| | | SVID = static_cast<unsigned short>(svidU4); |
| | | |
| | | // S1F3 supports batch query: {L:n SVID}. S1F4 must return {L:n SV} in the same order. |
| | | const int reqSize = pBody->getSubItemSize(); |
| | | for (int i = 0; i < reqSize; ++i) { |
| | | unsigned int idU4 = 0; |
| | | unsigned short idU2 = 0; |
| | | short idI2 = 0; |
| | | if (pBody->getSubItemU4(i, idU4)) { |
| | | reqIds.push_back(idU4); |
| | | } |
| | | else if (pBody->getSubItemU2(i, idU2)) { |
| | | reqIds.push_back(static_cast<unsigned int>(idU2)); |
| | | } |
| | | else if (pBody->getSubItemI2(i, idI2) && idI2 >= 0) { |
| | | reqIds.push_back(static_cast<unsigned int>(idI2)); |
| | | } |
| | | } |
| | | |
| | | SERVO::CVariable* pVariable = getVariable((int)SVID); |
| | | if (pVariable == nullptr) { |
| | | pMessage->getBody()->addU1Item(SVU1, "SV"); |
| | | goto MYREPLY; |
| | | // L:0 means "all SVIDs". |
| | | if (reqIds.empty()) { |
| | | Lock(); |
| | | for (auto* v : m_variabels) { |
| | | if (v != nullptr) { |
| | | reqIds.push_back(static_cast<unsigned int>(v->getVarialbleId())); |
| | | } |
| | | } |
| | | Unlock(); |
| | | } |
| | | addVariableValueToItem(pMessage->getBody(), pVariable); |
| | | |
| | | for (auto id : reqIds) { |
| | | SERVO::CVariable* pVariable = getVariable((int)id); |
| | | if (pVariable != nullptr) { |
| | | addVariableValueToItem(pMessage->getBody(), pVariable); |
| | | } |
| | | else { |
| | | // Unknown SVID placeholder. |
| | | pMessage->getBody()->addU1Item(0, "SV"); |
| | | } |
| | | } |
| | | |
| | | MYREPLY: |
| | | m_pPassive->sendMessage(pMessage); |
| | |
| | | return 0; |
| | | } |
| | | |
| | | // S1F11 |
| | | // S1F21 |
| | | int CHsmsPassive::replyStatusVariableNamelistRequest(IMessage* pRecv) |
| | | { |
| | | // [EAP_MAPPING][SV_HANDLER] |
| | | // Current behavior: handles S1F11 and replies S1F12 with SVID/SVNAME/UNITS. |
| | | // If customer requires SV/DV swap, this function body can be swapped with |
| | | // replyDataVariableNamelistRequest (or dispatch branches can be swapped instead). |
| | | if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) { |
| | | return ER_NOTSELECT; |
| | | } |
| | | |
| | | std::vector<unsigned short> reqIds; |
| | | std::vector<unsigned int> reqIds; |
| | | ISECS2Item* pBody = pRecv->getBody(); |
| | | if (pBody != nullptr && pBody->getType() == SITYPE::L) { |
| | | const int sz = pBody->getSubItemSize(); |
| | | for (int i = 0; i < sz; ++i) { |
| | | unsigned short id = 0; |
| | | if (pBody->getSubItemU2(i, id)) { |
| | | unsigned int id = 0; |
| | | unsigned short idU2 = 0; |
| | | short idI2 = 0; |
| | | if (pBody->getSubItemU4(i, id)) { |
| | | reqIds.push_back(id); |
| | | } |
| | | else if (pBody->getSubItemU2(i, idU2)) { |
| | | reqIds.push_back(static_cast<unsigned int>(idU2)); |
| | | } |
| | | else if (pBody->getSubItemI2(i, idI2) && idI2 >= 0) { |
| | | reqIds.push_back(static_cast<unsigned int>(idI2)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Build response list items: {L:3 SVID, SVNAME, UNITS} |
| | | std::vector<unsigned short> svids; |
| | | std::set<unsigned short> requested(reqIds.begin(), reqIds.end()); |
| | | std::vector<unsigned int> svids; |
| | | std::set<unsigned int> requested(reqIds.begin(), reqIds.end()); |
| | | Lock(); |
| | | if (reqIds.empty()) { |
| | | for (auto v : m_variabels) { |
| | | svids.push_back(static_cast<unsigned short>(v->getVarialbleId())); |
| | | svids.push_back(static_cast<unsigned int>(v->getVarialbleId())); |
| | | } |
| | | } |
| | | else { |
| | |
| | | Unlock(); |
| | | |
| | | IMessage* pMessage = NULL; |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 12, pRecv->getHeader()->systemBytes); |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 22, pRecv->getHeader()->systemBytes); |
| | | ASSERT(pMessage); |
| | | |
| | | ISECS2Item* pList = pMessage->getBody(); // Body is L[n] of {SVID, SVNAME, UNITS} |
| | | for (auto id : svids) { |
| | | ISECS2Item* pEntry = pList->addItem(); |
| | | pEntry->addU2Item(id, "SVID"); |
| | | pEntry->addU4Item(id, "SVID"); |
| | | SERVO::CVariable* v = getVariable((int)id); |
| | | if (v != nullptr) { |
| | | pEntry->addItem(v->getName().c_str(), "SVNAME"); |
| | |
| | | file.Close(); |
| | | return 0; |
| | | } |
| | | // S1F21/S1F22 - Data Variable Namelist |
| | | // S1F11/S1F12 - Data Variable Namelist |
| | | int CHsmsPassive::replyDataVariableNamelistRequest(IMessage* pRecv) |
| | | { |
| | | // [EAP_MAPPING][DV_HANDLER] |
| | | // Current behavior: handles S1F21 and replies S1F22 with DVID/DVNAME/UNITS. |
| | | // If customer requires SV/DV swap, this function body can be swapped with |
| | | // replyStatusVariableNamelistRequest (or dispatch branches can be swapped instead). |
| | | if (m_pPassive == NULL || STATE::SELECTED != m_pPassive->getState()) { |
| | | return ER_NOTSELECT; |
| | | } |
| | | |
| | | std::vector<unsigned short> reqIds; |
| | | std::vector<unsigned int> reqIds; |
| | | ISECS2Item* pBody = pRecv->getBody(); |
| | | if (pBody != nullptr && pBody->getType() == SITYPE::L) { |
| | | const int sz = pBody->getSubItemSize(); |
| | | for (int i = 0; i < sz; ++i) { |
| | | unsigned short id = 0; |
| | | if (pBody->getSubItemU2(i, id)) { |
| | | unsigned int id = 0; |
| | | unsigned short idU2 = 0; |
| | | short idI2 = 0; |
| | | if (pBody->getSubItemU4(i, id)) { |
| | | reqIds.push_back(id); |
| | | } |
| | | else if (pBody->getSubItemU2(i, idU2)) { |
| | | reqIds.push_back(static_cast<unsigned int>(idU2)); |
| | | } |
| | | else if (pBody->getSubItemI2(i, idI2) && idI2 >= 0) { |
| | | reqIds.push_back(static_cast<unsigned int>(idI2)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | std::vector<unsigned short> dvids; |
| | | std::set<unsigned short> requested(reqIds.begin(), reqIds.end()); |
| | | std::vector<unsigned int> dvids; |
| | | std::set<unsigned int> requested(reqIds.begin(), reqIds.end()); |
| | | Lock(); |
| | | if (reqIds.empty()) { |
| | | for (auto v : m_dataVariabels) { |
| | | if (v) dvids.push_back(static_cast<unsigned short>(v->getVarialbleId())); |
| | | if (v) dvids.push_back(static_cast<unsigned int>(v->getVarialbleId())); |
| | | } |
| | | } |
| | | else { |
| | |
| | | Unlock(); |
| | | |
| | | IMessage* pMessage = NULL; |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 22, pRecv->getHeader()->systemBytes); |
| | | HSMS_Create1Message(pMessage, m_nSessionId, 1, 12, pRecv->getHeader()->systemBytes); |
| | | ASSERT(pMessage); |
| | | |
| | | ISECS2Item* pList = pMessage->getBody(); // L[n] of {DVID, DVNAME, UNITS} |
| | | for (auto id : dvids) { |
| | | ISECS2Item* pEntry = pList->addItem(); |
| | | pEntry->addU2Item(id, "DVID"); |
| | | pEntry->addU4Item(id, "DVID"); |
| | | SERVO::CDataVariable* v = getDataVariable((int)id); |
| | | if (v != nullptr) { |
| | | pEntry->addItem(v->getName().c_str(), "DVNAME"); |
| | |
| | | return ER_NOTSELECT; |
| | | } |
| | | |
| | | std::vector<unsigned short> reqIds; |
| | | std::vector<unsigned int> reqIds; |
| | | ISECS2Item* pBody = pRecv->getBody(); |
| | | if (pBody != nullptr && pBody->getType() == SITYPE::L) { |
| | | const int sz = pBody->getSubItemSize(); |
| | | for (int i = 0; i < sz; ++i) { |
| | | unsigned short id = 0; |
| | | if (pBody->getSubItemU2(i, id)) { |
| | | unsigned int id = 0; |
| | | unsigned short idU2 = 0; |
| | | if (pBody->getSubItemU4(i, id)) { |
| | | reqIds.push_back(id); |
| | | } |
| | | else if (pBody->getSubItemU2(i, idU2)) { |
| | | reqIds.push_back(static_cast<unsigned int>(idU2)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | struct CEInfo { |
| | | unsigned short id{ 0 }; |
| | | unsigned int id{ 0 }; |
| | | std::string name; |
| | | std::vector<unsigned short> vids; |
| | | std::vector<unsigned int> vids; |
| | | }; |
| | | std::vector<CEInfo> ceInfos; |
| | | { |
| | |
| | | for (auto e : m_collectionEvents) { |
| | | if (e == nullptr) continue; |
| | | CEInfo info; |
| | | info.id = static_cast<unsigned short>(e->getEventId()); |
| | | info.id = static_cast<unsigned int>(e->getEventId()); |
| | | info.name = e->getName(); |
| | | std::set<unsigned short> vidSet; |
| | | std::set<unsigned int> vidSet; |
| | | for (auto rpt : e->getReports()) { |
| | | if (rpt == nullptr) continue; |
| | | for (auto vid : rpt->getVids()) { |
| | | vidSet.insert(static_cast<unsigned short>(vid)); |
| | | vidSet.insert(static_cast<unsigned int>(vid)); |
| | | } |
| | | } |
| | | info.vids.assign(vidSet.begin(), vidSet.end()); |
| | |
| | | for (auto id : reqIds) { |
| | | CEInfo info; |
| | | info.id = id; |
| | | SERVO::CCollectionEvent* e = getEvent(id); |
| | | SERVO::CCollectionEvent* e = getEvent(static_cast<unsigned int>(id)); |
| | | if (e != nullptr) { |
| | | info.name = e->getName(); |
| | | std::set<unsigned short> vidSet; |
| | | std::set<unsigned int> vidSet; |
| | | for (auto rpt : e->getReports()) { |
| | | if (rpt == nullptr) continue; |
| | | for (auto vid : rpt->getVids()) { |
| | | vidSet.insert(static_cast<unsigned short>(vid)); |
| | | vidSet.insert(static_cast<unsigned int>(vid)); |
| | | } |
| | | } |
| | | info.vids.assign(vidSet.begin(), vidSet.end()); |
| | |
| | | ISECS2Item* pList = pMessage->getBody(); // Body is L[n] of {CEID, CENAME, L[VIDs]} |
| | | for (const auto& info : ceInfos) { |
| | | ISECS2Item* pEntry = pList->addItem(); |
| | | pEntry->addU2Item(info.id, "CEID"); |
| | | pEntry->addU4Item(info.id, "CEID"); |
| | | pEntry->addItem(info.name.c_str(), "CENAME"); // empty if unknown |
| | | ISECS2Item* pVidList = pEntry->addItem(); |
| | | for (auto vid : info.vids) { |
| | | pVidList->addU2Item(vid, "VID"); |
| | | pVidList->addU4Item(vid, "VID"); |
| | | } |
| | | } |
| | | |