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
It works but is anoying and when unsuspected shutdown happens right in middle saving writes 000 to file.
how to handle auto save variables?
BR
Alex
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Anonymous
-
2016-01-02
Originally created by: crthomas1234
I am also interested in the answer to Alex's question.
The PLC I use does not have a lot of persistent retain memory, so I use the recipe system to backup and restore system parameters on a machine power cycle. This is also really helpful during the development stage when you are making a lot of changes to the PLC and a full download erases your retain memory.
What we have done for now is to create a function block and reads the name of each variable in the recipe file and then use the IEC Var Access library to request that variable's value by its name. I can then walk through the entire recipe file and if any value has changed, I can initiate the recipe save. I did this because if you were to just save the recipe file every minute or so, you would eventually render the flash memory in the controller unusable due to the limited number of writes you can have.
The downside of this method is that you cannot actually get the actual variable name from the recipe. Instead, there is a column for the user to type in their own descriptive name which can be accessed through the IEC program. So for every variable that I add to the recipe system, I must copy and paste the variable name including the full path in the "name" column of the recipe file for this to work. And since you can't copy/paste in the recipe editor or export to some sort of text file, this is very labor intensive in the beginning.
I would love to ask an extension to the RecipeManCommand function block that would automate looking at the values or the recipe file versus the current values to know if they are different so you can initiate the save.
The save changes to recipes option Alex mentioned sounds like it would do this, but I think it is for something different such as actual changes to the definition, not the actual recipe values.
I have read the help files over and over again trying to understand how the recipe system works. It sort of makes sense to me and through a lot of trial and error, I have gotten the system to work as I need it too.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
But, I did find where someone had posted enough information about saving retentive memory that I was able to get store / restore working around startup.. it was necessary as we've written apps on the raspberry pi..
It could use a little 'clean up', but its getting the job done. Notice also that I use it to initiate a controlled shutdown rather than just powering off the device.
I created a separate task, which runs this:
PROGRAMpersistentStorageVAR
  command1     : STRING :='sudo halt';
  stdout       : STRING(1000) :=''; Â
  result       : RTS_IEC_RESULT;
  doRetain        : FB_AppRetain;
  T_restoreAlarm      : TON;
  doSync      : BOOL;END_VAR//handlesaveofretainedmemorytodisk: /var/opt/codesys/PlcLogic/Application/estacada.retdoRetain(  store :=GVL.doSavePersist,
      restore :=GVL.doRestorePersist,
      shutdown :=GVL.doShutDown,
      busy=>GVL.pmBusy,
      done=>GVL.pmDone,
      error=>GVL.pmError,
      result=>GVL.pmResult);
     Â
//Saveretainedmemorycomplete, syncthefilesystemwiththeSDCardIF(GVL.doSavePersistAND(GVL.pmDoneORGVL.pmError))THEN
  GVL.doSavePersist  :=  FALSE;
  doSync  :=  GVL.pmDone;END_IF//restorepersistentmemoryuponstartupIF((GVL.iPersistState=0)ANDNOTGVL.doRestorePersist)THEN
  GVL.doRestorePersist  :=  TRUE;END_IF//Restoreretainedmemorycomplete, letthesystemknowitcanproceedIF(GVL.doRestorePersistANDGVL.pmDone)THEN
  GVL.doRestorePersist :=FALSE;
  GVL.iPersistState  :=  1;END_IF//Attention: allowshellcommandsinCODESYSControl.cfg-presentlyAllowAllIF(doSync)THEN
  doSync  :=  FALSE;
  command1  :=  'sudo sync'; Â
  SysProcess._(pszCommand:=command1, pszStdOut:=stdout, udiStdOutLen:=SIZEOF(stdout),pResult :=ADR(result));END_IF//Attention: allowshellcommandsinCODESYSControl.cfgIF(GVL.doShutDownANDNOT(GVL.doSavePersistORGVL.doRestorePersist))THEN
  GVL.doShutDown :=FALSE;
  command1  :=  'sudo halt'; Â
  SysProcess._(pszCommand:=command1, pszStdOut:=stdout, udiStdOutLen:=SIZEOF(stdout),pResult :=ADR(result));END_IF//SignaltoalarmprocessingthatrestorehasfailedT_restoreAlarm(IN :=GVL.doRestorePersist, PT :=T#3S);IF(T_restoreAlarm.Q)THEN
  GVL.doRestorePersist :=FALSE;
  GVL.iPersistState :=2;  // lie after warning the operatorEND_IF//end
The function block that it calls is this:
FUNCTION_BLOCKÂ FB_AppRetainVAR_INPUT
  store        : BOOL;
  restore      : BOOL;
  shutdown      : BOOL;END_VARVAR_OUTPUT
  done        : BOOL;
  busy        : BOOL;
  error        : BOOL;
  result      : RTS_IEC_RESULT;END_VARVAR
  fbDelete      : FILE.Delete; (* Function block to delete the file *)
  (*Theretainfile<application-name>.retisplacedinthedirectoryofthebootproject*)
  sFileName      : STRING :='/var/opt/codesys/PlcLogic/Application/estacada.ret';
  pApp        : POINTERTOAPPLICATION;
  step        : INT :=0;
  R_store        : R_TRIG;
  R_restore      : R_TRIG;
  F_store        : F_TRIG;
  F_restore      : F_TRIG;END_VAR//RETAINmemoryissavedto/var/opt/codesys/PlcLogic/Application/estacada.retR_store(CLK :=store);R_restore(CLK :=restore);F_store(CLK :=store);F_restore(CLK :=restore);//finished, oraborted?
IF(F_store.QORF_restore.Q)THEN
  step  :=  0;
  busy  :=  FALSE;
  error  :=  FALSE;
  done  :=  FALSE;END_IFCASEstepOF
 Â
  0:  //beginretainedmemorystoretofile
    IF(R_store.QANDNOT(restoreORshutdown))THEN
      step  :=  10;
      busy  :=  TRUE;
      error  :=  FALSE;
      done  :=  FALSE;
    END_IF
    //restoreretainedmemoryfromfile
    IF(R_restore.QANDNOT(storeORshutdown))THEN
      step  :=  20;
      busy  :=  TRUE;
      error  :=  FALSE;
      done  :=  FALSE;
    END_IF
  10: (*  Firstdeletetheretainfile.
        Thisisnecessary, becausethefunctionAppStoreRetainsInFileappendsthedataattheendofthefile. *)
    fbDelete(xExecute:=TRUE, sFileName:=sFileName);
    IF(   fbDelete.xDone
      OR(fbDelete.xErrorAND(fbDelete.eError=File.Error.NOT_EXIST)))THEN
 Â
      (*Attention: IttakesatleastonecycleuntilxDoneisTRUE*)
      fbDelete(xExecute:=FALSE);
      step  :=  12;  // file gone, replace it with a fresh copy
    ELSIF(fbDelete.xError)THEN
      fbDelete(xExecute:=FALSE);
      step  :=  14;  // file delete failed ugly
    END_IF
   Â
  12:  (*Now, it's the time to save the retains. *)
    pApp :=AppGetCurrent(pResult:=ADR(result));
    IFpApp<>0THEN
      (*Storethevariablesinafile*)
      result  :=AppStoreRetainsInFile(pApp,sFileName);
      error  :=  FALSE;
      busy  :=  FALSE;
      done  :=  TRUE;
      step  :=  0;
    ELSE
      step  :=  14;
    END_IF
 Â
  //somestepalongthewayfailed
  14:    error  :=  TRUE;
      busy  :=  FALSE;
      done  :=  FALSE;
      step  :=  0;
     Â
  20:  (*  RestoretheRetainVariablesfromthefile.
      Forstoringandrestoring, thesamepointertoapplication(pApp)mustbeused.*)
    pApp :=AppGetCurrent(pResult:=ADR(result));
    IFpApp<>0THEN
      result :=AppRestoreRetainsFromFile(pApp, sFileName);
      error  :=  FALSE;
      busy  :=  FALSE;
      done  :=  TRUE;
      step  :=  0;
    ELSE
      step  :=  14;
    END_IF   Â
 Â
END_CASE//END
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Why does function "Save recipe changes to files automatically" NOT work? What is the sense of this function and how is ment to be used.
I have solved my way by setting timer every 60sec to save variables to current file.
via:
It works but is anoying and when unsuspected shutdown happens right in middle saving writes 000 to file.
how to handle auto save variables?
BR
Alex
Originally created by: crthomas1234
I am also interested in the answer to Alex's question.
The PLC I use does not have a lot of persistent retain memory, so I use the recipe system to backup and restore system parameters on a machine power cycle. This is also really helpful during the development stage when you are making a lot of changes to the PLC and a full download erases your retain memory.
What we have done for now is to create a function block and reads the name of each variable in the recipe file and then use the IEC Var Access library to request that variable's value by its name. I can then walk through the entire recipe file and if any value has changed, I can initiate the recipe save. I did this because if you were to just save the recipe file every minute or so, you would eventually render the flash memory in the controller unusable due to the limited number of writes you can have.
The downside of this method is that you cannot actually get the actual variable name from the recipe. Instead, there is a column for the user to type in their own descriptive name which can be accessed through the IEC program. So for every variable that I add to the recipe system, I must copy and paste the variable name including the full path in the "name" column of the recipe file for this to work. And since you can't copy/paste in the recipe editor or export to some sort of text file, this is very labor intensive in the beginning.
I would love to ask an extension to the RecipeManCommand function block that would automate looking at the values or the recipe file versus the current values to know if they are different so you can initiate the save.
The save changes to recipes option Alex mentioned sounds like it would do this, but I think it is for something different such as actual changes to the definition, not the actual recipe values.
I have read the help files over and over again trying to understand how the recipe system works. It sort of makes sense to me and through a lot of trial and error, I have gotten the system to work as I need it too.
Anyone?
I didn't use recipes..
But, I did find where someone had posted enough information about saving retentive memory that I was able to get store / restore working around startup.. it was necessary as we've written apps on the raspberry pi..
It could use a little 'clean up', but its getting the job done. Notice also that I use it to initiate a controlled shutdown rather than just powering off the device.
I created a separate task, which runs this:
The function block that it calls is this: