Writing Variables to Flash
TurnipTruck
Junior Member
Greetings,
I would like to start writing variables to flash memory of Netlinx masters. Could someone give me a few pointers?
Let say I have an integer varaible of 50 bytes, nVaraible
I would like to write it to the memory during the course of program running then be able to retreive it at a startup.
Thanks!
I would like to start writing variables to flash memory of Netlinx masters. Could someone give me a few pointers?
Let say I have an integer varaible of 50 bytes, nVaraible
I would like to write it to the memory during the course of program running then be able to retreive it at a startup.
Thanks!
Comments
-
Simply making it persistent achieves that I believe.
Alternatively use file_open, file_write_line, file_read_line, file_close. -
As indicated you can use File system (excepted if these variables change often as there is a little delay to read/write to file than memory
But it works well and easily with STRING_TO_VARIABLE and VARIABLE_TO_STRING so you don't need to care how to encode/decode your variables or structures to save them on disk and read them from disk 
Something about PERSISTENT is that it doesn't work in modules
Only in main program 
Vince -
I should have been more specific. The values of this variable are created in a module and therfore cannot be persistent. This is why I am wanting to save to disk.
Thanks. -
TurnipTruck wrote:I should have been more specific. The values of this variable are created in a module and therfore cannot be persistent. This is why I am wanting to save to disk.
So you can do something like that to get back content of your structure from your file at startup:
File_Index = FILE_OPEN('RSS_News_Reader_Feeds.backup',FILE_READ_ONLY) // Open File in Read Only Mode
IF (File_Index > 0) // File exists with content of structure so we read it
{
FILE_READ(File_Index,Buffer_Feeds,MAX_LENGTH_STRING(Buffer_Feeds)) // Read data from file and put it in buffer
STRING_TO_VARIABLE(Feeds_Bookmark,Buffer_Feeds,1) // Put data back from buffer in structure
FILE_CLOSE(File_Index) -
I just happened to be converting old files to work on XM module to hold preset values this morning so I pulled out the apllicable files.
There's a function in a button event to initate write the file to RAM which I usually put on the "EXIT" device button and another function in the devices data_event to read when the device comes online. I haven't tested this to see if this is where it should be for this device but that's where it is now.
This should almost be plug and play once you change names around.PROGRAM_NAME='Read_N_Write_RAM' (***********************************************************) (* FILE_LAST_MODIFIED_ON: 04/14/2007 AT: 12:48:07 *) (***********************************************************) DEFINE_DEVICE dvXM = 5001:4:0 // Serial Port dvTP_XM = 10001:12:0 // Touch Panel vdvXM = 41004:1:0 // Virtual Device for Read N Write buffer "only" DEFINE_CONSTANT (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*) (*( FILENAME TO USE WHEN WRITING TO RAM )*) (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*) CHAR XM_XML_FILENAME[] = 'XM_STRUCTURE_DATA.xml' ; (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*) (*( BUFFER LENGHT TO HOLD XML READ & WRITE DATA )*) (*(VAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAVAV)*) LONG XM_READ_BUFLENGTH = 25000 ; DEFINE_TYPE structure sXM_PresetData { INTEGER XMChNum ; CHAR XMCategory[18] ; CHAR XMChName[18] ; } structure sXM_Zone { INTEGER XMChNum ; CHAR XMCategory[18] ; CHAR XMChName[18] ; CHAR XMArtist[18] ; CHAR XMSong[18] ; INTEGER XMPower ; INTEGER XMSigLVL ; INTEGER XMMute ; INTEGER XMMode ; CHAR XMXID[8] ; sXM_PresetData XMPreData[10] ; } structure sXM_Sent { INTEGER XMChNum ; CHAR XMCategory[18] ; CHAR XMChName[18] ; CHAR XMArtist[18] ; CHAR XMSong[18] ; INTEGER XMPower ; INTEGER XMSigLVL ; INTEGER XMMute ; INTEGER XMMode ; CHAR XMXID[8] ; sXM_PresetData XMPreData[10] ; } DEFINE_VARIABLE VOLATILE sXM_Zone sXMZone[3] ; VOLATILE sXM_Sent sXMSent[3] ; VOLATILE sXM_PresetData XMPreData ; VOLATILE INTEGER nXM_DeBug ; VOLATILE CHAR cXM_Var_to_XML ; DEFINE_FUNCTION CHAR fnXM_FileWrite_ToFile(CHAR iWriteFileName[],CHAR iWriteFileBuf[]) //filename //buffer containing data to write { stack_var slong nWriteFHandle ; stack_var slong nWriteFResult ; nWriteFHandle = file_open(iWriteFileName,FILE_RW_NEW) ; if (nWriteFHandle > 0) { if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnFileWrite_ToFile. File_Open successful for *', iWriteFileName,'*! line-<',ITOA(__LINE__),'>',crlf" ; } nWriteFResult = FILE_WRITE (nWriteFHandle,iWriteFileBuf,length_string(iWriteFileBuf)) ; if (nWriteFResult > 0) { if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnFileWrite_ToFile. File_Write OK. Wrote a ', itoa(nWriteFResult), ' CHAR String! line-<',ITOA(__LINE__),'>',crlf" ; } } else { stack_var char cErrorMsg [20] ; switch (itoa(nWriteFResult)) { case '-11': {cErrorMsg = 'disk full'} ; case '-5' : {cErrorMsg = 'disk I/O error'} ; case '-1' : {cErrorMsg = 'invalid file handle'} ; case '-0' : {cErrorMsg = 'zero bits returned?'} ; } if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnFileWrite_ToFile. Bad File_Write_Line: ',cErrorMsg, '! line-<',ITOA(__LINE__),'>',crlf" ; } } file_close(nWriteFHandle) ; } else { stack_var char cErrorMsg [40] ; switch (itoa(nWriteFHandle)) { case '-2': {cErrorMsg = 'invalid file path or name'} ; case '-5': {cErrorMsg = 'disk I/O error'} ; case '-3': {cErrorMsg = 'invalid value supplied for IOFlag'} ; } if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnFileWrite_ToFile. Bad File_Open: ',cErrorMsg, '! line-<',ITOA(__LINE__),'>',crlf" ; } } file_close(nWriteFHandle) ; RETURN TRUE ; } DEFINE_FUNCTION INTEGER fnXM_FileRead(CHAR icReadFile[]) { STACK_VAR SLONG nReadFHandle ; STACK_VAR SLONG nReadFResult ; nReadFHandle = file_open(icReadFile,FILE_READ_ONLY) ; if (nReadFHandle > 0) { if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnReadFile. File_Open successful for *', icReadFile,'*! line-<',ITOA(__LINE__),'>',crlf" ; } nReadFResult = file_read(nReadFHandle,cXM_Var_to_XML,XM_READ_BUFLENGTH) ; if (nReadFResult > 0) { if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnReadFile. File_Read OK. Rcvd: a ', itoa(length_string(cXM_Var_to_XML)), ' CHAR String! line-<',ITOA(__LINE__),'>',crlf" ; } } else { stack_var char cErrorMsg [20] ; switch (itoa(nReadFResult)) { case '-9': {cErrorMsg = 'end-of-file reached'} ; case '-6': {cErrorMsg = 'invalid parameter'} ; case '-5': {cErrorMsg = 'disk I/O error'} ; case '-1': {cErrorMsg = 'invalid file handle'} ; case '-0': {cErrorMsg = 'zero bits returned?'} ; } if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnReadFile. Bad Read_File: ',cErrorMsg, '! line-<',ITOA(__LINE__),'>',crlf" ; } RETURN FALSE ; } file_close(nReadFHandle) ; } else { stack_var char cErrorMsg [40] ; switch (itoa(nReadFHandle)) { case '-2': {cErrorMsg = 'invalid file path or name'} ; case '-5': {cErrorMsg = 'disk I/O error'} ; case '-3': {cErrorMsg = 'invalid value supplied for IOFlag'} ; } if (nXM_DeBug) { SEND_STRING 0,"'FUNCTION fnReadFile. Bad Open_File: ',cErrorMsg, '! line-<',ITOA(__LINE__),'>',crlf" ; } RETURN FALSE ; } file_close(nReadFHandle) ; RETURN TRUE ; } DEFINE_FUNCTION fnXM_StoreData_XML() { STACK_VAR SINTEGER nXML_Encode_Return ; STACK_VAR LONG nXM_EncodePOS ; STACK_VAR CHAR cXML_MSG[100] ; nXM_EncodePOS = 1 ; nXML_Encode_Return = VARIABLE_TO_XML(sXMZone,cXM_Var_to_XML,nXM_EncodePOS,0 ) ; if (nXM_DeBug) { switch (itoa(nXML_Encode_Return)) { case '-1': {cXML_MSG = 'ERROR -1 = decode variable type mismatch' } ; case '-2': {cXML_MSG = 'ERROR -2 = decode data too small, decoder ran out of data. Most likely poorly formed XML.' } ; case '-3': {cXML_MSG = 'ERROR -3 = output character buffer was too small' } ; case '3' : {cXML_MSG = 'ERROR 3 = XML decode data type mismatch' } ; case '2' : {cXML_MSG = 'ERROR 2 = XML decode data too small, more members in structure' } ; case '1' : {cXML_MSG = 'ERROR 1 = structure too small, more members in XML decode string' } ; case '0' : {cXML_MSG = 'Returned 0 = decoded OK! ' } ; } SEND_STRING 0,"'XM_Module: XML Loading: ',cXML_MSG,' Line-<',ITOA(__LINE__),'>',crlf" ; } fnXM_FileWrite_ToFile(XM_XML_FILENAME,cXM_Var_to_XML) ; CLEAR_BUFFER cXM_Var_to_XML ; } DEFINE_FUNCTION CHAR fnXM_LoadStartingValues() { STACK_VAR SLONG nXM_READ_OK ; nXM_READ_OK = fnXM_FileRead(XM_XML_FILENAME) ; if (nXM_READ_OK) { stack_var sinteger nXML_Decode_Return ; stack_var char cXML_MSG[100] ; stack_var long nXM_POS ; if (nXM_DeBug) { SEND_STRING 0,"'XM_Module: Loading RAM FILES: Line-<',ITOA(__LINE__),'>',crlf" ; } nXM_POS = 1 ; nXML_Decode_Return = XML_TO_VARIABLE (sXMZone,cXM_Var_to_XML,nXM_POS,0) ; if (nXM_DeBug) { switch (itoa(nXML_Decode_Return)) { case '-1': {cXML_MSG = 'ERROR -1 = decode variable type mismatch' } ; case '-2': {cXML_MSG = 'ERROR -2 = decode data too small, decoder ran out of data. Most likely poorly formed XML.' } ; case '-3': {cXML_MSG = 'ERROR -3 = output character buffer was too small' } ; case '3' : {cXML_MSG = 'ERROR 3 = XML decode data type mismatch' } ; case '2' : {cXML_MSG = 'ERROR 2 = XML decode data too small, more members in structure' } ; case '1' : {cXML_MSG = 'ERROR 1 = structure too small, more members in XML decode string' } ; case '0' : {cXML_MSG = 'Returned 0 = decoded OK! ' } ; } SEND_STRING 0,"'XM_Module: XML Loading: ',cXML_MSG,' Line-<',ITOA(__LINE__),'>',crlf" ; } } //else //if you create default settings // { // fnXM_Load_Defaults('BAD_XML') ; // } CLEAR_BUFFER cXM_Var_to_XML ;// use if global VAR or LOCAL is used!! RETURN TRUE ; } DEFINE_START CREATE_BUFFER vdvXM,cXM_Var_to_XML ; DEFINE_EVENT DATA_EVENT [dvXM] { ONLINE: { SEND_COMMAND dvXM,"'SET BAUD 9600,N,8,1 485 DISABLE'" ; SEND_STRING dvXM,"'UN1',CRLF" ;//enable unsolicited responses. if (nXM_DeBug) { SEND_STRING 0,"'dvXM is online! Line-<',ITOA(__LINE__),'>',crlf" ; } fnXM_LoadStartingValues() ; wait 700 { fnXM_InitialQuery(nXM_Zone) ; } } STRING: { // } } BUTTON_EVENT[dvTP_XM,nXM_BtnArry] { PUSH: { //I usually put his it an exit device button fnXM_StoreData_XML() ; } HOLD[5,REPEAT]: { //stuff } RELEASE: { //stuff } } -
I change the code in the last post. In the replaced code I used STACK_VARS to hold the encoded and decoded data which didn't work so I went back to what did work which is a GLOBAL which I made into a buffer using CREATE_BUFFER to hold large amount of data. I thought because this wasn't an input buffer assigned to a port a STACK_VAR would work but it didn't. I created the buffer using a virtual device that has no purpose other than to create this buffer.
The function "fnXM_FileRead(CHAR icReadFile[])" doesn't appear to do any thing in this example so don't let it confuse you. I just grabbed it while getting other stuff.
Any way with the change from STACKS back to a created buffer it's decoding properly so now it's almost plug and play. -
TurnipTruck wrote:The values of this variable are created in a module and therfore cannot be persistent.
Fair enough, but you *can* use persistent variables in a module, you just can't declare them in the module. You have to pass them through the module header.
As adding a new variable is such a pain when you pass it through the header, I use a large generic array so that the header never changes and you can just add a subscript constant to an include file to refer to a new variable. -
NMarkRoberts wrote:Fair enough, but you *can* use persistent variables in a module, you just can't declare them in the module. You have to pass them through the module header.
As adding a new variable is such a pain when you pass it through the header, I use a large generic array so that the header never changes and you can just add a subscript constant to an include file to refer to a new variable.
Excepted you can't do that with structure :-( -
vincen wrote:Excepted you can't do that with structure :-(
Yep, that's why you have to use a single generic array instead if you don't want to change the module header all the time.. -
I've come to the conclusion it's far more efficient using a persistent variable as a parameter than bothering to write it to flash and restore it every time. I personally don't mind changing the module header if the structure of the variable changes, but I can see the value in using a generic array too.
However, I will write to flash if I have a large amount of data to store, or to log events. -
DHawthorne wrote:I've come to the conclusion it's far more efficient using a persistent variable as a parameter than bothering to write it to flash and restore it every time. I personally don't mind changing the module header if the structure of the variable changes, but I can see the value in using a generic array too.
However, I will write to flash if I have a large amount of data to store, or to log events.
Good point. As I'm new to writing modules, I'm loving the fact that they can be droppoed right into a program without modifying declarations in any way. But, it seems reasonable to pass in the occasional variable that needs to be persistent. -
DHawthorne wrote:I personally don't mind changing the module header if the structure of the variable changes
Plan A:
a) Declare the new variable in the mainline in as many instances as you need, all with different names.
b) Add it to each of the module instance declarations in the mainline, making sure you get the different spellings right and you put them in the same place each time.
c) Add it to the module header, deciding whether you want to use the same naming, and ensuring that you declare it in the same way, and you put it in the right place.
d) Write the code that uses it, ensuring that you use the internal name not the external name if they are different.
Plan B:
a) Add a constant to your general include file which is a subscript to the generic array.
b) Write the code that uses it.
Plan A isn't that arduous but I found when building a large multi-room project (80 rooms in a dozen phases) that incrementally grew (sometimes the best way to build large projects) that I was endlessly adding configuration variables (sounds iffy but it was fine) and Plan B was much more likely to compile first time and work first time so I could get on with the important stuff.
Of course you do need wrapper code for your generic array, but you only have to write that once.
Categories
- All Categories
- 2.5K AMX General Discussion
- 922 AMX Technical Discussion
- 514 AMX Hardware
- 502 AMX Control Products
- 3 AMX Video Distribution Products
- 9 AMX Networked AV (SVSI) Products
- AMX Workspace & Collaboration Products
- 3.4K AMX Software
- 151 AMX Resource Management Suite Software
- 386 AMX Design Tools
- 2.4K NetLinx Studio
- 135 Duet/Cafe Duet
- 248 NetLinx Modules & Duet Modules
- 57 AMX RPM Forum
- 228 MODPEDIA - The Public Repository of Modules for Everyone
- 943 AMX Specialty Forums
- 2.6K AMXForums Archive
- 2.6K AMXForums Archive Threads
- 1.5K AMX Hardware
- 432 AMX Applications and Solutions
- 249 Residential Forum
- 182 Tips and Tricks
- 146 AMX Website/Forums
