]> cloudbase.mooo.com Git - z180-stamp.git/blame - avr/env.c
New U-Boot like AVR main program.
[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
16
17#define DELIM "\0"
18#define ENV_SIZE CONFIG_ENV_SIZE-2
19
20
21#define ENV_GET_VAL (1<<0)
22
23
24/*
25 * Debugging
26 *
27 * TODO: move elsewhere
28 */
29#include <ctype.h>
30
31static void print_blanks(uint_fast8_t count)
32{
33 while(count--)
34 putchar(' ');
35}
36
37
38void dump_ram(const uint8_t *startaddr, int len, char *title)
39{
40 uint8_t llen = 16;
41 uint8_t pre = (size_t) startaddr % 16;
42 const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
43 len += pre;
44 uint8_t i;
45
46 if (title && *title)
47 printf_P(PSTR("%s\n"),title);
48
49 while (len) {
50 if (len < 16)
51 llen = len;
52
53 printf_P(PSTR(" %.4x:"), (size_t) addr);
54 print_blanks(3 * pre);
55 for (i = pre; i < llen; i++)
56 printf_P(PSTR(" %.2x"), addr[i]);
57 print_blanks(3 * (16 - i + 1) + pre);
58 for (i = pre; i < llen; i++)
59 printf_P(PSTR("%c"), isprint(addr[i]) ? addr[i] : '.');
60 putchar('\n');
61
62 pre = 0;
63 addr += 16;
64 len -= llen;
65 }
66}
67
68void dump_heap(void)
69{
70 extern unsigned int __brkval;
71
72 dump_ram((uint8_t *) __malloc_heap_start,
73 __brkval - (unsigned int) __malloc_heap_start,
74 "=== Heap:");
75}
76
77/* TODO: combine with dump_ram() */
78void dump_eep(const uint8_t *addr, int len)
79{
80 int i;
81 uint8_t buf[16];
82
83 printf_P(PSTR("eeprom dump:"));
84 while (len) {
85 printf_P(PSTR("\n 0x%.4x:"), (unsigned int) addr);
86 for (i = 0; i<16; i++)
87 buf[i] = eeprom_read_byte(addr + i);
88 for (i = 0; i<16; i++)
89 printf_P(PSTR(" %.2x"), buf[i]);
90 printf_P(PSTR(" "));
91 for (i = 0; i<16; i++)
92 printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
93
94 addr += 16;
95 len -= len > 16 ? 16 : len;
96 }
97 putchar('\n');
98}
99
100
101const FLASH char default_env[] = {
102 "bootdelay=" "3" DELIM
103 "bootcmd=" "echo hallo" DELIM
104 "baudrate=" "115200" DELIM
105 DELIM
106};
107
108
109typedef struct environment_s {
110 uint16_t crc; /* CRC16 over data bytes */
111 char data[ENV_SIZE]; /* Environment data */
112} env_t;
113
114
115
116typedef struct env_item_s {
117#define EF_N_EEP (1<<7)
118#define EF_V_EEP (1<<6)
119#define EF_DIRTY (1<<0)
120 uint8_t flags;
121 union {
122 uint16_t eep;
123 char *ram;
124 } name;
125 union {
126 uint16_t eep;
127 char *ram;
128 } val;
129} env_item_t;
130
131
132static env_item_t env_list[CONFIG_ENVVAR_MAX];
133static int entrycount;
134
135
136static char env_get_char(uint16_t index)
137{
138 unsigned int off = CONFIG_ENV_OFFSET;
139
140 return (char) eeprom_read_byte((const uint8_t *)off + index +
141 offsetof(env_t, data));
142}
143
144
145uint16_t ee_name_get(char *buf, env_item_t *ep)
146{
147 int i = 0;
148 char c;
149
150 if (ep->flags & EF_N_EEP) {
151
152 while ((c = env_get_char(ep->name.eep + i)) != '=' &&
153 c != '\0' && i < CONFIG_SYS_ENV_NAMELEN) {
154
155 buf[i] = c;
156 i++;
157 }
158 if (i > 0 && c != '=') {
159 debug("** ee_name: '%s' not '=' terminated!\n", buf);
160 }
161 } else {
162 strncpy(buf, ep->name.ram, CONFIG_SYS_ENV_NAMELEN);
163 i = strnlen(buf, CONFIG_SYS_ENV_NAMELEN);
164 }
165 buf[i] = '\0';
166 return i;
167}
168
169
170uint16_t ee_val_get(char *buf, uint16_t index, int len)
171{
172 int i = 0;
173 char c;
174
175 while ((c = env_get_char (index + i)) != '\0' && i < len) {
176 buf[i] = c;
177 i++;
178 };
179
180 buf[i] = '\0';
181
182 /* TODO: len check */
183
184 return i;
185}
186
187static
188int comp_env_key_item(const void *key, const void *item)
189{
190 char buf[CONFIG_SYS_ENV_NAMELEN+1];
191 env_item_t *ep = (env_item_t *) item;
192
193 ee_name_get(buf, ep);
194
195 return strcmp((char *) key, buf);
196}
197
198static
199int comp_env_items(const void *m1, const void *m2)
200{
201 char b1[CONFIG_SYS_ENV_NAMELEN+1];
202 char b2[CONFIG_SYS_ENV_NAMELEN+1];
203
204 env_item_t *ep1 = (env_item_t *) m1;
205 env_item_t *ep2 = (env_item_t *) m2;
206
207 ee_name_get(b1, ep1);
208 ee_name_get(b2, ep2);
209
210 return strcmp(b1, b2);
211}
212
213#if 0
214env_item_t * ee_entry_get(const char *s, env_item_t *ep, uint_fast8_t flag)
215{
216 char name[CONFIG_SYS_ENV_NAMELEN+1];
217 uint16_t idx = 0;
218 int nlen;
219
220//printf_P(PSTR("*** ee_entry_get: >>>>>>>>> ENTER <<<<<<<<<\n"));
221
222
223 while ((nlen = ee_name_get(name, idx)) != 0 && idx < CONFIG_ENV_SIZE) {
224
225//printf_P(PSTR("** idx: %d, name: '%s', s: '%s', nlen: %d, cpres:%d\n"),
226// idx, name, s, nlen, strncmp(name, s, nlen));
227
228 if (strncmp(name, s, nlen) == 0)
229 break;
230
231 idx += nlen + 1;
232 while (env_get_char(idx++) != 0)
233 ;
234 }
235
236 if (nlen) {
237 char *vp;
238 ep->flags = EF_N_EEP;
239 ep->name.eep = idx;
240 if (flag & ENV_GET_VAL) {
241 vp = xmalloc(CONFIG_SYS_CBSIZE);
242 nlen = ee_val_get(vp, idx + nlen + 1, CONFIG_SYS_CBSIZE);
243 ep->val = xrealloc(vp, nlen + 1);
244 } else
245 ep->val = NULL;
246
247
248//printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE 0x%.4x <<<<<\n"),
249// (unsigned int) ep);
250 return ep;
251 }
252
253//printf_P(PSTR("*** ee_entry_get: >>>>>> LEAVE <NULL> <<<<<\n"));
254 return NULL;
255}
256#endif
257
258#if 0
259static char p_env_name_buf[CONFIG_SYS_ENV_NAMELEN+1];
260
261static char *dbg_p_env_name(env_item_t *p)
262{
263 if (p->flags & EF_N_EEP) {
264 if (ee_name_get(p_env_name_buf, p) != 0)
265 return p_env_name_buf;
266 else
267 return "<NULL>";
268 }
269 return "<NO EEP_NAME>";
270}
271#endif
272
273int env_item_print(env_item_t *ep)
274{
275 char buf[CONFIG_SYS_ENV_NAMELEN+1];
276 int len;
277 env_item_t e = *ep;
278
279 ee_name_get(buf, ep);
280 len = printf_P(PSTR("%s="), buf);
281
282 if (e.val.ram != NULL) {
283 while (1) {
284 char c;
285 if (e.flags & EF_V_EEP)
286 c = env_get_char(e.val.eep++);
287 else
288 c = *e.val.ram++;
289
290 if (c != '\0') {
291 putchar(c);
292 len++;
293 } else
294 break;
295 }
296 }
297 putchar('\n');
298 len ++;
299
300 return len;
301}
302
303
304static env_item_t *envlist_search(const char *name)
305{
306 return bsearch(name, env_list, entrycount,
307 sizeof(env_item_t), comp_env_key_item);
308}
309
310
311env_item_t *envlist_insert(const char *key, env_item_t *e)
312{
313 const size_t size = sizeof(env_item_t);
314
315 if (entrycount < CONFIG_ENVVAR_MAX) {
316 env_list[entrycount++] = *e;
317 qsort(env_list, entrycount, size, comp_env_items);
318
319 return bsearch(key, env_list, entrycount,
320 size, comp_env_key_item);
321
322 } else
323 return NULL;
324}
325
326
327env_item_t *envlist_enter(env_item_t *e)
328{
329 char *key = e->name.ram;
330 const size_t size = sizeof(env_item_t);
331 env_item_t *ep;
332
333 ep = bsearch(key, env_list, entrycount,
334 size, comp_env_key_item);
335
336 if (ep == NULL) {
337 if (entrycount < CONFIG_ENVVAR_MAX) {
338
339 env_list[entrycount++] = *e;
340 qsort(env_list, entrycount, size, comp_env_items);
341 ep = bsearch(key, env_list, entrycount,
342 size, comp_env_key_item);
343 }
344 } else {
345 if ((ep->flags & EF_V_EEP) == 0) {
346 free(ep->val.ram);
347 }
348 ep->val.ram = e->val.ram;
349 }
350
351 if (ep != NULL) {
352 ep->flags |= EF_DIRTY;
353 ep->flags &= ~EF_V_EEP;
354
355 if ((ep->flags & EF_N_EEP) == 0) {
356 int nlen = strnlen(key, CONFIG_SYS_ENV_NAMELEN);
357 char *name = xmalloc(nlen + 1);
358 if (name == NULL) {
359 printf_P(PSTR("## Can't malloc %d bytes\n"),
360 nlen + 1);
361 return NULL;
362 }
363 strcpy(name, key);
364 name[nlen] = '\0';
365 ep->name.ram = name;
366 }
367 }
368
369 return ep;
370}
371
372
373static env_item_t *envlist_get(const char *name, uint_fast8_t flag)
374{
375 env_item_t *ep;
376
377 ep = envlist_search(name);
378
379 if (ep != NULL && (flag & ENV_GET_VAL)) {
380 if (ep->flags & EF_V_EEP) {
381 char *vp;
382 uint_fast8_t len;
383 vp = xmalloc(CONFIG_SYS_CBSIZE);
384 len = ee_val_get(vp, ep->val.eep, CONFIG_SYS_CBSIZE);
385 ep->val.ram = xrealloc(vp, len + 1);
386 ep->flags &= ~EF_V_EEP;
387 }
388 }
389
390 return ep;
391}
392
393
394static int envlist_delete(const char *name)
395{
396 size_t size = sizeof(env_item_t);
397 env_item_t *ep = bsearch(name, env_list, entrycount,
398 sizeof(env_item_t), comp_env_key_item);
399 int rc = 0;
400
401 if (ep != NULL) {
402
403 if ((ep->flags & EF_V_EEP) == 0)
404 free(ep->val.ram);
405 if ((ep->flags & EF_N_EEP) == 0)
406 free(ep->name.ram);
407
408 entrycount--;
409printf_P(PSTR("*** envlist_delete memmove: 0x%.4x, 0x%.4x, %d\n"),
410 (unsigned) ep, (unsigned) ep + size,
411 (env_list - ep)*size + entrycount*size);
412 memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
413
414 rc = 1;
415 }
416#if 1
417 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
418 "=== env_list:");
419 dump_heap();
420 debug("** entrycount: %d\n", entrycount);
421 for (int i=0; i<entrycount; i++) {
422 printf_P(PSTR("** env var [%d] "), i);
423 env_item_print(&env_list[i]);
424 }
425#endif
426
427 return rc;
428}
429
430
431char *getenv(const char *name)
432{
433 env_item_t *ep;
434 char *ret = NULL;
435
436 debug("** getenv: %s\n", name);
437
438 ep = envlist_get(name, ENV_GET_VAL);
439 if (ep != NULL)
440 ret = ep->val.ram;
441
442#if 1
443 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
444 "=== env_list:");
445 dump_heap();
446 debug("** entrycount: %d\n", entrycount);
447 for (int i=0; i<entrycount; i++) {
448 printf_P(PSTR("** env var [%d] "), i);
449 env_item_print(&env_list[i]);
450 }
451#endif
452
453 return ret;
454}
455
456int saveenv(void)
457{
458 int rc = 0;
459
460
461// rc = env_export(&env_new);
462 if (rc)
463 return rc;
464
465
466// rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
467// off, (uchar *)&env_new, CONFIG_ENV_SIZE);
468
469 return rc;
470}
471
472
473/*-----------------------------------------------------------------------------*/
474
475
476int set_default_env(void)
477{
478 char buf[64];
479 uint16_t crc = 0xffff;
480 uint16_t eep = CONFIG_ENV_OFFSET + offsetof(env_t, data);
481 unsigned int len = CONFIG_ENV_SIZE - offsetof(env_t, data);
482 unsigned int i, src = 0;
483 char c = 0xff, c0 = c;
484
485printf_P(PSTR("\n\n** set_default_env()\n"));
486
487 while (len) {
488
489 memcpy_P(buf, default_env+src, sizeof(buf));
490
491 for (i=0; i < (len < sizeof(buf) ? len : sizeof(buf)) &&
492 !(c == 0 && c0 == 0);
493 i++)
494 {
495 c0 = c; c = buf[i];
496 crc = crc16(crc, c);
497 }
498
499 eeprom_update_block(buf, (char *) eep, i);
500/**/ printf_P(PSTR("eeprom_update_block: eep: 0x%.4x, i:%d\n"),
501 (unsigned int) eep, i);
502/**/ dump_ram((uint8_t *) buf, i, "=== buf:");
503/**/ dump_eep((const uint8_t *) eep, i);
504
505 if (c == 0 && c0 == 0)
506 len = 0;
507 if (len > sizeof(buf))
508 len -= sizeof(buf);
509 src += sizeof(buf);
510 eep += sizeof(buf);
511 }
512
513printf_P(PSTR("** crc adr: 0x%.4x, crc: 0x%.4x\n"),
514 (unsigned int) (uint16_t *) CONFIG_ENV_OFFSET + offsetof(env_t,crc), crc);
515
516 eeprom_update_word((uint16_t *) CONFIG_ENV_OFFSET + offsetof(env_t,crc), crc);
517
518/**/ dump_eep(0, 128);
519 return 0;
520}
521
522
523int env_check(void)
524{
525 uint16_t crc, stored_crc;
526 uint16_t i;
527 char c, c0;
528
529 debug("\n\n** env_check()\n");
530
531
532 /* read old CRC */
533 stored_crc = eeprom_read_word((const uint16_t *) CONFIG_ENV_OFFSET +
534 offsetof(env_t, crc));
535 crc = 0xffff;
536 c = 0xff;
537 for (i = offsetof(env_t, data);
538 !(c == 0 && c0 == 0) && i < CONFIG_ENV_SIZE;
539 i++)
540 {
541 c0 = c;
542 c = eeprom_read_byte((const uint8_t *) CONFIG_ENV_OFFSET + i);
543 crc = crc16(crc, c);
544 }
545 debug("** crc eep: 0x%.4x, crc new: 0x%.4x\n", stored_crc, crc);
546
547 return crc == stored_crc;
548}
549
550int env_init(void)
551{
552 char name[CONFIG_SYS_ENV_NAMELEN+1];
553 uint16_t idx = 0;
554 int nlen;
555 env_item_t e;
556
557 e.flags = EF_N_EEP | EF_V_EEP;
558 e.name.eep = idx;
559 while ((nlen = ee_name_get(name, &e)) != 0 && idx < ENV_SIZE) {
560
561 if (entrycount <= CONFIG_ENVVAR_MAX) {
562 e.val.eep = idx + nlen + 1;
563
564 env_list[entrycount++] = e;
565
566 idx += nlen + 1;
567 while (env_get_char(idx++) != 0 && idx < ENV_SIZE)
568 ;
569 e.name.eep = idx;
570 } else {
571 debug("** Too many environment variables!\n");
572 break;
573 }
574 }
575 qsort(env_list, entrycount, sizeof(env_item_t), comp_env_items);
576
577 return 0;
578}
579
580
581/*
582 * Command interface: print one or all environment variables
583 *
584 * Returns -1 in case of error, or length of printed string
585 */
586static int env_print(char *name)
587{
588 int len = -1;
589
590 if (name) { /* print a single name */
591
592 env_item_t *ep = envlist_search(name);
593 if (ep != NULL)
594 len = env_item_print(ep);
595
596 } else { /* print whole list */
597 len = 0;
598 for (int i = 0 ; i < entrycount; i++) {
599 len += env_item_print(&env_list[i]);
600 }
601 }
602 return len;
603}
604
605
606
607int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
608 char * const argv[])
609{
610 int i;
611 int rcode = 0;
612
613 (void) cmdtp; (void) flag;
614
615 if (argc == 1) {
616 /* print all env vars */
617 rcode = env_print(NULL);
618 if (rcode < 0)
619 return 1;
620 printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
621 rcode, ENV_SIZE);
622 return 0;
623 }
624
625 /* print selected env vars */
626 for (i = 1; i < argc; ++i) {
627 int rc = env_print(argv[i]);
628 if (rc < 0) {
629 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
630 ++rcode;
631 }
632 }
633
634 return rcode;
635}
636
637
638/*
639 * Set a new environment variable,
640 * or replace or delete an existing one.
641 */
642static int _do_env_set(int flag, int argc, char * const argv[])
643{
644 int i, len;
645 char *name, *value, *s;
646 env_item_t e, *ep;
647
648 (void) flag;
649 debug("Initial value for argc=%d\n", argc);
650
651 name = argv[1];
652 value = argv[2];
653
654 if (strchr(name, '=')) {
655 printf_P(PSTR("## Error: illegal character '='"
656 "in variable name \"%s\"\n"), name);
657 return 1;
658 }
659 if (strlen(name) > CONFIG_SYS_ENV_NAMELEN) {
660 printf_P(PSTR("## Error: Variable name \"%s\" too long. "
661 "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
662 return 1;
663 }
664/*
665 env_id++;
666*/
667 /* Delete only ? */
668 if (argc < 3 || argv[2] == NULL) {
669 int rc = envlist_delete(name);
670 return !rc;
671 }
672
673 /*
674 * Insert / replace new value
675 */
676 for (i = 2, len = 0; i < argc; ++i)
677 len += strlen(argv[i]) + 1;
678
679 value = xmalloc(len);
680 if (value == NULL) {
681 printf_P(PSTR("## Can't malloc %d bytes\n"), len);
682 return 1;
683 }
684 for (i = 2, s = value; i < argc; ++i) {
685 char *v = argv[i];
686
687 while ((*s++ = *v++) != '\0')
688 ;
689 *(s - 1) = ' ';
690 }
691 if (s != value)
692 *--s = '\0';
693
694 e.flags = EF_DIRTY;
695 e.name.ram = name;
696 e.val.ram = value;
697 ep = envlist_enter(&e);
698 if (!ep) {
699 printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
700 name);
701 return 1;
702 }
703
704 return 0;
705}
706
707int setenv(const char *varname, const char *varvalue)
708{
709 const char * const argv[3] = { NULL, varname, varvalue };
710 int argc = 3;
711
712 if (varvalue == NULL || varvalue[0] == '\0')
713 --argc;
714
715 return _do_env_set(0, argc, (char * const *)argv);
716}
717
718#if 0
719/**
720 * Set an environment variable to an integer value
721 *
722 * @param varname Environment variable to set
723 * @param value Value to set it to
724 * @return 0 if ok, 1 on error
725 */
726int setenv_ulong(const char *varname, unsigned long value)
727{
728 /* TODO: this should be unsigned */
729 char *str = simple_itoa(value);
730
731 return setenv(varname, str);
732}
733#endif
734
735
736/**
737 * Set an environment variable to an value in hex
738 *
739 * @param varname Environment variable to set
740 * @param value Value to set it to
741 * @return 0 if ok, 1 on error
742 */
743int setenv_hex(const char *varname, unsigned long value)
744{
745 char str[sizeof(unsigned long) *2 + 1];
746
747 sprintf_P(str, PSTR("%lx"), value);
748 return setenv(varname, str);
749}
750
751unsigned long getenv_hex(const char *varname, unsigned long default_val)
752{
753 const char *s;
754 unsigned long value;
755 char *endp;
756
757 s = getenv(varname);
758 if (s)
759 value = strtoul(s, &endp, 16);
760 if (!s || endp == s)
761 return default_val;
762
763 return value;
764}
765
766int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
767{
768 (void) cmdtp;
769
770 if (argc < 2)
771 return CMD_RET_USAGE;
772
773 return _do_env_set(flag, argc, argv);
774}
775
776
777#if defined(CONFIG_AUTO_COMPLETE)
778int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
779{
780 ENTRY *match;
781 int found, idx;
782
783 idx = 0;
784 found = 0;
785 cmdv[0] = NULL;
786
787 while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
788 int vallen = strlen(match->key) + 1;
789
790 if (found >= maxv - 2 || bufsz < vallen)
791 break;
792
793 cmdv[found++] = buf;
794 memcpy(buf, match->key, vallen);
795 buf += vallen;
796 bufsz -= vallen;
797 }
798
799 qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
800
801 if (idx)
802 cmdv[found++] = "...";
803
804 cmdv[found] = NULL;
805 return found;
806}
807#endif
808