]> cloudbase.mooo.com Git - z180-stamp.git/blob - avr/env.c
Add memory commands (cmp, cp, md, mm, mw, nm)
[z180-stamp.git] / avr / env.c
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
31 static void print_blanks(uint_fast8_t count)
32 {
33 while(count--)
34 putchar(' ');
35 }
36
37
38 void 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
68 void 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() */
78 void 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
101 const FLASH char default_env[] = {
102 "bootdelay=" "3" DELIM
103 "bootcmd=" "echo hallo" DELIM
104 "baudrate=" "115200" DELIM
105 DELIM
106 };
107
108
109 typedef struct environment_s {
110 uint16_t crc; /* CRC16 over data bytes */
111 char data[ENV_SIZE]; /* Environment data */
112 } env_t;
113
114
115
116 typedef struct env_item_s {
117 #define EF_N_EEP (1<<7) /* Variable name is in EEPROM */
118 #define EF_V_EEP (1<<6) /* Variable value is in EEPROM */
119 #define EF_DIRTY (1<<0) /* Variable is new or value changed */
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
132 static env_item_t env_list[CONFIG_ENVVAR_MAX];
133 static int entrycount;
134
135
136 static 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
145 uint16_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
170 uint16_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
187 static
188 int 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
198 static
199 int 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
214 env_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
259 static char p_env_name_buf[CONFIG_SYS_ENV_NAMELEN+1];
260
261 static 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
273 int 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
304 static 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 #if 0
311 env_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 #endif
326
327 env_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
373 static 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
394 static 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--;
409 memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
410
411 rc = 1;
412 }
413 #if 0
414 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
415 "=== env_list:");
416 dump_heap();
417 debug("** entrycount: %d\n", entrycount);
418 for (int i=0; i<entrycount; i++) {
419 printf_P(PSTR("** env var [%d] "), i);
420 env_item_print(&env_list[i]);
421 }
422 #endif
423
424 return rc;
425 }
426
427 char *getenv(const char *name)
428 {
429 env_item_t *ep;
430 char *ret = NULL;
431
432 debug("** getenv: %s\n", name);
433
434 ep = envlist_get(name, ENV_GET_VAL);
435 if (ep != NULL)
436 ret = ep->val.ram;
437 #if 0
438 dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
439 "=== env_list:");
440 dump_heap();
441 debug("** entrycount: %d\n", entrycount);
442 for (int i=0; i<entrycount; i++) {
443 printf_P(PSTR("** env var [%d] "), i);
444 env_item_print(&env_list[i]);
445 }
446 #endif
447 return ret;
448 }
449
450 /* TODO: implement saveenv() */
451 int saveenv(void)
452 {
453 int rc = 0;
454
455 // rc = env_export(&env_new);
456 if (rc)
457 return rc;
458
459 // rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
460 // off, (uchar *)&env_new, CONFIG_ENV_SIZE);
461 return rc;
462 }
463
464
465 /*-----------------------------------------------------------------------------*/
466
467
468 int set_default_env(void)
469 {
470 char buf[64];
471 uint16_t crc = 0xffff;
472 uint16_t eep = CONFIG_ENV_OFFSET + offsetof(env_t, data);
473 unsigned int len = CONFIG_ENV_SIZE - offsetof(env_t, data);
474 unsigned int i, src = 0;
475 char c = 0xff, c0 = c;
476 #if 0
477 printf_P(PSTR("\n\n** set_default_env()\n"));
478 #endif
479 while (len) {
480
481 memcpy_P(buf, default_env+src, sizeof(buf));
482
483 for (i=0; i < (len < sizeof(buf) ? len : sizeof(buf)) &&
484 !(c == 0 && c0 == 0);
485 i++)
486 {
487 c0 = c; c = buf[i];
488 crc = crc16(crc, c);
489 }
490
491 eeprom_update_block(buf, (char *) eep, i);
492 #if 0
493 printf_P(PSTR("eeprom_update_block: eep: 0x%.4x, i:%d\n"),
494 (unsigned int) eep, i);
495 dump_ram((uint8_t *) buf, i, "=== buf:");
496 dump_eep((const uint8_t *) eep, i);
497 #endif
498 if (c == 0 && c0 == 0)
499 len = 0;
500 if (len > sizeof(buf))
501 len -= sizeof(buf);
502 src += sizeof(buf);
503 eep += sizeof(buf);
504 }
505 #if 0
506 dump_eep(0, 128);
507 #endif
508 return 0;
509 }
510
511
512 int env_check(void)
513 {
514 uint16_t crc, stored_crc;
515 uint16_t i;
516 char c, c0;
517
518 debug("\n\n** env_check()\n");
519
520
521 /* read old CRC */
522 stored_crc = eeprom_read_word((const uint16_t *) CONFIG_ENV_OFFSET +
523 offsetof(env_t, crc));
524 crc = 0xffff;
525 c = 0xff;
526 for (i = offsetof(env_t, data);
527 !(c == 0 && c0 == 0) && i < CONFIG_ENV_SIZE;
528 i++)
529 {
530 c0 = c;
531 c = eeprom_read_byte((const uint8_t *) CONFIG_ENV_OFFSET + i);
532 crc = crc16(crc, c);
533 }
534 debug("** crc eep: 0x%.4x, crc new: 0x%.4x\n", stored_crc, crc);
535
536 return crc == stored_crc;
537 }
538
539 int env_init(void)
540 {
541 char name[CONFIG_SYS_ENV_NAMELEN+1];
542 uint16_t idx = 0;
543 int nlen;
544 env_item_t e;
545
546 e.flags = EF_N_EEP | EF_V_EEP;
547 e.name.eep = idx;
548 while ((nlen = ee_name_get(name, &e)) != 0 && idx < ENV_SIZE) {
549
550 if (entrycount <= CONFIG_ENVVAR_MAX) {
551 e.val.eep = idx + nlen + 1;
552
553 env_list[entrycount++] = e;
554
555 idx += nlen + 1;
556 while (env_get_char(idx++) != 0 && idx < ENV_SIZE)
557 ;
558 e.name.eep = idx;
559 } else {
560 debug("** Too many environment variables!\n");
561 break;
562 }
563 }
564 qsort(env_list, entrycount, sizeof(env_item_t), comp_env_items);
565
566 return 0;
567 }
568
569
570 /*
571 * Command interface: print one or all environment variables
572 *
573 * Returns -1 in case of error, or length of printed string
574 */
575 static int env_print(char *name)
576 {
577 int len = -1;
578
579 if (name) { /* print a single name */
580
581 env_item_t *ep = envlist_search(name);
582 if (ep != NULL)
583 len = env_item_print(ep);
584
585 } else { /* print whole list */
586 len = 0;
587 for (int i = 0 ; i < entrycount; i++) {
588 len += env_item_print(&env_list[i]);
589 }
590 }
591 return len;
592 }
593
594
595
596 int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
597 char * const argv[])
598 {
599 int i;
600 int rcode = 0;
601
602 (void) cmdtp; (void) flag;
603
604 if (argc == 1) {
605 /* print all env vars */
606 rcode = env_print(NULL);
607 if (rcode < 0)
608 return 1;
609 printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
610 rcode, ENV_SIZE);
611 return 0;
612 }
613
614 /* print selected env vars */
615 for (i = 1; i < argc; ++i) {
616 int rc = env_print(argv[i]);
617 if (rc < 0) {
618 printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
619 ++rcode;
620 }
621 }
622
623 return rcode;
624 }
625
626
627 /**
628 * Set or delete environment variable
629 *
630 * Set a new environment variable,
631 * or replace or delete an existing one.
632 *
633 * @param flag (not used)
634 * @param argc
635 * @param argv[1] Environment variable to set or delete
636 * if no more args
637 * @param argv[2] ... Value to set it to
638 *
639 * @return 0 if ok, 1 on error
640 */
641 static int _do_env_set(int flag, int argc, char * const argv[])
642 {
643 int i, len;
644 char *name, *value, *s;
645 env_item_t e, *ep;
646
647 (void) flag;
648 debug("Initial value for argc=%d\n", argc);
649
650 name = argv[1];
651 value = argv[2];
652
653 if (strchr(name, '=')) {
654 printf_P(PSTR("## Error: illegal character '='"
655 "in variable name \"%s\"\n"), name);
656 return 1;
657 }
658 if (strlen(name) > CONFIG_SYS_ENV_NAMELEN) {
659 printf_P(PSTR("## Error: Variable name \"%s\" too long. "
660 "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
661 return 1;
662 }
663 /*
664 env_id++;
665 */
666 /* Delete only ? */
667 if (argc < 3 || argv[2] == NULL) {
668 int rc = envlist_delete(name);
669 return !rc;
670 }
671
672 /*
673 * Insert / replace new value
674 */
675 for (i = 2, len = 0; i < argc; ++i)
676 len += strlen(argv[i]) + 1;
677
678 value = xmalloc(len);
679 if (value == NULL) {
680 printf_P(PSTR("## Can't malloc %d bytes\n"), len);
681 return 1;
682 }
683 for (i = 2, s = value; i < argc; ++i) {
684 char *v = argv[i];
685
686 while ((*s++ = *v++) != '\0')
687 ;
688 *(s - 1) = ' ';
689 }
690 if (s != value)
691 *--s = '\0';
692
693 e.flags = EF_DIRTY;
694 e.name.ram = name;
695 e.val.ram = value;
696 ep = envlist_enter(&e);
697 if (!ep) {
698 printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
699 name);
700 return 1;
701 }
702
703 return 0;
704 }
705
706 /**
707 * Set an environment variable
708 *
709 * @param varname Environment variable to set
710 * @param varvalue Value to set it to
711 * @return 0 if ok, 1 on error
712 */
713 int setenv(const char *varname, const char *varvalue)
714 {
715 const char * const argv[3] = { NULL, varname, varvalue };
716 int argc = 3;
717
718 if (varvalue == NULL || varvalue[0] == '\0')
719 --argc;
720
721 return _do_env_set(0, argc, (char * const *)argv);
722 }
723
724 #if 0
725 /**
726 * Set an environment variable to an integer value
727 *
728 * @param varname Environment variable to set
729 * @param value Value to set it to
730 * @return 0 if ok, 1 on error
731 */
732 int setenv_ulong(const char *varname, unsigned long value)
733 {
734 /* TODO: this should be unsigned */
735 char *str = simple_itoa(value);
736
737 return setenv(varname, str);
738 }
739 #endif
740
741
742 /**
743 * Set an environment variable to an value in hex
744 *
745 * @param varname Environment variable to set
746 * @param value Value to set it to
747 * @return 0 if ok, 1 on error
748 */
749 int setenv_hex(const char *varname, unsigned long value)
750 {
751 char str[sizeof(unsigned long) *2 + 1];
752
753 sprintf_P(str, PSTR("%lx"), value);
754 return setenv(varname, str);
755 }
756
757 /**
758 * Get an environment variable as a hex value
759 *
760 * @param varname Environment variable to get
761 * @param default_val Return this, if variable does not exist
762 * @return hex value of variable or default_val
763 */
764 unsigned long getenv_hex(const char *varname, unsigned long default_val)
765 {
766 const char *s;
767 unsigned long value;
768 char *endp;
769
770 s = getenv(varname);
771 if (s)
772 value = strtoul(s, &endp, 16);
773 if (!s || endp == s)
774 return default_val;
775
776 return value;
777 }
778
779 int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
780 {
781 (void) cmdtp;
782
783 if (argc < 2)
784 return CMD_RET_USAGE;
785
786 return _do_env_set(flag, argc, argv);
787 }
788
789
790 #if defined(CONFIG_AUTO_COMPLETE)
791 int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
792 {
793 ENTRY *match;
794 int found, idx;
795
796 idx = 0;
797 found = 0;
798 cmdv[0] = NULL;
799
800 while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
801 int vallen = strlen(match->key) + 1;
802
803 if (found >= maxv - 2 || bufsz < vallen)
804 break;
805
806 cmdv[found++] = buf;
807 memcpy(buf, match->key, vallen);
808 buf += vallen;
809 bufsz -= vallen;
810 }
811
812 qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
813
814 if (idx)
815 cmdv[found++] = "...";
816
817 cmdv[found] = NULL;
818 return found;
819 }
820 #endif
821