📄 flash.c
字号:
doneone = true;
ret = get_config(dp, title, list_opt, onevalue); // do this opt
}
switch (ret) {
case CONFIG_DONE:
goto done;
case CONFIG_ABORT:
memcpy(&config, &hold_config, sizeof(config));
return;
case CONFIG_CHANGED:
need_update = true;
case CONFIG_OK:
dp += len;
break;
case CONFIG_BACK:
dp = &config.config_data[0];
continue;
case CONFIG_BAD:
// Nothing - make him do it again
printf ("** invalid entry\n");
}
}
done:
if (NULL != onlyone && !doneone) {
#ifdef CYGSEM_REDBOOT_ALLOW_DYNAMIC_FLASH_CONFIG_DATA
if (verify_action("** entry '%s' not found - add", onlyone)) {
struct config_option opt;
printf("Trying to add value\n");
}
#else
printf("** entry '%s' not found", onlyone);
#endif
}
if (!need_update)
return;
flash_write_config();
}
#ifdef CYGSEM_REDBOOT_FLASH_ALIASES
static cmd_fun do_alias;
RedBoot_cmd("alias",
"Manage aliases kept in FLASH memory",
"name [value]",
do_alias
);
static void
make_alias(char *alias, char *name)
{
sprintf(alias, "alias/%s", name);
}
static void
do_alias(int argc, char *argv[])
{
char name[80];
char *val;
struct config_option opt;
switch (argc) {
case 2:
make_alias(name, argv[1]);
if (flash_get_config(name, &val, CONFIG_STRING)) {
printf("'%s' = '%s'\n", argv[1], val);
} else {
printf("'%s' not found\n", argv[1]);
}
break;
case 3:
if (strlen(argv[2]) >= MAX_STRING_LENGTH) {
printf("Sorry, value is too long\n");
break;
}
make_alias(name, argv[1]);
opt.type = CONFIG_STRING;
opt.enable = (char *)0;
opt.enable_sense = 1;
opt.key = name;
opt.dflt = (unsigned long)argv[2];
flash_add_config(&opt, true);
break;
default:
printf("usage: alias name [value]\n");
}
}
static char *
lookup_alias(char *alias)
{
char name[80];
char *val;
make_alias(name, alias);
if (flash_get_config(name, &val, CONFIG_STRING)) {
return val;
} else {
return (char *)NULL;
}
}
bool
_expand_aliases(char *line, int len)
{
char *lp = line;
char *ms, *me, *ep;
char *alias;
char c;
int offset, line_len, alias_len;
bool macro_found = false;
if ((line_len = strlen(line)) != 0) {
while (*lp) {
c = *lp++;
if ((c == '%') && (*lp == '{')) {
// Found a macro/alias to expand
ms = lp+1;
lp += 2;
while (*lp && (*lp != '}')) lp++;
if (!*lp) {
printf("Invalid macro/alias '%s'\n", ms);
line[0] = '\0'; // Destroy line
return false;
}
me = lp;
*me = '\0';
lp++;
if ((alias = lookup_alias(ms)) != (char *)NULL) {
alias_len = strlen(alias);
// See if there is room in the line to expand this macro/alias
if ((line_len+alias_len) < len) {
// Make a hole by moving data within the line
offset = alias_len-strlen(ms)-2; // Number of bytes being inserted
ep = &lp[strlen(lp)-1];
me = &ep[offset];
while (ep != (lp-1)) {
ep[offset-1] = *ep--;
}
*me = '\0';
// Insert the macro/alias data
lp = ms-2;
while (*alias) {
if ((alias[0] == '%') && (alias[1] == '{')) macro_found = true;
*lp++ = *alias++;
}
line_len = strlen(line);
} else {
printf("No room to expand '%s'\n", ms);
line[0] = '\0'; // Destroy line
return false;
}
} else {
printf("Alias '%s' not defined\n", ms);
*me = '|';
}
} else if (c == '"') {
// Skip quoted strings
while (*lp && (*lp != '"')) lp++;
}
}
}
return macro_found;
}
void
expand_aliases(char *line, int len)
{
while (_expand_aliases(line, len)) ;
}
#endif // CYGSEM_REDBOOT_FLASH_ALIASES
//
// Write the in-memory copy of the configuration data to the flash device.
//
void
flash_write_config(void)
{
int stat;
void *err_addr;
if(!(strap_options_val() & CFG_PROM_BOOT))
return;
config.len = sizeof(config);
config.key1 = CONFIG_KEY1;
config.key2 = CONFIG_KEY2;
config.cksum = crc32((unsigned char *)&config, sizeof(config)-sizeof(config.cksum));
if (verify_action("Update RedBoot non-volatile configuration")) {
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
// Insure [quietly] that the config page is unlocked before trying to update
flash_unlock((void *)cfg_base, cfg_size, (void **)&err_addr);
#endif
if ((stat = flash_erase(cfg_base, cfg_size, (void **)&err_addr)) != 0) {
printf(" initialization failed at %p: %s\n", err_addr, flash_errmsg(stat));
} else {
if ((stat = flash_program(cfg_base, (void *)&config,
sizeof(config), (void **)&err_addr)) != 0) {
printf("Error writing config data at %p: %s\n",
err_addr, flash_errmsg(stat));
}
}
#ifdef CYGSEM_REDBOOT_FLASH_LOCK_SPECIAL
// Insure [quietly] that the config data is locked after the update
flash_lock((void *)cfg_base, cfg_size, (void **)&err_addr);
#endif
}
}
//
// Find the configuration entry for a particular key
//
static unsigned char *
flash_lookup_config(char *key)
{
unsigned char *dp;
int len;
if (!config_ok) return (unsigned char *)NULL;
dp = &config.config_data[0];
while (dp < &config.config_data[sizeof(config.config_data)]) {
len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
config_length(CONFIG_OBJECT_TYPE(dp));
if (strcmp(key, CONFIG_OBJECT_KEY(dp)) == 0) {
return dp;
}
dp += len;
}
// printf("Can't find config data for '%s'\n", key);
return false;
}
//
// Retrieve a data object from the data base (in memory copy)
//
bool
flash_get_config(char *key, void *val, int type)
{
unsigned char *dp;
void *val_ptr;
if (!config_ok) return false;
if ((dp = flash_lookup_config(key)) != (unsigned char *)NULL) {
if (CONFIG_OBJECT_TYPE(dp) == type) {
val_ptr = (void *)CONFIG_OBJECT_VALUE(dp);
switch (type) {
// Note: the data may be unaligned in the configuration data
case CONFIG_BOOL:
memcpy(val, val_ptr, sizeof(bool));
break;
case CONFIG_INT:
memcpy(val, val_ptr, sizeof(unsigned long));
break;
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
memcpy(val, val_ptr, sizeof(in_addr_t));
break;
case CONFIG_ESA:
memcpy(val, val_ptr, sizeof(enet_addr_t));
break;
#endif
case CONFIG_STRING:
case CONFIG_SCRIPT:
// Just return a pointer to the script/line
*(unsigned char **)val = (unsigned char *)val_ptr;
break;
}
} else {
printf("Request for config value '%s' - wrong type\n", key);
}
return true;
}
return false;
}
//
// Copy data into the config area
//
static void
flash_config_insert_value(unsigned char *dp, struct config_option *opt)
{
switch (opt->type) {
// Note: the data may be unaligned in the configuration data
case CONFIG_BOOL:
memcpy(dp, (void *)&opt->dflt, sizeof(bool));
break;
case CONFIG_INT:
memcpy(dp, (void *)&opt->dflt, sizeof(unsigned long));
break;
#ifdef CYGPKG_REDBOOT_NETWORKING
case CONFIG_IP:
memcpy(dp, (void *)&opt->dflt, sizeof(in_addr_t));
break;
case CONFIG_ESA:
memcpy(dp, (void *)&opt->dflt, sizeof(enet_addr_t));
break;
#endif
case CONFIG_STRING:
memcpy(dp, (void *)opt->dflt, config_length(CONFIG_STRING));
break;
case CONFIG_SCRIPT:
break;
}
}
//
// Add a new option to the database
//
bool
flash_add_config(struct config_option *opt, bool update)
{
unsigned char *dp, *kp;
int len, elen, size;
// If data item is already present, just update it
// Note: only the data value can be thusly changed
if ((dp = flash_lookup_config(opt->key)) != (unsigned char *)NULL) {
flash_config_insert_value(CONFIG_OBJECT_VALUE(dp), opt);
if (update) {
flash_write_config();
}
return true;
}
// Add the data item
dp = &config.config_data[0];
size = 0;
while (size < sizeof(config.config_data)) {
if (CONFIG_OBJECT_TYPE(dp) == CONFIG_EMPTY) {
kp = opt->key;
len = strlen(kp) + 1;
size += len + 2 + 2 + config_length(opt->type);
if (opt->enable) {
elen = strlen(opt->enable) + 1;
size += elen;
} else {
elen = 0;
}
if (size > sizeof(config.config_data)) {
break;
}
CONFIG_OBJECT_TYPE(dp) = opt->type;
CONFIG_OBJECT_KEYLEN(dp) = len;
CONFIG_OBJECT_ENABLE_SENSE(dp) = opt->enable_sense;
CONFIG_OBJECT_ENABLE_KEYLEN(dp) = elen;
dp = CONFIG_OBJECT_KEY(dp);
while (*kp) *dp++ += *kp++;
*dp++ = '\0';
if (elen) {
kp = opt->enable;
while (*kp) *dp++ += *kp++;
*dp++ = '\0';
}
flash_config_insert_value(dp, opt);
if (update) {
flash_write_config();
}
return true;
} else {
len = 4 + CONFIG_OBJECT_KEYLEN(dp) + CONFIG_OBJECT_ENABLE_KEYLEN(dp) +
config_length(CONFIG_OBJECT_TYPE(dp));
dp += len;
size += len;
}
}
printf("No space to add '%s'\n", opt->key);
return false;
}
//
// Reset/initialize configuration data - used only when starting from scratch
//
static void
config_init(void)
{
// Well known optio
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -