Writing Variables to Flash
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!
0
Comments
Alternatively use file_open, file_write_line, file_read_line, file_close.
Something about PERSISTENT is that it doesn't work in modules
Vince
Thanks.
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)
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 } }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.
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 :-(
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..
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.
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.