Issue with CAA File Write FB throwing error code 1

Runtime
lmdejong
2020-05-25
2020-06-08
  • lmdejong

    lmdejong - 2020-05-25

    [Snippet of code in first response which throws the error]

    Hi,

    I'm creating a program for a machine that should test our products. The testing sequence is complete but I am unable to log the data.

    I'm able to create a folder and a file to write to. But I'm unable to write to the file.
    The filwr FB gives me an error on eError of value 1. At the moment I'm at a loss, any help would be appreciated.

    The code below ends up at ManagerState 90 with POU_ERROR = TRUE and ErrorAtState = 42 with State_eError = 1.
    1 is not present in the Error ENUM of the CAA_File library hence the reason I'm posting this.

    VAR
        POU_ERROR:          BOOL;
        ManagerState:       INT:=0;
        ErrorAtState:       INT:=0;
        State_eError:       FILE.ERROR;
    
        hFile:              FILE.CAA.HANDLE;
        filop:              FILE.Open;
        filcl:              FILE.Close;
        filwr:              FILE.Write;
    
        hDir:               FILE.CAA.HANDLE;
        fildop:             FILE.DirOpen;
        fildcl:             FILE.DirClose;
        fildcr:             FILE.DirCreate;
    
        LOG30:              TBLOG;
        LOG76:              TBLOG;
    
        LWD:                ARRAY [0..MaxID-1] OF TBTEST;
    
        sTarget:            STRING;
        sFileName:          STRING;
        TestID:             UINT;
        xFileExists:        BOOL;
        udiFileSize:        UDINT;
        szFileSize1:        FILE.CAA.SIZE := 0;
        udiCmpError:        UDINT;
        j:                  UINT;
        sData:              STRING(255);
    END_VAR
    VAR CONSTANT
        MaxID:              UINT := 3;
        HeaderNames: ARRAY[0..8] OF STRING := ['DateTime', 'TestState', 'TestPaused', 'TestCounterA', 'RunTimeStrokeA', 'RunTimeTotalA', 'TestCounterB', 'RunTimeStrokeB', 'RunTimeTotalB'];
        sTestString:        STRING := 'Hello world!';
    END_VAR
    
    //Save log section
    LOG30.LTT(PT:=gvl_LogUpdateFreq);
    LOG76.LTT(PT:=gvl_LogUpdateFreq);
    
    CASE(ManagerState) OF
        0: // Initializing LogManager
            POU_ERROR := FALSE;
            fildop( xExecute:=FALSE);
    
            IF PLC_R.i_wSdCardStatus <> SEC.PLC_R_SDCARD_STATUS.SDCARD_READWRITE THEN //
                // SDCARD error
                ErrorAtState := ManagerState;
                State_eError := FILE.ERROR.NOT_EXIST;
                ManagerState := 90;
            ELSE
                ManagerState := 10;
            END_IF
    
        10: // SD-card in correct state check if folder exists
            fildop.sDirName := gvl_sLogDir;
            fildop( xExecute:=TRUE);
            IF fildop.xDone THEN
                hDir := fildop.hDir;
                IF NOT fildop.xError THEN
                    ManagerState := 11;
                END_IF
            END_IF
            IF fildop.xError THEN 
                    ManagerState := 15;
            END_IF
            IF fildop.xDone THEN
                fildop( xExecute := FALSE );
            END_IF
    
        11: // Close directory
            fildcl.hDir := hDir;
            fildcl (xExecute := TRUE);
    
            IF fildcl.xDone = TRUE THEN
                fildcl (xExecute := FALSE);
                ManagerState := 20;
            END_IF
            IF fildcl.xError = TRUE THEN
                ErrorAtState := ManagerState;
                State_eError := fildcl.eError;
                ManagerState := 90;
            END_IF
    
        15: // Create directory
            fildcr.sDirName := gvl_sLogDir;
            fildcr( xExecute := TRUE );
            IF fildcr.xDone THEN
                fildcr.xExecute := FALSE;
                ManagerState := 0; // Return to check if file has been made
            END_IF
            IF fildcr.xError = TRUE THEN
                ErrorAtState := ManagerState;
                State_eError := fildcr.eError;
                ManagerState := 90;
            END_IF
    
        20: // Waiting for event
            // Resetting all FB's
            filop (xExecute := FALSE);
            filcl (xExecute := FALSE);
            filwr (xExecute := FALSE);
            fildop(xExecute := FALSE);
            fildcr(xExecute := FALSE);
    
            //Setting the timer to be linked to wether the test is active or not
            IF TB30.State = AUTO THEN
                LOG30.LTT(IN := TRUE);
            ELSE
                LOG30.LTT(IN := FALSE);
            END_IF
            IF TB76.State = AUTO THEN
                LOG76.LTT(IN := TRUE);
            ELSE
                LOG76.LTT(IN := FALSE);
            END_IF
    
            //Checking triggers
            IF LOG30.State <> TB30.State OR LOG30.Paused <> TB30.Paused OR LOG30.LTT.Q THEN
                LWD := TEST_30;
    
                ManagerState := 30;
    
                LOG30.State := TB30.State;
                LOG30.Paused := TB30.Paused;
    
                IF LOG30.LTT.Q THEN
                    LOG30.LTT( IN := FALSE);
                END_IF
    
            ELSIF LOG76.State <> TB76.State OR LOG76.Paused <> TB76.Paused OR LOG76.LTT.Q THEN
                LWD := TEST_76;
    
                ManagerState := 30;
    
                LOG76.State := TB76.State;
                LOG76.Paused := TB76.Paused;
    
                IF LOG76.LTT.Q THEN
                    LOG76.LTT( IN := FALSE);
                END_IF
    
            END_IF
    
        30: // Write start
            TestID := 0;
    
            ManagerState := 34;
    
        34: // Check if enabled and generate name
            IF LWD[TestID].Enabled THEN
                //Generate file name
                IF LWD[TestID].Product = '' THEN
                    LWD[TestID].Product := 'UNKNOWN PRODUCT';
                END_IF
                IF LWD[TestID].ProductID = '' THEN
                    LWD[TestID].ProductID := CONCAT('UNKNOWN PRODUCT ID ', UINT_TO_STRING(TestID));
                END_IF
    
                sFileName := CONCAT(LWD[TestID].Product, ' - ');
                sFileName := CONCAT(sFileName, LWD[TestID].ProductID);
                sFileName := CONCAT(sFileName, '.csv');
    
                sTarget := CONCAT(gvl_sLogDir, sFileName);
    
                ManagerState := 36;
            ELSE
                ManagerState := 70;
            END_IF
    
        36: // Check if file exists
            udiFileSize := FILE.SysFileGetSize(sTarget, ADR(udiCmpError));
    
            IF udiFileSize = 0 THEN
                //File doesnt exist or is empty
                //Header should be created
                ManagerState := 40;
            ELSIF udiCmpError = ERR_OK THEN
                //File exists
                //File should be directly opened in Append mode
                ManagerState := 45;
            ELSE
                State_eError := FILE.ERROR.ERROR_UNKNOWN;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        40: // File doenst exist - Create file
            filop.sFileName := sTarget;
            filop.eFileMode := FILE.MODE.MWRITE;
            filop.xExclusive:= TRUE;
            filop (xExecute := TRUE );
    
            IF filop.xDone THEN
                hFile := filop.hFile;
                ManagerState := 42;
            END_IF
    
            IF filop.xError THEN
                State_eError := filop.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        42: // New file created - Write header
            //Creation of table header string
            sData := '';
            FOR j := 0 TO SIZEOF(HeaderNames) DO
                sData := CONCAT(sData, HeaderNames[j]);
                sData := CONCAT(sData, ';');
            END_FOR
    
            filwr.hFile := hFile;
            filwr.pBuffer := ADR(sTestString);
            szFileSize1:= SIZEOF(sTestString);
            filwr.szSize := szFileSize1;
            filwr.udiTimeOut := 100000; // 100ms TimeOut
    
            filwr (xExecute := TRUE);
    
            IF filwr.xDone THEN
                ManagerState := 42;
                filwr (xExecute := FALSE);
            END_IF
    
            IF filwr.xError THEN
                State_eError := filwr.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        45: // File exists open in MAPPD
            filop.sFileName := sTarget;
            filop.eFileMode := FILE.MODE.MAPPD;
            filop (xExecute := TRUE );
    
            IF filop.xDone THEN
                hFile := filop.hFile;
                ManagerState := 60; //   -------------------------- TEMP
            END_IF
    
            IF filop.xError THEN
                State_eError := filop.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        60: // Writing done, close file
            filcl.hFile := hFile;
            filcl( xExecute := TRUE );
    
            IF filcl.xDone THEN
                ManagerState := 70;
            END_IF
    
            IF filcl.xError THEN
                State_eError := filcl.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        70: // Next item state or end cycle
            TestID := TestID + 1;
            IF TestID < MaxID THEN
                ManagerState := 34;
            ELSE
                ManagerState := 20;
            END_IF
    
        90: // Error state
            POU_ERROR := TRUE;
    END_CASE
    

    I'm running this on a M241 Schneider Electric PLC in SoMachine V4.3. I need to revert the CAA library to the v3.5.3.0 instead of v3.5.3.132 because otherwise the PLC throws 2 unresolved references: FILE_CLOSE and FILE_DIRCLOSE.

     

    Last edit: lmdejong 2020-05-25
  • lmdejong

    lmdejong - 2020-06-08

    Sure, no problem

     
    👍
    1
  • lmdejong

    lmdejong - 2020-05-25

    The actual problem could be in here:

    42: // New file created - Write header
            //Creation of table header string
            sData := '';
            FOR j := 0 TO SIZEOF(HeaderNames) DO
                sData := CONCAT(sData, HeaderNames[j]);
                sData := CONCAT(sData, ';');
            END_FOR
    
            filwr.hFile := hFile;
            filwr.pBuffer := ADR(sTestString);
            szFileSize1:= SIZEOF(sTestString);
            filwr.szSize := szFileSize1;
            filwr.udiTimeOut := 100000; // 100ms TimeOut
    
            filwr (xExecute := TRUE);
    
            IF filwr.xDone THEN
                ManagerState := 42;
                filwr (xExecute := FALSE);
            END_IF
    
            IF filwr.xError THEN
                State_eError := filwr.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    

    As far as I know this is exactly as in the example from the CAA_File documentation.

     
  • lmdejong

    lmdejong - 2020-06-08

    SOLVED: Been working on this too long, didn't see a typo. The errorcode remains unfound though!

     
    • aliazzz

      aliazzz - 2020-06-08

      Would you mind correcting this typo so we can c/p your solution?
      That would be awesome!

       
  • lmdejong

    lmdejong - 2020-06-08

    The error is in step 42, writing step. I circle it back to step 42 and try to write again without resetting the write function.
    There is the error.

    Below is the final code.

    I had to add some extra steps to reset the write function because when u start a file it writes two lines, one to create the table header.

    PROGRAM LogManager
    VAR
        POU_ERROR:          BOOL;
        ManagerState:       INT:=0;
        ErrorAtState:       INT:=0;
        State_eError:       FILE.ERROR;
    
        hFile:              FILE.CAA.HANDLE;
        filop:              FILE.Open;
        filcl:              FILE.Close;
        filwr:              FILE.Write;
    
        hDir:               FILE.CAA.HANDLE;
        fildop:             FILE.DirOpen;
        fildcl:             FILE.DirClose;
        fildcr:             FILE.DirCreate;
    
        LOG30:              TBLOG;
        LOG76:              TBLOG;
    
        LWD:                ARRAY [0..MaxID-1] OF TBTEST;
    
        sTarget:            STRING;
        sFileName:          STRING;
        TestID:             UINT;
        xFileExists:        BOOL;
        udiFileSize:        UDINT;
        szFileSize1:        FILE.CAA.SIZE := 0;
        udiCmpError:        UDINT;
        j:                  UINT;
        sData:              STRING(255);
        sRaw:               STRING(255);
    
        sYear:              STRING(4);
        sMonth:             STRING(2);
        sDay:               STRING(2);
        sHour:              STRING(2);
        sMinute:            STRING(2);
        sSecond:            STRING(2);
        sDaySep:            STRING(1) := '-';
        sTimSep:            STRING(1) := ':';
    
        xTrigLog30:         BOOL;
        xTrigLog76:         BOOL;
    END_VAR
    VAR CONSTANT
        MaxID:              UINT := 3;
        HeaderNames:        STRING(117) := 'DateTime;TestState;TestPaused;TestCounterA;RunTimeStrokeA;RunTimeTotalA;TestCounterB;RunTimeStrokeB;RunTimeTotalB$R$N';
    END_VAR
    
    //Save log section
    LOG30.LTT(PT:=gvl_LogUpdateFreq);
    LOG76.LTT(PT:=gvl_LogUpdateFreq);
    
    CASE(ManagerState) OF
        0: // Initializing LogManager
            POU_ERROR := FALSE;
            fildop( xExecute:=FALSE);
    
            IF PLC_R.i_wSdCardStatus <> SEC.PLC_R_SDCARD_STATUS.SDCARD_READWRITE THEN //
                // SDCARD error
                ErrorAtState := ManagerState;
                State_eError := FILE.ERROR.NOT_EXIST;
                ManagerState := 90;
            ELSE
                ManagerState := 10; // Skip folder actions
            END_IF
    
        10: // SD-card in correct state check if folder exists
            fildop.sDirName := gvl_sLogDir;
            fildop( xExecute:=TRUE);
            IF fildop.xDone THEN
                hDir := fildop.hDir;
                IF NOT fildop.xError THEN
                    ManagerState := 11;
                END_IF
            END_IF
            IF fildop.xError THEN 
                //IF fildop.eError = FILE.ERROR.NOT_EXIST THEN
                    ManagerState := 15;
                (*ELSE
                    State_eError := fildop.eError;
                    ErrorAtState := ManagerState;
                    ManagerState := 90;
                END_IF*)
            END_IF
            IF fildop.xDone THEN
                fildop( xExecute := FALSE );
            END_IF
    
        11: // Close directory
            fildcl.hDir := hDir;
            fildcl (xExecute := TRUE);
    
            IF fildcl.xDone = TRUE THEN
                fildcl (xExecute := FALSE);
                ManagerState := 20;
            END_IF
            IF fildcl.xError = TRUE THEN
                ErrorAtState := ManagerState;
                State_eError := fildcl.eError;
                ManagerState := 90;
            END_IF
    
        15: // Create directory
            fildcr.sDirName := gvl_sLogDir;
            fildcr( xExecute := TRUE );
            IF fildcr.xDone THEN
                fildcr.xExecute := FALSE;
                ManagerState := 0; // Return to check if file has been made
            END_IF
            IF fildcr.xError = TRUE THEN
                ErrorAtState := ManagerState;
                State_eError := fildcr.eError;
                ManagerState := 90;
            END_IF
    
        20: // Waiting for event
            // Resetting all FB's
            filop (xExecute := FALSE);
            filcl (xExecute := FALSE);
            filwr (xExecute := FALSE);
            fildop(xExecute := FALSE);
            fildcr(xExecute := FALSE);
    
            //Setting the timer to be linked to wether the test is active or not
            IF TB30.State = STATE.AUTO THEN
                LOG30.LTT(IN := TRUE);
            ELSE
                LOG30.LTT(IN := FALSE);
            END_IF
            IF TB76.State = STATE.AUTO THEN
                LOG76.LTT(IN := TRUE);
            ELSE
                LOG76.LTT(IN := FALSE);
            END_IF
    
            //Checking triggers
            IF LOG30.State <> TB30.State OR LOG30.Paused <> TB30.Paused OR LOG30.LTT.Q OR xTrigLog30 THEN
                LWD := TEST_30;
    
                ManagerState := 30;
    
                LOG30.State := TB30.State;
                LOG30.Paused := TB30.Paused;
    
                IF LOG30.LTT.Q THEN
                    LOG30.LTT( IN := FALSE);
                END_IF
    
                IF xTrigLog30 THEN
                    xTrigLog30 := FALSE;
                END_IF
    
            ELSIF LOG76.State <> TB76.State OR LOG76.Paused <> TB76.Paused OR LOG76.LTT.Q OR xTrigLog76 THEN
                LWD := TEST_76;
    
                ManagerState := 30;
    
                LOG76.State := TB76.State;
                LOG76.Paused := TB76.Paused;
    
                IF LOG76.LTT.Q THEN
                    LOG76.LTT( IN := FALSE);
                END_IF
    
                IF xTrigLog76 THEN
                    xTrigLog76 := FALSE;
                END_IF
    
            END_IF
    
        30: // Write start
            TestID := 0;
    
            ManagerState := 34;
    
        34: // Check if enabled and generate name
            IF LWD[TestID].Enabled THEN
                //Generate file name
                IF LWD[TestID].Product = '' THEN
                    LWD[TestID].Product := 'UNKNOWN PRODUCT';
                END_IF
                IF LWD[TestID].ProductID = '' THEN
                    LWD[TestID].ProductID := CONCAT('UNKNOWN PRODUCT ID ', UINT_TO_STRING(TestID));
                END_IF
    
                sFileName := CONCAT(LWD[TestID].Product, ' - ');
                sFileName := CONCAT(sFileName, LWD[TestID].ProductID);
                sFileName := CONCAT(sFileName, '.csv');
    
                sTarget := CONCAT(gvl_sLogDir, sFileName);
                //sTarget  := sFileName;
                //sTarget := 'TestFile.txt';
    
                ManagerState := 36;
            ELSE
                ManagerState := 70;
            END_IF
    
        36: // Check if file exists
            udiFileSize := FILE.SysFileGetSize(sTarget, ADR(udiCmpError));
    
            IF udiFileSize = 0 THEN
                //File doesnt exist or is empty
                //Header should be created
                ManagerState := 40;
            ELSIF udiCmpError = ERR_OK THEN
                //File exists
                //File should be directly opened in Append mode
                ManagerState := 45;
            ELSE
                State_eError := FILE.ERROR.ERROR_UNKNOWN;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        40: // File doenst exist - Create file
            filop.sFileName := sTarget;
            filop.eFileMode := FILE.MODE.MRDWR;
            filop.xExclusive:= TRUE;
            filop (xExecute := TRUE );
    
            IF filop.xDone THEN
                hFile := filop.hFile;
                ManagerState := 42;
            END_IF
    
            IF filop.xError THEN
                State_eError := filop.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        42: // New file created - Write header      
            filwr.hFile:=hFile;
            filwr.pBuffer:=ADR(HeaderNames);
            filwr.szSize := INT_TO_USINT(Len(HeaderNames));
            filwr.udiTimeOut:=100000;    (* 100ms Timeout *)
            filwr( xExecute:=TRUE);
    
            IF filwr.xDone THEN
                ManagerState := 49;
                filwr (xExecute := FALSE);
            END_IF
    
            IF filwr.xError THEN
                State_eError := filwr.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        45: // File exists open in MAPPD
            filop.sFileName := sTarget;
            filop.eFileMode := FILE.MODE.MAPPD;
            filop (xExecute := TRUE );
    
            IF filop.xDone THEN
                hFile := filop.hFile;
                ManagerState := 50;
            END_IF
    
            IF filop.xError THEN
                State_eError := filop.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        49: // Reset write FB
            filwr(xExecute := FALSE);
            IF NOT filwr.xBusy AND NOT filwr.xDone THEN
                ManagerState := 50;
            END_IF 
    
        50: // Generate data
            sYear := Mid(gvl_DT_string, 4, 4);
            sMonth:= Mid(gvl_DT_string, 2, 9);
            sDay  := Mid(gvl_DT_string, 2, 12);
    
            sHour := Mid(gvl_DT_string, 2, 15);
            sMinute:=Mid(gvl_DT_string, 2, 18);
            sSecond:=Mid(gvl_DT_string, 2, 21);     
    
            sRaw := '';
            sRaw := CONCAT(sDay, sDaySep);
            sRaw := CONCAT(sRaw, sMonth);
            sRaw := CONCAT(sRaw, sDaySep);
            sRaw := CONCAT(sRaw, sYear);
            sRaw := CONCAT(sRaw, ' ');
            sRaw := CONCAT(sRaw, sHour);
            sRaw := CONCAT(sRaw, sTimSep);
            sRaw := CONCAT(sRaw, sMinute);
            sRaw := CONCAT(sRaw, sTimSep);
            sRaw := CONCAT(sRaw, sSecond);
            sRaw := CONCAT(sRaw,';');
    
            sRaw := CONCAT(sRaw,StateText(LWD[TestID].TestState));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,BOOL_TO_STRING(LWD[TestID].TestPaused));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,INT_TO_STRING(LWD[TestID].TestCounterA));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,TIME_TO_STRING(LWD[TestID].RunTimeStrokeA));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,TIME_TO_STRING(LWD[TestID].RunTimeTotalA));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,INT_TO_STRING(LWD[TestID].TestCounterB));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,TIME_TO_STRING(LWD[TestID].RunTimeStrokeB));
            sRaw := CONCAT(sRaw,';');
            sRaw := CONCAT(sRaw,TIME_TO_STRING(LWD[TestID].RunTimeTotalB));
            sData := CONCAT(sRaw,'$R$N');
    
            ManagerState := 55;
    
        55: // Write data
            filwr.hFile:=hFile;
            filwr.pBuffer:=ADR(sData);
            filwr.szSize := INT_TO_USINT(Len(sData));
            filwr.udiTimeOut:=100000;    (* 100ms Timeout *)
            filwr( xExecute:=TRUE);
    
            IF filwr.xDone THEN
                ManagerState := 60;
                filwr (xExecute := FALSE);
            END_IF
    
            IF filwr.xError THEN
                State_eError := filwr.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        60: // Writing done, close file
            filcl.hFile := hFile;
            filcl( xExecute := TRUE );
    
            IF filcl.xDone THEN
                ManagerState := 61;
            END_IF
    
            IF filcl.xError THEN
                State_eError := filcl.eError;
                ErrorAtState := ManagerState;
                ManagerState := 90;
            END_IF
    
        61: // Round up file writing
            filop(xExecute := FALSE);
            filcl(xExecute := FALSE);
            filwr(xExecute := FALSE);
    
            IF NOT filop.xBusy AND NOT filop.xDone AND
             NOT filcl.xBusy AND NOT filcl.xDone AND
             NOT filwr.xBusy AND NOT filwr.xDone THEN
                ManagerState := 70;
            END_IF
    
        70: // Next item state or end cycle
            TestID := TestID + 1;
            IF TestID < MaxID THEN
                ManagerState := 34;
            ELSE
                ManagerState := 20;
            END_IF
    
        90: // Error state
            POU_ERROR := TRUE;
    END_CASE
    
     
  • aliazzz

    aliazzz - 2020-06-08

    Thanks for posting this! Would you mind if I submit this into the code snippet corner? As this seems a good snippet for it

     

Log in to post a comment.