summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/env/fw_env.c127
-rw-r--r--tools/env/fw_env.h24
-rw-r--r--tools/env/fw_env_main.c249
-rw-r--r--tools/palmtreo680/flash_u-boot.c2
-rw-r--r--tools/patman/README2
-rw-r--r--tools/tbot/README185
-rw-r--r--tools/tbot/README-ToDo62
-rw-r--r--tools/tbot/README.create_a_new_testcase117
-rw-r--r--tools/tbot/README.install370
9 files changed, 967 insertions, 171 deletions
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 39f733376e..ee17a69016 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -34,8 +34,6 @@
#include "fw_env.h"
-#include <aes.h>
-
#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
#define WHITESPACE(c) ((c == '\t') || (c == ' '))
@@ -105,9 +103,6 @@ static struct environment environment = {
.flag_scheme = FLAG_NONE,
};
-/* Is AES encryption used? */
-static int aes_flag;
-static uint8_t aes_key[AES_KEY_LENGTH] = { 0 };
static int env_aes_cbc_crypt(char *data, const int enc);
static int HaveRedundEnv = 0;
@@ -125,7 +120,6 @@ static int parse_config (void);
#if defined(CONFIG_FILE)
static int get_config (char *);
-static char *config_file = CONFIG_FILE;
#endif
static inline ulong getenvsize (void)
{
@@ -134,7 +128,7 @@ static inline ulong getenvsize (void)
if (HaveRedundEnv)
rc -= sizeof (char);
- if (aes_flag)
+ if (common_args.aes_flag)
rc &= ~(AES_KEY_LENGTH - 1);
return rc;
@@ -208,7 +202,7 @@ char *fw_getdefenv(char *name)
return NULL;
}
-static int parse_aes_key(char *key)
+int parse_aes_key(char *key, uint8_t *bin_key)
{
char tmp[5] = { '0', 'x', 0, 0, 0 };
unsigned long ul;
@@ -230,11 +224,9 @@ static int parse_aes_key(char *key)
"## Error: '-a' option requires valid AES key\n");
return -1;
}
- aes_key[i] = ul & 0xff;
+ bin_key[i] = ul & 0xff;
key += 2;
}
- aes_flag = 1;
-
return 0;
}
@@ -245,39 +237,12 @@ static int parse_aes_key(char *key)
int fw_printenv (int argc, char *argv[])
{
char *env, *nxt;
- int i, n_flag;
- int rc = 0;
-
-#ifdef CONFIG_FILE
- if (argc >= 2 && strcmp(argv[1], "-c") == 0) {
- if (argc < 3) {
- fprintf(stderr,
- "## Error: '-c' option requires the config file to use\n");
- return -1;
- }
- config_file = argv[2];
- argv += 2;
- argc -= 2;
- }
-#endif
-
- if (argc >= 2 && strcmp(argv[1], "-a") == 0) {
- if (argc < 3) {
- fprintf(stderr,
- "## Error: '-a' option requires AES key\n");
- return -1;
- }
- rc = parse_aes_key(argv[2]);
- if (rc)
- return rc;
- argv += 2;
- argc -= 2;
- }
+ int i, rc = 0;
if (fw_env_open())
return -1;
- if (argc == 1) { /* Print all env variables */
+ if (argc == 0) { /* Print all env variables */
for (env = environment.data; *env; env = nxt + 1) {
for (nxt = env; *nxt; ++nxt) {
if (nxt >= &environment.data[ENV_SIZE]) {
@@ -292,20 +257,13 @@ int fw_printenv (int argc, char *argv[])
return 0;
}
- if (strcmp (argv[1], "-n") == 0) {
- n_flag = 1;
- ++argv;
- --argc;
- if (argc != 2) {
- fprintf (stderr, "## Error: "
- "`-n' option requires exactly one argument\n");
- return -1;
- }
- } else {
- n_flag = 0;
+ if (printenv_args.name_suppress && argc != 1) {
+ fprintf(stderr,
+ "## Error: `-n' option requires exactly one argument\n");
+ return -1;
}
- for (i = 1; i < argc; ++i) { /* print single env variables */
+ for (i = 0; i < argc; ++i) { /* print single env variables */
char *name = argv[i];
char *val = NULL;
@@ -320,7 +278,7 @@ int fw_printenv (int argc, char *argv[])
}
val = envmatch (name, env);
if (val) {
- if (!n_flag) {
+ if (!printenv_args.name_suppress) {
fputs (name, stdout);
putc ('=', stdout);
}
@@ -340,7 +298,7 @@ int fw_printenv (int argc, char *argv[])
int fw_env_close(void)
{
int ret;
- if (aes_flag) {
+ if (common_args.aes_flag) {
ret = env_aes_cbc_crypt(environment.data, 1);
if (ret) {
fprintf(stderr,
@@ -496,43 +454,14 @@ int fw_env_write(char *name, char *value)
*/
int fw_setenv(int argc, char *argv[])
{
- int i, rc;
+ int i;
size_t len;
- char *name;
+ char *name, **valv;
char *value = NULL;
+ int valc;
-#ifdef CONFIG_FILE
- if (argc >= 2 && strcmp(argv[1], "-c") == 0) {
- if (argc < 3) {
- fprintf(stderr,
- "## Error: '-c' option requires the config file to use\n");
- return -1;
- }
- config_file = argv[2];
- argv += 2;
- argc -= 2;
- }
-#endif
-
- if (argc < 2) {
- errno = EINVAL;
- return -1;
- }
-
- if (strcmp(argv[1], "-a") == 0) {
- if (argc < 3) {
- fprintf(stderr,
- "## Error: '-a' option requires AES key\n");
- return -1;
- }
- rc = parse_aes_key(argv[2]);
- if (rc)
- return rc;
- argv += 2;
- argc -= 2;
- }
-
- if (argc < 2) {
+ if (argc < 1) {
+ fprintf(stderr, "## Error: variable name missing\n");
errno = EINVAL;
return -1;
}
@@ -542,14 +471,16 @@ int fw_setenv(int argc, char *argv[])
return -1;
}
- name = argv[1];
+ name = argv[0];
+ valv = argv + 1;
+ valc = argc - 1;
- if (env_flags_validate_env_set_params(argc, argv) < 0)
+ if (env_flags_validate_env_set_params(name, valv, valc) < 0)
return 1;
len = 0;
- for (i = 2; i < argc; ++i) {
- char *val = argv[i];
+ for (i = 0; i < valc; ++i) {
+ char *val = valv[i];
size_t val_len = strlen(val);
if (value)
@@ -1023,7 +954,7 @@ static int env_aes_cbc_crypt(char *payload, const int enc)
uint32_t aes_blocks;
/* First we expand the key. */
- aes_expand_key(aes_key, key_exp);
+ aes_expand_key(common_args.aes_key, key_exp);
/* Calculate the number of AES blocks to encrypt. */
aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH);
@@ -1251,7 +1182,7 @@ int fw_env_open(void)
crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
- if (aes_flag) {
+ if (common_args.aes_flag) {
ret = env_aes_cbc_crypt(environment.data, 0);
if (ret)
return ret;
@@ -1308,7 +1239,7 @@ int fw_env_open(void)
crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
- if (aes_flag) {
+ if (common_args.aes_flag) {
ret = env_aes_cbc_crypt(redundant->data, 0);
if (ret)
return ret;
@@ -1392,9 +1323,9 @@ static int parse_config ()
#if defined(CONFIG_FILE)
/* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
- if (get_config (config_file)) {
- fprintf (stderr,
- "Cannot parse config file '%s': %s\n", config_file, strerror (errno));
+ if (get_config(common_args.config_file)) {
+ fprintf(stderr, "Cannot parse config file '%s': %m\n",
+ common_args.config_file);
return -1;
}
#else
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
index 60c05177ff..57149e733b 100644
--- a/tools/env/fw_env.h
+++ b/tools/env/fw_env.h
@@ -5,6 +5,9 @@
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <aes.h>
+#include <stdint.h>
+
/* Pull in the current config to define the default environment */
#include <linux/kconfig.h>
@@ -54,6 +57,27 @@
"bootm"
#endif
+struct common_args {
+#ifdef CONFIG_FILE
+ char *config_file;
+#endif
+ uint8_t aes_key[AES_KEY_LENGTH];
+ int aes_flag; /* Is AES encryption used? */
+};
+extern struct common_args common_args;
+
+struct printenv_args {
+ int name_suppress;
+};
+extern struct printenv_args printenv_args;
+
+struct setenv_args {
+ char *script_file;
+};
+extern struct setenv_args setenv_args;
+
+int parse_aes_key(char *key, uint8_t *bin_key);
+
extern int fw_printenv(int argc, char *argv[]);
extern char *fw_getenv (char *name);
extern int fw_setenv (int argc, char *argv[]);
diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
index 234c061544..4bd4216625 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -36,119 +36,226 @@
#include <unistd.h>
#include "fw_env.h"
-#define CMD_PRINTENV "fw_printenv"
+#define CMD_PRINTENV "fw_printenv"
#define CMD_SETENV "fw_setenv"
+static int do_printenv;
static struct option long_options[] = {
- {"script", required_argument, NULL, 's'},
+ {"aes", required_argument, NULL, 'a'},
+ {"config", required_argument, NULL, 'c'},
{"help", no_argument, NULL, 'h'},
+ {"script", required_argument, NULL, 's'},
+ {"noheader", required_argument, NULL, 'n'},
{NULL, 0, NULL, 0}
};
-void usage(void)
+struct common_args common_args;
+struct printenv_args printenv_args;
+struct setenv_args setenv_args;
+
+void usage_printenv(void)
{
- fprintf(stderr, "fw_printenv/fw_setenv, "
- "a command line interface to U-Boot environment\n\n"
-#ifndef CONFIG_FILE
- "usage:\tfw_printenv [-a key] [-n] [variable name]\n"
- "\tfw_setenv [-a key] [variable name] [variable value]\n"
-#else
- "usage:\tfw_printenv [-c /my/fw_env.config] [-a key] [-n] [variable name]\n"
- "\tfw_setenv [-c /my/fw_env.config] [-a key] [variable name] [variable value]\n"
+ fprintf(stderr,
+ "Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n"
+ "Print variables from U-Boot environment\n"
+ "\n"
+ " -h, --help print this help.\n"
+#ifdef CONFIG_ENV_AES
+ " -a, --aes aes key to access environment\n"
+#endif
+#ifdef CONFIG_FILE
+ " -c, --config configuration file, default:" CONFIG_FILE "\n"
+#endif
+ " -n, --noheader do not repeat variable name in output\n"
+ "\n");
+}
+
+void usage_setenv(void)
+{
+ fprintf(stderr,
+ "Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n"
+ "Modify variables in U-Boot environment\n"
+ "\n"
+ " -h, --help print this help.\n"
+#ifdef CONFIG_ENV_AES
+ " -a, --aes aes key to access environment\n"
+#endif
+#ifdef CONFIG_FILE
+ " -c, --config configuration file, default:" CONFIG_FILE "\n"
#endif
- "\tfw_setenv -s [ file ]\n"
- "\tfw_setenv -s - < [ file ]\n\n"
- "The file passed as argument contains only pairs "
- "name / value\n"
- "Example:\n"
- "# Any line starting with # is treated as comment\n"
+ " -s, --script batch mode to minimize writes\n"
+ "\n"
+ "Examples:\n"
+ " fw_setenv foo bar set variable foo equal bar\n"
+ " fw_setenv foo clear variable foo\n"
+ " fw_setenv --script file run batch script\n"
"\n"
- "\t netdev eth0\n"
- "\t kernel_addr 400000\n"
- "\t var1\n"
- "\t var2 The quick brown fox jumps over the "
- "lazy dog\n"
+ "Script Syntax:\n"
+ " key [space] value\n"
+ " lines starting with '#' are treated as commment\n"
"\n"
- "A variable without value will be dropped. It is possible\n"
- "to put any number of spaces between the fields, but any\n"
- "space inside the value is treated as part of the value "
- "itself.\n\n"
- );
+ " A variable without value will be deleted. Any number of spaces are\n"
+ " allowed between key and value. Space inside of the value is treated\n"
+ " as part of the value itself.\n"
+ "\n"
+ "Script Example:\n"
+ " netdev eth0\n"
+ " kernel_addr 400000\n"
+ " foo empty empty empty empty empty empty\n"
+ " bar\n"
+ "\n");
}
-int main(int argc, char *argv[])
+static void parse_common_args(int argc, char *argv[])
{
- char *p;
- char *cmdname = *argv;
- char *script_file = NULL;
int c;
- const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
- int lockfd = -1;
- int retval = EXIT_SUCCESS;
- lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (-1 == lockfd) {
- fprintf(stderr, "Error opening lock file %s\n", lockname);
- return EXIT_FAILURE;
- }
+#ifdef CONFIG_FILE
+ common_args.config_file = CONFIG_FILE;
+#endif
- if (-1 == flock(lockfd, LOCK_EX)) {
- fprintf(stderr, "Error locking file %s\n", lockname);
- close(lockfd);
- return EXIT_FAILURE;
+ while ((c = getopt_long(argc, argv, ":a:c:h", long_options, NULL)) !=
+ EOF) {
+ switch (c) {
+ case 'a':
+ if (parse_aes_key(optarg, common_args.aes_key)) {
+ fprintf(stderr, "AES key parse error\n");
+ exit(EXIT_FAILURE);
+ }
+ common_args.aes_flag = 1;
+ break;
+#ifdef CONFIG_FILE
+ case 'c':
+ common_args.config_file = optarg;
+ break;
+#endif
+ case 'h':
+ do_printenv ? usage_printenv() : usage_setenv();
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ /* ignore unknown options */
+ break;
+ }
}
- if ((p = strrchr (cmdname, '/')) != NULL) {
- cmdname = p + 1;
- }
+ /* Reset getopt for the next pass. */
+ opterr = 1;
+ optind = 1;
+}
+
+int parse_printenv_args(int argc, char *argv[])
+{
+ int c;
- while ((c = getopt_long (argc, argv, "a:c:ns:h",
- long_options, NULL)) != EOF) {
+ parse_common_args(argc, argv);
+
+ while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) !=
+ EOF) {
switch (c) {
- case 'a':
- /* AES key, handled later */
+ case 'n':
+ printenv_args.name_suppress = 1;
break;
+ case 'a':
case 'c':
- /* handled later */
+ case 'h':
+ /* ignore common options */
break;
- case 'n':
- /* handled in fw_printenv */
+ default: /* '?' */
+ usage_printenv();
+ exit(EXIT_FAILURE);
break;
+ }
+ }
+ return 0;
+}
+
+int parse_setenv_args(int argc, char *argv[])
+{
+ int c;
+
+ parse_common_args(argc, argv);
+
+ while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) !=
+ EOF) {
+ switch (c) {
case 's':
- script_file = optarg;
+ setenv_args.script_file = optarg;
break;
+ case 'a':
+ case 'c':
case 'h':
- usage();
- goto exit;
+ /* ignore common options */
+ break;
default: /* '?' */
- fprintf(stderr, "Try `%s --help' for more information."
- "\n", cmdname);
- retval = EXIT_FAILURE;
- goto exit;
+ usage_setenv();
+ exit(EXIT_FAILURE);
+ break;
}
}
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
+ int lockfd = -1;
+ int retval = EXIT_SUCCESS;
+ char *_cmdname;
+
+ _cmdname = *argv;
+ if (strrchr(_cmdname, '/') != NULL)
+ _cmdname = strrchr(_cmdname, '/') + 1;
- if (strcmp(cmdname, CMD_PRINTENV) == 0) {
+ if (strcmp(_cmdname, CMD_PRINTENV) == 0) {
+ do_printenv = 1;
+ } else if (strcmp(_cmdname, CMD_SETENV) == 0) {
+ do_printenv = 0;
+ } else {
+ fprintf(stderr,
+ "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n",
+ CMD_PRINTENV, CMD_SETENV, _cmdname);
+ exit(EXIT_FAILURE);
+ }
+
+ if (do_printenv) {
+ if (parse_printenv_args(argc, argv))
+ exit(EXIT_FAILURE);
+ } else {
+ if (parse_setenv_args(argc, argv))
+ exit(EXIT_FAILURE);
+ }
+
+ /* shift parsed flags, jump to non-option arguments */
+ argc -= optind;
+ argv += optind;
+
+ lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (-1 == lockfd) {
+ fprintf(stderr, "Error opening lock file %s\n", lockname);
+ return EXIT_FAILURE;
+ }
+
+ if (-1 == flock(lockfd, LOCK_EX)) {
+ fprintf(stderr, "Error locking file %s\n", lockname);
+ close(lockfd);
+ return EXIT_FAILURE;
+ }
+
+ if (do_printenv) {
if (fw_printenv(argc, argv) != 0)
retval = EXIT_FAILURE;
- } else if (strcmp(cmdname, CMD_SETENV) == 0) {
- if (!script_file) {
+ } else {
+ if (!setenv_args.script_file) {
if (fw_setenv(argc, argv) != 0)
retval = EXIT_FAILURE;
} else {
- if (fw_parse_script(script_file) != 0)
+ if (fw_parse_script(setenv_args.script_file) != 0)
retval = EXIT_FAILURE;
}
- } else {
- fprintf(stderr,
- "Identity crisis - may be called as `" CMD_PRINTENV
- "' or as `" CMD_SETENV "' but not as `%s'\n",
- cmdname);
- retval = EXIT_FAILURE;
}
-exit:
flock(lockfd, LOCK_UN);
close(lockfd);
return retval;
diff --git a/tools/palmtreo680/flash_u-boot.c b/tools/palmtreo680/flash_u-boot.c
index 3d8296fc6b..832d3fef7b 100644
--- a/tools/palmtreo680/flash_u-boot.c
+++ b/tools/palmtreo680/flash_u-boot.c
@@ -97,7 +97,7 @@ int main(int argc, char * const argv[])
return -errsv;
}
printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt);
- printf("U-boot will occupy %d blocks\n", num_blocks);
+ printf("U-Boot will occupy %d blocks\n", num_blocks);
if (num_blocks > devinfo.eb_cnt) {
fprintf(stderr, "Insufficient blocks on partition\n");
return -EINVAL;
diff --git a/tools/patman/README b/tools/patman/README
index 5bd74c4f83..e36857dede 100644
--- a/tools/patman/README
+++ b/tools/patman/README
@@ -138,7 +138,7 @@ is useful if your top commit is for setting up testing.
How to install it
=================
-The most up to date version of patman can be found in the U-boot sources.
+The most up to date version of patman can be found in the U-Boot sources.
However to use it on other projects it may be more convenient to install it as
a standalone application. A distutils installer is included, this can be used
to install patman:
diff --git a/tools/tbot/README b/tools/tbot/README
new file mode 100644
index 0000000000..a637a63d32
--- /dev/null
+++ b/tools/tbot/README
@@ -0,0 +1,185 @@
+# Copyright (c) 2016 DENX Software Engineering GmbH
+# Heiko Schocher <hs@denx.de>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+What is tbot ?
+==============
+
+tbot is a tool for executing testcases on boards.
+Source code found on [1]
+Based on DUTS [2]
+written in python
+
+Basic Ideas of tbot
+===================
+(see also the figure:
+https://github.com/hsdenx/tbot/blob/master/doc/tbot_structure.png )
+
+- Virtual laboratory (VL)
+ VL is the basic environment that groups:
+ - [a number of] boards - target devices on which tbot executes testcases.
+ - one Lab PC
+
+- Test case (TC):
+ A piece of python code, which uses the tbot class from [1].
+ Tbot provides functions for sending shell commands and parsing the
+ shell commands output.
+ Tbot waits endless for a shell commands end (detected through reading
+ the consoles prompt).
+ A TC can also call other TC-es.
+
+ remark:
+ Tbot not really waits endless, for a shell commands end, instead
+ tbot starts a watchdog in the background, and if it triggers, tbot
+ ends the TC as failed. In the tbot beginning there was a lot of
+ timeouts / retry cases, but it turned out, that waiting endless
+ is robust and easy ...
+
+- Host PC (where tbot runs, currently only linux host tested)
+ must not a powerful machine (For example [3], I use a
+ raspberry pi for running tbot and buildbot)
+
+- Lab PC:
+ - Host PC connects through ssh to the Lab PC
+ -> so it is possible to test boards, which
+ are not at the same place as the Host PC.
+ (Lab PC and Host PC can be the same of course)
+ -> maybe we can setup a Testsystem, which does nightly
+ U-Boot/Linux builds and test from current mainline U-Boot
+ on boards wherever they are accessible.
+
+ - necessary tasks a Lab PC must deliver:
+ - connect to boards console through a shell command.
+ - power on/off boards through a shell command
+ - detect the current power state of a board through
+ a shell command
+
+ - optional tasks:
+ - tftp server (for example loading images)
+ - nfs server (used as rootfs for linux kernels)
+ - Internet access for example for downloading
+ U-Boot source with git.
+ - toolchains installed for compiling source code
+
+ -> a linux machine is preffered.
+
+ - currently only Lab PC with an installed linux supported/tested.
+
+- Boards(s):
+ the boards on which shell commands are executed.
+
+- Board state:
+ equals to the software, the board is currently running.
+
+ Currently tbot supports 2 board states:
+ - "u-boot", if the board is running U-Boot
+ - "linux", if the board is running a linux kernel
+
+ It should be easy to add other board states to tbot, see
+ https://github.com/hsdenx/tbot/tree/master/src/lab_api/state_[u-boot/linux].py
+
+ A board state is detected through analysing the boards
+ shell prompt. In linux, tbot sets a special tbot prompt,
+ in U-Boot the prompt is static, and configurable in tbot through
+ a board config file.
+
+ A TC can say in which board state it want to send shell commands.
+ Tbot tries to detect the current board state, if board is not in
+ the requested board state, tbot tries to switch into the correct
+ state. If this fails, the TC fails.
+
+ It is possible to switch in a single TC between board states.
+
+- tbot cmdline parameters:
+
+$ python2.7 src/common/tbot.py --help
+Usage: tbot.py [options]
+
+Options:
+ -h, --help show this help message and exit
+ -c CFGFILE, --cfgfile=CFGFILE
+ the tbot common configfilename
+ -l LOGFILE, --logfile=LOGFILE
+ the tbot logfilename, if default, tbot creates a
+ defaultnamelogfile
+ -t TC, --testcase=TC the testcase which should be run
+ -v, --verbose be verbose, print all read/write to stdout
+ -w WORKDIR, --workdir=WORKDIR
+ set workdir, default os.getcwd()
+$
+
+tbot needs the following files for proper execution:
+
+ - tbot board configuration file (option -c):
+ A board configuration file contains settings tbot needs to
+ connect to the Lab PC and board specific variable settings
+ for testcases.
+
+ - name of the logfile tbot creates (option -l)
+ defaultname: 'log/' + now.strftime("%Y-%m-%d-%H-%M") + '.log'
+
+ - tbots working directory (option -w)
+
+ - the testcasename tbot executes (option -t)
+
+You are interested and want to use tbot?
+If so, please read on the file:
+tools/tbot/README.install
+
+If not read [3] ;-)
+
+Heiko Schocher <hs@denx.de>
+v1 2016.01.22
+
+--------------
+[1] https://github.com/hsdenx/tbot
+[2] http://www.denx.de/wiki/DUTS/DUTSDocs
+[3] automated Testsetup with buildbot and tbot doing cyclic tests
+ (buildbot used for starting tbot TC and web presentation of the
+ results, all testing done through tbot):
+ http://xeidos.ddns.net/buildbot/tgrid
+ Host PC in Letkes/hungary
+ VL in munich/germany
+
+ Fancy things are done here, for example:
+ - http://xeidos.ddns.net/buildbot/builders/smartweb_dfu/builds/43/steps/shell/logs/tbotlog
+ (I try to cleanup the logfile soon, so it is not so filled with crap ;-)
+ A first step see here:
+ http://xeidos.ddns.net/buildbot/builders/smartweb_dfu/builds/45/steps/shell/logs/tbotlog
+ (same TC now with the new loglevel = 'CON' ... not yet perfect)
+ Executed steps:
+ - clone u-boot.git
+ - set toolchain
+ - get a list of patchwork patches from my U-Boots ToDo list
+ - download all of them, and check them with checkpatch
+ and apply them to u-boot.git
+ - compile U-Boot for the smartweb board
+ - install the resulting images on the smartweb board
+ - boot U-boot
+ - test DFU
+ - more TC should be added here for testing U-Boot
+
+ - automatic "git bisect"
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_board_git_bisect.py
+ http://xeidos.ddns.net/buildbot/builders/tqm5200s/builds/3/steps/shell/logs/tbotlog
+
+ If a current U-Boot image not works on the tqm5200 board
+ this TC can be started. It starts a "git bisect" session,
+ and compiles for each step U-Boot, install it on the tqm5200
+ board, and tests if U-Boot works !
+
+ At the end, it detects the commit, which breaks the board
+
+ This TC is not dependend on U-Boot nor on a special board. It
+ needs only 3 variables:
+ tb.board_git_bisect_get_source_tc: TC which gets the source tree, in which
+ "git bisect" should be executed
+ tb.board_git_bisect_call_tc: TC which gets called every "git bisect" step,
+ which executes commands for detecting if current source code is OK or not.
+ This could be a TC which compiles U-Boot, install it on the board and
+ executes TC on the new booted U-Boot image. ! Board maybe gets borken,
+ as not all U-Boot images work, so you must have a TC which install U-Boot
+ image for example through a debugger.
+ tb.board_git_bisect_good_commit: last nown good commit id
diff --git a/tools/tbot/README-ToDo b/tools/tbot/README-ToDo
new file mode 100644
index 0000000000..daf1af1323
--- /dev/null
+++ b/tools/tbot/README-ToDo
@@ -0,0 +1,62 @@
+# Copyright (c) 2016 DENX Software Engineering GmbH
+# Heiko Schocher <hs@denx.de>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+ToDo list for tbot
+==================
+
+please look also into the tbot ToDo list.
+https://github.com/hsdenx/tbot/blob/master/ToDo
+
+- cleanup tbot code:
+ - remove all retry / timeout pieces of code
+ - clean up tbot function names, as I am not good in
+ giving function a understandable name ;-)
+ - as I am not a python programmer, cleanup whole tbot code
+
+- introduce a "layering" like yocto do, so U-Boot TC can integrated
+ into U-Boot source code.
+
+ Proposal:
+ introduce subdirs in "src/tc"
+
+ lab: all lab specific stuff
+ lab/common: common lab stuff (for example ssh handling)
+ lab/ssh_std: ssh_std specific stuff
+
+ u-boot: all u-boot tests
+ u-boot/common: common u-boot tc
+ u-boot/duts: DUTS tc
+ u-boot-dxr2: all u-boot dxr2 board specific tc
+
+ board: board tc
+ board/common: common board tc
+ board/dxr2: all tc for dxr2 board
+
+ linux: all linux tc
+ linux/common: common linux tc
+ linux/dxr2
+
+ - move U-Boot special TC to U-Boot source
+ -> need a mechanism in tbot, how it gets automatically for example
+ U-Boot TC from U-Boot source...
+ -> add a consistency checker
+
+- simplify tbot log output (seperate a lot of output which is currently
+ in INFO logging level, to another logging level)
+ started (new loglevel "CON", whih prints read/write from console only), see:
+ https://github.com/hsdenx/tbot/commit/b4ab2567ad8c19ad53f785203159d3c8465a21c6
+ - make the timestamp configurable
+
+- Open more than 2 filehandles ?
+ Do we need for more complex TC more than 2 filehandles?
+
+- Find a way to document all TC and document all variables they use in an
+ automated way.
+
+- write a lot of more TC
+
+- get U-Boot configuration settings from current U-Boot code and use
+ them in U-Boot TC-es
diff --git a/tools/tbot/README.create_a_new_testcase b/tools/tbot/README.create_a_new_testcase
new file mode 100644
index 0000000000..fbf8ae8329
--- /dev/null
+++ b/tools/tbot/README.create_a_new_testcase
@@ -0,0 +1,117 @@
+# Copyright (c) 2016 DENX Software Engineering GmbH
+# Heiko Schocher <hs@denx.de>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+write a new testcase
+=====================
+
+A TC is written in python, so you can use python as usual. For accessing
+the boards console, use functions from the tbotlib, therefore
+
+First import the tbotlib with the line:
+
+ from tbotlib import tbot
+
+If your TC uses variables, please add a line which adds them to
+the log file (for debugging purposes):
+
+ logging.info("args: %s ...", tb.varname, ...)
+
+Say tbot, for which board state your TC is valid with:
+
+ tb.set_board_state("u-boot")
+
+Then you are ready ... and you can use the tbotlib funtions
+for writting/reading to the boards console.
+
+Big fat warning:
+
+A TC must worry about to end only if a board has finished the shell
+command!
+
+Not following this rule, will end in unpredictable behaviour.
+
+(hopefully) useful tbotlib functions
+====================================
+- set the board state, you want to test
+ tb.set_board_state(state)
+ states are: "u-boot" or "linux"
+ If tbot could not set the board state, tbot ends with failure.
+
+- write a command to the boards console:
+ tb.eof_write_con(command):
+ write the command to the boards console. If this
+ fails, tbot ends with failure
+
+- write a command to boards console and wait for prompt:
+ tb.eof_write_cmd(fd, command):
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ command: command which is written to fd
+
+ Wait endless for board prompt
+
+- write a list of commands to boards console:
+ tb.eof_write_cmd_list(fd, cmdlist):
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ cmdlist: python list of commandstrings which is written to fd
+
+- wait for boards prompt:
+ tb.eof_read_end_state_con(retry):
+ retry: deprecated, not used anymore, cleanup needed here...
+ tbot waits endless for the boards prompt
+
+- write a command, wait for prompt and check, if a string is read
+ tb.write_cmd_check(fd, cmd, string):
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ cmd: command, which is send to fd
+ string: string which should be read from fd
+
+ return value:
+ True, if string is read and tbot got back boards prompt
+ False, else
+
+ tb.eof_write_cmd_check(fd, cmd, string):
+ same as tb.write_cmd_check(fd, cmd, string) except, that tbot
+ ends immediately with Failure, if string is not read.
+
+- read until prompt and search strings:
+ tb.readline_and_search_strings(fd, strings):
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ strings: python list of strings, which can be read
+ If one of this strings is read, this function return the index, which
+ string is read. This function shoud be called in a while loop,
+ until this function returns 'prompt'
+
+- read a line from filedescriptor:
+ not recommended to use, as the TC must check, if tprompt is read for every
+ readen line. Also TC must ensure, that it ends only, if prompt is read.
+ tb.read_line(fd, retry)
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ retry: retry of trying to reead a line
+
+ return values:
+ True, if a line is read. Readen line in tb.buf[fd]
+ False, if something read, but not a complete line
+ None, if nothing is read
+
+ check if string contains prompt with:
+ tb.is_end_fd(fd, string)
+ fd: filedescriptor which is used, use tb.channel_con for boards console
+ string: buffer, in which a prompt gets searched.
+
+- calling other TC:
+ eof_call_tc(name):
+ call another TC from "src/tc"
+ if the called TC fails with failure, tbot ends with failure
+
+ call_tc(name):
+ call another TC from "src/tc"
+ if the TC which call_tc calls fails, call_tc() returns False, else True
+
+There are more functions, but for writting TC this should be enough. But
+its software, so new useful functions can always pop up.
+
+Heiko Schocher <hs@denx.de>
+v1 2016.01.23
diff --git a/tools/tbot/README.install b/tools/tbot/README.install
new file mode 100644
index 0000000000..24c67bc661
--- /dev/null
+++ b/tools/tbot/README.install
@@ -0,0 +1,370 @@
+# Copyright (c) 2016 DENX Software Engineering GmbH
+# Heiko Schocher <hs@denx.de>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+install tbot on your PC (linux only tested):
+============================================
+
+- get the source code:
+
+$ git clone https://github.com/hsdenx/tbot.git
+[...]
+$
+
+ cd into the tbot directory.
+
+- you need the for running tbot the python paramiko module, see:
+ http://www.paramiko.org/installing.html
+
+ paramiko is used for handling ssh sessions, and open filedescriptors
+ on a ssh connection. Tbot open a ssh connection to a "lab PC" and
+ opens on that connection 2 filehandles, one for control functions
+ and one for the connection to the boards console. May it is worth
+ to think about to open more filehandles and use them in tbot, but
+ thats a point in the Todo list ...
+
+ See [1] for more infos about tbot principles.
+
+- prepare a directory for storing the logfiles
+ and pass it with the commandline option "-l"
+ to tbot. Default is the directory "log" in the tbot
+ root (don;t forget to create it, if you want to use it)
+
+- If your VL is not yet in tbot source, integrate it
+ (This task has only to be done once for your VL):
+
+ A VL has, as described in [2] "necessary tasks for a Lab PC" explained,
+ 3 tasks:
+
+ a) power on/off the board
+ b) get power state of the board
+ c) connect to the boards console
+
+ As tbot sends only shell commands (also to the Lab PC)
+ this tasks must be executable through shell commands on your
+ Lab PC:
+
+ Task a) power on/off board:
+ default TC for this task is:
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_power.py
+
+ - now copy this file to for example
+ cp src/tc/tc_lab_denx_power.py src/tc/tc_lab_denx_power_XXX.py
+ (replace XXX to a proper value)
+ and adapt the "remote_power" command from the denx lab to your needs.
+
+ As this TC powers on the board for all your boards in your VL,
+ you can differ between the boards through the tbot class
+ variable "tb.boardlabpowername" (which is in the default case the
+ same as "tb.boardname"), but you may need to name the power target
+ with an other name than boardname, so you can configure this case.
+ The power state "tb.power_state" which the TC has to set
+ is "on" for power on, or "off" for power off.
+
+ If switching on the power is successful, call "tb.end_tc(True)"
+ else "tb.end_tc(False)"
+
+ - set in your board config file:
+ self.tc_lab_denx_power_tc = 'tc_lab_denx_power_XXX.py'
+
+ Task b) power on/off board:
+ default TC for this task is:
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_get_power_state.py
+
+ - now copy this file to for example
+ (replace XXX to a proper value)
+ cp src/tc/tc_lab_denx_get_power_state.py src/tc/tc_lab_denx_get_power_state_XXX.py
+ and adapt the commands to your needs.
+
+ If the power of the board is on, call "tb.end_tc(True)"
+ else "tb.end_tc(False)"
+
+ - set in your board config file:
+ self.tc_lab_denx_get_power_state_tc = 'tc_lab_denx_get_power_state_XXX.py'
+
+ Task c) connect to the boards console:
+ default TC for this task is:
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_lab_denx_connect_to_board.py
+
+ - now copy this file to for example
+ (replace XXX to a proper value)
+ cp src/tc/tc_lab_denx_connect_to_board.py src/tc/tc_lab_denx_connect_to_board_XXX.py
+ and adapt the commands to your needs.
+
+ As this TC powers on the board for all your boards in your VL,
+ you can differ between the boards through the tbot class
+ variable "tb.boardlabname" (which is in the default case the
+ same as "tb.boardname"), but you may need to name the power target
+ with an other name than boardname, so you can configure this case.
+
+ If connect fails end this TC with "tb.end_tc(False)"
+ else call "tb.end_tc(True)"
+
+ If you want to use kermit for connecting to the boards console, you
+ can use:
+
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_workfd_connect_with_kermit.py
+
+ Example for such a board in the VL from denx:
+ self.tc_lab_denx_connect_to_board_tc = 'tc_workfd_connect_with_kermit.py'
+ https://github.com/hsdenx/tbot/blob/master/tbot_dxr2.cfg#L24
+
+ Hopefully this works for you too.
+
+ - set in your board config file:
+ self.tc_lab_denx_connect_to_board_tc = 'tc_lab_denx_connect_to_board_XXX.py'
+
+ remarks while writting this:
+ - Currently there is only the denx VL. Original idea was to include
+ other VL through a seperate class/file in
+ https://github.com/hsdenx/tbot/tree/master/src/lab_api
+ but it turned out, that if we say "ssh" is the standard way to connect
+ to a VL, we can integrate the VL specific tasks through testcases, see
+ above, so we should do:
+ - rename the "denx" API to a more general name.
+ This is a point on my ToDo list ... done, renamed to 'ssh_std'
+
+ - the VL specific configuration may moved from the board config files
+ and should be collected in VL specific config files, which boards
+ config file simple include.
+
+- prepare password.py file:
+ This file contains all passwords tbot needs (for example for
+ linux login on the boards)
+ tbot searches this file in the tbot root directory.
+ It is a simple python file, for example:
+
+ # passwords for the lab
+ if (board == 'lab'):
+ if (user == 'hs'):
+ password = 'passwordforuserhs'
+ if (user == 'root'):
+ password = 'passwordforrootuser'
+ # passwords for the boards
+ elif (board == 'mcx'):
+ if (user == 'root'):
+ password = 'passwordformcxrootfs'
+ else:
+ if (user == 'root'):
+ password = ''
+
+ In the above example passwords for logging into the Lab PC tbot finds
+ through:
+ if (board == 'lab'):
+ user = 'name':
+ password = 'gnlmpf' # password 'gnlmpf' for login of user 'name'
+
+- prepare board config file
+ Each board which is found in the VL needs a tbot configuration file
+ pass the config file name with the option '-c' to tbot, tbot searches
+ in the root dir for them.
+
+ board Example (dxr2 board):
+ https://github.com/hsdenx/tbot/blob/master/tbot_dxr2.cfg
+
+ Necessary variables:
+
+ line 3: boardname, here it is the "etamin" board
+ no default value, must be set.
+ line 4: boardlabname: name used for connecting to the board
+ may differ from tb.boardname, default tb.boardname
+ line 5: boardlabpowername: name used for power on/off
+ may differ from tb.boardname, default tb.boardname
+ line 6: tftpboardname: name used for tftp subdir (from where
+ U-Boot loads images for example).
+ may differ from tb.boardname, default tb.boardname
+ line 7: labprompt: linux prompt tbot sets
+ no defaultvalue, must be set (maybe we should introduce
+ "ttbott" as default ...
+ line 8: debug: If True, adds debug output on the tbot shell
+ line 9: debugstatus: enable status debug output on the shell
+ line 10: ip: Where tbot finds the Lab PC
+ line 11: user: As which user does tbot logs into the Lab PC
+ line 12: accept_all: passed to paramiko, accept all connections
+ line 13: keepalivetimout: passed to paramiko, timeout for sending
+ keepalive message.
+ line 14: channel_timeout: passed to paramiko
+ line 15: loglevel: tbots loglevel for adding entries into the logfile.
+ line 16: lap_api: used lap API (currently only 'ssh_std')
+ Should be declared as standard -> this line would be not needed
+ longer.
+ line 17: wdt_timeout: timeout in seconds for tbots watchdog.
+ Watchdog gets triggered if prompt get read.
+ line 20,21: include 'ssh_std' api
+ should be removed.
+ line 24: tc_lab_denx_connect_to_board_tc: Which TC is used for
+ connecting to the boards console the TC, here:
+ https://github.com/hsdenx/tbot/blob/master/src/tc/tc_workfd_connect_with_kermit.py
+ line 27: uboot_prompt: boards U-Boot prompt
+ line 28: linux_prompt: boards linux prompt
+
+ Now comes a list of variables TC needs, this vary from which TC
+ you start on the board.
+
+Thats it ... you now can call tbot and hopefully, it works ;-)
+Find an example log [3] for calling simple U-Boot TC for setting
+an U-Boot Environmentvariable.
+
+If you have problems in setting tbot up, please contact me
+(and may give me ssh access to your Lab PC ;-)
+
+If you have running your first TC [3], you may want to write now your own
+TC (and hopefully share them), so continue with:
+u-boot:tools/tbot/README.create_a_new_testcase
+
+Heiko Schocher <hs@denx.de>
+v1 2016.01.22
+
+--------------
+
+[1] tbot Dokumentation:
+ [2] u-boot:/tools/tbot/README
+ https://github.com/hsdenx/tbot/blob/master/README.md
+
+[3] Example for a first U-Boot TC which should always work:
+ (with commandline option "-v" for verbose output):
+
+hs@localhost:tbot [master] $ python2.7 src/common/tbot.py -c tbot_dxr2.cfg -t tc_ub_setenv.py -v -l log/tbot.log
+**** option cfg: tbot_dxr2.cfg log: log/tbot.log tc: tc_ub_setenv.py v 1
+('CUR WORK PATH: ', '/home/hs/data/Entwicklung/tbot')
+('CFGFILE ', 'tbot_dxr2.cfg')
+('LOGFILE ', '/home/hs/data/Entwicklung/tbot/log/tbot.log')
+(<denx.tbot_lab_api object at 0x7f53ac1808d0>, <tbotlib.tbot object at 0x7f53a45fd410>, True)
+(<denx.tbot_lab_api object at 0x7f53ac1808d0>, <tbotlib.tbot object at 0x7f53a45fd410>, True)
+read 0: Last login: Fri Jan 22 12:20:12 2016 from 87.97.28.177
+read 0:
+read 0: *************************************************************
+read 0: BDI2000 Assignment: (last updated: 2015-11-20 12:30 MET)
+read 0: bdi1 => techem bdi2 => cetec_mx25 bdi3 => lpc3250
+read 0: bdi4 => - bdi5 => --Rev.B!-- bdi6 => tqm5200s
+read 0: bdi7 => [stefano] bdi8 => smartweb bdi9 => sigmatek-nand
+read 0: bdi10 => pcm052 bdi11 => socrates bdi12 => aristainetos
+read 0: bdi13 => imx53 bdi14 => ib8315 bdi15 => cairo
+read 0: bdi16 => g2c1 bdi17 => lwe090 bdi18 => symphony
+read 0: bdi19 => dxr2 bdi20 => ima3-mx6 bdi21 => sama5d3
+read 0: bdi98 => - bdi99 => - bdi0 => -
+read 0: Please power off unused systems when you leave! Thanks, wd.
+read 0: *************************************************************
+read no ret 0:
+pollux:~ hs $
+write 0: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 0: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 0: hs@pollux [12:21:00] ttbott >
+read 1: Last login: Fri Jan 22 12:20:59 2016 from 87.97.28.177
+read 1:
+read 1: *************************************************************
+read 1: BDI2000 Assignment: (last updated: 2015-11-20 12:30 MET)
+read 1: bdi1 => techem bdi2 => cetec_mx25 bdi3 => lpc3250
+read 1: bdi4 => - bdi5 => --Rev.B!-- bdi6 => tqm5200s
+read 1: bdi7 => [stefano] bdi8 => smartweb bdi9 => sigmatek-nand
+read 1: bdi10 => pcm052 bdi11 => socrates bdi12 => aristainetos
+read 1: bdi13 => imx53 bdi14 => ib8315 bdi15 => cairo
+read 1: bdi16 => g2c1 bdi17 => lwe090 bdi18 => symphony
+read 1: bdi19 => dxr2 bdi20 => ima3-mx6 bdi21 => sama5d3
+read 1: bdi98 => - bdi99 => - bdi0 => -
+read 1: Please power off unused systems when you leave! Thanks, wd.
+read 1: *************************************************************
+read no ret 1:
+pollux:~ hs $
+write 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 1: hs@pollux [12:21:02] ttbott >
+write 0: remote_power dxr2 -l
+read 0: hs@pollux [12:21:00] ttbott >remote_power dxr2 -l
+read 0: dxr2 ON
+read 0: hs@pollux [12:21:02] ttbott >
+read no ret 1:
+hs@pollux [12:21:02] ttbott >
+write 1: ssh hs@lena
+read 1: ssh hs@lena
+read no ret 1:
+hs@lena's password:
+read 1:
+read 1: Last login: Fri Jan 22 12:20:17 2016 from 192.168.1.1
+read 1:
+read no ret 1:
+[hs@lena ~]$
+write 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 1: export PS1="\u@\h [\$(date +%k:%M:%S)] ttbott >"
+read 1: hs@lena [12:21:07] ttbott >
+read no ret 1:
+hs@lena [12:21:07] ttbott >
+write 1: stty cols 200
+read 1: stty cols 200
+read 1: hs@lena [12:21:08] ttbott >
+write 1: export TERM=vt200
+read 1: hs@lena [12:21:08] ttbott >export TERM=vt200
+read 1: hs@lena [12:21:08] ttbott >
+write 1: echo $COLUMNS
+read 1: hs@lena [12:21:08] ttbott >echo $COLUMNS
+read 1: 200
+read 1: hs@lena [12:21:08] ttbott >
+write 1: kermit
+read 1: hs@lena [12:21:08] ttbott >kermit
+read 1: C-Kermit 8.0.211, 10 Apr 2004, for Linux
+read 1:
+read 1: Copyright (C) 1985, 2004,
+read 1: Trustees of Columbia University in the City of New York.
+read 1: Type ? or HELP for help.
+read 1:
+read 1: (/home/hs/) C-Kermit>
+read 1:
+read no ret 1: (/home/hs/) C-Kermit>
+write 1: set line /dev/ttyUSB0
+read 1: set line /dev/ttyUSB0
+read 1:
+read 1: (/home/hs/) C-Kermit>
+write 1: set speed 115200
+read 1:
+read 1: (/home/hs/) C-Kermit>set speed 115200
+read 1: /dev/ttyUSB0, 115200 bps
+read 1:
+read 1: (/home/hs/) C-Kermit>
+write 1: set flow-control none
+read 1:
+read 1: (/home/hs/) C-Kermit>set flow-control none
+read 1:
+read 1: (/home/hs/) C-Kermit>
+write 1: set carrier-watch off
+read 1:
+read 1: (/home/hs/) C-Kermit>set carrier-watch off
+read 1:
+read 1: (/home/hs/) C-Kermit>
+write 1: connect
+read 1:
+read 1: (/home/hs/) C-Kermit>connect
+read 1: Connecting to /dev/ttyUSB0, speed 115200
+read 1:
+read 1: Escape character: Ctrl-\ (ASCII 28, FS): enabled
+read 1:
+read 1: Type the escape character followed by C to get back,
+read 1:
+read 1: or followed by ? to see other options.
+read 1:
+read 1: ----------------------------------------------------
+read no ret 1:
+
+write no ret 1:
+
+read 1:
+read 1: Heiko=Schocher
+read no ret 1:
+U-Boot#
+write no ret 1:
+write no ret 1:
+
+read 1: <INTERRUPT>
+read 1: U-Boot#
+write 1: setenv Heiko Schocher
+read 1: U-Boot# setenv Heiko Schocher
+read no ret 1:
+U-Boot#
+write 1: printenv Heiko
+read 1: printenv Heiko
+read 1: Heiko=Schocher
+read no ret 1:
+U-Boot#
+End of TBOT: success
+hs@localhost:tbot [master] $
OpenPOWER on IntegriCloud