884 lines
36 KiB
C++
884 lines
36 KiB
C++
#ifndef _ZJD_IEC101_PROCESS_H_
|
|
#define _ZJD_IEC101_PROCESS_H_
|
|
|
|
#include "portproc.h"
|
|
#include "iec_101_104_lib.h"
|
|
#include <semaphore.h>
|
|
|
|
#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_
|