]>
cloudbase.mooo.com Git - z180-stamp.git/blob - avr/env.c
5 #include <avr/eeprom.h>
16 #define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) -1)
18 #define OBSOLETE_FLAG 0
24 #define ENV_GET_VAL (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
41 typedef struct environment_s
{
42 uint16_t crc
; /* CRC16 over data bytes */
43 uint8_t flags
; /* active/obsolete flags */
44 char data
[ENV_SIZE
]; /* Environment data */
49 typedef struct env_item_s
{
50 #define EF_N_EEP (1<<7) /* Variable name is in EEPROM */
51 #define EF_V_EEP (1<<6) /* Variable value is in EEPROM */
52 #define EF_DIRTY (1<<0) /* Variable is new or value changed */
64 static uint8_t env_valid
;
65 static env_item_t env_list
[CONFIG_ENVVAR_MAX
];
66 static int entrycount
;
69 static 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
));
81 uint16_t ee_name_get(char *buf
, env_item_t
*ep
)
86 if (ep
->flags
& EF_N_EEP
) {
88 while ((c
= env_get_char(ep
->name
.eep
+ i
)) != '=' &&
89 c
!= '\0' && i
< CONFIG_SYS_ENV_NAMELEN
) {
94 if (i
> 0 && c
!= '=') {
95 debug("** ee_name: '%s' not '=' terminated!\n", buf
);
98 strncpy(buf
, ep
->name
.ram
, CONFIG_SYS_ENV_NAMELEN
);
99 i
= strnlen(buf
, CONFIG_SYS_ENV_NAMELEN
);
106 uint16_t ee_val_get(char *buf
, uint16_t index
, int len
)
111 while ((c
= env_get_char (index
+ i
)) != '\0' && i
< len
) {
118 /* TODO: len check */
124 int comp_env_key_item(const void *key
, const void *item
)
126 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
127 env_item_t
*ep
= (env_item_t
*) item
;
129 ee_name_get(buf
, ep
);
131 return strcmp((char *) key
, buf
);
135 int comp_env_items(const void *m1
, const void *m2
)
137 char b1
[CONFIG_SYS_ENV_NAMELEN
+1];
138 char b2
[CONFIG_SYS_ENV_NAMELEN
+1];
140 env_item_t
*ep1
= (env_item_t
*) m1
;
141 env_item_t
*ep2
= (env_item_t
*) m2
;
143 ee_name_get(b1
, ep1
);
144 ee_name_get(b2
, ep2
);
146 return strcmp(b1
, b2
);
150 env_item_t
* ee_entry_get(const char *s
, env_item_t
*ep
, uint_fast8_t flag
)
152 char name
[CONFIG_SYS_ENV_NAMELEN
+1];
156 //printf_P(PSTR("*** ee_entry_get: >>>>>>>>> ENTER <<<<<<<<<\n"));
159 while ((nlen
= ee_name_get(name
, idx
)) != 0 && idx
< CONFIG_ENV_SIZE
) {
161 //printf_P(PSTR("** idx: %d, name: '%s', s: '%s', nlen: %d, cpres:%d\n"),
162 // idx, name, s, nlen, strncmp(name, s, nlen));
164 if (strncmp(name
, s
, nlen
) == 0)
168 while (env_get_char(idx
++) != 0)
174 ep
->flags
= EF_N_EEP
;
176 if (flag
& ENV_GET_VAL
) {
177 vp
= xmalloc(CONFIG_SYS_CBSIZE
);
178 nlen
= ee_val_get(vp
, idx
+ nlen
+ 1, CONFIG_SYS_CBSIZE
);
179 ep
->val
= xrealloc(vp
, nlen
+ 1);
184 //printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE 0x%.4x <<<<<\n"),
185 // (unsigned int) ep);
189 //printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE <NULL> <<<<<\n"));
195 static char p_env_name_buf
[CONFIG_SYS_ENV_NAMELEN
+1];
197 static char *dbg_p_env_name(env_item_t
*p
)
199 if (p
->flags
& EF_N_EEP
) {
200 if (ee_name_get(p_env_name_buf
, p
) != 0)
201 return p_env_name_buf
;
205 return "<NO EEP_NAME>";
209 int env_item_print(env_item_t
*ep
)
211 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
215 ee_name_get(buf
, ep
);
216 len
= printf_P(PSTR("%s="), buf
);
218 if (e
.val
.ram
!= NULL
) {
221 if (e
.flags
& EF_V_EEP
)
222 c
= env_get_char(e
.val
.eep
++);
240 int env_item_save(env_item_t
*ep
, uint16_t offset
, int space_left
)
242 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
246 debug("-- env_item_save(%04x, %04x, %d)\n",
247 ep
, offset
, space_left
);
249 len
= ee_name_get(buf
, ep
);
255 if ((unsigned) len
< sizeof(buf
))
256 buf
[len
] = '\0'; /* terminate for debugging */
257 debug(" len: %d, buf: '%s', space_left: %d\n", len
, buf
, space_left
);
262 eeprom_update_block(buf
, (uint8_t *) offset
, len
);
265 if (e
.val
.ram
!= NULL
) {
268 if (e
.flags
& EF_V_EEP
)
269 c
= env_get_char(e
.val
.eep
++);
273 eeprom_update_byte((uint8_t *) offset
, c
);
277 } while ((c
!= '\0') && space_left
);
287 int env_item_update(env_item_t
*ep
)
289 char buf
[CONFIG_SYS_ENV_NAMELEN
+1];
294 /* get name from old loc. (eeprom or ram */
295 len
= ee_name_get(buf
, ep
);
298 debug("-- env_item_update(%04x)\n", ep
);
299 if (len
< sizeof(buf
))
300 buf
[len
] = '\0'; /* terminate for debugging */
301 debug(" len: %d, buf: '%s'\n", len
, buf
);
303 /* search this name in new eeprom env */
304 /* TODO: eliminate this ugly hack */
305 uint8_t save_env_valid
= env_valid
;
306 env_valid
= (env_valid
== 2) ? 1 : 2;
308 debug(" len: %d, buf: '%s', env_valid: %d\n", len
, buf
, env_valid
);
310 while ((c
= env_get_char(pos
)) != '\0' && pos
< (ENV_SIZE
- len
)) {
313 debug(" while: c: %02x, pos: %d\n ", c
, pos
);
315 while (c
== buf
[i
] && i
<= len
) {
320 c
= env_get_char(pos
+ i
);
323 debug("\n c: %02x, i: %d, pos: %d\n", c
, i
, pos
);
326 if ((ep
->flags
& EF_N_EEP
) == 0)
329 if ((ep
->flags
& EF_V_EEP
) == 0)
331 ep
->val
.eep
= pos
+ i
;
332 ep
->flags
&= ~EF_DIRTY
;
333 ep
->flags
|= EF_N_EEP
| EF_V_EEP
;
336 env_valid
= save_env_valid
;
340 while (((c
= env_get_char(pos
++)) != '\0') && pos
< (ENV_SIZE
- len
))
343 debug("\n c: %02x, i: %d, pos: %d\n", c
, i
, pos
);
347 env_valid
= save_env_valid
;
354 int envlist_import(void)
356 char name
[CONFIG_SYS_ENV_NAMELEN
+1];
361 e
.flags
= EF_N_EEP
| EF_V_EEP
;
363 while ((nlen
= ee_name_get(name
, &e
)) != 0 && idx
< ENV_SIZE
) {
365 if (entrycount
<= CONFIG_ENVVAR_MAX
) {
366 e
.val
.eep
= idx
+ nlen
+ 1;
368 env_list
[entrycount
++] = e
;
371 while (env_get_char(idx
++) != 0 && idx
< ENV_SIZE
)
375 debug("** Too many environment variables!\n");
379 qsort(env_list
, entrycount
, sizeof(env_item_t
), comp_env_items
);
384 static env_item_t
*envlist_search(const char *name
)
386 return bsearch(name
, env_list
, entrycount
,
387 sizeof(env_item_t
), comp_env_key_item
);
391 env_item_t
*envlist_insert(const char *key
, env_item_t
*e
)
393 const size_t size
= sizeof(env_item_t
);
395 if (entrycount
< CONFIG_ENVVAR_MAX
) {
396 env_list
[entrycount
++] = *e
;
397 qsort(env_list
, entrycount
, size
, comp_env_items
);
399 return bsearch(key
, env_list
, entrycount
,
400 size
, comp_env_key_item
);
407 env_item_t
*envlist_enter(env_item_t
*e
)
409 char *key
= e
->name
.ram
;
410 const size_t size
= sizeof(env_item_t
);
413 ep
= bsearch(key
, env_list
, entrycount
,
414 size
, comp_env_key_item
);
417 if (entrycount
< CONFIG_ENVVAR_MAX
) {
419 env_list
[entrycount
++] = *e
;
420 qsort(env_list
, entrycount
, size
, comp_env_items
);
421 ep
= bsearch(key
, env_list
, entrycount
,
422 size
, comp_env_key_item
);
425 if ((ep
->flags
& EF_V_EEP
) == 0) {
428 ep
->val
.ram
= e
->val
.ram
;
432 ep
->flags
|= EF_DIRTY
;
433 ep
->flags
&= ~EF_V_EEP
;
435 if ((ep
->flags
& EF_N_EEP
) == 0) {
436 int nlen
= strnlen(key
, CONFIG_SYS_ENV_NAMELEN
);
437 char *name
= xmalloc(nlen
+ 1);
439 printf_P(PSTR("## Can't malloc %d bytes\n"),
453 static env_item_t
*envlist_get(const char *name
, uint_fast8_t flag
)
457 ep
= envlist_search(name
);
459 if (ep
!= NULL
&& (flag
& ENV_GET_VAL
)) {
460 if (ep
->flags
& EF_V_EEP
) {
463 /* TODO: function that gets len of val,
464 to get rid of xrealloc */
465 vp
= xmalloc(CONFIG_SYS_CBSIZE
);
466 len
= ee_val_get(vp
, ep
->val
.eep
, CONFIG_SYS_CBSIZE
);
467 ep
->val
.ram
= xrealloc(vp
, len
+ 1);
468 ep
->flags
&= ~EF_V_EEP
;
475 int env_item_delete(env_item_t
*ep
)
479 if ((ep
->flags
& EF_V_EEP
) == 0)
481 if ((ep
->flags
& EF_N_EEP
) == 0)
485 size_t size
= sizeof(env_item_t
);
486 memmove(ep
, ep
+ 1, (env_list
- ep
)*size
+ entrycount
*size
);
491 static int envlist_delete(const char *name
)
493 env_item_t
*ep
= bsearch(name
, env_list
, entrycount
,
494 sizeof(env_item_t
), comp_env_key_item
);
497 return env_item_delete(ep
);
500 dump_ram((uint8_t *) &env_list
[0], entrycount
* sizeof(env_item_t
),
503 debug("** entrycount: %d\n", entrycount
);
504 for (int i
=0; i
<entrycount
; i
++) {
505 printf_P(PSTR("** env var [%d] "), i
);
506 env_item_print(&env_list
[i
]);
513 char *getenv(const char *name
)
518 debug("** getenv: %s\n", name
);
520 ep
= envlist_get(name
, ENV_GET_VAL
);
524 dump_ram((uint8_t *) &env_list
[0], entrycount
* sizeof(env_item_t
),
527 debug("** entrycount: %d\n", entrycount
);
528 for (int i
=0; i
<entrycount
; i
++) {
529 printf_P(PSTR("** env var [%d] "), i
);
530 env_item_print(&env_list
[i
]);
536 uint16_t env_crc(uint16_t data_offset
)
544 for (i
= 0; !(c
== 0 && c0
== 0) && i
< ENV_SIZE
; i
++)
547 c
= eeprom_read_byte((const uint8_t *) data_offset
+ i
);
555 unsigned int off
= CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
556 unsigned int off_red
= CONFIG_ENV_OFFSET
;
562 if (env_valid
== 2) {
563 off
= CONFIG_ENV_OFFSET
;
564 off_red
= CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
567 eeprom_update_byte((uint8_t *) off
+ offsetof(env_t
, flags
), 0xff);
569 pos
= off
+ offsetof(env_t
, data
);
571 for (int i
= 0 ; i
< entrycount
; i
++) {
572 len
= env_item_save(&env_list
[i
], pos
, left
);
580 eeprom_update_byte((uint8_t *) pos
, 0);
581 crc
= env_crc(off
+ offsetof(env_t
, data
));
582 eeprom_update_word((uint16_t *) off
+ offsetof(env_t
, crc
), crc
);
583 eeprom_update_byte((uint8_t *) off
+ offsetof(env_t
, flags
),
587 while (entrycount
!= 0) {
588 env_item_delete(&env_list
[entrycount
-1]);
590 eeprom_update_byte((uint8_t *) off_red
+ offsetof(env_t
, flags
),
592 env_valid
= (env_valid
== 2) ? 1 : 2;
600 /*-----------------------------------------------------------------------------*/
602 int set_default_env(void)
605 uint16_t eep
= CONFIG_ENV_OFFSET
+ offsetof(env_t
, data
);
606 unsigned int len
= ENV_SIZE
;
607 unsigned int i
, src
= 0;
608 char c
= 0xff, c0
= c
;
610 printf_P(PSTR("\n\n** set_default_env()\n"));
612 if (env_valid
== 1) {
613 eep
= CONFIG_ENV_OFFSET
+ offsetof(env_t
, data
) + CONFIG_ENV_SIZE
;
617 memcpy_P(buf
, default_env
+src
, sizeof(buf
));
618 for (i
=0; i
< (len
< sizeof(buf
) ? len
: sizeof(buf
)) &&
619 !(c
== 0 && c0
== 0);
623 eeprom_update_block(buf
, (char *) eep
, i
);
625 printf_P(PSTR("eeprom_update_block: eep: 0x%.4x, i:%d\n"),
626 (unsigned int) eep
, i
);
627 dump_ram((uint8_t *) buf
, i
, "=== buf:");
628 dump_eep((const uint8_t *) eep
, i
);
630 if (c
== 0 && c0
== 0)
632 if (len
> sizeof(buf
))
645 int env_check(uint16_t offset
)
647 uint16_t crc
, stored_crc
;
650 stored_crc
= eeprom_read_word(
651 (const uint16_t *) offset
+ offsetof(env_t
, crc
));
652 crc
= env_crc(offset
+ offsetof(env_t
, data
));
654 debug_cond((crc
!= stored_crc
),
655 "** crc eep: 0x%.4x, crc new: 0x%.4x\n", stored_crc
, crc
);
657 return crc
== stored_crc
;
662 unsigned int off_env
[2];
663 uint8_t flags
[2], crc_ok
[2];
665 off_env
[0] = CONFIG_ENV_OFFSET
;
666 off_env
[1] = CONFIG_ENV_OFFSET
+ CONFIG_ENV_SIZE
;
668 for (uint_fast8_t i
= 0; i
< 2; i
++) {
670 flags
[i
] = eeprom_read_byte ((uint8_t *) off_env
[i
] +
671 offsetof(env_t
, flags
));
675 eeprom_read_word((uint16_t *) off_env
[i
] +
676 offsetof(env_t
, crc
))
677 == env_crc(off_env
[i
] + offsetof(env_t
, data
))
681 if (!crc_ok
[0] && !crc_ok
[1]) {
683 debug("crc1: %02x, crc2: %02x, flag1 %02x, flag2 %02x, env_valid: %d\n",
684 crc_ok
[0], crc_ok
[1], flags
[0], flags
[1], env_valid
);
687 } else if (crc_ok
[0] && !crc_ok
[1]) {
689 } else if (!crc_ok
[0] && crc_ok
[1]) {
692 /* both ok - check serial */
693 if (flags
[0] == ACTIVE_FLAG
&& flags
[1] == OBSOLETE_FLAG
)
695 else if (flags
[0] == OBSOLETE_FLAG
&& flags
[1] == ACTIVE_FLAG
)
697 else if (flags
[0] == 0xFF && flags
[1] == 0)
699 else if (flags
[1] == 0xFF && flags
[0] == 0)
701 else /* flags are equal - almost impossible */
705 debug("crc1: %02x, crc2: %02x, flag1 %02x, flag2 %02x, env_valid: %d\n",
706 crc_ok
[0], crc_ok
[1], flags
[0], flags
[1], env_valid
);
715 if (env_valid
== 0) {
716 printf_P(PSTR("*** Warning - bad CRC, "
717 "using default environment\n\n"));
727 * Command interface: print one or all environment variables
729 * Returns -1 in case of error, or length of printed string
731 static int env_print(char *name
)
735 if (name
) { /* print a single name */
737 env_item_t
*ep
= envlist_search(name
);
739 len
= env_item_print(ep
);
741 } else { /* print whole list */
743 for (int i
= 0 ; i
< entrycount
; i
++) {
744 len
+= env_item_print(&env_list
[i
]);
750 int env_print_ramsize(void)
753 uint8_t name_cnt
= 0;
756 for (int i
= 0 ; i
< entrycount
; i
++) {
757 if ((env_list
[i
].flags
& EF_N_EEP
) == 0 &&
758 (env_list
[i
].name
.ram
!= NULL
)) {
760 size
+= strlen(env_list
[i
].name
.ram
) + 3;
762 if ((env_list
[i
].flags
& EF_V_EEP
) == 0 &&
763 (env_list
[i
].val
.ram
!= NULL
)) {
765 size
+= strlen(env_list
[i
].val
.ram
) + 3;
768 printf_P(PSTR("%d bytes RAM used for %u names and %u values\n"),
769 size
, name_cnt
, val_cnt
);
773 int do_env_print(cmd_tbl_t
*cmdtp
, int flag
, int argc
,
779 (void) cmdtp
; (void) flag
;
782 /* print all env vars */
783 rcode
= env_print(NULL
);
786 printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
792 /* print selected env vars */
793 for (i
= 1; i
< argc
; ++i
) {
794 int rc
= env_print(argv
[i
]);
796 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv
[i
]);
806 * Set or delete environment variable
808 * Set a new environment variable,
809 * or replace or delete an existing one.
811 * @param flag (not used)
813 * @param argv[1] Environment variable to set or delete
815 * @param argv[2] ... Value to set it to
817 * @return 0 if ok, 1 on error
819 static int _do_env_set(int flag
, int argc
, char * const argv
[])
822 char *name
, *value
, *s
;
826 debug("Initial value for argc=%d\n", argc
);
831 if (strchr(name
, '=')) {
832 printf_P(PSTR("## Error: illegal character '='"
833 "in variable name \"%s\"\n"), name
);
836 if (strlen(name
) > CONFIG_SYS_ENV_NAMELEN
) {
837 printf_P(PSTR("## Error: Variable name \"%s\" too long. "
838 "(max %d characters)\n"), name
, CONFIG_SYS_ENV_NAMELEN
);
845 if (argc
< 3 || argv
[2] == NULL
) {
846 int rc
= envlist_delete(name
);
851 * Insert / replace new value
853 for (i
= 2, len
= 0; i
< argc
; ++i
)
854 len
+= strlen(argv
[i
]) + 1;
856 value
= xmalloc(len
);
858 printf_P(PSTR("## Can't malloc %d bytes\n"), len
);
861 for (i
= 2, s
= value
; i
< argc
; ++i
) {
864 while ((*s
++ = *v
++) != '\0')
874 ep
= envlist_enter(&e
);
876 printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
885 * Set an environment variable
887 * @param varname Environment variable to set
888 * @param varvalue Value to set it to
889 * @return 0 if ok, 1 on error
891 int setenv(const char *varname
, const char *varvalue
)
893 const char * const argv
[3] = { NULL
, varname
, varvalue
};
896 if (varvalue
== NULL
|| varvalue
[0] == '\0')
899 return _do_env_set(0, argc
, (char * const *)argv
);
904 * Set an environment variable to an integer value
906 * @param varname Environment variable to set
907 * @param value Value to set it to
908 * @return 0 if ok, 1 on error
910 int setenv_ulong(const char *varname
, unsigned long value
)
912 /* TODO: this should be unsigned */
913 char *str
= simple_itoa(value
);
915 return setenv(varname
, str
);
921 * Set an environment variable to an value in hex
923 * @param varname Environment variable to set
924 * @param value Value to set it to
925 * @return 0 if ok, 1 on error
927 int setenv_hex(const char *varname
, unsigned long value
)
929 char str
[sizeof(unsigned long) *2 + 1];
931 sprintf_P(str
, PSTR("%lx"), value
);
932 return setenv(varname
, str
);
936 * Get an environment variable as a hex value
938 * @param varname Environment variable to get
939 * @param default_val Return this, if variable does not exist
940 * @return hex value of variable or default_val
942 unsigned long getenv_hex(const char *varname
, unsigned long default_val
)
950 value
= strtoul(s
, &endp
, 16);
957 int do_env_set(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
962 return CMD_RET_USAGE
;
964 return _do_env_set(flag
, argc
, argv
);
968 int do_env_save(cmd_tbl_t
*cmdtp
, int flag
, int argc
, char * const argv
[])
970 (void) cmdtp
; (void) flag
; (void) argc
; (void) argv
;
972 printf_P(PSTR("Saving Environment ...\n"));
974 return saveenv() ? 1 : 0;
977 #if defined(CONFIG_AUTO_COMPLETE)
978 int env_complete(char *var
, int maxv
, char *cmdv
[], int bufsz
, char *buf
)
987 while ((idx
= hmatch_r(var
, idx
, &match
, &env_htab
))) {
988 int vallen
= strlen(match
->key
) + 1;
990 if (found
>= maxv
- 2 || bufsz
< vallen
)
994 memcpy(buf
, match
->key
, vallen
);
999 qsort(cmdv
, found
, sizeof(cmdv
[0]), strcmp_compar
);
1002 cmdv
[found
++] = "...";