Welcome to our new forum
All users of the legacy CODESYS Forums, please create a new account at account.codesys.com. But make sure to use the same E-Mail address as in the old Forum. Then your posts will be matched. Close

CmpApp library and the "AppStoreRetainsInFile" function

patrik
2022-01-18
2023-04-17
  • patrik - 2022-01-18

    I'm having problems with using the "AppStoreRetainsInFile" function. specificity using the function in a program with multiple applications. when I use it on the main application it works and returns 0 in the result tag. but when I use it on one of the child application it doesn't seem to work and return 2. What does the return code mean? does it correspond to the table in the "CmpErrors2 interfaces" library? then it means "Invalid parameter for this operation" but I can't figure out what I am doing wrong.

    here is the test version of the code I'm trying to run. it is based on the application manager program example found on CoDeSys forge.

    VAR
        fbDelete            : FILE.Delete; (* Function block to delete the file *)
        (* The retain file <application-name>.ret is placed in the directory of the bootproject *)
        sFileName           : STRING := 'Mod3.ret';
        pApp                : POINTER TO APPLICATION;
        Result              : RTS_IEC_RESULT; (* Result code *)
        Result2             : RTS_IEC_RESULT; (* Result code *)
        Result3             : RTS_IEC_RESULT; (* Result code *)
        Result4             : RTS_IEC_RESULT; (* Result code *)
        xInit               : BOOL;
        test1               : BOOL;
        test2               : BOOL;
        test3               : BOOL;
        test4               : BOOL;
        teststring          : string;
    END_VAR
    
    (* The retain variables are stores in a file and get retrieved afterwards. *)
    IF NOT xInit AND test1 THEN
    
        (* First delete the retain file.
           This is necessary, because the function AppStoreRetainsInFile appends the data at the end of the file. *)
        fbDelete(xExecute:=TRUE, sFileName:=sFileName);
        IF fbDelete.xDone OR (fbDelete.xError AND fbDelete.eError = FILE.ERROR.NOT_EXIST) THEN
            (* Attention: It takes at least one cycle until xDone is TRUE *)
            fbDelete(xExecute:=FALSE);
            xInit := TRUE;
            (* Now, it's the time to save the retains. *)
            pApp := AppFindApplicationByName('Mod2', ADR(Result));
            IF pApp <> 0 THEN
                (* Store the variables in a file*)
                Result2 := AppStoreRetainsInFile(pApp,sFileName);
            END_IF
        END_IF
    END_IF
    
    (* Restore the Retain Variables from the file.
       For storing and restoring, the same pointer to application (pApp) must be used.*)
    IF test2 THEN   
        Result3 := AppRestoreRetainsFromFile(pApp, sFileName);
        test2 := FALSE;
    END_IF;
    

    If I change the string in the "AppFindApplicationByName" function to 'Site' and change the sFileName to 'Site.ret' it works and the "AppStoreRetainsInFile" returns 0. this is my main application. in that application I have 4 child applications. Mod2, Mod3, Mod4 and Mod5. if I do the same with them the "AppStoreRetainsInFile" function returns 2. It should not a problem with the "AppFindApplicationByName" function because it successfully finds the pointer to the application.

    is there any documentation about the CmpApp library? What does the 2 mean? thanks in advance!

     
  • matthew - 2022-01-20

    Hi Patrik,

    Did you get everything working?
    I have been trying to get it to work but doesn't seem to be working correctly for me.
    It returns 0 saying everything was fine and no errors but does not seem to save the retain value when I restart the CodeSys runtime or with power loss the retain value is not restored and the old value from a correct shutdown is returned.

    Thanks,
    Matthew

     
  • patrik - 2022-01-21

    Hello!
    sorry about the late answer.

    I have not gotten it to work yet. however it sounds like it is working for you. if the function returns 0 then it should mean that it works. To get the saved values back you have to use the "AppRestoreRetainsFromFile" function as far as I know. Try using that.

     
    • matthew - 2022-01-21

      Hi Patrik,

      Thanks for the reply. I do have this "Result := AppRestoreRetainsFromFile(pApp, sFileName);" Is this not correct way?
      I'm using the exact example from ApplicationManager.
      All I have changed is the .ret file name to Application.ret as that's what it's called on the RPI in "/var/opt/codesys/PlcLogic/Application/Application.ret"

      Thanks,
      Matthew

       
    • matthew - 2022-01-21
       

      Last edit: matthew 2022-01-21
  • patrik - 2022-01-24

    Hi Matthew!

    If I interpret the code right. The example from the ApplicationManager program saves the persistant to a file when it detects "firstscan". This is not what I want of the program and I think it's not the function you are looking for either. I wan't it to run the restore from file when it detects that persistant vars has been lost. I've made it so my program tries to save to file each 10 sec or so. that way the data should be quite fresh when I want to restore from file. If this is a good way to do it or even the right way, I don't know.

     
    • matthew - 2022-01-24

      Hi Patrik,

      I did try with my own save button as a test. I think my issue could be reading the file back. Or it's just not writing to the file correctly. If I restart the CodeSys service after saving it should read that .ret file, but it's just reading the old original file. Maybe if I back up the file and remove it and see if it will create a new file or create a blank file and see if any data is being stored.

      My Plan was the store all my retain variables for the parameters/setpoints etc in a struct and monitor the struct for any changes in values and then trigger the save automatically using the AppRetain. But I can't even get a simple test to work correctly. So hopefully someone who has been down this track can shed some light on this issue.

       
      • patrik - 2022-01-24

        Can you post your code and I can see if I can help.
        I think my problem is related to the functions having issues with child applications.

         
  • eschwellinger

    eschwellinger - 2022-01-25

    Hi,
    I try to explain, the persistence/retain feature:
    Usually if you do nothing in your application and you shutdown your plc graceful( not just poweroff), this means Linux shutdown or - you have for example a UPS connected, Application.ret will be written by tthe runtime, no need to call anything.
    on next restart the Application.ret will be loaded with the bootproject on startup.
    This is how retains in generell work.

    Now if you trigger this 'save retains' from the application to application.ret it might that these interact with the in background working feature.
    Try to save the retains with another name.ret, and recover them on startup of your application.

    Altough the proper solution is to have a UPS and a graceful shutdown. Then no need to do anything with this function and additional you protect your OS against damage on the SD card/flash, makes it more robust against the ' I could not start my OS because filesystem is corrupt' problem.

     
    • matthew - 2022-01-25

      Hi eschwellinger,

      Thanks for the response. I have read through the other threads and understand the risks. I have used UPS Hats in the past for my other RPI projects with no issues. The problem with this project is it uses the RPI4 Compute module in a touch screen.

      https://chipsee.com/product/industrial-pi-cm4-70-pa/

      The screen does not use an SD but has EMMC memory ( my understanding a bit more robust memory ) There is no UPS available nor built into the screen. I do have a shutdown button for the system to be shutdown correctly. The issue is the supply of electricity is unreliable with regular outages. So I need to make sure any changes to the setpoints etc are saved.

      I have the AppRetain working but not reliable, maybe works every 1 in 5 times. I have also been using Sudo Sync and sudo sync -f /var/opt/codesys/PlcLogic/Application this seems to help a bit but not every time. I will try your recommendations of using a different file name and see how I get on. Note: I only plan to save to the disk if the value of the setpoint changes. I have also tried the Persistence Manager without success ( would only work the odd time )

      Thanks,
      Matthew

       
    • patrik - 2022-01-25

      Hi!

      Thanks for the response. My problem also originates from unreliable power with regular outages. The best solution would be a working UPS but we have tried to get the customer to use it but with no success. This is a work around more or less. If I can save the data in regular intervals then the problem would be solved. I will try to save it to a different file name.
      but to my original question of the return value of the function. what does 2 mean? is it

      ERR_PARAMETER   UDINT   16#2    Invalid parameter for this operation
      

      from the CmpErrors2 interfaces lib?

      Thanks in advance!

       
      • matthew - 2022-01-25

        Hi Patrik,

        I also get the 2 but only after "sudo service codesyscontrol restart" and when I use the save button via webvisu the execution is correct and returns 0.

        From my testing I have to wait on average for 2 minutes for the .ret file to save ( may still be in ram during this time ) Sometimes it will be fine in 10 secs or 30 sec but will still fail at times even after waiting 90 sec so to be save if I wait 120+ sec it seems to work every time. I have tried the sudo sync commands etc but does not seem to help. The Log shows no faults. I don't know what format the .ret is or if there is a way to read the .ret to see if the file is being written to the SD card etc. I will post my code below.

        PROGRAM AppRetain
        
        VAR
            fbDelete            : FILE.Delete; (* Function block to delete the file *)
            (* The retain file <application-name>.ret is placed in the directory of the bootproject *)
            sFileName           : STRING := 'ApplicationTest.ret'; //  /var/opt/codesys/PlcLogic/Application
            pApp                : POINTER TO APPLICATION;
            Result              : RTS_IEC_RESULT; (* Result code *)
            xInit               : BOOL;
            SaveButton          : BOOL;
            ReadButton          : BOOL;
        END_VAR
        
        (* The retain variables are stores in a file and get retrieved afterwards. *)
        IF NOT xInit AND SaveButton THEN
            (* First delete the retain file.
               This is necessary, because the function AppStoreRetainsInFile appends the data at the end of the file. *)
            fbDelete(xExecute:=TRUE, sFileName:=sFileName);
            IF fbDelete.xDone OR (fbDelete.xError AND fbDelete.eError = FILE.ERROR.NOT_EXIST) THEN
                (* Attention: It takes at least one cycle until xDone is TRUE *)
                fbDelete(xExecute:=FALSE);
                xInit := TRUE;
                (* Now, it's the time to save the retains. *)
                pApp := AppGetCurrent(pResult:=ADR(Result));
                IF pApp <> 0 THEN
                    (* Store the variables in a file*)
                    Result := AppStoreRetainsInFile(pApp,sFileName);
                    xInit := FALSE;
                END_IF
            END_IF
        END_IF 
        
        IF ReadButton THEN
            (* Restore the Retain Variables from the file.
            For storing and restoring, the same pointer to application (pApp) must be used.*)
            Result := AppRestoreRetainsFromFile(pApp, sFileName); 
        END_IF
        
         
      • matthew - 2022-01-26

        Hi Patrik,

        I have everything working well now using a different method posted in another forum.
        https://forge.codesys.com/forge/talk/Engineering/thread/1f8eee253c/
        This works perfect and is instant. I point the FB MemLocation to the ADR of a Struct. In the struct I have a bunch of different data types and variables, all of them work well. For the length I make sure it is more than all the data types and variables ( Real is 8 bytes and Int is 4 bytes etc ) Note: Under Application settings You have to enable "Use dynamic memory allocation" and set the maximum size of memory.
        Hope this helps you out and a big thanks to arj3090.

         
  • murdemon - 2023-04-15

    Have problem with AppStoreRetainsInFile, AppRestoreRetainsFromFile function. All time return
    ERR_OPERATION_DENIED.
    Maybe need add something in Codesys Config file (/etc/CODESYSControl_User.cfg) to make it accessible ? Using ARM SL 4.7.0.0 Runtime.

     
  • kislov - 2023-04-16

    I think you need use file placeholders ($$PlcLogic$$/Application/...) instead of direct filepath.

     

    Last edit: kislov 2023-04-16
  • murdemon - 2023-04-17

    yes thanks this is help.

     

Log in to post a comment.