#ifndef _ZJD_IEC101_PROCESS_H_ #define _ZJD_IEC101_PROCESS_H_ #include "portproc.h" #include "iec_101_104_lib.h" #include #define IEC101S_IDLE 0 #define IEC101S_SYNC 1 #define IEC101S_INFO 2 #define IEC101_STX1 0x10 #define IEC101_STX2 0x68 #define IEC101_ETX 0x16 typedef enum { IEC60870_LINK_LAYER_BALANCED = 0, IEC60870_LINK_LAYER_UNBALANCED = 1 } enumIEC101_LinkLayerMode; typedef enum { LL_STATE_IDLE, LL_STATE_ERROR, LL_STATE_BUSY, LL_STATE_AVAILABLE } enumIEC101_LinkLayerState; typedef enum { PLL_IDLE, PLL_EXECUTE_REQUEST_STATUS_OF_LINK, PLL_EXECUTE_RESET_REMOTE_LINK, PLL_LINK_LAYERS_AVAILABLE, PLL_EXECUTE_SERVICE_SEND_CONFIRM, PLL_EXECUTE_SERVICE_REQUEST_RESPOND, PLL_SECONDARY_LINK_LAYER_BUSY /* Only required in balanced link layer */ } enumIEC101_PrimaryLinkLayerState; typedef struct { int addressLength; /* 0/1/2 bytes */ int timeoutForACK; /* timeout for ACKs in ms */ int timeoutRepeat; /* timeout for repeating messages when no ACK received in ms */ BOOLEAN useSingleCharACK; /* use single char ACK for ACK (FC=0) or RESP_NO_USER_DATA (FC=9) */ } struIEC101_LinkLayerParameters; typedef struct { BOOLEAN dir; /* DIR bit to be used when messages are sent in balanced mode */ BYTE mode; struIEC101_LinkLayerParameters linkLayerParameters; } struIEC101_LinkLayer; typedef struIEC101_LinkLayer* pIEC101_LinkLayer; typedef struct { int sizeOfTypeId; /* size of the type id (default = 1 - don't change) */ int sizeOfVSQ; /* don't change */ int sizeOfCOT; /* size of COT (1/2 - default = 2 -> COT includes OA) */ int originatorAddress; /* originator address (OA) to use (0-255) */ int sizeOfCA; /* size of common address (CA) of ASDU (1/2 - default = 2) */ int sizeOfIOA; /* size of information object address (IOA) (1/2/3 - default = 3) */ int maxSizeOfASDU; /* maximum size of the ASDU that is generated - the maximum maximum value is 249 for IEC 104 and 254 for IEC 101 */ } struIEC101_AppLayerParameters; typedef struIEC101_AppLayerParameters* pIEC101_AppLayerParameters; typedef struct { enumIEC101_LinkLayerState state; /* user visible state */ enumIEC101_PrimaryLinkLayerState primaryState; /* internal PLL state machine state */ BOOLEAN hasMessageToSend; /* indicates if an app layer message is ready to be sent */ BYTE buffer[256]; int bufferLength; int address; QWORD lastSendTime; QWORD originalSendTime; BOOLEAN requestClass1Data; BOOLEAN requestClass2Data; BOOLEAN dontSendMessages; BOOLEAN waitingForResponse; BOOLEAN sendLinkLayerTestFunction; BOOLEAN nextFcb; } struIEC101_LinkLayerSlaveConnection; typedef struct { struIEC101_LinkLayerSlaveConnection slaveConnection; } struIEC101_LinkLayerPrimaryUnbalanced; typedef struct { enumIEC101_LinkLayerState state; /* state information for user */ enumIEC101_PrimaryLinkLayerState primaryState; /* internal PLL state machine state */ BYTE buffer[256]; int bufferLength; BOOLEAN waitingForResponse; BOOLEAN sendLinkLayerTestFunction; BOOLEAN nextFcb; QWORD lastSendTime; QWORD originalSendTime; QWORD lastReceivedMsg; int otherStationAddress; int idleTimeout; /* connection timeout in ms */ } struIEC101_LinkLayerPrimaryBalanced; typedef struIEC101_LinkLayerPrimaryBalanced* pIEC101_LinkLayerPrimaryBalanced; typedef struct { BOOLEAN expectedFcb; /* expected value of next frame count bit (FCB) */ } struIEC101_LinkLayerSecondaryBalanced; typedef struIEC101_LinkLayerSecondaryBalanced* pIEC101_LinkLayerSecondaryBalanced; typedef struct { //enumIEC101_LinkLayerState state; BOOLEAN expectedFcb; /* expected value of next frame count bit (FCB) */ struIEC101_LinkLayerParameters linkLayerParameters; //QWORD lastReceivedMsg; //int idleTimeout; /* connection timeout in ms */ } struIEC101_LinkLayerSecondaryUnbalanced; typedef struIEC101_LinkLayerSecondaryUnbalanced* pIEC101_LinkLayerSecondaryUnbalanced; typedef struct { short size; BYTE buffer[256]; } struIEC101_QueueElement; typedef struIEC101_QueueElement* pIEC101_QueueElement; class CIEC101_Queue { public: CIEC101_Queue() { initialize(-1); } CIEC101_Queue(int maxQueueSize) { initialize(maxQueueSize); } virtual ~CIEC101_Queue() { dispose(); }; private: int m_size; int m_entryCounter; int m_lastMsgIndex; int m_firstMsgIndex; pIEC101_QueueElement m_elements; sem_t m_queueLock; public: inline void initialize(int maxQueueSize) { m_entryCounter = 0; m_firstMsgIndex = 0; m_lastMsgIndex = 0; m_size = maxQueueSize; int queueSize = maxQueueSize; if (maxQueueSize == -1) queueSize = DATABASE_YXBW_NUM; m_elements = new struIEC101_QueueElement[queueSize]; m_size = queueSize; sem_init(&m_queueLock, 0, 1); } inline void dispose(void) { sem_destroy(&m_queueLock); delete [] m_elements; } inline void lock(void) { sem_wait(&m_queueLock); } inline void unlock(void) { sem_post(&m_queueLock); } inline void enqueue(BYTE* buffer, int msgSize) { lock(); int nextIndex; BOOLEAN removeEntry = FALSE; if (m_entryCounter == 0) { m_firstMsgIndex = 0; nextIndex = 0; } else { nextIndex = m_lastMsgIndex + 1; } if (nextIndex == m_size) nextIndex = 0; if (m_entryCounter == m_size) removeEntry = TRUE; if (removeEntry == FALSE) { m_lastMsgIndex = nextIndex; m_entryCounter++; } else { m_lastMsgIndex = nextIndex; int firstIndex = nextIndex + 1; if (firstIndex == m_size) firstIndex = 0; m_firstMsgIndex = firstIndex; } memcpy(m_elements[nextIndex].buffer, buffer, msgSize); m_elements[nextIndex].size = msgSize; unlock(); } inline pIEC101_QueueElement dequeue(void) { if (m_entryCounter != 0) { int currentIndex = m_firstMsgIndex; m_firstMsgIndex = (currentIndex + 1) % m_size; m_entryCounter--; return &m_elements[currentIndex]; } return NULL; } inline BOOLEAN isFull(void) { return (m_entryCounter == m_size); } inline BOOLEAN isEmpty(void) { return (m_entryCounter == 0); } void flush(void) { lock(); m_entryCounter = 0; m_firstMsgIndex = 0; m_lastMsgIndex = 0; unlock(); } }; class CIEC101ProcessItem : public CPortProcessItem { public: struIEC101_LinkLayerPrimaryUnbalanced primaryLinkUnbalanced; struIEC101_LinkLayerPrimaryBalanced primaryLinkBalanced; struIEC101_LinkLayerSecondaryBalanced secondaryLinkBalanced; struIEC101_LinkLayerSecondaryUnbalanced secondaryLinkUnbalanced; struIEC101_AppLayerParameters applicationlParameters; int address; //own address int common_address; //平衡模式下主协议的数据列表 CIEC101_Queue userDataQueue; //从协议下的数据列表 CIEC101_Queue userDataClass1Queue; CIEC101_Queue userDataClass2Queue; public: BOOLEAN end_of_initialisation; BOOLEAN clock_synchronized_start; BOOLEAN clock_synchronized_finish; BOOLEAN interrogation_start; BOOLEAN interrogation_yx_fin; BOOLEAN interrogation_yc_fin; BOOLEAN interrogation_finish; BOOLEAN pulse_start; BOOLEAN pulse_fin; DWORD apdu_t4_begin; DWORD apdu_t5_begin; DWORD background_scan_begin; int total_yx; int total_yc; int total_ym; int total_yk; int yx_pos; int yc_pos; int ym_pos; int call_type; BYTE yk_value; YCBWBuffer ycbws; YXBWBuffer yxbws; EventBuffer events; int yx_start_address; int yc_start_address; int ym_start_address; public: CIEC101ProcessItem(); virtual ~CIEC101ProcessItem(); public: void Attach(int uid, int phy_addr = 0, int common_addr = 0, int originatorAddress = 0); void Release(void); inline void setAppLayerParameters(int sizeOfCOT = 1, int sizeOfCA = 1, int sizeOfIOA = 2, int maxSizeOfASDU = 254) { applicationlParameters.sizeOfTypeId = 1; applicationlParameters.sizeOfVSQ = 1; applicationlParameters.sizeOfCOT = sizeOfCOT; applicationlParameters.sizeOfCA = sizeOfCA; applicationlParameters.sizeOfIOA = sizeOfIOA; applicationlParameters.maxSizeOfASDU = maxSizeOfASDU; } inline void setAppLayerIOABase(int yx = 0, int yc = 0, int ym = 0) { 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; if (yx > 0) yx_start_address = yx; if (yc > 0) yc_start_address = yc; if (ym > 0) ym_start_address = ym; } }; class CIEC101Process : public CPortProcess { public: enum { llSecUnbalanced, llSecBalanced, llPriBalanced, llPriUnbalanced, }; public: int m_nNeedCount; int m_nState; DWORD m_nCount; DWORD m_nSendPoint; DWORD m_nCurFrame; short m_nTimeout; struIEC101Option m_option; struIEC101_LinkLayer m_linkLayer; time_t last_sec; public: int apdu_t4_max; int apdu_t5_max; BOOLEAN use_cycle_interrogation_command; public: CIEC101Process(); virtual ~CIEC101Process(); CPortProcessItem *CreateItem(int ord); void DestroyItem(int ord, BOOLEAN bDeleted = FALSE); BOOLEAN OnPreCreate(int id); virtual BOOLEAN Run(void); virtual BOOLEAN OnTimer(void); void GetItemYXBWs(CIEC101ProcessItem* pItem); void GetItemEvents(CIEC101ProcessItem* pItem); void GetItemYCBWs(CIEC101ProcessItem* pItem); virtual int OnPackageReceived(BYTE* pBuf, int count, int ord = -1); private: virtual void LinkLayerSecondaryBalanced_ReceivedMessage(BYTE fc, BOOLEAN isBroadcast, BOOLEAN fcb, BOOLEAN fcv, int address, BYTE* msg, int userDataStart, int userDataLength) {}; virtual void LinkLayerSecondaryUnbalanced_ReceivedMessage(BYTE fc, BOOLEAN isBroadcast, BOOLEAN fcb, BOOLEAN fcv, int address, BYTE* msg, int userDataStart, int userDataLength) {}; virtual void LinkLayerPrimaryBalanced_ReceivedMessage(BYTE fc, BOOLEAN dir, BOOLEAN dfc, int address, BYTE* msg, int userDataStart, int userDataLength); virtual void LinkLayerPrimaryBalanced_resetIdleTimeout() {}; virtual void LinkLayerPrimaryUnbalanced_ReceivedMessage(BYTE fc, BOOLEAN acd, BOOLEAN dfc, int address, BYTE* msg, int userDataStart, int userDataLength) {}; inline void SendMessage(const BYTE* msg, int msgSize) { DisplayTxData((BYTE *)msg, msgSize, TRUE); WriteData(msg, msgSize); m_nSendPoint = system32.ticks; } public: inline int LinkLayer_getBroadcastAddress(void) { if (m_linkLayer.linkLayerParameters.addressLength == 1) { return 255; } else if (m_linkLayer.linkLayerParameters.addressLength == 2) { return 65535; } return 0; } inline int ASDU_initialize(BYTE* pBuf, pIEC101_AppLayerParameters parameters, BYTE typeId, BOOLEAN isSequence, BYTE cot, int oa, int ca, BOOLEAN isTest = FALSE, BOOLEAN isNegative = FALSE) { BYTE* encodedData = pBuf; encodedData[0] = (BYTE)typeId; if (isSequence) encodedData[1] = 0x80; else encodedData[1] = 0; encodedData[2] = (BYTE)(cot & 0x3f); if (isTest) encodedData[2] |= 0x80; if (isNegative) encodedData[2] |= 0x40; int caIndex; if (parameters->sizeOfCOT > 1) { encodedData[3] = (BYTE)oa; caIndex = 4; } else caIndex = 3; encodedData[caIndex] = ca % 0x100; if (parameters->sizeOfCA > 1) encodedData[caIndex + 1] = ca / 0x100; return (caIndex + parameters->sizeOfCA); } inline int InformationObject_setObjectAddress(pIEC101_AppLayerParameters parameters, BYTE* buffer, int ioa, BOOLEAN isSequence) { if (!isSequence) { buffer[0] = (BYTE)(ioa & 0xff); if (parameters->sizeOfIOA > 1) { buffer[1] = (BYTE)((ioa / 0x100) & 0xff); } if (parameters->sizeOfIOA > 2) { buffer[2] = (BYTE)((ioa / 0x10000) & 0xff); } return parameters->sizeOfIOA; } return 0; } inline TypeID ASDU_getTypeID(BYTE* asdu) { return (TypeID)(asdu[0]); } inline void ASDU_setTypeID(BYTE* asdu, TypeID typeId) { asdu[0] = (BYTE)typeId; } inline BOOLEAN ASDU_isTest(BYTE* asdu) { if ((asdu[2] & 0x80) == 0x80) return TRUE; return FALSE; } inline void ASDU_setTest(BYTE*asdu, BOOLEAN value) { if (value) asdu[2] |= 0x80; asdu[2] &= ~(0x80); } inline BOOLEAN ASDU_isNegative(BYTE* asdu) { if ((asdu[2] & 0x40) == 0x40) return TRUE; return FALSE; } inline void ASDU_setNegative(BYTE* asdu, BOOLEAN value) { if (value) asdu[2] |= 0x40; else asdu[2] &= ~(0x40); } inline int ASDU_getOA(pIEC101_AppLayerParameters parameters, BYTE* asdu) { if (parameters->sizeOfCOT < 2) return -1; return (int)asdu[3]; } inline BYTE ASDU_getCOT(BYTE* asdu) { return (BYTE)(asdu[2] & 0x3f); } inline void ASDU_setCOT(BYTE* asdu, BYTE value) { BYTE cot = asdu[2] & 0xc0; cot += ((int)value) & 0x3f; asdu[2] = cot; } inline int ASDU_getCA(pIEC101_AppLayerParameters parameters, BYTE* asdu) { int caIndex = 2 + parameters->sizeOfCOT; int ca = asdu[caIndex]; if (parameters->sizeOfCA > 1) ca += (asdu[caIndex + 1] * 0x100); return ca; } inline void ASDU_setCA(pIEC101_AppLayerParameters parameters, BYTE* asdu, int ca) { int caIndex = 2 + parameters->sizeOfCOT; int setCa = ca; /* Check if CA is in range and adjust if not */ if (ca < 0) setCa = 0; else { if (parameters->sizeOfCA == 1) { if (ca > 255) setCa = 255; } else if (parameters->sizeOfCA > 1) { if (ca > 65535) setCa = 65535; } } if (parameters->sizeOfCA == 1) { asdu[caIndex] = (BYTE)setCa; } else { asdu[caIndex] = (BYTE) (setCa % 0x100); asdu[caIndex + 1] = (BYTE) (setCa / 0x100); } } inline int ASDU_getNumberOfElements(BYTE* asdu) { return (asdu[1] & 0x7f); } inline void ASDU_setNumberOfElements(BYTE* asdu, int value) { asdu[1] += value; } inline void ASDU_addNumberOfElements(BYTE* asdu) { asdu[1] ++; } inline BOOLEAN ASDU_isSequence(BYTE* asdu) { if ((asdu[1] & 0x80) != 0) return TRUE; else return FALSE; } inline void ASDU_setSequence(BYTE* asdu, BOOLEAN isSequence) { if (isSequence) asdu[1] |= 0x80; else asdu[1] &= 0x7f; } inline int ASDU_getIOA(pIEC101_AppLayerParameters parameters, BYTE* asdu) { int ioa = asdu[0]; if (parameters->sizeOfIOA > 1) ioa += (asdu[1] * 0x100); if (parameters->sizeOfIOA > 2) ioa += (asdu[2] * 0x10000); return ioa; } void SendSingleCharCharacter(void); void SendFixedFrame(BYTE fc, int address, BOOLEAN prm, BOOLEAN dir, BOOLEAN acd /*FCB*/, BOOLEAN dfc /*FCV*/); void SendVariableLengthFrame(BYTE fc, int address, BOOLEAN prm, BOOLEAN dir, BOOLEAN acd, BOOLEAN dfc, BYTE* userData, int userDataLength); public: inline BOOLEAN IsClass1DataAvailable(CIEC101ProcessItem* pItem) { return (pItem->userDataClass1Queue.isEmpty() == FALSE); } inline pIEC101_QueueElement GetClass1Data(CIEC101ProcessItem* pItem) { pIEC101_QueueElement element = NULL; pItem->userDataClass1Queue.lock(); element = pItem->userDataClass1Queue.dequeue(); pItem->userDataClass1Queue.unlock(); return element; } inline BOOLEAN IsClass2DataAvailable(CIEC101ProcessItem* pItem) { return (pItem->userDataClass2Queue.isEmpty() == FALSE); } inline pIEC101_QueueElement GetClass2Data(CIEC101ProcessItem* pItem) { pIEC101_QueueElement element; pItem->userDataClass2Queue.lock(); element = pItem->userDataClass2Queue.dequeue(); pItem->userDataClass2Queue.unlock(); return element; } inline virtual pIEC101_QueueElement ApplicationLayer_GetUserData(CIEC101ProcessItem* pItem) { if (m_linkLayer.mode == llPriBalanced) { pIEC101_QueueElement element; pItem->userDataQueue.lock(); element = pItem->userDataQueue.dequeue(); pItem->userDataQueue.unlock(); return element; } else { if (IsClass1DataAvailable(pItem)) return GetClass1Data(pItem); else if (IsClass2DataAvailable(pItem)) return GetClass2Data(pItem); } return NULL; } inline void llpb_setNewState(pIEC101_LinkLayerPrimaryBalanced pItem, enumIEC101_LinkLayerState newState) { if (newState != pItem->state) { pItem->state = newState; } } void LinkLayerPrimaryBalanced_runStateMachine(CIEC101ProcessItem *pItem); }; class CIEC101PrimaryProcess : public CIEC101Process { public: CIEC101PrimaryProcess() {}; virtual ~CIEC101PrimaryProcess() {}; private: virtual void LinkLayerPrimaryBalanced_resetIdleTimeout() {}; virtual void LinkLayerPrimaryUnbalanced_ReceivedMessage(BYTE fc, BOOLEAN acd, BOOLEAN dfc, int address, BYTE* msg, int userDataStart, int userDataLength) {}; public: virtual BOOLEAN Master_isChannelReady(int address) { return FALSE; }; virtual void Master_sendLinkLayerTestFunction(void) {}; inline void Master_sendInterrogationCommand(CIEC101ProcessItem* pItem, BYTE cot, QualifierOfInterrogation qoi) { 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; Master_sendASDU(pItem, asdu, len); } inline void Master_sendCounterInterrogationCommand(CIEC101ProcessItem* pItem, BYTE cot, QualifierOfCIC qcc) { 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; Master_sendASDU(pItem, asdu, len); } inline void Master_sendClockSyncCommand(CIEC101ProcessItem* pItem) { 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], system32.now); Master_sendASDU(pItem, asdu, len); } #if 0 void Master_sendReadCommand(CIEC101ProcessItem* pItem, int ca, int ioa) { struStaticASDU _asdu; ASDU asdu = ASDU_initializeStatic(&_asdu, &(self->alParameters), FALSE, IEC_101_104_COT_REQ, self->alParameters.originatorAddress, ca, FALSE, FALSE); struct sReadCommand _io; InformationObject io = (InformationObject) ReadCommand_create(&_io, ioa); ASDU_addInformationObject(asdu, io); Master_sendASDU(pItem, asdu, len); } void Master_sendTestCommand(CIEC101ProcessItem* pItem, int ca) { BYTE asdu[260]; int len = ASDU_initialize(&asdu, &(pItem->applicationlParameters), FALSE, IEC_101_104_COT_ACT, pItem->applicationlParameters.originatorAddress, ca, FALSE, FALSE); struct sTestCommand _io; InformationObject io = (InformationObject) TestCommand_create(&_io); ASDU_addInformationObject(asdu, io); Master_sendASDU(pItem, asdu, len); } void Master_sendProcessCommand(CIEC101ProcessItem* pItem, BYTE cot, int ca, InformationObject command) { BYTE asdu[260]; int len = ASDU_initialize(&asdu, &(pItem->applicationlParameters), FALSE, cot, pItem->applicationlParameters.originatorAddress, ca, FALSE, FALSE); ASDU_addInformationObject(asdu, command); Master_sendASDU(pItem, asdu, len); } #endif inline BOOLEAN isBroadcastAddress(CIEC101ProcessItem* pItem, int address) { if (m_linkLayer.linkLayerParameters.addressLength == 1) { return (address == 255); } else if (m_linkLayer.linkLayerParameters.addressLength == 2) { return (address == 65535); } return FALSE; } virtual void Master_sendASDU(CIEC101ProcessItem*, BYTE*, int) {}; BOOLEAN OnReceiveSingle_point_information(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSingle_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSingle_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveDouble_point_information(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveDouble_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveDouble_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_normalised(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_scaled(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_short_floating_point(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_normalised_without_quality(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_normalised_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_scaled_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_short_floating_point_with_time_tag(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_normalised_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_scaled_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveMeasured_value_short_floating_point_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveIntegrated_totals(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveInterrogation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveClock_synchronisation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveCounter_Interrogation_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSingle_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveDouble_command(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSet_point_command_normalized(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSet_point_command_scaled(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); BOOLEAN OnReceiveSet_point_command_short_floating(CIEC101ProcessItem* pItem, BYTE* pBuf, BOOLEAN isSequence, BOOLEAN isNegative, BOOLEAN isTest, BYTE num, BYTE cot); void PrimaryApplicationLayer_UserData(CIEC101ProcessItem* pItem, int slaveAddress, BYTE* msg, int start, int length) { BYTE *asdu = msg + start; 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); BYTE *pData = asdu + parameters->sizeOfTypeId + parameters->sizeOfVSQ + parameters->sizeOfCOT + parameters->sizeOfCA; switch (tid) { case M_SP_NA_1: OnReceiveSingle_point_information(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_SP_TA_1: OnReceiveSingle_point_information_with_time_tag(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_DP_NA_1: OnReceiveDouble_point_information(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_DP_TA_1: OnReceiveDouble_point_information_with_time_tag(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_NA_1: OnReceiveMeasured_value_normalised(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TA_1: OnReceiveMeasured_value_normalised_with_time_tag(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_NB_1: OnReceiveMeasured_value_scaled(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TB_1: OnReceiveMeasured_value_scaled_with_time_tag(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_NC_1: OnReceiveMeasured_value_short_floating_point(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TC_1: OnReceiveMeasured_value_short_floating_point_with_time_tag(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_ND_1: OnReceiveMeasured_value_normalised_without_quality(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_SP_TB_1: OnReceiveSingle_point_information_with_time_tag_cp56time2a(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_DP_TB_1: OnReceiveDouble_point_information_with_time_tag_cp56time2a(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TD_1: OnReceiveMeasured_value_normalised_with_time_tag_cp56time2a(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TE_1: OnReceiveMeasured_value_scaled_with_time_tag_cp56time2a(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_ME_TF_1: OnReceiveMeasured_value_short_floating_point_with_time_tag_cp56time2a(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_IT_NA_1: OnReceiveIntegrated_totals(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_SC_NA_1: OnReceiveSingle_command(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_DC_NA_1: OnReceiveDouble_command(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_SE_NA_1: OnReceiveSet_point_command_normalized(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_SE_NB_1: OnReceiveSet_point_command_scaled(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_SE_NC_1: OnReceiveSet_point_command_short_floating(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_IC_NA_1: OnReceiveInterrogation_command(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_CS_NA_1: OnReceiveClock_synchronisation_command(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case C_CI_NA_1: OnReceiveCounter_Interrogation_command(pItem, pData, isSequence, isNegative, isTest, num, cot); break; case M_EI_NA_1: pItem->end_of_initialisation = TRUE; break; default: vLog(LOG_WARN, "Unit(%d) typedid is: %s, cot is: %d, and element number is: %d\n", pItem->GetUnitID(), val_to_str(tid, iec_101_104_asdu_types, "unknow(%d)"), cot, num); break; } } BOOLEAN GetYKFrame(CIEC101ProcessItem* pItem, int ord = -1); BOOLEAN GetYTFrame(CIEC101ProcessItem* pItem, int ord = -1); }; class CIEC101SecondaryProcess : public CIEC101Process { public: CIEC101SecondaryProcess() {}; virtual ~CIEC101SecondaryProcess() {}; public: BOOLEAN MakeYKFrame(CIEC101ProcessItem* pItem); BOOLEAN MakeYTFrame(CIEC101ProcessItem* pItem); BOOLEAN Receive_Interrogation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //总召唤 BOOLEAN Receive_Clock_synchronisation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //时钟同步 BOOLEAN Receive_Counter_interrogation_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //累积量 BOOLEAN Receive_Reset_process_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //复位进程 BOOLEAN Receive_Single_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //单点令 BOOLEAN Receive_Double_command(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //单点令 BOOLEAN Receive_Set_point_command_normalized(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //设定规一化值命令 BOOLEAN Receive_Set_point_command_scaled(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //设定标度化值命令 BOOLEAN Receive_Set_point_command_short_floating(CIEC101ProcessItem* pItem, const BYTE* pBuf, BYTE cot); //设定短浮点值命令 BOOLEAN Send_End_of_initialisation(CIEC101ProcessItem* pItem); BOOLEAN Send_Single_point_information(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Single_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Single_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Double_point_information(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Double_point_information_with_time_tag(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Double_point_information_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Measured_value_normalised(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Measured_value_scaled(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Measured_value_short_floating_point(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Measured_value_normalised_without_quality(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_Integrated_totals(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_SPONT); BOOLEAN Send_FrameInterrogation(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_ACTTREM); BOOLEAN Send_FrameCounterInterrogation(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_ACTTREM); BOOLEAN Send_Test_command(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_ACTTREM); BOOLEAN Send_Test_command_with_time_tag_cp56time2a(CIEC101ProcessItem* pItem, BYTE cause_of_transimission = IEC_101_104_COT_ACTTREM); public: BOOLEAN ApplicationLayer_ReceivedData(CIEC101ProcessItem* pItem, BYTE* msg, BOOLEAN isBroadcast, int userDataStart, int userDataLength); inline BOOLEAN Slave_isClass1QueueFull(CIEC101ProcessItem* pItem) { return pItem->userDataClass1Queue.isFull(); } inline void Slave_enqueueUserDataClass1(CIEC101ProcessItem* pItem, BYTE* asdu, int msgSize) { pItem->userDataClass1Queue.enqueue(asdu, msgSize); } inline BOOLEAN Slave_isClass2QueueFull(CIEC101ProcessItem* pItem) { return pItem->userDataClass2Queue.isFull(); } inline void Slave_enqueueUserDataClass2(CIEC101ProcessItem* pItem, BYTE* asdu, int msgSize) { pItem->userDataClass2Queue.enqueue(asdu, msgSize); } inline void Slave_flushQueues(CIEC101ProcessItem* pItem) { pItem->userDataClass1Queue.flush(); pItem->userDataClass2Queue.flush(); } private: inline BOOLEAN isSingleCommandChecked(BYTE yk_type, BYTE relay_type, BYTE value) { if (yk_type != USE_YK_SC) return FALSE; if (relay_type) { if (relay_type == 1) { //Only on if (!value) return FALSE; } else { //Only off if (value) return FALSE; } } return TRUE; } }; #endif //_ZJD_IEC101_PROCESS_H_