440 lines
15 KiB
C++
440 lines
15 KiB
C++
![]() |
#include "host_iec104.h"
|
|||
|
|
|||
|
CHostIEC104Process::CHostIEC104Process()
|
|||
|
{
|
|||
|
last_sec = system32.timers;
|
|||
|
}
|
|||
|
|
|||
|
CHostIEC104Process::~CHostIEC104Process()
|
|||
|
{
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::OnPreCreate(int id)
|
|||
|
{
|
|||
|
if (!CIEC104Process::OnPreCreate(id)) return FALSE;
|
|||
|
|
|||
|
int i;
|
|||
|
CIEC104ProcessItem *pItem;
|
|||
|
//更新配置
|
|||
|
for (i = 0; i < PROCESS_UNIT_NUM; i++)
|
|||
|
{
|
|||
|
pItem = (CIEC104ProcessItem *)GetItem(i);
|
|||
|
if (NULL == pItem) continue;
|
|||
|
pItem->apdu_k_max = m_nOption.k;
|
|||
|
pItem->apdu_w_max = m_nOption.w;
|
|||
|
pItem->apdu_t0_begin = 10;//system32.timers;
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::OnCreated(int id)
|
|||
|
{
|
|||
|
return CIEC104Process::OnCreated(id);
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::Run(void)
|
|||
|
{
|
|||
|
if (!CIEC104Process::Run())
|
|||
|
{
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
FeedDog();
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::OnTimer(void)
|
|||
|
{
|
|||
|
int uid;
|
|||
|
int i;
|
|||
|
CIEC104ProcessItem *pItem;
|
|||
|
BOOLEAN sec_changed = FALSE;
|
|||
|
if (!CIEC104Process::OnTimer()) return FALSE;
|
|||
|
if (last_sec != (time_t)system32.timers)
|
|||
|
{
|
|||
|
last_sec = system32.timers;
|
|||
|
sec_changed = TRUE;
|
|||
|
}
|
|||
|
for (i = 0; i < PROCESS_UNIT_NUM; i++)
|
|||
|
{
|
|||
|
pItem = (CIEC104ProcessItem *)GetItem(i);
|
|||
|
if (NULL == pItem) continue;
|
|||
|
uid = pItem->GetUnitID();
|
|||
|
if (uid < 0 || uid >= UNIT_NUM) continue;
|
|||
|
int sock = pItem->GetSock();
|
|||
|
if (sock < 0)
|
|||
|
{ //服务器等待客户端链接
|
|||
|
if (!IsClient()) continue;
|
|||
|
//需要连接server
|
|||
|
if (pItem->apdu_t0_begin > 0 && system32.timers > (pItem->apdu_t0_begin + apdu_t0_max))
|
|||
|
{
|
|||
|
pItem->apdu_t0_begin = system32.timers;
|
|||
|
if (Connect(pItem, i))
|
|||
|
{
|
|||
|
if (!SendUFrame(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
usleep(20000);
|
|||
|
continue;
|
|||
|
}
|
|||
|
pItem->apdu_t0_begin = system32.timers;
|
|||
|
//TCP连接就表示该单元通讯正常
|
|||
|
UnitFeedDog(uid);
|
|||
|
if (pItem->apdu_t3_begin > 0 && system32.timers > (pItem->apdu_t3_begin + apdu_t3_max))
|
|||
|
{
|
|||
|
//vLog(LOG_DEBUG, "Unit(%d) t3 expired.\n", uid);
|
|||
|
if (!SendUFrame(FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
pItem->apdu_t3_begin = 0;
|
|||
|
//启动t1计时
|
|||
|
pItem->apdu_t1_begin = system32.timers;
|
|||
|
pItem->apdu_wait_test = TRUE;
|
|||
|
continue;
|
|||
|
}
|
|||
|
//判断t1超时
|
|||
|
if (pItem->apdu_t1_begin > 0 && system32.timers > (pItem->apdu_t1_begin + apdu_t1_max))
|
|||
|
{ //直接复位链路
|
|||
|
vLog(LOG_ERROR, "Unit(%d) t1 expired (begin at %lu).\n", uid, pItem->apdu_t1_begin);
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
//判断t2超时
|
|||
|
if (pItem->apdu_t2_begin > 0 && system32.timers > (pItem->apdu_t2_begin + apdu_t2_max))
|
|||
|
{ //发送S帧
|
|||
|
//vLog(LOG_DEBUG, "Unit(%d) t2 expired.\n", uid);
|
|||
|
if (!SendSFrame(i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
//如果链路通信未启动则不发送任何报文
|
|||
|
if (!pItem->apdu_setup)
|
|||
|
{
|
|||
|
//vLog(LOG_DEBUG, "apdu is not setup. \n ");
|
|||
|
if (IsClient() && !pItem->apdu_setup_sent)
|
|||
|
{
|
|||
|
pItem->apdu_setup_sent = TRUE;
|
|||
|
vLog(LOG_DEBUG, "sent start dt command.\r\n");
|
|||
|
if (!SendUFrame(TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
continue;
|
|||
|
}
|
|||
|
//是否已经达到k值,若k值已经达到则不再发送数据报文
|
|||
|
if (pItem->apdu_k >= pItem->apdu_k_max) continue;
|
|||
|
//遥控报文
|
|||
|
if (GetYKFrame(pItem, i)) continue;
|
|||
|
//遥调报文
|
|||
|
if (GetYTFrame(pItem, i)) continue;
|
|||
|
//时钟同步
|
|||
|
if (GetSetTimeGap() > 0)
|
|||
|
{ //需要对时
|
|||
|
if (!pItem->clock_synchronized_start && !pItem->clock_synchronized_finish)
|
|||
|
{
|
|||
|
pItem->clock_synchronized_start = TRUE;
|
|||
|
if (!SendClock_synchronisation_command(pItem, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
if (!pItem->clock_synchronized_finish) continue;
|
|||
|
}
|
|||
|
//是否需要总召唤
|
|||
|
if (!pItem->interrogation_start)
|
|||
|
{
|
|||
|
pItem->interrogation_start = TRUE;
|
|||
|
//发送总召唤报文
|
|||
|
if (!SendInterrogation_command(pItem, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
//总召唤没有结束
|
|||
|
if (!pItem->interrogation_finish) continue;
|
|||
|
if (sec_changed)
|
|||
|
{
|
|||
|
if (pItem->total_ym > 0)
|
|||
|
{
|
|||
|
if (apdu_t5_max > 0 && system32.timers > (pItem->apdu_t5_begin + apdu_t5_max)) //请求电度
|
|||
|
{
|
|||
|
pItem->apdu_t5_begin = system32.timers;
|
|||
|
if (!SendCounter_Interrogation_command(pItem, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (use_cycle_interrogation_command)
|
|||
|
{
|
|||
|
if (apdu_t4_max > 0 && system32.timers > (pItem->apdu_t4_begin + apdu_t4_max)) //请求总召唤
|
|||
|
{
|
|||
|
pItem->apdu_t4_begin = system32.timers;
|
|||
|
if (!SendInterrogation_command(pItem, i))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
continue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::OnIFrameReceived(WORD ns, WORD nr, BYTE* pBuf, int count, int ord)
|
|||
|
{
|
|||
|
int uid;
|
|||
|
BYTE* pData = pBuf;
|
|||
|
CIEC104ProcessItem* pItem = (CIEC104ProcessItem *)GetItem(ord);
|
|||
|
if (NULL == pItem) return FALSE;
|
|||
|
uid = (int)pItem->GetUnitID();
|
|||
|
if (uid < 0 || uid >= UNIT_NUM) return FALSE;
|
|||
|
|
|||
|
vLog(LOG_DEBUG, "Unit(%d) On I Frame (%s %s) Received ns = %d, nr = %d\n", uid, val_to_str(pBuf[0], iec_101_104_asdu_types, "UnknowType=%02x"), val_to_str(pBuf[0], iec_101_104_asdu_lngtypes, "UnknowType=%02x"), (int)ns, (int)nr);
|
|||
|
|
|||
|
//处理接收序号
|
|||
|
if (!OnDealWithPeerNS(pItem, ns)) return FALSE;
|
|||
|
//处理发送序号
|
|||
|
if (!OnDealWithPeerNR(pItem, nr)) return FALSE;
|
|||
|
|
|||
|
BYTE num, vsq, type;
|
|||
|
BOOLEAN sq, pn, test;
|
|||
|
WORD cot = 0;
|
|||
|
WORD asdu_address = 0;
|
|||
|
type = *pData; pData++;
|
|||
|
vsq = *pData; pData++;
|
|||
|
if (1 == m_nOption.cot_size)
|
|||
|
{
|
|||
|
cot = *pData; pData++;
|
|||
|
}
|
|||
|
else if (2 == m_nOption.cot_size)
|
|||
|
{
|
|||
|
cot = *pData; pData++;
|
|||
|
cot |= (*pData << 8); pData++;
|
|||
|
}
|
|||
|
if (1 == m_nOption.asdu_addr_size)
|
|||
|
{
|
|||
|
asdu_address = *pData; pData++;
|
|||
|
}
|
|||
|
if (2 == m_nOption.asdu_addr_size)
|
|||
|
{
|
|||
|
asdu_address = *pData; pData++;
|
|||
|
asdu_address |= (*pData << 8); pData++;
|
|||
|
}
|
|||
|
num = (vsq & 0x7f);
|
|||
|
sq = (vsq & 0x80) == 0x80 ? TRUE : FALSE;
|
|||
|
pn = (cot & 0x40) == 0x40 ? TRUE : FALSE;
|
|||
|
test = (cot & 0x80) == 0x80 ? TRUE : FALSE;
|
|||
|
|
|||
|
//判断CA地址是否正确
|
|||
|
if (asdu_address != pItem->apdu_addr)
|
|||
|
{ //返回未知的应用服务数据单元公共地址
|
|||
|
vLog(LOG_WARN, "Unit(%d) CA(%d) received type(%d).\n", uid, asdu_address, type);
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
//启动t2计时
|
|||
|
if (pItem->apdu_t2_begin == 0)
|
|||
|
{
|
|||
|
pItem->apdu_t2_begin = system32.timers;
|
|||
|
}
|
|||
|
pItem->apdu_w++;
|
|||
|
if (pItem->apdu_w >= pItem->apdu_w_max)
|
|||
|
{
|
|||
|
//vLog(LOG_DEBUG, "Unit(%d) w value reached.\n", uid);
|
|||
|
if (!SendSFrame(ord))
|
|||
|
{
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
//重置t3计时
|
|||
|
pItem->apdu_t3_begin = system32.timers;
|
|||
|
//处理接收到的报文
|
|||
|
switch (type)
|
|||
|
{
|
|||
|
case M_SP_NA_1: //单点遥信
|
|||
|
OnReceiveSingle_point_information(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_SP_TA_1: //带时标的单点遥信
|
|||
|
OnReceiveSingle_point_information_with_time_tag(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_DP_NA_1: //双点遥信
|
|||
|
OnReceiveDouble_point_information(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_DP_TA_1: //带时标的双点遥信
|
|||
|
OnReceiveDouble_point_information_with_time_tag(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_NA_1: //测量值,归一化值
|
|||
|
OnReceiveMeasured_value_normalised(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TA_1: //带时标的遥测量,归一化值
|
|||
|
OnReceiveMeasured_value_normalised_with_time_tag(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_NB_1: //测量值,标度化值
|
|||
|
OnReceiveMeasured_value_scaled(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TB_1: //带时标的遥测量,标度化值
|
|||
|
OnReceiveMeasured_value_scaled_with_time_tag(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_NC_1: //测量值,短浮点数
|
|||
|
OnReceiveMeasured_value_short_floating_point(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TC_1: //带时标的遥测量值,短浮点数
|
|||
|
OnReceiveMeasured_value_short_floating_point_with_time_tag(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_ND_1: //测量值,不带品质描述的归一化测量值
|
|||
|
OnReceiveMeasured_value_normalised_without_quality(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_SP_TB_1: //带CP56Time2a时标的单点信息
|
|||
|
OnReceiveSingle_point_information_with_time_tag_cp56time2a(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_DP_TB_1: //带CP56Time2a时标的双点信息
|
|||
|
OnReceiveDouble_point_information_with_time_tag_cp56time2a(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TD_1: //带CP56Time2a时标的遥测量值,归一化值
|
|||
|
OnReceiveMeasured_value_normalised_with_time_tag_cp56time2a(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TE_1: //带CP56Time2a时标的遥测量值,标度化值
|
|||
|
OnReceiveMeasured_value_scaled_with_time_tag_cp56time2a(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_ME_TF_1: //带CP56Time2a时标的遥测量值,短浮点数
|
|||
|
OnReceiveMeasured_value_short_floating_point_with_time_tag_cp56time2a(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_IT_NA_1: //累积量
|
|||
|
OnReceiveIntegrated_totals(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_SC_NA_1: //单点令
|
|||
|
OnReceiveSingle_command(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_DC_NA_1: //双点令
|
|||
|
OnReceiveDouble_command(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_SE_NA_1: //设定值命令,归一化值
|
|||
|
OnReceiveSet_point_command_normalized(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_SE_NB_1: //设定值命令,标度化值
|
|||
|
OnReceiveSet_point_command_scaled(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_SE_NC_1: //设定值命令,短浮点数
|
|||
|
OnReceiveSet_point_command_short_floating(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_IC_NA_1: //总召唤命令
|
|||
|
OnReceiveInterrogation_command(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_CS_NA_1: //时钟同步
|
|||
|
OnReceiveClock_synchronisation_command(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case C_CI_NA_1:
|
|||
|
OnReceiveCounter_Interrogation_command(pItem, uid, pData, sq, pn, test, num, cot);
|
|||
|
break;
|
|||
|
case M_EI_NA_1:
|
|||
|
pItem->end_of_initialisation = TRUE;
|
|||
|
break;
|
|||
|
default:
|
|||
|
vLog(LOG_WARN, "Unit(%d) Unsupported I frame type = 0x%02x\n", uid, (int)pBuf[0]);
|
|||
|
break;
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
BOOLEAN CHostIEC104Process::OnUFrameReceived(BOOLEAN STARTDT_ACT, BOOLEAN STARTDT_CON, BOOLEAN STOPDT_ACT, BOOLEAN STOPDT_CON, BOOLEAN TESTFR_ACT, BOOLEAN TESTFR_CON, int ord)
|
|||
|
{
|
|||
|
int uid;
|
|||
|
BYTE phy_addr[6];
|
|||
|
CIEC104ProcessItem* pItem = (CIEC104ProcessItem *)GetItem(ord);
|
|||
|
if (NULL == pItem) return FALSE;
|
|||
|
uid = (int)pItem->GetUnitID();
|
|||
|
if (uid < 0 || uid >= UNIT_NUM) return FALSE;
|
|||
|
vLog(LOG_DEBUG, "Unit(%d) Received U Frame%s%s%s%s%s%s\n",
|
|||
|
uid,
|
|||
|
(STARTDT_ACT ? " STARTDT active": ""),
|
|||
|
(STOPDT_ACT ? " STOPDT active": ""),
|
|||
|
(TESTFR_ACT ? " TESTFR active": ""),
|
|||
|
(STARTDT_CON ? " STARTDT confirm": ""),
|
|||
|
(STOPDT_CON ? " STOPDT confirm": ""),
|
|||
|
(TESTFR_CON ? " TESTFR confirm": ""));
|
|||
|
if (STARTDT_ACT)
|
|||
|
{
|
|||
|
vLog(LOG_ERROR, "UNSUPPORT STARTDT CONFIRM! Disconnect link!\n");
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (STARTDT_CON)
|
|||
|
{
|
|||
|
if (!GetUnitAddr(uid, (BYTE *)phy_addr, 6))
|
|||
|
{
|
|||
|
pItem->apdu_addr = 0x0001;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
pItem->apdu_addr = ((phy_addr[5] << 8) | phy_addr[4]);
|
|||
|
}
|
|||
|
vLog(LOG_DEBUG, "Unit(%d) apdu_addr(%d)\n", uid, pItem->apdu_addr);
|
|||
|
pItem->apdu_setup = TRUE;
|
|||
|
pItem->apdu_ns = 0;
|
|||
|
pItem->apdu_nr = 0;
|
|||
|
pItem->apdu_ack = 0;
|
|||
|
pItem->apdu_t3_begin = system32.timers; //启动t3计时
|
|||
|
pItem->apdu_wait_test = FALSE;
|
|||
|
pItem->apdu_k = 0;
|
|||
|
pItem->total_ym = GetUnitYMCount(uid);
|
|||
|
}
|
|||
|
if (STOPDT_ACT)
|
|||
|
{
|
|||
|
vLog(LOG_ERROR, "UNSUPPORT STOPDT CONFIRM! Disconnect link!\n");
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (STOPDT_CON)
|
|||
|
{
|
|||
|
vLog(LOG_WARN, "UNSUPPORT STOPDT COMMAND! Disconnect link!\n");
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
if (TESTFR_ACT)
|
|||
|
{
|
|||
|
if (!SendUFrame(FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ord))
|
|||
|
{
|
|||
|
vLog(LOG_ERROR, "Send U Frame Error.\n");
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
pItem->apdu_t1_begin = 0;
|
|||
|
pItem->apdu_setup_sent = FALSE;
|
|||
|
pItem->apdu_t3_begin = system32.timers; //重置t3计时
|
|||
|
}
|
|||
|
if (TESTFR_CON)
|
|||
|
{
|
|||
|
if (pItem->apdu_wait_test)
|
|||
|
{
|
|||
|
pItem->apdu_t1_begin = 0;
|
|||
|
pItem->apdu_t3_begin = system32.timers; //重置t3计时
|
|||
|
pItem->apdu_wait_test = FALSE;
|
|||
|
pItem->apdu_setup_sent = FALSE;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vLog(LOG_ERROR, "UNSUPPORT TESTFR CONFIRM! Disconnect link!\n");
|
|||
|
pItem->Release();
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
return TRUE;
|
|||
|
}
|