Example: File access from the PLC

System requirements:

-  TwinCAT 2.9;

 

This example illustrates use of the PLC function blocks from the TcSystem.Lib for file access. A new function block, FB_FileCopy, is implemented with the aid of the existing function blocks. This block can be used, for instance, to copy binary data on the local TwinCAT PC or from a remote TwinCAT PC to the local TwinCAT PC. The function block cannot be used to access network drives. A rising edge at the bExecute input of the FB_FileCopy block results in execution of the following steps.

a) Open the source and destination files;

b) Read the source file into a buffer;

c) Write the bytes that have been read from the buffer into the destination file;

d) Check whether the end of the source file has been reached. If not, then repeat b) and c). If yes, then jump to e);

e) Close the source and destination files;

The file is copied one segment at a time. In this example, the size of the buffer has been specified as 1000 bytes, but this can be modified. The complete source code for the example project can be unpacked from here: File access from the PLC.

The PLC program:

PROGRAM MAIN
VAR
    fbFileCopy  : FB_FileCopy;
    bCopy       : BOOL;
    bBusy       : BOOL;
    bError      : BOOL;
    nErrId      : UDINT;
END_VAR

Example: File access from the PLC 1:

In this example, the file Settings.txt is copied from the Temp directory of a remote TwinCAT PC having network address "172.16.2.209.1.1" to the TwinCAT directory on the local TwinCAT PC.

 

The FB_FileCopy Function Block

Interface:

FUNCTION_BLOCK FB_FileCopy
VAR_INPUT
    sSrcNetId           : T_AmsNetId;(* TwinCAT network address of the source file *)
    sSrcPathName        : T_MaxString;(* Source file path and name *)
    sDestNetId          : T_AmsNetId;(* TwinCAT network address of the destination file *)
    sDestPathName       : T_MaxString; (* Destination file path and name *)
    bExecute            : BOOL; (* Rising edge start fb execution *)
    tTimeOut            : TIME := DEFAULT_ADS_TIMEOUT;(* Max. ADS timeout time *)
END_VAR
VAR_OUTPUT
    bBusy           :BOOL;(* TRUE => File copy execution in progress, FALSE => File copy execution idle *)
 bError             :BOOL;(* TRUE => Error, FALSE => No error *)
 nErrId             :UDINT;(* Error code *)
END_VAR
VAR
    fbFileOpen          :FB_FileOpen;
    fbFileClose         :FB_FileClose;
    fbFileRead          :FB_FileRead;
    fbFileWrite         :FB_FileWrite;

    hSrcFile            :UINT   := 0;(* File handle of the source file *)
 hDestFile              :UINT   := 0;(* File handle of the destination file *)

    Step                :DWORD;
    RisingEdge          :R_TRIG;

    buffRead            :ARRAY[1..1000] OF BYTE;(* Buffer *)
 cbReadLength           :UDINT := 0;
END_VAR

Implementation:

RisingEdge(CLK:=bExecute);

CASE Step OF
    0:      (* Idle state *)
     IF RisingEdge.Q THEN
            bBusy := TRUE;
            bError:= FALSE;
            nErrId:=0;
            Step := 1;
            cbReadLength:=0;
            hSrcFile:=0;
            hDestFile:=0;
        END_IF

    1:      (* Open source file *)
     fbFileOpen( bExecute := FALSE );
        fbFileOpen( sNetId := sSrcNetId, sPathName := sSrcPathName,
            nMode := FOPEN_MODEREAD OR FOPEN_MODEBINARY,
            ePath := PATH_GENERIC, tTimeout := tTimeOut, bExecute := TRUE );
        Step := Step + 1;
    2:
        fbFileOpen( bExecute := FALSE );
        IF NOT fbFileOpen.bBusy THEN
            IF fbFileOpen.bError THEN
                nErrId := fbFileOpen.nErrId;
                bError := TRUE;
                Step := 50;
            ELSE
                hSrcFile := fbFileOpen.hFile;
                Step := Step + 1;
            END_IF
        END_IF

    3:      (* Open destination file *)
     fbFileOpen( bExecute := FALSE );
        fbFileOpen( sNetId := sDestNetId, sPathName := sDestPathName,
            nMode := FOPEN_MODEWRITE OR FOPEN_MODEBINARY,
            ePath := PATH_GENERIC, tTimeout := tTimeOut, bExecute := TRUE );
        Step := Step+1;
    4:
        fbFileOpen( bExecute := FALSE );
        IF NOT fbFileOpen.bBusy THEN
            IF fbFileOpen.bError THEN
                nErrId := fbFileOpen.nErrId;
                bError := TRUE;
                Step := 50;
            ELSE
                hDestFile := fbFileOpen.hFile;
                Step := Step + 1;
            END_IF
        END_IF

    5:      (* Read data from source file *)
     cbReadLength := 0;
        fbFileRead( bExecute:= FALSE );
        fbFileRead( sNetId:=sSrcNetId, hFile:=hSrcFile,
            pReadBuff:= ADR(buffRead), cbReadLen:= SIZEOF(buffRead),
            bExecute:=TRUE, tTimeout:=tTimeOut );
        Step := Step + 1;
    6:
        fbFileRead( bExecute:= FALSE );
        IF NOT fbFileRead.bBusy THEN
            IF fbFileRead.bError THEN
                nErrId := fbFileRead.nErrId;
                bError := TRUE;
                Step := 50;
            ELSE
                cbReadLength := fbFileRead.cbRead;
                Step := Step + 1;
            END_IF
        END_IF

    7:      (* Write data to destination file *)
     fbFileWrite( bExecute := FALSE );
        fbFileWrite( sNetId:=sDestNetId, hFile:=hDestFile,
            pWriteBuff:= ADR(buffRead), cbWriteLen:= cbReadLength,
            bExecute:=TRUE, tTimeout:=tTimeOut );
        Step := Step + 1;
    8:
        fbFileWrite( bExecute := FALSE );
        IF NOT fbFileWrite.bBusy THEN
            IF fbFileWrite.bError THEN
                nErrId := fbFileWrite.nErrId;
                bError := TRUE;
                Step := 50;
            ELSE
                IF fbFileRead.bEOF THEN (* Check if the EOF flag ist set *)
                 Step := 50;(* Cleanup: close the destination and source files *)
             ELSE
                    Step := 5; (* Repeat reading/writing *)
             END_IF
            END_IF
        END_IF

    30:     (* Close the destination file *)
     fbFileClose( bExecute := FALSE );
        fbFileClose( sNetId:=sDestNetId, hFile:=hDestFile, bExecute:=TRUE, tTimeout:=tTimeOut );
        Step := Step + 1;
    31:
        fbFileClose( bExecute := FALSE );
        IF NOT fbFileClose.bBusy THEN
            IF fbFileClose.bError THEN
                nErrId := fbFileClose.nErrId;
                bError := TRUE;
            END_IF
            Step := 50;
            hDestFile := 0;
        END_IF

    40: (* Close source file *)
     fbFileClose( bExecute := FALSE );
        fbFileClose( sNetId:=sSrcNetId, hFile:=hSrcFile, bExecute:=TRUE, tTimeout:=tTimeOut );
        Step := Step + 1;
    41:
        fbFileClose( bExecute := FALSE );
        IF NOT fbFileClose.bBusy THEN
            IF fbFileClose.bError THEN
                nErrId := fbFileClose.nErrId;
                bError := TRUE;
            END_IF
            Step := 50;
            hSrcFile := 0;
        END_IF

    50: (* Error or ready => Cleanup *)
     IF ( hDestFile <> 0 ) THEN
            Step := 30; (* Close the destination file*)
     ELSIF (hSrcFile <> 0 ) THEN
            Step := 40; (* Close the source file *)
     ELSE
            Step := 0;      (* Ready *)
            bBusy := FALSE;
        END_IF

END_CASE

The complete source code for the example project can be unpacked from here: File access from the PLC.