diff --git a/examples/shell/BUILD.gn b/examples/shell/BUILD.gn index 95239268380250..16841e17a58fbe 100644 --- a/examples/shell/BUILD.gn +++ b/examples/shell/BUILD.gn @@ -23,6 +23,7 @@ executable("chip-shell") { "cmd_base64.cpp", "cmd_device.cpp", "cmd_misc.cpp", + "cmd_otcli.cpp", "main.cpp", ] diff --git a/examples/shell/README.md b/examples/shell/README.md index 30ff5783f579fe..696ab03dec36f4 100644 --- a/examples/shell/README.md +++ b/examples/shell/README.md @@ -33,6 +33,7 @@ Done - [echo](#echo-string) - [exit](#exit) - [help](#help) +- [otcli](README_OTCLI.md) - [rand](#rand) - [version](#version) @@ -49,6 +50,7 @@ Display a list of all top-level commands supported and a brief description. rand Random number utilities base64 Base64 encode / decode utilities device Device Layer commands + otcli Dispatch OpenThread CLI command exit Exit the shell application help List out all top level commands version Output the software version diff --git a/examples/shell/README_OTCLI.md b/examples/shell/README_OTCLI.md new file mode 100644 index 00000000000000..421a2a66d4dec1 --- /dev/null +++ b/examples/shell/README_OTCLI.md @@ -0,0 +1,50 @@ +# CHIP Shell - OpenThread CLI pass-through + +The CHIP Shell CLI can execute pass-through commands to the +[OpenThread cli](../../third_party/openthread/repo/src/cli/README.md) directly. + +## Setup + +### Embedded + +On embedded platforms, the otcli commands are available simply when OpenThread +support is enabled. + +### Linux + +On embedded Linux platforms, otcli commands require installation of some +OpenThread daemons: + +``` +# Start Border Router agent +sudo /usr/local/sbin/otbr-agent -d6 -v -I wpan0 spinel+hdlc+forkpty:///usr/local/bin/ot-rcp\?forkpty-arg=5 +``` + +If this command is not available, the follow instructions will build and install +it: + +``` +# Build OpenThread Interface (simulation used as example -- alternatively could be RCP hardware) +cd third_party/openthread/repo +./script/bootstrap +mkdir build && cd build +cmake .. -DCMAKE_INSTALL_PREFIX=/usr/local -DOT_PLATFORM=simulation -GNinja +ninja -j8 && sudo ninja install + +# Build Border Router functionality +cd third_party/ot-br-posix/repo +./script/bootstrap +mkdir build && cd build +cmake .. -DOTBR_DBUS=ON -GNinja -DCMAKE_INSTALL_PREFIX=/usr/local - +ninja -j8 && sudo ninja install + +# Start Border Router agent +sudo /usr/local/sbin/otbr-agent -d6 -v -I wpan0 spinel+hdlc+forkpty:///usr/local/bin/ot-rcp\?forkpty-arg=5 + +# In a new shell, at top-level of CHIP repo, test Thread device layer is operational +./bootstrap +mkdir build && cd build +../configure --with-device-layer=linux +make -C src/platform/tests TestThreadStackMgr +sudo ./src/platform/tests/TestThreadStackMgr +``` diff --git a/examples/shell/cmd_otcli.cpp b/examples/shell/cmd_otcli.cpp new file mode 100644 index 00000000000000..ca21db7b765f10 --- /dev/null +++ b/examples/shell/cmd_otcli.cpp @@ -0,0 +1,168 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#if CHIP_ENABLE_OPENTHREAD + +#include + +#include +#include +#include +#include +#include + +#if CHIP_TARGET_STYLE_EMBEDDED +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +using namespace chip; +using namespace chip::Shell; +using namespace chip::Platform; +using namespace chip::DeviceLayer; +using namespace chip::Logging; +using namespace chip::ArgParser; + +static chip::Shell::Shell sShellOtcliSubcommands; + +int cmd_otcli_help_iterator(shell_command_t * command, void * arg) +{ + streamer_printf(streamer_get(), " %-15s %s\n\r", command->cmd_name, command->cmd_help); + return 0; +} + +int cmd_otcli_help(int argc, char ** argv) +{ + sShellOtcliSubcommands.ForEachCommand(cmd_otcli_help_iterator, NULL); + return 0; +} + +#if CHIP_TARGET_STYLE_EMBEDDED + +int cmd_otcli_dispatch(int argc, char ** argv) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + +// From OT CLI internal lib, kMaxLineLength = 128 +#define kMaxLineLength 128 + char buff[kMaxLineLength] = { 0 }; + char * buff_ptr = buff; + int i = 0; + + VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + + for (i = 0; i < argc; i++) + { + size_t arg_len = strlen(argv[i]); + + /* Make sure that the next argument won't overflow the buffer */ + VerifyOrExit(buff_ptr + arg_len < buff + kMaxLineLength, error = CHIP_ERROR_BUFFER_TOO_SMALL); + + strncpy(buff_ptr, argv[i], arg_len); + buff_ptr += arg_len; + + /* Make sure that there is enough buffer for a space char */ + if (buff_ptr + sizeof(char) < buff + kMaxLineLength) + { + strncpy(buff_ptr, " ", sizeof(char)); + buff_ptr++; + } + } + buff_ptr = 0; + + otCliConsoleInputLine(buff, buff_ptr - buff); +exit: + return error; +} + +#elif CHIP_TARGET_STYLE_UNIX + +int cmd_otcli_dispatch(int argc, char ** argv) +{ + CHIP_ERROR error = CHIP_NO_ERROR; + + int pid, status; + uid_t euid = geteuid(); + char ctl_command[] = "/usr/local/sbin/ot-ctl"; + + // Must run as sudo. + if (euid != 0) + { + streamer_printf(streamer_get(), "Error otcli: requires running chip-shell as sudo\n\r"); + error = CHIP_ERROR_INCORRECT_STATE; + ExitNow(); + } + + VerifyOrExit(argc > 0, error = CHIP_ERROR_INVALID_ARGUMENT); + + // Fork and execute the command. + pid = fork(); + VerifyOrExit(pid != -1, error = CHIP_ERROR_INCORRECT_STATE); + + if (pid == 0) + { + // Child process to execute the command with provided arguments + --argv; // Restore access to entry [0] containing the command; + argv[0] = ctl_command; + execv(ctl_command, argv); + exit(0); + } + else + { + // Parent process to wait on child. + error = (waitpid(pid, &status, 0) == -1) ? CHIP_ERROR_INCORRECT_STATE : CHIP_NO_ERROR; + } + +exit: + return error; +} + +#endif // CHIP_TARGET_STYLE_UNIX + +static const shell_command_t cmds_otcli_root = { &cmd_otcli_dispatch, "otcli", "Dispatch OpenThread CLI command" }; + +#if CHIP_TARGET_STYLE_EMBEDDED +static int OnOtCliInitialized(const char * aBuf, uint16_t aBufLength, void * aContext) +{ + ChipLogProgress(chipTool, "%s", aBuf); + return 0; +} +#endif + +#endif // CHIP_ENABLE_OPENTHREAD + +void cmd_otcli_init(void) +{ +#if CHIP_ENABLE_OPENTHREAD +#if CHIP_TARGET_STYLE_EMBEDDED + otCliConsoleInit(GetOtInstance(), &OnOtCliInitialized, NULL); +#endif + + // Register the root otcli command with the top-level shell. + shell_register(&cmds_otcli_root, 1); +#endif // CHIP_ENABLE_OPENTHREAD +} diff --git a/examples/shell/main.cpp b/examples/shell/main.cpp index ddd6cc576a72c6..24704422bae096 100644 --- a/examples/shell/main.cpp +++ b/examples/shell/main.cpp @@ -35,12 +35,14 @@ using namespace chip::Shell; void cmd_misc_init(); void cmd_base64_init(); void cmd_device_init(); +void cmd_otcli_init(); int main(void) { cmd_misc_init(); cmd_base64_init(); cmd_device_init(); + cmd_otcli_init(); shell_task(NULL); } diff --git a/src/lib/shell/shell.h b/src/lib/shell/shell.h index 4e6d87da60f753..ec01bb4c91be7b 100644 --- a/src/lib/shell/shell.h +++ b/src/lib/shell/shell.h @@ -33,7 +33,7 @@ #endif // CHIP_SHELL_PROMPT #ifndef CHIP_SHELL_MAX_MODULES -#define CHIP_SHELL_MAX_MODULES 4 +#define CHIP_SHELL_MAX_MODULES 10 #endif // CHIP_SHELL_MAX_MODULES #ifndef CHIP_SHELL_MAX_LINE_SIZE diff --git a/src/platform/Linux/CHIPDevicePlatformConfig.h b/src/platform/Linux/CHIPDevicePlatformConfig.h index 56422c48d3cd01..3d02fe8138ba2c 100644 --- a/src/platform/Linux/CHIPDevicePlatformConfig.h +++ b/src/platform/Linux/CHIPDevicePlatformConfig.h @@ -30,7 +30,7 @@ #define CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP 0 #ifndef CHIP_DEVICE_CONFIG_ENABLE_THREAD -#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 0 +#define CHIP_DEVICE_CONFIG_ENABLE_THREAD 1 #endif #define CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE 0