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.
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:
- RxRemoveObj (removes the oldest FIFO entry from the RX FIFO);
- RxReset (clears all the RX FIFO entries, resets the RX FIFO);
- TxAddObj (inserts a new FIFO entry into the TX FIFO);
- TxReset (clears all the TX FIFO entries, resets the TX FIFO);
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 |