]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/env.c
f743f417424c3961746f1da207a282ba1f71f964
5 #include <avr/eeprom.h>
16 #define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) -1)
18 #define OBSOLETE_FLAG 0
19 #define ENV_GET_VAL (1<<0)
21 #define ENVLIST_DELETE (1<<0)
30 const FLASH
char default_env
[] = {
31 "bootdelay=" "3" DELIM
32 "bootcmd=" "reset; loadf; go $(startaddr)" DELIM
33 "baudrate=" "115200" DELIM
34 "startaddr=" "0" DELIM
39 typedef struct environment_s
{
40 uint16_t crc
; /* CRC16 over data bytes */
41 uint8_t flags
; /* active/obsolete flags */
42 char data
[ENV_SIZE
]; /* Environment data */
47 typedef struct env_item_s
{
48 #define EF_N_EEP (1<<7) /* Variable name is in EEPROM */
49 #define EF_V_EEP (1<<6) /* Variable value is in EEPROM */
50 #define EF_DIRTY (1<<0) /* Variable is new or value changed */
63 static uint8_t env_valid
;
64 static env_item_t env_list
[CONFIG_ENVVAR_MAX
];
65 static int entrycount
;
69 char env_get_char(uint16_t index
)
71 unsigned int off
= CONFIG_ENV_OFFSET
;
74 off
= CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
76 return (char) eeprom_read_byte((const uint8_t *)off
+ index
+
77 offsetof(env_t
, data
));
82 uint16_t varname_get(char *buf
, env_item_t
*ep
)
87 if (ep
->flags
& EF_N_EEP
) {
89 while ((c
= env_get_char(ep
->name
.eep
+ i
)) != '=' &&
90 c
!= '\0' && i
< CONFIG_SYS_ENV_NAMELEN
) {
95 if (i
> 0 && c
!= '=') {
96 debug("** ee_name: '%s' not '=' terminated!\n", buf
);
99 strncpy(buf
, ep
->name
.ram
, CONFIG_SYS_ENV_NAMELEN
);
100 i
= strnlen(buf
, CONFIG_SYS_ENV_NAMELEN
);
108 uint16_t varval_getlen(uint16_t index
)
113 while ((c
= env_get_char (index
+ i
)) != '\0') {
121 uint16_t varval_get(char *buf
, uint16_t index
, int len
)
126 while ((c
= env_get_char (index
+ i
)) != '\0' && i
< len
) {
133 /* TODO: len check */
139 int comp_env_key_item(const void *key
, const void *item
)
141 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
142 env_item_t
*ep
= (env_item_t
*) item
;
144 varname_get(buf
, ep
);
146 return strcmp((char *) key
, buf
);
150 int comp_env_items(const void *m1
, const void *m2
)
152 char b1
[CONFIG_SYS_ENV_NAMELEN
+1];
153 char b2
[CONFIG_SYS_ENV_NAMELEN
+1];
155 env_item_t
*ep1
= (env_item_t
*) m1
;
156 env_item_t
*ep2
= (env_item_t
*) m2
;
158 varname_get(b1
, ep1
);
159 varname_get(b2
, ep2
);
161 return strcmp(b1
, b2
);
165 env_item_t
*envlist_search(const MEMX
char *name
)
167 char *p
= (char *) name
;
170 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
172 if (__builtin_avr_flash_segment(name
) != -1) {
174 while ((*p
++ = *name
++) != '\0')
180 return bsearch(p
, env_list
, entrycount
,
181 sizeof(env_item_t
), comp_env_key_item
);
186 env_item_t
*envlist_enter(env_item_t
*e
)
188 char *key
= e
->name
.ram
;
189 const size_t size
= sizeof(env_item_t
);
192 ep
= bsearch(key
, env_list
, entrycount
,
193 size
, comp_env_key_item
);
196 if (entrycount
< CONFIG_ENVVAR_MAX
) {
198 env_list
[entrycount
++] = *e
;
199 qsort(env_list
, entrycount
, size
, comp_env_items
);
200 ep
= bsearch(key
, env_list
, entrycount
,
201 size
, comp_env_key_item
);
204 if ((ep
->flags
& EF_V_EEP
) == 0) {
207 ep
->val
.ram
= e
->val
.ram
;
211 ep
->flags
|= EF_DIRTY
;
212 ep
->flags
&= ~EF_V_EEP
;
214 if ((ep
->flags
& EF_N_EEP
) == 0) {
215 int nlen
= strnlen(key
, CONFIG_SYS_ENV_NAMELEN
);
216 char *name
= xmalloc(nlen
+ 1);
218 printf_P(PSTR("## Can't malloc %d bytes\n"),
233 int env_item_delete(env_item_t
*ep
)
237 if ((ep
->flags
& EF_V_EEP
) == 0)
239 if ((ep
->flags
& EF_N_EEP
) == 0)
243 size_t size
= sizeof(env_item_t
);
244 memmove(ep
, ep
+ 1, (env_list
- ep
)*size
+ entrycount
*size
);
250 int envlist_delete(const char *name
)
252 env_item_t
*ep
= bsearch(name
, env_list
, entrycount
,
253 sizeof(env_item_t
), comp_env_key_item
);
256 return env_item_delete(ep
);
263 env_item_t
*envlist_get(const MEMX
char *name
, uint_fast8_t flag
)
267 ep
= envlist_search(name
);
269 if (ep
!= NULL
&& (flag
& ENV_GET_VAL
)) {
270 if (ep
->flags
& EF_V_EEP
) {
273 len
= varval_getlen(ep
->val
.eep
);
274 if (len
> CONFIG_SYS_CBSIZE
)
275 len
= CONFIG_SYS_CBSIZE
;
276 vp
= xmalloc(len
+ 1);
278 varval_get(vp
, ep
->val
.eep
, len
+ 1);
280 ep
->flags
&= ~EF_V_EEP
;
282 printf_P(PSTR("Out of memory!\n"));
291 int envlist_import(uint8_t flags
)
293 char name
[CONFIG_SYS_ENV_NAMELEN
+1];
298 if ((flags
& ENVLIST_DELETE
) != 0)
299 while (entrycount
!= 0)
300 env_item_delete(&env_list
[entrycount
-1]);
302 e
.flags
= EF_N_EEP
| EF_V_EEP
;
304 while (idx
< ENV_SIZE
&& (nlen
= varname_get(name
, &e
)) != 0) {
306 if (entrycount
<= CONFIG_ENVVAR_MAX
) {
307 e
.val
.eep
= idx
+ nlen
+ 1;
309 env_list
[entrycount
++] = e
;
312 while (idx
< ENV_SIZE
&& env_get_char(idx
++) != 0)
316 debug("** Too many environment variables!\n");
320 qsort(env_list
, entrycount
, sizeof(env_item_t
), comp_env_items
);
327 int set_default_env(const FLASH
char* msg
)
330 uint16_t eep
= CONFIG_ENV_OFFSET
+ offsetof(env_t
, data
);
331 unsigned int len
= ENV_SIZE
;
332 unsigned int i
, src
= 0;
333 char c
= 0xff, c0
= c
;
338 if (env_valid
== 1) {
339 eep
= CONFIG_ENV_OFFSET
+ offsetof(env_t
, data
) + CONFIG_ENV_SIZE
;
343 memcpy_P(buf
, default_env
+src
, sizeof(buf
));
344 for (i
=0; i
< (len
< sizeof(buf
) ? len
: sizeof(buf
)) &&
345 !(c
== 0 && c0
== 0);
349 eeprom_update_block(buf
, (char *) eep
, i
);
350 if (c
== 0 && c0
== 0)
352 if (len
> sizeof(buf
))
363 uint16_t env_crc(uint16_t data_offset
)
371 for (i
= 0; !(c
== 0 && c0
== 0) && i
< ENV_SIZE
; i
++)
374 c
= eeprom_read_byte((const uint8_t *) data_offset
+ i
);
385 int env_check_valid(void)
387 const uint16_t offset
[2] = {CONFIG_ENV_OFFSET
,
388 CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
};
389 uint_fast8_t flags
[2], crc_ok
[2];
393 flags
[0] = eeprom_read_byte ((uint8_t *) offset
[0] +
394 offsetof(env_t
, flags
));
395 flags
[1] = eeprom_read_byte ((uint8_t *) offset
[1] +
396 offsetof(env_t
, flags
));
400 eeprom_read_word((uint16_t *) offset
[0] +
401 offsetof(env_t
, crc
))
402 == env_crc(offset
[0] + offsetof(env_t
, data
))
405 eeprom_read_word((uint16_t *) offset
[1] +
406 offsetof(env_t
, crc
))
407 == env_crc(offset
[1] + offsetof(env_t
, data
))
410 if (!crc_ok
[0] && !crc_ok
[1]) {
413 } else if (crc_ok
[0] && !crc_ok
[1]) {
415 } else if (!crc_ok
[0] && crc_ok
[1]) {
418 /* both ok - check serial */
420 if (flags
[1] == ACTIVE_FLAG
&& flags
[0] != ACTIVE_FLAG
)
422 else if (flags
[1] == OBSOLETE_FLAG
&& flags
[0] == 0xFF)
427 if (flags
[0] == ACTIVE_FLAG
&& flags
[1] == OBSOLETE_FLAG
)
429 else if (flags
[0] == OBSOLETE_FLAG
&& flags
[1] == ACTIVE_FLAG
)
431 else if (flags
[0] == 0xFF && flags
[1] == 0)
433 else if (flags
[1] == 0xFF && flags
[0] == 0)
435 else /* flags are equal - almost impossible */
446 env_valid
= env_check_valid();
447 if (env_valid
== 0) {
448 set_default_env(PSTR("*** Warning - bad CRC, "
449 "using default environment\n\n"));
451 envlist_import(ENVLIST_DELETE
);
457 char *getenv(const MEMX
char *name
)
462 ep
= envlist_get(name
, ENV_GET_VAL
);
469 int env_item_save(env_item_t
*ep
, uint16_t offset
, int space_left
)
471 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
475 len
= varname_get(buf
, ep
);
484 eeprom_update_block(buf
, (uint8_t *) offset
, len
);
487 if (e
.val
.ram
!= NULL
) {
490 if (e
.flags
& EF_V_EEP
)
491 c
= env_get_char(e
.val
.eep
++);
495 eeprom_update_byte((uint8_t *) offset
, c
);
499 } while ((c
!= '\0') && space_left
);
508 unsigned int off
= CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
509 unsigned int off_red
= CONFIG_ENV_OFFSET
;
515 if (env_valid
== 2) {
516 off
= CONFIG_ENV_OFFSET
;
517 off_red
= CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
520 eeprom_update_byte((uint8_t *) off
+ offsetof(env_t
, flags
), 0xff);
522 pos
= off
+ offsetof(env_t
, data
);
524 for (int i
= 0 ; i
< entrycount
; i
++) {
525 len
= env_item_save(&env_list
[i
], pos
, left
);
533 eeprom_update_byte((uint8_t *) pos
, 0);
534 crc
= env_crc(off
+ offsetof(env_t
, data
));
535 eeprom_update_word((uint16_t *) off
+ offsetof(env_t
, crc
), crc
);
536 eeprom_update_byte((uint8_t *) off
+ offsetof(env_t
, flags
),
540 eeprom_update_byte((uint8_t *) off_red
+ offsetof(env_t
, flags
),
542 env_valid
= (env_valid
== 2) ? 1 : 2;
544 envlist_import(ENVLIST_DELETE
);
552 int env_item_print(env_item_t
*ep
)
554 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
558 varname_get(buf
, ep
);
559 len
= printf_P(PSTR("%s="), buf
);
561 if (e
.val
.ram
!= NULL
) {
564 if (e
.flags
& EF_V_EEP
)
565 c
= env_get_char(e
.val
.eep
++);
584 * Command interface: print one or all environment variables
586 * Returns -1 in case of error, or length of printed string
589 int env_print(const MEMX
char *name
)
593 if (name
) { /* print a single name */
595 env_item_t
*ep
= envlist_search(name
);
597 len
= env_item_print(ep
);
599 } else { /* print whole list */
601 for (int i
= 0 ; i
< entrycount
; i
++) {
602 len
+= env_item_print(&env_list
[i
]);
609 int env_print_ramsize(void)
612 uint8_t name_cnt
= 0;
615 for (int i
= 0 ; i
< entrycount
; i
++) {
616 if ((env_list
[i
].flags
& EF_N_EEP
) == 0 &&
617 (env_list
[i
].name
.ram
!= NULL
)) {
619 size
+= strlen(env_list
[i
].name
.ram
) + 3;
621 if ((env_list
[i
].flags
& EF_V_EEP
) == 0 &&
622 (env_list
[i
].val
.ram
!= NULL
)) {
624 size
+= strlen(env_list
[i
].val
.ram
) + 3;
627 printf_P(PSTR("%d bytes RAM used for %u names and %u values\n"),
628 size
, name_cnt
, val_cnt
);
633 command_ret_t
do_env_print(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
635 command_ret_t rc
= CMD_RET_SUCCESS
;
637 (void) cmdtp
; (void) flag
;
640 /* print all env vars */
641 int size
= env_print(NULL
);
643 return CMD_RET_FAILURE
;
644 printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
647 return CMD_RET_SUCCESS
;
650 /* print selected env vars */
651 for (int i
= 1; i
< argc
; ++i
) {
652 int rc
= env_print(argv
[i
]);
654 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv
[i
]);
655 rc
= CMD_RET_FAILURE
;
664 * Set or delete environment variable
666 * Set a new environment variable,
667 * or replace or delete an existing one.
669 * @param flag (not used)
671 * @param argv[1] Environment variable to set or delete
673 * @param argv[2] ... Value to set it to
675 * @return 0 if ok, 1 on error
678 command_ret_t
_do_env_set(int flag
, int argc
, char * const argv
[])
681 char *name
, *value
, *s
;
685 debug("Initial value for argc=%d\n", argc
);
690 if (strchr(name
, '=')) {
691 printf_P(PSTR("## Error: illegal character '='"
692 "in variable name \"%s\"\n"), name
);
693 return CMD_RET_FAILURE
;
695 if (strlen(name
) > CONFIG_SYS_ENV_NAMELEN
) {
696 printf_P(PSTR("## Error: Variable name \"%s\" too long. "
697 "(max %d characters)\n"), name
, CONFIG_SYS_ENV_NAMELEN
);
698 return CMD_RET_FAILURE
;
704 if (argc
< 3 || argv
[2] == NULL
) {
705 int rc
= envlist_delete(name
);
706 return rc
? CMD_RET_FAILURE
: CMD_RET_SUCCESS
;
710 * Insert / replace new value
712 for (i
= 2, len
= 0; i
< argc
; ++i
)
713 len
+= strlen(argv
[i
]) + 1;
715 value
= xmalloc(len
);
717 printf_P(PSTR("## Can't malloc %d bytes\n"), len
);
718 return CMD_RET_FAILURE
;
720 for (i
= 2, s
= value
; i
< argc
; ++i
) {
723 while ((*s
++ = *v
++) != '\0')
733 ep
= envlist_enter(&e
);
735 printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
737 return CMD_RET_FAILURE
;
740 return CMD_RET_SUCCESS
;
744 * Set an environment variable
746 * @param varname Environment variable to set
747 * @param varvalue Value to set it to
748 * @return 0 if ok, 1 on error
751 int setenv(const char *varname
, const char *varvalue
)
753 const char * const argv
[3] = { NULL
, varname
, varvalue
};
756 if (varvalue
== NULL
|| varvalue
[0] == '\0')
759 return (int) _do_env_set(0, argc
, (char * const *)argv
);
764 * Set an environment variable to an integer value
766 * @param varname Environment variable to set
767 * @param value Value to set it to
768 * @return 0 if ok, 1 on error
770 int setenv_ulong(const char *varname
, unsigned long value
)
772 /* TODO: this should be unsigned */
773 char *str
= simple_itoa(value
);
775 return setenv(varname
, str
);
781 * Set an environment variable to an value in hex
783 * @param varname Environment variable to set
784 * @param value Value to set it to
785 * @return 0 if ok, 1 on error
787 int setenv_hex(const MEMX
char *varname
, unsigned long value
)
789 char str
[sizeof(unsigned long) *2 + 1];
791 sprintf_P(str
, PSTR("%lx"), value
);
792 return setenv(varname
, str
);
797 * Decode the integer value of an environment variable and return it.
799 * @param name Name of environemnt variable
800 * @param base Number base to use (normally 10, or 16 for hex)
801 * @param default_val Default value to return if the variable is not
803 * @return the decoded value, or default_val if not found
805 unsigned long getenv_ulong(const MEMX
char *name
, int base
, unsigned long default_val
)
811 env_item_t
*ep
= envlist_search(name
);
814 if (ep
->flags
& EF_V_EEP
) {
815 varval_get(buf
, ep
->val
.eep
, sizeof(buf
));
820 value
= strtoul(vp
, &endp
, base
);
830 command_ret_t
do_env_set(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
835 return CMD_RET_USAGE
;
837 return _do_env_set(flag
, argc
, argv
);
841 command_ret_t
do_env_default(cmd_tbl_t
*cmdtp
, int flag
,
842 int argc
, char * const argv
[])
844 (void) cmdtp
; (void) flag
; (void) argc
; (void) argv
;
846 /* Reset the whole environment */
847 set_default_env(PSTR("## Resetting to default environment\n"));
848 envlist_import(ENVLIST_DELETE
);
850 return CMD_RET_SUCCESS
;
853 command_ret_t
do_env_save(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
855 (void) cmdtp
; (void) flag
; (void) argc
; (void) argv
;
857 printf_P(PSTR("Saving Environment ...\n"));
858 return saveenv() ? CMD_RET_FAILURE
: CMD_RET_SUCCESS
;
861 #if defined(CONFIG_AUTO_COMPLETE)
862 int env_complete(char *var
, int maxv
, char *cmdv
[], int bufsz
, char *buf
)
871 while ((idx
= hmatch_r(var
, idx
, &match
, &env_htab
))) {
872 int vallen
= strlen(match
->key
) + 1;
874 if (found
>= maxv
- 2 || bufsz
< vallen
)
878 memcpy(buf
, match
->key
, vallen
);
883 qsort(cmdv
, found
, sizeof(cmdv
[0]), strcmp_compar
);
886 cmdv
[found
++] = "...";