#include "iec101.h" CIEC101ProcessItem::CIEC101ProcessItem() { end_of_initialisation = FALSE; background_scan_begin = 0; call_type = 0; interrogation_start = FALSE; //总召启动 interrogation_yx_fin = FALSE; //遥信发送完毕 interrogation_yc_fin = FALSE; //遥测发送完毕 pulse_start = FALSE; pulse_fin = FALSE; clock_synchronized_start = FALSE; clock_synchronized_finish = FALSE; interrogation_start = FALSE; interrogation_finish = FALSE; yx_start_address = IEC_101_104_YX_START_ADDR; yc_start_address = IEC_101_104_YC_START_ADDR; ym_start_address = IEC_101_104_YM_START_ADDR; //LinkLayerPrimaryBalanced_init primaryLinkBalanced.primaryState = PLL_IDLE; primaryLinkBalanced.state = LL_STATE_IDLE; primaryLinkBalanced.waitingForResponse = FALSE; primaryLinkBalanced.sendLinkLayerTestFunction = FALSE; primaryLinkBalanced.nextFcb = TRUE; primaryLinkBalanced.idleTimeout = 5000; primaryLinkBalanced.otherStationAddress = 0; //LinkLayerSecondaryBalanced_init secondaryLinkBalanced.expectedFcb = TRUE; //LinkLayerSecondaryUnbalanced_init secondaryLinkUnbalanced.expectedFcb = TRUE; applicationlParameters.sizeOfTypeId = 1; applicationlParameters.sizeOfVSQ = 1; applicationlParameters.sizeOfCOT = 1; applicationlParameters.originatorAddress = 0; applicationlParameters.sizeOfCA = 1; applicationlParameters.sizeOfIOA = 2; applicationlParameters.maxSizeOfASDU = 254; memset(&ycbws, 0, sizeof(ycbws)); memset(&yxbws, 0, sizeof(yxbws)); memset(&events, 0, sizeof(events)); } CIEC101ProcessItem::~CIEC101ProcessItem() { } void CIEC101ProcessItem::Attach(int uid, int physicsAddress /* = 0 */, int commonAddress /* = 0 */, int originatorAddress /* = 0 */) { CPortProcessItem::Attach(uid, physicsAddress, commonAddress, originatorAddress); } void CIEC101ProcessItem::Release(void) { CPortProcessItem::Release(); } CIEC101Process::CIEC101Process() { apdu_t4_max = 0; //t4的最大值(设定) apdu_t5_max = 0; //t5的最大值(设定) m_linkLayer.linkLayerParameters.addressLength = 1; m_linkLayer.linkLayerParameters.useSingleCharACK = TRUE; m_linkLayer.linkLayerParameters.timeoutForACK = 200; m_linkLayer.linkLayerParameters.timeoutRepeat = 1000; } CIEC101Process::~CIEC101Process() { } CPortProcessItem *CIEC101Process::CreateItem(int ord) { return dynamic_cast(new CIEC101ProcessItem); } void CIEC101Process::DestroyItem(int ord, BOOLEAN bDeleted /* = FALSE */) { CIEC101ProcessItem *pItem = (CIEC101ProcessItem *)GetItem(ord); if (pItem != NULL && !bDeleted) { delete pItem; return CPortProcess::DestroyItem(ord, TRUE); } return CPortProcess::DestroyItem(ord, bDeleted); } BOOLEAN CIEC101Process::OnPreCreate(int id) { if (!CPortProcess::OnPreCreate(id)) return FALSE; if (GetOption(&m_option, sizeof(m_option))) { m_linkLayer.linkLayerParameters.addressLength = m_option.addressLength; m_linkLayer.linkLayerParameters.useSingleCharACK = m_option.useSingleCharACK; m_linkLayer.linkLayerParameters.timeoutForACK = m_option.timeoutForACK; m_linkLayer.linkLayerParameters.timeoutRepeat = m_option.timeoutRepeat; apdu_t4_max = m_option.t4; apdu_t5_max = m_option.t5; use_cycle_interrogation_command = m_option.use_cycle_interrogation_command; } m_nTimeout = GetTimeout(); return TRUE; } BOOLEAN CIEC101Process::Run(void) { int i; BOOLEAN bFailed; BYTE checkSum; BYTE buffer[512]; if (!CPortProcess::Run()) return FALSE; memset(buffer, 0, sizeof(buffer)); if (m_nNeedCount < 1) m_nNeedCount = 1; if (GetDataCount() < m_nNeedCount) return TRUE; if (!GetData(buffer, m_nNeedCount)) { vLog(LOG_ERROR, "%s GetData error!\n", __FILE__); } FeedDog(); bFailed = FALSE; if (buffer[0] == 0xe5) { DropData(1); DisplayRxData(buffer, 1, TRUE); OnPackageReceived(buffer, 1); m_nCurFrame = 0; m_nNeedCount = 1; m_nState = IEC101S_IDLE; return TRUE; } if (m_nState == IEC101S_INFO) { if (buffer[0] == IEC101_STX2) { checkSum = buffer[m_nNeedCount - 2]; if (checkSum != GetCheckSum8(&buffer[4], buffer[1])) { DisplayRxData(buffer, m_nNeedCount, FALSE); bFailed = TRUE; } else { DropData(m_nNeedCount); DisplayRxData(buffer, m_nNeedCount, TRUE); if (OnPackageReceived(buffer, m_nNeedCount) >= 0) { m_nCurFrame = 0; } m_nNeedCount = 1; m_nState = IEC101S_IDLE; } } else if (buffer[0] == IEC101_STX1) { checkSum = buffer[m_nNeedCount - 2]; if (checkSum != GetCheckSum8(&buffer[1], (m_nNeedCount - 3))) { DisplayRxData(buffer, m_nNeedCount, FALSE); bFailed = TRUE; } else { DropData(m_nNeedCount); DisplayRxData(buffer, m_nNeedCount, TRUE); if (OnPackageReceived(buffer, m_nNeedCount) >= 0) { m_nCurFrame = 0; } m_nNeedCount = 1; m_nState = IEC101S_IDLE; } } } else if (m_nState == IEC101S_SYNC) { if (buffer[0] == IEC101_STX2 && buffer[3] == IEC101_STX2 && buffer[1] == buffer[2]) { m_nNeedCount = buffer[1] + 6; m_nState = IEC101S_INFO; } else if (buffer[0] == IEC101_STX1 && buffer[m_nNeedCount - 1] == IEC101_ETX) { m_nState = IEC101S_INFO; } else { m_nNeedCount = 1; bFailed = TRUE; } } else { if (IEC101_STX2 == buffer[0]) { m_nNeedCount = 4; m_nState = IEC101S_SYNC; } else if (IEC101_STX1 == buffer[0]) { m_nNeedCount = m_linkLayer.linkLayerParameters.addressLength + 4; m_nState = IEC101S_SYNC; } else { m_nNeedCount = 1; bFailed = TRUE; } } if (bFailed) { for (i = 0; i < m_nNeedCount; i++) { if (buffer[i] == IEC101_STX1 || buffer[i] == IEC101_STX2) { break; } } if (i == 0) i = 1; if (i > 0) { DropData(i); DisplayRxData(buffer, i, FALSE); } m_nState = IEC101S_IDLE; m_nNeedCount = 1; } return TRUE; } BOOLEAN CIEC101Process::OnTimer(void) { if (!CPortProcess::OnTimer()) return FALSE; m_nCount++; if (m_nCurFrame != 0) { if (m_nSendPoint && (m_nSendPoint + m_nTimeout) <= system32.ticks) { //0.5 second command time out m_nSendPoint = 0; m_nCurFrame = 0; } } return TRUE; } int CIEC101Process::OnPackageReceived(BYTE* pBuf, int msgSize, int /* ord = -1 */) { int userDataLength = 0; int userDataStart = 0; BYTE c = 0; int csStart = 0; int csIndex = 0; int address = 0; BOOLEAN prm = TRUE; int fc = 0; BOOLEAN isAck = FALSE; BYTE* msg = (BYTE *)pBuf; if (msg[0] == IEC101_STX2) { if (msg[1] != msg[2]) { vLog(LOG_ERROR, "ERROR: L fields differ!\n"); return -1; } userDataLength = (int)msg[1] - m_linkLayer.linkLayerParameters.addressLength - 1; userDataStart = 5 + m_linkLayer.linkLayerParameters.addressLength; csStart = 4; csIndex = userDataStart + userDataLength; if (msgSize != (userDataStart + userDataLength + 2 /* CS + END */)) { vLog(LOG_ERROR, "ERROR: Invalid message length\n"); return -1; } c = msg[4]; if (m_linkLayer.linkLayerParameters.addressLength > 0) address += msg[5]; if (m_linkLayer.linkLayerParameters.addressLength > 1) address += msg [6] * 0x100; } else if (msg[0] == IEC101_STX1) { c = msg[1]; csStart = 1; csIndex = 2 + m_linkLayer.linkLayerParameters.addressLength; if (m_linkLayer.linkLayerParameters.addressLength > 0) address += msg[2]; if (m_linkLayer.linkLayerParameters.addressLength > 1) address += msg[3] * 0x100; } else if (msg[0] == 0xe5) { isAck = TRUE; fc = LL_FC_00_ACK; prm = FALSE; /* single char ACK is only sent by secondary station */ } else { vLog(LOG_ERROR, "Received unexpected message type!\n"); return -1; } if (isAck == FALSE) { /* parse C field bits */ fc = c & 0x0f; prm = ((c & 0x40) == 0x40); if (prm) { /* we are secondary link layer */ //本程序为IEC101从协议。 BOOLEAN fcb = ((c & 0x20) == 0x20); BOOLEAN fcv = ((c & 0x10) == 0x10); if (m_linkLayer.mode == llSecBalanced) { LinkLayerSecondaryBalanced_ReceivedMessage(fc, FALSE, fcb, fcv, address, msg, userDataStart, userDataLength); } else { vLog(LOG_DEBUG, "No secondary link layer available!\n"); } if (m_linkLayer.mode == llPriBalanced) { LinkLayerPrimaryBalanced_resetIdleTimeout(); } } else { /* we are primary link layer */ //本程序为IEC101主协议。 BOOLEAN dir = ((c & 0x80) == 0x80); /* DIR - direction for balanced transmission */ BOOLEAN dfc = ((c & 0x10) == 0x10); /* DFC - Data flow control */ if (m_linkLayer.mode == llPriBalanced || m_linkLayer.mode == llSecBalanced) { LinkLayerPrimaryBalanced_ReceivedMessage(fc, dir, dfc, address, msg, userDataStart, userDataLength); } else if (m_linkLayer.mode == llPriUnbalanced) { BOOLEAN acd = ((c & 0x20) == 0x20); /* ACD - access demand for class 1 data - for unbalanced transmission */ LinkLayerPrimaryUnbalanced_ReceivedMessage(fc, acd, dfc, address, msg, userDataStart, userDataLength); } else { vLog(LOG_DEBUG, "No primary link layer available!\n"); } } } else { /* Single byte ACK */ //本程序为IEC101主协议。 if (m_linkLayer.mode == llPriBalanced || m_linkLayer.mode == llSecBalanced) { LinkLayerPrimaryBalanced_ReceivedMessage(LL_FC_00_ACK, FALSE, FALSE, -1, NULL, 0, 0); } else if (m_linkLayer.mode == llPriUnbalanced) { LinkLayerPrimaryUnbalanced_ReceivedMessage(LL_FC_00_ACK, FALSE, FALSE, -1, NULL, 0, 0); } else { vLog(LOG_DEBUG, "No primary link layer available!\n"); } } return 1; } //平衡方式主协议接收到从站报文 void CIEC101Process::LinkLayerPrimaryBalanced_ReceivedMessage(BYTE fc, BOOLEAN dir, BOOLEAN dfc, int address, BYTE* msg, int userDataStart, int userDataLength) { UNUSED(dir); //UNUSED(address); UNUSED(msg); UNUSED(userDataStart); UNUSED(userDataLength); CIEC101ProcessItem* pItem; if (address == -1) pItem = (CIEC101ProcessItem *)GetCurItem(); else { int uid = GetUnitByAddr((BYTE *)&address, m_linkLayer.linkLayerParameters.addressLength); if (uid < 0 || uid >= UNIT_NUM) return; pItem = (CIEC101ProcessItem *)GetItem(GetOrderByUnitID(uid)); } if (pItem == NULL) { vLog(LOG_DEBUG, "PLL RECV - response from unknown slave %i\n", address); return; } pIEC101_LinkLayerPrimaryBalanced self = &(pItem->primaryLinkBalanced); enumIEC101_PrimaryLinkLayerState primaryState = self->primaryState; enumIEC101_PrimaryLinkLayerState newState = primaryState; self->lastReceivedMsg = getTimeInMs(); if (dfc) { switch (self->primaryState) { case PLL_EXECUTE_REQUEST_STATUS_OF_LINK: case PLL_EXECUTE_RESET_REMOTE_LINK: newState = PLL_EXECUTE_REQUEST_STATUS_OF_LINK; break; case PLL_EXECUTE_SERVICE_SEND_CONFIRM: case PLL_SECONDARY_LINK_LAYER_BUSY: newState = PLL_SECONDARY_LINK_LAYER_BUSY; break; default: break; } llpb_setNewState(self, LL_STATE_BUSY); self->primaryState = newState; return; } switch (fc) { case LL_FC_00_ACK: //vLog(LOG_DEBUG, "PLL - RECV FC 00 - ACK\n"); if (primaryState == PLL_EXECUTE_RESET_REMOTE_LINK) { newState = PLL_LINK_LAYERS_AVAILABLE; llpb_setNewState(self, LL_STATE_AVAILABLE); } else if (primaryState == PLL_EXECUTE_SERVICE_SEND_CONFIRM) { if (self->sendLinkLayerTestFunction) { self->sendLinkLayerTestFunction = FALSE; } newState = PLL_LINK_LAYERS_AVAILABLE; llpb_setNewState(self, LL_STATE_AVAILABLE); } self->waitingForResponse = FALSE; break; case LL_FC_01_NACK: //vLog(LOG_DEBUG, "PLL - RECV FC 01 - NACK\n"); if (primaryState == PLL_EXECUTE_SERVICE_SEND_CONFIRM) { newState = PLL_SECONDARY_LINK_LAYER_BUSY; llpb_setNewState(self, LL_STATE_BUSY); } break; case LL_FC_08_RESP_USER_DATA: //vLog(LOG_DEBUG, "PLL - RECV FC 08 - RESP USER DATA\n"); newState = PLL_IDLE; llpb_setNewState(self, LL_STATE_ERROR); break; case LL_FC_09_RESP_NACK_NO_DATA: //vLog(LOG_DEBUG, "PLL - RECV FC 09 - RESP NACK - NO DATA\n"); newState = PLL_IDLE; llpb_setNewState(self, LL_STATE_ERROR); break; case LL_FC_11_STATUS_OF_LINK_OR_ACCESS_DEMAND: //vLog(LOG_DEBUG, "PLL - RECV FC 11 - STATUS OF LINK\n"); if (primaryState == PLL_EXECUTE_REQUEST_STATUS_OF_LINK) { vLog(LOG_DEBUG, "PLL - SEND FC 00 - RESET REMOTE LINK\n"); SendFixedFrame(LL_FC_00_RESET_REMOTE_LINK, self->otherStationAddress, TRUE, m_linkLayer.dir, FALSE, FALSE); self->lastSendTime = getTimeInMs(); self->waitingForResponse = TRUE; newState = PLL_EXECUTE_RESET_REMOTE_LINK; llpb_setNewState(self, LL_STATE_BUSY); } else { /* illegal message in this state */ newState = PLL_IDLE; llpb_setNewState(self, LL_STATE_ERROR); } break; case LL_FC_14_SERVICE_NOT_FUNCTIONING: case LL_FC_15_SERVICE_NOT_IMPLEMENTED: //vLog(LOG_DEBUG, "PLL - link layer service not functioning/not implemented in secondary station\n"); if (self->sendLinkLayerTestFunction) { self->sendLinkLayerTestFunction = FALSE; } if (primaryState == PLL_EXECUTE_SERVICE_SEND_CONFIRM) { newState = PLL_LINK_LAYERS_AVAILABLE; llpb_setNewState(self, LL_STATE_AVAILABLE); } break; default: //vLog(LOG_DEBUG, "UNEXPECTED SECONDARY LINK LAYER MESSAGE\n"); break; } //vLog(LOG_DEBUG, "PLL RECV - old state: %i new state %i\n", primaryState, newState); self->primaryState = newState; } void CIEC101Process::SendSingleCharCharacter(void) { BYTE singleCharAck[] = {0xe5}; SendMessage(singleCharAck, 1); m_nCurFrame = 1; } void CIEC101Process::SendFixedFrame(BYTE fc, int address, BOOLEAN prm, BOOLEAN dir, BOOLEAN acd /*FCB*/, BOOLEAN dfc /*FCV*/) { BYTE buffer[16]; int bufPos = 0; int addressLength = m_linkLayer.linkLayerParameters.addressLength; buffer[bufPos++] = IEC101_STX1; /* START */ BYTE c = fc & 0x0f; if (prm) c += 0x40; if (dir) c += 0x80; if (acd) c += 0x20; if (dfc) c += 0x10; buffer[bufPos++] = c; if (addressLength > 0) { buffer [bufPos++] = (BYTE)(address & 0xFF); if (addressLength > 1) { buffer [bufPos++] = (BYTE) ((address >> 4) & 0xFF); } } BYTE checksum = 0; int i; for (i = 1; i < bufPos; i++) checksum += buffer[i]; buffer[bufPos++] = checksum; buffer[bufPos++] = IEC101_ETX; /* END */ //vLog(LOG_DEBUG, "Send fixed frame (fc=%i)\n", fc); SendMessage(buffer, bufPos); m_nCurFrame = 2; } void CIEC101Process::SendVariableLengthFrame(BYTE fc, int address, BOOLEAN prm, BOOLEAN dir, BOOLEAN acd, BOOLEAN dfc, BYTE* userData, int userDataLength) { BYTE buffer[280]; int addressLength = m_linkLayer.linkLayerParameters.addressLength; buffer[0] = IEC101_STX2; /* START */ buffer[3] = IEC101_STX2; /* START */ BYTE c = fc & 0x0f; if (prm) c += 0x40; if (dir) c += 0x80; if (acd) c += 0x20; if (dfc) c += 0x10; buffer [4] = c; int bufPos = 5; if (addressLength > 0) { buffer [bufPos++] = (BYTE)(address & 0xFF); if (addressLength > 1) { buffer[bufPos++] = (BYTE)((address >> 4) & 0xFF); } } int l = 1 + addressLength + userDataLength; if (l > 255) return; buffer[1] = (BYTE)l; buffer[2] = (BYTE)l; int i; for (i = 0; i < userDataLength; i++) buffer[bufPos++] = userData[i]; BYTE checksum = 0; for (i = 4; i < bufPos; i++) checksum += buffer[i]; buffer[bufPos++] = checksum; buffer[bufPos++] = IEC101_ETX; /* END */ //vLog(LOG_DEBUG, "Send variable frame (fc=%i, size=%i)\n", (int) fc, bufPos); SendMessage(buffer, bufPos); m_nCurFrame = 3; } void CIEC101Process::GetItemYXBWs(CIEC101ProcessItem* pItem) { int i, uid, count; int yxbw_point; BOOLEAN yxbw_value; BYTE yxbw_qds; if (NULL == pItem) return; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return; if (NULL == pItem->yxbws.data) return; count = pItem->yxbws.count; if (count < 0 || count >= DATABASE_YXBW_NUM) count = 0; int max_count = DATABASE_YXBW_NUM - count; for (i = 0; i < max_count; i++) { yxbw_point = GetUnitYXBW(uid, yxbw_value, yxbw_qds); if (yxbw_point < 0) break; if (count >= DATABASE_YXBW_NUM) break; pItem->yxbws.data[count].order = yxbw_point; pItem->yxbws.data[count].value = yxbw_value; pItem->yxbws.data[count].qds = yxbw_qds; count++; } pItem->yxbws.count = count; } void CIEC101Process::GetItemEvents(CIEC101ProcessItem* pItem) { int i, uid, count; int soe_point; BOOLEAN soe_value; BYTE soe_qds; unionCP56Time soe_time; if (NULL == pItem) return; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return; if (NULL == pItem->events.data) return; count = pItem->events.count; if (count < 0 || count >= DATABASE_SOE_NUM) count = 0; int max_count = DATABASE_SOE_NUM - count; for (i = 0; i < max_count; i++) { soe_point = GetUnitSOE(uid, soe_value, soe_qds, soe_time); if (soe_point < 0) break; pItem->events.data[count].order = soe_point; pItem->events.data[count].value = soe_value; pItem->events.data[count].qds = soe_qds; memcpy(&pItem->events.data[count].ct, &soe_time, sizeof(soe_time)); count++; } pItem->events.count = count; } void CIEC101Process::GetItemYCBWs(CIEC101ProcessItem* pItem) { int i, uid, count; if (NULL == pItem) return; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return; if (NULL == pItem->ycbws.data) return; count = pItem->ycbws.count; if (count < 0 || count >= pItem->total_yc) count = 0; for (i = 0; i < pItem->total_yc; i++) { if (TRUE == IsUnitYCBW(uid, i)) { //有变位产生 pItem->ycbws.data[count].order = i; pItem->ycbws.data[count].value = GetUnitYC(uid, i); pItem->ycbws.data[count].flVal = GetUnitYCReal(uid, i); pItem->ycbws.data[count].qds = GetUnitYCQDS(uid, i); ClearUnitYCBW(uid, i); count++; } } pItem->ycbws.count = count; } void CIEC101Process::LinkLayerPrimaryBalanced_runStateMachine(CIEC101ProcessItem *pItem) { QWORD currentTime = getTimeInMs(); pIEC101_LinkLayerPrimaryBalanced self = &(pItem->primaryLinkBalanced); enumIEC101_PrimaryLinkLayerState primaryState = self->primaryState; enumIEC101_PrimaryLinkLayerState newState = primaryState; switch (primaryState) { case PLL_IDLE: self->waitingForResponse = FALSE; self->originalSendTime = 0; self->lastSendTime = 0; self->sendLinkLayerTestFunction = FALSE; newState = PLL_EXECUTE_REQUEST_STATUS_OF_LINK; break; case PLL_EXECUTE_REQUEST_STATUS_OF_LINK: if (self->waitingForResponse) { if (self->lastSendTime > currentTime) { /* last sent time not plausible! */ self->lastSendTime = currentTime; } if (currentTime > (self->lastSendTime + m_linkLayer.linkLayerParameters.timeoutForACK)) { SendFixedFrame(LL_FC_09_REQUEST_LINK_STATUS, self->otherStationAddress, TRUE, m_linkLayer.dir, FALSE, FALSE); self->lastSendTime = currentTime; } } else { //vLog(LOG_DEBUG, "PLL - SEND RESET REMOTE LINK\n"); SendFixedFrame(LL_FC_00_RESET_REMOTE_LINK, self->otherStationAddress, TRUE, m_linkLayer.dir, FALSE, FALSE); self->lastSendTime = currentTime; self->waitingForResponse = TRUE; newState = PLL_EXECUTE_RESET_REMOTE_LINK; } break; case PLL_EXECUTE_RESET_REMOTE_LINK: if (self->waitingForResponse) { if (currentTime > (self->lastSendTime + m_linkLayer.linkLayerParameters.timeoutForACK)) { self->waitingForResponse = FALSE; newState = PLL_IDLE; llpb_setNewState(self, LL_STATE_ERROR); } } else { newState = PLL_LINK_LAYERS_AVAILABLE; llpb_setNewState(self, LL_STATE_AVAILABLE); } break; case PLL_LINK_LAYERS_AVAILABLE: if (self->lastReceivedMsg > currentTime) { /* last received message not plausible */ self->lastReceivedMsg = currentTime; } if ((currentTime - self->lastReceivedMsg) > (unsigned int)self->idleTimeout) { //vLog(LOG_DEBUG, "PLL - Idle timeout detected. Send link layer test function\n"); self->sendLinkLayerTestFunction = TRUE; } if (self->sendLinkLayerTestFunction) { //vLog(LOG_DEBUG, "PLL - SEND TEST LINK\n"); SendFixedFrame(LL_FC_02_TEST_FUNCTION_FOR_LINK, self->otherStationAddress, TRUE, m_linkLayer.dir, self->nextFcb, TRUE); self->nextFcb = !(self->nextFcb); self->lastSendTime = currentTime; self->originalSendTime = self->lastSendTime; newState = PLL_EXECUTE_SERVICE_SEND_CONFIRM; } else { /* provide a buffer where the application layer can encode the user data */ pIEC101_QueueElement element = ApplicationLayer_GetUserData(pItem); if (element) { //vLog(LOG_DEBUG, "PLL: SEND USER DATA CONFIRMED\n"); memcpy(self->buffer, element->buffer, element->size); self->bufferLength = element->size; SendVariableLengthFrame(LL_FC_03_USER_DATA_CONFIRMED, self->otherStationAddress, TRUE, m_linkLayer.dir, self->nextFcb, TRUE, element->buffer, element->size); self->nextFcb = !(self->nextFcb); self->lastSendTime = currentTime; self->originalSendTime = self->lastSendTime; self->waitingForResponse = TRUE; newState = PLL_EXECUTE_SERVICE_SEND_CONFIRM; } } break; case PLL_EXECUTE_SERVICE_SEND_CONFIRM: if (currentTime > (self->lastSendTime + m_linkLayer.linkLayerParameters.timeoutForACK)) { if (currentTime > (self->originalSendTime + m_linkLayer.linkLayerParameters.timeoutRepeat)) { vLog(LOG_DEBUG, "TIMEOUT: ASDU not confirmed after repeated transmission\n"); newState = PLL_IDLE; llpb_setNewState(self, LL_STATE_ERROR); } else { //vLog(LOG_DEBUG, "TIMEOUT: ASDU not confirmed\n"); if (self->sendLinkLayerTestFunction) { //vLog(LOG_DEBUG, "PLL - repeat send test function\n"); SendFixedFrame(LL_FC_02_TEST_FUNCTION_FOR_LINK, self->otherStationAddress, TRUE, m_linkLayer.dir, !(self->nextFcb), TRUE); } else { //vLog(LOG_DEBUG, "PLL - repeat last ASDU\n"); SendVariableLengthFrame(LL_FC_03_USER_DATA_CONFIRMED, self->otherStationAddress, TRUE, m_linkLayer.dir, !(self->nextFcb), TRUE, self->buffer, self->bufferLength); } self->lastSendTime = currentTime; } } break; case PLL_SECONDARY_LINK_LAYER_BUSY: break; default: break; } if (primaryState != newState) { //vLog(LOG_DEBUG, "PLL - old state: %i new state: %i\n", primaryState, newState); } self->primaryState = newState; } /// BOOLEAN CIEC101PrimaryProcess::OnReceiveSingle_point_information(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //单点遥信 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot || IEC_101_104_COT_PER_CYC == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = (*pData & 0x01) == 0x01 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, FALSE, qds); } } } else //单一寻址自动生成YXBW信号 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x01) == 0x01 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSingle_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带时标的单点遥信 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x01) == 0x01 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); SetUnitSOE(uid, point, value, st); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveDouble_point_information(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //双点遥信 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot || IEC_101_104_COT_PER_CYC == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = (*pData & 0x03) == 0x02 ? TRUE : FALSE; qds = (*pData & 0xf0); ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, FALSE, qds); } } } else //单一寻址自动生成YXBW信号 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x03) == 0x02 ? TRUE : FALSE; qds = (*pData & 0xf0); ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveDouble_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带时标的双点遥信 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x03) == 0x02 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); SetUnitSOE(uid, point, value, st); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_normalised(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //测量值,归一化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_PER_CYC == cot || IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } else //单一寻址 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_normalised_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带时标的遥测量,归一化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_scaled(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //测量值,标度化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_PER_CYC == cot || IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } else //单一寻址 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_scaled_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带时标的遥测量,标度化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_short_floating_point(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //测量值,短浮点数 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_PER_CYC == cot || IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; DWORD dwValue; float fValue; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { dwValue = (DWORD)((pData[3] << 24) | (pData[2] << 16) | (pData[1] << 8) | pData[0]); pData += 4; memcpy(&fValue, &dwValue, sizeof(DWORD)); qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, fValue, qds); } } } else //单一寻址 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; dwValue = (DWORD)((pData[3] << 24) | (pData[2] << 16) | (pData[1] << 8) | pData[0]); pData += 4; memcpy(&fValue, &dwValue, sizeof(DWORD)); qds = (*pData & 0xf1); pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, fValue, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_short_floating_point_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带时标的遥测量值,短浮点数 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; DWORD dwValue; float fValue; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; dwValue = (DWORD)((pData[3] << 24) | (pData[2] << 16) | (pData[1] << 8) | pData[0]); pData += 4; memcpy(&fValue, &dwValue, sizeof(DWORD)); qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, fValue, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_normalised_without_quality(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //测量值,不带品质描述的归一化测量值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_PER_CYC == cot || IEC_101_104_COT_BACK == cot || IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot || IEC_101_104_COT_INTERROGATION == cot || IEC_101_104_COT_INRO1 == cot || IEC_101_104_COT_INRO2 == cot || IEC_101_104_COT_INRO3 == cot || IEC_101_104_COT_INRO4 == cot || IEC_101_104_COT_INRO5 == cot || IEC_101_104_COT_INRO6 == cot || IEC_101_104_COT_INRO7 == cot || IEC_101_104_COT_INRO8 == cot || IEC_101_104_COT_INRO9 == cot || IEC_101_104_COT_INRO10 == cot || IEC_101_104_COT_INRO11 == cot || IEC_101_104_COT_INRO12 == cot || IEC_101_104_COT_INRO13 == cot || IEC_101_104_COT_INRO14 == cot || IEC_101_104_COT_INRO15 == cot || IEC_101_104_COT_INRO16 == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = *pData; pData++; value |= (*pData << 8); pData++; qds = 0x00; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } else //单一寻址 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = 0x00; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSingle_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带CP56Time2a时标的单点信息 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x01) == 0x01 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); SetUnitSOE(uid, point, value, st); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveDouble_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带CP56Time2a时标的双点信息 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot || IEC_101_104_COT_RETREM == cot || IEC_101_104_COT_RETLOC == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; BOOLEAN value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = (*pData & 0x03) == 0x02 ? TRUE : FALSE; qds = (*pData & 0xf0); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYXPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYX(uid, point, value, TRUE, qds); SetUnitSOE(uid, point, value, st); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_normalised_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带CP56Time2a时标的遥测量值,归一化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_scaled_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带CP56Time2a时标的遥测量值,标度化值 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; short value; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, (LONG)value, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveMeasured_value_short_floating_point_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //带CP56Time2a时标的遥测量值,短浮点数 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQ == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 DWORD i; DWORD information_address; DWORD dwValue; float fValue; BYTE qds; BYTE ioa[4]; unionCP56Time st; memcpy(&st, &system32.now, sizeof(st)); for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; dwValue = (DWORD)((pData[3] << 24) | (pData[2] << 16) | (pData[1] << 8) | pData[0]); pData += 4; memcpy(&fValue, &dwValue, sizeof(DWORD)); qds = (*pData & 0xf1); pData++; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYCPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYC(uid, point, fValue, qds); } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveIntegrated_totals(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //累积量 { BYTE* pData = pBuf; int point; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (IEC_101_104_COT_SPONT == cot || IEC_101_104_COT_REQCOGEN == cot || IEC_101_104_COT_REQCO1 == cot || IEC_101_104_COT_REQCO2 == cot || IEC_101_104_COT_REQCO3 == cot || IEC_101_104_COT_REQCO4 == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 int i; DWORD information_address; DWORD value; BYTE ioa[4]; if (isSequence) //顺序寻址 { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; for (i = 0; i < num; i++, information_address++) { value = *pData; pData++; value |= (*pData << 8); pData++; value |= (*pData << 16); pData++; value |= (*pData << 24); pData++; //sn = *pData; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYMPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYM(uid, point, value); } } } else //单一寻址 { for (i = 0; i < num; i++) { information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; value = *pData; pData++; value |= (*pData << 8); pData++; value |= (*pData << 16); pData++; value |= (*pData << 24); pData++; //sn = *pData; pData++; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYMPointByParam(uid, ioa, 4); if (point >= 0) { SetUnitYM(uid, point, value); } } } return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveInterrogation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //总召唤 { BYTE* pData = pBuf; DWORD information_address; BYTE QOI; if (IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; if (information_address != 0) return FALSE; QOI = *pData; pData++; if (QOI < 20 || QOI > 36) { return FALSE; } if (IEC_101_104_COT_ACT == cot) { return FALSE; } if (IEC_101_104_COT_ACTCON == cot) { return TRUE; } if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 //总召唤结束 pItem->interrogation_finish = TRUE; return TRUE; } if (IEC_101_104_COT_DEACT == cot) { return FALSE; } if (IEC_101_104_COT_DEACTCON == cot) { return TRUE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveClock_synchronisation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //时钟同步 { BYTE* pData = pBuf; DWORD information_address; unionCP56Time st; if (IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; if (information_address != 0) return FALSE; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; if (cot == IEC_101_104_COT_ACTCON) { pItem->clock_synchronized_finish = TRUE; return TRUE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveCounter_Interrogation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //召唤电度量 { BYTE* pData = pBuf; DWORD information_address; BYTE QCC; if (IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; if (information_address != 0) return FALSE; QCC = *pData; pData++; if ((QCC & 0x3f) < 1 || (QCC & 0x3f) > 5) return FALSE; if (IEC_101_104_COT_ACT == cot) return FALSE; if (IEC_101_104_COT_ACTCON == cot) return TRUE; //激活终止 //召唤电度结束 if (IEC_101_104_COT_ACTTREM == cot) return TRUE; if (IEC_101_104_COT_DEACT == cot) return FALSE; if (IEC_101_104_COT_DEACTCON == cot) return TRUE; } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSingle_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //单点遥控 { BYTE* pData = pBuf; BYTE SE, value; int point; DWORD information_address; BYTE ioa[4]; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if( IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYKPointByParam(uid, ioa, 4); if (point < 0) { vLog(LOG_WARN, "Unit(%d) information address error.\n", uid); return FALSE; } SE = (*pData & 0x80) == 0x80 ? TRUE : FALSE; value = (*pData & 0x01) == 0x01 ? TRUE : FALSE; BYTE* pYKParam = GetUnitYKParamByPoint(uid, point); if (pYKParam == NULL) return FALSE; switch (pYKParam[5]) { case 1: //单触点合圈 if (value != TRUE) return FALSE; break; case 2: //单触点分圈 if (value != FALSE) return FALSE; break; } value = pItem->yk_value; if (SE) { //遥控选择 if (IEC_101_104_COT_ACTCON == cot) { //激活确认 SetUnitYK(uid, point, value, YKS_SELED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_SELED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYK(uid, point, value, YKS_ABRED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP" )); return TRUE; } return FALSE; } else { //遥控执行 if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 SetUnitYK(uid, point, value, YKS_EXEED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYK(uid, point, value, YKS_ABRED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_ACTCON == cot) { //激活确认 vLog(LOG_WARN, "Unit(%d) yk(%d) %s ACTCON.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } return FALSE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveDouble_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //双点遥控 { BYTE* pData = pBuf; BYTE SE, value; int point; DWORD information_address; BYTE ioa[4]; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if( IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYKPointByParam(uid, ioa, 4); if (point < 0) { vLog(LOG_WARN, "Unit(%d) information address error.\n", uid); return FALSE; } SE = (*pData & 0x80) == 0x80 ? TRUE : FALSE; value = (*pData & 0x03) == 0x02 ? TRUE : FALSE; BYTE* pYKParam = GetUnitYKParamByPoint(uid, point); if (pYKParam == NULL) return FALSE; switch (pYKParam[5]) { case 1: //单触点合圈 if (value != TRUE) return FALSE; break; case 2: //单触点分圈 if (value != FALSE) return FALSE; break; } value = pItem->yk_value; if (SE) { //遥控选择 if (IEC_101_104_COT_ACTCON == cot) { //激活确认 SetUnitYK(uid, point, value, YKS_SELED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_SELED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYK(uid, point, value, YKS_ABRED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP" )); return TRUE; } return FALSE; } else { //遥控执行 if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 SetUnitYK(uid, point, value, YKS_EXEED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYK(uid, point, value, YKS_ABRED, YKR_SUCC); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRED result is YKR_SUCC.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else if (IEC_101_104_COT_ACTCON == cot) { //激活确认 vLog(LOG_WARN, "Unit(%d) yk(%d) %s ACTCON.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } return FALSE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSet_point_command_normalized(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //设定归一化值命令 { BYTE* pData = pBuf; BYTE SE; WORD value; int point; DWORD information_address; BYTE ioa[4]; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if( IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { vLog(LOG_WARN, "Unit(%d) information address error.\n", uid); return FALSE; } value = *pData; pData++; value |= (*pData << 8); pData++; SE = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; if (SE) { //遥控选择 if (IEC_101_104_COT_ACTCON == cot) { //激活确认 SetUnitYT(uid, point, value, YTS_SELED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_SELED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } return FALSE; } else { //遥控执行 if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 SetUnitYT(uid, point, value, YTS_EXEED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_EXEED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_ACTCON == cot) { //激活确认 vLog(LOG_WARN, "Unit(%d) set point(%d) %d ACTCON.\n", uid, point, value); return TRUE; } return FALSE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSet_point_command_scaled(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //设定标度化值命令 { BYTE* pData = pBuf; BYTE SE; WORD value; int point; DWORD information_address; BYTE ioa[4]; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if( IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { vLog(LOG_WARN, "Unit(%d) information address error.\n", uid); return FALSE; } value = *pData; pData++; value |= (*pData << 8); pData++; SE = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; if (SE) { //遥控选择 if (IEC_101_104_COT_ACTCON == cot) { //激活确认 SetUnitYT(uid, point, value, YTS_SELED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_SELED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } return FALSE; } else { //遥控执行 if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 SetUnitYT(uid, point, value, YTS_EXEED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_EXEED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_ACTCON == cot) { //激活确认 vLog(LOG_WARN, "Unit(%d) set point(%d) %d ACTCON.\n", uid, point, value); return TRUE; } return FALSE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::OnReceiveSet_point_command_short_floating(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot) //设定短浮点值命令 { BYTE* pData = pBuf; BYTE SE; DWORD value; int point; DWORD information_address; BYTE ioa[4]; int uid; uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if( IEC_101_104_COT_ACTCON == cot || IEC_101_104_COT_DEACTCON == cot || IEC_101_104_COT_ACTTREM == cot || IEC_101_104_COT_UNKNOWN_TI == cot || IEC_101_104_COT_UNKNOWN_COT == cot || IEC_101_104_COT_UNKNOWN_ASDU == cot || IEC_101_104_COT_UNKNOWN_INFO == cot ) { if (isNegative) return FALSE; //否定 if (isTest) return FALSE; //试验 if (isSequence) return FALSE; //顺序寻址 //if (num != 1) return FALSE; information_address = 0; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pData); pData += pItem->applicationlParameters.sizeOfIOA; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { vLog(LOG_WARN, "Unit(%d) information address error.\n", uid); return FALSE; } value = *pData; pData++; value |= (*pData << 8); pData++; value |= (*pData << 16); pData++; value |= (*pData << 24); pData++; SE = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; if (SE) { //遥控选择 if (IEC_101_104_COT_ACTCON == cot) { //激活确认 SetUnitYT(uid, point, value, YTS_SELED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_SELED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } return FALSE; } else { //遥控执行 if (IEC_101_104_COT_ACTTREM == cot) { //激活终止 SetUnitYT(uid, point, value, YTS_EXEED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_EXEED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_DEACTCON == cot) { //停止激活确认 SetUnitYT(uid, point, value, YTS_ABRED, YTR_SUCC); vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is YTS_ABRED result is YTR_SUCC.\n", uid, point, value); return TRUE; } else if (IEC_101_104_COT_ACTCON == cot) { //激活确认 vLog(LOG_WARN, "Unit(%d) set point(%d) %d ACTCON.\n", uid, point, value); return TRUE; } return FALSE; } } return FALSE; } BOOLEAN CIEC101PrimaryProcess::GetYKFrame(CIEC101ProcessItem* pItem, int ord) { int uid, order, len; DWORD information_address; BYTE value, state, result, command, yk_type, relay_type, QU; BYTE cause_of_transmission = 0; BYTE type_id; BYTE buffer[64]; if (NULL == pItem) return FALSE; command = 0; len = 0; memset(buffer, 0, sizeof(buffer)); uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (!GetUnitYK(uid, order, value, state, result)) return FALSE; vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is %s result is %s.\n", uid, order, (value ? "CLOSE" : "TRIP"), val_to_str( state, yk_state, "STATE= %d" ), val_to_str( result, yk_result, "RESULT= %d")); //获取遥控信息体地址 BYTE* pParam = GetUnitYKParamByPoint(uid, order); if (NULL == pParam) return FALSE; pItem->yk_value = value; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pParam); yk_type = pParam[4]; relay_type = pParam[5]; QU = pParam[6]; QU <<= 2; QU &= 0x7c; if (yk_type == USE_YK_DC || yk_type == USE_YK_DEF) { //双点遥控 command = (value == TRUE) ? DCO_ON: DCO_OFF; type_id = C_DC_NA_1; //buffer[len++] = C_DC_NA_1; } else if (yk_type == USE_YK_SC) { switch (relay_type) { case 1: //单触点合圈 command = TRUE; break; case 2: //单触点分圈 command = FALSE; break; default: //双触点线圈 command = value; break; } //buffer[len++] = C_SC_NA_1; type_id = C_SC_NA_1; } if (YKS_SELREQ == state) { cause_of_transmission = IEC_101_104_COT_ACT; command |= 0x80; } else if (YKS_EXEREQ == state) { cause_of_transmission = IEC_101_104_COT_ACT; } else if ((YKS_ABRREQ == state) || ((YKS_SELING == state || YKS_SELED == state) && YKR_OVER == result)) { cause_of_transmission = IEC_101_104_COT_DEACT; command |= 0x80; } len = ASDU_initialize(buffer, &(pItem->applicationlParameters), type_id, FALSE, cause_of_transmission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(buffer); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], information_address, FALSE); buffer[len++] = (command | QU); Master_sendASDU(pItem, buffer, len); return TRUE; } BOOLEAN CIEC101PrimaryProcess::GetYTFrame(CIEC101ProcessItem* pItem, int ord) { int uid, order, len, data_length; DWORD information_address, value; BYTE state, result, yt_type; BYTE command = 0; BYTE type_id; BYTE cause_of_transmission = 0; BYTE buffer[64]; if (NULL == pItem) return FALSE; data_length = 2; len = 0; memset(buffer, 0, sizeof(buffer)); uid = pItem->GetUnitID(); if (uid < 0 || uid >= UNIT_NUM) return FALSE; if (!GetUnitYT(uid, order, value, state, result)) return FALSE; vLog(LOG_WARN, "Unit(%d) set point(%d) %d state is %s result is %s.\n", uid, order, value, val_to_str( state, yt_state, "STATE= %d" ), val_to_str( result, yt_result, "RESULT= %d")); //获取遥调信息体地址 BYTE* pParam = GetUnitYTParamByPoint(uid, order); if (NULL == pParam) return FALSE; information_address = ASDU_getIOA(&(pItem->applicationlParameters), pParam); yt_type = pParam[4]; if (yt_type == USE_YT_NA) { data_length = 2; type_id = C_SE_NA_1; } else if (yt_type == USE_YT_NB) { data_length = 2; type_id = C_SE_NB_1; } else if (yt_type == USE_YT_NC) { data_length = 4; type_id = C_SE_NC_1; } else { vLog(LOG_WARN, "Unit(%d) set point(%d) type(%d) error.\n", uid, order, yt_type); return FALSE; } if (YTS_SELREQ == state) { cause_of_transmission = IEC_101_104_COT_ACT; command |= IEC_101_104_SE; } else if (YTS_EXEREQ == state) { cause_of_transmission = IEC_101_104_COT_ACT; command = 0; } else if ((YTS_ABRREQ == state) || ((YTS_SELING == state || YTS_SELED == state) && YTR_OVER == result)) { cause_of_transmission = IEC_101_104_COT_DEACT; command = 0; } len = ASDU_initialize(buffer, &(pItem->applicationlParameters), type_id, FALSE, cause_of_transmission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(buffer); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], information_address, FALSE); if (data_length == 2) { buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; } else if (data_length == 4) { buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; buffer[len++] = (value >> 16) & 0xff; buffer[len++] = (value >> 24) & 0xff; } buffer[len++] = command; Master_sendASDU(pItem, buffer, len); return TRUE; } /***************************************************************************************/ BOOLEAN CIEC101SecondaryProcess::ApplicationLayer_ReceivedData(CIEC101ProcessItem* pItem, BYTE* msg, BOOLEAN isBroadcast, int userDataStart, int userDataLength) { UNUSED(isBroadcast); BYTE *asdu = msg + userDataStart; BYTE tid = ASDU_getTypeID(asdu); BYTE cot = ASDU_getCOT(asdu); BOOLEAN isSequence = ASDU_isSequence(asdu); BOOLEAN isNegative = ASDU_isNegative(asdu); BOOLEAN isTest = ASDU_isTest(asdu); int num = ASDU_getNumberOfElements(asdu); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); int ret = NO_ERROR; int uid = pItem->GetUnitID(); BYTE *pData = asdu + parameters->sizeOfTypeId + parameters->sizeOfVSQ + parameters->sizeOfCOT + parameters->sizeOfCA; switch (tid) { case C_IC_NA_1: //总召唤命令 return Receive_Interrogation_command(pItem, pData, cot); case C_SC_NA_1: //单点遥控命令.没有总召唤,不响应遥控报文 return Receive_Single_command(pItem, pData, cot); case C_DC_NA_1: //双点遥控命令.没有总召唤,不响应遥控报文 return Receive_Double_command(pItem, pData, cot); case C_CI_NA_1: //脉冲量召唤命令 return Receive_Counter_interrogation_command(pItem, pData, cot); case C_CS_NA_1: //时间同步命令 return Receive_Clock_synchronisation_command(pItem, pData, cot); case C_SE_NA_1: //设定命令,归一化值.没有总召唤,不响应设定报文 return Receive_Set_point_command_normalized(pItem, pData, cot); //设定规一化值命令 case C_SE_NB_1: //设定命令,标度化值.没有总召唤,不响应设定报文 return Receive_Set_point_command_scaled(pItem, pData, cot); //设定标度化值命令 case C_SE_NC_1: //设定命令,短浮点数.没有总召唤,不响应设定报文 return Receive_Set_point_command_short_floating(pItem, pData, cot); //设定短浮点值命令 default: vLog(LOG_WARN, "Unit(%d) Unsupported I frame type = 0x%02x\n", uid, (int)tid); } return TRUE; } BOOLEAN CIEC101SecondaryProcess::MakeYKFrame(CIEC101ProcessItem* pItem) { BYTE buffer[32]; if (NULL == pItem) return -1; int order; BYTE value, action, result; BYTE command = 0; if (!GetUnitYK(pItem->GetUnitID(), order, value, action, result)) { return FALSE; } vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is %s result is %s\n", pItem->GetUnitID(), order, (value ? "CLOSE" : "TRIP"), val_to_str(action, yk_state, "STATE=%d"), val_to_str(result, yk_result, "RESULT=%d")); if (YKS_SELED == action && YKR_FAIL == result) { command |= IEC_101_104_SE; action = YKS_ABRED; } else if (YKS_SELREQ == action && YKR_OVER == result) { command |= IEC_101_104_SE; action = YKS_ABRED; } else if (YKS_SELING == action && YKR_OVER == result) { command |= IEC_101_104_SE; action = YKS_ABRED; } BYTE* param; BYTE yk_type; DWORD ioa; param = GetUnitYKParamByPoint(pItem->GetUnitID(), order); ioa = MAKEDWORD(MAKEWORD(param[0], param[1]), MAKEWORD(param[2], param[3])); BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_DC_NA_1, FALSE, 0, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], ioa, FALSE); yk_type = param[4]; if (yk_type == USE_YK_DC || yk_type == USE_YK_DEF) { //双点遥控 ASDU_setTypeID(asdu, C_DC_NA_1); command |= value ? DCO_ON : DCO_OFF; } else { ASDU_setTypeID(asdu, C_SC_NA_1); command |= value ? SCO_ON : SCO_OFF; } if (YKS_SELED == action) { command |= IEC_101_104_SE; ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); } else if (YKS_ABRED == action) { ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); } else if (YKS_EXEED == action) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTTREM); } else { return FALSE; } asdu[len++] = command; Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::MakeYTFrame(CIEC101ProcessItem* pItem) { int order; BYTE action, result; DWORD value; BYTE command = 0; if (!GetUnitYT(pItem->GetUnitID(), order, value, action, result)) { return FALSE; } vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is %s result is %s\n", pItem->GetUnitID(), order, value, val_to_str(action, yt_state, "STATE=%d"), val_to_str(result, yt_result, "RESULT=%d")); BYTE* param; BYTE yt_type; DWORD ioa; param = GetUnitYTParamByPoint(pItem->GetUnitID(), order); ioa = MAKEDWORD(MAKEWORD(param[0], param[1]), MAKEWORD(param[2], param[3])); BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_SE_NA_1, FALSE, 0, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], ioa, FALSE); yt_type = param[4]; if (yt_type == USE_YT_NA) { //双点遥控 ASDU_setTypeID(asdu, C_SE_NA_1); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; } else if (yt_type == USE_YT_NB) { ASDU_setTypeID(asdu, C_SE_NB_1); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; } else { ASDU_setTypeID(asdu, C_SE_NC_1); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; asdu[len++] = (value >> 16) & 0xff; asdu[len++] = (value >> 24) & 0xff; } if (YTS_SELED == action && YTR_FAIL == result) { command = IEC_101_104_SE; action = YTS_ABRED; } else if (YTS_SELREQ == action && YTR_OVER == result) { command = IEC_101_104_SE; action = YTS_ABRED; } else if (YTS_SELING == action && YTR_OVER == result) { command = IEC_101_104_SE; action = YTS_ABRED; } if (YTS_SELED == action) { command = IEC_101_104_SE; ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); } else if (YTS_ABRED == action) { ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); } else if (YTS_EXEED == action) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTTREM); } else { return FALSE; } asdu[len++] = command; Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Interrogation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //总召唤 { QualifierOfInterrogation QOI; BYTE* pData = (BYTE*)pBuf; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); int ioa = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; QOI = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_IC_NA_1, FALSE, cot, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); asdu[len++] = QOI; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { if (QOI < IEC60870_QOI_STATION || QOI > IEC60870_QOI_GROUP_16) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } else { //总召唤,分组召唤 pItem->call_type = QOI; ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); } pItem->interrogation_start = TRUE; pItem->interrogation_yx_fin = FALSE; pItem->interrogation_yc_fin = FALSE; pItem->yx_pos = 0; pItem->yc_pos = 0; //清空原先YXBW库 ClearUnitYXBW(pItem->GetUnitID()); return TRUE; } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; //传输原因错误 } BOOLEAN CIEC101SecondaryProcess::Receive_Clock_synchronisation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //时钟同步 { BYTE* pData = (BYTE*)pBuf; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); int ioa = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; unionCP56Time st; st.millisecond = *pData; pData++; st.millisecond |= (*pData << 8); pData++; st.minute = *pData & 0x3f; st.IV = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.hour = *pData & 0x1f; st.SU = (*pData & 0x80) == 0x80 ? TRUE : FALSE; pData++; st.dayofmonth = *pData & 0x1f; st.dayofweek = ((*pData & 0xe0) >> 5); pData++; st.month = *pData & 0x0f; pData++; st.year = *pData & 0x7f; pData++; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_CS_NA_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); len += unionCP56TimeToBuf(&asdu[len], st); if (IEC_101_104_COT_ACT == cot) { if (st.IV) { vLog(LOG_WARN, "Remote Control system time is invalid.\n"); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } if (!IsAcceptTime()) { vLog(LOG_WARN, "Local clock sync is not supported or not configured.\n"); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } set_system_time(&st); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; //传输原因错误 } BOOLEAN CIEC101SecondaryProcess::Receive_Counter_interrogation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //累积量 { QualifierOfCIC QCC; BYTE* pData = (BYTE*)pBuf; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); int ioa = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; QCC = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_CI_NA_1, FALSE, cot, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); asdu[len++] = QCC; //累计量召唤命令限定词出错 if ((QCC & 0x3f) < IEC60870_QCC_RQT_GROUP_1 || (QCC & 0x3f) > IEC60870_QCC_RQT_GENERAL) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } if (IEC_101_104_COT_ACT == cot) { pItem->call_type = QCC; pItem->ym_pos = 0; pItem->pulse_start = TRUE; pItem->pulse_fin = FALSE; ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; //传输原因错误 } BOOLEAN CIEC101SecondaryProcess::Receive_Reset_process_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //复位进程 { if (IEC_101_104_COT_ACT == cot) { return TRUE; } return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Single_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //单点令 { BYTE* pData = (BYTE*)pBuf; BYTE command; int uid, point; DWORD information_address; BOOLEAN value; BYTE SE; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); if (!pItem->interrogation_finish) return TRUE; information_address = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; command = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_SC_NA_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], information_address, FALSE); asdu[len++] = command; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { uid = pItem->GetUnitID(); BYTE ioa[4]; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYKPointByParam(uid, ioa, 4); if (point < 0) { //信息体地址错误 ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_INFO); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } SE = GET_SE(command); value = GET_SCO(command); pData++; //判断该点是否为单点遥控及参数状态 BYTE* param; BYTE yk_type; BYTE relay_type; param = GetUnitYKParamByPoint(uid, point); yk_type = param[4]; relay_type = param[5]; if (IEC_101_104_COT_ACT == cot) { if (!isSingleCommandChecked(yk_type, relay_type, value)) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活 if (SE) { //选择 SetUnitYK(uid, point, value, YKS_SELREQ, YKR_IDLE); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_SELREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else { //执行 SetUnitYK(uid, point, value, YKS_EXEREQ, YKR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } } else if (IEC_101_104_COT_DEACT == cot) { if (!isSingleCommandChecked(yk_type, relay_type, value)) { ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活终止 SetUnitYK(uid, point, value, YKS_ABRREQ, YKR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Double_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //单点令 { BYTE* pData = (BYTE*)pBuf; BYTE command; int uid, point; DWORD information_address; BOOLEAN value; BYTE SE; if (!pItem->interrogation_finish) return TRUE; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); information_address = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; command = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_DC_NA_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], information_address, FALSE); asdu[len++] = command; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { uid = pItem->GetUnitID(); BYTE ioa[4]; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYKPointByParam(uid, ioa, 4); if (point < 0) { ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_INFO); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } SE = GET_SE(command); value = GET_DCO(command); pData++; //判断该点是否为单点遥控及参数状态 BYTE* param; BYTE yk_type; param = GetUnitYKParamByPoint(uid, point); yk_type = param[4]; if (IEC_101_104_COT_ACT == cot) { if (yk_type == USE_YK_SC) { ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活 if (SE) { //选择 SetUnitYK(uid, point, value, YKS_SELREQ, YKR_IDLE); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_SELREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } else { //执行 SetUnitYK(uid, point, value, YKS_EXEREQ, YKR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_EXEREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } } else if (IEC_101_104_COT_DEACT == cot) { if (yk_type == USE_YK_SC) { ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活终止 SetUnitYK(uid, point, value, YKS_ABRREQ, YKR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_WARN, "Unit(%d) yk(%d) %s state is YKS_ABRREQ result is YKR_IDLE.\n", uid, point, (value ? "CLOSE" : "TRIP")); return TRUE; } } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Set_point_command_normalized(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //设定规一化值命令 { BYTE* pData = (BYTE*)pBuf; BYTE command; int uid, point; int information_address; WORD value = 0; BYTE SE; if (!pItem->interrogation_finish) return TRUE; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); information_address = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; value = (WORD)(pData[0] | pData[1] << 8); pData += 2; command = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_SE_NA_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], information_address, FALSE); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; asdu[len++] = command; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { uid = pItem->GetUnitID(); BYTE ioa[4]; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_INFO); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } SE = GET_SE(command); //判断该点是否为单点遥控及参数状态 BYTE* param; BYTE yt_type; param = GetUnitYTParamByPoint(pItem->GetUnitID(), point); yt_type = param[4]; if (IEC_101_104_COT_ACT == cot) { if (yt_type != USE_YT_NA) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活 if (SE) { //选择 SetUnitYT(uid, point, value, YTS_SELREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_SELREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } else { //执行 SetUnitYT(uid, point, value, YTS_EXEREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_EXEREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } else if (IEC_101_104_COT_DEACT == cot) { if (yt_type != USE_YT_NA) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活终止 SetUnitYT(uid, point, value, YTS_ABRREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_ABRREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Set_point_command_scaled(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //设定标度化值命令 { BYTE* pData = (BYTE*)pBuf; BYTE command; int uid, point; int information_address; WORD value = 0; BYTE SE; if (!pItem->interrogation_finish) return TRUE; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); information_address = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; value = (WORD)(pData[0] | pData[1] << 8); pData += 2; command = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_SE_NB_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], information_address, FALSE); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; asdu[len++] = command; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { uid = pItem->GetUnitID(); BYTE ioa[4]; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_INFO); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } SE = GET_SE(command); //判断该点是否为单点遥控及参数状态 BYTE* param; BYTE yt_type; param = GetUnitYTParamByPoint(pItem->GetUnitID(), point); yt_type = param[4]; if (IEC_101_104_COT_ACT == cot) { if (yt_type != USE_YT_NB) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活 if (SE) { //选择 SetUnitYT(uid, point, value, YTS_SELREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_SELREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } else { //执行 SetUnitYT(uid, point, value, YTS_EXEREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_EXEREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } else if (IEC_101_104_COT_DEACT == cot) { if (yt_type != USE_YT_NB) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活终止 SetUnitYT(uid, point, value, YTS_ABRREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_ABRREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Receive_Set_point_command_short_floating(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot) //设定短浮点值命令 { BYTE* pData = (BYTE*)pBuf; BYTE command; int uid, point; int information_address; DWORD value; BYTE SE; if (!pItem->interrogation_finish) return TRUE; pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); information_address = ASDU_getIOA(parameters, pData); pData += parameters->sizeOfIOA; value = (DWORD)(pData[0] | (pData[1] << 8) | (pData[2] << 16) | (pData[3] << 24)); pData += 4; command = *pData; BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_SE_NC_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], information_address, FALSE); asdu[len++] = value & 0xff; asdu[len++] = (value >> 8) & 0xff; asdu[len++] = (value >> 16) & 0xff; asdu[len++] = (value >> 24) & 0xff; asdu[len++] = command; if (IEC_101_104_COT_ACT == cot || IEC_101_104_COT_DEACT == cot) { uid = pItem->GetUnitID(); BYTE ioa[4]; ioa[0] = information_address & 0xff; ioa[1] = (information_address >> 8) & 0xff; ioa[2] = (information_address >> 16) & 0xff; ioa[3] = (information_address >> 24) & 0xff; point = GetUnitYTPointByParam(uid, ioa, 4); if (point < 0) { ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_INFO); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } SE = GET_SE(command); //判断该点是否为单点遥控及参数状态 BYTE* param; BYTE yt_type; param = GetUnitYTParamByPoint(pItem->GetUnitID(), point); yt_type = param[4]; if (IEC_101_104_COT_ACT == cot) { if (yt_type != USE_YT_NC) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活 if (SE) { //选择 SetUnitYT(uid, point, value, YTS_SELREQ, YTR_IDLE); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_SELREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } else { //执行 SetUnitYT(uid, point, value, YTS_EXEREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_ACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_EXEREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } else if (IEC_101_104_COT_DEACT == cot) { if (yt_type != USE_YT_NB) { //遥控类型错误,返回否定确认 ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } //激活终止 SetUnitYT(uid, point, value, YTS_ABRREQ, YTR_IDLE); ASDU_setCOT(asdu, IEC_101_104_COT_DEACTCON); Slave_enqueueUserDataClass1(pItem, asdu, len); vLog(LOG_DEBUG, "Unit(%d) set point(%d) %d state is YTS_ABRREQ result is YTR_IDLE.\n", uid, point, value); return TRUE; } } ASDU_setCOT(asdu, IEC_101_104_COT_UNKNOWN_COT); ASDU_setNegative(asdu, TRUE); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Send_End_of_initialisation(CIEC101ProcessItem* pItem) { BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), M_EI_NA_1, FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); ASDU_setCOT(asdu, IEC_101_104_COT_INIT); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Send_Single_point_information(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count, len; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_SP_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥信变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 1)); count = (pItem->yxbws.count > count) ? count : pItem->yxbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yxbws.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->yxbws.data[i].value; } pItem->yxbws.count -= count; if (pItem->yxbws.count <= 0 || pItem->yxbws.count >= DATABASE_YXBW_NUM) { //遥信变位发送结束 pItem->yxbws.count = 0; } else { memcpy(pItem->yxbws.data, &pItem->yxbws.data[count], sizeof(struYXData) * pItem->yxbws.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } else { //召唤 count = (parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA); count = (count > 127) ? 127 : count; //遥信最大为127个信息 count = (pItem->total_yx - pItem->yx_pos) > count ? count : (pItem->total_yx - pItem->yx_pos); if (count <= 0) { pItem->yx_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yx_fin = TRUE; //遥信发送完毕 } return FALSE; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yx_pos + pItem->yx_start_address), FALSE); uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { buffer[len++] = GetUnitYX(uid, pItem->yx_pos + i) | GetUnitYXQDS(uid, pItem->yx_pos + i); } pItem->yx_pos += count; if (pItem->yx_pos < 0 || pItem->yx_pos >= pItem->total_yx) { pItem->yx_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yx_fin = TRUE; //遥信发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Single_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_SP_TA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //短时标事件记录 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 4)); count = (pItem->events.count > count) ? count : pItem->events.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->events.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->yxbws.data[i].value; buffer[len++] = (BYTE)(pItem->events.data[i].ct.millisecond & 0x00ff);; buffer[len++] = (BYTE)((pItem->events.data[i].ct.millisecond >> 8)& 0x00ff); buffer[len++] = (BYTE)(pItem->events.data[i].ct.minute | (pItem->events.data[i].ct.IV << 7)); } pItem->events.count -= count; if (pItem->events.count <= 0 || pItem->events.count >= DATABASE_SOE_NUM) { //事件记录发送结束 pItem->events.count = 0; } else { memcpy(pItem->events.data, &pItem->events.data[count], sizeof(struEventsData) * pItem->events.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Single_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_SP_TB_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //长时标事件记录 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 8)); count = (pItem->events.count > count) ? count : pItem->events.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->events.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->events.data[i].value; buffer[len++]= (BYTE)(pItem->events.data[i].ct.millisecond & 0x00ff); buffer[len++] = (BYTE)((pItem->events.data[i].ct.millisecond >> 8)& 0x00ff); buffer[len++] = (BYTE)(pItem->events.data[i].ct.minute | (pItem->events.data[i].ct.IV << 7)); buffer[len++] = (BYTE)(pItem->events.data[i].ct.hour | (pItem->events.data[i].ct.SU << 7)); buffer[len++] = (BYTE)(pItem->events.data[i].ct.dayofmonth | (pItem->events.data[i].ct.dayofweek << 5)); buffer[len++] = (BYTE)pItem->events.data[i].ct.month; buffer[len++] = (BYTE)pItem->events.data[i].ct.year; } pItem->events.count -= count; if (pItem->events.count <= 0 || pItem->events.count >= DATABASE_SOE_NUM) { //事件记录发送结束 pItem->events.count = 0; } else { memcpy(pItem->events.data, &pItem->events.data[count], sizeof(struEventsData) * pItem->events.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Double_point_information(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count, len; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_DP_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥信变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 1)); count = (pItem->yxbws.count > count) ? count : pItem->yxbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yxbws.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->yxbws.data[i].value ? DPI_ON : DPI_OFF; } pItem->yxbws.count -= count; if (pItem->yxbws.count <= 0 || pItem->yxbws.count >= DATABASE_YXBW_NUM) { //遥信变位发送结束 pItem->yxbws.count = 0; } else { memcpy(pItem->yxbws.data, &pItem->yxbws.data[count], sizeof(struYXData) * pItem->yxbws.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } else { //召唤 count = (parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA); count = (count > 127) ? 127 : count; //遥信最大为127个信息 count = (pItem->total_yx - pItem->yx_pos) > count ? count : (pItem->total_yx - pItem->yx_pos); if (count <= 0) { pItem->yx_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yx_fin = TRUE; //遥信发送完毕 } return FALSE; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yx_pos + pItem->yx_start_address), FALSE); uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { buffer[len++] = (GetUnitYX(uid, pItem->yx_pos + i) ? DPI_ON : DPI_OFF) | GetUnitYXQDS(uid, pItem->yx_pos + i); } pItem->yx_pos += count; if (pItem->yx_pos < 0 || pItem->yx_pos >= pItem->total_yx) { pItem->yx_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yx_fin = TRUE; //遥信发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Double_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_DP_TA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //短时标事件记录 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 4)); count = (pItem->events.count > count) ? count : pItem->events.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->events.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->yxbws.data[i].value ? DPI_ON : DPI_OFF; buffer[len++] = (BYTE)(pItem->events.data[i].ct.millisecond & 0x00ff);; buffer[len++] = (BYTE)((pItem->events.data[i].ct.millisecond >> 8)& 0x00ff); buffer[len++] = (BYTE)(pItem->events.data[i].ct.minute | (pItem->events.data[i].ct.IV << 7)); } pItem->events.count -= count; if (pItem->events.count <= 0 || pItem->events.count >= DATABASE_SOE_NUM) { //事件记录发送结束 pItem->events.count = 0; } else { memcpy(pItem->events.data, &pItem->events.data[count], sizeof(struEventsData) * pItem->events.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Double_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_DP_TB_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //长时标事件记录 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 8)); count = (pItem->events.count > count) ? count : pItem->events.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->events.data[i].order + pItem->yx_start_address), FALSE); buffer[len++] = pItem->events.data[i].value ? DPI_ON : DPI_OFF; buffer[len++]= (BYTE)(pItem->events.data[i].ct.millisecond & 0x00ff); buffer[len++] = (BYTE)((pItem->events.data[i].ct.millisecond >> 8)& 0x00ff); buffer[len++] = (BYTE)(pItem->events.data[i].ct.minute | (pItem->events.data[i].ct.IV << 7)); buffer[len++] = (BYTE)(pItem->events.data[i].ct.hour | (pItem->events.data[i].ct.SU << 7)); buffer[len++] = (BYTE)(pItem->events.data[i].ct.dayofmonth | (pItem->events.data[i].ct.dayofweek << 5)); buffer[len++] = (BYTE)pItem->events.data[i].ct.month; buffer[len++] = (BYTE)pItem->events.data[i].ct.year; } pItem->events.count -= count; if (pItem->events.count <= 0 || pItem->events.count >= DATABASE_SOE_NUM) { //事件记录发送结束 pItem->events.count = 0; } else { memcpy(pItem->events.data, &pItem->events.data[count], sizeof(struEventsData) * pItem->events.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Measured_value_normalised(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_ME_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥测变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 3)); count = (pItem->ycbws.count > count) ? count : pItem->ycbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ycbws.data[i].order + pItem->yc_start_address), FALSE); buffer[len++] = pItem->ycbws.data[i].value & 0xff; buffer[len++] = (pItem->ycbws.data[i].value >> 8) & 0xff; buffer[len++] = 0; } pItem->ycbws.count -= count; if (pItem->ycbws.count <= 0 || pItem->ycbws.count >= UNIT_YC_MAX) { //遥测变位发送结束 pItem->ycbws.count = 0; } else { memcpy(pItem->ycbws.data, &pItem->ycbws.data[count], sizeof(struYCBW) * pItem->ycbws.count); } Slave_enqueueUserDataClass2(pItem, buffer, len); return TRUE; } else { //召唤 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA) / 3); count = ((pItem->total_yc - pItem->yc_pos) > count) ? count : (pItem->total_yc - pItem->yc_pos); if (count <= 0) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } return 0; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yc_pos + pItem->yc_start_address), FALSE); short value; uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { value = (short)GetUnitYC(uid, pItem->yc_pos + i); buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; buffer[len++] = GetUnitYCQDS(uid, pItem->yc_pos + i); } pItem->yc_pos += count; if (pItem->yc_pos < 0 || pItem->yc_pos >= pItem->total_yc) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Measured_value_scaled(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_ME_NB_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥测变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 3)); count = (pItem->ycbws.count > count) ? count : pItem->ycbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ycbws.data[i].order + pItem->yc_start_address), FALSE); buffer[len++] = pItem->ycbws.data[i].value & 0xff; buffer[len++] = (pItem->ycbws.data[i].value >> 8) & 0xff; buffer[len++] = 0; } pItem->ycbws.count -= count; if (pItem->ycbws.count <= 0 || pItem->ycbws.count >= UNIT_YC_MAX) { //遥测变位发送结束 pItem->ycbws.count = 0; } else { memcpy(pItem->ycbws.data, &pItem->ycbws.data[count], sizeof(struYCBW) * pItem->ycbws.count); } Slave_enqueueUserDataClass2(pItem, buffer, len); return TRUE; } else { //召唤 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA) / 3); count = ((pItem->total_yc - pItem->yc_pos) > count) ? count : (pItem->total_yc - pItem->yc_pos); if (count <= 0) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } return 0; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yc_pos + pItem->yc_start_address), FALSE); short value; uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { value = (short)GetUnitYC(uid, pItem->yc_pos + i); buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; buffer[len++] = GetUnitYCQDS(uid, pItem->yc_pos + i); } pItem->yc_pos += count; if (pItem->yc_pos < 0 || pItem->yc_pos >= pItem->total_yc) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Measured_value_short_floating_point(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_ME_NC_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥测变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 5)); count = (pItem->ycbws.count > count) ? count : pItem->ycbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ycbws.data[i].order + pItem->yc_start_address), FALSE); buffer[len++] = pItem->ycbws.data[i].code & 0xff; buffer[len++] = (pItem->ycbws.data[i].code >> 8) & 0xff; buffer[len++] = (pItem->ycbws.data[i].code >> 16) & 0xff; buffer[len++] = (pItem->ycbws.data[i].code >> 24) & 0xff; buffer[len++] = 0; } pItem->ycbws.count -= count; if (pItem->ycbws.count <= 0 || pItem->ycbws.count >= UNIT_YC_MAX) { //遥测变位发送结束 pItem->ycbws.count = 0; } else { memcpy(pItem->ycbws.data, &pItem->ycbws.data[count], sizeof(struYCBW) * pItem->ycbws.count); } Slave_enqueueUserDataClass2(pItem, buffer, len); return TRUE; } else { //召唤 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA) / 5); count = ((pItem->total_yc - pItem->yc_pos) > count) ? count : (pItem->total_yc - pItem->yc_pos); if (count <= 0) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } return 0; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yc_pos + pItem->yc_start_address), FALSE); union { float flval; DWORD code; } value; uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { value.flval = GetUnitYCReal(uid, pItem->yc_pos + i); buffer[len++] = value.code & 0xff; buffer[len++] = (value.code >> 8) & 0xff; buffer[len++] = (value.code >> 16) & 0xff; buffer[len++] = (value.code >> 24) & 0xff; buffer[len++] = GetUnitYCQDS(uid, pItem->yc_pos + i); } pItem->yc_pos += count; if (pItem->yc_pos < 0 || pItem->yc_pos >= pItem->total_yc) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Measured_value_normalised_without_quality(CIEC101ProcessItem* pItem, BYTE cause_of_transimission /* = IEC_101_104_COT_SPONT */) { int uid; int i, count; int len = 0; BYTE buffer[268]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_ME_ND_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥测变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 2)); count = (pItem->ycbws.count > count) ? count : pItem->ycbws.count; if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ycbws.data[i].order + pItem->yc_start_address), FALSE); buffer[len++] = pItem->ycbws.data[i].value & 0xff; buffer[len++] = (pItem->ycbws.data[i].value >> 8) & 0xff; } pItem->ycbws.count -= count; if (pItem->ycbws.count <= 0 || pItem->ycbws.count >= UNIT_YC_MAX) { //遥测变位发送结束 pItem->ycbws.count = 0; } else { memcpy(pItem->ycbws.data, &pItem->ycbws.data[count], sizeof(struYCBW) * pItem->ycbws.count); } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } else { //召唤 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA) << 1); count = ((pItem->total_yc - pItem->yc_pos) > count) ? count : (pItem->total_yc - pItem->yc_pos); if (count <= 0) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } return 0; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->yc_pos + pItem->yc_start_address), FALSE); short value; uid = pItem->GetUnitID(); for (i = 0; i < count; i++) { value = (short)GetUnitYC(uid, pItem->yc_pos + i); buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; } pItem->yc_pos += count; if (pItem->yc_pos < 0 || pItem->yc_pos >= pItem->total_yc) { pItem->yc_pos = 0; if (IEC_101_104_COT_INTERROGATION == cause_of_transimission && pItem->interrogation_start) { pItem->interrogation_yc_fin = TRUE; //遥测发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_Integrated_totals(CIEC101ProcessItem* pItem, BYTE cause_of_transimission) { int uid, len; int i, count; DWORD value; BYTE buffer[256]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), M_IT_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); uid = pItem->GetUnitID(); if (IEC_101_104_COT_SPONT == cause_of_transimission) { //遥脉变位 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA) / (parameters->sizeOfIOA + 5)); count = ((pItem->total_ym - pItem->ym_pos) > count) ? count : (pItem->total_ym - pItem->ym_pos); if (count <= 0) return FALSE; ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, FALSE); for (i = 0; i < count; i++) { len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ym_pos + pItem->ym_start_address + i), FALSE); value = GetUnitYM(uid, pItem->ym_pos + i); buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; buffer[len++] = (value >> 16) & 0xff; buffer[len++] = (value >> 24) & 0xff; buffer[len++] = (pItem->ym_pos + i ) % 32; } pItem->ym_pos += count; if (pItem->ym_pos < 0 || pItem->ym_pos >= pItem->total_ym) { pItem->ym_pos = 0; if ((IEC_101_104_COT_REQCOGEN == cause_of_transimission || IEC_101_104_COT_INTERROGATION == cause_of_transimission) && pItem->pulse_start) { pItem->pulse_fin = TRUE; //遥脉发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } else { //召唤 count = ((parameters->maxSizeOfASDU - parameters->sizeOfCOT - parameters->sizeOfCA - parameters->sizeOfIOA) / + 5); count = ((pItem->total_ym - pItem->ym_pos) > count) ? count : (pItem->total_ym - pItem->ym_pos); if (count <= 0) { pItem->ym_pos = 0; if ((IEC_101_104_COT_REQCOGEN == cause_of_transimission || IEC_101_104_COT_INTERROGATION == cause_of_transimission) && pItem->pulse_start) { pItem->pulse_fin = TRUE; //遥脉发送完毕 } return 0; } ASDU_setNumberOfElements(buffer, count); ASDU_setSequence(buffer, TRUE); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], (pItem->ym_pos + pItem->ym_start_address), FALSE); for (i = 0; i < count; i++) { value = GetUnitYM(uid, pItem->ym_pos + i); buffer[len++] = value & 0xff; buffer[len++] = (value >> 8) & 0xff; buffer[len++] = (value >> 16) & 0xff; buffer[len++] = (value >> 24) & 0xff; buffer[len++] = (pItem->ym_pos + i ) % 32; } pItem->ym_pos += count; if (pItem->ym_pos < 0 || pItem->ym_pos >= pItem->total_ym) { pItem->ym_pos = 0; if ((IEC_101_104_COT_REQCOGEN == cause_of_transimission || IEC_101_104_COT_INTERROGATION == cause_of_transimission) && pItem->pulse_start) { pItem->pulse_fin = TRUE; //遥脉发送完毕 } } Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } return FALSE; } BOOLEAN CIEC101SecondaryProcess::Send_FrameInterrogation(CIEC101ProcessItem* pItem, BYTE cause_of_transimission) { int len; BYTE buffer[256]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), C_IC_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(buffer); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], 0, FALSE); buffer[len++] = pItem->call_type; Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Send_FrameCounterInterrogation(CIEC101ProcessItem* pItem, BYTE cause_of_transimission) { int len; BYTE buffer[256]; memset(buffer, 0, sizeof(buffer)); pIEC101_AppLayerParameters parameters = &(pItem->applicationlParameters); len = ASDU_initialize(buffer, &(pItem->applicationlParameters), C_CI_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(buffer); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &buffer[len], 0, FALSE); buffer[len++] = pItem->call_type; Slave_enqueueUserDataClass1(pItem, buffer, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Send_Test_command(CIEC101ProcessItem* pItem, BYTE cause_of_transimission) { BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_TS_NA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); asdu[len++] = 0xAA; asdu[len++] = 0x55; Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; } BOOLEAN CIEC101SecondaryProcess::Send_Test_command_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission) { BYTE asdu[260]; int len = ASDU_initialize(asdu, &(pItem->applicationlParameters), C_TS_TA_1, FALSE, cause_of_transimission, pItem->applicationlParameters.originatorAddress, pItem->common_address, FALSE, FALSE); ASDU_addNumberOfElements(asdu); len += InformationObject_setObjectAddress(&(pItem->applicationlParameters), &asdu[len], 0, FALSE); asdu[len++] = 0xAA; asdu[len++] = 0x55; len += unionCP56TimeToBuf(&asdu[len], system32.now); Slave_enqueueUserDataClass1(pItem, asdu, len); return TRUE; }