FB_IEC870_5_101FBufferCtrl

From product version: TwinCAT PLC Library IEC60870-5-101/104 substation v3.0.2 / IEC60870-5-104 controlling station v1.0.2 and higher.

FB_IEC870_5_101FBufferCtrl 1:

This function block allows the contents of the TX/RX data buffer that is used for communication through the IEC60870-5-104/101 (low level) transport interface to be manipulated. In addition, the ASDUs that are to be transmitted (only in the TX direction) are buffered in the file if the connection to the central station is interrupted (in offline mode). The functionality is like that of the FB_IEC870_5_101TBufferCtrl function block.

The function block features the following tasks:

The content of the TX/RX data buffer can be changed by calling the actions listed above.

VAR_IN_OUT

VAR_IN_OUT
    bOnline : BOOL; (* TRUE => route frames to the link layer, FALSE => route frames to the file buffer *)
    buffer  : ST_IEC870_5_101TBuffer; (* TX/RX data buffer *)
END_VAR

bOnline: This input tells the function block whether the connection is in offline or online mode. TRUE = online, FALSE = offline. In offline mode, the ASDUs that are to be transmitted are buffered in a file. In online mode, the ASDUs that are buffered in the file are taken out of the file and sent to the central station.

buffer: TX/RX data buffer. The TX/RX buffer parameters (such as asduSize) must be configured before use.

VAR_INPUT

VAR_INPUT
    config  : ST_IEC870_5_101FBufferCfg; (* File buffer configuration settings *)
    putObj  : ST_IEC870_5_101AOGen; (* ASDU to send *)
END_VAR

config: offline file buffer configuration settings.

putObj: data unit (ASDU) that is to be transmitted.

VAR_OUTPUT

VAR_OUTPUT
    status  : ST_IEC870_5_101FBufferStatus; (* File buffer status *)
    getObj  : ST_IEC870_5_101AOGen; (* received ASDU *)
    bOk     : BOOL; (* TRUE = action succesfully, FALSE=Fifo overflow or fifo empty *)
END_VAR

status: Offline data buffer status information.

getObj:: Received data unit (ASDU).

bOk: This variable becomes TRUE if a new entry was successfully added to or removed from the FIFO. This variable becomes FALSE if the buffer overflows and if it is not possible to remove an entry because the FIFO is already empty.

 

Example in ST:

The following fragment of example code demonstrates the use of the function block actions. Approximately every 1s (tCycle) a new ASDU (M_BO_TB_1) is generated with "spontaneous" as the transmission cause and with a timestamp and is placed in the TX FIFO.
The test command (C_TS_TA_1) and clock synchronization command (C_CS_NA_1) received are removed from the RX FIFO, and replied to with reflected ASDUs.

The VAR_IN_OUT variable bOnline is used to control the storage or loading of the ASDUs in the file. If bOnline = FALSE the file is opened, and all the TX ASDUs that arise are written into the file in the background. If bOnline = TRUE the ASDUs are taken out of the file in the background and transmitted. For saving and loading of the buffer file in the background to be possible, the FB_IEC870_5_101FBufferCtrl function block must be called cyclically. The insertion of new TX ASDUs or the editing of old RX ASDUs is not affected by saving or loading data into or out of the file.

 

 

PROGRAM P_ProcessSlaveBufferData
VAR_IN_OUT
    bOnline : BOOL;
    buffer : ST_IEC870_5_101TBuffer;
END_VAR
VAR
    asduAddr : DWORD := 7; (* Common asdu address *)

    fbBuffer : FB_IEC870_5_101FBufferCtrl :=( config := ( sPathName := 'c:\tmp\OfflineAsdu.dat',
                            bOverwrite := TRUE,
                        cbBuffer := 16#100000 )); (* RX/TX buffer control function block *)

    txAsdu : ST_IEC870_5_101AOGen; (* asdu to send *)
    txTT : T_CP56Time2a; (* time tag to send *)

    rxAsdu : ST_IEC870_5_101AOGen; (* received asdu *)
    rxTT : T_CP56Time2a; (* received time tag *)

    rxQOI : BYTE; (* qualifier of interrogation command *)
    txBSI : DWORD := 1; (* bit string value *)
    txQDS : BYTE; (* bit string quality descriptor *)
    tCycle : TIME := T#1s;
    bSpont : BOOL := TRUE;
    timer : TON;
    fbRTC : RTC_EX2 := ( EN := TRUE, PDT := ( wYear := 2006, wMonth := 8, wDay := 17, wHour := 12, wMinute := 23 ) );
END_VAR
timer( IN := bSpont, PT := tCycle );
IF timer.Q THEN
    timer( IN := FALSE ); timer( IN := bSpont );

    txBSI := ROL( txBSI, 1); (* Modify bit string value *)
    txQDS.7 := NOT txQDS.7; (* Toggle IV quality flag *)(* create dummy time tag *)
    fbRTC();
    txTT := SYSTEMTIME_TO_CP56Time2a( fbRTC.CDT, TRUE );

    (* create asdu *)
    txAsdu.ident.eType := M_BO_TB_1; (* Bit string with time tag *)
    txAsdu.ident.bSQ := FALSE;
    txAsdu.ident.nObj := 1;
    txAsdu.ident.eCOT := eIEC870_COT_SPONTAN;
    txAsdu.ident.nORG := 1;
    txAsdu.ident.bPN := FALSE;
    txAsdu.ident.bT := FALSE;
    txAsdu.ident.eClass := eIEC870_Class_1;
    txAsdu.ident.asduAddr := asduAddr;
    txAsdu.info.objAddr := 100;
    F_iecResetStream( 0, txAsdu.info.stream ); (* clear previous data (this sets the stream length = 0 *)
    F_iecCopyBufferToStream( ADR( txBSI ), SIZEOF( txBSI ), txAsdu.info.stream ); (* put BSI to stream *)
    F_iecCopyBufferToStream( ADR( txQDS ), SIZEOF( txQDS ), txAsdu.info.stream ); (* put QDS to stream *)
    F_iecCopyBufferToStream( ADR( txTT ), SIZEOF( txTT ), txAsdu.info.stream ); (* put time tag to stream *)

    fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
    IF NOT fbBuffer.bOk THEN
        RETURN;
        (* TODO: Report send buffer overflow error *)
    END_IF
END_IF




REPEAT
    fbBuffer.RxRemoveObj( bOnline := bOnline, getObj=>rxAsdu, buffer := buffer ); (* Try to remove asdu from RX fifo *)
    IF fbBuffer.RxRemoveObj.bOk THEN (* success *)
        CASE rxAsdu.ident.eType OF

        C_TS_NA_1: (* Simple test command implementation *)

        txAsdu := rxAsdu;
        txAsdu.ident.eCOT := eIEC870_COT_ACT_CON; (* send activation confirmation *)
        fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
        IF NOT fbBuffer.bOk THEN
            EXIT;
            (* TODO: Report send buffer overflow error *)
        END_IF

        C_CS_NA_1: (* Simple clock synchronisation command implementation *)

        F_iecCopyStreamToBuffer( ADR( rxTT ), SIZEOF( rxTT ), rxAsdu.info.stream );

        (*... *)

        txAsdu := rxAsdu; (* dummy old time value *)
        txAsdu.ident.eCOT := eIEC870_COT_ACT_CON; (* send activation confirmation *)
        fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
        IF NOT fbBuffer.bOk THEN
            EXIT;
            (* TODO: Report send buffer overflow error *)
        END_IF

        C_IC_NA_1: (* Simple interrogation command implementation *)

        txAsdu := rxAsdu;
        txAsdu.ident.eCOT := eIEC870_COT_ACT_CON; (* send activation confirmation *)
        fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
        IF NOT fbBuffer.bOk THEN
            EXIT;
            (* TODO: Report send buffer overflow error *)
        END_IF

        F_iecCopyStreamToBuffer( ADR( rxQOI ), SIZEOF(rxQOI), rxAsdu.info.stream );

        (* create asdu *)
        txAsdu.ident.eType := M_BO_NA_1; (* Bit string without time tag! *)
        txAsdu.ident.bSQ := FALSE;
        txAsdu.ident.nObj := 1;
        txAsdu.ident.eCOT := BYTE_TO_INT( rxQOI );
        txAsdu.ident.nORG := 1;
        txAsdu.ident.bPN := FALSE;
        txAsdu.ident.bT := FALSE;
        txAsdu.ident.eClass := eIEC870_Class_1;
        txAsdu.ident.asduAddr := asduAddr;
        txAsdu.info.objAddr := 100;
        F_iecResetStream( 0, txAsdu.info.stream ); (* clear previous data (this sets the stream length = 0 *)
        F_iecCopyBufferToStream( ADR( txBSI ), SIZEOF( txBSI ), txAsdu.info.stream ); (* put BSI to stream *)
        F_iecCopyBufferToStream( ADR( txQDS ), SIZEOF( txQDS ), txAsdu.info.stream ); (* put QDS to stream *)
        fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
        IF NOT fbBuffer.bOk THEN
            EXIT;
            (* TODO: Report send buffer overflow error *)
        END_IF


        txAsdu := rxAsdu;
        txAsdu.ident.eCOT := eIEC870_COT_ACT_TERM; (* send activation termination *)
        fbBuffer.TxAddObj( bOnline := bOnline, putObj := txAsdu, buffer := buffer ); (* put asdu to the TX fifo *)
        IF NOT fbBuffer.bOk THEN
            EXIT;
            (* TODO: Report send buffer overflow error *)
        END_IF

        ELSE
            (* TODO: Report invalid asdu type...*)
            EXIT;
        END_CASE

    END_IF
UNTIL NOT fbBuffer.bOk (* RX fifo is empty *)
END_REPEAT



(* Offline frames are written to the file. Execute this function block in every cycle! *)
fbBuffer(bOnline := bOnline, buffer:= buffer );
IF fbBuffer.status.eState = eIEC870_FBUFFER_ERROR THEN
    (*TODO: Report file access error *)
    ;
END_IF

 

Requirements

Development environment

Target system type

PLC libraries to be linked

TwinCAT v2.10.0 Build >= 1313

PC or CX (x86, ARM)

TcIEC870_5_101.Lib
( Standard.Lib; TcBase.Lib; TcSystem.Lib; TcUtilities.Lib are included automatically )