[En-Nut-Discussion] Settings & Eeprom etc

Ralph Mason ralph.mason at telogis.com
Mon Jan 9 06:23:43 CET 2006


I see very many questions here regarding eeprom and saving settings 
etc.  So would like to suggest that nutos use the attached method.

We have been using a system of environment variables for about 3 years 
now and it works well.  It's simple and expandable and easy to use.  I 
think it could replace all the confos stuff and is easy other apps to 
use also.  The coupling is very low.

It works around getenv and putenv.  

const char* ip_address=getenv_P(PSTR("ipaddress"));

So all you need to do to change the ip address

putenv("ipaddress=1.2.3.4");

It's pretty nice because you can put setting deep down and they can be 
accessed without linking

eg

if (!  getenv_P(PSTR("NO_PING_REPLY"))
    //Send a ping reply

You can load and save when you want.  So it's all held in memory only 
until you do a saveenv.

Attached are the files.

Regards
Ralph






-------------- next part --------------
#ifndef _ENV_H_
#define _ENV_H_


#ifdef __cplusplus
extern "C" {
#endif

char* getenv(const char* varname);
int putenv(const char* envstring);


char* getenv_P(PGM_P varname);
int putenv_P(PGM_P varname );

//Managment
int saveenv(void);
int loadenv(void);
int initenv(PGM_P defaultenv);

//To iterate though entries
int envcount(void);
const char* enventry(int offset);

//For a given entry returns the value
const char* envval(const char* entry);


#ifdef __cplusplus
}
#endif

#endif

-------------- next part --------------
#include <vcore/vcore.h>
#include <stddef.h>
#include <stdlib.h>
#include <sys/heap.h>
#include <sys/thread.h>
#include <string.h>
#include <vcore/env.h>

char**  _environ;
u_char _environ_size;

int cmp_it(const void* p1,const void* p2){
	char** c1=(char**)p1;
	char** c2=(char**)p2;
	return strcasecmp(*c1,*c2);	
}

int cmp_it_P(const void* p1,const void* p2){
	char** c1=(char**)p1;
	char** c2=(char**)p2;
	
	//Compare backwards because of the order that you must
	//Put arguments into strcasecmp_P
	int ret= strcasecmp_P(*c2,*c1);	
	
	if ( ret==0 )
		return 0;
	if ( ret < 0 )
		return 1;
	
	return -1;
}

char* getenv_internal(const char* varname,int (*func)(const void*,const void*)){
	void* ret;
	
	if ( _environ == NULL ){
		return NULL;
	}

	ret = bsearch((const void*)&varname,(const void*)_environ,_environ_size,sizeof(char*),func);
	
	if ( ret ){
		char* val= *(char**)ret;
		
		while ( *val != 0 )
			val++;
		
		if ( *(val+1) == null )
			return null;
			
		return (val+1);
	}
	
	return null;
}

char* getenv(const char* varname){
	return getenv_internal(varname,cmp_it);
}

char* getenv_P(PGM_P varname){
	return getenv_internal(varname,cmp_it_P);
}

int putenv(const char* envstring){

	char* env;
	char* new_entry;
	int   len; 
	u_short offset;
	void* res;
	int len_b4=0;
	char** new_env;

	//Set newentry to the string
	len = strlen(envstring);

	if ( len >= 64 )
		return -1;

	env = new_entry = malloc(len+1);
	strcpy(new_entry,envstring);

	//Find and kill the =
	while(*env && len_b4 < len ){
		if ( *env == '=' ){
			*env = 0;
			break;	
		}
		env++;
		len_b4++;
	}
	
	//Empty or no '='
	if (len_b4==0 || len_b4 == len ){
		free(new_entry);
		return -1;
	}

	res=bsearch((const void*)&new_entry,(const void*)_environ,_environ_size,sizeof(char*),cmp_it);

	//It's empty and not found
	if ( len_b4 == (len-1) ){
		free(new_entry);

		//Not found - do nothing
		if ( res != NULL ){
			
			//Already Exisits - delete
			offset= ((char**)res) - _environ ;

			//Free old
			free(*(char**)res);

			_environ_size--;

			new_env = malloc(_environ_size * sizeof(char*));
			memcpy(new_env,_environ,offset * sizeof(char*));
			memcpy(new_env + offset,_environ+offset+1,(_environ_size-offset) * sizeof(char*));
			free(_environ);
			_environ = new_env;

		}
	
		return 0;

	}


	if ( res != NULL ){
		//Free old
		free(*(char**)res);
		
		//Update entry
		*(char**)res =new_entry; 
	}
	else{
			
		if ( _environ_size == 0xff )
			return -1;

		//Offset points to end
		offset = _environ_size;
		
		//Expad envorinment
		_environ_size++;
		
		new_env = malloc(_environ_size * sizeof(char*));
		memcpy(new_env,_environ,offset * sizeof(char*));
		free(_environ);

		//Put new entry at end
		_environ = new_env;
		_environ[offset] = new_entry;	

		//Put us back into order	
		qsort(_environ,_environ_size,sizeof(char*),cmp_it);
	}
	
	return 0;
}

int putenv_P( PGM_P varname ){

	int ret;
	char* str = malloc(strlen_P(varname)+1);
	
	if ( str == 0 )
		return -1;
	
	strcpy_P(str,varname);
	
	ret = putenv(str);
	
	free(str);

	return ret;
}

int free_env(void){
	int i;
	
	if ( _environ == 0 )
		return 0;
	
	for(i=0; i<	_environ_size; i++ )
		free(_environ[i]);

	free(_environ);
	
	_environ=null;
	_environ_size=0;
	
	return 0;
}

/*
	This function expects the array in the format
	
	"NAME=VALUE\0"
	"NAME2=VALUE2\0"
	"\0"
	
	It frees any associated memory on exit
*/
int int_initenv( char* defaultenv){

	char* pos = defaultenv;
	int i=0;
	int num_entries=0;
	
	free_env();
	
	//Count the number of entries
	if (*pos) while(1){
		if (*pos++ == 0 ){
			num_entries++;
			
			if ( *pos == 0 )
				break;
		}
	}

	pos = defaultenv;
	
	//Load the strings
	while ( i < num_entries ){
		i++;
		putenv(pos);
		while ( *pos++ != 0 );
	}
	

	return 0;
} 

typedef struct{
	u_char    magic[2];
	u_short	  len;
}  ENV_EEPROM;

#define ENV_BASE_ADDR (u_char*)0x800

int loadenv(void){

	//Env can take up to 1K of EE2
	u_char* envbase = ENV_BASE_ADDR;
	ENV_EEPROM  header;
	u_char* data;
	
	eeprom_read_block(&header, envbase, sizeof(ENV_EEPROM));
	
	if ( header.magic[0] != 'E'  && header.magic[1] != 'V' )
		return -1;

	if ( header.len > 1024 ){
		return -1;
	}
  
	data = malloc(header.len);	
	eeprom_read_block(data, envbase+sizeof(ENV_EEPROM), header.len);
	
	return int_initenv(data);
}

int initenv(PGM_P defaultenv){

	PGM_P pos = defaultenv;
	u_char* data;
	
	/* Find the length of the envronment */
	while(1){
		if (PRG_RDB(pos++) == 0 ){
			
			if ( PRG_RDB(pos) == 0 ){
				pos++;
				break;
			}
		}
	}
	
	data=malloc(pos-defaultenv);
	memcpy_P(data,defaultenv,pos-defaultenv);	
	
	return int_initenv(data);
}

void eeprom_write_block(u_char* data,u_char* addr,size_t len){
	
	while(len){
		eeprom_write_byte(addr++,*data++);
		len--;
	}	
}

int saveenv(void){
	
	int i;
	u_char* addr = ENV_BASE_ADDR + sizeof(ENV_EEPROM);
	ENV_EEPROM  header;
	int len;
//	char* penv;

	for(i=0; i<	_environ_size; i++ ){
		//Remove deleted items
		const char* pval = envval( _environ[i]);
		if ( *pval == 0 )
			continue;
		
		len = strlen( _environ[i]);
		eeprom_write_block(_environ[i], addr, len);
		addr+=len;
		eeprom_write_byte(addr++,'=');
		len = strlen( pval);
		eeprom_write_block(pval, addr, len+1);
		addr+=len+1;
		NutThreadYield();
	}
	
	eeprom_write_byte(addr++,0);
	
    header.magic[0] = 'E';
    header.magic[1] = 'V';
	header.len = addr-ENV_BASE_ADDR;
	
	eeprom_write_block((u_char*)&header, ENV_BASE_ADDR, sizeof(ENV_EEPROM));
	
	return 0;
}

int envcount(void){
	return _environ_size;	
}

const char* enventry(int offset){
	return 	_environ[offset];
}

const char* envval(const char* entry){
	return entry+strlen(entry)+1;
}




More information about the En-Nut-Discussion mailing list