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