diff --git a/Makefile.include b/Makefile.include index 1a7607ad5b..befb9d8647 100644 --- a/Makefile.include +++ b/Makefile.include @@ -630,6 +630,13 @@ term: $(filter flash flash-only, $(MAKECMDGOALS)) $(TERMDEPS) $(call check_cmd,$(TERMPROG),Terminal program) $(TERMPROG) $(TERMFLAGS) +# Term without the pyterm added logging +# TERMFLAGS must be exported for `jlink.sh term_rtt`. +cleanterm: export PYTERMFLAGS += --noprefix --no-repeat-command-on-empty-line +cleanterm: $(filter flash, $(MAKECMDGOALS)) $(TERMDEPS) + $(call check_cmd,$(TERMPROG),Terminal program) + $(TERMPROG) $(TERMFLAGS) + list-ttys: $(Q)$(RIOTTOOLS)/usb-serial/list-ttys.sh diff --git a/dist/pythonlibs/testrunner/spawn.py b/dist/pythonlibs/testrunner/spawn.py index 84164d1a1d..34859b1f61 100644 --- a/dist/pythonlibs/testrunner/spawn.py +++ b/dist/pythonlibs/testrunner/spawn.py @@ -36,7 +36,7 @@ def find_exc_origin(exc_info): def setup_child(timeout=10, spawnclass=pexpect.spawnu, env=None, logfile=None): - child = spawnclass("make term", env=env, timeout=timeout, + child = spawnclass("make cleanterm", env=env, timeout=timeout, codec_errors='replace', echo=False) # on many platforms, the termprog needs a short while to be ready... diff --git a/dist/tools/jlink/jlink.sh b/dist/tools/jlink/jlink.sh index 8783f529af..03edba36e3 100755 --- a/dist/tools/jlink/jlink.sh +++ b/dist/tools/jlink/jlink.sh @@ -68,7 +68,7 @@ _JLINK_IF=SWD _JLINK_SPEED=2000 # default terminal frontend _JLINK_TERMPROG=${RIOTTOOLS}/pyterm/pyterm -_JLINK_TERMFLAGS="-ts 19021" +_JLINK_TERMFLAGS="-ts 19021 ${PYTERMFLAGS}" # # a couple of tests for certain configuration options diff --git a/tests/README.md b/tests/README.md index e0e3b1f5f9..62d6644485 100644 --- a/tests/README.md +++ b/tests/README.md @@ -27,3 +27,18 @@ An automated way of knowing if a test is available is to execute the It executes without error if tests run by 'make test' are present. make test/available + + +Interaction through the uart +---------------------------- + +Tests implemented with `testrunner` use the `cleanterm` target that +provides an interaction without adding extra text output or input handling. +It can currently be expected to have unmodified line based interaction with the +board. + +The expected behavior is verified with the test in `tests/test_tools`. + +Tests cannot rely on having on all boards and terminal programs: +* unbuffered input +* allowing sending special characters like `ctrl+c/ctrl+d` diff --git a/tests/test_tools/main.c b/tests/test_tools/main.c index cb3927f243..1051930c1b 100644 --- a/tests/test_tools/main.c +++ b/tests/test_tools/main.c @@ -15,6 +15,8 @@ */ #include +#include +#include #include "shell_commands.h" #include "shell.h" @@ -64,10 +66,62 @@ static int cmd_shellping(int argc, char **argv) return 0; } +/** + * @brief Uppercase the first word + * + * First argument is read, converted to uppercase and printed with a newline. + * + * @param[in] argc Number of arguments + * @param[in] argv Array of arguments + * + * @return 0 on success + * + */ +static int cmd_toupper(int argc, char **argv) +{ + if (argc != 2) { + puts("Invalid number of argument"); + printf("Usage: %s \n", argv[0]); + return 1; + } + + size_t len = strlen(argv[1]); + for (size_t i = 0; i < len; i++) { + /* Cast to 'int' as llvm and some compilers complain about + * array subscript has type 'char' */ + char c = toupper((int)argv[1][i]); + putchar(c); + } + putchar('\n'); + + return 0; +} + +/** + * @brief getchar, read one character + * + * Read one character and print its hex value + * + * @param[in] argc Number of arguments + * @param[in] argv Array of arguments + * + * @return 0 + * + */ +static int cmd_getchar(int argc, char **argv) +{ + (void)argc; + (void)argv; + printf("%s 0x%02x\n", argv[0], getchar()); + return 0; +} + static const shell_command_t shell_commands[] = { { "shellping", "Just print 'shellpong'", cmd_shellping }, { "true", "do nothing, successfully", cmd_true }, + { "toupper", "uppercase first argument", cmd_toupper }, + { "getchar", "Get one character and print the hex value", cmd_getchar }, { NULL, NULL, NULL } }; diff --git a/tests/test_tools/tests/01-run.py b/tests/test_tools/tests/01-run.py index ced29379ed..ca278074a8 100755 --- a/tests/test_tools/tests/01-run.py +++ b/tests/test_tools/tests/01-run.py @@ -38,12 +38,31 @@ def _test_no_local_echo(child): assert res == 0, "There should have been a timeout and not match stdin" +def _test_sending_newline(child): + """Verify that a empty line can be send to the node. + + The local terminal must NOT repeat the previous command. + """ + child.sendline('getchar') + child.sendline('') # send only one newline character + child.expect_exact('getchar 0x0a\r\n') + + +def _test_clean_output(child): + """Verify that only what the node sends is received.""" + child.sendline('toupper lowercase') + retline = child.readline() + assert retline.strip() == 'LOWERCASE' + + def testfunc(child): """Run some tests to verify the board under test behaves correctly. It currently tests: * local echo + * getting some test output without other messages + * sending empty lines """ child.expect_exact("Running 'tests_tools' application") @@ -55,6 +74,12 @@ def testfunc(child): # The node should still answer after the previous one _shellping(child) + # Check that the output is clean without extra terminal output + _test_clean_output(child) + + # It is possible to send an empty newline + _test_sending_newline(child) + if __name__ == "__main__": sys.exit(run(testfunc))