代码走读UDP103规约--2024年3月21日15:50:20

问题:

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 )






  • 20
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值