Function Block to Write Persistent Variables

arj3090
2019-07-25
2019-07-26
  • arj3090

    arj3090 - 2019-07-25

    Is the a function block that forces the values of the persistent variables to be written to the disk? I am using a Raspberry Pi which does not have a UPS. My list of persistent variables is small and change infrequently, so I can monitor the values for any changes and write the values when a change occurs.

     
  • yannickasselin1

    yannickasselin1 - 2019-07-25

    Good question. I know there is one in TwinCAT but I am not aware of any function block to do it in Codesys. I would be interrested to know.

     
  • arj3090

    arj3090 - 2019-07-26

    I am guessing the requested FB does not exist, so I started creating a function block to mimc the persistent variable functionality. It requires the SysFile library. It seems kind of clunky, but works. If anyone has any improvements or better options, I am open for them. This is what I have so far

    FUNCTION_BLOCK PUBLIC fbSaveMemoryBlock
    VAR_INPUT
       Write : BOOL;               //Edge triggered
       Read : BOOL;               //Edge triggered
       MemLocation : POINTER TO BYTE;   // e.g ADR(%MB0)
       ByteLength : DWORD;            // byte count to monitor and store
       MinTimeBetweenWrites : TIME;   // Used to limit writing
    END_VAR
    VAR_OUTPUT
       WriteCount : DINT;            //Count showing number of times write was triggered
    END_VAR
    VAR
       LastWrite : BOOL;
       LastRead : BOOL;
       
       FileHandle : RTS_IEC_HANDLE;
       OpenResult: RTS_IEC_RESULT;
       WriteResult,ReadResult: RTS_IEC_RESULT;
       
       pCompare : POINTER TO BYTE;
       LastByteLength : DWORD;
       DifferenceFound : BOOL;
       index : DWORD;
       pWorking, pWorking2 : POINTER TO BYTE;
       FirstPass : BOOL;
       TimeBetweenWrites : TON;
    END_VAR
    
    (*********************************************************************************)
    (* This function block is to provide an alternative to persitent variable values *)
    (* on systems that do not have a UPS or NOVRAM                                   *)
    (* CAUTION must be used because excessive writing can damage flash memory        *)
    (* MemLocation is specified like ADR(%MB0)  or ADR(V1)                                      *)
    (* Variable values to be saved are mapped to the block starting as specified     *)
    (* by MemLocation                                                                *)
    (* A method that works, but not guaranteed is to create a GVL only for the      *)
    (* variables to be persisted. Use ADR(firstvar) and calculate the byte length of *)
    (* all the variables in the list to use in ByteLength                            *)
    (* EDIT : The method above will not work as variables are added unless a Clean All*)
    (* is done to reorganize the variable memory assignments                         *)
    (* The memory block values are monitored for changes which will trigger the write*)
    (* The writing can be limited by using the MinTimeBetweenWrites                  *)
    (* Read input can be set to TRUE to load values on first scan                    *)
    (*********************************************************************************)
    (******************************************************************************)
    (* Read the file and store in memory - rising edge triggered                  *)
    (******************************************************************************)
    IF Read AND Read<>LastRead THEN
       FileHandle:=SysFileOpen('PFile.dat',SysFile.AM_READ,ADR(OpenResult));
       
       IF OpenResult=0 THEN
          SysFileRead(FileHandle,(MemLocation),ByteLength,ADR(ReadResult));
       
          SysFileClose(FileHandle);
       END_IF
       LastRead:=Read;
    END_IF
    (******************************************************************************)
    (* Create a memory area for comparing a change in values                      *)
    (******************************************************************************)
    IF LastByteLength<>ByteLength THEN
       IF LastByteLength>0 THEN
          __DELETE(pCompare);
       END_IF
       
       pCompare := __NEW(BYTE,ByteLength);
       LastByteLength:=ByteLength;
    END_IF
    (******************************************************************************)
    (* Check for a change in values                                               *)
    (******************************************************************************)
    // Do not set PT here so that first check occurs without delsy
    TimeBetweenWrites(IN:=TRUE);
    index:=0;
    IF TimeBetweenWrites.Q THEN
       WHILE (index<ByteLength) DO
          pWorking:=pCompare+index;
          pWorking2:=MemLocation+index;
       
          IF (pWorking^ <> pWorking2^) THEN
             DifferenceFound:=TRUE;
             // Copy all values to working memory area for checking value chsnge
             pWorking^:=pWorking2^;
          END_IF
          
          index:=index+1;
       END_WHILE
       IF DifferenceFound THEN
          TimeBetweenWrites(IN:=FALSE,PT:=MinTimeBetweenWrites);
       END_IF
    END_IF
    (******************************************************************************)
    (* Write Values to the file                                                   *)
    (******************************************************************************)
    IF (Write AND Write<>LastWrite) OR (DifferenceFound AND FirstPass) THEN
       FileHandle:=SysFileOpen('PFile.dat',SysFile.AM_WRITE,ADR(OpenResult));
       
       IF OpenResult=0 THEN
          SysFileWrite(FileHandle,(MemLocation),ByteLength,ADR(WriteResult));
       
          SysFileClose(FileHandle);
       END_IF
       
       LastWrite:=Write;
       WriteCount:=WriteCount+1;
    END_IF
    DifferenceFound:=FALSE;
    FirstPass:=TRUE;
    
     
  • arj3090

    arj3090 - 2019-07-26

    Here is a sample of its use:

    IMG: SaveMemoryBlock.png

     
  • arj3090

    arj3090 - 2019-07-26

    With some more digging I did discover the function blocks to read and write retain variables do exist:

    AppStoreRetainsInFile
    AppRestoreRetainsFromFile

     

Log in to post a comment.