[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