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.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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_BLOCKPUBLICfbSaveMemoryBlockVAR_INPUT  Write:BOOL;          //Edgetriggered  Read:BOOL;          //Edgetriggered  MemLocation:POINTERTOBYTE;  //e.gADR(%MB0)  ByteLength:DWORD;        //bytecounttomonitorandstore  MinTimeBetweenWrites:TIME;  //UsedtolimitwritingEND_VARVAR_OUTPUT  WriteCount:DINT;        //CountshowingnumberoftimeswritewastriggeredEND_VARVAR  LastWrite:BOOL;  LastRead:BOOL;    FileHandle:RTS_IEC_HANDLE;  OpenResult:RTS_IEC_RESULT;  WriteResult,ReadResult:RTS_IEC_RESULT;    pCompare:POINTERTOBYTE;  LastByteLength:DWORD;  DifferenceFound:BOOL;  index:DWORD;  pWorking,pWorking2:POINTERTOBYTE;  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         *)(******************************************************************************)IFReadANDRead<>LastReadTHEN  FileHandle:=SysFileOpen('PFile.dat',SysFile.AM_READ,ADR(OpenResult));    IFOpenResult=0THEN    SysFileRead(FileHandle,(MemLocation),ByteLength,ADR(ReadResult));      SysFileClose(FileHandle);  END_IF  LastRead:=Read;END_IF(******************************************************************************)(* Create a memory area for comparing a change in values           *)(******************************************************************************)IFLastByteLength<>ByteLengthTHEN  IFLastByteLength>0THEN    __DELETE(pCompare);  END_IF    pCompare:=__NEW(BYTE,ByteLength);  LastByteLength:=ByteLength;END_IF(******************************************************************************)(* Check for a change in values                        *)(******************************************************************************)//DonotsetPTheresothatfirstcheckoccurswithoutdelsyTimeBetweenWrites(IN:=TRUE);index:=0;IFTimeBetweenWrites.QTHEN  WHILE(index<ByteLength)DO    pWorking:=pCompare+index;    pWorking2:=MemLocation+index;      IF(pWorking^<>pWorking2^)THEN      DifferenceFound:=TRUE;      //Copyallvaluestoworkingmemoryareaforcheckingvaluechsnge      pWorking^:=pWorking2^;    END_IF        index:=index+1;  END_WHILE  IFDifferenceFoundTHEN    TimeBetweenWrites(IN:=FALSE,PT:=MinTimeBetweenWrites);  END_IFEND_IF(******************************************************************************)(* Write Values to the file                          *)(******************************************************************************)IF(WriteANDWrite<>LastWrite)OR(DifferenceFoundANDFirstPass)THEN  FileHandle:=SysFileOpen('PFile.dat',SysFile.AM_WRITE,ADR(OpenResult));    IFOpenResult=0THEN    SysFileWrite(FileHandle,(MemLocation),ByteLength,ADR(WriteResult));      SysFileClose(FileHandle);  END_IF    LastWrite:=Write;  WriteCount:=WriteCount+1;END_IFDifferenceFound:=FALSE;FirstPass:=TRUE;
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
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.
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.
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
Here is a sample of its use:
With some more digging I did discover the function blocks to read and write retain variables do exist:
AppStoreRetainsInFile
AppRestoreRetainsFromFile