diff --git a/config/esp32/components/chip/CMakeLists.txt b/config/esp32/components/chip/CMakeLists.txt index e1d77cc7b08e2f..2eebe4821adeea 100644 --- a/config/esp32/components/chip/CMakeLists.txt +++ b/config/esp32/components/chip/CMakeLists.txt @@ -29,8 +29,13 @@ if(NOT CHIP_ROOT) get_filename_component(CHIP_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. REALPATH) endif() +set(CHIP_REQURIE_COMPONENTS freertos lwip bt mdns mbedtls fatfs) +if (CONFIG_ENABLE_CHIP_SHELL) + list(APPEND CHIP_REQURIE_COMPONENTS console) +endif() + idf_component_register(SRCS chip.c chip.cpp - PRIV_REQUIRES freertos lwip bt mdns mbedtls fatfs) + PRIV_REQUIRES ${CHIP_REQURIE_COMPONENTS}) # Prepare initial args file (lacking compile flags) # This will be saved as args.gn.in @@ -57,6 +62,10 @@ if (NOT CONFIG_USE_MINIMAL_MDNS) chip_gn_arg_append("chip_mdns" "\"platform\"") endif() +if (CONFIG_ENABLE_CHIP_SHELL) + chip_gn_arg_append("chip_build_shell_lib" "true") +endif() + set(args_gn_input "${CMAKE_CURRENT_BINARY_DIR}/args.gn.in") file(GENERATE OUTPUT "${args_gn_input}" CONTENT "${chip_gn_args}") @@ -151,6 +160,11 @@ if(CONFIG_BT_ENABLED) list(APPEND chip_libraries $ -lbtdm_app) endif() +if (CONFIG_ENABLE_CHIP_SHELL) + idf_component_get_property(console_lib console COMPONENT_LIB) + list(APPEND chip_libraries $) +endif() + if(NOT CONFIG_USE_MINIMAL_MDNS) idf_component_get_property(mdns_lib mdns COMPONENT_LIB) list(APPEND chip_libraries $) diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 98811d3971d349..c4c92daf30cca4 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -91,6 +91,12 @@ menu "CHIP Core" The CHIP library is shipped with a minimal mDNS implementation, enable this config to use it rather than the mDNS library in IDF. + config ENABLE_CHIP_SHELL + bool "Use the CHIP shell library" + default n + help + Link the application against CHIP interactive shell. + # TODO: add log level selection endmenu # "General Options" diff --git a/examples/shell/esp32/.gitignore b/examples/shell/esp32/.gitignore new file mode 100644 index 00000000000000..234526a082ad26 --- /dev/null +++ b/examples/shell/esp32/.gitignore @@ -0,0 +1,5 @@ +*.vscode + +/build/ +/sdkconfig +/sdkconfig.old diff --git a/examples/shell/esp32/CMakeLists.txt b/examples/shell/esp32/CMakeLists.txt new file mode 100644 index 00000000000000..edc51b752ea69f --- /dev/null +++ b/examples/shell/esp32/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright (c) 2021 Project CHIP Authors +# All rights reserved. +# +# 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. + +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(EXTRA_COMPONENT_DIRS + ${CMAKE_CURRENT_LIST_DIR}/third_party/connectedhomeip/config/esp32/components +) + +project(chip-shell) +idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++14;-Os;-DLWIP_IPV6_SCOPES=0;-DCHIP_HAVE_CONFIG_H" APPEND) +idf_build_set_property(C_COMPILE_OPTIONS "-Os;-DLWIP_IPV6_SCOPES=0" APPEND) diff --git a/examples/shell/esp32/main/CMakeLists.txt b/examples/shell/esp32/main/CMakeLists.txt new file mode 100644 index 00000000000000..806b9952dc9171 --- /dev/null +++ b/examples/shell/esp32/main/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright (c) 2021 Project CHIP Authors +# All rights reserved. +# +# 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. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) + +set(CHIP_SHELL_DIR "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/shell") + + +idf_component_register(SRCS main.cpp + "${CHIP_SHELL_DIR}/shell_common/cmd_ping.cpp" + PRIV_INCLUDE_DIRS + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src" + "${CHIP_SHELL_DIR}/shell_common/include" + PRIV_REQUIRES chip nvs_flash bt console) diff --git a/examples/shell/esp32/main/main.cpp b/examples/shell/esp32/main/main.cpp new file mode 100644 index 00000000000000..882fc8d6c5eabf --- /dev/null +++ b/examples/shell/esp32/main/main.cpp @@ -0,0 +1,76 @@ +/* + * + * Copyright (c) 2021 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 "esp_console.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_netif.h" +#include "esp_system.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "linenoise/linenoise.h" +#include "nvs_flash.h" +#include "support/CHIPMem.h" + +#include +#include +#include +#include + +static void chip_shell_task(void * args) +{ + chip::Platform::MemoryInit(); + chip::DeviceLayer::PlatformMgr().InitChipStack(); + chip::DeviceLayer::PlatformMgr().StartEventLoopTask(); + int ret = chip::Shell::streamer_init(chip::Shell::streamer_get()); + assert(ret == 0); + cmd_ping_init(); + while (true) + { + const char * prompt = LOG_COLOR_I "> " LOG_RESET_COLOR; + char * line = linenoise(prompt); + if (line == NULL || strlen(line) == 0) + { + continue; + } + linenoiseHistoryAdd(line); + int ret; + esp_console_run(line, &ret); + if (ret) + { + char errorStr[160]; + bool errorStrFound = chip::FormatCHIPError(errorStr, sizeof(errorStr), ret); + if (!errorStrFound) + { + errorStr[0] = 0; + } + printf("Error: %s\n", errorStr); + } + else + { + printf("Done\n"); + } + + linenoiseFree(line); + } +} + +extern "C" void app_main(void) +{ + ESP_ERROR_CHECK(nvs_flash_init()); + xTaskCreate(&chip_shell_task, "chip_shell", 8192, NULL, 5, NULL); +} diff --git a/examples/shell/esp32/partitions.csv b/examples/shell/esp32/partitions.csv new file mode 100644 index 00000000000000..b338ff11a11589 --- /dev/null +++ b/examples/shell/esp32/partitions.csv @@ -0,0 +1,6 @@ +# Name, Type, SubType, Offset, Size, Flags +# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap +nvs, data, nvs, , 0x6000, +phy_init, data, phy, , 0x1000, +# Factory partition size about 1.9MB +factory, app, factory, , 1945K, diff --git a/examples/shell/esp32/sdkconfig.defaults b/examples/shell/esp32/sdkconfig.defaults new file mode 100644 index 00000000000000..c1ef813ca0a511 --- /dev/null +++ b/examples/shell/esp32/sdkconfig.defaults @@ -0,0 +1,40 @@ +# +# Copyright (c) 2021 Project CHIP Authors +# All rights reserved. +# +# 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. +# + + +# Default to 921600 baud when flashing and monitoring device +CONFIG_ESPTOOLPY_BAUD_921600B=y +CONFIG_ESPTOOLPY_BAUD=921600 +CONFIG_ESPTOOLPY_COMPRESSED=y +CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y +CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 + +#enable BT +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y + +#enable lwip ipv6 autoconfig +CONFIG_LWIP_IPV6_AUTOCONFIG=y + +# Use a custom partition table +CONFIG_PARTITION_TABLE_CUSTOM=y +CONFIG_PARTITION_TABLE_FILENAME="partitions.csv" + +# Vendor and product id +CONFIG_DEVICE_VENDOR_ID=0x235A +CONFIG_DEVICE_PRODUCT_ID=0x4541 +CONFIG_ENABLE_CHIP_SHELL=y diff --git a/examples/shell/esp32/third_party/connectedhomeip b/examples/shell/esp32/third_party/connectedhomeip new file mode 120000 index 00000000000000..11a54ed360106c --- /dev/null +++ b/examples/shell/esp32/third_party/connectedhomeip @@ -0,0 +1 @@ +../../../../ \ No newline at end of file diff --git a/examples/shell/shell_common/cmd_ping.cpp b/examples/shell/shell_common/cmd_ping.cpp index 471b37561f166f..0dfa705a932dc8 100644 --- a/examples/shell/shell_common/cmd_ping.cpp +++ b/examples/shell/shell_common/cmd_ping.cpp @@ -37,6 +37,7 @@ using namespace chip; using namespace Shell; using namespace Logging; +using chip::Inet::IPAddress; #if INET_CONFIG_ENABLE_TCP_ENDPOINT constexpr size_t kMaxTcpActiveConnectionCount = 4; @@ -143,7 +144,7 @@ TransportMgr Messaging::ExchangeManager gExchangeManager; SecureSessionMgr gSessionManager; -Inet::IPAddress gDestAddr; +IPAddress gDestAddr; bool EchoIntervalExpired(void) { @@ -259,7 +260,7 @@ void StartPinging(streamer_t * stream, char * destination) Transport::AdminPairingInfo * adminInfo = nullptr; uint32_t maxEchoCount = 0; - if (!Inet::IPAddress::FromString(destination, gDestAddr)) + if (!IPAddress::FromString(destination, gDestAddr)) { streamer_printf(stream, "Invalid Echo Server IP address: %s\n", destination); ExitNow(err = CHIP_ERROR_INVALID_ARGUMENT); diff --git a/src/lib/BUILD.gn b/src/lib/BUILD.gn index 2fc0cfd41cec9f..19c6a1678dd88a 100644 --- a/src/lib/BUILD.gn +++ b/src/lib/BUILD.gn @@ -15,6 +15,10 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/platform/device.gni") +declare_args() { + chip_build_shell_lib = false +} + config("includes") { include_dirs = [ "." ] } @@ -37,6 +41,10 @@ static_library("lib") { "${chip_root}/src/transport", ] + if (chip_build_shell_lib) { + public_deps += [ "${chip_root}/src/lib/shell" ] + } + if (chip_device_platform != "none") { public_deps += [ "${chip_root}/src/app/server" ] } diff --git a/src/lib/shell/BUILD.gn b/src/lib/shell/BUILD.gn index a2b15460de359f..8392dd3f0312e1 100644 --- a/src/lib/shell/BUILD.gn +++ b/src/lib/shell/BUILD.gn @@ -15,6 +15,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/src/lib/core/core.gni") +import("${chip_root}/src/platform/device.gni") static_library("shell") { output_name = "libCHIPShell" @@ -33,6 +34,10 @@ static_library("shell") { sources += [ "streamer_stdio.cpp" ] } + if (chip_device_platform == "esp32") { + sources += [ "streamer_esp32.cpp" ] + } + if (current_os == "zephyr") { sources += [ "streamer_zephyr.cpp" ] } diff --git a/src/lib/shell/shell_core.h b/src/lib/shell/shell_core.h index 3c1afa865f89aa..555ee57163cece 100644 --- a/src/lib/shell/shell_core.h +++ b/src/lib/shell/shell_core.h @@ -100,6 +100,12 @@ class Shell unsigned _commandSetSize[CHIP_SHELL_MAX_MODULES]; unsigned _commandSetCount; +public: + Shell() {} + + /** Return the root singleton for the Shell command hierarchy. */ + static Shell & Root() { return theShellRoot; } + /** * Registers a set of defaults commands (help) for all Shell and sub-Shell instances. * @@ -110,12 +116,6 @@ class Shell */ void RegisterDefaultCommands(); -public: - Shell() {} - - /** Return the root singleton for the Shell command hierarchy. */ - static Shell & Root() { return theShellRoot; } - /** * Execution callback for a shell command. * diff --git a/src/lib/shell/streamer_esp32.cpp b/src/lib/shell/streamer_esp32.cpp new file mode 100644 index 00000000000000..2f250b16262c3e --- /dev/null +++ b/src/lib/shell/streamer_esp32.cpp @@ -0,0 +1,101 @@ +/* + * + * Copyright (c) 2021 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 "shell_core.h" +#include "streamer.h" + +#include "driver/uart.h" +#include "esp_console.h" +#include "esp_vfs_dev.h" +#include "linenoise/linenoise.h" +#include +#include +#include +#include + +namespace chip { +namespace Shell { + +static int chip_command_handler(int argc, char ** argv) +{ + if (argc > 0) + { + return chip::Shell::Shell::Root().ExecCommand(argc - 1, argv + 1); + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } +} + +int streamer_esp32_init(streamer_t * streamer) +{ + fflush(stdout); + fsync(fileno(stdout)); + setvbuf(stdin, NULL, _IONBF, 0); + esp_vfs_dev_uart_port_set_rx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CR); + esp_vfs_dev_uart_port_set_tx_line_endings(CONFIG_ESP_CONSOLE_UART_NUM, ESP_LINE_ENDINGS_CRLF); + + ESP_ERROR_CHECK(uart_driver_install(UART_NUM_0, 256, 0, 0, NULL, 0)); + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .rx_flow_ctrl_thresh = 0, + .source_clk = UART_SCLK_APB, + }; + ESP_ERROR_CHECK(uart_param_config(UART_NUM_0, &uart_config)); + esp_vfs_dev_uart_use_driver(0); + esp_console_config_t console_config = { + .max_cmdline_length = 256, + .max_cmdline_args = 8, + }; + ESP_ERROR_CHECK(esp_console_init(&console_config)); + linenoiseSetMultiLine(1); + linenoiseHistorySetMaxLen(100); + + esp_console_cmd_t command = { .command = "chip", .help = "CHIP utilities", .func = chip_command_handler }; + ESP_ERROR_CHECK(esp_console_cmd_register(&command)); + chip::Shell::Shell::Root().RegisterDefaultCommands(); + return 0; +} + +ssize_t streamer_esp32_read(streamer_t * streamer, char * buf, size_t len) +{ + return 0; +} + +ssize_t streamer_esp32_write(streamer_t * streamer, const char * buf, size_t len) +{ + return fprintf(stdout, buf, len); +} + +static streamer_t streamer_stdio = { + .init_cb = streamer_esp32_init, + .read_cb = streamer_esp32_read, + .write_cb = streamer_esp32_write, +}; + +streamer_t * streamer_get() +{ + return &streamer_stdio; +} + +} // namespace Shell +} // namespace chip