FB_IEC870_5_101FBufferCtrl

FB_IEC870_5_101FBufferCtrl 1:

Mit diesem Funktionsbaustein kann der Inhalt des TX/RX-Datenpuffers manipuliert werden, der bei der Kommunikation über das IEC 60870-5-101/104 (Low Level) Transport Interface benutzt wird. Zusätzlich werden die zu verschickenden ASDUs (nur TX-Richtung) in die Datei gepuffert wenn die Verbindung zur Zentralstation unterbrochen wurde (im Offline-Mode). Die Funktionalität ähnelt der Funktionalität des FB_IEC870_5_101TBufferCtrl-Funktionsbausteins.

Der Funktionsbaustein besitzt folgende Aktionen:

Durch den Aufruf der oben aufgelisteten Aktionen kann der Inhalt des TX/RX-Datenpuffers verändert werden.

VAR_IN_OUT

VAR_IN_OUT
    bOnline : BOOL;
    buffer  : ST_IEC870_5_101TBuffer;
END_VAR

bOnline: Über diesen Eingang wird dem Funktionsbaustein mitgeteilt ob die Verbindung sich im Offline oder Online-Mode befindet. TRUE = Online, FALSE = Offline. Im Offline-Mode werden die zu versendenden ASDUs in einer Datei gepuffert. Im Online-Mode werden dann die in der Datei gepufferten ASDUs aus der Datei entfernt und an die Zentralstation verschickt.

buffer: TX/RX-Datenpuffer. Die TX/RX-Pufferparameter (wie z.B. asduSize ) müssen vor der Benutzung konfiguriert werden.

VAR_INPUT

VAR_INPUT
    config  : ST_IEC870_5_101FBufferCfg;
    putObj  : ST_IEC870_5_101AOGen;
END_VAR

config: Offline-Dateipuffer-Konfigurationseinstellungen.

putObj: Dateneinheit (ASDU), die gesendet werden soll.

VAR_OUTPUT

VAR_OUTPUT
    status  : ST_IEC870_5_101FBufferStatus;
    getObj  : ST_IEC870_5_101AOGen;
    bOk     : BOOL;
END_VAR

status: Offline-Datenpuffer-Statusinformationen.

getObj: Empfangene Dateneinheit (ASDU).

bOk: Diese Variable wird TRUE, wenn ein neuer Eintrag erfolgreich hinzugefügt oder aus dem Fifo entfernt wurde. Diese Variable wird FALSE beim Pufferüberlauf und wenn kein Eintrag entfernt werden konnte weil der Fifo bereits leer ist.

Beispiel in ST:

Folgender Beispielcode (Ausschnitt) demonstriert die Benutzung der Baustein-Aktionen. Alle ~1s (tCycle) wird eine neue ASDU (M_BO_TB_1) mit der Übertragungsursache: Spontan und Zeitstempel generiert und in den TX-Fifo abgelegt.
Die empfangenen Testkommandos (C_TS_TA_1) und Uhrzeitsynchronisationskommandos (C_CS_NA_1) werden aus dem RX-Fifo entfernt und mit gespiegelten ASDUs beantwortet.

Über die VAR_IN_OUT-Variable bOnline wird das Speichern oder Laden der ASDUs in die Datei gesteuert. Bei bOnline = FALSE wird die Datei geöffnet und die anfallenden TX-ASDUs im Hintergrund in die Datei geschrieben. Bei bOnline = TRUE werden die ASDUs aus der Datei im Hintergrund geladen und verschickt. Damit das Speichern und Laden der Pufferdatei im Hintergrund durchgeführt werden kann muss der FB_IEC870_5_101FBufferCtrl-Funktionsbaustein zyklisch aufgerufen werden. Das Hinzufügen neuer TX-ASDUs oder das Bearbeiten alter RX-ASDUs wird von dem Speichern/Laden in/aus der Datei nicht beeinflusst.

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

Voraussetzungen

Entwicklungsumgebung

Zielplattform

Einzubindende SPS Bibliotheken (Kategoriegruppe)

TwinCAT v3.1.4012.0

PC oder CX (x86, x64, ARM)

Tc2_IEC60870_5_10x (Communication->IEC60870)
Tc2_SerialCom (Communication->Serial)
Tc2_TcpIp (Communication->TcpIp)
Tc2_Utilities (System)