]> cloudbase.mooo.com Git - z180-stamp.git/commitdiff
New U-Boot like AVR main program.
authorLeo C <erbl259-lmu@yahoo.de>
Tue, 12 Aug 2014 10:35:28 +0000 (12:35 +0200)
committerLeo C <erbl259-lmu@yahoo.de>
Tue, 12 Aug 2014 10:35:28 +0000 (12:35 +0200)
Uses U-Boot source code taken from:
git://git.denx.de/u-boot.git

29 files changed:
.gitignore
avr/Tupfile
avr/bootc.c [new file with mode: 0644]
avr/cli.c [new file with mode: 0644]
avr/cli.h [new file with mode: 0644]
avr/cli_readline.c [new file with mode: 0644]
avr/cli_readline.h [new file with mode: 0644]
avr/cmd_echo.c [new file with mode: 0644]
avr/cmd_help.c [new file with mode: 0644]
avr/command.c [new file with mode: 0644]
avr/command.h [new file with mode: 0644]
avr/command_tbl.c [new file with mode: 0644]
avr/common.h [new file with mode: 0644]
avr/con-utils.c [new file with mode: 0644]
avr/con-utils.h [new file with mode: 0644]
avr/config.h [new file with mode: 0644]
avr/crc.h [new file with mode: 0644]
avr/debug.h
avr/env.c [new file with mode: 0644]
avr/env.h [new file with mode: 0644]
avr/serial.c
avr/serial.h
avr/timer.c [new file with mode: 0644]
avr/timer.h [new file with mode: 0644]
avr/xmalloc.c [new file with mode: 0644]
avr/xmalloc.h [new file with mode: 0644]
avr/z180-stamp-avr.c
configs/debug.config
configs/gcc.tup [new file with mode: 0644]

index 1cb02eab6a54111eddb2e2574ef28bc3d2a6183a..725065f4b2f20595df07fad55dafed3054e96c21 100644 (file)
@@ -1,8 +1,11 @@
-/.tup
-Makefiledev
-/.settings
+#Makefiledev
 /.cproject
 /.project
-/doc/
-/joe/
-/scratch/
+/.settings
+/.tup
+/build-debug
+/doc
+/fatfs
+/joe
+/scratch
+
index a90b7b55ea1de1a24840713bd8e8e815f99cf6d9..d90f225c4cc41b99d967d9ced4afc32580437f30 100644 (file)
@@ -1,15 +1,22 @@
 include_rules
 
-PROG           = z180-stamp-avr
-SRC            = z180-stamp-avr.c serial.c z80-if.c
-SRC_Z          = ../z180/hdrom.c
+PROG           = stamp-bootc
+SRC            = bootc.c
+SRC            += cli.c cli_readline.c command.c command_tbl.c
+SRC            += cmd_help.c cmd_echo.c
+SRC            += env.c xmalloc.c
+SRC            += timer.c con-utils.c serial.c
+SRC            += z80-if.c
+
+#SRC_Z         = ../z180/hdrom.c
+
 #TARGETS       = $(PROG).elf
 
 MCU_TARGET     = atmega1281
 F_CPU          = 18432000UL
 DEFS           = -DF_CPU=$(F_CPU) -DBAUD=115200UL
 
-INCLUDES += ../z180
+#INCLUDES += ../z180
 
 ###############################################################################
 
@@ -34,7 +41,7 @@ endif
 CFLAGS = -g -Os
 CFLAGS += -mmcu=$(MCU_TARGET)
 CFLAGS += -std=gnu99
-CFLAGS += -Wall -Wextra -Wimplicit-function-declaration
+CFLAGS += -Wall -Wextra
 CFLAGS += -Wredundant-decls 
 #CFLAGS        += -fno-common -ffunction-sections -fdata-sections
 #CFLAGS        += -I $(INCLUDES)
diff --git a/avr/bootc.c b/avr/bootc.c
new file mode 100644 (file)
index 0000000..6dbcdef
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ */
+
+
+#include "common.h"
+
+#include <util/delay.h>
+//#include <avr/power.h>
+//#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+//#include <util/atomic.h>
+//#include <avr/sleep.h>
+//#include <string.h>
+
+#include <util/delay.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+
+#include "config.h"
+#include "debug.h"
+#include "z80-if.h"
+#include "con-utils.h"
+#include "serial.h"
+#include "timer.h"
+#include "cli.h"
+#include "env.h"
+
+/*--------------------------------------------------------------------------*/
+
+void setup_avr(void)
+{
+       /* WD */
+
+       /* CPU */
+
+       /* Disable JTAG Interface regardless of the JTAGEN fuse setting. */
+       MCUCR = _BV(JTD);
+       MCUCR = _BV(JTD);
+
+       /* disable unused periphels */
+       PRR0 = _BV(PRTIM2) | _BV(PRTIM0) | _BV(PRADC);
+       PRR1 = _BV(PRTIM5) | _BV(PRTIM4) | _BV(PRTIM3) | 
+               _BV(PRUSART3) | _BV(PRUSART2) | _BV(PRUSART1);
+
+       /* disable analog comparator */
+       ACSR = _BV(ACD);
+       /* Ports */
+
+       /* Clock */
+       CLKPR = _BV(CLKPCE);
+       CLKPR = 0;
+
+       /* Timer */
+
+       OCR1A = F_CPU / 8 / 1000 - 1; // Timer1: 1000Hz interval (OC1A)
+       TCCR1B = 0b00001010;
+       TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interrupt
+}
+
+
+
+/*******************************************************************************/
+/*******************************************************************************/
+
+#define udelay(n)  _delay_us(n)
+
+
+/* Stored value of bootdelay, used by autoboot_command() */
+static int  stored_bootdelay;
+
+
+/***************************************************************************
+ * Watch for 'delay' seconds for autoboot stop.
+ * returns: 0 - no key, allow autoboot 
+ *          1 - got key, abort
+ */
+
+static int abortboot(int  bootdelay)
+{
+       int abort = 0;
+       uint32_t ts;
+
+       if (bootdelay >= 0)
+               printf_P(PSTR("Hit any key to stop autoboot: %2d "), bootdelay);
+
+#if defined CONFIG_ZERO_BOOTDELAY_CHECK
+       /*
+        * Check if key already pressed
+        * Don't check if bootdelay < 0
+        */
+       if (bootdelay >= 0) {
+               if (tstc()) {   /* we got a key press   */
+                       (void) my_getchar();  /* consume input  */
+                       my_puts_P(PSTR("\b\b\b 0"));
+                       abort = 1;      /* don't auto boot      */
+               }
+       }
+#endif
+
+       while ((bootdelay > 0) && (!abort)) {
+               --bootdelay;
+               /* delay 1000 ms */
+               ts = get_timer(0);
+               do {
+                       if (tstc()) {   /* we got a key press   */
+                               abort  = 1;     /* don't auto boot      */
+                               bootdelay = 0;  /* no more delay        */
+                               break;
+                       }
+                       udelay(10000);
+               } while (!abort && get_timer(ts) < 1000);
+
+               printf_P(PSTR("\b\b\b%2d "), bootdelay);
+       }
+
+       putchar('\n');
+
+       return abort;
+}
+
+const char *bootdelay_process(void)
+{
+       char *s;
+       int bootdelay;
+
+       s = getenv("bootdelay");
+       bootdelay = s ? atoi(s) : CONFIG_BOOTDELAY;
+
+
+       debug("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+       _delay_ms(20);
+
+       s = getenv("bootcmd");
+       stored_bootdelay = bootdelay;
+       return s;
+}
+
+void autoboot_command(const char *s)
+{
+       debug("### main_loop: bootcmd=\"%s\"\n", s ? s : PSTR("<UNDEFINED>"));
+       _delay_ms(20);
+
+       if (stored_bootdelay != -1 && s && !abortboot(stored_bootdelay)) {
+               run_command_list(s, -1);
+       }
+}
+
+
+void main_loop(void)
+{
+       const char *s;
+
+       s = bootdelay_process();
+       autoboot_command(s);
+       cli_loop();
+}
+
+int main(void)
+{
+       setup_avr();
+       z80_setup_bus();
+       
+       serial_setup();
+       sei();
+       
+       if (env_check() == 0)
+               set_default_env();
+       env_init();
+
+       printf_P(PSTR("\n(ATMEGA1281+HD64180)_stamp Tester\n"));
+       
+       main_loop();
+}
diff --git a/avr/cli.c b/avr/cli.c
new file mode 100644 (file)
index 0000000..44cf5b8
--- /dev/null
+++ b/avr/cli.c
@@ -0,0 +1,369 @@
+#include "common.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "command.h"
+#include "xmalloc.h"
+#include "debug.h"
+#include "env.h"
+#include "cli_readline.h"
+#include "con-utils.h"
+#include "cli.h"
+
+#define DEBUG_PARSER   0       /* set to 1 to debug */
+
+#define debug_parser(fmt, args...)             \
+       debug_cond(DEBUG_PARSER, fmt, ##args)
+
+static int cli_parse_line(char *line, char *argv[])
+{
+       static const FLASH char delim[] = {" \t"};
+
+       char *ptr;
+       uint_fast8_t nargs = 0;
+
+       debug_parser("parse_line: \"%s\"\n", line);
+
+       ptr = strtok_P(line, delim);
+       while(nargs < CONFIG_SYS_MAXARGS && ptr != NULL) {
+               argv[nargs++] = ptr;
+               ptr = strtok_P(NULL, delim);
+       }
+
+       if (ptr != NULL)
+               printf_P(PSTR("** Too many args (max. %d) **\n"), CONFIG_SYS_MAXARGS);
+
+       argv[nargs] = NULL;
+       debug_parser("parse_line: nargs=%d\n", nargs);
+
+       return nargs;
+}
+
+static void process_macros(const char *input, char *output)
+{
+       char c, prev;
+       const char *varname_start = NULL;
+#if 0 && (CONFIG_SYS_CBSIZE < __UINT_FAST8_MAX__)
+       uint_fast8_t inputcnt = strlen(input);
+       uint_fast8_t outputcnt = CONFIG_SYS_CBSIZE;
+#else
+       int inputcnt = strlen(input);
+       int outputcnt = CONFIG_SYS_CBSIZE;
+#endif
+       uint_fast8_t state = 0;         /* 0 = waiting for '$'  */
+
+       /* 1 = waiting for '(' or '{' */
+       /* 2 = waiting for ')' or '}' */
+       /* 3 = waiting for '''  */
+       char *output_start = output;
+
+       debug_parser("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen(input),
+                    input);
+
+       prev = '\0';            /* previous character   */
+
+       while (inputcnt && outputcnt) {
+               c = *input++;
+               inputcnt--;
+
+               if (state != 3) {
+                       /* remove one level of escape characters */
+                       if ((c == '\\') && (prev != '\\')) {
+                               if (inputcnt-- == 0)
+                                       break;
+                               prev = c;
+                               c = *input++;
+                       }
+               }
+
+               switch (state) {
+               case 0: /* Waiting for (unescaped) $    */
+                       if ((c == '\'') && (prev != '\\')) {
+                               state = 3;
+                               break;
+                       }
+                       if ((c == '$') && (prev != '\\')) {
+                               state++;
+                       } else {
+                               *(output++) = c;
+                               outputcnt--;
+                       }
+                       break;
+               case 1: /* Waiting for (        */
+                       if (c == '(' || c == '{') {
+                               state++;
+                               varname_start = input;
+                       } else {
+                               state = 0;
+                               *(output++) = '$';
+                               outputcnt--;
+
+                               if (outputcnt) {
+                                       *(output++) = c;
+                                       outputcnt--;
+                               }
+                       }
+                       break;
+               case 2: /* Waiting for )        */
+                       if (c == ')' || c == '}') {
+                               char envname[CONFIG_SYS_ENV_NAMELEN+1], *envval;
+                               /* Varname # of chars */
+                               uint_fast8_t envcnt = input - varname_start - 1;
+                               if (envcnt > CONFIG_SYS_ENV_NAMELEN)
+                                       envcnt = CONFIG_SYS_ENV_NAMELEN;
+
+                               memcpy(envname, varname_start, envcnt);
+                               envname[envcnt] = '\0';
+
+                               /* Get its value */
+                               envval = getenv(envname);
+
+                               /* Copy into the line if it exists */
+                               if (envval != NULL)
+                                       while ((*envval) && outputcnt) {
+                                               *(output++) = *(envval++);
+                                               outputcnt--;
+                                       }
+                               /* Look for another '$' */
+                               state = 0;
+                       }
+                       break;
+               case 3: /* Waiting for '        */
+                       if ((c == '\'') && (prev != '\\')) {
+                               state = 0;
+                       } else {
+                               *(output++) = c;
+                               outputcnt--;
+                       }
+                       break;
+               }
+               prev = c;
+       }
+
+       if (outputcnt)
+               *output = 0;
+       else
+               *(output - 1) = 0;
+
+       debug_parser("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n",
+                    strlen(output_start), output_start);
+}
+
+ /*
+ * WARNING:
+ *
+ * We must create a temporary copy of the command since the command we get
+ * may be the result from getenv(), which returns a pointer directly to
+ * the environment data, which may change magicly when the command we run
+ * creates or modifies environment variables (like "bootp" does).
+ */
+static int cli_run_command(const char *cmd, int flag)
+{
+       char *cmdbuf;                   /* working copy of cmd          */
+       char *token;                    /* start of token in cmdbuf     */
+       char *sep;                      /* end of token (separator) in cmdbuf */
+       char *finaltoken;
+       char *str;
+       char *argv[CONFIG_SYS_MAXARGS + 1];     /* NULL terminated      */
+       int argc;
+       uint_fast8_t inquotes, repeatable = 1;
+       int rc = 0;
+
+       debug_parser("[RUN_COMMAND] cmd[%p]=\"%s\"\n", 
+                       cmd, cmd ? cmd : "NULL");
+
+       clear_ctrlc();          /* forget any previous Control C */
+
+       if (!cmd || !*cmd)
+               return -1;      /* empty command */
+
+
+       cmdbuf = xmalloc(strlen(cmd) + 1);
+       finaltoken = xmalloc(CONFIG_SYS_CBSIZE);
+
+       strcpy(cmdbuf, cmd);
+       str = cmdbuf;
+
+       /* Process separators and check for invalid
+        * repeatable commands
+        */
+
+       debug_parser("[PROCESS_SEPARATORS] %s\n", cmd);
+       while (*str) {
+               /*
+                * Find separator, or string end
+                * Allow simple escape of ';' by writing "\;"
+                */
+               for (inquotes = 0, sep = str; *sep; sep++) {
+                       if ((*sep == '\'') &&
+                           (*(sep - 1) != '\\'))
+                               inquotes = !inquotes;
+
+                       if (!inquotes &&
+                           (*sep == ';' || *sep == '\n') &&    /* separator            */
+                           (sep != str) &&                     /* past string start    */
+                           (*(sep - 1) != '\\'))               /* and NOT escaped */
+                               break;
+               }
+
+               /*
+                * Limit the token to data between separators
+                */
+               token = str;
+               if (*sep) {
+                       str = sep + 1;  /* start of command for next pass */
+                       *sep = '\0';
+               } else {
+                       str = sep;      /* no more commands for next pass */
+               }
+               debug_parser("token: \"%s\"\n", token);
+
+               /* find macros in this token and replace them */
+               process_macros(token, finaltoken);
+
+               /* Extract arguments */
+               argc = cli_parse_line(finaltoken, argv);
+               if (argc == 0) {
+                       rc = -1;        /* no command at all */
+                       continue;
+               }
+
+               if (cmd_process(flag, argc, argv, &repeatable))
+                       rc = -1;
+
+               /* Did the user stop this? */
+               if (had_ctrlc()) {
+                       rc = -1;        /* if stopped then not repeatable */
+                       break;
+               }
+       }
+
+       free(cmdbuf);
+       free(finaltoken);
+
+       return rc ? rc : repeatable;
+}
+
+static int cli_run_command_list(const char *cmd)
+{
+       return (cli_run_command(cmd, 0) < 0);
+}
+
+/******************************************************************************/
+
+
+/*
+ * Run a command using the selected parser.
+ *
+ * @param cmd  Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+int run_command(const char *cmd, int flag)
+{
+       /*
+        * cli_run_command can return 0 or 1 for success, so clean up
+        * its result.
+        */
+       if (cli_run_command(cmd, flag) == -1)
+               return 1;
+
+       return 0;
+}
+
+/*
+ * Run a command using the selected parser, and check if it is repeatable.
+ *
+ * @param cmd  Command to run
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 (not repeatable) or 1 (repeatable) on success, -1 on error.
+ */
+static int run_command_repeatable(const char *cmd, int flag)
+{
+       return cli_run_command(cmd, flag);
+}
+
+int run_command_list(const char *cmd, int len)
+{
+       (void) len;
+       
+       return cli_run_command_list(cmd);
+}
+
+/****************************************************************************/
+
+#define DYN_BUFFER 1
+
+void cli_loop(void)
+{
+#if DYN_BUFFER
+       char *lastcommand = NULL;
+#else
+       static char lastcommand[CONFIG_SYS_CBSIZE];
+#endif
+       int len;
+       int flag;
+       int rc = 1;
+
+       for (;;) {
+               len = cli_readline(PSTR(CONFIG_SYS_PROMPT));
+
+               flag = 0;       /* assume no special flags for now */
+               if (len > 0) {
+#if DYN_BUFFER
+                       lastcommand = (char *) xrealloc(lastcommand, len+1);
+                       if (lastcommand != NULL) {
+                               strncpy(lastcommand, console_buffer, len+1);
+                               lastcommand[len] = '\0';
+                       }
+#else
+                       strcpy(lastcommand, console_buffer);
+#endif
+               } else if (len == 0)
+                       flag |= CMD_FLAG_REPEAT;
+
+               if (len == -1)
+                       my_puts_P(PSTR("<INTERRUPT>\n"));
+               else
+                       rc = run_command_repeatable(lastcommand, flag);
+
+               if (rc <= 0) {
+                       /* invalid command or not repeatable, forget it */
+#if DYN_BUFFER
+                       free(lastcommand);
+                       lastcommand = NULL;
+#else
+                       lastcommand[0] = 0;
+#endif
+               }
+       }
+}
+
+
+int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int i;
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       for (i = 1; i < argc; ++i) {
+               char *arg;
+
+               arg = getenv(argv[i]);
+               if (arg == NULL) {
+                       printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+                       return 1;
+               }
+
+               if (run_command(arg, flag) != 0)
+                       return 1;
+       }
+       return 0;
+}
+
diff --git a/avr/cli.h b/avr/cli.h
new file mode 100644 (file)
index 0000000..67ff63b
--- /dev/null
+++ b/avr/cli.h
@@ -0,0 +1,64 @@
+#ifndef CLI_H          
+#define CLI_H
+
+/**
+ * Go into the command loop
+ *
+ * This will return if we get a timeout waiting for a command, but only for
+ * the simple parser (not hush). See CONFIG_BOOT_RETRY_TIME.
+ */
+void cli_loop(void);
+
+/**
+ * cli_simple_run_command() - Execute a command with the simple CLI
+ *
+ * @cmd:       String containing the command to execute
+ * @flag       Flag value - see CMD_FLAG_...
+ * @return 1  - command executed, repeatable
+ *     0  - command executed but not repeatable, interrupted commands are
+ *          always considered not repeatable
+ *     -1 - not executed (unrecognized, bootd recursion or too many args)
+ *           (If cmd is NULL or "" or longer than CONFIG_SYS_CBSIZE-1 it is
+ *           considered unrecognized)
+ */
+//int cli_simple_run_command(const char *cmd, int flag);
+
+/**
+ * cli_simple_run_command_list() - Execute a list of command
+ *
+ * The commands should be separated by ; or \n and will be executed
+ * by the built-in parser.
+ *
+ * This function cannot take a const char * for the command, since if it
+ * finds newlines in the string, it replaces them with \0.
+ *
+ * @param cmd  String containing list of commands
+ * @param flag Execution flags (CMD_FLAG_...)
+ * @return 0 on success, or != 0 on error.
+ */
+//int cli_simple_run_command_list(char *cmd, int flag);
+
+/**
+ * parse_line() - split a command line down into separate arguments
+ *
+ * The argv[] array is filled with pointers into @line, and each argument
+ * is terminated by \0 (i.e. @line is changed in the process unless there
+ * is only one argument).
+ *
+ * #argv is terminated by a NULL after the last argument pointer.
+ *
+ * At most CONFIG_SYS_MAXARGS arguments are permited - if there are more
+ * than that then an error is printed, and this function returns
+ * CONFIG_SYS_MAXARGS, with argv[] set up to that point.
+ *
+ * @line:      Command line to parse
+ * @args:      Array to hold arguments
+ * @return number of arguments
+ */
+//int cli_simple_parse_line(char *line, char *argv[]);
+
+int run_command_list(const char *cmd, int len);
+
+
+#endif /* CLI_H */
+
diff --git a/avr/cli_readline.c b/avr/cli_readline.c
new file mode 100644 (file)
index 0000000..17d5494
--- /dev/null
@@ -0,0 +1,595 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * Add to readline cmdline-editing by
+ * (C) Copyright 2005
+ * JinHua Luo, GuangDong Linux Center, <luo.jinhua@gd-linux.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+
+#include <avr/pgmspace.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "con-utils.h"
+#include "command.h"
+#include "cli_readline.h"
+
+char console_buffer[CONFIG_SYS_CBSIZE + 1];    /* console I/O buffer   */
+
+static const FLASH char erase_seq[] = "\b \b";   /* erase sequence */
+static const FLASH char   tab_seq[] = "        "; /* used to expand TABs */
+
+#ifndef CONFIG_CMDLINE_EDITING
+static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen)
+{
+       char *s;
+
+       if (*np == 0)
+               return p;
+
+       if (*(--p) == '\t') {           /* will retype the whole line */
+               while (*colp > plen) {
+                       my_puts_P(erase_seq);
+                       (*colp)--;
+               }
+               for (s = buffer; s < p; ++s) {
+                       if (*s == '\t') {
+                               my_puts_P(tab_seq + ((*colp) & 07));
+                               *colp += 8 - ((*colp) & 07);
+                       } else {
+                               ++(*colp);
+                               putchar(*s);
+                       }
+               }
+       } else {
+               my_puts_P(erase_seq);
+               (*colp)--;
+       }
+       (*np)--;
+
+       return p;
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+
+#ifdef CONFIG_CMDLINE_EDITING
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+#define putnstr(str, n)        printf_P(PSTR("%.*s"), (int)n, str)
+
+#define CTL_CH(c)              ((c) - 'a' + 1)
+#define CTL_BACKSPACE          ('\b')
+#define DEL                    ((char)255)
+#define DEL7                   ((char)127)
+#define CREAD_HIST_CHAR                ('!')
+
+#define getcmd_putch(ch)       putchar(ch)
+#define getcmd_getch()         my_getchar()
+#define getcmd_cbeep()         getcmd_putch('\a')
+
+#define HIST_MAX               5
+#define HIST_SIZE              CONFIG_SYS_CBSIZE
+
+static int hist_max;
+static int hist_add_idx;
+static int hist_cur = -1;
+static unsigned hist_num;
+
+static char *hist_list[HIST_MAX];
+static char hist_lines[HIST_MAX][HIST_SIZE + 1];       /* Save room for NULL */
+
+#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
+
+static void hist_init(void)
+{
+       int i;
+
+       hist_max = 0;
+       hist_add_idx = 0;
+       hist_cur = -1;
+       hist_num = 0;
+
+       for (i = 0; i < HIST_MAX; i++) {
+               hist_list[i] = hist_lines[i];
+               hist_list[i][0] = '\0';
+       }
+}
+
+static void cread_add_to_hist(char *line)
+{
+       strcpy(hist_list[hist_add_idx], line);
+
+       if (++hist_add_idx >= HIST_MAX)
+               hist_add_idx = 0;
+
+       if (hist_add_idx > hist_max)
+               hist_max = hist_add_idx;
+
+       hist_num++;
+}
+
+static char *hist_prev(void)
+{
+       char *ret;
+       int old_cur;
+
+       if (hist_cur < 0)
+               return NULL;
+
+       old_cur = hist_cur;
+       if (--hist_cur < 0)
+               hist_cur = hist_max;
+
+       if (hist_cur == hist_add_idx) {
+               hist_cur = old_cur;
+               ret = NULL;
+       } else {
+               ret = hist_list[hist_cur];
+       }
+
+       return ret;
+}
+
+static char *hist_next(void)
+{
+       char *ret;
+
+       if (hist_cur < 0)
+               return NULL;
+
+       if (hist_cur == hist_add_idx)
+               return NULL;
+
+       if (++hist_cur > hist_max)
+               hist_cur = 0;
+
+       if (hist_cur == hist_add_idx)
+               ret = "";
+       else
+               ret = hist_list[hist_cur];
+
+       return ret;
+}
+
+#ifndef CONFIG_CMDLINE_EDITING
+static void cread_print_hist_list(void)
+{
+       int i;
+       unsigned n;
+
+       n = hist_num - hist_max;
+
+       i = hist_add_idx + 1;
+       while (1) {
+               if (i > hist_max)
+                       i = 0;
+               if (i == hist_add_idx)
+                       break;
+               printf_P(PSTR("%s\n"), hist_list[i]);
+               n++;
+               i++;
+       }
+}
+#endif /* CONFIG_CMDLINE_EDITING */
+
+#define BEGINNING_OF_LINE() {                  \
+       while (num) {                           \
+               getcmd_putch(CTL_BACKSPACE);    \
+               num--;                          \
+       }                                       \
+}
+
+#define ERASE_TO_EOL() {                               \
+       if (num < eol_num) {                            \
+               printf_P(PSTR("%*S"), (int)(eol_num - num), PSTR("")); \
+               do {                                    \
+                       getcmd_putch(CTL_BACKSPACE);    \
+               } while (--eol_num > num);              \
+       }                                               \
+}
+
+#define REFRESH_TO_EOL() {                     \
+       if (num < eol_num) {                    \
+               wlen = eol_num - num;           \
+               putnstr(buf + num, wlen);       \
+               num = eol_num;                  \
+       }                                       \
+}
+
+static void cread_add_char(char ichar, int insert, unsigned long *num,
+              unsigned long *eol_num, char *buf, unsigned long len)
+{
+       unsigned long wlen;
+
+       /* room ??? */
+       if (insert || *num == *eol_num) {
+               if (*eol_num > len - 1) {
+                       getcmd_cbeep();
+                       return;
+               }
+               (*eol_num)++;
+       }
+
+       if (insert) {
+               wlen = *eol_num - *num;
+               if (wlen > 1)
+                       memmove(&buf[*num+1], &buf[*num], wlen-1);
+
+               buf[*num] = ichar;
+               putnstr(buf + *num, wlen);
+               (*num)++;
+               while (--wlen)
+                       getcmd_putch(CTL_BACKSPACE);
+       } else {
+               /* echo the character */
+               wlen = 1;
+               buf[*num] = ichar;
+               putnstr(buf + *num, wlen);
+               (*num)++;
+       }
+}
+
+static void cread_add_str(char *str, int strsize, int insert,
+                         unsigned long *num, unsigned long *eol_num,
+                         char *buf, unsigned long len)
+{
+       while (strsize--) {
+               cread_add_char(*str, insert, num, eol_num, buf, len);
+               str++;
+       }
+}
+
+static int cread_line(const FLASH char *const prompt, char *buf, unsigned int *len)
+{
+       unsigned long num = 0;
+       unsigned long eol_num = 0;
+       unsigned long wlen;
+       char ichar;
+       int insert = 1;
+       int esc_len = 0;
+       char esc_save[8];
+       int init_len = strlen(buf);
+
+       (void) prompt;
+
+       if (init_len)
+               cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
+
+       while (1) {
+               ichar = getcmd_getch();
+
+               if ((ichar == '\n') || (ichar == '\r')) {
+                       putchar('\n');
+                       break;
+               }
+
+               /*
+                * handle standard linux xterm esc sequences for arrow key, etc.
+                */
+               if (esc_len != 0) {
+                       if (esc_len == 1) {
+                               if (ichar == '[') {
+                                       esc_save[esc_len] = ichar;
+                                       esc_len = 2;
+                               } else {
+                                       cread_add_str(esc_save, esc_len,
+                                                     insert, &num, &eol_num,
+                                                     buf, *len);
+                                       esc_len = 0;
+                               }
+                               continue;
+                       }
+
+                       switch (ichar) {
+                       case 'D':       /* <- key */
+                               ichar = CTL_CH('b');
+                               esc_len = 0;
+                               break;
+                       case 'C':       /* -> key */
+                               ichar = CTL_CH('f');
+                               esc_len = 0;
+                               break;  /* pass off to ^F handler */
+                       case 'H':       /* Home key */
+                               ichar = CTL_CH('a');
+                               esc_len = 0;
+                               break;  /* pass off to ^A handler */
+                       case 'A':       /* up arrow */
+                               ichar = CTL_CH('p');
+                               esc_len = 0;
+                               break;  /* pass off to ^P handler */
+                       case 'B':       /* down arrow */
+                               ichar = CTL_CH('n');
+                               esc_len = 0;
+                               break;  /* pass off to ^N handler */
+                       default:
+                               esc_save[esc_len++] = ichar;
+                               cread_add_str(esc_save, esc_len, insert,
+                                             &num, &eol_num, buf, *len);
+                               esc_len = 0;
+                               continue;
+                       }
+               }
+
+               switch (ichar) {
+               case 0x1b:
+                       if (esc_len == 0) {
+                               esc_save[esc_len] = ichar;
+                               esc_len = 1;
+                       } else {
+                               my_puts_P(PSTR("impossible condition #876\n"));
+                               esc_len = 0;
+                       }
+                       break;
+
+               case CTL_CH('a'):
+                       BEGINNING_OF_LINE();
+                       break;
+               case CTL_CH('c'):       /* ^C - break */
+                       *buf = '\0';    /* discard input */
+                       return -1;
+               case CTL_CH('f'):
+                       if (num < eol_num) {
+                               getcmd_putch(buf[num]);
+                               num++;
+                       }
+                       break;
+               case CTL_CH('b'):
+                       if (num) {
+                               getcmd_putch(CTL_BACKSPACE);
+                               num--;
+                       }
+                       break;
+               case CTL_CH('d'):
+                       if (num < eol_num) {
+                               wlen = eol_num - num - 1;
+                               if (wlen) {
+                                       memmove(&buf[num], &buf[num+1], wlen);
+                                       putnstr(buf + num, wlen);
+                               }
+
+                               getcmd_putch(' ');
+                               do {
+                                       getcmd_putch(CTL_BACKSPACE);
+                               } while (wlen--);
+                               eol_num--;
+                       }
+                       break;
+               case CTL_CH('k'):
+                       ERASE_TO_EOL();
+                       break;
+               case CTL_CH('e'):
+                       REFRESH_TO_EOL();
+                       break;
+               case CTL_CH('o'):
+                       insert = !insert;
+                       break;
+               case CTL_CH('x'):
+               case CTL_CH('u'):
+                       BEGINNING_OF_LINE();
+                       ERASE_TO_EOL();
+                       break;
+               case DEL:
+               case DEL7:
+               case 8:
+                       if (num) {
+                               wlen = eol_num - num;
+                               num--;
+                               memmove(&buf[num], &buf[num+1], wlen);
+                               getcmd_putch(CTL_BACKSPACE);
+                               putnstr(buf + num, wlen);
+                               getcmd_putch(' ');
+                               do {
+                                       getcmd_putch(CTL_BACKSPACE);
+                               } while (wlen--);
+                               eol_num--;
+                       }
+                       break;
+               case CTL_CH('p'):
+               case CTL_CH('n'):
+               {
+                       char *hline;
+
+                       esc_len = 0;
+
+                       if (ichar == CTL_CH('p'))
+                               hline = hist_prev();
+                       else
+                               hline = hist_next();
+
+                       if (!hline) {
+                               getcmd_cbeep();
+                               continue;
+                       }
+
+                       /* nuke the current line */
+                       /* first, go home */
+                       BEGINNING_OF_LINE();
+
+                       /* erase to end of line */
+                       ERASE_TO_EOL();
+
+                       /* copy new line into place and display */
+                       strcpy(buf, hline);
+                       eol_num = strlen(buf);
+                       REFRESH_TO_EOL();
+                       continue;
+               }
+#ifdef CONFIG_AUTO_COMPLETE
+               case '\t': {
+                       int num2, col;
+
+                       /* do not autocomplete when in the middle */
+                       if (num < eol_num) {
+                               getcmd_cbeep();
+                               break;
+                       }
+
+                       buf[num] = '\0';
+                       col = strlen_P(prompt) + eol_num;
+                       num2 = num;
+                       if (cmd_auto_complete(prompt, buf, &num2, &col)) {
+                               col = num2 - num;
+                               num += col;
+                               eol_num += col;
+                       }
+                       break;
+               }
+#endif
+               default:
+                       cread_add_char(ichar, insert, &num, &eol_num, buf,
+                                      *len);
+                       break;
+               }
+       }
+       *len = eol_num;
+       buf[eol_num] = '\0';    /* lose the newline */
+
+       if (buf[0] && buf[0] != CREAD_HIST_CHAR)
+               cread_add_to_hist(buf);
+       hist_cur = hist_add_idx;
+
+       return 0;
+}
+
+#endif /* CONFIG_CMDLINE_EDITING */
+
+/****************************************************************************/
+
+static int cli_readline_into_buffer(const FLASH char *const prompt, char *buffer)
+{
+       char *p = buffer;
+#ifdef CONFIG_CMDLINE_EDITING
+       unsigned int len = CONFIG_SYS_CBSIZE;
+       int rc;
+       static int initted;
+
+       if (!initted) {
+               hist_init();
+               initted = 1;
+       }
+
+       if (prompt)
+               my_puts_P(prompt);
+
+       rc = cread_line(prompt, p, &len);
+       return rc < 0 ? rc : (int) len;
+
+#else  /* CONFIG_CMDLINE_EDITING */
+       char *p_buf = p;
+       int     n = 0;                          /* buffer index         */
+       int     plen = 0;                       /* prompt length        */
+       int     col;                            /* output column cnt    */
+       char    c;
+
+       /* print prompt */
+       if (prompt) {
+               plen = strlen_P(prompt);
+               my_puts_P(prompt);
+       }
+       col = plen;
+
+       for (;;) {
+
+               c = my_getchar();
+
+               /*
+                * Special character handling
+                */
+               switch (c) {
+               case '\r':                      /* Enter                */
+               case '\n':
+                       *p = '\0';
+                       my_puts_P(PSTR("\r\n"));
+                       return p - p_buf;
+
+               case '\0':                      /* nul                  */
+                       continue;
+
+               case 0x03:                      /* ^C - break           */
+                       p_buf[0] = '\0';        /* discard input */
+                       return -1;
+
+               case 0x15:                      /* ^U - erase line      */
+                       while (col > plen) {
+                               my_puts_P(erase_seq);
+                               --col;
+                       }
+                       p = p_buf;
+                       n = 0;
+                       continue;
+
+               case 0x17:                      /* ^W - erase word      */
+                       p = delete_char(p_buf, p, &col, &n, plen);
+                       while ((n > 0) && (*p != ' '))
+                               p = delete_char(p_buf, p, &col, &n, plen);
+                       continue;
+
+               case 0x08:                      /* ^H  - backspace      */
+               case 0x7F:                      /* DEL - backspace      */
+                       p = delete_char(p_buf, p, &col, &n, plen);
+                       continue;
+
+               default:
+                       /*
+                        * Must be a normal character then
+                        */
+                       if (n < CONFIG_SYS_CBSIZE-2) {
+                               if (c == '\t') {        /* expand TABs */
+#ifdef CONFIG_AUTO_COMPLETE
+                                       /*
+                                        * if auto completion triggered just
+                                        * continue
+                                        */
+                                       *p = '\0';
+                                       if (cmd_auto_complete(prompt,
+                                                             console_buffer,
+                                                             &n, &col)) {
+                                               p = p_buf + n;  /* reset */
+                                               continue;
+                                       }
+#endif
+                                       my_puts_P(tab_seq + (col & 07));
+                                       col += 8 - (col & 07);
+                               } else {
+                                       char buf[2];
+
+                                       /*
+                                        * Echo input using puts() to force an
+                                        * LCD flush if we are using an LCD
+                                        */
+                                       ++col;
+                                       buf[0] = c;
+                                       buf[1] = '\0';
+                                       my_puts(buf);
+                               }
+                               *p++ = c;
+                               ++n;
+                       } else {                        /* Buffer full */
+                               putchar('\a');
+                       }
+               }
+       }
+#endif /* CONFIG_CMDLINE_EDITING */
+}
+
+int cli_readline(const FLASH char *const prompt)
+{
+       /*
+        * If console_buffer isn't 0-length the user will be prompted to modify
+        * it instead of entering it from scratch as desired.
+        */
+       console_buffer[0] = '\0';
+
+       return cli_readline_into_buffer(prompt, console_buffer);
+}
+
diff --git a/avr/cli_readline.h b/avr/cli_readline.h
new file mode 100644 (file)
index 0000000..5b25762
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2014 Google, Inc
+ * Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef CLI_READLINE_H
+#define CLI_READLINE_H
+
+extern char console_buffer[];  /* console I/O buffer   */
+
+/**
+ * cli_readline() - read a line into the console_buffer
+ *
+ * This is a convenience function which calls cli_readline_into_buffer().
+ *
+ * @prompt: Prompt to display
+ * @return command line length excluding terminator, or -ve on error
+ */
+int cli_readline(const FLASH char *const prompt);
+
+/**
+ * readline_into_buffer() - read a line into a buffer
+ *
+ * Display the prompt, then read a command line into @buffer. The
+ * maximum line length is CONFIG_SYS_CBSIZE including a \0 terminator, which
+ * will always be added.
+ *
+ * The command is echoed as it is typed. Command editing is supported if
+ * CONFIG_CMDLINE_EDITING is defined. Tab auto-complete is supported if
+ * CONFIG_AUTO_COMPLETE is defined. If CONFIG_BOOT_RETRY_TIME is defined,
+ * then a timeout will be applied.
+ *
+ * If CONFIG_BOOT_RETRY_TIME is defined and retry_time >= 0,
+ * time out when time goes past endtime (timebase time in ticks).
+ *
+ * @prompt:    Prompt to display
+ * @buffer:    Place to put the line that is entered
+ * @timeout:   Timeout in milliseconds, 0 if none
+ * @return command line length excluding terminator, or -ve on error: of the
+ * timeout is exceeded (either CONFIG_BOOT_RETRY_TIME or the timeout
+ * parameter), then -2 is returned. If a break is detected (Ctrl-C) then
+ * -1 is returned.
+ */
+//int cli_readline_into_buffer(const char *const prompt, char *buffer, int timeout);
+
+
+#endif /* CLI_READLINE_H */
+
diff --git a/avr/cmd_echo.c b/avr/cmd_echo.c
new file mode 100644 (file)
index 0000000..d142ab6
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2000-2009
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include "common.h"
+#include "command.h"
+
+
+int do_echo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       uint_fast8_t putnl = 1;
+       
+       (void) cmdtp; (void) flag;
+
+       for (uint_fast8_t i = 1; i < argc; i++) {
+
+               uint_fast8_t backslash = 0;
+               char *p = argv[i];
+               char c;
+               
+               if (i != 1)
+                       putchar(' ');
+               while ((c = *p++) != '\0') {
+               
+                       if(backslash) {
+                               backslash = 0;
+                               if (c == 'c') {
+                                       putnl = 0;
+                                       continue;
+                               } else
+                                       putchar('\\');
+                       } else {
+                               if (c == '\\') {
+                                       backslash = 1;
+                                       continue;
+                               }
+                       }
+                       putchar(c);
+               }
+       }                       
+                                       
+       if (putnl)
+               putchar('\n');
+
+       return 0;
+}
+
+#if 0
+U_BOOT_CMD(
+       echo,   CONFIG_SYS_MAXARGS,     1,      do_echo,
+       "echo args to console",
+       "[args..]\n"
+       "    - echo args to console; \\c suppresses newline"
+);
+#endif
diff --git a/avr/cmd_help.c b/avr/cmd_help.c
new file mode 100644 (file)
index 0000000..317eb5d
--- /dev/null
@@ -0,0 +1,32 @@
+
+#include "common.h"
+#include "command.h"
+
+int do_help(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       const int len = cmd_tbl_item_count();
+       return _do_help(cmd_tbl, len, cmdtp, flag, argc, argv);
+}
+
+
+#if 0
+
+U_BOOT_CMD(
+       help,   CONFIG_SYS_MAXARGS,     1,      do_help,
+       "print command description/usage",
+       "\n"
+       "       - print brief description of all commands\n"
+       "help command ...\n"
+       "       - print detailed usage of 'command'"
+);
+
+/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
+ll_entry_declare(cmd_tbl_t, question_mark, cmd) = {
+       "?",    CONFIG_SYS_MAXARGS,     1,      do_help,
+       "alias for 'help'",
+#ifdef  CONFIG_SYS_LONGHELP
+       ""
+#endif /* CONFIG_SYS_LONGHELP */
+};
+
+#endif
diff --git a/avr/command.c b/avr/command.c
new file mode 100644 (file)
index 0000000..ad39006
--- /dev/null
@@ -0,0 +1,525 @@
+
+/*
+ *  Command Processor Table
+ */
+
+#include "common.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "debug.h"
+#include "con-utils.h"
+#include "env.h"
+#include "timer.h"
+#include "command.h"
+
+
+static void print_blanks(int_fast8_t count)
+{
+       while(count--)
+               putchar(' ');
+}
+
+static void print_usage_line(const FLASH char *name, const FLASH char *usage)
+{
+       my_puts_P(name);
+       print_blanks(CONFIG_SYS_MAXARGS - strlen_P(name));
+       my_puts_P(PSTR(" - "));
+       my_puts_P(usage);
+       my_puts_P(PSTR("\n"));
+}
+
+int strcmp_PP(const FLASH char *s1, const FLASH char *s2)
+{
+       unsigned char c1, c2;
+
+       while ((c1 = *(const FLASH unsigned char *)s1++) 
+                       == (c2 = *(const FLASH unsigned char *)s2++))
+               if (c1 == 0)
+                       return 0;
+
+       return c1 - c2;
+}
+
+int cmpstringp(const void *p1, const void *p2)
+{
+       return strcmp_PP((*(const FLASH cmd_tbl_t **) p1)->name, 
+                        (*(const FLASH cmd_tbl_t **) p2)->name);
+}
+
+int cmd_tbl_item_count(void)
+{
+       cmd_tbl_t * p = cmd_tbl;
+       int count = 0;
+
+       while (p->name != NULL) {
+               p++; count++;
+       }
+       return count;
+}
+
+/*
+ * Use puts() instead of printf() to avoid printf buffer overflow
+ * for long help messages
+ */
+
+int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, 
+               int flag, int argc, char * const argv[])
+{
+       uint_fast8_t i;
+       int rcode = 0;
+
+       (void) flag;
+
+       if (argc == 1) {        /*show list of commands */
+               cmd_tbl_t *cmd_array[cmd_items];
+               int i;
+
+               /* Make array of commands from .uboot_cmd section */
+               cmdtp = cmd_start;
+               for (i = 0; i < cmd_items; i++) {
+                       cmd_array[i] = cmdtp++;
+               }
+
+               /* Sort command list */
+               qsort(cmd_array, cmd_items, sizeof (cmd_tbl_t *), cmpstringp);
+
+               /* print short help (usage) */
+               for (i = 0; i < cmd_items; i++) {
+                       const FLASH char *usage = cmd_array[i]->usage;
+
+                       /* allow user abort */
+                       if (ctrlc ())
+                               return 1;
+                       if (usage == NULL)
+                               continue;
+#ifdef GCC_BUG_61443 
+                       print_usage_line(cmd_array[i]->name, usage);
+#else
+                       printf_P(PSTR("%-" stringify(CONFIG_SYS_MAXARGS) "S - %S\n"), 
+                                       cmd_array[i]->name, usage);
+#endif
+               }
+               return 0;
+       }
+       /*
+        * command help (long version)
+        */
+       for (i = 1; i < argc; ++i) {
+               if ((cmdtp = find_cmd_tbl (argv[i], cmd_start, cmd_items )) != NULL) {
+                       rcode |= cmd_usage(cmdtp);
+               } else {
+                       printf_P(PSTR("Unknown command '%s' - try 'help'"
+                               " without arguments.\n\n"), argv[i]
+                               );
+                       rcode = 1;
+               }
+       }
+       return rcode;
+}
+
+/***************************************************************************
+ * find command table entry for a command
+ */
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len)
+{
+       cmd_tbl_t *cmdtp;
+       cmd_tbl_t *cmdtp_temp = table;  /*Init value */
+       int len;
+       uint_fast8_t n_found = 0;
+
+       if (!cmd)
+               return NULL;
+
+       len = strlen(cmd);
+
+       for (cmdtp = table;
+            cmdtp != table + table_len;
+            cmdtp++) {
+               if (strncmp_P (cmd, cmdtp->name, len) == 0) {
+                       if (len == strlen (cmdtp->name))
+                               return cmdtp;   /* full match */
+
+                       cmdtp_temp = cmdtp;     /* abbreviated command ? */
+                       n_found++;
+               }
+       }
+       if (n_found == 1) {                     /* exactly one match */
+               return cmdtp_temp;
+       }
+
+       return NULL;    /* not found or ambiguous command */
+}
+
+
+cmd_tbl_t *find_cmd (const char *cmd)
+{
+       return find_cmd_tbl(cmd, cmd_tbl, cmd_tbl_item_count());
+}
+
+
+int cmd_usage(const FLASH cmd_tbl_t *cmdtp)
+{
+//     printf("%s - %s\n\n", cmdtp->name, cmdtp->usage);
+       print_usage_line(cmdtp->name, cmdtp->usage);
+#if 0
+       my_puts_P(cmdtp->name);
+       print_blanks(CONFIG_SYS_MAXARGS - strlen_P(cmdtp->name));
+       my_puts_P(PSTR(" - "));
+       my_puts_P(cmdtp->usage);
+       my_puts_P(PSTR("\n\n"));
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+//     printf("Usage:\n%s ", cmdtp->name);
+       my_puts_P(PSTR("Usage:\n"));
+       my_puts_P(cmdtp->name);
+
+       if (!cmdtp->help) {
+               my_puts_P(PSTR(" - No additional help available.\n"));
+               return 1;
+       }
+
+       my_puts_P(cmdtp->help);
+       my_puts_P(PSTR("\n"));
+#endif /* CONFIG_SYS_LONGHELP */
+       return 1;
+}
+
+#ifdef CONFIG_AUTO_COMPLETE
+
+int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+       static char tmp_buf[512];
+       int space;
+
+       space = last_char == '\0' || isblank(last_char);
+
+       if (space && argc == 1)
+               return env_complete("", maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+       if (!space && argc == 2)
+               return env_complete(argv[1], maxv, cmdv, sizeof(tmp_buf), tmp_buf);
+
+       return 0;
+}
+
+/*************************************************************************************/
+
+static int complete_cmdv(int argc, char * const argv[], char last_char, int maxv, char *cmdv[])
+{
+       cmd_tbl_t *cmdtp = cmd_tbl;
+//     const int count = ARRAY_SIZE(cmd_tbl);
+//     const cmd_tbl_t *cmdend = cmdtp + count;
+//     const char *p;
+       int len, clen;
+       int n_found = 0;
+       const char *cmd;
+
+       /* sanity? */
+       if (maxv < 2)
+               return -2;
+
+       cmdv[0] = NULL;
+
+       if (argc == 0) {
+               /* output full list of commands */
+               for (; cmdtp->name[0] != '\0'; cmdtp++) {
+                       if (n_found >= maxv - 2) {
+                               cmdv[n_found++] = "...";
+                               break;
+                       }
+                       cmdv[n_found++] = cmdtp->name;
+               }
+               cmdv[n_found] = NULL;
+               return n_found;
+       }
+
+       /* more than one arg or one but the start of the next */
+       if (argc > 1 || (last_char == '\0' || isblank(last_char))) {
+               cmdtp = find_cmd(argv[0]);
+               if (cmdtp == NULL || cmdtp->complete == NULL) {
+                       cmdv[0] = NULL;
+                       return 0;
+               }
+               return (*cmdtp->complete)(argc, argv, last_char, maxv, cmdv);
+       }
+
+       cmd = argv[0];
+
+       len = strlen(cmd);
+
+       /* return the partial matches */
+       for (; cmdtp->name[0] != '\0'; cmdtp++) {
+
+               clen = strlen(cmdtp->name);
+               if (clen < len)
+                       continue;
+
+               if (memcmp(cmd, cmdtp->name, len) != 0)
+                       continue;
+
+               /* too many! */
+               if (n_found >= maxv - 2) {
+                       cmdv[n_found++] = "...";
+                       break;
+               }
+
+               cmdv[n_found++] = cmdtp->name;
+       }
+
+       cmdv[n_found] = NULL;
+       return n_found;
+}
+
+static int make_argv(char *s, int argvsz, char *argv[])
+{
+       int argc = 0;
+
+       /* split into argv */
+       while (argc < argvsz - 1) {
+
+               /* skip any white space */
+               while (isblank(*s))
+                       ++s;
+
+               if (*s == '\0') /* end of s, no more args       */
+                       break;
+
+               argv[argc++] = s;       /* begin of argument string     */
+
+               /* find end of string */
+               while (*s && !isblank(*s))
+                       ++s;
+
+               if (*s == '\0')         /* end of s, no more args       */
+                       break;
+
+               *s++ = '\0';            /* terminate current arg         */
+       }
+       argv[argc] = NULL;
+
+       return argc;
+}
+
+static void print_argv(const char *banner, const char *leader, const char *sep, int linemax, char * const argv[])
+{
+       int ll = leader != NULL ? strlen(leader) : 0;
+       int sl = sep != NULL ? strlen(sep) : 0;
+       int len, i;
+
+       if (banner) {
+               my_puts_P(PSTR("\n"));
+               my_puts(banner);
+       }
+
+       i = linemax;    /* force leader and newline */
+       while (*argv != NULL) {
+               len = strlen(*argv) + sl;
+               if (i + len >= linemax) {
+                       my_puts_P(PSTR("\n"));
+                       if (leader)
+                               my_puts(leader);
+                       i = ll - sl;
+               } else if (sep)
+                       my_puts(sep);
+               my_puts(*argv++);
+               i += len;
+       }
+       my_puts_P(PSTR("\n"));
+}
+
+static int find_common_prefix(char * const argv[])
+{
+       int i, len;
+       char *anchor, *s, *t;
+
+       if (*argv == NULL)
+               return 0;
+
+       /* begin with max */
+       anchor = *argv++;
+       len = strlen(anchor);
+       while ((t = *argv++) != NULL) {
+               s = anchor;
+               for (i = 0; i < len; i++, t++, s++) {
+                       if (*t != *s)
+                               break;
+               }
+               len = s - anchor;
+       }
+       return len;
+}
+
+static char tmp_buf[CONFIG_SYS_CBSIZE];        /* copy of console I/O buffer   */
+
+int cmd_auto_complete(const FLASH char *const prompt, char *buf, int *np, int *colp)
+{
+       int n = *np, col = *colp;
+       char *argv[CONFIG_SYS_MAXARGS + 1];             /* NULL terminated      */
+       char *cmdv[20];
+       char *s, *t;
+       const char *sep;
+       int i, j, k, len, seplen, argc;
+       int cnt;
+       char last_char;
+
+       if (strcmp_PP(prompt, CONFIG_SYS_PROMPT) != 0)
+               return 0;       /* not in normal console */
+
+       cnt = strlen(buf);
+       if (cnt >= 1)
+               last_char = buf[cnt - 1];
+       else
+               last_char = '\0';
+
+       /* copy to secondary buffer which will be affected */
+       strcpy(tmp_buf, buf);
+
+       /* separate into argv */
+       argc = make_argv(tmp_buf, sizeof(argv)/sizeof(argv[0]), argv);
+
+       /* do the completion and return the possible completions */
+       i = complete_cmdv(argc, argv, last_char, sizeof(cmdv)/sizeof(cmdv[0]), cmdv);
+
+       /* no match; bell and out */
+       if (i == 0) {
+               if (argc > 1)   /* allow tab for non command */
+                       return 0;
+               putchar('\a');
+               return 1;
+       }
+
+       s = NULL;
+       len = 0;
+       sep = NULL;
+       seplen = 0;
+       if (i == 1) { /* one match; perfect */
+               k = strlen(argv[argc - 1]);
+               s = cmdv[0] + k;
+               len = strlen(s);
+               sep = " ";
+               seplen = 1;
+       } else if (i > 1 && (j = find_common_prefix(cmdv)) != 0) {      /* more */
+               k = strlen(argv[argc - 1]);
+               j -= k;
+               if (j > 0) {
+                       s = cmdv[0] + k;
+                       len = j;
+               }
+       }
+
+       if (s != NULL) {
+               k = len + seplen;
+               /* make sure it fits */
+               if (n + k >= CONFIG_SYS_CBSIZE - 2) {
+                       putchar('\a');
+                       return 1;
+               }
+
+               t = buf + cnt;
+               for (i = 0; i < len; i++)
+                       *t++ = *s++;
+               if (sep != NULL)
+                       for (i = 0; i < seplen; i++)
+                               *t++ = sep[i];
+               *t = '\0';
+               n += k;
+               col += k;
+               my_puts(t - k);
+               if (sep == NULL)
+                       putchar('\a');
+               *np = n;
+               *colp = col;
+       } else {
+               print_argv(NULL, "  ", " ", 78, cmdv);
+
+               my_puts_P(prompt);
+               my_puts(buf);
+       }
+       return 1;
+}
+
+#endif /* CONFIG_AUTO_COMPLETE */
+
+
+
+/**
+ * Call a command function. This should be the only route in U-Boot to call
+ * a command, so that we can track whether we are waiting for input or
+ * executing a command.
+ *
+ * @param cmdtp                Pointer to the command to execute
+ * @param flag         Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc         Number of arguments (arg 0 must be the command text)
+ * @param argv         Arguments
+ * @return 0 if command succeeded, else non-zero (CMD_RET_...)
+ */
+static int cmd_call(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int result;
+
+       result = (cmdtp->cmd)(cmdtp, flag, argc, argv);
+       if (result)
+               debug("Command failed, result=%d\n", result);
+       return result;
+}
+
+enum command_ret_t cmd_process(int flag, int argc, char * const argv[],
+                              uint_fast8_t *repeatable)
+{
+       enum command_ret_t rc = CMD_RET_SUCCESS;
+       cmd_tbl_t *cmdtp;
+
+       /* Look up command in command table */
+       cmdtp = find_cmd(argv[0]);
+       if (cmdtp == NULL) {
+               printf_P(PSTR("Unknown command '%s' - try 'help'\n"), argv[0]);
+               return 1;
+       }
+       if (!cmdtp->cmd) {
+               debug("### Command '%s' found, but ->cmd == NULL \n", argv[0]);
+               return 1;
+       }
+
+       /* found - check max args */
+       if (argc > cmdtp->maxargs)
+               rc = CMD_RET_USAGE;
+
+#if defined(CONFIG_CMD_BOOTD)
+       /* avoid "bootd" recursion */
+       else if (cmdtp->cmd == do_bootd) {
+               if (flag & CMD_FLAG_BOOTD) {
+                       my_puts_P(PSTR("'bootd' recursion detected\n"));
+                       rc = CMD_RET_FAILURE;
+               } else {
+                       flag |= CMD_FLAG_BOOTD;
+               }
+       }
+#endif
+
+       /* If OK so far, then do the command */
+       if (!rc) {
+               rc = cmd_call(cmdtp, flag, argc, argv);
+               *repeatable &= cmdtp->repeatable;
+       }
+       if (rc == CMD_RET_USAGE)
+               rc = cmd_usage(cmdtp);
+       return rc;
+}
+
+int cmd_process_error(cmd_tbl_t *cmdtp, int err)
+{
+       char buf[strlen_P(cmdtp->name) + 1];
+       strcpy_P(buf, cmdtp->name);
+
+       if (err) {
+               printf_P(PSTR("Command '%s' failed: Error %d\n"), buf, err);
+               return 1;
+       }
+
+       return 0;
+}
diff --git a/avr/command.h b/avr/command.h
new file mode 100644 (file)
index 0000000..82b83ba
--- /dev/null
@@ -0,0 +1,157 @@
+
+/*
+ *  Definitions for Command Processor
+ */
+#ifndef __COMMAND_H
+#define __COMMAND_H
+
+#include "common.h"
+#include "config.h"
+
+#ifndef NULL
+#define NULL   0
+#endif
+
+/* Default to a width of 8 characters for help message command width */
+#ifndef CONFIG_SYS_HELP_CMD_WIDTH
+#define CONFIG_SYS_HELP_CMD_WIDTH      8
+#endif
+
+/*
+ * Monitor Command Table
+ */
+
+struct cmd_tbl_s {
+       const FLASH char *name;         /* Command Name                 */
+       int             maxargs;        /* maximum number of arguments  */
+       int             repeatable;     /* autorepeat allowed?          */
+                                       /* Implementation function      */
+       int             (*cmd)(const FLASH struct cmd_tbl_s *, int, int, char * const []);
+       const FLASH char *usage;                /* Usage message        (short) */
+#ifdef CONFIG_SYS_LONGHELP
+       const FLASH char *help;         /* Help  message        (long)  */
+#endif
+#ifdef CONFIG_AUTO_COMPLETE
+       /* do auto completion on the arguments */
+       int             (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
+#endif
+};
+
+typedef const FLASH struct cmd_tbl_s cmd_tbl_t;
+
+extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+/* command.c */
+int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
+             flag, int argc, char * const argv[]);
+cmd_tbl_t *find_cmd(const char *cmd);
+cmd_tbl_t *find_cmd_tbl (const char *cmd, cmd_tbl_t *table, int table_len);
+
+int cmd_tbl_item_count(void);
+int cmd_usage(cmd_tbl_t *cmdtp);
+
+#ifdef CONFIG_AUTO_COMPLETE
+extern int var_complete(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
+extern int cmd_auto_complete(const char *const prompt, char *buf, int *np, int *colp);
+#endif
+
+/**
+ * cmd_process_error() - report and process a possible error
+ *
+ * @cmdtp: Command which caused the error
+ * @err: Error code (0 if none, -ve for error, like -EIO)
+ * @return 0 if there is not error, 1 (CMD_RET_FAILURE) if an error is found
+ */
+int cmd_process_error(cmd_tbl_t *cmdtp, int err);
+
+/*
+ * Monitor Command
+ *
+ * All commands use a common argument format:
+ *
+ * void function (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+ */
+
+
+#ifdef CONFIG_CMD_BOOTD
+extern int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+#endif
+#ifdef CONFIG_CMD_BOOTM
+extern int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+extern int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd);
+#else
+static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
+{
+       (void) cmdtp; (void) cmd;
+
+       return 0;
+}
+#endif
+
+extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
+                          char *const argv[]);
+
+extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
+/*
+ * Error codes that commands return to cmd_process(). We use the standard 0
+ * and 1 for success and failure, but add one more case - failure with a
+ * request to call cmd_usage(). But the cmd_process() function handles
+ * CMD_RET_USAGE itself and after calling cmd_usage() it will return 1.
+ * This is just a convenience for commands to avoid them having to call
+ * cmd_usage() all over the place.
+ */
+enum command_ret_t {
+       CMD_RET_SUCCESS,        /* 0 = Success */
+       CMD_RET_FAILURE,        /* 1 = Failure */
+       CMD_RET_USAGE = -1,     /* Failure, please report 'usage' error */
+};
+
+/**
+ * Process a command with arguments. We look up the command and execute it
+ * if valid. Otherwise we print a usage message.
+ *
+ * @param flag         Some flags normally 0 (see CMD_FLAG_.. above)
+ * @param argc         Number of arguments (arg 0 must be the command text)
+ * @param argv         Arguments
+ * @param repeatable   This function sets this to 0 if the command is not
+ *                     repeatable. If the command is repeatable, the value
+ *                     is left unchanged.
+ * @return 0 if the command succeeded, 1 if it failed
+ */
+int cmd_process(int flag, int argc, char * const argv[], uint_fast8_t *repeatable);
+
+
+/*
+ * Command Flags:
+ */
+#define CMD_FLAG_REPEAT                0x0001  /* repeat last command          */
+#define CMD_FLAG_BOOTD         0x0002  /* command is from bootd        */
+
+#ifdef CONFIG_AUTO_COMPLETE
+# define _CMD_COMPLETE(x) x,
+#else
+# define _CMD_COMPLETE(x)
+#endif
+#ifdef CONFIG_SYS_LONGHELP
+# define _CMD_HELP(x) x,
+#else
+# define _CMD_HELP(x)
+#endif
+
+
+#define CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd,             \
+                               _usage, _help, _comp)                   \
+               { FSTR(#_name), _maxargs, _rep, _cmd, FSTR(_usage),     \
+                       _CMD_HELP(FSTR(_help)) _CMD_COMPLETE(_comp) }
+
+#define CMD_TBL_ITEM(_name, _maxargs, _rep, _cmd, _usage, _help)       \
+       CMD_TBL_ITEM_COMPLETE(_name, _maxargs, _rep, _cmd,              \
+                                       _usage, _help, NULL)
+
+typedef int (*do_cmd_t)(cmd_tbl_t *, int, int, char * const []);
+
+extern  cmd_tbl_t cmd_tbl[];
+
+
+#endif /* __COMMAND_H */
diff --git a/avr/command_tbl.c b/avr/command_tbl.c
new file mode 100644 (file)
index 0000000..c0579bc
--- /dev/null
@@ -0,0 +1,76 @@
+
+#include "common.h"
+
+#include "command.h"
+
+
+
+extern int do_help(cmd_tbl_t *, int, int, char * const []);
+extern int do_echo(cmd_tbl_t *, int, int, char * const []);
+extern int do_env_print(cmd_tbl_t *, int, int, char * const []);
+extern int do_env_set(cmd_tbl_t *, int, int, char * const []);
+
+
+cmd_tbl_t cmd_tbl[] = {
+
+CMD_TBL_ITEM(
+       echo,   CONFIG_SYS_MAXARGS,     1,      do_echo,
+       "echo args to console",
+       "[args..]\n"
+       "     - echo args to console; \\c suppresses newline"
+),
+CMD_TBL_ITEM_COMPLETE(
+       run,    CONFIG_SYS_MAXARGS,     1,      do_run,
+       "run commands in an environment variable",
+       "var [...]\n"
+       "    - run the commands in the environment variable(s) 'var'",
+       var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+       printenv, CONFIG_SYS_MAXARGS,   1,      do_env_print,
+       "print environment variables",
+       "\n    - print [all] values of all environment variables\n"
+       "printenv name ...\n"
+       "    - print value of environment variable 'name'",
+       var_complete
+),
+CMD_TBL_ITEM_COMPLETE(
+       setenv, CONFIG_SYS_MAXARGS,     0,      do_env_set,
+       "set environment variables",
+       "[-f] name value ...\n"
+       "    - [forcibly] set environment variable 'name' to 'value ...'\n"
+       "setenv [-f] name\n"
+       "    - [forcibly] delete environment variable 'name'",
+       var_complete
+),
+CMD_TBL_ITEM(
+       help,   CONFIG_SYS_MAXARGS,     1,      do_help,
+       "print command description/usage",
+       "\n"
+       "       - print brief description of all commands\n"
+       "help command ...\n"
+       "       - print detailed usage of 'command'"
+),
+
+/* This does not use the U_BOOT_CMD macro as ? can't be used in symbol names */
+       {FSTR("?"),   CONFIG_SYS_MAXARGS, 1, do_help,
+        FSTR("alias for 'help'"),
+#ifdef  CONFIG_SYS_LONGHELP
+       FSTR(""),
+#endif /* CONFIG_SYS_LONGHELP */
+#ifdef CONFIG_AUTO_COMPLETE
+       0,
+#endif
+},
+/* Mark end of table */
+{ 0 },
+};
+
+
+
+
+
+
+
+
+
diff --git a/avr/common.h b/avr/common.h
new file mode 100644 (file)
index 0000000..ace0fcb
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#ifdef __AVR__
+#include <avr/io.h>
+
+//TODO:
+//  Known to work: 4.8.4, 4.9.1
+//  Known to fail: 4.8.3, 4.9.0
+#define GCC_BUG_61443 1
+
+#else
+// TODO: stm32
+#endif
+
+#include <stdio.h>
+
+#ifdef __FLASH
+#define FLASH __flash
+#else
+#define FLASH
+#endif 
+
+#define stringify(s)   tostring(s)
+#define tostring(s)    #s
+
+#define FSTR(X) ((const FLASH char[]) { X } )
+#define ARRAY_SIZE(x)  (sizeof(x) / sizeof((x)[0]))
+
+
+#ifdef __AVR__
+#define Stat GPIOR0
+#else
+extern volatile uint_least8_t Stat;
+#endif
+
+#define S_10MS_TO      (1<<0)
+
+
+#include <util/delay.h>
+
+static inline 
+void my_puts(const char *s)
+{
+       fputs(s, stdout);
+//     _delay_ms(10);
+}
+
+static inline 
+void my_puts_P(const char *s)
+{
+       fputs_P(s, stdout);
+//     _delay_ms(10);
+}
+
+#endif /* COMMON_H */
+
diff --git a/avr/con-utils.c b/avr/con-utils.c
new file mode 100644 (file)
index 0000000..430ba98
--- /dev/null
@@ -0,0 +1,91 @@
+
+#include <string.h>
+#include <stdio.h>
+
+#include "serial.h"
+#include "con-utils.h"
+
+
+uint_fast8_t tstc(void)
+{
+       return serial_tstc();
+}
+
+int my_getchar(void)
+{
+       int c;
+       
+       while((c = serial_getc()) < 0)
+               ;
+       return c;
+}
+
+
+/* test if ctrl-c was pressed */
+
+static uint_fast8_t ctrlc_disabled = 0;        /* see disable_ctrl() */
+static uint_fast8_t ctrlc_was_pressed = 0;
+
+uint_fast8_t ctrlc(void)
+{
+       if (!ctrlc_disabled) {
+               switch (serial_getc()) {
+               case 0x03:              /* ^C - Control C */
+                       ctrlc_was_pressed = 1;
+                       return 1;
+               default:
+                       break;
+               }
+       }
+       return 0;
+}
+
+/* Reads user's confirmation.
+   Returns 1 if user's input is "y", "Y", "yes" or "YES"
+*/
+uint_fast8_t confirm_yesno(void)
+{
+       unsigned int i;
+       char str_input[5];
+
+       /* Flush input */
+       while (serial_getc())
+               ;
+       i = 0;
+       while (i < sizeof(str_input)) {
+               str_input[i] = my_getchar();
+               putchar(str_input[i]);
+               if (str_input[i] == '\r')
+                       break;
+               i++;
+       }
+       putchar('\n');
+       if (strncmp(str_input, "y\r", 2) == 0 ||
+           strncmp(str_input, "Y\r", 2) == 0 ||
+           strncmp(str_input, "yes\r", 4) == 0 ||
+           strncmp(str_input, "YES\r", 4) == 0)
+               return 1;
+       return 0;
+}
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+uint_fast8_t disable_ctrlc(uint_fast8_t disable)
+{
+       uint_fast8_t prev = ctrlc_disabled;     /* save previous state */
+
+       ctrlc_disabled = disable;
+       return prev;
+}
+
+uint_fast8_t had_ctrlc (void)
+{
+       return ctrlc_was_pressed;
+}
+
+void clear_ctrlc(void)
+{
+       ctrlc_was_pressed = 0;
+}
+
diff --git a/avr/con-utils.h b/avr/con-utils.h
new file mode 100644 (file)
index 0000000..f03dfb3
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef CON_UTILS_H            
+#define CON_UTILS_H
+
+uint_fast8_t tstc(void);
+
+int my_getchar(void);
+
+/* test if ctrl-c was pressed */
+uint_fast8_t ctrlc(void);
+
+
+/* pass 1 to disable ctrlc() checking, 0 to enable.
+ * returns previous state
+ */
+uint_fast8_t disable_ctrlc(uint_fast8_t disable);
+
+uint_fast8_t had_ctrlc (void);
+void clear_ctrlc(void);
+
+#endif /* CON_UTILS_H */
+
+
diff --git a/avr/config.h b/avr/config.h
new file mode 100644 (file)
index 0000000..9e6d4d7
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef CONFIG_H               
+#define CONFIG_H
+
+#define CONFIG_ENV_SIZE                2000
+#define CONFIG_ENV_OFFSET      0
+#define CONFIG_ENVVAR_MAX      20
+
+#define CONFIG_BOOTDELAY       4
+//#define CONFIG_ZERO_BOOTDELAY_CHECK  1
+
+#define CONFIG_SYS_CBSIZE      250
+#define CONFIG_SYS_ENV_NAMELEN 16
+#define CONFIG_SYS_MAXARGS     8
+
+#define CONFIG_SYS_PROMPT      "=> "
+
+
+//#define CONFIG_CMDLINE_EDITING       1
+//#define CONFIG_AUTO_COMPLETE 1
+
+#define CONFIG_SYS_LONGHELP    1
+
+#endif /* CONFIG_H */
+
diff --git a/avr/crc.h b/avr/crc.h
new file mode 100644 (file)
index 0000000..c38bae4
--- /dev/null
+++ b/avr/crc.h
@@ -0,0 +1,12 @@
+#ifndef CRC_H
+#define CRC_H
+
+#include <util/crc16.h>
+
+static inline
+uint16_t crc16(uint16_t crc, uint8_t data) 
+{
+       return _crc_ccitt_update(crc, data);
+}
+
+#endif /* CRC_H */
index ea67a99e5ebf6bc12e2dd1e1d989e63355b72027..1815166195761d684eab5b1917308c1d10f2649d 100644 (file)
@@ -2,13 +2,33 @@
 #ifndef DEBUG_H_
 #define DEBUG_H_
 
+#include "common.h"
 #include <avr/pgmspace.h>
 
+#ifdef DEBUG
+#define _DEBUG 1
+#else
+#define _DEBUG 0
+#endif
+
+#define debug_cond(cond, fmt, args...)         \
+       do {                                    \
+               if (cond)                       \
+                       printf_P(PSTR(fmt), ##args);    \
+       } while (0)
+
+#define debug(fmt, args...)                    \
+       debug_cond(_DEBUG, fmt, ##args)
+
+
+#if 1
 #ifdef DEBUG
 #define DBG_P(lvl, format, ...) if (DEBUG>=lvl) \
                                fprintf_P( stdout, PSTR(format), ##__VA_ARGS__ )
 #else
 #define DBG_P(lvl, ...)
 #endif
+#endif /* 0 */
 
 #endif /* DEBUG_H_ */
+
diff --git a/avr/env.c b/avr/env.c
new file mode 100644 (file)
index 0000000..97bd2e3
--- /dev/null
+++ b/avr/env.c
@@ -0,0 +1,808 @@
+#include "common.h"
+#include <string.h>
+#include <stdlib.h>
+
+#include <avr/eeprom.h>
+
+#include "config.h"
+#include "debug.h"
+#include "xmalloc.h"
+#include "crc.h"
+#include "command.h"
+
+#include "env.h"
+
+
+
+#define DELIM          "\0"
+#define ENV_SIZE       CONFIG_ENV_SIZE-2
+
+
+#define ENV_GET_VAL    (1<<0)
+
+
+/*
+ * Debugging
+ *
+ * TODO: move elsewhere
+ */
+#include <ctype.h>
+
+static void print_blanks(uint_fast8_t count)
+{
+       while(count--)
+               putchar(' ');
+}
+
+
+void dump_ram(const uint8_t *startaddr, int len, char *title)
+{
+       uint8_t llen = 16;
+       uint8_t pre = (size_t) startaddr % 16;
+       const uint8_t *addr = (uint8_t *) ((size_t) startaddr & ~0x0f);
+       len += pre;
+       uint8_t i;
+       
+       if (title && *title)
+               printf_P(PSTR("%s\n"),title);
+               
+       while (len) {
+               if (len < 16)
+                       llen = len;
+                       
+               printf_P(PSTR("    %.4x:"), (size_t) addr);
+               print_blanks(3 * pre);
+               for (i = pre; i < llen; i++)
+                       printf_P(PSTR(" %.2x"), addr[i]);
+               print_blanks(3 * (16 - i + 1) + pre);
+               for (i = pre; i < llen; i++)
+                       printf_P(PSTR("%c"), isprint(addr[i]) ? addr[i] : '.');
+               putchar('\n');
+
+               pre = 0;
+               addr += 16;
+               len -= llen;
+       }
+}
+
+void dump_heap(void)
+{
+       extern unsigned int __brkval;
+
+       dump_ram((uint8_t *) __malloc_heap_start, 
+               __brkval - (unsigned int) __malloc_heap_start,
+               "=== Heap:");
+}
+
+/* TODO: combine with dump_ram() */
+void dump_eep(const uint8_t *addr, int len)
+{
+       int i;
+       uint8_t buf[16];
+       
+       printf_P(PSTR("eeprom dump:"));
+       while (len) {
+               printf_P(PSTR("\n    0x%.4x:"), (unsigned int) addr);
+               for (i = 0; i<16; i++)
+                       buf[i] = eeprom_read_byte(addr + i);
+               for (i = 0; i<16; i++)
+                       printf_P(PSTR(" %.2x"), buf[i]);
+               printf_P(PSTR("   "));
+               for (i = 0; i<16; i++) 
+                       printf_P(PSTR("%c"), isprint(buf[i]) ? buf[i] : '.');
+                       
+               addr += 16;
+               len -= len > 16 ? 16 : len;
+       }
+       putchar('\n');
+}
+
+
+const FLASH char default_env[] = {
+       "bootdelay="    "3"             DELIM
+       "bootcmd="      "echo hallo"    DELIM
+       "baudrate="     "115200"        DELIM
+       DELIM
+};
+
+
+typedef struct environment_s {
+       uint16_t        crc;            /* CRC16 over data bytes        */
+       char            data[ENV_SIZE]; /* Environment data             */
+} env_t;
+
+
+
+typedef struct env_item_s {
+#define EF_N_EEP               (1<<7)
+#define EF_V_EEP               (1<<6)
+#define EF_DIRTY               (1<<0)
+       uint8_t flags;
+       union {
+               uint16_t eep;
+               char     *ram;
+       } name;
+       union {
+               uint16_t eep;
+               char     *ram;
+       } val;
+} env_item_t;
+
+
+static env_item_t env_list[CONFIG_ENVVAR_MAX];
+static int entrycount;
+
+
+static char env_get_char(uint16_t index)
+{
+       unsigned int off = CONFIG_ENV_OFFSET;
+
+       return (char) eeprom_read_byte((const uint8_t *)off + index + 
+                               offsetof(env_t, data));
+}
+
+
+uint16_t ee_name_get(char *buf, env_item_t *ep)
+{
+       int i = 0;
+       char c;
+       
+       if (ep->flags & EF_N_EEP) {
+
+               while ((c = env_get_char(ep->name.eep + i)) != '=' &&
+                               c != '\0' && i < CONFIG_SYS_ENV_NAMELEN) {
+
+                       buf[i] = c;
+                       i++;
+               }
+               if (i > 0 && c != '=') {
+                       debug("** ee_name: '%s' not '=' terminated!\n", buf);
+               }
+       } else {
+               strncpy(buf, ep->name.ram, CONFIG_SYS_ENV_NAMELEN);
+               i = strnlen(buf, CONFIG_SYS_ENV_NAMELEN);
+       }
+       buf[i] = '\0';
+       return i;
+}
+
+
+uint16_t ee_val_get(char *buf, uint16_t index, int len)
+{
+       int i = 0;
+       char c;
+       
+       while ((c = env_get_char (index + i)) != '\0' && i < len) {
+               buf[i] = c;
+               i++;
+       };
+               
+       buf[i] = '\0';
+       
+       /* TODO: len check */
+       
+       return i;
+}
+
+static
+int comp_env_key_item(const void *key, const void *item)
+{
+       char buf[CONFIG_SYS_ENV_NAMELEN+1];
+       env_item_t *ep = (env_item_t *) item;
+       
+       ee_name_get(buf, ep);
+       
+       return strcmp((char *) key, buf);
+}
+
+static
+int comp_env_items(const void *m1, const void *m2)
+{
+       char b1[CONFIG_SYS_ENV_NAMELEN+1];
+       char b2[CONFIG_SYS_ENV_NAMELEN+1];
+       
+       env_item_t *ep1 = (env_item_t *) m1;
+       env_item_t *ep2 = (env_item_t *) m2;
+       
+       ee_name_get(b1, ep1);
+       ee_name_get(b2, ep2);
+       
+       return strcmp(b1, b2);
+}
+
+#if 0
+env_item_t * ee_entry_get(const char *s, env_item_t *ep, uint_fast8_t flag)
+{
+       char name[CONFIG_SYS_ENV_NAMELEN+1];
+       uint16_t idx = 0;
+       int nlen;
+       
+//printf_P(PSTR("*** ee_entry_get:        >>>>>>>>> ENTER <<<<<<<<<\n"));
+
+
+       while ((nlen = ee_name_get(name, idx)) != 0 && idx < CONFIG_ENV_SIZE) {
+       
+//printf_P(PSTR("**  idx: %d, name: '%s', s: '%s', nlen: %d, cpres:%d\n"), 
+//             idx, name, s, nlen, strncmp(name, s, nlen));
+       
+               if (strncmp(name, s, nlen) == 0)
+                       break;
+                       
+               idx += nlen + 1;
+               while (env_get_char(idx++) != 0)
+                       ;
+       }
+       
+       if (nlen) {
+               char *vp;
+               ep->flags = EF_N_EEP;
+               ep->name.eep = idx;
+               if (flag & ENV_GET_VAL) {
+                       vp = xmalloc(CONFIG_SYS_CBSIZE);
+                       nlen = ee_val_get(vp, idx + nlen + 1, CONFIG_SYS_CBSIZE);
+                       ep->val = xrealloc(vp, nlen + 1);
+               } else
+                       ep->val = NULL;
+
+
+//printf_P(PSTR("*** ee_entry_get:        >>>>>> LEAVE 0x%.4x <<<<<\n"), 
+//                     (unsigned int) ep);
+               return ep;
+       }
+
+//printf_P(PSTR("*** ee_entry_get:        >>>>>> LEAVE <NULL> <<<<<\n"));
+       return NULL;
+}                      
+#endif
+
+#if 0
+static char p_env_name_buf[CONFIG_SYS_ENV_NAMELEN+1];
+
+static char *dbg_p_env_name(env_item_t *p)
+{
+       if (p->flags & EF_N_EEP) {
+               if (ee_name_get(p_env_name_buf, p) != 0)
+                       return p_env_name_buf;
+               else
+                       return "<NULL>";
+       }
+       return "<NO EEP_NAME>";
+}
+#endif
+
+int env_item_print(env_item_t *ep)
+{
+       char buf[CONFIG_SYS_ENV_NAMELEN+1];
+       int len;
+       env_item_t e = *ep;
+       
+       ee_name_get(buf, ep);
+       len = printf_P(PSTR("%s="), buf);
+       
+       if (e.val.ram != NULL) {
+               while (1) {
+                       char c;
+                       if (e.flags & EF_V_EEP) 
+                               c = env_get_char(e.val.eep++);
+                       else
+                               c = *e.val.ram++;
+                       
+                       if (c != '\0') {
+                               putchar(c);
+                               len++;
+                       } else
+                               break;
+               }
+       }
+       putchar('\n');
+       len ++;
+
+       return len;
+}      
+
+
+static env_item_t *envlist_search(const char *name)
+{
+       return bsearch(name, env_list, entrycount, 
+                               sizeof(env_item_t), comp_env_key_item);
+}
+                       
+
+env_item_t *envlist_insert(const char *key, env_item_t *e)
+{
+       const size_t size = sizeof(env_item_t);
+
+       if (entrycount < CONFIG_ENVVAR_MAX) {
+               env_list[entrycount++] = *e;
+               qsort(env_list, entrycount, size, comp_env_items);
+
+               return bsearch(key, env_list, entrycount, 
+                                       size, comp_env_key_item);
+               
+       } else
+               return NULL;
+}      
+
+
+env_item_t *envlist_enter(env_item_t *e)
+{
+       char *key = e->name.ram;
+       const size_t size = sizeof(env_item_t);
+       env_item_t *ep;
+       
+       ep = bsearch(key, env_list, entrycount, 
+                       size, comp_env_key_item);
+                                       
+       if (ep == NULL) {
+               if (entrycount < CONFIG_ENVVAR_MAX) {
+                       
+                       env_list[entrycount++] = *e;
+                       qsort(env_list, entrycount, size, comp_env_items);
+                       ep = bsearch(key, env_list, entrycount, 
+                                               size, comp_env_key_item);
+               }
+       } else { 
+               if ((ep->flags & EF_V_EEP) == 0) {
+                       free(ep->val.ram);
+               }
+               ep->val.ram = e->val.ram;
+       }               
+
+       if (ep != NULL) {
+               ep->flags |= EF_DIRTY;
+               ep->flags &= ~EF_V_EEP;
+               
+               if ((ep->flags & EF_N_EEP) == 0) {
+                       int nlen = strnlen(key, CONFIG_SYS_ENV_NAMELEN);
+                       char *name = xmalloc(nlen + 1);
+                       if (name == NULL) {
+                               printf_P(PSTR("## Can't malloc %d bytes\n"), 
+                                       nlen + 1);
+                               return NULL;
+                       }
+                       strcpy(name, key);
+                       name[nlen] = '\0';
+                       ep->name.ram = name;
+               }
+       }
+
+       return ep;              
+}      
+
+
+static env_item_t *envlist_get(const char *name, uint_fast8_t flag)
+{
+       env_item_t *ep;
+       
+       ep = envlist_search(name);
+
+       if (ep != NULL && (flag & ENV_GET_VAL)) {
+               if (ep->flags & EF_V_EEP) {
+                       char *vp;
+                       uint_fast8_t len;
+                       vp = xmalloc(CONFIG_SYS_CBSIZE);
+                       len = ee_val_get(vp, ep->val.eep, CONFIG_SYS_CBSIZE);
+                       ep->val.ram = xrealloc(vp, len + 1);
+                       ep->flags &= ~EF_V_EEP;
+               }
+       }                       
+       
+       return ep;
+}
+
+
+static int envlist_delete(const char *name)
+{
+       size_t size = sizeof(env_item_t);
+       env_item_t *ep = bsearch(name, env_list, entrycount, 
+                               sizeof(env_item_t), comp_env_key_item);
+       int rc = 0;
+
+       if (ep != NULL) {
+       
+               if ((ep->flags & EF_V_EEP) == 0) 
+                       free(ep->val.ram);
+               if ((ep->flags & EF_N_EEP) == 0) 
+                       free(ep->name.ram); 
+
+               entrycount--;
+printf_P(PSTR("*** envlist_delete memmove: 0x%.4x, 0x%.4x, %d\n"), 
+                       (unsigned) ep, (unsigned) ep + size, 
+                       (env_list - ep)*size + entrycount*size);
+               memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size);
+               
+               rc = 1;
+       }
+#if 1
+       dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
+                       "=== env_list:");
+       dump_heap();
+       debug("** entrycount: %d\n", entrycount);
+       for (int i=0; i<entrycount; i++) {
+               printf_P(PSTR("** env var [%d] "), i);
+               env_item_print(&env_list[i]);
+       }
+#endif
+
+       return rc;
+}
+                       
+
+char *getenv(const char *name)
+{
+       env_item_t *ep;
+       char *ret = NULL;
+
+       debug("** getenv: %s\n", name);
+       
+       ep = envlist_get(name, ENV_GET_VAL);
+       if (ep != NULL)
+               ret = ep->val.ram;
+               
+#if 1
+       dump_ram((uint8_t *) &env_list[0], entrycount * sizeof(env_item_t),
+                       "=== env_list:");
+       dump_heap();
+       debug("** entrycount: %d\n", entrycount);
+       for (int i=0; i<entrycount; i++) {
+               printf_P(PSTR("** env var [%d] "), i);
+               env_item_print(&env_list[i]);
+       }
+#endif
+
+       return ret;
+}
+
+int saveenv(void)
+{
+       int     rc = 0;
+
+
+//     rc = env_export(&env_new);
+       if (rc)
+               return rc;
+
+
+//     rc = eeprom_bus_write(CONFIG_SYS_DEF_EEPROM_ADDR,
+//                           off, (uchar *)&env_new, CONFIG_ENV_SIZE);
+
+       return rc;
+}
+
+
+/*-----------------------------------------------------------------------------*/
+
+
+int set_default_env(void)
+{
+       char buf[64];
+       uint16_t crc = 0xffff;
+       uint16_t eep = CONFIG_ENV_OFFSET + offsetof(env_t, data);
+       unsigned int len = CONFIG_ENV_SIZE - offsetof(env_t, data);
+       unsigned int i, src = 0;
+       char c = 0xff, c0 = c;
+       
+printf_P(PSTR("\n\n** set_default_env()\n"));
+       
+       while (len)  {
+       
+               memcpy_P(buf, default_env+src, sizeof(buf));
+               
+               for (i=0; i < (len < sizeof(buf) ? len : sizeof(buf)) &&
+                    !(c == 0 && c0 == 0);
+                   i++)
+               {
+                       c0 = c; c = buf[i];
+                       crc = crc16(crc, c);
+               }
+               
+               eeprom_update_block(buf, (char *) eep, i);
+/**/           printf_P(PSTR("eeprom_update_block: eep: 0x%.4x, i:%d\n"), 
+                       (unsigned int) eep, i);
+/**/           dump_ram((uint8_t *) buf, i, "=== buf:");
+/**/           dump_eep((const uint8_t *) eep, i);
+
+               if (c == 0 && c0 == 0)
+                       len = 0;
+               if (len > sizeof(buf))
+                       len -= sizeof(buf);
+               src += sizeof(buf);
+               eep += sizeof(buf);
+       }
+       
+printf_P(PSTR("** crc adr: 0x%.4x, crc: 0x%.4x\n"),
+       (unsigned int) (uint16_t *) CONFIG_ENV_OFFSET + offsetof(env_t,crc), crc);
+       
+       eeprom_update_word((uint16_t *) CONFIG_ENV_OFFSET + offsetof(env_t,crc), crc);
+       
+/**/   dump_eep(0, 128);
+       return 0;
+}
+
+
+int env_check(void)
+{
+       uint16_t crc, stored_crc; 
+       uint16_t i;
+       char c, c0;
+
+       debug("\n\n** env_check()\n");
+       
+
+       /* read old CRC */
+       stored_crc = eeprom_read_word((const uint16_t *) CONFIG_ENV_OFFSET + 
+                                       offsetof(env_t, crc));
+       crc = 0xffff;
+       c = 0xff;
+       for (i = offsetof(env_t, data); 
+               !(c == 0 && c0 == 0) && i < CONFIG_ENV_SIZE;
+               i++)
+       {
+               c0 = c; 
+               c = eeprom_read_byte((const uint8_t *) CONFIG_ENV_OFFSET + i);
+               crc = crc16(crc, c);
+       }
+       debug("** crc eep: 0x%.4x, crc new: 0x%.4x\n", stored_crc, crc);
+       
+       return crc == stored_crc;
+}
+
+int env_init(void)
+{
+       char name[CONFIG_SYS_ENV_NAMELEN+1];
+       uint16_t idx = 0;
+       int nlen;
+       env_item_t e;
+       
+       e.flags = EF_N_EEP | EF_V_EEP;
+       e.name.eep = idx;
+       while ((nlen = ee_name_get(name, &e)) != 0 && idx < ENV_SIZE) {
+       
+               if (entrycount <= CONFIG_ENVVAR_MAX) {
+                       e.val.eep = idx + nlen + 1;
+       
+                       env_list[entrycount++] = e;
+
+                       idx += nlen + 1;
+                       while (env_get_char(idx++) != 0 && idx < ENV_SIZE)
+                               ;
+                       e.name.eep = idx;
+               } else {
+                       debug("** Too many environment variables!\n");
+                       break;
+               }
+       }
+       qsort(env_list, entrycount, sizeof(env_item_t), comp_env_items);
+
+       return 0;
+}
+
+
+/*
+ * Command interface: print one or all environment variables
+ *
+ * Returns -1 in case of error, or length of printed string
+ */
+static int env_print(char *name)
+{
+       int len = -1;
+
+       if (name) {             /* print a single name */
+       
+               env_item_t *ep = envlist_search(name);
+               if (ep != NULL)
+                       len = env_item_print(ep);
+
+       } else {                /* print whole list */
+               len = 0;
+               for (int i = 0 ; i < entrycount; i++) {
+                       len += env_item_print(&env_list[i]);
+               }
+       }
+       return len;
+}
+
+
+
+int do_env_print(cmd_tbl_t *cmdtp, int flag, int argc,
+                       char * const argv[])
+{
+       int i;
+       int rcode = 0;
+
+       (void) cmdtp; (void) flag;
+
+       if (argc == 1) {
+               /* print all env vars */
+               rcode = env_print(NULL);
+               if (rcode < 0)
+                       return 1;
+               printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"),
+                       rcode, ENV_SIZE);
+               return 0;
+       }
+
+       /* print selected env vars */
+       for (i = 1; i < argc; ++i) {
+               int rc = env_print(argv[i]);
+               if (rc < 0) {
+                       printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]);
+                       ++rcode;
+               }
+       }
+
+       return rcode;
+}
+
+
+/*
+ * Set a new environment variable,
+ * or replace or delete an existing one.
+ */
+static int _do_env_set(int flag, int argc, char * const argv[])
+{
+       int   i, len;
+       char  *name, *value, *s;
+       env_item_t e, *ep;
+
+       (void) flag;
+       debug("Initial value for argc=%d\n", argc);
+
+       name = argv[1];
+       value = argv[2];
+
+       if (strchr(name, '=')) {
+               printf_P(PSTR("## Error: illegal character '='"
+                      "in variable name \"%s\"\n"), name);
+               return 1;
+       }
+       if (strlen(name) > CONFIG_SYS_ENV_NAMELEN) {
+               printf_P(PSTR("## Error: Variable name \"%s\" too long. "
+                      "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN);
+               return 1;
+       }
+/*
+       env_id++;
+*/
+       /* Delete only ? */
+       if (argc < 3 || argv[2] == NULL) {
+               int rc = envlist_delete(name);
+               return !rc;
+       }
+
+       /*
+        * Insert / replace new value
+        */
+       for (i = 2, len = 0; i < argc; ++i)
+               len += strlen(argv[i]) + 1;
+
+       value = xmalloc(len);
+       if (value == NULL) {
+               printf_P(PSTR("## Can't malloc %d bytes\n"), len);
+               return 1;
+       }
+       for (i = 2, s = value; i < argc; ++i) {
+               char *v = argv[i];
+
+               while ((*s++ = *v++) != '\0')
+                       ;
+               *(s - 1) = ' ';
+       }
+       if (s != value)
+               *--s = '\0';
+
+       e.flags = EF_DIRTY;
+       e.name.ram = name;
+       e.val.ram = value;
+       ep = envlist_enter(&e);
+       if (!ep) {
+               printf_P(PSTR("## Error inserting \"%s\" variable.\n"),
+                       name);
+               return 1;
+       }
+
+       return 0;
+}
+
+int setenv(const char *varname, const char *varvalue)
+{
+       const char * const argv[3] = { NULL, varname, varvalue };
+       int argc = 3;
+
+       if (varvalue == NULL || varvalue[0] == '\0')
+               --argc;
+               
+       return _do_env_set(0, argc, (char * const *)argv);
+}
+
+#if 0
+/**
+ * Set an environment variable to an integer value
+ *
+ * @param varname      Environment variable to set
+ * @param value                Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_ulong(const char *varname, unsigned long value)
+{
+       /* TODO: this should be unsigned */
+       char *str = simple_itoa(value);
+
+       return setenv(varname, str);
+}
+#endif
+
+
+/**
+ * Set an environment variable to an value in hex
+ *
+ * @param varname      Environment variable to set
+ * @param value                Value to set it to
+ * @return 0 if ok, 1 on error
+ */
+int setenv_hex(const char *varname, unsigned long value)
+{
+       char str[sizeof(unsigned long) *2 + 1];
+
+       sprintf_P(str, PSTR("%lx"), value);
+       return setenv(varname, str);
+}
+
+unsigned long getenv_hex(const char *varname, unsigned long default_val)
+{
+       const char *s;
+       unsigned long value;
+       char *endp;
+
+       s = getenv(varname);
+       if (s)
+               value = strtoul(s, &endp, 16);
+       if (!s || endp == s)
+               return default_val;
+
+       return value;
+}
+
+int do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       (void) cmdtp;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       return _do_env_set(flag, argc, argv);
+}
+
+
+#if defined(CONFIG_AUTO_COMPLETE) 
+int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf)
+{
+       ENTRY *match;
+       int found, idx;
+
+       idx = 0;
+       found = 0;
+       cmdv[0] = NULL;
+
+       while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
+               int vallen = strlen(match->key) + 1;
+
+               if (found >= maxv - 2 || bufsz < vallen)
+                       break;
+
+               cmdv[found++] = buf;
+               memcpy(buf, match->key, vallen);
+               buf += vallen;
+               bufsz -= vallen;
+       }
+
+       qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
+
+       if (idx)
+               cmdv[found++] = "...";
+
+       cmdv[found] = NULL;
+       return found;
+}
+#endif
+
diff --git a/avr/env.h b/avr/env.h
new file mode 100644 (file)
index 0000000..ac66846
--- /dev/null
+++ b/avr/env.h
@@ -0,0 +1,12 @@
+#ifndef ENV_H
+#define ENV_H
+
+int set_default_env(void);
+int env_check(void);
+int env_init(void);
+
+char *getenv(const char *name);
+int env_complete(char *var, int maxv, char *cmdv[], int maxsz, char *buf);
+
+#endif /* ENV_H */
+
index 2d2c5515ddba3c4f441d48b712fbbfe62cd1bd16..b2fea512c481e773ef0d7aac2a2b0d944efaa5f7 100644 (file)
@@ -106,7 +106,7 @@ int serial_getc(void)
        return ring_read_ch(&rx_ring);
 }
 
-void serial_putc(uint8_t data)
+void serial_putc(char data)
 {
        while (ring_write_ch(&tx_ring, data) < 0)
                ;
@@ -115,3 +115,9 @@ void serial_putc(uint8_t data)
        UCSR0B = _BV(RXCIE0) | _BV(RXEN0) | _BV(TXEN0) | _BV(UDRIE0);
 }
 
+uint_fast8_t serial_tstc(void)
+{
+       return !ring_is_empty(&rx_ring);
+}
+
+
index 1a0f5103d1ba3f969c69f7e7aab98d90c84eb913..7414ef17d12a6aeb5ba0eb46640e6061f5166cdd 100644 (file)
@@ -2,7 +2,8 @@
 #define SERIAL_H
 
 void serial_setup(void);
-void serial_putc(uint8_t);
+void serial_putc(char);
 int serial_getc(void);
+uint_fast8_t serial_tstc(void);
 
 #endif /* SERIAL_H */
diff --git a/avr/timer.c b/avr/timer.c
new file mode 100644 (file)
index 0000000..84a9737
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ */
+
+
+#include "common.h"
+
+//#include <avr/power.h>
+//#include <avr/pgmspace.h>
+#include <avr/interrupt.h>
+#include <util/atomic.h>
+
+//#include <stdio.h>
+
+
+#include "timer.h"
+
+/* timer interrupt/overflow counter */
+static volatile uint32_t timestamp;
+
+
+/*---------------------------------------------------------*/
+/* 1000Hz timer interrupt generated by OC1A                 */
+/*---------------------------------------------------------*/
+
+ISR(TIMER1_COMPA_vect)
+{
+       static int_fast8_t tick_10ms;
+       int_fast8_t i;
+
+
+       timestamp++;
+
+       i = tick_10ms + 1;
+       if (i == 10) {
+               i = 0;
+               Stat |= S_10MS_TO;
+               
+               /* Drive timer procedure of low level disk I/O module */
+               //disk_timerproc();
+       }
+       tick_10ms = i;
+       
+}
+
+
+
+/*--------------------------------------------------------------------------*/
+
+#if 0
+
+void do_10ms(void) 
+{
+               if (to_counter)
+                       to_counter--;
+}
+
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+
+void timer_setup(void)
+{
+
+       /* Clock */
+       CLKPR = _BV(CLKPCE);
+       CLKPR = 0;
+
+       /* Timer */
+
+       OCR1A = F_CPU / 1000 - 1; // Timer1: 1000Hz interval (OC1A)
+       TCCR1B = 0b00001001;
+       TIMSK1 = _BV(OCIE1A); // Enable TC1.oca interrupt
+}
+
+
+uint32_t get_timer(uint32_t base)
+{
+       uint32_t ret;
+       
+       ATOMIC_BLOCK(ATOMIC_FORCEON)
+       {
+               ret = timestamp;
+       }
+       return ret - base;
+}
+
diff --git a/avr/timer.h b/avr/timer.h
new file mode 100644 (file)
index 0000000..bed3eb0
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef TIMER_H                
+#define TIMER_H
+
+uint32_t get_timer(uint32_t);
+
+#endif /* TIMER_H */
+
diff --git a/avr/xmalloc.c b/avr/xmalloc.c
new file mode 100644 (file)
index 0000000..9bf2684
--- /dev/null
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+
+#include "debug.h"
+#include "xmalloc.h"
+
+void* xmalloc(size_t size)
+{
+       void *p;
+
+       p = malloc(size);
+
+       if (p == NULL)
+               debug("*** Out of memory!\n");
+       
+       return p;
+}
+
+
+void* xrealloc(void *p, size_t size)
+{
+       p = realloc(p, size);
+
+       if (p == NULL)
+               debug("*** Out of memory!\n");
+       
+       return p;
+}
diff --git a/avr/xmalloc.h b/avr/xmalloc.h
new file mode 100644 (file)
index 0000000..cb0019f
--- /dev/null
@@ -0,0 +1,8 @@
+
+#ifndef XMALLOC_H
+#define XMALLOC_H
+
+void* xmalloc(size_t size);
+void* xrealloc(void *p, size_t size);
+
+#endif /* XMALLOC_H */
index 09f323c373b30c20e08471e60b5646da984f6c8b..b5a3fb8963f19e08109573549e4c506251dcf1bc 100644 (file)
@@ -242,13 +242,13 @@ const FLASH struct msg_item z80_messages[] =
 {
        { 0,                    /* fct nr. */
          0, 0,                 /* sub fct nr. from, to */
-         &do_msg_ini_msgfifo},
+         do_msg_ini_msgfifo},
        { 0,
          1, 2,
-         &do_msg_ini_memfifo},
+         do_msg_ini_memfifo},
        { 1,
          1, 1,
-         &do_msg_char_out},
+         do_msg_char_out},
        { 0xff,                         /* end mark */
          0, 0,
          0},
index 04be44059ff409cf18a3b277583d56b67a671155..1a54f76b924a99d985ad162ce7b1106edf4792d1 100644 (file)
@@ -1 +1 @@
-CONFIG_DEBUG=2
+CONFIG_DEBUG=0
diff --git a/configs/gcc.tup b/configs/gcc.tup
new file mode 100644 (file)
index 0000000..ad2d788
--- /dev/null
@@ -0,0 +1,40 @@
+CC     = $(TOOLCHAIN)-gcc
+LD     = $(TOOLCHAIN)-gcc
+AR     = $(TOOLCHAIN)-ar
+AS     = $(TOOLCHAIN)-as
+OBJCOPY        = $(TOOLCHAIN)-objcopy
+OBJDUMP        = $(TOOLCHAIN)-objdump
+SIZE   = $(TOOLCHAIN)-size
+GDB    = $(TOOLCHAIN)-gdb
+
+
+CFLAGS += -g -Os
+CFLAGS += -std=gnu99
+CFLAGS += -Wall -Wextra
+CFLAGS += -Wredundant-decls 
+#CFLAGS        += -fno-common -ffunction-sections -fdata-sections
+
+
+LDFLAGS        += -Wl,--gc-sections
+LDFLAGS        += -Wl,--cref
+
+ifneq ($(LDSCRIPT),)
+LDFLAGS        += -T$(LDSCRIPT)
+endif
+
+
+!cc = |> ^ CC %f^ $(CC) $(CFLAGS) $(CPPFLAGS) -c %f -o %o |> %B.o
+!LINK = |> ^ LINK %o^ $(LD) $(CFLAGS) $(LDFLAGS) -Wl,-Map=%O.map %f $(LDLIBS) -o %o |> | %O.map
+!OBJCOPY= |> ^ OBJCOPY %o^ $(OBJCOPY) -Oihex %f %o |> 
+!OBJDUMP= |> ^ OBJDUMP %o^ $(OBJDUMP) -h -S %f > %o |> %O.lss
+!SIZE = |> ^ SIZE %f^ $(SIZE) %f |> 
+
+
+: foreach $(SRC) | $(PREDEP) |> !cc |>  {objs}
+: $(SRC_Z) |> !cc $(CPPFLAGS_Z) |> {objs}
+
+: {objs} |> !LINK |> $(PROG).elf {elf}
+: {elf}  |> !OBJCOPY |> %B.hex {aux}
+: {elf}  |> !OBJDUMP |> %B.lss {aux}
+: {elf}  | {aux} |> !SIZE |>
+