From 3c24546ec76c371d3f6f1461905a219045a4bf1d Mon Sep 17 00:00:00 2001 From: Sun Lu Xin Date: Wed, 17 Jul 2024 20:26:38 +0800 Subject: [PATCH] update how_to_add_user-defined_AT_commands --- .../How_to_add_user-defined_AT_commands.rst | 322 ++++++++++++++---- .../How_to_add_user-defined_AT_commands.rst | 320 +++++++++++++---- 2 files changed, 503 insertions(+), 139 deletions(-) diff --git a/docs/en/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst b/docs/en/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst index ed011cb2e..dbd534a58 100644 --- a/docs/en/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst +++ b/docs/en/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst @@ -1,20 +1,29 @@ -How to add user-defined AT commands -=================================== +.. _user-defined_at_cmd: -:link_to_translation:`zh_CN:[中文]` +************************************ +How to Add User-defined AT Commands +************************************ -This document details how to add a user-defined AT command based on the `ESP-AT `_ project. It uses the ``AT+TEST`` command as an example to show the sample code for each step. +:link_to_translation:`en:[English]` -Customizing a basic and well-functioned command requires at least the two steps below: +This document provides a detailed introduction on how to add user-defined AT commands. In fact, the ESP-AT project already provides the `at_custom_cmd example `_, and the following text mainly focuses on this example, using the ``AT+TEST`` command to demonstrate each step with example code. + +Before customizing AT commands, please understand: + +- :ref:`at-custom_cmd` + +To define a basic, functional command, at least the following four steps are required: - :ref:`define-at-commands` - :ref:`register-at-commands` +- :ref:`update-cmakelist` +- :ref:`set-component-env-and-compile` -This step checks how the newly defined command works out. +After completing the above steps, let's look at the operation and response of the new command (AT+TEST): -- :ref:`user-define-at-commands-give-it-a-try` +- :ref:`user-at-cmd-give-it-a-try` -The remaining steps are for relatively complex AT commands and are optional depending on your needs. +The following steps are suitable for customizing relatively complex commands and can be selected according to your needs: - :ref:`define-return-values` - :ref:`access-command-parameters` @@ -22,14 +31,154 @@ The remaining steps are for relatively complex AT commands and are optional depe - :ref:`block-command-execution` - :ref:`access-input-data-from-at-command-port` -The source code of AT command set is not open-source, and is provided in the form of :component:`library file `. It is also the basis to parse user-defined AT commands. +The source code for the AT command set is not open source and is presented in the form of :component:`library files `, which is also the basis for parsing custom AT commands. + +.. _at-custom_cmd: + +:ref:`at_custom_cmd component introduction ` +================================================================== + +Introduction to the at_custom_cmd component +-------------------------------------------- + +You can first read the `README `_ of the at_custom_cmd component to get a brief understanding of it. + +For concepts and related knowledge about components, refer to the `ESP-IDF Build System documentation `_. + +.. _at_custom_cmd_component: + +at_custom_cmd Component Directory Structure +-------------------------------------------- + +The directory structure of the at_custom_cmd component is as follows: + +.. code-block:: none + + - at_custom_cmd/ + - custom/ - at_custom_cmd.c + - include/ - at_custom_cmd.h + - CMakeLists.txt + - README.md + +This example project "at_custom_cmd" includes the following components: + + - The .c files under the at_custom_cmd/custom/ directory are used to store the source code for :ref:`custom AT commands `. Besides the at_custom_cmd.c file, you can create additional .c files in this directory. + - The .h files under the at_custom_cmd/include/ directory are used to store the header files for custom AT commands. Besides the at_custom_cmd.h file, you can create additional .h files in this directory. + - The CMakeLists.txt file defines variables to control the build process of this component and its integration with the ESP-AT project. For more detailed information, refer to `Component CMakeLists File `_. + - The README.md file is used to describe this component. + +at_custom_cmd Component CMakeLists.txt File +-------------------------------------------- + +- Add the path of the `.c` files to the `srcs` variable: + + .. code-block:: none + + file(GLOB_RECURSE srcs *.c) + +- Set the include directory for the header file (at_custom_cmd.h file): + + .. code-block:: none + + set(includes "include") + +.. _add-component_dependencies: + +- Add component dependencies and add the component to the build system: + + - Add the required component dependencies in the CMakeLists.txt file as needed for the :ref:`custom AT command code `. Use idf_component_register to add the component to the build system. For more details, refer to `idf_component_register `_. + + .. code-block:: none + + set(require_components at freertos nvs_flash) + + idf_component_register( + SRCS ${srcs} + INCLUDE_DIRS ${includes} + REQUIRES ${require_components}) + + .. note:: + If you use other components in the :ref:`custom AT command code `, you need to add these component dependencies in the `esp-at/examples/at_custom_cmd/CMakeLists.txt` file. For example, if you also use the LwIP component, your setting should be as follows: + + .. code-block:: none + + set(require_components at freertos nvs_flash lwip) + +.. _add-link_options: + +- Link the name of your :ref:`custom registered AT command function ` as a link option to ${COMPONENT_LIB} to ensure that the program can find this custom registered AT command function correctly at runtime. The following link example uses the `esp_at_custom_cmd_register` registration of AT command function in the at_custom_cmd example: + + .. code-block:: none + + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_at_custom_cmd_register") + + .. note:: + If the name of your :ref:`custom registered AT command function ` is ``esp_at_custom_cmd_register_1``, you need to add the following code: + + .. code-block:: none + + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_at_custom_cmd_register_1") + +.. _component-usage: + +Usage of the at_custom_cmd component +------------------------------------- + +1. Add your custom AT command code to the `at_custom_cmd/custom/**/*.c` and `at_custom_cmd/custom/**/*.h` files (you can also create new source and header files if needed, ensuring that the AT command registration function is handled in the .c files). +2. If your code uses other components, you may need to add more component dependencies in the `at_custom_cmd/CMakeLists.txt` file. + +.. _compinents-3: + +3. Set the `at_custom_cmd` component environment variable so that the `ESP-AT` project can find this component during compilation. Choose one of the following two methods: + +.. _set-path_1: + +- **Method 1:** Set the `AT_CUSTOM_COMPONENTS` environment variable directly in the command line + + .. note:: + - You need to replace (path_of_at_custom_cmd) with the actual absolute path of the `at_custom_cmd` directory. + - You can specify multiple components. For example: `export AT_CUSTOM_COMPONENTS="~/prefix/my_path1 ~/prefix/my_path2"`. + + - Linux or macOS + + .. code-block:: none + + export AT_CUSTOM_COMPONENTS=(path_of_at_custom_cmd) + + - Windows + + .. code-block:: none + + set AT_CUSTOM_COMPONENTS=(path_of_at_custom_cmd) + +.. _set-path_2: + +- **Method 2:** Directly add the code to set the AT_CUSTOM_COMPONENTS environment variable in the `esp-at/build.py` file's ``setup_env_variables()`` function. The code example is as follows: + + .. code-block:: none + + # set AT_CUSTOM_COMPONENTS + at_custom_cmd_path=os.path.join(os.getcwd(), 'examples/at_custom_cmd') + os.environ['AT_CUSTOM_COMPONENTS']=at_custom_cmd_path + +.. _compile-at: + +4. Choose one of the following two methods to recompile the AT firmware + + - **Method 1:** Recompile the AT firmware according to :doc:`local compilation guide for the ESP-AT project <../Compile_and_Develop/How_to_clone_project_and_compile_it>`. + - **Method 2:** Recompile the AT firmware according to :doc:`web compilation guide for the ESP-AT project <../Compile_and_Develop/How_to_build_project_with_web_page>` (if you choose this method to compile the AT firmware, the third step :ref:`component-usage` must use :ref:`Method 2 `). + +.. _step-define_at_command: + +:ref:`Custom AT Command Steps ` +==================================================== .. _define-at-commands: -Define AT Commands ------------------- +:ref:`Custom AT Commands ` +------------------------------------------------ -Before defining any AT command, you should first decide on the name and type of the command. +Before customizing AT commands, please decide on the name and type of the AT command. **Command naming rules:** @@ -46,12 +195,10 @@ Test Command: .. code-block:: c - uint8_t at_test_cmd_test(uint8_t *cmd_name) + static uint8_t at_test_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is test cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "test command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; @@ -61,12 +208,10 @@ Query Command: .. code-block:: c - uint8_t at_query_cmd_test(uint8_t *cmd_name) + static uint8_t at_query_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is query cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "query command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; @@ -78,31 +223,33 @@ Set Command: .. code-block:: c - uint8_t at_setup_cmd_test(uint8_t para_num) + static uint8_t at_setup_cmd_test(uint8_t para_num) { - int32_t para_int_1 = 0; - uint8_t *para_str_2 = NULL; - uint8_t num_index = 0; - uint8_t buffer[64] = {0}; + uint8_t index = 0; - if (esp_at_get_para_as_digit(num_index++, ¶_int_1) != ESP_AT_PARA_PARSE_RESULT_OK) { + // get first parameter, and parse it into a digit + int32_t digit = 0; + if (esp_at_get_para_as_digit(index++, &digit) != ESP_AT_PARA_PARSE_RESULT_OK) { return ESP_AT_RESULT_CODE_ERROR; } - if (esp_at_get_para_as_str(num_index++, ¶_str_2) != ESP_AT_PARA_PARSE_RESULT_OK) { + // get second parameter, and parse it into a string + uint8_t *str = NULL; + if (esp_at_get_para_as_str(index++, &str) != ESP_AT_PARA_PARSE_RESULT_OK) { return ESP_AT_RESULT_CODE_ERROR; } - snprintf((char *)buffer, 64, "this cmd is setup cmd and cmd num is: %u\r\n", para_num); - esp_at_port_write_data(buffer, strlen((char *)buffer)); - - memset(buffer, 0, 64); - snprintf((char *)buffer, 64, "first parameter is: %d\r\n", para_int_1); - esp_at_port_write_data(buffer, strlen((char *)buffer)); + // allocate a buffer and construct the data, then send the data to mcu via interface (uart/spi/sdio/socket) + uint8_t *buffer = (uint8_t *)malloc(512); + if (!buffer) { + return ESP_AT_RESULT_CODE_ERROR; + } + int len = snprintf((char *)buffer, 512, "setup command: is executed\r\n", + esp_at_get_current_cmd_name(), digit, str); + esp_at_port_write_data(buffer, len); - memset(buffer, 0, 64); - snprintf((char *)buffer, 64, "second parameter is: %s\r\n", para_str_2); - esp_at_port_write_data(buffer, strlen((char *)buffer)); + // remember to free the buffer + free(buffer); return ESP_AT_RESULT_CODE_OK; } @@ -111,12 +258,10 @@ Execute Command: .. code-block:: c - uint8_t at_exe_cmd_test(uint8_t *cmd_name) + static uint8_t at_exe_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is execute cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "execute command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; @@ -124,37 +269,71 @@ Execute Command: Finally, call :cpp:type:`esp_at_cmd_struct` to define the name and type(s) that your AT command supports. The sample code below defined the name ``+TEST`` (omitting ``AT``) and all the four types. +.. note:: + If you do not want to define a particular type, set it to ``NULL``. + .. code-block:: c - static esp_at_cmd_struct at_custom_cmd[] = { + static const esp_at_cmd_struct at_custom_cmd[] = { {"+TEST", at_test_cmd_test, at_query_cmd_test, at_setup_cmd_test, at_exe_cmd_test}, + /** + * @brief You can define your own AT commands here. + */ }; -If you do not want to define a particular type, set it to ``NULL``. - .. _register-at-commands: -Register AT Commands --------------------- +:ref:`Registering AT Command Functions and Initialization ` +---------------------------------------------------------------------------------- -Call API :cpp:func:`esp_at_custom_cmd_array_regist` to register your AT command. Below is the sample code to register ``AT+TEST``: +In the at_custom_cmd example, the esp_at_custom_cmd_register function calls the API :cpp:func:`esp_at_custom_cmd_array_regist` to register the AT command. Below is an example code for registering ``AT+TEST``. .. code-block:: c - esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(at_custom_cmd[0])); + bool esp_at_custom_cmd_register(void) + { + return esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(esp_at_cmd_struct)); + } + +Finally, call the API `ESP_AT_CMD_SET_INIT_FN `_ to initialize your implemented registration AT command function `esp_at_custom_cmd_register`. Below is an example code for initializing the registration of the `AT+TEST` command. + +.. code-block:: c + + ESP_AT_CMD_SET_INIT_FN(esp_at_custom_cmd_register, 1); .. note:: + If you choose not to define AT commands in the `at_custom_cmd.c` and `at_custom_cmd.h` files, but instead create new source and header files in the `esp-at/examples/at_custom_cmd/custom` and `esp-at/examples/at_custom_cmd/include` directories to customize AT commands and the custom registration function, you should avoid naming your registration function `esp_at_custom_cmd_register`. This is because there is already a function named esp_at_custom_cmd_register in the at_custom_cmd example, which has been initialized. You can define a function with a different name to register AT commands, and then use ESP_AT_CMD_SET_INIT_FN to initialize your defined registration function. - ``esp_at_custom_cmd_array_regist`` is recommended to be added to the ``at_custom_init()`` in ``app_main()``. +.. _update-cmakelist: -.. _user-define-at-commands-give-it-a-try: +:ref:`Update the CMakeLists.txt File ` +------------------------------------------------------------ -Give it a try -------------- +Now you need to update the `CMakeLists.txt file `_ based on the :ref:`custom AT command code ` and :ref:`custom register AT command function and initialization code ` implemented above. Pay special attention to the following two points: -If you have finished the above two steps, the command should work after you build the ESP-AT project and flash the firmware to your device. Give it a try! +1. :ref:`Add component dependencies ` +2. :ref:`Add link options ` -Below is how ``AT+TEST`` works out. +.. _set-component-env-and-compile: + +:ref:`Setting Component Environment Variables and Compiling the AT Project ` +----------------------------------------------------------------------------------------------------- + +- Please choose one of the following two methods to recompile the AT firmware. + + - **Method 1:** If you choose to recompile the AT firmware according to the :doc:`ESP-AT Project Compilation Guide `, please set the environment variables for the at_custom_cmd component using one of the two methods described in the `Setting Environment Variables Document `_ before you start compiling the AT project. + - **Method 2:** If you choose to recompile the AT firmware according to the :doc:`Web Compilation Guide for the ESP-AT Project `, please set the environment variables for the at_custom_cmd component using the :ref:`second method ` in the `Setting Environment Variables Document `_ before you start compiling the AT project. + +- Please `flash the AT firmware you compiled <../Get_Started/Downloading_guide>`_. + +.. _user-at-cmd-give-it-a-try: + +:ref:`Give the AT+TEST Command a Try ` +------------------------------------------------------------------------ + +If you have completed the four steps of :ref:`define-at-commands`, :ref:`register-at-commands`, :ref:`update-cmakelist`, and :ref:`set-component-env-and-compile`, the `AT+TEST` command should run correctly on your device. Give it a try! + +If you have followed the steps correctly, below is the execution result of the `AT+TEST` command you defined. **Test Command:** @@ -167,7 +346,7 @@ Below is how ``AT+TEST`` works out. .. code-block:: none AT+TEST=? - this cmd is test cmd: +TEST + test command: is executed OK @@ -182,7 +361,7 @@ Below is how ``AT+TEST`` works out. .. code-block:: none AT+TEST? - this cmd is query cmd: +TEST + query command: is executed OK @@ -197,9 +376,7 @@ Below is how ``AT+TEST`` works out. .. code-block:: none AT+TEST=1,"espressif" - this cmd is setup cmd and cmd num is: 2 - first parameter is: 1 - second parameter is: espressif + setup command: is executed OK @@ -214,14 +391,19 @@ Below is how ``AT+TEST`` works out. .. code-block:: none AT+TEST - this cmd is execute cmd: +TEST + execute command: is executed OK +Custom Complex AT Command Code +=============================== + +**If you have completed the above steps, you have successfully created a simple AT+TEST command. Below are some code examples suitable for defining relatively complex commands, which you can choose based on your needs.** + .. _define-return-values: -Define Return Values ---------------------- +:ref:`Define Return Values ` +-------------------------------------------------- ESP-AT has defined return values in :cpp:type:`esp_at_result_code_string_index`. See :ref:`at-messages` for more return values. @@ -261,8 +443,8 @@ How it works out: .. _access-command-parameters: -Access Command Parameters -------------------------- +:ref:`Access Command Parameters ` +------------------------------------------------------- ESP-AT provides two APIs to access command parameters: @@ -273,8 +455,8 @@ See :ref:`Set Command ` for an example. .. _omit-command-parameters: -Omit Command Parameters ------------------------- +:ref:`Omit Command Parameters ` +----------------------------------------------------- This section describes how to provide optional command parameters: @@ -459,8 +641,8 @@ Below is the sample code to achieve it: .. _block-command-execution: -Block Command Execution ------------------------- +:ref:`Block Command Execution ` +----------------------------------------------------- Sometimes you want to block the execution of one command to wait for another execution result, and the system may return different values according to the result. @@ -497,8 +679,8 @@ The sample code is as follows: .. _access-input-data-from-at-command-port: -Access Input Data from AT Command Port --------------------------------------- +:ref:`Access Input Data from AT Command Port ` +-------------------------------------------------------------------- ESP-AT supports accessing input data from AT Command port. It provides two APIs for this purpose. @@ -695,4 +877,4 @@ So, if the first input data is ``1234567890``, and the second input data is ``++ AT+TEST > received data is: 1234567890 - OK \ No newline at end of file + OK diff --git a/docs/zh_CN/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst b/docs/zh_CN/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst index 12c5b3dea..897a5500f 100644 --- a/docs/zh_CN/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst +++ b/docs/zh_CN/Compile_and_Develop/How_to_add_user-defined_AT_commands.rst @@ -1,20 +1,29 @@ -添加自定义 AT 命令 -===================== +.. _user-defined_at_cmd: + +************************ +增加自定义 AT 命令 +************************ :link_to_translation:`en:[English]` -本文档详细介绍了如何在 `ESP-AT `_ 工程中添加用户定义的 AT 命令,以 ``AT+TEST`` 命令为例展示每个步骤的示例代码。 +本文档详细介绍了如何添加自定义的 AT 命令,其实在 ESP-AT 工程中已经提供了 `at_custom_cmd 示例 `_,下文主要是围绕该示例展开说明,将以 ``AT+TEST`` 命令为例展示每个步骤的示例代码。 + +在您自定义 AT 命令之前,请先了解: -自定义一个基本的、功能良好的命令至少需要以下两个步骤。 +- :ref:`at-custom_cmd` + +自定义一个基本的、功能良好的命令至少需要以下四个步骤: - :ref:`define-at-commands` - :ref:`register-at-commands` +- :ref:`update-cmakelist` +- :ref:`set-component-env-and-compile` -这一步介绍新命令的运行及响应情况。 +完成上述步骤后,我们来看下新命令(AT+TEST)的运行及响应情况: -- :ref:`user-define-at-commands-give-it-a-try` +- :ref:`user-at-cmd-give-it-a-try` -其余的步骤适用于定义相对复杂的命令,可根据您的需要进行选择。 +下面步骤适用于自定义相对复杂的命令,可根据您的需要进行选择: - :ref:`define-return-values` - :ref:`access-command-parameters` @@ -24,12 +33,152 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形式呈现,它也是解析自定义的 AT 命令的基础。 +.. _at-custom_cmd: + +:ref:`at_custom_cmd 组件 ` +================================================== + +at_custom_cmd 组件简介 +------------------------- + +您可以先阅读 at_custom_cmd 组件的 `README `_ 简单了解下它。 + +关于组件概念和相关知识,具体参考ESP-IDF 构建系统中 `介绍组件的文档 `_。 + +.. _at_custom_cmd_component: + +at_custom_cmd 组件目录树结构 +------------------------------ + +at_custom_cmd 组件的目录树结构如下所示: + +.. code-block:: none + + - at_custom_cmd/ + - custom/ - at_custom_cmd.c + - include/ - at_custom_cmd.h + - CMakeLists.txt + - README.md + +该示例项目 "at_custom_cmd" 包含以下组成部分: + + - at_custom_cmd/custom/ 目录下的 .c 文件用来存放 :ref:`自定义 AT 命令的源代码 `。除了 at_custom_cmd.c 文件,可在此目录下再另外创建 .c 文件。 + - at_custom_cmd/include/ 目录下的 .h 文件用来存放自定义 AT 命令的头文件。除了 at_custom_cmd.h 文件,可在此目录下再另外创建 .h 文件。 + - CMakeLists.txt 文件,里面会定义一些变量以控制该组件的构建过程,以及其与 ESP-AT 项目的集成。更多详细信息请参阅 `组件 CMakeLists 文件 `_。 + - README.md 文件,用来对该组件进行说明。 + +at_custom_cmd 组件 CMakeLists.txt 文件 +----------------------------------------- + +- 将 `.c` 文件路径添加到变量 `srcs` 中: + + .. code-block:: none + + file(GLOB_RECURSE srcs *.c) + +- 设置头文件(at_custom_cmd.h 文件)包含目录: + + .. code-block:: none + + set(includes "include") + +.. _add-component_dependencies: + +- 增加组件依赖,并将组件添加到构建系统中: + + - 在 CMakeLists.txt 文件中添加 :ref:`自定义 AT 命令代码 ` 中需要的组件依赖。并使用 idf_component_register 将组件添加到构建系统中,具体可参考 `idf_component_register `_。 + + .. code-block:: none + + set(require_components at freertos nvs_flash) + + idf_component_register( + SRCS ${srcs} + INCLUDE_DIRS ${includes} + REQUIRES ${require_components}) + + .. note:: + 如果您 :ref:`自定义 AT 命令代码 ` 中使用了其他组件,您需要在 `esp-at/examples/at_custom_cmd/CMakeLists.txt` 文件中添加这些组件依赖。例如您还使用到了 LwIP 组件,则您设置应如下: + + .. code-block:: none + + set(require_components at freertos nvs_flash lwip) + +.. _add-link_options: + +- 将您 :ref:`自定义的注册 AT 命令函数 ` 的名称作为一个链接选项强制链接给 ${COMPONENT_LIB},确保程序运行时可以正确找到该自定义的注册 AT 命令函数。以下链接示例是以 at_custom_cmd 示例中的 `esp_at_custom_cmd_register` 注册 AT 命令函数为例: + + .. code-block:: none + + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_at_custom_cmd_register") + + .. note:: + 如果您 :ref:`自定义的注册 AT 命令函数 ` 的名称为 ``esp_at_custom_cmd_register_1`` 则需增加如下代码: + + .. code-block:: none + + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_at_custom_cmd_register_1") + +.. _component-usage: + +at_custom_cmd 组件用法 +------------------------ + +1. 将 :ref:`自定义 AT 命令代码 ` 添加到 `at_custom_cmd/custom/**/*.c` 和 `at_custom_cmd/custom/**/*.h` 文件中(您也可以创建新的源文件和头文件,如果使用此方法的话,您需要注意在 .c 文件中对 :ref:`注册 AT 命令函数 ` 的处理)。 +2. 如果您的代码中使用了其他组件,您可能需要在 `at_custom_cmd/CMakeLists.txt` 文件中添加更多组件依赖。 + +.. _compinents-3: + +3. 设置 `at_custom_cmd` 组件环境变量,以便让 `ESP-AT` 项目在编译时能找到该组件,以下两种方法,选择其一即可。 + +.. _set-path_1: + +- **方法一:** 直接在命令行中设置 `AT_CUSTOM_COMPONENTS` 环境变量 + + .. note:: + - 您需要将 (path_of_at_custom_cmd) 替换为 `at_custom_cmd` 目录的真实绝对路径。 + - 您可以指定多个组件。例如:`export AT_CUSTOM_COMPONENTS="~/prefix/my_path1 ~/prefix/my_path2"`。 + + - Linux or macOS + + .. code-block:: none + + export AT_CUSTOM_COMPONENTS=(path_of_at_custom_cmd) + + - Windows + + .. code-block:: none + + set AT_CUSTOM_COMPONENTS=(path_of_at_custom_cmd) + +.. _set-path_2: + +- **方法二:** 直接在 `esp-at/build.py` 文件 ``setup_env_variables()`` 函数中加入设置 AT_CUSTOM_COMPONENTS 环境变量的代码,代码示例如下: + + .. code-block:: none + + # set AT_CUSTOM_COMPONENTS + at_custom_cmd_path=os.path.join(os.getcwd(), 'examples/at_custom_cmd') + os.environ['AT_CUSTOM_COMPONENTS']=at_custom_cmd_path + +.. _compile-at: + +4. 选择以下两种方法重新编译 AT 固件 + + - **方法一:** 根据 :doc:`本地编译 ESP-AT 项目指南 <../Compile_and_Develop/How_to_clone_project_and_compile_it>` 来重新编译 AT 固件。 + - **方法二:** 根据 :doc:`网页编译 ESP-AT 项目指南 <../Compile_and_Develop/How_to_build_project_with_web_page>` 来重新编译 AT 固件(如果选择了此方法进行编译 AT 固件,则上述的第三步 :ref:`component-usage` 必须选用 :ref:`第二种方法 `)。 + +.. _step-define_at_command: + +:ref:`自定义 AT 命令步骤 ` +================================================== + .. _define-at-commands: -定义 AT 命令 ------------------- +:ref:`自定义 AT 命令代码 ` +-------------------------------------------------- -在定义 AT 命令之前,请先决定 AT 命令的名称和类型。 +在自定义 AT 命令之前,请先决定 AT 命令的名称和类型。 **命令命名规则:** @@ -46,12 +195,10 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: c - uint8_t at_test_cmd_test(uint8_t *cmd_name) + static uint8_t at_test_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is test cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "test command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; @@ -61,12 +208,10 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: c - uint8_t at_query_cmd_test(uint8_t *cmd_name) + static uint8_t at_query_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is query cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "query command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; @@ -78,31 +223,33 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: c - uint8_t at_setup_cmd_test(uint8_t para_num) + static uint8_t at_setup_cmd_test(uint8_t para_num) { - int32_t para_int_1 = 0; - uint8_t *para_str_2 = NULL; - uint8_t num_index = 0; - uint8_t buffer[64] = {0}; + uint8_t index = 0; - if (esp_at_get_para_as_digit(num_index++, ¶_int_1) != ESP_AT_PARA_PARSE_RESULT_OK) { + // get first parameter, and parse it into a digit + int32_t digit = 0; + if (esp_at_get_para_as_digit(index++, &digit) != ESP_AT_PARA_PARSE_RESULT_OK) { return ESP_AT_RESULT_CODE_ERROR; } - if (esp_at_get_para_as_str(num_index++, ¶_str_2) != ESP_AT_PARA_PARSE_RESULT_OK) { + // get second parameter, and parse it into a string + uint8_t *str = NULL; + if (esp_at_get_para_as_str(index++, &str) != ESP_AT_PARA_PARSE_RESULT_OK) { return ESP_AT_RESULT_CODE_ERROR; } - snprintf((char *)buffer, 64, "this cmd is setup cmd and cmd num is: %u\r\n", para_num); - esp_at_port_write_data(buffer, strlen((char *)buffer)); - - memset(buffer, 0, 64); - snprintf((char *)buffer, 64, "first parameter is: %d\r\n", para_int_1); - esp_at_port_write_data(buffer, strlen((char *)buffer)); + // allocate a buffer and construct the data, then send the data to mcu via interface (uart/spi/sdio/socket) + uint8_t *buffer = (uint8_t *)malloc(512); + if (!buffer) { + return ESP_AT_RESULT_CODE_ERROR; + } + int len = snprintf((char *)buffer, 512, "setup command: is executed\r\n", + esp_at_get_current_cmd_name(), digit, str); + esp_at_port_write_data(buffer, len); - memset(buffer, 0, 64); - snprintf((char *)buffer, 64, "second parameter is: %s\r\n", para_str_2); - esp_at_port_write_data(buffer, strlen((char *)buffer)); + // remember to free the buffer + free(buffer); return ESP_AT_RESULT_CODE_OK; } @@ -111,50 +258,82 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: c - uint8_t at_exe_cmd_test(uint8_t *cmd_name) + static uint8_t at_exe_cmd_test(uint8_t *cmd_name) { uint8_t buffer[64] = {0}; - - snprintf((char *)buffer, 64, "this cmd is execute cmd: %s\r\n", cmd_name); - + snprintf((char *)buffer, 64, "execute command: is executed\r\n", cmd_name); esp_at_port_write_data(buffer, strlen((char *)buffer)); return ESP_AT_RESULT_CODE_OK; } -最后,调用 :cpp:type:`esp_at_cmd_struct` 来定义 AT 命令的名称和支持的类型,下面的示例代码定义了名称为 ``+TEST``(省略了 ``AT``) 并支持所有四种类型的命令。 +最后,调用 :cpp:type:`esp_at_cmd_struct` 来定义 AT 命令的名称和支持的类型,下面的示例代码定义了名称为 ``+TEST`` (省略了 ``AT``) 并支持所有四种类型的命令。 + +.. note:: + 如果不定义某个类型,将其设置为 ``NULL``。 .. code-block:: c - static esp_at_cmd_struct at_custom_cmd[] = { + static const esp_at_cmd_struct at_custom_cmd[] = { {"+TEST", at_test_cmd_test, at_query_cmd_test, at_setup_cmd_test, at_exe_cmd_test}, + /** + * @brief You can define your own AT commands here. + */ }; -如果不定义某个类型,将其设置为 ``NULL``。 - .. _register-at-commands: -注册 AT 命令 --------------------- +:ref:`定义注册 AT 命令函数并初始化 ` +---------------------------------------------------------- -调用 API :cpp:func:`esp_at_custom_cmd_array_regist` 来注册 AT 命令,以下是注册 ``AT+TEST`` 的示例代码。 +at_custom_cmd 示例中 esp_at_custom_cmd_register 函数调用 API :cpp:func:`esp_at_custom_cmd_array_regist` 来注册 AT 命令,以下是注册 ``AT+TEST`` 的示例代码。 .. code-block:: c - esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(at_custom_cmd[0])); + bool esp_at_custom_cmd_register(void) + { + return esp_at_custom_cmd_array_regist(at_custom_cmd, sizeof(at_custom_cmd) / sizeof(esp_at_cmd_struct)); + } + +最后调用 API `ESP_AT_CMD_SET_INIT_FN `_ 来初始化您实现的注册 AT 命令函数 esp_at_custom_cmd_register,以下是初始化注册 ``AT+TEST`` 命令函数的示例代码。 + +.. code-block:: c + + ESP_AT_CMD_SET_INIT_FN(esp_at_custom_cmd_register, 1); .. note:: + 如果您选择不在 `at_custom_cmd.c` 和 `at_custom_cmd.h` 文件中 :ref:`define-at-commands`,而是在 `esp-at/examples/at_custom_cmd/custom` 和 `esp-at/examples/at_custom_cmd/include` 目录下创建新的源文件和头文件来 :ref:`自定义 AT 命令 ` 和 :ref:`自定义注册 AT 命令函数并初始化 `,则您在实现注册 AT 命令函数时就要避免将函数名称设置为 `esp_at_custom_cmd_register`,因为在 at_custom_cmd 示例中已经存在了名为 esp_at_custom_cmd_register 的函数,并对它进行了初始化,您可以定义一个名称不是 `esp_at_custom_cmd_register` 的函数去注册 AT 命令,然后您再使用 ESP_AT_CMD_SET_INIT_FN 将您定义的注册 AT 命令函数初始化即可。 + +.. _update-cmakelist: - 建议把 ``esp_at_custom_cmd_array_regist`` 加入 ``app_main()`` 中的 ``at_custom_init()``。 +:ref:`更新 CMakeLists.txt 文件 ` +-------------------------------------------------------- -.. _user-define-at-commands-give-it-a-try: +现在您需要根据以上实现的 :ref:`自定义 AT 命令代码 ` 和 :ref:`自定义注册 AT 命令函数并初始化代码 ` 来更新 `CMakeLists.txt 文件 `_。特别注意以下两点: -尝试一下吧 -------------- +1. :ref:`增加组件依赖 ` +2. :ref:`增加链接选项 ` -如果你已经完成了上述两个步骤,请编译 ESP-AT 工程并烧录固件,该命令即可在您的设备上正常运行。尝试运行一下吧! +.. _set-component-env-and-compile: -下面是 ``AT+TEST`` 的运行情况。 +:ref:`设置组件环境变量以及编译 AT 工程 ` +--------------------------------------------------------------- + +- 请在以下两种编译 AT 工程方法中选择其一重新编译 AT 固件。 + + - **方法一:** 如果您选择根据 :doc:`本地编译 ESP-AT 项目指南 <../Compile_and_Develop/How_to_clone_project_and_compile_it>` 来重新编译 AT 固件,那么请您在开始编译 AT 工程之前,先根据 `设置环境变量文档 `_ 中描述的两种方法选择其一设置 at_custom_cmd 组件的环境变量。 + - **方法二:** 如果您选择根据 :doc:`网页编译 ESP-AT 项目指南 <../Compile_and_Develop/How_to_build_project_with_web_page>` 来重新编译 AT 固件,那么请您在开始编译 AT 工程之前,先根据 `设置环境变量文档 `_ 中 :ref:`第二种方法 ` 设置 at_custom_cmd 组件的环境变量。 + +- 请 `烧录您编译的 AT 固件 <../Get_Started/Downloading_guide>`_。 + +.. _user-at-cmd-give-it-a-try: + +:ref:`尝试运行 AT+TEST 命令吧 ` +===================================================== + +如果你已经完成了 :ref:`define-at-commands`, :ref:`register-at-commands`, :ref:`update-cmakelist` 以及 :ref:`set-component-env-and-compile` 四个步骤, `AT+TEST` 命令即可在您的设备上正常运行。尝试运行一下吧! + +如果你上面的步骤都操作正确了,那么下面就是您定义的 ``AT+TEST`` 命令的运行情况。 **测试命令:** @@ -167,7 +346,7 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: none AT+TEST=? - this cmd is test cmd: +TEST + test command: is executed OK @@ -182,7 +361,7 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: none AT+TEST? - this cmd is query cmd: +TEST + query command: is executed OK @@ -197,9 +376,7 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: none AT+TEST=1,"espressif" - this cmd is setup cmd and cmd num is: 2 - first parameter is: 1 - second parameter is: espressif + setup command: is executed OK @@ -214,14 +391,19 @@ AT 命令集的源代码不开源,以 :component:`库文件 ` 的形 .. code-block:: none AT+TEST - this cmd is execute cmd: +TEST + execute command: is executed OK +自定义复杂的 AT 命令代码 +========================= + +**如果您完成了上述步骤,则您已经可以完成一个简单的 AT+TEST 命令了,下面会介绍一些适用于定义相对复杂的命令的代码示例,可根据您的需要进行选择。** + .. _define-return-values: -定义返回消息 ---------------------- +:ref:`定义返回消息 ` +------------------------------------------ ESP-AT 已经在 :cpp:type:`esp_at_result_code_string_index` 定义了一些返回消息,更多返回消息请参见 :ref:`at-messages`。 @@ -261,8 +443,8 @@ ESP-AT 已经在 :cpp:type:`esp_at_result_code_string_index` 定义了一些返 .. _access-command-parameters: -获取命令参数 -------------- +:ref:`获取命令参数 ` +------------------------------------------------- ESP-AT 提供以下两个 API 获取命令参数。 @@ -273,8 +455,8 @@ ESP-AT 提供以下两个 API 获取命令参数。 .. _omit-command-parameters: -省略命令参数 ------------------------- +:ref:`省略命令参数 ` +------------------------------------------------ 本节介绍如何设置某些命令参数为可选参数。 @@ -459,8 +641,8 @@ ESP-AT 提供以下两个 API 获取命令参数。 .. _block-command-execution: -阻塞命令的执行 ----------------- +:ref:`阻塞命令的执行 ` +--------------------------------------------- 有时您想阻塞某个命令的执行,等待另一个执行结果,然后系统基于这个结果可能会返回不同的值。 @@ -497,8 +679,8 @@ ESP-AT 提供以下两个 API 获取命令参数。 .. _access-input-data-from-at-command-port: -从 AT 命令端口获取输入的数据 -------------------------------- +:ref:`从 AT 命令端口获取输入的数据 ` +----------------------------------------------------------- ESP-AT 支持从 AT 命令端口访问输入的数据,为此提供以下两个 API。 @@ -695,4 +877,4 @@ ESP-AT 支持从 AT 命令端口访问输入的数据,为此提供以下两个 AT+TEST > received data is: 1234567890 - OK \ No newline at end of file + OK