Beispiel: Dateizugriff aus der SPS

Systemvoraussetzungen: 

-  TwinCAT 2.9;

In diesem Beispiel wird die Anwendung der SPS-Funktionsbausteine für den Dateizugriff aus der TcSystem.Lib vorgestellt. Mit Hilfe der vorhandenen Funktionsbausteine wurde ein neuer Funktionsbaustein FB_FileCopy realisiert. Mit diesem Baustein können Binärdateien z.B. auf dem lokalen TwinCAT PC oder von einem Remote-TwinCAT PC auf den lokalen TwinCAT PC kopiert werden. Mit den Funktionsbausteinen kann nicht auf Netzwerklaufwerke zugegriffen werden.  Bei einer steigenden Flanke am bExecute-Eingang des FB_FileCopy-Bausteines werden folgende Schritte ausgeführt.

a) Öffnen der Quell- und Ziel-Datei;

b) Lesen der Quell-Datei in einen Puffer;

c) Schreiben der gelesenen Bytes aus dem Puffer in die Ziel-Datei;

d) Überprüfen, ob das Ende der Quell-Datei erreicht wurde. Wenn nicht dann b) und c) wiederholen. Wenn ja, dann zu e) springen;

e) Schließen der Quell- und Ziel-Datei;

Die Datei wird stückweise kopiert. Die Größe des Puffers wurde im Beispiel auf 1000 Byte festgelegt, kann aber geändert werden. Die kompletten Sourcen zu dem Beispielprojekt können hier entpackt werden: Dateizugriff aus der SPS.

Das SPS-Programm:

PROGRAM MAIN
VAR
    fbFileCopy  : FB_FileCopy;
    bCopy       : BOOL;
    bBusy       : BOOL;
    bError      : BOOL;
    nErrId      : UDINT;
END_VAR
Beispiel: Dateizugriff aus der SPS 1:

Im Beispiel wird die Settings.txt-Datei aus dem Temp-Ordner von einem Remote-TwinCAT-PC mit der Netzwerkadresse: "172.16.2.209.1.1" in den TwinCAT-Ordner auf dem lokalen TwinCAT PC kopiert.

 

Der FB_FileCopy-Funktionsbaustein

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

Implementierung:

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

Die kompletten Sourcen zu dem Beispielprojekt können hier entpackt werden: Dateizugriff aus der SPS.