diff --git a/components/esp_matter_console/CMakeLists.txt b/components/esp_matter_console/CMakeLists.txt new file mode 100644 index 000000000..39cc81967 --- /dev/null +++ b/components/esp_matter_console/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS esp_matter_console.cpp + INCLUDE_DIRS . + PRIV_REQUIRES chip esp32_mbedtls) diff --git a/components/esp_matter_console/Kconfig b/components/esp_matter_console/Kconfig new file mode 100644 index 000000000..2ddebb4c4 --- /dev/null +++ b/components/esp_matter_console/Kconfig @@ -0,0 +1,15 @@ +menu "ESP Matter Console" + + config ESP_MATTER_CONSOLE_TASK_STACK + int "Task stack size" + default 2048 + help + Stack size of the console task. + + config ESP_MATTER_CONSOLE_MAX_COMMANDS + int "Max commands supported" + default 10 + help + Maximum number of commands that can be added for the 'chip esp ' command. + +endmenu diff --git a/components/esp_matter_console/esp_matter_console.cpp b/components/esp_matter_console/esp_matter_console.cpp new file mode 100644 index 000000000..e50f3137f --- /dev/null +++ b/components/esp_matter_console/esp_matter_console.cpp @@ -0,0 +1,127 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// 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 +#include +#include + +#include +#include + +#define MAX_CONSOLE_COMMANDS CONFIG_ESP_MATTER_CONSOLE_MAX_COMMANDS + +static const char *TAG = "esp_matter_console"; +static esp_matter_console_command_t commands[MAX_CONSOLE_COMMANDS]; +static int total_added_commands = 0; + +esp_err_t esp_matter_console_add_command(esp_matter_console_command_t *command) +{ + if (total_added_commands + 1 > MAX_CONSOLE_COMMANDS) { + ESP_LOGE(TAG, "Could not add command. Increase the max limit to add more."); + return ESP_FAIL; + } + /* Since the strings in esp_matter_console_command_t are constants, this will work */ + commands[total_added_commands] = *command; + total_added_commands++; + return ESP_OK; +} + +static void esp_matter_console_print_help() +{ + ESP_LOGI(TAG, "Usage: chip esp "); + ESP_LOGI(TAG, "Sub commands:"); + for (int i = 0; i < total_added_commands; i++) { + ESP_LOGI(TAG, "\t%s: %s", commands[i].name, commands[i].description); + } +} + +static esp_err_t esp_matter_console_help_handler(int argc, char** argv) +{ + esp_matter_console_print_help(); + return ESP_OK; +} + +static esp_err_t esp_matter_console_register_default_commands() +{ + esp_matter_console_command_t command= { + .name = "help", + .description = "Print help", + .handler = esp_matter_console_help_handler, + }; + return esp_matter_console_add_command(&command); +} + +static CHIP_ERROR esp_matter_console_common_handler(int argc, char** argv) +{ + /* This common handler is added to avoid adding `CHIP_ERROR` and its component requirements in other esp-matter components */ + if (argc <= 0) { + esp_matter_console_print_help(); + return CHIP_NO_ERROR; + } + for (int i = 0; i < total_added_commands; i++) { + if (strncmp(argv[0], commands[i].name, strlen(commands[i].name) + 1) == 0) { + if (commands[i].handler == NULL) { + ESP_LOGW(TAG, "No handler set for the command: %s", argv[0]); + return CHIP_NO_ERROR; + } + if (commands[i].handler(argc - 1, &argv[1]) == ESP_OK) { /* Removing the first argument from argv */ + return CHIP_NO_ERROR; + } + /* The command handler returned error */ + return CHIP_ERROR_INVALID_ARGUMENT; + } + } + ESP_LOGE(TAG, "Could not find the command: %s. Try the help command for more details: chip esp help", argv[0]); + return CHIP_ERROR_INVALID_ARGUMENT; +} + +static esp_err_t esp_matter_console_register_common_shell_handler() +{ + static chip::Shell::shell_command_t cmds[] = { + { + .cmd_func = esp_matter_console_common_handler, + .cmd_name = "esp", + .cmd_help = "Usage: chip esp ", + }, + }; + int cmds_num = sizeof(cmds) / sizeof(chip::Shell::shell_command_t); + chip::Shell::Engine::Root().RegisterCommands(cmds, cmds_num); + return ESP_OK; +} + +static void ChipShellTask(void *args) +{ + chip::Shell::Engine::Root().RunMainLoop(); +} + +esp_err_t esp_matter_console_init() +{ + esp_err_t err = ESP_OK; + err = esp_matter_console_register_default_commands(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Couldn't register default console commands"); + } + err = esp_matter_console_register_common_shell_handler(); + if (err != ESP_OK) { + ESP_LOGE(TAG, "Couldn't register common handler"); + return err; + } + + if (xTaskCreate(&ChipShellTask, "console", CONFIG_ESP_MATTER_CONSOLE_TASK_STACK, NULL, 5, NULL) != pdPASS) { + ESP_LOGE(TAG, "Couldn't create console task"); + err = ESP_FAIL; + } + return err; +} diff --git a/components/esp_matter_console/esp_matter_console.h b/components/esp_matter_console/esp_matter_console.h new file mode 100644 index 000000000..c38fec90b --- /dev/null +++ b/components/esp_matter_console/esp_matter_console.h @@ -0,0 +1,66 @@ +// Copyright 2021 Espressif Systems (Shanghai) PTE LTD +// +// 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. + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** Callback for console commands + * + * This callback handler will be called when console command is triggered. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +typedef esp_err_t (*esp_matter_console_handler_t)(int argc, char** argv); + +/** ESP Matter Console Command */ +typedef struct { + /** Command Name */ + const char *name; + /** Command Description/Help */ + const char *description; + /** Command Handler */ + esp_matter_console_handler_t handler; +} esp_matter_console_command_t; + +/** Initialize Console + * + * This API internally initializes the matter shell. + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t esp_matter_console_init(void); + +/** Add Console Command + * + * Add a new console command. + * This can be done before calling `esp_matter_console_init()` but the commands will not work until initialized. + * + * @param[in] command Pointer to command struct + * + * @return ESP_OK on success. + * @return error in case of failure. + */ +esp_err_t esp_matter_console_add_command(esp_matter_console_command_t *command); + +#ifdef __cplusplus +} +#endif diff --git a/examples/common/app_driver/CMakeLists.txt b/examples/common/app_driver/CMakeLists.txt index dd3c2a77d..efc30a06b 100644 --- a/examples/common/app_driver/CMakeLists.txt +++ b/examples/common/app_driver/CMakeLists.txt @@ -1,4 +1,4 @@ include($ENV{ESP_MATTER_DEVICE_PATH}/esp_matter_device.cmake) idf_component_register(SRCS app_driver.c INCLUDE_DIRS . - PRIV_REQUIRES device ${used_driver} esp_matter) + PRIV_REQUIRES device ${used_driver} esp_matter esp_matter_console) diff --git a/examples/common/app_driver/app_driver.c b/examples/common/app_driver/app_driver.c index 5a2cc4366..75fe08dd2 100644 --- a/examples/common/app_driver/app_driver.c +++ b/examples/common/app_driver/app_driver.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,7 @@ static void app_driver_print_attr_val(const char *endpoint, const char *attribut } } -int app_driver_cli_handler(int argc, char** argv) +static esp_err_t app_driver_console_handler(int argc, char** argv) { if (argc == 4 && strncmp(argv[0], "set", sizeof("set")) == 0) { char *endpoint_name = argv[1]; @@ -74,6 +75,16 @@ int app_driver_cli_handler(int argc, char** argv) return 0; } +static void app_driver_register_commands() +{ + esp_matter_console_command_t command= { + .name = "driver", + .description = "This can be used to simulate on-device control. Usage: chip esp driver [value]. Example1: chip esp driver set Light Power 1. Example2: chip esp driver get Light Power.", + .handler = app_driver_console_handler, + }; + esp_matter_console_add_command(&command); +} + static esp_matter_attr_val_t app_driver_attribute_get(const char *endpoint, const char *attribute) { if (strncmp(endpoint, ESP_MATTER_ENDPOINT_LIGHT, sizeof(ESP_MATTER_ENDPOINT_LIGHT)) == 0) { @@ -135,5 +146,6 @@ esp_err_t app_driver_init() { device_init(); esp_matter_attribute_callback_add(APP_DRIVER_NAME, app_driver_attribute_update, NULL); + app_driver_register_commands(); return ESP_OK; } diff --git a/examples/common/app_driver/app_driver.h b/examples/common/app_driver/app_driver.h index 37f12dd27..1f6d4fe33 100644 --- a/examples/common/app_driver/app_driver.h +++ b/examples/common/app_driver/app_driver.h @@ -24,15 +24,6 @@ extern "C" */ esp_err_t app_driver_init(void); -/** CLI handler for driver - * - * This API can be added as the callback for shell commands - * - * @return 0 on success. - * @return -1 in case of failure. - */ -int app_driver_cli_handler(int argc, char** argv); - #ifdef __cplusplus } #endif diff --git a/examples/light/main/CMakeLists.txt b/examples/light/main/CMakeLists.txt index 630ab12b3..b1fd30cc2 100644 --- a/examples/light/main/CMakeLists.txt +++ b/examples/light/main/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" "${MATTER_SDK_PATH}/src") -set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver app_qrcode) +set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter esp_matter_console app_driver app_qrcode) if ("${IDF_TARGET}" STREQUAL "esp32h2") list(APPEND PRIV_REQUIRES_LIST openthread mynewt_nimble) diff --git a/examples/light/main/app_main.cpp b/examples/light/main/app_main.cpp index f5af502f5..82e63fabf 100644 --- a/examples/light/main/app_main.cpp +++ b/examples/light/main/app_main.cpp @@ -6,10 +6,9 @@ CONDITIONS OF ANY KIND, either express or implied. */ -#include - #include "esp_matter.h" #include "esp_matter_standard.h" +#include "esp_matter_console.h" #include "app_driver.h" #include "app_qrcode.h" #include "app_matter.h" @@ -25,42 +24,6 @@ #define APP_MAIN_NAME "Main" static const char *TAG = "app_main"; -#if CONFIG_ENABLE_CHIP_SHELL -void ChipShellTask(void *args) -{ - chip::Shell::Engine::Root().RunMainLoop(); -} - -CHIP_ERROR app_cli_common_handler(int argc, char** argv) -{ - /* This common handler is added to avoid adding `CHIP_ERROR` and its component requirements in other esp-matter components */ - if (argc <= 0) { - ESP_LOGE(TAG, "Incorrect arguments"); - return CHIP_ERROR_INVALID_ARGUMENT; - } - if (strncmp(argv[0], "driver", sizeof("driver")) == 0) { - app_driver_cli_handler(argc - 1, &argv[1]); - } else { - ESP_LOGE(TAG, "Incorrect arguments"); - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; -} - -static void app_cli_register_commands() -{ - static chip::Shell::shell_command_t cmds[] = { - { - .cmd_func = &app_cli_common_handler, - .cmd_name = "esp", - .cmd_help = "driver: This can be used to simulate on-device control. Usage: chip esp driver [value]. Example1: chip esp driver set Light Power 1. Example2: chip esp driver get Light Power.", - }, - }; - int cmds_num = sizeof(cmds) / sizeof(chip::Shell::shell_command_t); - chip::Shell::Engine::Root().RegisterCommands(cmds, cmds_num); -} -#endif // CONFIG_ENABLE_CHIP_SHELL - static esp_err_t app_main_attribute_update(const char *endpoint, const char *attribute, esp_matter_attr_val_t val, void *priv_data) { /* Just adding this callback to notify the application */ @@ -113,7 +76,6 @@ extern "C" void app_main() esp_matter_attribute_notify(APP_MAIN_NAME, ESP_MATTER_ENDPOINT_LIGHT, ESP_MATTER_ATTR_SATURATION, esp_matter_int(DEFAULT_SATURATION)); #if CONFIG_ENABLE_CHIP_SHELL - xTaskCreate(&ChipShellTask, "chip_shell", 2048, NULL, 5, NULL); - app_cli_register_commands(); + esp_matter_console_init(); #endif } diff --git a/examples/rainmaker_light/main/CMakeLists.txt b/examples/rainmaker_light/main/CMakeLists.txt index 23f316a49..de1b978fd 100644 --- a/examples/rainmaker_light/main/CMakeLists.txt +++ b/examples/rainmaker_light/main/CMakeLists.txt @@ -18,7 +18,7 @@ set(SRC_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" set(PRIV_INCLUDE_DIRS_LIST "${CMAKE_CURRENT_LIST_DIR}" "${MATTER_SDK_PATH}/src") -set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter app_driver app_qrcode esp_rainmaker) +set(PRIV_REQUIRES_LIST chip bt esp32_mbedtls esp_matter esp_matter_console app_driver app_qrcode esp_rainmaker) idf_component_register(SRC_DIRS ${SRC_DIRS_LIST} PRIV_INCLUDE_DIRS ${PRIV_INCLUDE_DIRS_LIST} diff --git a/examples/rainmaker_light/main/app_main.cpp b/examples/rainmaker_light/main/app_main.cpp index 81c54d254..4e110a86e 100644 --- a/examples/rainmaker_light/main/app_main.cpp +++ b/examples/rainmaker_light/main/app_main.cpp @@ -6,10 +6,9 @@ CONDITIONS OF ANY KIND, either express or implied. */ -#include - #include "esp_matter.h" #include "esp_matter_standard.h" +#include "esp_matter_console.h" #include "app_driver.h" #include "app_qrcode.h" #include "app_matter.h" @@ -26,44 +25,6 @@ #define APP_MAIN_NAME "Main" static const char *TAG = "app_main"; -#if CONFIG_ENABLE_CHIP_SHELL -void ChipShellTask(void *args) -{ - chip::Shell::Engine::Root().RunMainLoop(); -} - -CHIP_ERROR app_cli_common_handler(int argc, char** argv) -{ - /* This common handler is added to avoid adding `CHIP_ERROR` and its component requirements in other esp-matter components */ - if (argc <= 0) { - ESP_LOGE(TAG, "Incorrect arguments"); - return CHIP_ERROR_INVALID_ARGUMENT; - } - if (strncmp(argv[0], "driver", sizeof("driver")) == 0) { - app_driver_cli_handler(argc - 1, &argv[1]); - } else if (strncmp(argv[0], "rainmaker", sizeof("rainmaker")) == 0) { - app_rainmaker_cli_handler(argc - 1, &argv[1]); - } else { - ESP_LOGE(TAG, "Incorrect arguments"); - return CHIP_ERROR_INVALID_ARGUMENT; - } - return CHIP_NO_ERROR; -} - -static void app_cli_register_commands() -{ - static chip::Shell::shell_command_t cmds[] = { - { - .cmd_func = &app_cli_common_handler, - .cmd_name = "esp", - .cmd_help = "command1: driver: This can be used to simulate on-device control. Usage: chip esp driver [value]. Example1: chip esp driver set Light Power 1. Example2: chip esp driver get Light Power. command2: rainmaker: Initiate ESP RainMaker User-Node mapping from the node. Usage: chip esp rainmaker add-user ", - }, - }; - int cmds_num = sizeof(cmds) / sizeof(chip::Shell::shell_command_t); - chip::Shell::Engine::Root().RegisterCommands(cmds, cmds_num); -} -#endif // CONFIG_ENABLE_CHIP_SHELL - static esp_err_t app_main_attribute_update(const char *endpoint, const char *attribute, esp_matter_attr_val_t val, void *priv_data) { /* Just adding this callback to notify the application */ @@ -119,7 +80,6 @@ extern "C" void app_main() esp_matter_attribute_notify(APP_MAIN_NAME, ESP_MATTER_ENDPOINT_LIGHT, ESP_MATTER_ATTR_SATURATION, esp_matter_int(DEFAULT_SATURATION)); #if CONFIG_ENABLE_CHIP_SHELL - xTaskCreate(&ChipShellTask, "chip_shell", 2048, NULL, 5, NULL); - app_cli_register_commands(); + esp_matter_console_init(); #endif } diff --git a/examples/rainmaker_light/main/app_rainmaker.c b/examples/rainmaker_light/main/app_rainmaker.c index b366b0ffd..4cd6f2eac 100644 --- a/examples/rainmaker_light/main/app_rainmaker.c +++ b/examples/rainmaker_light/main/app_rainmaker.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "app_constants.h" @@ -30,7 +31,7 @@ static const char *TAG = "app_rainmaker"; esp_rmaker_device_t *light_device; -int app_rainmaker_cli_handler(int argc, char** argv) +static esp_err_t app_rainmaker_console_handler(int argc, char** argv) { if (argc == 3 && strncmp(argv[0], "add-user", sizeof("add-user")) == 0) { printf("%s: Starting user-node mapping\n", TAG); @@ -44,6 +45,16 @@ int app_rainmaker_cli_handler(int argc, char** argv) return 0; } +static void app_rainmaker_register_commands() +{ + esp_matter_console_command_t command= { + .name = "rainmaker", + .description = "Initiate ESP RainMaker User-Node mapping from the node. Usage: chip esp rainmaker add-user ", + .handler = app_rainmaker_console_handler, + }; + esp_matter_console_add_command(&command); +} + static esp_rmaker_param_val_t esp_rmaker_get_rmaker_val(esp_matter_attr_val_t val) { if (val.type == ESP_MATTER_VAL_TYPE_BOOLEAN) { @@ -167,5 +178,6 @@ esp_err_t app_rainmaker_init() esp_rmaker_start(); esp_matter_attribute_callback_add(APP_RAINMAKER_NAME, app_rainmaker_attribute_update, NULL); + app_rainmaker_register_commands(); return ESP_OK; } diff --git a/examples/rainmaker_light/main/app_rainmaker.h b/examples/rainmaker_light/main/app_rainmaker.h index 5493d71a1..d96746cb0 100644 --- a/examples/rainmaker_light/main/app_rainmaker.h +++ b/examples/rainmaker_light/main/app_rainmaker.h @@ -24,15 +24,6 @@ extern "C" */ esp_err_t app_rainmaker_init(void); -/** CLI handler for RainMaker - * - * This API can be added as the callback for shell commands - * - * @return 0 on success. - * @return -1 in case of failure. - */ -int app_rainmaker_cli_handler(int argc, char** argv); - #ifdef __cplusplus } #endif