Garbage when reading flash


#1

Hi guys,

I hope somebody can help me with this. I have developped an application which first reads an xml file (which I have already put inside the application root folder) and then it stores this information to flash. Lets say that the xml file contains 18 variables, I have checked the values of each variable after stored them to flash and they are ok! But when I try to read from flash, I get garbages at the end of variable “SOSContact” and at the end of variable “DevicePW” (please see code below). Instead of +306930553480 I get +306930553480cG and instead of 1230 I get 1230ULTIBAND 900E. I supposed something else was first stored there. I have chenged FLASH LOCATION and made it 10, but then when reading from flash, I get only the first eight variables (FLASH LOCATION+8=18). First I thought that it was because of FLASH LOCATION, but now it seems that it isn’t. Could anyone suggest me what can go wrong?

I forgot to tell that I have used:
#define FLASH_LOCATION 0
static const ascii* flash_test_var = “”;

I would really appreciate any help!
Thanks
Tatiana

void ReadFromFlash()
{   s32 length [18];
	int i;

	for (i=0;i<18;i++){

      if ((length[i] = adl_flhExist (flash_test_var, FLASH_LOCATION+i)) > 0)
	                  
         { switch ( i )
			   {
			   case 0:
				 DateTime = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],DateTime);
				  TRACE ((TraceLevel, DateTime)); 
				 break;
			   case 1:
				 DeviceID = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],DeviceID);
				  TRACE ((TraceLevel, DeviceID)); 
				 break;
			   case 2:
				 DevicePW = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],DevicePW);
				 
				  TRACE ((TraceLevel, DevicePW)); break;
			   case 3:
				  Name = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Name);
				  TRACE ((TraceLevel, Name)); break;
			   case 4:
				  Surname = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Surname);
				  TRACE ((TraceLevel, Surname)); break;
			   case 5:
				  PinCode = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],PinCode);
				  TRACE ((TraceLevel, PinCode)); break;
			   case 6:
				 SOSContact = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],SOSContact);
				 TRACE ((TraceLevel, SOSContact)); 
				 break;
			   case 7:
				 Supervisor = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Supervisor);
				 TRACE ((TraceLevel, Supervisor)); 
			     break;		
                          case 8:
				 Mode = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Mode);
				  TRACE ((TraceLevel, Mode)); break;
			   case 9:
				 APNUserName = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],APNUserName);
				  TRACE ((TraceLevel, APNUserName)); break;
			   case 10:
				  APNLoggin = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],APNLoggin);
				  TRACE ((TraceLevel, APNLoggin)); break;
			   case 11:
				  APNPassword = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],APNPassword);
				  TRACE ((TraceLevel, APNPassword)); break;
			   case 12:
				  IP = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],IP);
				  TRACE ((TraceLevel, IP)); break;
			   case 13:
				  TCPPort = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],TCPPort);
				  TRACE ((TraceLevel, TCPPort)); break;
			   case 14:
				  UDPPort = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],UDPPort);
				  TRACE ((TraceLevel, UDPPort)); break;
			   case 15:
				  Medication = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Medication);
				  TRACE ((TraceLevel, Medication)); break;
			   case 16:
				 Diseases = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Diseases);
				  TRACE ((TraceLevel, Diseases)); break;
			   case 17:
				  Allergies = adl_memGet(sizeof(u8) * length[i]);	 
	             adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],Allergies);
				  TRACE ((TraceLevel, Allergies)); break;
			   }

			
		}
	}
				  
}	                 	            
			   }

			}
	}
				  
}
//////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------
bool FCM_USB_DataHandler() //bool FCM_USB_DataHandler(u16 DataSize, u8 * Data)
{   
	if (init_type=="OK")//was sent from the GUI ie: Data=="OK"....
	{   s8 res;
		struct basicxmlnode * root = NULL;
		
		Initialisation=TRUE;

			fp = fopen("Initialization.xml", "rt");
			if (!fp) 
				{ 
				TRACE((TraceLevel, "Cannot open XML File"));  
				}
			else
				{
				root = readbasicxmlnode(fp);
				fclose(fp);

			    if (!root) 
					{ 
				   	TRACE((TraceLevel, "Cannot Read Root"));  
					}
				   adl_flhSubscribe( flash_test_var, 18 );  
                 
				   
				   
				   DateTime= Findatt(root,"DateTime");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION, 15,DateTime);
				
                 DeviceID= Findatt(root,"DeviceID");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+1, 12,DeviceID);

				   DevicePW= Findatt(root,"DevicePW");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+2, 4,DevicePW);

				   Name= Findatt(root,"Name");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+3, 30,Name); 

                   Surname= Findatt(root,"Surname");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+4, 30,Surname); 

				   PinCode= Findatt(root,"PIN");
				   adl_flhWrite(flash_test_var, FLASH_LOCATION+5, 4,PinCode);
                  
				   SOSContact= Findatt(root,"SOSContact");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+6, 13,SOSContact);
				   
                   Supervisor= Findatt(root,"Supervisor");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+7, 13,Supervisor);
				   
                   Mode= Findatt(root,"Mode");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+8, 1,Mode);

				   APNUserName= Findatt(root,"APNUserName");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+9, 20,APNUserName);
          

				   APNLoggin= Findatt(root,"APNLoggin");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+10, 5,APNLoggin);

				   APNPassword= Findatt(root,"APNPassword");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+11, 5,APNPassword);

				   IP= Findatt(root,"IP");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+12, 15,IP);

				   TCPPort= Findatt(root,"TCPPort");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+13, 4,TCPPort);

				   UDPPort= Findatt(root,"UDPPort");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+14, 4,UDPPort);

    			   Medication= Findatt(root,"Medication");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+15, 200,Medication);

				   Diseases= Findatt(root,"Diseases");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+16, 200,Diseases);

				   Allergies= Findatt(root,"Allergies");			  				   		   
                   adl_flhWrite(flash_test_var, FLASH_LOCATION+17, 200,Allergies);


                   res = adl_fcmSendData(FCM_USB_handle,"OK",2 ); 
				 }
				   
	} 			
   
	Initialisation=FALSE;

}
//////////////////////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------
void Inititalize()
{   	
    init_type="OK"; 
    //FCM_USB_DataHandler(); //at first time

	ReadFromFlash();	
}
//----------------------------------------------------------------------------------------
void adl_main ( adl_InitType_e InitType )
{     
	
    Inititalize();
	
}

#2

Hiya,

I guess you’re running off the end of a string after you read your variables out of flash. Remember that strings in C are NUL (0x00 or \0) terminated - and all the C string handling libraries rely on this NUL to define the end of the string.

Looking at your code:

DateTime = adl_memGet(sizeof(u8) * length[i]);   
                adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],DateTime);
              TRACE ((TraceLevel, DateTime));

You’re allocating enough memory for the data stored in flash, but you are never NUL terminating your string before displaying it.

There are two solutions:

  1. Ensure that you always store a 0x00 character as the end of your string
  2. (and this is more robust)Use the following code when reading back from Flash:
DateTime = adl_memGet(sizeof(ascii) * (length[i]+1)); // allocate memory plus one more ascii for end of string marker
    wm_memset(DateTime, 0x00, (length[i]+1)); // ensure memory is clear
    adl_flhRead(flash_test_var,FLASH_LOCATION+i,length[i],DateTime); // read from flash
    TRACE ((TraceLevel, DateTime));

// output string
[/code]
Hope this helps.

ciao, Dave


#3

Maybe the OP is being misled by the documentation: viewtopic.php?f=47&t=1682&p=6103&hilit=flash+string#p6103 :question:


#4

Hiya,

I suspect so. In my view the documentation should say ‘array of type u8’, not ‘string’.

ciao, Dave


#5

Or “buffer” or anything other than “string” :exclamation:

Although it does raise the question of why it’s a u8* rather than a void*


#6

Hiya,

You’re right. It should be a void* - as long as the length (or size if storing an array/structure) is correct it doesn’t matter what data you write to flash - as long as you read if back the same way.

I only made the assumption ( :blush: ) that u8* was better than string as the underlying flash is an unsigned byte oriented piece of hardware…

ciao, Dave


#7

It’s advisable to especify a type on a pointer when you recieve a length. In the prototipe of the function you’ve got all the information: The number of elements you are going to recieve in the function and the size of each one (8 bits, 16 bits, 32 bits…). It’s good practice on defensive programing.
Anyway, on documentation string is not a good description.


#8

Not sure what your point is here?

Functions like adl_flhRead and adl_flhWrite are generic functions for writing any arbitrary data, of any arbitrary type - hence void* is the appropriate pointer to use.


#9

As I’ve already said:

Casting was include on C standars to solve the problem of:


#10

So how would you write functions like adl_flhRead and adl_flhWrite so that they can accept any arbitrary data of any arbitrary type?


#11

#12

You’re missing the point - we’re talking about adl_flhRead and adl_flhWrite themselves - not code that uses them:

Functions like adl_flhRead and adl_flhWrite need to deal with arbitrary data of arbitrary types - which is precisely what the void* is for!

Of course, code that gives data to adl_flhWrite and/or gets data from adl_flhRead will use appropriate casts for the actual type of the data required - but void* is the correct one for functions like adl_flhRead and adl_flhWrite

For example, look at malloc


#13

void* is known as a Generic Pointer - see:

faq.zanvar.in/generic-pointers/


#14

I’m not forgiving it. In embebed human life dependant systems, as trains, cars or planes, defensive programming is used, with a double meaning: unforessable uses protection and self-explicative code (coding errors avoidance). To fulfill self-explicative code requirements, C is used with subsets restrictions, for example: use variables names with it’s type included in the name (byte length index: u8Length). There are some subsets, like MISRA, most of them doesn’t accept void pointer, in the same way void return functions are not acceptable. Both, because are indefinitions on themselves.
From my point of view, u8 pointer use is safer because specifies, what means length (bits, bytes, words). This gives borderlines to the user on how would data be internally managed

Anyway, in programming world there’s not correct or incorrect things, unless it doesn’t work. Each implementation has it’s own advantages and disadvantages. Each one can has his own opinion, there’s not just one truth. Although, documentation must be always clear. For me, this is not optional.