#include "sub_iec101_unbalanced.h" /***************************************************************************************/ BOOLEAN CIEC101SecondaryUnbalancedProcess::OnPreCreate(int id) { if (!CIEC101Process::OnPreCreate(id)) return FALSE; int i; int uid; CIEC101SecondaryUnbalancedProcessItem* pItem; for (i = 0; i < PROCESS_UNIT_NUM; i++) { pItem = (CIEC101SecondaryUnbalancedProcessItem *)GetItem(i); if (NULL == pItem) continue; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) continue; BYTE phy_addr[2]; GetUnitAddr(uid, phy_addr, 2); pItem->Attach(uid, phy_addr[0], phy_addr[0], m_option.originatorAddress); //默认公共地址和物理地址一致 pItem->setAppLayerParameters(m_option.sizeOfCOT, m_option.sizeOfCA, m_option.sizeOfIOA, m_option.maxSizeOfASDU); Slave_setLinkLayerAddressOtherStation(pItem, phy_addr[1]); pItem->setAppLayerIOABase(); pItem->setAppLayerDataCount(GetUnitYXCount(uid), GetUnitYCCount(uid), GetUnitYMCount(uid)); } last_sec = (time_t)system32.timers; return TRUE; } BOOLEAN CIEC101SecondaryUnbalancedProcess::Run(void) { if (!CIEC101Process::Run()) return FALSE; FeedDog(); if (m_state != LL_STATE_IDLE) { if ((getTimeInMs() - m_lastReceivedMsg) > (unsigned int) m_idleTimeout) { llsu_setState(LL_STATE_IDLE); } } return TRUE; } BOOLEAN CIEC101SecondaryUnbalancedProcess::OnTimer(void) { if (!CIEC101Process::OnTimer()) return FALSE; BOOLEAN sec_changed = FALSE; if (last_sec != (time_t)system32.timers) { last_sec = (time_t)system32.timers; sec_changed = TRUE; } CIEC101ProcessItem* pItem = (CIEC101ProcessItem *)GetCurItem(); if (NULL == pItem) return TRUE; int uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return TRUE; //刷新事件记录库 GetItemEvents(pItem); //刷新遥测库 FetchUnitYC(0); if (pItem->interrogation_finish) { //总召唤结束,开始上送遥信变位 GetItemYXBWs(pItem); //总召唤结束,开始刷新遥测变位缓冲。 if (pItem->ycbws.count <= 0) { //当遥测变位发送结束后才更新 GetItemYCBWs(pItem); } //发送遥控返校 if (MakeYKFrame(pItem)) return TRUE; if (MakeYTFrame(pItem)) return TRUE; if (Send_Single_point_information(pItem)) return TRUE; if (Send_Single_point_information_with_time_tag_cp56time2a(pItem)) return TRUE; if (!pItem->interrogation_start) { //变位遥测优先级在总召唤之后。 if (sec_changed) { switch (m_option.yc_type) { case USE_YC_NB: //标度化值 return Send_Measured_value_scaled(pItem); case USE_YC_NC: //短浮点数 return Send_Measured_value_short_floating_point(pItem); case USE_YC_ND: //不带品质归一化值 return Send_Measured_value_normalised_without_quality(pItem); default: //USE_YC_NA: 归一化值 return Send_Measured_value_normalised(pItem); } } } } //响应总召唤命令 if (pItem->interrogation_start) { if (pItem->call_type != IEC_101_104_COT_INTERROGATION) { //组召唤 //激活终止 Send_FrameInterrogation(pItem); pItem->call_type = 0; pItem->interrogation_finish = TRUE; pItem->interrogation_start = FALSE; pItem->interrogation_yx_fin = TRUE; pItem->interrogation_yc_fin = TRUE; } else if (!pItem->interrogation_yx_fin) { Send_Single_point_information(pItem, IEC_101_104_COT_INTERROGATION); } else if (!pItem->interrogation_yc_fin) { switch (m_option.yc_type) { case USE_YC_NB: //标度化值 return Send_Measured_value_scaled(pItem, IEC_101_104_COT_INTERROGATION); case USE_YC_NC: //短浮点数 return Send_Measured_value_short_floating_point(pItem, IEC_101_104_COT_INTERROGATION); case USE_YC_ND: //不带品质归一化值 return Send_Measured_value_normalised_without_quality(pItem, IEC_101_104_COT_INTERROGATION); default: //USE_YC_NA: 归一化值 return Send_Measured_value_normalised(pItem, IEC_101_104_COT_INTERROGATION); } } else { Send_FrameInterrogation(pItem); pItem->call_type = 0; pItem->interrogation_finish = TRUE; pItem->interrogation_start = FALSE; pItem->interrogation_yx_fin = TRUE; pItem->interrogation_yc_fin = TRUE; } } else if (pItem->pulse_start) { if (!pItem->pulse_fin) { Send_Integrated_totals(pItem, IEC_101_104_COT_REQCOGEN); } else { Send_FrameCounterInterrogation(pItem); pItem->call_type = 0; pItem->pulse_start = FALSE; pItem->pulse_fin = TRUE; } } return TRUE; } int CIEC101SecondaryUnbalancedProcess::OnPackageReceived(BYTE* pBuf, int msgSize, int /* ord = -1 */) { m_lastReceivedMsg = getTimeInMs(); int userDataLength = 0; int userDataStart = 0; BYTE c; int csStart; int csIndex; int address = 0; int addressLength = m_linkLayer.linkLayerParameters.addressLength; BYTE* msg = (BYTE *)pBuf; if (msg [0] == 0x68) { if (msg [1] != msg [2]) { vLog(LOG_DEBUG, "ERROR: L fields differ!\n"); llsu_setState(LL_STATE_ERROR); return 1; } userDataLength = (int)msg [1] - addressLength - 1; userDataStart = 5 + addressLength; csStart = 4; csIndex = userDataStart + userDataLength; /* check if message size is reasonable */ if (msgSize != (userDataStart + userDataLength + 2 /* CS + END */)) { vLog(LOG_DEBUG, "ERROR: Invalid message length\n"); llsu_setState(LL_STATE_ERROR); return 1; } c = msg [4]; } else if (msg [0] == 0x10) { c = msg [1]; csStart = 1; csIndex = 2 + addressLength; } else { vLog(LOG_DEBUG, "ERROR: Received unexpected message type in unbalanced slave mode!\n"); llsu_setState(LL_STATE_ERROR); return 1; } BOOLEAN isBroadcast = false; CIEC101ProcessItem* pItem; /* check address */ if (addressLength > 0) { address = msg[csStart + 1]; if (addressLength > 1) { address += msg [csStart + 2] * 0x100; if (address == 65535) isBroadcast = TRUE; } else { if (address == 255) isBroadcast = TRUE; } } int fc = c & 0x0f; if (isBroadcast) { if (fc != LL_FC_04_USER_DATA_NO_REPLY) { vLog(LOG_DEBUG, "ERROR: Invalid function code for broadcast message!\n"); llsu_setState(LL_STATE_ERROR); return 1; } } else { int uid = GetUnitByAddr((BYTE *)&address, m_linkLayer.linkLayerParameters.addressLength); if (uid < 0 || uid >= UNIT_NUM) { vLog(LOG_DEBUG, "INFO: unknown link layer address(%i) -> ignore message\n", address); return 1; } pItem = (CIEC101ProcessItem *)GetItem(GetOrderByUnitID(uid)); if (pItem == NULL) { vLog(LOG_DEBUG, "INFO: unknown link layer address(%i) -> ignore message\n", address); return 1; } UnitFeedDog(uid); } /* check checksum */ BYTE checksum = 0; int i; for (i = csStart; i < csIndex; i++) checksum += msg [i]; if (checksum != msg [csIndex]) { vLog(LOG_DEBUG, "ERROR: checksum invalid!\n"); llsu_setState(LL_STATE_ERROR); return 1; } /* parse C field bits */ BOOLEAN prm = ((c & 0x40) == 0x40); if (prm == FALSE) { vLog(LOG_DEBUG, "ERROR: Received secondary message in unbalanced slave mode!\n"); llsu_setState(LL_STATE_ERROR); return 1; } BOOLEAN fcb = ((c & 0x20) == 0x20); BOOLEAN fcv = ((c & 0x10) == 0x10); LinkLayerSecondaryUnbalanced_ReceivedMessage(pItem, fc, isBroadcast, fcb, fcv, msg, userDataStart, userDataLength); return 1; } //不平衡方式从协议接收到主站报文 void CIEC101SecondaryUnbalancedProcess::LinkLayerSecondaryUnbalanced_ReceivedMessage(CIEC101ProcessItem* pItem, BYTE fc, BOOLEAN isBroadcast, BOOLEAN fcb, BOOLEAN fcv, BYTE* msg, int userDataStart, int userDataLength) { pIEC101_LinkLayerSecondaryUnbalanced self = &(pItem->secondaryLinkUnbalanced); if (fcv) { if (checkFCB(self, fcb) == FALSE) { vLog(LOG_DEBUG, "SLL - FCB check failed\n"); llsu_setState(LL_STATE_ERROR); return; } } llsu_setState(LL_STATE_AVAILABLE); switch (fc) { case LL_FC_09_REQUEST_LINK_STATUS: //vLog(LOG_DEBUG, "SLL - REQUEST LINK STATUS\n"); { BOOLEAN accessDemand = IsClass1DataAvailable(pItem); SendFixedFrame(LL_FC_11_STATUS_OF_LINK_OR_ACCESS_DEMAND, pItem->address, FALSE, FALSE, accessDemand, FALSE); } break; case LL_FC_00_RESET_REMOTE_LINK: //vLog(LOG_DEBUG, "SLL - RESET REMOTE LINK\n"); { self->expectedFcb = TRUE; if (m_linkLayer.linkLayerParameters.useSingleCharACK) { SendSingleCharCharacter(); } else { SendFixedFrame(LL_FC_00_ACK, pItem->address, FALSE, FALSE, FALSE, FALSE); } ResetCUReceived(pItem, FALSE); } break; case LL_FC_07_RESET_FCB: //vLog(LOG_DEBUG, "SLL - RESET FCB\n"); { self->expectedFcb = TRUE; if (m_linkLayer.linkLayerParameters.useSingleCharACK) { SendSingleCharCharacter(); } else { SendFixedFrame(LL_FC_00_ACK, pItem->address, FALSE, FALSE, FALSE, FALSE); } ResetCUReceived(pItem, TRUE); } break; case LL_FC_11_REQUEST_USER_DATA_CLASS_2: //vLog(LOG_DEBUG, "SLL - REQUEST USER DATA CLASS 2\n"); { /* provide a buffer where the application layer can encode the user data */ pIEC101_QueueElement element = GetClass2Data(pItem); BOOLEAN accessDemand = IsClass1DataAvailable(pItem); if (element) { SendVariableLengthFrame(LL_FC_08_RESP_USER_DATA, pItem->address, FALSE, FALSE, accessDemand, FALSE, element->buffer, element->size); } else { if (m_linkLayer.linkLayerParameters.useSingleCharACK && !accessDemand) { SendSingleCharCharacter(); } else { SendFixedFrame(LL_FC_09_RESP_NACK_NO_DATA, pItem->address, FALSE, FALSE, accessDemand, FALSE); } } } break; case LL_FC_10_REQUEST_USER_DATA_CLASS_1: //vLog(LOG_DEBUG, "SLL - REQUEST USER DATA CLASS 1\n"); { /* provide a buffer where the application layer can encode the user data */ pIEC101_QueueElement element = GetClass1Data(pItem); BOOLEAN accessDemand = IsClass1DataAvailable(pItem); if (element) { SendVariableLengthFrame(LL_FC_08_RESP_USER_DATA, pItem->address, FALSE, FALSE, accessDemand, FALSE, element->buffer, element->size); } else { if (m_linkLayer.linkLayerParameters.useSingleCharACK && !accessDemand) { SendSingleCharCharacter(); } else { SendFixedFrame(LL_FC_09_RESP_NACK_NO_DATA, pItem->address, FALSE, FALSE, accessDemand, FALSE); } } } break; case LL_FC_03_USER_DATA_CONFIRMED: //vLog(LOG_DEBUG, "SLL - USER DATA CONFIRMED\n"); if (userDataLength > 0) { if (ApplicationLayer_ReceivedData(pItem, msg, isBroadcast, userDataStart, userDataLength)) { BOOLEAN accessDemand = IsClass1DataAvailable(pItem); if (m_linkLayer.linkLayerParameters.useSingleCharACK && !accessDemand) { SendSingleCharCharacter(); } else { SendFixedFrame(LL_FC_00_ACK, pItem->address, FALSE, FALSE, accessDemand, FALSE); } } } break; case LL_FC_04_USER_DATA_NO_REPLY: //vLog(LOG_DEBUG, "SLL - USER DATA NO REPLY\n"); if (userDataLength > 0) { ApplicationLayer_ReceivedData(pItem, msg, isBroadcast, userDataStart, userDataLength); } break; default: //vLog(LOG_DEBUG, "SLL - UNEXPECTED LINK LAYER MESSAGE\n"); SendFixedFrame(LL_FC_15_SERVICE_NOT_IMPLEMENTED, pItem->address, FALSE, FALSE, FALSE, FALSE); break; } }