问题:
1)UDP有没有服务器和客户端一说?
2)有南网版本和非南网版本,怎么区分?
3)为什么是选择的UDP而不是TCP?
4)主从通道关系是什么?是 2份报文还是份报文?主通道A,B,和从通道A,B关系?
双机双网的关系,是否都停用的情况下就是单机单网?
代码走读:
0.UPD103装置和后台连接。
1.装置界面设置参数:
1.const_Dsp.c 菜单:
{ 1, "通信参数", "", 0, 0x0000, 0, EN_CELL_BASE, (PFUNC)Menu_NonPfunc ,DB0 ,DB0 },
{ 2, "通信设置", "外部通信设置", 0, CN_OPER_PWD_BIT, 0, EN_CELL_BASE, (PFUNC)MenuProc_Set_ComPara, DB0, DB0 },
2.执行函数:(PFUNC)MenuProc_Set_ComPara,
const char g_byCanHeadTab[]= // debug by wy 2005.06.29
{
" 通信口$ "
CN_NEWLINE "端口类型: $ 使用状态: #"
CN_NEWLINE "通信规约: #"
};
const char g_byEtherParaTab[]=
{
"双机投退: # 双网投退: #"
CN_NEWLINE "端口号 : # 主网网口: # 从网网口: #"
CN_NEWLINE "主机主网IP : # .# .# .#"
CN_NEWLINE "主机从网IP : # .# .# .#"
CN_NEWLINE "从机主网IP : # .# .# .#"
CN_NEWLINE "从机从网IP : # .# .# .# "
};
dwProtocolID = ptPortVal->ptPortSet->wProtocolID;
ptParamNet = (tagPParamNet)( ptPortVal->ptPortSet->dwParam );
2. 103通信:
//IEC 103_Function.c
2.1串口103:
int Mon_IEC103_SIO_TaskStart( BYTE byPortNo )
2.2 TCP 103?
int Mon_IEC103_TCP_TaskStart( BYTE byPortNo )
2.3 UDP 103
int Mon_IEC103_UDP_TaskStart( BYTE byPortNo )
vvvvvvvvvvvvvvvvvvvv
//Protocol.c
onst tagProtocolSet g_tProtocolPort[ ] = { // 端口通讯讯规约定义
#if( CN_INCLUDE_PORT_IEC_103 )
{ EN_PROTOCOL_PORT_SIO_IEC_103, "IEC60870-5-103规约S", CN_INCLUDE_PORT_IEC_103, (PFUNC)Mon_IEC103_SIO_TaskStart, (PFUNC)NONE_InitDummy },
{ EN_PROTOCOL_PORT_TCP_IEC_103, "IEC60870-5-103规约T", CN_INCLUDE_PORT_IEC_103, (PFUNC)Mon_IEC103_TCP_TaskStart, (PFUNC)NONE_InitDummy },
{ EN_PROTOCOL_PORT_UDP_IEC_103, "IEC60870-5-103规约U", CN_INCLUDE_PORT_IEC_103, (PFUNC)Mon_IEC103_UDP_TaskStart, (PFUNC)NONE_InitDummy },
// { EN_PROTOCOL_PORT_TCP_ZJ_103, "浙江网络103规约T", CN_INCLUDE_PORT_IEC_103, (PFUNC)Mon_IEC103ZJ_TaskStart, (PFUNC)NONE_InitDummy },
#endif
// 装置外通讯协议
#define CN_IEC61850_USE ( TRUE ) // 通讯协议选择开关:(TRUE)-IEC61850规约
#define CN_INCLUDE_PORT_IEC_103 ( TRUE ) // IEC60870-5-103规约
#define CN_INCLUDE_PORT_IEC_103NW ( TRUE ) // IEC60870-5-103规约南网103
//规约ID的获取:
// ============================================================================
// 函数功能:获取端口通讯规约指针
// 输入参数:通讯端口编号
// 输出参数:通讯规约指针
// 返回值: 是否获取成功
// ============================================================================
BOOLEAN Fun_GetProtocolPort( BYTE byPortNo, tagPProtocolSet *pptProtocolSet )
{
bRtVal = FALSE;
*pptProtocolSet = (tagPProtocolSet)(&g_tProtocolPort[0]);
if( byPortNo >=M_CN_NUM_PORT ) return bRtVal;
if( FALSE==Fun_GetPortVariable( byPortNo, &ptPortVal) ) return bRtVal;
ptPortSet = ptPortVal->ptPortSet;
for( byLoop=0; byLoop<CN_NUM_PROTOCOL_PORT; byLoop++ )
{
if( g_tProtocolPort[byLoop].wProtocolID != ptPortSet->wProtocolID ) continue;
*pptProtocolSet = (tagPProtocolSet)(&g_tProtocolPort[byLoop]);
ptPortVal->wIndexProtocol = byLoop;
bRtVal = TRUE;
break;
}
}
// 外部通讯全局变量
tagPPortSet g_ptPortSet[12]; // 本管理板通讯端口设定参数指针
//protocol.c 初始化端口控制变量
void Init_PortCtrl( BYTE byPortNo, BOOLEAN bFirst )
{
for( byLoop=0; byLoop<M_CN_NUM_PORT; byLoop++ )
{
ptPortVal->ptPortSet = g_ptPortSet[byLoop]; // 通讯端口参数变量指针
}
}
//启动UDP103
int Mon_IEC103_UDP_TaskStart( BYTE byPortNo )
{
iTaskID = taskSpawn( strTaskName, ptTaskCfg->dwPriority, VX_FP_TASK, ptTaskCfg->dwStackSize,
(FUNCPTR)Mon_IEC103_UDP_Main, byPortNo, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
taskDelay( CN_TICKS_TASK_START );
}
//任务配置:
typedef struct
{
UINT32 dwTaskID; // 任务类型
char byName[50]; // 任务名称
UINT32 dwPriority; // 任务优先级
UINT32 dwStackSize; // 任务栈区大小
} tagTaskCfg;
const tagTaskCfg g_tTaskCfg[] = {
//UDP103
{EN_TASK_ID_IEC103, "tIEC103", 106, 0x8000},
//udp103相关函数:
//====================================================
///网口(UDP)IEC103规约处理主函数(接口函数)
//====================================================
void Mon_IEC103_UDP_Main( BYTE byPortNo )
{
Mon_IEC103_Init( byPortNo ); // 初始化IEC103变量
{
//初始化干了些什么?
//1.初始化INF号!三遥的INF号及定值的INF号;
// 只要在spf表配置即上送 自动计算inf 不上送置0,通讯是只需判断inf是否为0即可
ptSpfSoeRecTab = (tagSpfRecInfo *)&g_tSpfSoeRecTab[0];
//2.网络部分的初始化;
//未设置时,默认为#define CN_MON_103_NETPORT ( 2420 ) // 103链接端口号
//装置是服务端,监听2420端口;
TcpAddServer( pbyIP, ptParamNet->wNetPort ); // 端口侦听
}
while( 1 )
{
//--udp103---e
Mon_IEC103_UdpMsgRecv( byPortNo );
Mon_IEC103_Proc( byPortNo );
Mon_IEC103_Send( byPortNo );
//--串口103--start
// Mon_IEC103_Recieve( byPortNo );
// Mon_IEC103_Proc( byPortNo );
// Mon_IEC103_Send( byPortNo );
//--串口103--end
}
}
//====================================================
// Net103网络数据接收
//====================================================
BOOLEAN Mon_IEC103_UdpMsgRecv( BYTE byPortNo )
{
wMsgLen = Udp_ReadMsg( ptNetCtrl->iGroupNo, (short *)&wConnNo,
(char *)pbyMsg103, M_CN_VOL_BUF_MSG, &( ptMonIEC103RunCtl->wUdpRead ) ); // sunzj 160926 接受报文缓冲区
switch( pbyMsg103[0] )
{
case CN_MON_IEC_LFR_START_CODE: // 长帧启动字符
//接收报文ok!
ptMsgCtrl->byMsgStatus = EN_MON_IEC_FR_RCVS_OK;
}
//报文接收
/
//报文接收主函数:拼成规约报文
/
void Mon_IEC103_Recieve( BYTE byPortNo )
{
//报文正确68.。。16验证后,
//通信地址非本装置地址,丢弃!为自己要的报文后,置位:接收OK!
ptMsgCtrl->byMsgStatus = EN_MON_IEC_FR_RCVS_OK;
//本装置地址:
5)10 40 0f 4f 16 复位通讯单元(CU)
6)10 20 0f 2f 16 装置15上电,响应复位通信单元命令,ACD置1请求查询1级数据。
1) 68 09 09 68 73 0F 07 81 09 0f ff 00 04 25 16 总控启动总查询
2) 10 20 0f 2f 16 装置15确认总查询。
if( pRevMsgBuf[5] != g_tSysSet.wCommAddr ) // 非本装置报文
{
ptMsgCtrl->byMsgStatus = EN_MON_IEC_FR_RCVS_START;
break;
}
}
//本装置地址:
void Init_DefaultSet( void )
{
#ifdef CN_EQUIP_3392
g_tSysSet.wCommAddr = g_dwTlvUsing[CN_TLV_PARA_LOC13]; //本机装置地址初始化
#else
g_tSysSet.wCommAddr =g_dwTlvUsing[CN_TLV_PARA_LOC19+CN_NUM_PORT_NET*14]; //南网统一化界面调整,装置编号和IP都放到TLV19,CN_NUM_PORT_NET*13为前面IP占用地址
#endif
}
//--装置地址就是装置编号???
//=======================================================
// 函数功能: 返回装置编号
WORD Prn_Inter_Pub_GetDevNo( )
{
从TVL参数中读取
return g_dwTlvUsing[CND_TLV_PARA_LOC19+DW_NUM_PORT_NET*14]; //南网统一化界面调整 编号移到TLV19和IP一起
}
//装置编号如何存?
&g_dwTlvUsing[CN_TLV_PARA_LOC19+CN_NUM_PORT_NET*14], // 装置地址 南网统一化界面调整 编号移到TLV19和IP一起
{ 2, "装置编号", "设置装置编号", 0, CN_OPER_PWD_BIT, 0, EN_CELL_BASE, (PFUNC)MenuProc_Set_DeviceAddr, DB0, DB0 },
//设置装置地址
void MenuProc_Cfg_DeviceAddr(BYTE byState,BYTE byScreen)
{
}
//是不是有问题??
#define DSP_TLV_ADDR (EN_TLV_PARA_13) //装置地址
//定义了宏定义:
void Init_DefaultSet( void )
{
#ifdef CN_EQUIP_3392
g_tSysSet.wCommAddr = g_dwTlvUsing[CN_TLV_PARA_LOC13]; //本机装置地址初始化
#else
g_tSysSet.wCommAddr =g_dwTlvUsing[CN_TLV_PARA_LOC19+CN_NUM_PORT_NET*14]; //南网统一化界面调整,装置编号和IP都放到TLV19,CN_NUM_PORT_NET*13为前面IP占用地址
#endif
}
//报文处理
//报文打印:
//====================================================
// Deals with the Msg process of Mon_IEC103
// TCP、udp、串口103 处理;
//====================================================
DWORD g_dbg103 = 0;
void Mon_IEC103_Proc( BYTE byPortNo )
{
//tcp 103
if( byPortNo >= CND_PORT_BASE_NET && ptPortSet->wPortType == CN_PORT_NET &&
ptPortSet->wProtocolID == EN_PROTOCOL_PORT_TCP_IEC_103 ) // sunzj 161009 暂不处理
{
iMsgLen = TcpRead( iTcpSockNo, (char *)pbyMsgIEC103 );
}
//udp 103
else if( byPortNo >= CND_PORT_BASE_NET && ptPortSet->wPortType == CN_PORT_NET &&
ptPortSet->wProtocolID == EN_PROTOCOL_PORT_UDP_IEC_103 ) // sunzj 160926
{
}
//串口103
else
{
}
//问题:小熊猫吗???
// message-watching // 报文监视组件 sunzj 161112
if( RMon_MsgDataRecv( byPortNo ) )
{
RMon_SavePortMsg( byPortNo, EN_DBG_MSG_RECV, iMsgLen, pbyMsgIEC103 );
// printf("Mon_IEC103_Proc+6:\r\n");
}
//这个存着谁用???
Dbg_SavePortMsgCom( byPortNo, EN_DBG_MSG_RECV, (WORD)(iMsgLen), pbyMsgIEC103 );
//报文保存,及解析
Mon_IEC103_ProcParse( byPortNo, pbyMsgIEC103 );
}
//=====================================================*
// Deals with the IEC103-Para from Mon
//=====================================================
void Mon_IEC103_ProcParse( BYTE byPortNo, BYTE *pbyMsgIEC103 )
{
//upd连接状态的检查;
//103报文正确性的验证:是否地址正确,
//报文解析处理:
Mon_IEC103_VolatileFrameProcess( byPortNo, pbyMsgIEC103 );
}
//=====================================================*
// Deals with the IEC103-VolatileFrame Para from Mon
//=====================================================
void Mon_IEC103_VolatileFrameProcess( BYTE byPortNo, BYTE *pbyMsgIEC103 )
{
byASDUType = pbyMsgIEC103[3];
switch( byASDUType )
{
case EN_MON_IEC103_CDIR_ASDU06: // 校时命令
Mon_IEC103_CheckTimeProcess( byPortNo, pbyMsgIEC103 );
if( CN_MON_IEC103_BROADCAST_ADD != wUnitID && EN_MON_IEC103_CDIR_LK_FUN_GD != ( byControlField & 0x0f ) )
{
ptMonIEC103RunCtl->byProcessState = EN_MON_IEC103_CHECKTIME_STATE;
Mon_IEC103_ConfirmMonWithAcd1( wUnitID, byPortNo );
}
break;
case EN_MON_IEC103_CDIR_ASDU07: // 总召唤命令
if( CN_MON_IEC103_BROADCAST_ADD == wUnitID || EN_MON_IEC103_CDIR_LK_FUN_GD == ( byControlField & 0x0f ) )
{
break;
}
ptMonIEC103RunCtl->byScanNo = pbyMsgIEC103[9];
ptMonIEC103RunCtl->byProcessState = EN_MON_IEC103_GEN_QUEST_STARTUP_STATE;
//总查询启动状态:
ptMonIEC103RunCtl->tMonRunState.GeneralQuestSta = EN_MON_IEC103_GEN_STARTUP_STATE;
Mon_IEC103_ConfirmMonWithAcd1( wUnitID, byPortNo );
break;
}
}
//总查询处理:
//总召数据上送:
void Mon_IEC103_ConstFrameProcess( BYTE byPortNo, BYTE *pbyMsgIEC103 )
{
if( EN_MON_IEC103_GEN_QUEST_STARTUP_STATE == ptMonIEC103RunCtl->byProcessState )
{ // 总查询开始,先送保护事件
if( Mon_IEC103_ResponseMonSendAsdu1ForBH( byPortNo, wUnitID, &wSYNum ) )
{
//下一个状态: // 总查询送告警遥信
ptMonIEC103RunCtl->byProcessState = EN_MON_IEC103_GEN_QUEST_ALLALM_STATE;
//总查询送自检遥信,送保护开入遥信,送装置运行记录,总查询保护投退,全遥信,
//单点遥信,双点遥信,全遥测,扰动表,总查询结束,
}
}
BOOLEAN Mon_IEC103_ResponseMonSendAsdu1ForBH( BYTE byPortNo, WORD wUnitID, WORD *wYXNum )
{
//debug 103 事件遥信状态处理
wInf = g_tSysSet.pwActRecInf[dwYXSentBase + wLoop];
pbyTemp[wBasePosi++] = g_tSysSet.byFunc + wInf / 256;
pbyTemp[wBasePosi++] = wInf % 256;
pbyTemp[wBasePosi++] = byStatus;
Mon_IEC103_LinkSendFrame( byPortNo, pbyTemp );
}
//====================================================
// Deals with the Sending process of Mon_IEC103
//====================================================
void Mon_IEC103_Send( BYTE byPortNo ) // 发送缓冲区用的是端口缓冲区
{
//1.监视发送的报文:
// message-watching
// #if(CN_103_HAVE_RMON)
if( ptSendCtrl->wSendLen != 0 )
{
if( RMon_MsgDataSend( byPortNo ) )
{
RMon_SavePortMsg( byPortNo, EN_DBG_MSG_SEND, ptSendCtrl->wSendLen, ptSendCtrl->bySendBuf );
}
//2.发送成功
if( wMsgLen == Hard_Udp_TxStartup( iSockNo, ptSendCtrl->bySendBuf, ptSendCtrl->wSendLen, byPortNo, EN_DBG_MSG_SEND ) ) // 发送成功
{ // 发送成功
Time_TimerBStop( &ptSendCtrl->tTimerAbandon );
Time_TimerBReset( &ptSendCtrl->tTimerLineIdle ); // 用Reset便于不同规约使用不同的空闲间隔
}
}
//发送忙:装置报文处理组织好报文要发送,置位忙;发函数调用底层接口发送后,置位闲;有忙标志时,不接收新报文。
if( CN_STATUS_SEND_BUSY == ptSendCtrl->wSendFlag )