]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/env.c
Add command saveenv
[z180-stamp.git] / avr / env.c
CommitLineData
d684c216
L
1#include "common.h"
2#include <string.h>
3#include <stdlib.h>
4
5#include <avr/eeprom.h>
6
7#include "config.h"
8#include "debug.h"
9#include "xmalloc.h"
10#include "crc.h"
11#include "command.h"
12
13#include "env.h"
14
15
323398b1
L
16#define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) -1)
17#define ACTIVE_FLAG 1
18#define OBSOLETE_FLAG 0
19
d684c216
L
20
21#define DELIM "\0"
d684c216
L
22
23
24#define ENV_GET_VAL (1<<0)
25
26
534e1dfc
L
27/*
28 * Default Environment
29 */
30const FLASH char default_env[] = {
31 "bootdelay=" "3" DELIM
32 "bootcmd=" "reset; loadf; go $(startaddr)" DELIM
33 "baudrate=" "115200" DELIM
34 "startaddr=" "0" DELIM
35 DELIM
36};
37
38
323398b1
L
39#ifdef DEBUG
40
d684c216
L
41/*
42 * Debugging
43 *
44 * TODO: move elsewhere
45 */
46#include <ctype.h>
47
48static void print_blanks(uint_fast8_t count)
49{
50 while(count--)
51 putchar(' ');
52}
53
54
55void dump_ram(const uint8_t *startaddr, int len, char *title)
56{
57 uint8_t llen = 16;
58 uint8_t pre = (size_t) startaddr % 16;
59 const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
60 len += pre;
61 uint8_t i;
62
63 if (title && *title)
64 printf_P(PSTR("%s\n"),title);
65
66 while (len) {
67 if (len < 16)
68 llen = len;
69
70 printf_P(PSTR(" %.4x:"), (size_t) addr);
71 print_blanks(3 * pre);
72 for (i = pre; i < llen; i++)
73 printf_P(PSTR(" %.2x"), addr[i]);
74 print_blanks(3 * (16 - i + 1) + pre);
75 for (i = pre; i < llen; i++)
76 printf_P(PSTR("%c"), isprint(addr[i]) ? addr[i] : '.');
77 putchar('\n');
78
79 pre = 0;
80 addr += 16;
81 len -= llen;
82 }
83}
84
85void dump_heap(void)
86{
87 extern unsigned int __brkval;
88
89 dump_ram((uint8_t *) __malloc_heap_start,
90 __brkval - (unsigned int) __malloc_heap_start,
91 "=== Heap:");
92}
93
94/* TODO: combine with dump_ram() */
323398b1 95void dump_eep(const uint8_t *addr, unsigned int len)
d684c216 96{
323398b1 97 uint_fast8_t i;
d684c216
L
98 uint8_t buf[16];
99
100 printf_P(PSTR("eeprom dump:"));
101 while (len) {
102 printf_P(PSTR("\n 0x%.4x:"), (unsigned int) addr);
103 for (i = 0; i<16; i++)
104 buf[i] = eeprom_read_byte(addr + i);
105 for (i = 0; i<16; i++)
106 printf_P(PSTR(" %.2x"), buf[i]);
107 printf_P(PSTR(" "));
108 for (i = 0; i<16; i++)
109 printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
110
111 addr += 16;
112 len -= len > 16 ? 16 : len;
113 }
114 putchar('\n');
115}
116
323398b1
L
117/*
118 * EEPROM Display
119 * md addr {len}
120 */
121int do_dump_eep(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
122{
123 const uint8_t *addr;
124 uint16_t length;
125
126 (void) cmdtp;
127
128
129 /* We use the last specified parameters, unless new ones are
130 * entered.
131 */
132 addr = 0;
133 length = 128;
134
135 if (argc < 2)
136 return CMD_RET_USAGE;
137
138 if ((flag & CMD_FLAG_REPEAT) == 0) {
139 /* Address is specified since argc > 1 */
140 addr = (const uint8_t *) (size_t) strtoul(argv[1], NULL, 16);
141
142 /* If another parameter, it is the length to display. */
143 if (argc > 2)
144 length = (uint16_t) strtoul(argv[2], NULL, 16);
145 }
146
147 /* Print the lines. */
148 dump_eep(addr, length);
149
150 return 0;
151}
152
153int do_eep_cp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
154{
155 uint16_t src, dest, count;
156 int_fast8_t step;
157
158 (void) cmdtp;
159 (void) flag;
160
161 if (argc != 4)
162 return CMD_RET_USAGE;
163
164 src = (size_t) strtoul(argv[1], NULL, 16);
165 dest = (size_t) strtoul(argv[2], NULL, 16);
166 count = (size_t) strtoul(argv[3], NULL, 16);
167
168 if (src > E2END) {
169 debug("src > EEPROM size: 0x%04x\n", src);
170 return 1;
171 }
172 if (dest > E2END) {
173 debug("dest > EEPROM size: 0x%04x\n", dest);
174 return 1;
175 }
176 if (count > E2END+1) {
177 debug("count > EEPROM size: 0x%04x\n", count);
178 return 1;
179 }
180 if (count == 0) {
181 debug("Zero length ???\n");
182 return 1;
183 }
184
185 if (dest > src) {
186 src += count - 1;
187 dest += count - 1;
188 step = -1;
189 } else
190 step = 1;
191
192 while (count-- > 0) {
193 uint8_t data;
194 data = eeprom_read_byte((uint8_t *) src);
195 eeprom_write_byte((uint8_t *) dest, data);
196 src += step;
197 dest += step;
198
199 }
200 return 0;
201}
202#endif /* DEBUG */
203
204
d684c216
L
205typedef struct environment_s {
206 uint16_t crc; /* CRC16 over data bytes */
323398b1 207 uint8_t flags; /* active/obsolete flags */
d684c216
L
208 char data[ENV_SIZE]; /* Environment data */
209} env_t;
210
211
212
213typedef struct env_item_s {
72f58822
L
214#define EF_N_EEP (1<<7) /* Variable name is in EEPROM */
215#define EF_V_EEP (1<<6) /* Variable value is in EEPROM */
216#define EF_DIRTY (1<<0) /* Variable is new or value changed */
d684c216
L
217 uint8_t flags;
218 union {
219 uint16_t eep;
220 char *ram;
221 } name;
222 union {
223 uint16_t eep;
224 char *ram;
225 } val;
226} env_item_t;
227
323398b1 228static uint8_t env_valid;
d684c216
L
229static env_item_t env_list[CONFIG_ENVVAR_MAX];
230static int entrycount;
231
232
233static char env_get_char(uint16_t index)
234{
235 unsigned int off = CONFIG_ENV_OFFSET;
236
323398b1
L
237 if (env_valid == 2)
238 off = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
239
d684c216
L
240 return (char) eeprom_read_byte((const uint8_t *)off + index +
241 offsetof(env_t, data));
242}
243
244
245uint16_t ee_name_get(char *buf, env_item_t *ep)
246{
247 int i = 0;
248 char c;
249
250 if (ep->flags & EF_N_EEP) {
251
252 while ((c = env_get_char(ep->name.eep + i)) != '=' &&
253 c != '\0' && i < CONFIG_SYS_ENV_NAMELEN) {
254
255 buf[i] = c;
256 i++;
257 }
258 if (i > 0 && c != '=') {
259 debug("** ee_name: '%s' not '=' terminated!\n", buf);
260 }
261 } else {
262 strncpy(buf, ep->name.ram, CONFIG_SYS_ENV_NAMELEN);
263 i = strnlen(buf, CONFIG_SYS_ENV_NAMELEN);
264 }
265 buf[i] = '\0';
266 return i;
267}
268
269
270uint16_t ee_val_get(char *buf, uint16_t index, int len)
271{
272 int i = 0;
273 char c;
274
275 while ((c = env_get_char (index + i)) != '\0' && i < len) {
276 buf[i] = c;
277 i++;
278 };
279
280 buf[i] = '\0';
281
282 /* TODO: len check */
283
284 return i;
285}
286
287static
288int comp_env_key_item(const void *key, const void *item)
289{
290 char buf[CONFIG_SYS_ENV_NAMELEN+1];
291 env_item_t *ep = (env_item_t *) item;
292
293 ee_name_get(buf, ep);
294
295 return strcmp((char *) key, buf);
296}
297
298static
299int comp_env_items(const void *m1, const void *m2)
300{
301 char b1[CONFIG_SYS_ENV_NAMELEN+1];
302 char b2[CONFIG_SYS_ENV_NAMELEN+1];
303
304 env_item_t *ep1 = (env_item_t *) m1;
305 env_item_t *ep2 = (env_item_t *) m2;
306
307 ee_name_get(b1, ep1);
308 ee_name_get(b2, ep2);
309
310 return strcmp(b1, b2);
311}
312
313#if 0
314env_item_t * ee_entry_get(const char *s, env_item_t *ep, uint_fast8_t flag)
315{
316 char name[CONFIG_SYS_ENV_NAMELEN+1];
317 uint16_t idx = 0;
318 int nlen;
319
320//printf_P(PSTR("*** ee_entry_get: >>>>>>>>> ENTER <<<<<<<<<\n"));
321
322
323 while ((nlen = ee_name_get(name, idx)) != 0 && idx < CONFIG_ENV_SIZE) {
324
325//printf_P(PSTR("** idx: %d, name: '%s', s: '%s', nlen: %d, cpres:%d\n"),
326// idx, name, s, nlen, strncmp(name, s, nlen));
327
328 if (strncmp(name, s, nlen) == 0)
329 break;
330
331 idx += nlen + 1;
332 while (env_get_char(idx++) != 0)
333 ;
334 }
335
336 if (nlen) {
337 char *vp;
338 ep->flags = EF_N_EEP;
339 ep->name.eep = idx;
340 if (flag & ENV_GET_VAL) {
341 vp = xmalloc(CONFIG_SYS_CBSIZE);
342 nlen = ee_val_get(vp, idx + nlen + 1, CONFIG_SYS_CBSIZE);
343 ep->val = xrealloc(vp, nlen + 1);
344 } else
345 ep->val = NULL;
346
347
348//printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE 0x%.4x <<<<<\n"),
349// (unsigned int) ep);
350 return ep;
351 }
352
353//printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE <NULL> <<<<<\n"));
354 return NULL;
355}
356#endif
357
358#if 0
359static char p_env_name_buf[CONFIG_SYS_ENV_NAMELEN+1];
360
361static char *dbg_p_env_name(env_item_t *p)
362{
363 if (p->flags & EF_N_EEP) {
364 if (ee_name_get(p_env_name_buf, p) != 0)
365 return p_env_name_buf;
366 else
367 return "<NULL>";
368 }
369 return "<NO EEP_NAME>";
370}
371#endif
372
373int env_item_print(env_item_t *ep)
374{
375 char buf[CONFIG_SYS_ENV_NAMELEN+1];
376 int len;
377 env_item_t e = *ep;
378
379 ee_name_get(buf, ep);
380 len = printf_P(PSTR("%s="), buf);
381
382 if (e.val.ram != NULL) {
383 while (1) {
384 char c;
385 if (e.flags & EF_V_EEP)
386 c = env_get_char(e.val.eep++);
387 else
388 c = *e.val.ram++;
389
390 if (c != '\0') {
391 putchar(c);
392 len++;
393 } else
394 break;
395 }
396 }
397 putchar('\n');
398 len ++;
399
400 return len;
401}
402
403
323398b1
L
404int env_item_save(env_item_t *ep, uint16_t offset, int space_left)
405{
406 char buf[CONFIG_SYS_ENV_NAMELEN+1];
407 int len;
408 env_item_t e = *ep;
409
410debug("-- env_item_save(%04x, %04x, %d)\n",
411 ep, offset, space_left);
412
413 len = ee_name_get(buf, ep);
414 if (len == 0)
415 return 0;
416 buf[len++] = '=';
417 space_left -= len;
418
419if ((unsigned) len < sizeof(buf))
420 buf[len] = '\0'; /* terminate for debugging */
421debug(" len: %d, buf: '%s', space_left: %d\n", len, buf, space_left);
422
423 if (space_left <= 0)
424 return 0;
425
426 eeprom_update_block(buf, (uint8_t *) offset, len);
427 offset += len;
428
429 if (e.val.ram != NULL) {
430 char c;
431 do {
432 if (e.flags & EF_V_EEP)
433 c = env_get_char(e.val.eep++);
434 else
435 c = *e.val.ram++;
436
437 eeprom_update_byte((uint8_t *) offset, c);
438 offset++;
439 space_left--;
440 len++;
441 } while ((c != '\0') && space_left );
442 }
443 return len;
444}
445
446
447/*
448 * Update
449 *
450 */
451int env_item_update(env_item_t *ep)
452{
453 char buf[CONFIG_SYS_ENV_NAMELEN+1];
454 uint_fast8_t len;
455 char c;
456 unsigned pos = 0;
457
458 /* get name from old loc. (eeprom or ram */
459 len = ee_name_get(buf, ep);
460 buf[len++] = '=';
461
462debug("-- env_item_update(%04x)\n", ep);
463if (len < sizeof(buf))
464 buf[len] = '\0'; /* terminate for debugging */
465debug(" len: %d, buf: '%s'\n", len, buf);
466
467 /* search this name in new eeprom env */
468 /* TODO: eliminate this ugly hack */
469 uint8_t save_env_valid = env_valid;
470 env_valid = (env_valid == 2) ? 1 : 2;
471
472debug(" len: %d, buf: '%s', env_valid: %d\n", len, buf, env_valid);
473
474 while ((c = env_get_char(pos)) != '\0' && pos < (ENV_SIZE - len)) {
475 uint_fast8_t i = 0;
476
477debug(" while: c: %02x, pos: %d\n ", c, pos);
478
479 while (c == buf[i] && i <= len) {
480
481debug("%02x ", c);
482
483 ++i;
484 c = env_get_char(pos + i);
485 }
486
487debug("\n c: %02x, i: %d, pos: %d\n", c, i, pos);
488
489 if (i == len) {
490 if ((ep->flags & EF_N_EEP) == 0)
491 free(ep->name.ram);
492 ep->name.eep = pos;
493 if ((ep->flags & EF_V_EEP) == 0)
494 free(ep->val.ram);
495 ep->val.eep = pos + i;
496 ep->flags &= ~EF_DIRTY;
497 ep->flags |= EF_N_EEP | EF_V_EEP;
498
499 /* TODO: */
500 env_valid = save_env_valid;
501 return 0;
502 }
503 pos += i + 1;
504 while (((c = env_get_char(pos++)) != '\0') && pos < (ENV_SIZE - len))
505 ;
506
507debug("\n c: %02x, i: %d, pos: %d\n", c, i, pos);
508
509 }
510 /* TODO: */
511 env_valid = save_env_valid;
512
513 /* name not found */
514 return -1;
515}
516
517
518int envlist_import(void)
519{
520 char name[CONFIG_SYS_ENV_NAMELEN+1];
521 uint16_t idx = 0;
522 int nlen;
523 env_item_t e;
524
525 e.flags = EF_N_EEP | EF_V_EEP;
526 e.name.eep = idx;
527 while ((nlen = ee_name_get(name, &e)) != 0 && idx < ENV_SIZE) {
528
529 if (entrycount <= CONFIG_ENVVAR_MAX) {
530 e.val.eep = idx + nlen + 1;
531
532 env_list[entrycount++] = e;
533
534 idx += nlen + 1;
535 while (env_get_char(idx++) != 0 && idx < ENV_SIZE)
536 ;
537 e.name.eep = idx;
538 } else {
539 debug("** Too many environment variables!\n");
540 break;
541 }
542 }
543 qsort(env_list, entrycount, sizeof(env_item_t), comp_env_items);
544
545 return 0;
546}
547
d684c216
L
548static env_item_t *envlist_search(const char *name)
549{
550 return bsearch(name, env_list, entrycount,
551 sizeof(env_item_t), comp_env_key_item);
552}
553
72f58822 554#if 0
d684c216
L
555env_item_t *envlist_insert(const char *key, env_item_t *e)
556{
557 const size_t size = sizeof(env_item_t);
558
559 if (entrycount < CONFIG_ENVVAR_MAX) {
560 env_list[entrycount++] = *e;
561 qsort(env_list, entrycount, size, comp_env_items);
562
563 return bsearch(key, env_list, entrycount,
564 size, comp_env_key_item);
565
566 } else
567 return NULL;
568}
72f58822 569#endif
d684c216
L
570
571env_item_t *envlist_enter(env_item_t *e)
572{
573 char *key = e->name.ram;
574 const size_t size = sizeof(env_item_t);
575 env_item_t *ep;
576
577 ep = bsearch(key, env_list, entrycount,
578 size, comp_env_key_item);
579
580 if (ep == NULL) {
581 if (entrycount < CONFIG_ENVVAR_MAX) {
582
583 env_list[entrycount++] = *e;
584 qsort(env_list, entrycount, size, comp_env_items);
585 ep = bsearch(key, env_list, entrycount,
586 size, comp_env_key_item);
587 }
588 } else {
589 if ((ep->flags & EF_V_EEP) == 0) {
590 free(ep->val.ram);
591 }
592 ep->val.ram = e->val.ram;
593 }
594
595 if (ep != NULL) {
596 ep->flags |= EF_DIRTY;
597 ep->flags &= ~EF_V_EEP;
598
599 if ((ep->flags & EF_N_EEP) == 0) {
600 int nlen = strnlen(key, CONFIG_SYS_ENV_NAMELEN);
601 char *name = xmalloc(nlen + 1);
602 if (name == NULL) {
603 printf_P(PSTR("## Can't malloc %d bytes\n"),
604 nlen + 1);
605 return NULL;
606 }
607 strcpy(name, key);
608 name[nlen] = '\0';
609 ep->name.ram = name;
610 }
611 }
612
613 return ep;
614}
615
616
617static env_item_t *envlist_get(const char *name, uint_fast8_t flag)
618{
619 env_item_t *ep;
620
621 ep = envlist_search(name);
622
623 if (ep != NULL && (flag & ENV_GET_VAL)) {
624 if (ep->flags & EF_V_EEP) {
625 char *vp;
626 uint_fast8_t len;
323398b1
L
627 /* TODO: function that gets len of val,
628 to get rid of xrealloc */
d684c216
L
629 vp = xmalloc(CONFIG_SYS_CBSIZE);
630 len = ee_val_get(vp, ep->val.eep, CONFIG_SYS_CBSIZE);
631 ep->val.ram = xrealloc(vp, len + 1);
632 ep->flags &= ~EF_V_EEP;
633 }
634 }
635
636 return ep;
637}
638
323398b1
L
639int env_item_delete(env_item_t *ep)
640{
641 if (entrycount == 0)
642 return -1;
643 if ((ep->flags & EF_V_EEP) == 0)
644 free(ep->val.ram);
645 if ((ep->flags & EF_N_EEP) == 0)
646 free(ep->name.ram);
647
648 entrycount--;
649 size_t size = sizeof(env_item_t);
650 memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
651
652 return 0;
653}
d684c216
L
654
655static int envlist_delete(const char *name)
656{
d684c216
L
657 env_item_t *ep = bsearch(name, env_list, entrycount,
658 sizeof(env_item_t), comp_env_key_item);
d684c216 659
323398b1
L
660 if (ep != NULL)
661 return env_item_delete(ep);
d684c216 662
72f58822 663#if 0
d684c216
L
664 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
665 "=== env_list:");
666 dump_heap();
667 debug("** entrycount: %d\n", entrycount);
668 for (int i=0; i<entrycount; i++) {
669 printf_P(PSTR("** env var [%d] "), i);
670 env_item_print(&env_list[i]);
671 }
672#endif
673
323398b1 674 return 1;
d684c216
L
675}
676
d684c216
L
677char *getenv(const char *name)
678{
679 env_item_t *ep;
680 char *ret = NULL;
681
682 debug("** getenv: %s\n", name);
683
684 ep = envlist_get(name, ENV_GET_VAL);
685 if (ep != NULL)
686 ret = ep->val.ram;
72f58822 687#if 0
d684c216
L
688 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
689 "=== env_list:");
690 dump_heap();
691 debug("** entrycount: %d\n", entrycount);
692 for (int i=0; i<entrycount; i++) {
693 printf_P(PSTR("** env var [%d] "), i);
694 env_item_print(&env_list[i]);
695 }
696#endif
d684c216
L
697 return ret;
698}
699
323398b1
L
700uint16_t env_crc(uint16_t data_offset)
701{
702 uint16_t crc;
703 uint16_t i;
704 char c, c0;
705
706 crc = 0xffff;
707 c = 0xff;
708 for (i = 0; !(c == 0 && c0 == 0) && i < ENV_SIZE; i++)
709 {
710 c0 = c;
711 c = eeprom_read_byte((const uint8_t *) data_offset + i);
712 crc = crc16(crc, c);
713 }
714 return crc ;
715}
716
d684c216
L
717int saveenv(void)
718{
323398b1
L
719 unsigned int off = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
720 unsigned int off_red = CONFIG_ENV_OFFSET;
721 unsigned int pos;
722 int len, left;
723 uint16_t crc;
724 int rc = 0;
d684c216 725
323398b1
L
726 if (env_valid == 2) {
727 off = CONFIG_ENV_OFFSET;
728 off_red = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
729 }
730
731 eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags), 0xff);
d684c216 732
323398b1
L
733 pos = off + offsetof(env_t, data);
734 left = ENV_SIZE - 1;
735 for (int i = 0 ; i < entrycount; i++) {
736 len = env_item_save(&env_list[i], pos, left);
737 if (len == 0) {
738 return 1;
739 }
740 pos += len;
741 left -= len;
742 }
743 /* terminate list */
744 eeprom_update_byte((uint8_t *) pos, 0);
745 crc = env_crc(off + offsetof(env_t, data));
746 eeprom_update_word((uint16_t *) off + offsetof(env_t, crc), crc);
747 eeprom_update_byte((uint8_t *) off + offsetof(env_t, flags),
748 ACTIVE_FLAG);
749
750 if (rc == 0) {
751 while (entrycount != 0) {
752 env_item_delete(&env_list[entrycount-1]);
753 }
754 eeprom_update_byte((uint8_t *) off_red + offsetof(env_t, flags),
755 OBSOLETE_FLAG);
756 env_valid = (env_valid == 2) ? 1 : 2;
757
758 envlist_import();
759 }
760
d684c216
L
761 return rc;
762}
763
d684c216
L
764/*-----------------------------------------------------------------------------*/
765
d684c216
L
766int set_default_env(void)
767{
768 char buf[64];
d684c216 769 uint16_t eep = CONFIG_ENV_OFFSET + offsetof(env_t, data);
534e1dfc 770 unsigned int len = ENV_SIZE;
d684c216
L
771 unsigned int i, src = 0;
772 char c = 0xff, c0 = c;
72f58822 773#if 0
d684c216 774printf_P(PSTR("\n\n** set_default_env()\n"));
72f58822 775#endif
323398b1
L
776 if (env_valid == 1) {
777 eep = CONFIG_ENV_OFFSET + offsetof(env_t, data) + CONFIG_ENV_SIZE;
778 }
779
d684c216 780 while (len) {
d684c216 781 memcpy_P(buf, default_env+src, sizeof(buf));
d684c216 782 for (i=0; i < (len < sizeof(buf) ? len : sizeof(buf)) &&
323398b1
L
783 !(c == 0 && c0 == 0);
784 i++) {
d684c216 785 c0 = c; c = buf[i];
d684c216 786 }
d684c216 787 eeprom_update_block(buf, (char *) eep, i);
72f58822
L
788#if 0
789 printf_P(PSTR("eeprom_update_block: eep: 0x%.4x, i:%d\n"),
d684c216 790 (unsigned int) eep, i);
72f58822
L
791 dump_ram((uint8_t *) buf, i, "=== buf:");
792 dump_eep((const uint8_t *) eep, i);
793#endif
d684c216
L
794 if (c == 0 && c0 == 0)
795 len = 0;
796 if (len > sizeof(buf))
797 len -= sizeof(buf);
798 src += sizeof(buf);
799 eep += sizeof(buf);
800 }
534e1dfc 801
72f58822
L
802#if 0
803 dump_eep(0, 128);
804#endif
d684c216
L
805 return 0;
806}
807
808
323398b1 809int env_check(uint16_t offset)
d684c216
L
810{
811 uint16_t crc, stored_crc;
d684c216
L
812
813 /* read old CRC */
323398b1
L
814 stored_crc = eeprom_read_word(
815 (const uint16_t *) offset + offsetof(env_t, crc));
816 crc = env_crc(offset + offsetof(env_t, data));
817
534e1dfc
L
818 debug_cond((crc != stored_crc),
819 "** crc eep: 0x%.4x, crc new: 0x%.4x\n", stored_crc, crc);
d684c216
L
820
821 return crc == stored_crc;
822}
823
323398b1 824int _env_init(void)
d684c216 825{
323398b1
L
826 unsigned int off_env[2];
827 uint8_t flags[2], crc_ok[2];
828
829 off_env[0] = CONFIG_ENV_OFFSET;
830 off_env[1] = CONFIG_ENV_OFFSET + CONFIG_ENV_SIZE;
831
832 for (uint_fast8_t i = 0; i < 2; i++) {
833 /* read FLAGS */
834 flags[i] = eeprom_read_byte ((uint8_t *) off_env[i] +
835 offsetof(env_t, flags));
836
837 /* check CRC */
838 crc_ok[i] = (
839 eeprom_read_word((uint16_t *) off_env[i] +
840 offsetof(env_t, crc))
841 == env_crc(off_env[i] + offsetof(env_t, data))
842 );
843 }
d684c216 844
323398b1
L
845 if (!crc_ok[0] && !crc_ok[1]) {
846 env_valid = 0;
847debug("crc1: %02x, crc2: %02x, flag1 %02x, flag2 %02x, env_valid: %d\n",
848 crc_ok[0], crc_ok[1], flags[0], flags[1], env_valid);
849 return 0;
850
851 } else if (crc_ok[0] && !crc_ok[1]) {
852 env_valid = 1;
853 } else if (!crc_ok[0] && crc_ok[1]) {
854 env_valid = 2;
855 } else {
856 /* both ok - check serial */
857 if (flags[0] == ACTIVE_FLAG && flags[1] == OBSOLETE_FLAG)
858 env_valid = 1;
859 else if (flags[0] == OBSOLETE_FLAG && flags[1] == ACTIVE_FLAG)
860 env_valid = 2;
861 else if (flags[0] == 0xFF && flags[1] == 0)
862 env_valid = 2;
863 else if (flags[1] == 0xFF && flags[0] == 0)
864 env_valid = 1;
865 else /* flags are equal - almost impossible */
866 env_valid = 1;
d684c216 867 }
323398b1
L
868
869debug("crc1: %02x, crc2: %02x, flag1 %02x, flag2 %02x, env_valid: %d\n",
870 crc_ok[0], crc_ok[1], flags[0], flags[1], env_valid);
d684c216
L
871
872 return 0;
873}
874
875
323398b1
L
876int env_init(void)
877{
878 _env_init();
879 if (env_valid == 0) {
880 printf_P(PSTR("*** Warning - bad CRC, "
881 "using default environment\n\n"));
882 set_default_env();
883 }
884 entrycount = 0;
885 envlist_import();
886 return 0;
887}
888
889
d684c216
L
890/*
891 * Command interface: print one or all environment variables
892 *
893 * Returns -1 in case of error, or length of printed string
894 */
895static int env_print(char *name)
896{
897 int len = -1;
898
899 if (name) { /* print a single name */
900
901 env_item_t *ep = envlist_search(name);
902 if (ep != NULL)
903 len = env_item_print(ep);
904
905 } else { /* print whole list */
906 len = 0;
907 for (int i = 0 ; i < entrycount; i++) {
908 len += env_item_print(&env_list[i]);
909 }
910 }
911 return len;
912}
913
534e1dfc
L
914int env_print_ramsize(void)
915{
916 int size = 0;
917 uint8_t name_cnt = 0;
918 uint8_t val_cnt = 0;
919
920 for (int i = 0 ; i < entrycount; i++) {
921 if ((env_list[i].flags & EF_N_EEP) == 0 &&
922 (env_list[i].name.ram != NULL)) {
923 name_cnt++;
924 size += strlen(env_list[i].name.ram) + 3;
925 }
926 if ((env_list[i].flags & EF_V_EEP) == 0 &&
927 (env_list[i].val.ram != NULL)) {
928 val_cnt++;
929 size += strlen(env_list[i].val.ram) + 3;
930 }
931 }
932 printf_P(PSTR("%d bytes RAM used for %u names and %u values\n"),
933 size, name_cnt, val_cnt);
934 return size;
935}
d684c216
L
936
937int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
938 char * const argv[])
939{
940 int i;
941 int rcode = 0;
942
943 (void) cmdtp; (void) flag;
944
945 if (argc == 1) {
946 /* print all env vars */
947 rcode = env_print(NULL);
948 if (rcode < 0)
949 return 1;
950 printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
951 rcode, ENV_SIZE);
534e1dfc 952 env_print_ramsize();
d684c216
L
953 return 0;
954 }
955
956 /* print selected env vars */
957 for (i = 1; i < argc; ++i) {
958 int rc = env_print(argv[i]);
959 if (rc < 0) {
960 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
961 ++rcode;
962 }
963 }
964
965 return rcode;
966}
967
968
72f58822
L
969/**
970 * Set or delete environment variable
971 *
d684c216
L
972 * Set a new environment variable,
973 * or replace or delete an existing one.
72f58822
L
974 *
975 * @param flag (not used)
976 * @param argc
977 * @param argv[1] Environment variable to set or delete
978 * if no more args
979 * @param argv[2] ... Value to set it to
980 *
981 * @return 0 if ok, 1 on error
d684c216
L
982 */
983static int _do_env_set(int flag, int argc, char * const argv[])
984{
72f58822
L
985 int i, len;
986 char *name, *value, *s;
d684c216
L
987 env_item_t e, *ep;
988
989 (void) flag;
990 debug("Initial value for argc=%d\n", argc);
991
992 name = argv[1];
993 value = argv[2];
994
995 if (strchr(name, '=')) {
996 printf_P(PSTR("## Error: illegal character '='"
997 "in variable name \"%s\"\n"), name);
998 return 1;
999 }
1000 if (strlen(name) > CONFIG_SYS_ENV_NAMELEN) {
1001 printf_P(PSTR("## Error: Variable name \"%s\" too long. "
1002 "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
1003 return 1;
1004 }
1005/*
1006 env_id++;
1007*/
1008 /* Delete only ? */
1009 if (argc < 3 || argv[2] == NULL) {
1010 int rc = envlist_delete(name);
323398b1 1011 return rc != 0;
d684c216
L
1012 }
1013
1014 /*
1015 * Insert / replace new value
1016 */
1017 for (i = 2, len = 0; i < argc; ++i)
1018 len += strlen(argv[i]) + 1;
1019
1020 value = xmalloc(len);
1021 if (value == NULL) {
1022 printf_P(PSTR("## Can't malloc %d bytes\n"), len);
1023 return 1;
1024 }
1025 for (i = 2, s = value; i < argc; ++i) {
1026 char *v = argv[i];
1027
1028 while ((*s++ = *v++) != '\0')
1029 ;
1030 *(s - 1) = ' ';
1031 }
1032 if (s != value)
1033 *--s = '\0';
1034
1035 e.flags = EF_DIRTY;
1036 e.name.ram = name;
1037 e.val.ram = value;
1038 ep = envlist_enter(&e);
1039 if (!ep) {
1040 printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
1041 name);
1042 return 1;
1043 }
1044
1045 return 0;
1046}
1047
72f58822
L
1048/**
1049 * Set an environment variable
1050 *
1051 * @param varname Environment variable to set
1052 * @param varvalue Value to set it to
1053 * @return 0 if ok, 1 on error
1054 */
d684c216
L
1055int setenv(const char *varname, const char *varvalue)
1056{
1057 const char * const argv[3] = { NULL, varname, varvalue };
1058 int argc = 3;
1059
1060 if (varvalue == NULL || varvalue[0] == '\0')
1061 --argc;
1062
1063 return _do_env_set(0, argc, (char * const *)argv);
1064}
1065
1066#if 0
1067/**
1068 * Set an environment variable to an integer value
1069 *
1070 * @param varname Environment variable to set
1071 * @param value Value to set it to
1072 * @return 0 if ok, 1 on error
1073 */
1074int setenv_ulong(const char *varname, unsigned long value)
1075{
1076 /* TODO: this should be unsigned */
1077 char *str = simple_itoa(value);
1078
1079 return setenv(varname, str);
1080}
1081#endif
1082
1083
1084/**
1085 * Set an environment variable to an value in hex
1086 *
1087 * @param varname Environment variable to set
1088 * @param value Value to set it to
1089 * @return 0 if ok, 1 on error
1090 */
1091int setenv_hex(const char *varname, unsigned long value)
1092{
1093 char str[sizeof(unsigned long) *2 + 1];
1094
1095 sprintf_P(str, PSTR("%lx"), value);
1096 return setenv(varname, str);
1097}
1098
72f58822
L
1099/**
1100 * Get an environment variable as a hex value
1101 *
1102 * @param varname Environment variable to get
1103 * @param default_val Return this, if variable does not exist
1104 * @return hex value of variable or default_val
1105 */
d684c216
L
1106unsigned long getenv_hex(const char *varname, unsigned long default_val)
1107{
1108 const char *s;
1109 unsigned long value;
1110 char *endp;
1111
1112 s = getenv(varname);
1113 if (s)
1114 value = strtoul(s, &endp, 16);
1115 if (!s || endp == s)
1116 return default_val;
1117
1118 return value;
1119}
1120
1121int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1122{
1123 (void) cmdtp;
1124
1125 if (argc < 2)
1126 return CMD_RET_USAGE;
1127
1128 return _do_env_set(flag, argc, argv);
1129}
1130
1131
323398b1
L
1132int do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
1133{
1134 (void) cmdtp; (void) flag; (void) argc; (void) argv;
1135
1136 printf_P(PSTR("Saving Environment ...\n"));
1137
1138 return saveenv() ? 1 : 0;
1139}
1140
d684c216
L
1141#if defined(CONFIG_AUTO_COMPLETE)
1142int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
1143{
1144 ENTRY *match;
1145 int found, idx;
1146
1147 idx = 0;
1148 found = 0;
1149 cmdv[0] = NULL;
1150
1151 while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
1152 int vallen = strlen(match->key) + 1;
1153
1154 if (found >= maxv - 2 || bufsz < vallen)
1155 break;
1156
1157 cmdv[found++] = buf;
1158 memcpy(buf, match->key, vallen);
1159 buf += vallen;
1160 bufsz -= vallen;
1161 }
1162
1163 qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
1164
1165 if (idx)
1166 cmdv[found++] = "...";
1167
1168 cmdv[found] = NULL;
1169 return found;
1170}
1171#endif