]> granicus.if.org Git - esp-idf/commitdiff
Merge branch 'bugfix/macros_trailing_semicolon' into 'master' v4.0-dev
authorAngus Gratton <angus@espressif.com>
Wed, 13 Mar 2019 05:15:12 +0000 (13:15 +0800)
committerAngus Gratton <angus@espressif.com>
Wed, 13 Mar 2019 05:15:12 +0000 (13:15 +0800)
Remove trialing semicolon from function-like macros

See merge request idf/esp-idf!4397

115 files changed:
.github/main.workflow [new file with mode: 0644]
.gitlab-ci.yml
components/bt/Kconfig
components/bt/bluedroid/common/include/common/bt_target.h
components/bt/bluedroid/stack/btm/btm_ble.c
components/bt/bluedroid/stack/btm/include/btm_int.h
components/bt/bluedroid/stack/smp/smp_act.c
components/bt/bluedroid/stack/smp/smp_utils.c
components/bt/bt.c
components/bt/lib
components/driver/test/test_spi_param.c
components/driver/uart.c
components/efuse/src/esp_efuse_utility.c
components/esp32/CMakeLists.txt
components/esp32/Kconfig
components/esp32/coexist.c
components/esp32/coexist_internal.h [deleted file]
components/esp32/cpu_start.c
components/esp32/esp_adapter.c [moved from components/esp32/wifi_os_adapter.c with 74% similarity]
components/esp32/gdbstub.c
components/esp32/include/esp_coexist_adapter.h [new file with mode: 0644]
components/esp32/include/esp_coexist_internal.h [new file with mode: 0644]
components/esp32/include/esp_core_dump.h [deleted file]
components/esp32/include/esp_event_legacy.h
components/esp32/include/esp_wifi_internal.h
components/esp32/include/esp_wifi_os_adapter.h
components/esp32/include/rom/crc.h
components/esp32/intr_alloc.c
components/esp32/lib
components/esp32/phy_init.c
components/esp32/test/CMakeLists.txt
components/esp32/test/component.mk
components/esp32/test/test_header_files_md5.c
components/esp32/wifi_init.c
components/esp_http_client/esp_http_client.c
components/esp_http_client/include/esp_http_client.h
components/esp_http_server/include/esp_http_server.h
components/esp_http_server/src/esp_httpd_priv.h
components/esp_http_server/src/httpd_parse.c
components/esp_https_ota/src/esp_https_ota.c
components/espcoredump/include/esp_core_dump.h
components/espcoredump/linker.lf
components/esptool_py/project_include.cmake
components/freemodbus/port/port.h
components/freemodbus/port/portother.c
components/freemodbus/port/portserial.c
components/lwip/apps/dhcpserver/dhcpserver.c
components/lwip/lwip
components/mdns/mdns.c
components/mdns/private_include/mdns_private.h
components/tcp_transport/include/esp_transport_ssl.h
components/tcp_transport/transport_ssl.c
components/tcpip_adapter/tcpip_adapter_lwip.c
components/ulp/cmake/CMakeLists.txt
docs/_static/jtag-debugging-overview_zh.jpg [new file with mode: 0644]
docs/check_doc_warnings.sh
docs/en/api-guides/build-system-cmake.rst
docs/en/api-guides/build-system.rst
docs/en/api-guides/hlinterrupts.rst
docs/en/api-guides/jtag-debugging/building-openocd-linux.rst
docs/en/api-guides/jtag-debugging/building-openocd-macos.rst
docs/en/api-guides/jtag-debugging/building-openocd-windows.rst
docs/en/api-guides/jtag-debugging/configure-other-jtag.rst
docs/en/api-guides/jtag-debugging/configure-wrover.rst
docs/en/api-guides/jtag-debugging/debugging-examples.rst
docs/en/api-guides/jtag-debugging/index.rst
docs/en/api-guides/jtag-debugging/setup-openocd-linux.rst
docs/en/api-guides/jtag-debugging/setup-openocd-macos.rst
docs/en/api-guides/jtag-debugging/setup-openocd-windows.rst
docs/en/api-guides/jtag-debugging/tips-and-quirks.rst
docs/en/api-guides/jtag-debugging/using-debugger.rst
docs/en/api-guides/linker-script-generation.rst
docs/en/api-reference/system/efuse.rst
docs/en/api-reference/system/system.rst
docs/en/get-started-cmake/linux-setup-scratch.rst
docs/en/get-started-cmake/linux-setup.rst
docs/en/get-started/linux-setup-scratch.rst
docs/requirements.txt
docs/sphinx-known-warnings.txt
docs/zh_CN/api-guides/build-system-cmake.rst
docs/zh_CN/api-guides/build-system.rst
docs/zh_CN/api-guides/index.rst
docs/zh_CN/api-guides/jtag-debugging/building-openocd-linux.rst
docs/zh_CN/api-guides/jtag-debugging/building-openocd-macos.rst
docs/zh_CN/api-guides/jtag-debugging/building-openocd-windows.rst
docs/zh_CN/api-guides/jtag-debugging/configure-other-jtag.rst
docs/zh_CN/api-guides/jtag-debugging/configure-wrover.rst
docs/zh_CN/api-guides/jtag-debugging/debugging-examples.rst
docs/zh_CN/api-guides/jtag-debugging/index.rst
docs/zh_CN/api-guides/jtag-debugging/setup-openocd-linux.rst
docs/zh_CN/api-guides/jtag-debugging/setup-openocd-macos.rst
docs/zh_CN/api-guides/jtag-debugging/setup-openocd-windows.rst
docs/zh_CN/api-guides/jtag-debugging/tips-and-quirks.rst
docs/zh_CN/api-guides/jtag-debugging/using-debugger.rst
docs/zh_CN/api-guides/jtag-debugging/windows-openocd-note.rst
docs/zh_CN/api-guides/linker-script-generation.rst
docs/zh_CN/cmake-pending-features.rst
docs/zh_CN/cmake-warning.rst
docs/zh_CN/get-started-cmake/linux-setup-scratch.rst
docs/zh_CN/get-started-cmake/linux-setup.rst
docs/zh_CN/get-started/linux-setup-scratch.rst
docs/zh_CN/get-started/linux-setup.rst
examples/bluetooth/ble_hid_device_demo/main/ble_hidd_demo_main.c
examples/bluetooth/ble_hid_device_demo/main/hid_device_le_prf.c
examples/bluetooth/ble_hid_device_demo/main/hidd_le_prf_int.h
examples/get-started/blink/main/blink.c
examples/system/console/main/cmd_wifi.c
examples/system/ota/simple_ota_example/main/simple_ota_example.c
tools/ci/mirror-submodule-update.sh
tools/ci/test_build_system_cmake.sh
tools/cmake/components.cmake
tools/cmake/ldgen.cmake
tools/idf.py
tools/unit-test-app/partition_table_unit_test_app.csv
tools/unit-test-app/unit_test.py

diff --git a/.github/main.workflow b/.github/main.workflow
new file mode 100644 (file)
index 0000000..12e566f
--- /dev/null
@@ -0,0 +1,17 @@
+workflow "Sync issues to JIRA" {
+  on = "issues"
+  resolves = ["Sync to JIRA"]
+}
+
+workflow "Sync issue comments to JIRA" {
+  on = "issue_comment"
+  resolves = ["Sync to JIRA"]
+}
+
+action "Sync to JIRA" {
+  uses = "espressif/github-actions/sync_issues_to_jira@master"
+  secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"]
+  env = {
+    JIRA_PROJECT = "IDFGH"
+  }
+}
index 0c55ce4cd50746e37e5bfefc732ba0a8a319d7aa..8742f5fd744fe6b5efbd356a50e6cb18814abadd 100644 (file)
@@ -19,7 +19,7 @@ variables:
   GET_SOURCES_ATTEMPTS: "10"
   ARTIFACT_DOWNLOAD_ATTEMPTS: "10"
 
-  # We use get_sources.sh script to fetch the submodules and/or re-fetch the repo
+  # We use get-full-sources.sh script to fetch the submodules and/or re-fetch the repo
   # if it was corrupted (if submodule update fails this can happen)
   GIT_STRATEGY: fetch
   GIT_SUBMODULE_STRATEGY: none
@@ -1299,6 +1299,12 @@ UT_001_42:
     - ESP32_IDF
     - UT_T1_1
 
+UT_001_43:
+  <<: *unit_test_template
+  tags:
+    - ESP32_IDF
+    - UT_T1_1
+
 UT_002_01:
   <<: *unit_test_template
   tags:
index 4551a47f88148ca574739a2be5235a9711393f2e..d0152d6ff802e500e15f77584d0fd3c489e7b86c 100644 (file)
@@ -428,6 +428,13 @@ menu Bluetooth
         help
             This option can be close when the app not used the ble security connect.
 
+    config SMP_SLAVE_CON_PARAMS_UPD_ENABLE
+        bool "Slave enable connection parameters update during pairing"
+        depends on BLE_SMP_ENABLE
+        default n
+        help
+            In order to reduce the pairing time, slave actively initiates connection parameters update during pairing.
+
     config BT_STACK_NO_LOG
         bool "Disable BT debug logs (minimize bin size)"
         depends on BLUEDROID_ENABLED
index e2b5f8538a480ed900640c536deca9dd0b4ac5a7..997295bb419377b251230dbf9933ca68bbcd8420 100644 (file)
 #define BLE_PRIVACY_SPT           FALSE
 #endif  /* CONFIG_SMP_ENABLE */
 
+#ifdef CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE
+#if(CONFIG_SMP_SLAVE_CON_PARAMS_UPD_ENABLE)
+#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE  TRUE
+#else
+#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE  FALSE
+#endif
+#else
+#define SMP_SLAVE_CON_PARAMS_UPD_ENABLE  FALSE
+#endif
+
 #if (CONFIG_BT_ACL_CONNECTIONS)
 #define MAX_ACL_CONNECTIONS  CONFIG_BT_ACL_CONNECTIONS
 #define GATT_MAX_PHY_CHANNEL CONFIG_BT_ACL_CONNECTIONS
index 0a5ad832c9cb003a6c20a386f0bf965d833d12ed..5e4c9ee71ceeb8b89c86b3f1051fa5576ef05a44 100644 (file)
@@ -1468,13 +1468,14 @@ tBTM_STATUS btm_ble_set_encryption (BD_ADDR bd_addr, void *p_ref_data, UINT8 lin
                 break;
             }
         }
-
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
         // already have encrypted information, do not need to update connection parameters
         if(link_role == BTM_ROLE_SLAVE && (p_rec->ble.key_type & BTM_LE_KEY_PENC)) {
             p_rec->ble.skip_update_conn_param = true;
         } else {
             p_rec->ble.skip_update_conn_param = false;
         }
+#endif
         if (SMP_Pair(bd_addr) == SMP_STARTED) {
             cmd = BTM_CMD_STARTED;
             p_rec->sec_state = BTM_SEC_STATE_AUTHENTICATING;
index 490d9afe42f53f7015fd5f85f44abe8da456a98e..47ddfd3449b3885b9d1fb5953931ffdb8698e93c 100644 (file)
@@ -488,7 +488,9 @@ typedef struct {
 #if SMP_INCLUDED == TRUE
     tBTM_LE_KEY_TYPE    key_type;       /* bit mask of valid key types in record */
     tBTM_SEC_BLE_KEYS   keys;           /* LE device security info in slave rode */
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
     bool skip_update_conn_param;        /* skip update connection paraams or not*/
+#endif
     UINT16 auth_mode;                   /* Authentication mode */
 #endif
 #if (BLE_PRIVACY_SPT == TRUE)
index 63b9cb10e5fc540728109bd7a7235741618545c1..dcd3495f254dbd3aecae1c0fb6ff61ebaff655a6 100644 (file)
@@ -1478,16 +1478,23 @@ void smp_idle_terminate(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
 *******************************************************************************/
 void smp_fast_conn_param(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
 {
-    tBTM_SEC_DEV_REC    *p_rec = btm_find_dev (p_cb->pairing_bda);
-    if(p_rec && p_rec->ble.skip_update_conn_param) {
-        //do nothing
-        return;
+    if(p_cb->role == BTM_ROLE_MASTER) {
+        L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
+    } 
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
+    else {
+        tBTM_SEC_DEV_REC    *p_rec = btm_find_dev (p_cb->pairing_bda);
+        if(p_rec && p_rec->ble.skip_update_conn_param) {
+            //do nothing
+            return;
+        }
+        /* Disable L2CAP connection parameter updates while bonding since
+        some peripherals are not able to revert to fast connection parameters
+        during the start of service discovery. Connection paramter updates
+        get enabled again once service discovery completes. */
+        L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
     }
-    /* Disable L2CAP connection parameter updates while bonding since
-       some peripherals are not able to revert to fast connection parameters
-       during the start of service discovery. Connection paramter updates
-       get enabled again once service discovery completes. */
-    L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, FALSE);
+#endif
 }
 
 /*******************************************************************************
index 79a8b1dd59ebd674989067309d428629bdeec6ab..19c2cde99bfd7463797fcb0e8874887844365fe9 100644 (file)
@@ -996,6 +996,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
 
     memcpy (pairing_bda, p_cb->pairing_bda, BD_ADDR_LEN);
 
+#if (SMP_SLAVE_CON_PARAMS_UPD_ENABLE == TRUE)
     if (p_cb->role == HCI_ROLE_SLAVE) {
         if(p_rec && p_rec->ble.skip_update_conn_param) {
             //clear flag
@@ -1004,6 +1005,7 @@ void smp_proc_pairing_cmpl(tSMP_CB *p_cb)
             L2CA_EnableUpdateBleConnParams(p_cb->pairing_bda, TRUE);
         }
     }
+#endif
     smp_reset_control_value(p_cb);
 
     if (p_callback) {
index 82bf79fde6d50c7f18eb43a7cce142eebdbe834b..dc17d9b025c72de8642e37f30589589e4fcedbdc 100644 (file)
@@ -43,6 +43,7 @@
 #include "soc/rtc_cntl_reg.h"
 #include "soc/soc_memory_layout.h"
 #include "esp_clk.h"
+#include "esp_coexist_internal.h"
 
 
 #if CONFIG_BT_ENABLED
@@ -166,6 +167,11 @@ struct osi_funcs_t {
     void (* _btdm_sleep_exit_phase1)(void);  /* called from ISR */
     void (* _btdm_sleep_exit_phase2)(void);  /* called from ISR */
     void (* _btdm_sleep_exit_phase3)(void);  /* called from task */
+    int (* _coex_bt_request)(uint32_t event, uint32_t latency, uint32_t duration);
+    int (* _coex_bt_release)(uint32_t event);
+    int (* _coex_register_bt_cb)(coex_func_cb_t cb);
+    uint32_t (* _coex_bb_reset_lock)(void);
+    void (* _coex_bb_reset_unlock)(uint32_t restore);
     uint32_t _magic;
 };
 
@@ -205,6 +211,12 @@ extern int bredr_txpwr_set(int min_power_level, int max_power_level);
 extern int bredr_txpwr_get(int *min_power_level, int *max_power_level);
 extern void bredr_sco_datapath_set(uint8_t data_path);
 extern void btdm_controller_scan_duplicate_list_clear(void);
+/* Coexistence */
+extern int coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration);
+extern int coex_bt_release_wrapper(uint32_t event);
+extern int coex_register_bt_cb_wrapper(coex_func_cb_t cb);
+extern uint32_t coex_bb_reset_lock_wrapper(void);
+extern void coex_bb_reset_unlock_wrapper(uint32_t restore);
 
 extern char _bss_start_btdm;
 extern char _bss_end_btdm;
@@ -311,6 +323,11 @@ static const struct osi_funcs_t osi_funcs_ro = {
     ._btdm_sleep_exit_phase1 = btdm_sleep_exit_phase1_wrapper,
     ._btdm_sleep_exit_phase2 = NULL,
     ._btdm_sleep_exit_phase3 = btdm_sleep_exit_phase3_wrapper,
+    ._coex_bt_request = coex_bt_request_wrapper,
+    ._coex_bt_release = coex_bt_release_wrapper,
+    ._coex_register_bt_cb = coex_register_bt_cb_wrapper,
+    ._coex_bb_reset_lock = coex_bb_reset_lock_wrapper,
+    ._coex_bb_reset_unlock = coex_bb_reset_unlock_wrapper,
     ._magic = OSI_MAGIC_VALUE,
 };
 
index 86fa066be494c2f3889dbea0821da44fdc1ba4df..48ecf82c99f9e5d729e07c39a9d4c350a0f2f8e9 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 86fa066be494c2f3889dbea0821da44fdc1ba4df
+Subproject commit 48ecf82c99f9e5d729e07c39a9d4c350a0f2f8e9
index 87036e0cdb1636b4a222b9d677712ff90b598c22..d591cc1a9187f5cf1abcb47d26e51cb6ead35313 100644 (file)
@@ -432,6 +432,16 @@ TEST_SPI_LOCAL(MODE, mode_pgroup)
 
 /********************************************************************************
  *      Test By Master & Slave (2 boards)
+ *
+ *  Wiring:
+ * | Master | Slave |
+ * | ------ | ----- |
+ * | 12     | 19    |
+ * | 13     | 23    |
+ * | 14     | 18    |
+ * | 15     | 5     |
+ * | GND    | GND   |
+ *
  ********************************************************************************/
 static void test_master_init(void** context);
 static void test_master_deinit(void* context);
@@ -455,9 +465,9 @@ static const ptest_func_t slave_test_func = {
     .def_param = spitest_def_param,
 };
 
-#define TEST_SPI_MASTER_SLAVE(name, param_group) \
+#define TEST_SPI_MASTER_SLAVE(name, param_group, extra_tag) \
     PARAM_GROUP_DECLARE(name, param_group) \
-    TEST_MASTER_SLAVE(name, param_group, "[spi_ms][test_env=Example_SPI_Multi_device][timeout=120]", &master_test_func, &slave_test_func)
+    TEST_MASTER_SLAVE(name, param_group, "[spi_ms][test_env=Example_SPI_Multi_device][timeout=120]"#extra_tag, &master_test_func, &slave_test_func)
 
 /************ Master Code ***********************************************/
 static void test_master_init(void** arg)
@@ -779,7 +789,7 @@ static spitest_param_set_t timing_conf[] = {
         .slave_tv_ns = TV_WITH_ESP_SLAVE_GPIO,
     },
 };
-TEST_SPI_MASTER_SLAVE(TIMING, timing_conf)
+TEST_SPI_MASTER_SLAVE(TIMING, timing_conf, "")
 
 /************ Mode Test ***********************************************/
 #define FREQ_LIMIT_MODE SPI_MASTER_FREQ_16M
@@ -966,4 +976,4 @@ spitest_param_set_t mode_conf[] = {
       .slave_dma_chan = 1,
     },
 };
-TEST_SPI_MASTER_SLAVE(MODE, mode_conf)
+TEST_SPI_MASTER_SLAVE(MODE, mode_conf, "[ignore]")
index afead15a599e724f2689f23eabf97847417f6b52..de872d881d56183bca44d70f6a4850ebc6dd1773 100644 (file)
@@ -333,6 +333,21 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
     return ESP_OK;
 }
 
+static void uart_disable_intr_mask_from_isr(uart_port_t uart_num, uint32_t disable_mask)
+{
+    UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+    CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);
+    UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+}
+
+static void uart_enable_intr_mask_from_isr(uart_port_t uart_num, uint32_t enable_mask)
+{
+    UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+    SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);
+    SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask);
+    UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+}
+
 static esp_err_t uart_pattern_link_free(uart_port_t uart_num)
 {
     UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
@@ -730,7 +745,7 @@ static void uart_rx_intr_handler_default(void *param)
         uart_event.type = UART_EVENT_MAX;
         if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
             uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
-            uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
+            uart_disable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
             if(p_uart->tx_waiting_brk) {
                 continue;
             }
@@ -832,7 +847,7 @@ static void uart_rx_intr_handler_default(void *param)
                 }
                 if (en_tx_flg) {
                     uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M);
-                    uart_enable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
+                    uart_enable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M);
                 }
             }
         }
@@ -876,7 +891,7 @@ static void uart_rx_intr_handler_default(void *param)
                 //Mainly for applications that uses flow control or small ring buffer.
                 if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
                     p_uart->rx_buffer_full_flg = true;
-                    uart_disable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
+                    uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M);
                     if (uart_event.type == UART_PATTERN_DET) {
                         if (rx_fifo_len < pat_num) {
                             //some of the characters are read out in last interrupt
@@ -912,7 +927,7 @@ static void uart_rx_intr_handler_default(void *param)
                     portYIELD_FROM_ISR();
                 }
             } else {
-                uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
+                uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M);
                 uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M);
                 if(uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
                     uart_reg->int_clr.at_cmd_char_det = 1;
@@ -971,7 +986,7 @@ static void uart_rx_intr_handler_default(void *param)
                 }
             }
         } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {
-            uart_disable_intr_mask(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M);
+            uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M);
             uart_clear_intr_status(uart_num, UART_TX_BRK_IDLE_DONE_INT_CLR_M);
         } else if(uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) {
             uart_reg->int_clr.at_cmd_char_det = 1;
@@ -988,7 +1003,7 @@ static void uart_rx_intr_handler_default(void *param)
             UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
             uart_event.type = UART_EVENT_MAX;
         } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
-            uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
+            uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M);
             uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M);
             // If RS485 half duplex mode is enable then reset FIFO and 
             // reset RTS pin to start receiver driver
index fa360e46ba38866ffabc9466a9080aa920234070..a9401f163a652da500caa6cdedc5fcfb836d0bad 100644 (file)
@@ -32,6 +32,10 @@ static const char *TAG = "efuse";
 // Array for emulate efuse registers.
 #ifdef CONFIG_EFUSE_VIRTUAL
 static uint32_t virt_blocks[COUNT_EFUSE_BLOCKS][COUNT_EFUSE_REG_PER_BLOCK];
+
+/* Call the update function to seed virtual efuses during initialization */
+__attribute__((constructor)) void esp_efuse_utility_update_virt_blocks();
+
 #endif
 
 /**
@@ -181,7 +185,7 @@ void esp_efuse_utility_reset(void)
 void esp_efuse_utility_burn_efuses(void)
 {
 #ifdef CONFIG_EFUSE_VIRTUAL
-    ESP_LOGE(TAG, "Not really burning any efuses!");
+    ESP_LOGW(TAG, "Virtual efuses enabled: Not really burning eFuses");
     for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
         esp_efuse_coding_scheme_t scheme = esp_efuse_get_coding_scheme(num_block);
         if (scheme == EFUSE_CODING_SCHEME_3_4) {
@@ -229,7 +233,7 @@ void esp_efuse_utility_erase_virt_blocks()
 void esp_efuse_utility_update_virt_blocks()
 {
 #ifdef CONFIG_EFUSE_VIRTUAL
-    ESP_LOGI(TAG, "Emulate efuse is enabled");
+    ESP_LOGI(TAG, "Loading virtual efuse blocks from real efuses");
     for (int num_block = 0; num_block < COUNT_EFUSE_BLOCKS; num_block++) {
         int subblock = 0;
         for (uint32_t addr_rd_block = range_read_addr_blocks[num_block].start; addr_rd_block <= range_read_addr_blocks[num_block].end; addr_rd_block += 4) {
index 75b76010d96b96df9131632184273351e040c0ac..4e9740a405dba6eb522ea8f22f67b2d0cf08297d 100644 (file)
@@ -19,6 +19,7 @@ else()
                    "dbg_stubs.c"
                    "dport_access.c"
                    "dport_panic_highint_hdl.S"
+                   "esp_adapter.c"
                    "esp_err_to_name.c"
                    "esp_timer.c"
                    "esp_timer_esp32.c"
@@ -48,7 +49,6 @@ else()
                    "system_api.c"
                    "task_wdt.c"
                    "wifi_init.c"
-                   "wifi_os_adapter.c"
                    "hwcrypto/aes.c"
                    "hwcrypto/sha.c")
     set(COMPONENT_ADD_INCLUDEDIRS "include")
@@ -59,7 +59,7 @@ else()
     # app_update is added here because cpu_start.c uses esp_ota_get_app_description() function.
     set(COMPONENT_PRIV_REQUIRES
         app_trace app_update bootloader_support ethernet log mbedtls nvs_flash
-        pthread smartconfig_ack spi_flash vfs wpa_supplicant xtensa-debug-module)
+        pthread smartconfig_ack spi_flash vfs wpa_supplicant xtensa-debug-module espcoredump)
 
     set(COMPONENT_ADD_LDFRAGMENTS linker.lf ld/esp32_fragments.lf)
 
index 1952e2febb3d74f1a61ab4bae41d57211a3f288b..ab73fbada86eb6f150ae61dce50ee16357afc263 100644 (file)
@@ -544,6 +544,23 @@ menu "ESP32-specific"
                 of the crash.
     endchoice
 
+    config GDBSTUB_SUPPORT_TASKS
+        bool "GDBStub: enable listing FreeRTOS tasks"
+        default y
+        depends on ESP32_PANIC_GDBSTUB
+        help
+            If enabled, GDBStub can supply the list of FreeRTOS tasks to GDB.
+            Thread list can be queried from GDB using 'info threads' command.
+            Note that if GDB task lists were corrupted, this feature may not work.
+            If GDBStub fails, try disabling this feature.
+
+    config GDBSTUB_MAX_TASKS
+        int "GDBStub: maximum number of tasks supported"
+        default 32
+        depends on GDBSTUB_SUPPORT_TASKS
+        help
+            Set the number of tasks which GDB Stub will support.
+
     config ESP32_DEBUG_OCDAWARE
         bool "Make exception and panic handlers JTAG/OCD aware"
         default y
@@ -924,6 +941,8 @@ menu Wi-Fi
             If enabled, WiFi & Bluetooth coexistence is controlled by software rather than hardware.
             Recommended for heavy traffic scenarios. Both coexistence configuration options are
             automatically managed, no user intervention is required.
+            If only Bluetooth is used, it is recommended to disable this option to reduce binary file
+            size.
 
     choice SW_COEXIST_PREFERENCE
         prompt "WiFi/Bluetooth coexistence performance preference"
index 9eff30868a55b654a3f9f2c52847ec02804e0572..628269942783efe232733e9ef6059e43fc5a3e5e 100644 (file)
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "esp_coexist.h"
-#include "coexist_internal.h"
+#include "esp_coexist_internal.h"
 
 const char *esp_coex_version_get(void)
 {
diff --git a/components/esp32/coexist_internal.h b/components/esp32/coexist_internal.h
deleted file mode 100644 (file)
index fb21e24..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright 2018-2018 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.
-
-#ifndef __COEXIST_INTERNAL_H__
-#define __COEXIST_INTERNAL_H__
-
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-    COEX_PREFER_WIFI = 0,
-    COEX_PREFER_BT,
-    COEX_PREFER_BALANCE,
-    COEX_PREFER_NUM,
-} coex_prefer_t;
-
-/**
- * @brief Init software coexist
- *        extern function for internal use.
- *
- * @return Init ok or failed.
- */
-esp_err_t coex_init(void);
-
-/**
- * @brief De-init software coexist
- *        extern function for internal use.
- */
-void coex_deinit(void);
-
-/**
- * @brief Pause software coexist
- *        extern function for internal use.
- */
-void coex_pause(void);
-
-/**
- * @brief Resume software coexist
- *        extern function for internal use.
- */
-void coex_resume(void);
-
-/**
- * @brief Get software coexist version string
- *        extern function for internal use.
- * @return : version string
- */
-const char *coex_version_get(void);
-
-/**
- * @brief Coexist performance preference set from libbt.a
- *        extern function for internal use.
- *
- *  @param prefer : the prefer enumeration value
- *  @return : ESP_OK - success, other - failed
- */
-esp_err_t coex_preference_set(coex_prefer_t prefer);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __COEXIST_INTERNAL_H__ */
index bf28857fb8fa0242403c1e7531063c6309191911..7e45abb037f9aaf169438bec0309a667526c9faa 100644 (file)
@@ -59,7 +59,7 @@
 #include "esp_task_wdt.h"
 #include "esp_phy_init.h"
 #include "esp_cache_err_int.h"
-#include "esp_coexist.h"
+#include "esp_coexist_internal.h"
 #include "esp_panic.h"
 #include "esp_core_dump.h"
 #include "esp_app_trace.h"
@@ -412,6 +412,10 @@ void start_cpu0_default(void)
     }
 #endif
 
+#if CONFIG_SW_COEXIST_ENABLE
+    esp_coex_adapter_register(&g_coex_adapter_funcs);
+#endif
+
     portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main",
                                                 ESP_TASK_MAIN_STACK, NULL,
                                                 ESP_TASK_MAIN_PRIO, NULL, 0);
similarity index 74%
rename from components/esp32/wifi_os_adapter.c
rename to components/esp32/esp_adapter.c
index e63b0135fcd85fb8ddee5718fba8dd4296346070..342494233f96de1389874e646253051e81a37e86 100644 (file)
@@ -46,6 +46,8 @@
 #include "os.h"
 #include "esp_smartconfig.h"
 #include "smartconfig_ack.h"
+#include "esp_coexist_internal.h"
+#include "esp_coexist_adapter.h"
 
 
 extern void esp_dport_access_stall_other_cpu_start_wrap(void);
@@ -100,38 +102,38 @@ static void * IRAM_ATTR wifi_zalloc_wrapper(size_t size)
 }
 
 wifi_static_queue_t* wifi_create_queue( int queue_len, int item_size)
-{   
+{
     wifi_static_queue_t *queue = NULL;
-                      
+
     queue = (wifi_static_queue_t*)heap_caps_malloc(sizeof(wifi_static_queue_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
     if (!queue) {
         return NULL;
     }
-                              
+
 #if CONFIG_SPIRAM_USE_MALLOC
 
     queue->storage = heap_caps_calloc(1, sizeof(StaticQueue_t) + (queue_len*item_size), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT);
     if (!queue->storage) {
         goto _error;
     }
-                                          
+
     queue->handle = xQueueCreateStatic( queue_len, item_size, ((uint8_t*)(queue->storage)) + sizeof(StaticQueue_t), (StaticQueue_t*)(queue->storage));
-                                                    
+
     if (!queue->handle) {
         goto _error;
     }
-                                                      
+
     return queue;
-                                                            
+
 _error:
     if (queue) {
         if (queue->storage) {
             free(queue->storage);
         }
-                                                                                        
+
         free(queue);
     }
-                                                                      
+
     return NULL;
 #else
     queue->handle = xQueueCreate( queue_len, item_size);
@@ -154,26 +156,26 @@ void wifi_delete_queue(wifi_static_queue_t *queue)
     }
 }
 
-static void * IRAM_ATTR wifi_create_queue_wrapper(int queue_len, int item_size)
+static void * wifi_create_queue_wrapper(int queue_len, int item_size)
 {
     return wifi_create_queue(queue_len, item_size);
 }
 
-static void IRAM_ATTR wifi_delete_queue_wrapper(void *queue)
+static void wifi_delete_queue_wrapper(void *queue)
 {
     wifi_delete_queue(queue);
 }
 
-static void IRAM_ATTR set_isr_wrapper(int32_t n, void *f, void *arg)
+static void set_isr_wrapper(int32_t n, void *f, void *arg)
 {
     xt_set_interrupt_handler(n, (xt_handler)f, arg);
 }
 
-static void * IRAM_ATTR spin_lock_create_wrapper(void)
+static void * spin_lock_create_wrapper(void)
 {
     portMUX_TYPE tmp = portMUX_INITIALIZER_UNLOCKED;
     void *mux = malloc(sizeof(portMUX_TYPE));
-    
+
     if (mux) {
         memcpy(mux,&tmp,sizeof(portMUX_TYPE));
         return mux;
@@ -184,10 +186,10 @@ static void * IRAM_ATTR spin_lock_create_wrapper(void)
 static uint32_t IRAM_ATTR wifi_int_disable_wrapper(void *wifi_int_mux)
 {
     if (xPortInIsrContext()) {
-        portENTER_CRITICAL_ISR(wifi_int_mux); 
-    } else {                        
-        portENTER_CRITICAL(wifi_int_mux);     
-    }   
+        portENTER_CRITICAL_ISR(wifi_int_mux);
+    } else {
+        portENTER_CRITICAL(wifi_int_mux);
+    }
 
     return 0;
 }
@@ -195,10 +197,10 @@ static uint32_t IRAM_ATTR wifi_int_disable_wrapper(void *wifi_int_mux)
 static void IRAM_ATTR wifi_int_restore_wrapper(void *wifi_int_mux, uint32_t tmp)
 {
     if (xPortInIsrContext()) {
-        portEXIT_CRITICAL_ISR(wifi_int_mux); 
-    } else {                        
-        portEXIT_CRITICAL(wifi_int_mux);     
-    }   
+        portEXIT_CRITICAL_ISR(wifi_int_mux);
+    } else {
+        portEXIT_CRITICAL(wifi_int_mux);
+    }
 }
 
 static void IRAM_ATTR task_yield_from_isr_wrapper(void)
@@ -206,12 +208,12 @@ static void IRAM_ATTR task_yield_from_isr_wrapper(void)
     portYIELD_FROM_ISR();
 }
 
-static void *IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init)
+static void * semphr_create_wrapper(uint32_t max, uint32_t init)
 {
     return (void *)xSemaphoreCreateCounting(max, init);
 }
 
-static void IRAM_ATTR semphr_delete_wrapper(void *semphr)
+static void semphr_delete_wrapper(void *semphr)
 {
     vSemaphoreDelete(semphr);
 }
@@ -226,7 +228,7 @@ static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
     return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
 }
 
-static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_tick)
+static int32_t semphr_take_wrapper(void *semphr, uint32_t block_time_tick)
 {
     if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
         return (int32_t)xSemaphoreTake(semphr, portMAX_DELAY);
@@ -235,22 +237,22 @@ static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_t
     }
 }
 
-static int32_t IRAM_ATTR semphr_give_wrapper(void *semphr)
+static int32_t semphr_give_wrapper(void *semphr)
 {
     return (int32_t)xSemaphoreGive(semphr);
 }
 
-static void *IRAM_ATTR recursive_mutex_create_wrapper(void)
+static void * recursive_mutex_create_wrapper(void)
 {
     return (void *)xSemaphoreCreateRecursiveMutex();
 }
 
-static void *IRAM_ATTR mutex_create_wrapper(void)
+static void * mutex_create_wrapper(void)
 {
     return (void *)xSemaphoreCreateMutex();
 }
 
-static void IRAM_ATTR mutex_delete_wrapper(void *mutex)
+static void mutex_delete_wrapper(void *mutex)
 {
     vSemaphoreDelete(mutex);
 }
@@ -265,12 +267,12 @@ static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex)
     return (int32_t)xSemaphoreGiveRecursive(mutex);
 }
 
-static void *IRAM_ATTR queue_create_wrapper(uint32_t queue_len, uint32_t item_size)
+static void * queue_create_wrapper(uint32_t queue_len, uint32_t item_size)
 {
     return (void *)xQueueCreate(queue_len, item_size);
 }
 
-static int32_t IRAM_ATTR queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick)
+static int32_t queue_send_wrapper(void *queue, void *item, uint32_t block_time_tick)
 {
     if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
         return (int32_t)xQueueSend(queue, item, portMAX_DELAY);
@@ -284,17 +286,17 @@ static int32_t IRAM_ATTR queue_send_from_isr_wrapper(void *queue, void *item, vo
     return (int32_t)xQueueSendFromISR(queue, item, hptw);
 }
 
-static int32_t IRAM_ATTR queue_send_to_back_wrapper(void *queue, void *item, uint32_t block_time_tick)
+static int32_t queue_send_to_back_wrapper(void *queue, void *item, uint32_t block_time_tick)
 {
-    return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_BACK); 
+    return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_BACK);
 }
 
-static int32_t IRAM_ATTR queue_send_to_front_wrapper(void *queue, void *item, uint32_t block_time_tick)
+static int32_t queue_send_to_front_wrapper(void *queue, void *item, uint32_t block_time_tick)
 {
     return (int32_t)xQueueGenericSend(queue, item, block_time_tick, queueSEND_TO_FRONT);
 }
 
-static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick)
+static int32_t queue_recv_wrapper(void *queue, void *item, uint32_t block_time_tick)
 {
     if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
         return (int32_t)xQueueReceive(queue, item, portMAX_DELAY);
@@ -303,7 +305,7 @@ static int32_t IRAM_ATTR queue_recv_wrapper(void *queue, void *item, uint32_t bl
     }
 }
 
-static uint32_t IRAM_ATTR event_group_wait_bits_wrapper(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick)
+static uint32_t event_group_wait_bits_wrapper(void *event, uint32_t bits_to_wait_for, int clear_on_exit, int wait_for_all_bits, uint32_t block_time_tick)
 {
     if (block_time_tick == OSI_FUNCS_TIME_BLOCKING) {
         return (uint32_t)xEventGroupWaitBits(event, bits_to_wait_for, clear_on_exit, wait_for_all_bits, portMAX_DELAY);
@@ -312,12 +314,12 @@ static uint32_t IRAM_ATTR event_group_wait_bits_wrapper(void *event, uint32_t bi
     }
 }
 
-static int32_t IRAM_ATTR task_create_pinned_to_core_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
+static int32_t task_create_pinned_to_core_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle, uint32_t core_id)
 {
     return (uint32_t)xTaskCreatePinnedToCore(task_func, name, stack_depth, param, prio, task_handle, (core_id < portNUM_PROCESSORS ? core_id : tskNO_AFFINITY));
 }
 
-static int32_t IRAM_ATTR task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle)
+static int32_t task_create_wrapper(void *task_func, const char *name, uint32_t stack_depth, void *param, uint32_t prio, void *task_handle)
 {
     return (uint32_t)xTaskCreate(task_func, name, stack_depth, param, prio, task_handle);
 }
@@ -328,16 +330,11 @@ static int32_t IRAM_ATTR task_ms_to_tick_wrapper(uint32_t ms)
 }
 
 
-static int32_t IRAM_ATTR task_get_max_priority_wrapper(void)
+static int32_t task_get_max_priority_wrapper(void)
 {
     return (int32_t)(configMAX_PRIORITIES);
 }
 
-static int32_t IRAM_ATTR phy_rf_init_wrapper(const void* init_data, uint32_t mode, void* calibration_data, uint32_t module)
-{
-    return esp_phy_rf_init( init_data, mode, calibration_data, module);
-}
-
 static void IRAM_ATTR timer_arm_wrapper(void *timer, uint32_t tmout, bool repeat)
 {
     ets_timer_arm(timer, tmout, repeat);
@@ -348,12 +345,12 @@ static void IRAM_ATTR timer_disarm_wrapper(void *timer)
     ets_timer_disarm(timer);
 }
 
-static void IRAM_ATTR timer_done_wrapper(void *ptimer)
+static void timer_done_wrapper(void *ptimer)
 {
     ets_timer_done(ptimer);
 }
 
-static void IRAM_ATTR timer_setfn_wrapper(void *ptimer, void *pfunction, void *parg)
+static void timer_setfn_wrapper(void *ptimer, void *pfunction, void *parg)
 {
     ets_timer_setfn(ptimer, pfunction, parg);
 }
@@ -363,7 +360,7 @@ static void IRAM_ATTR timer_arm_us_wrapper(void *ptimer, uint32_t us, bool repea
     ets_timer_arm_us(ptimer, us, repeat);
 }
 
-static int IRAM_ATTR get_time_wrapper(void *t)
+static int get_time_wrapper(void *t)
 {
     return os_get_time(t);
 }
@@ -373,7 +370,7 @@ static void * IRAM_ATTR malloc_internal_wrapper(size_t size)
     return heap_caps_malloc(size, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
 }
 
-static void * IRAM_ATTR realloc_internal_wrapper(void *ptr, size_t size) 
+static void * IRAM_ATTR realloc_internal_wrapper(void *ptr, size_t size)
 {
     return heap_caps_realloc(ptr, size, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
 }
@@ -392,11 +389,81 @@ static void * IRAM_ATTR zalloc_internal_wrapper(size_t size)
     return ptr;
 }
 
-static void IRAM_ATTR sc_ack_send_wrapper(void *param)
+static void sc_ack_send_wrapper(void *param)
 {
     return sc_ack_send((sc_ack_t *)param);
 }
 
+static uint32_t coex_status_get_wrapper(void)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_status_get();
+#else
+    return 0;
+#endif
+}
+
+static int coex_wifi_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_wifi_request(event, latency, duration);
+#else
+    return 0;
+#endif
+}
+
+static int coex_wifi_release_wrapper(uint32_t event)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_wifi_release(event);
+#else
+    return 0;
+#endif
+}
+
+int IRAM_ATTR coex_bt_request_wrapper(uint32_t event, uint32_t latency, uint32_t duration)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_bt_request(event, latency, duration);
+#else
+    return 0;
+#endif
+}
+
+int IRAM_ATTR coex_bt_release_wrapper(uint32_t event)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_bt_release(event);
+#else
+    return 0;
+#endif
+}
+
+int coex_register_bt_cb_wrapper(coex_func_cb_t cb)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_register_bt_cb(cb);
+#else
+    return 0;
+#endif
+}
+
+uint32_t IRAM_ATTR coex_bb_reset_lock_wrapper(void)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    return coex_bb_reset_lock();
+#else
+    return 0;
+#endif
+}
+
+void IRAM_ATTR coex_bb_reset_unlock_wrapper(uint32_t restore)
+{
+#if CONFIG_SW_COEXIST_ENABLE
+    coex_bb_reset_unlock(restore);
+#endif
+}
+
 wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._version = ESP_WIFI_OS_ADAPTER_VERSION,
     ._set_isr = set_isr_wrapper,
@@ -406,12 +473,9 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._spin_lock_delete = free,
     ._wifi_int_disable = wifi_int_disable_wrapper,
     ._wifi_int_restore = wifi_int_restore_wrapper,
-    ._task_yield = vPortYield,
     ._task_yield_from_isr = task_yield_from_isr_wrapper,
     ._semphr_create = semphr_create_wrapper,
     ._semphr_delete = semphr_delete_wrapper,
-    ._semphr_take_from_isr = semphr_take_from_isr_wrapper,
-    ._semphr_give_from_isr = semphr_give_from_isr_wrapper,
     ._semphr_take = semphr_take_wrapper,
     ._semphr_give = semphr_give_wrapper,
     ._mutex_create = mutex_create_wrapper,
@@ -426,7 +490,6 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._queue_send_to_back = queue_send_to_back_wrapper,
     ._queue_send_to_front = queue_send_to_front_wrapper,
     ._queue_recv = queue_recv_wrapper,
-    ._queue_recv_from_isr = xQueueReceiveFromISR,
     ._queue_msg_waiting = uxQueueMessagesWaiting,
     ._event_group_create = xEventGroupCreate,
     ._event_group_delete = vEventGroupDelete,
@@ -440,19 +503,15 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._task_ms_to_tick = task_ms_to_tick_wrapper,
     ._task_get_current_task = xTaskGetCurrentTaskHandle,
     ._task_get_max_priority = task_get_max_priority_wrapper,
-    ._is_in_isr = xPortInIsrContext,
     ._malloc = malloc,
     ._free = free,
     ._get_free_heap_size = esp_get_free_heap_size,
     ._rand = esp_random,
     ._dport_access_stall_other_cpu_start_wrap = esp_dport_access_stall_other_cpu_start_wrap,
     ._dport_access_stall_other_cpu_end_wrap = esp_dport_access_stall_other_cpu_end_wrap,
-    ._phy_rf_init = phy_rf_init_wrapper,
     ._phy_rf_deinit = esp_phy_rf_deinit,
     ._phy_load_cal_and_init = esp_phy_load_cal_and_init,
     ._read_mac = esp_read_mac,
-    ._timer_init = ets_timer_init,
-    ._timer_deinit = ets_timer_deinit,
     ._timer_arm = timer_arm_wrapper,
     ._timer_disarm = timer_disarm_wrapper,
     ._timer_done = timer_done_wrapper,
@@ -481,7 +540,7 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._malloc_internal =  malloc_internal_wrapper,
     ._realloc_internal = realloc_internal_wrapper,
     ._calloc_internal = calloc_internal_wrapper,
-    ._zalloc_internal = zalloc_internal_wrapper, 
+    ._zalloc_internal = zalloc_internal_wrapper,
     ._wifi_malloc = wifi_malloc,
     ._wifi_realloc = wifi_realloc,
     ._wifi_calloc = wifi_calloc,
@@ -494,5 +553,32 @@ wifi_osi_funcs_t g_wifi_osi_funcs = {
     ._modem_sleep_deregister = esp_modem_sleep_deregister,
     ._sc_ack_send = sc_ack_send_wrapper,
     ._sc_ack_send_stop = sc_ack_send_stop,
+    ._coex_status_get = coex_status_get_wrapper,
+    ._coex_wifi_request = coex_wifi_request_wrapper,
+    ._coex_wifi_release = coex_wifi_release_wrapper,
     ._magic = ESP_WIFI_OS_ADAPTER_MAGIC,
 };
+
+coex_adapter_funcs_t g_coex_adapter_funcs = {
+    ._version = COEX_ADAPTER_VERSION,
+    ._spin_lock_create = spin_lock_create_wrapper,
+    ._spin_lock_delete = free,
+    ._int_disable = wifi_int_disable_wrapper,
+    ._int_enable = wifi_int_restore_wrapper,
+    ._task_yield_from_isr = task_yield_from_isr_wrapper,
+    ._semphr_create = semphr_create_wrapper,
+    ._semphr_delete = semphr_delete_wrapper,
+    ._semphr_take_from_isr = semphr_take_from_isr_wrapper,
+    ._semphr_give_from_isr = semphr_give_from_isr_wrapper,
+    ._semphr_take = semphr_take_wrapper,
+    ._semphr_give = semphr_give_wrapper,
+    ._is_in_isr = xPortInIsrContext,
+    ._malloc_internal =  malloc_internal_wrapper,
+    ._free = free,
+    ._timer_disarm = timer_disarm_wrapper,
+    ._timer_done = timer_done_wrapper,
+    ._timer_setfn = timer_setfn_wrapper,
+    ._timer_arm_us = timer_arm_us_wrapper,
+    ._esp_timer_get_time = esp_timer_get_time,
+    ._magic = COEX_ADAPTER_MAGIC,
+};
index df04c91992e8043a3d335ede300f7e68d5133228..a93b459927cf4bad9903e926d20a94924123fd22 100644 (file)
 // limitations under the License.
 
 /******************************************************************************
- * Description: A stub to make the ESP32 debuggable by GDB over the serial 
+ * Description: A stub to make the ESP32 debuggable by GDB over the serial
  * port, at least enough to do a backtrace on panic. This gdbstub is read-only:
- * it allows inspecting the ESP32 state 
+ * it allows inspecting the ESP32 state
  *******************************************************************************/
 
+#include <string.h>
 #include "rom/ets_sys.h"
 #include "soc/uart_reg.h"
 #include "soc/io_mux_reg.h"
 #include "esp_gdbstub.h"
+#include "esp_panic.h"
 #include "driver/gpio.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "sdkconfig.h"
 
 //Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
 //implies a minimum size of about 320 bytes.
@@ -187,7 +192,7 @@ typedef struct {
 
 GdbRegFile gdbRegFile;
 
-/* 
+/*
 //Register format as the Xtensa HAL has it:
 STRUCT_FIELD (long, 4, XT_STK_EXIT,     exit)
 STRUCT_FIELD (long, 4, XT_STK_PC,       pc)
@@ -201,7 +206,7 @@ STRUCT_FIELD (long, 4, XT_STK_EXCVADDR, excvaddr)
 STRUCT_FIELD (long, 4, XT_STK_LBEG,   lbeg)
 STRUCT_FIELD (long, 4, XT_STK_LEND,   lend)
 STRUCT_FIELD (long, 4, XT_STK_LCOUNT, lcount)
-// Temporary space for saving stuff during window spill 
+// Temporary space for saving stuff during window spill
 STRUCT_FIELD (long, 4, XT_STK_TMP0,   tmp0)
 STRUCT_FIELD (long, 4, XT_STK_TMP1,   tmp1)
 STRUCT_FIELD (long, 4, XT_STK_TMP2,   tmp2)
@@ -211,24 +216,13 @@ STRUCT_FIELD (long, 4, XT_STK_OVLY,   ovly)
 STRUCT_END(XtExcFrame)
 */
 
-
-static void dumpHwToRegfile(XtExcFrame *frame) {
-       int i;
-       long *frameAregs=&frame->a0;
-       gdbRegFile.pc=frame->pc;
-       for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i];
-       for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
-       gdbRegFile.lbeg=frame->lbeg;
-       gdbRegFile.lend=frame->lend;
-       gdbRegFile.lcount=frame->lcount;
-       gdbRegFile.sar=frame->sar;
-       //All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
-       gdbRegFile.sar=frame->sar;
+static void commonRegfile() {
+       if (gdbRegFile.a[0] & 0x8000000U) gdbRegFile.a[0] = (gdbRegFile.a[0] & 0x3fffffffU) | 0x40000000U;
+       if (!esp_stack_ptr_is_sane(gdbRegFile.a[1])) gdbRegFile.a[1] = 0xDEADBEEF;
        gdbRegFile.windowbase=0; //0
        gdbRegFile.windowstart=0x1; //1
        gdbRegFile.configid0=0xdeadbeef; //ToDo
        gdbRegFile.configid1=0xdeadbeef; //ToDo
-       gdbRegFile.ps=frame->ps-PS_EXCM_MASK;
        gdbRegFile.threadptr=0xdeadbeef; //ToDo
        gdbRegFile.br=0xdeadbeef; //ToDo
        gdbRegFile.scompare1=0xdeadbeef; //ToDo
@@ -238,9 +232,23 @@ static void dumpHwToRegfile(XtExcFrame *frame) {
        gdbRegFile.m1=0xdeadbeef; //ToDo
        gdbRegFile.m2=0xdeadbeef; //ToDo
        gdbRegFile.m3=0xdeadbeef; //ToDo
-       gdbRegFile.expstate=frame->exccause; //ToDo
 }
 
+static void dumpHwToRegfile(XtExcFrame *frame) {
+       int i;
+       long *frameAregs=&frame->a0;
+       gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U;
+       for (i=0; i<16; i++) gdbRegFile.a[i]=frameAregs[i];
+       for (i=16; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
+       gdbRegFile.lbeg=frame->lbeg;
+       gdbRegFile.lend=frame->lend;
+       gdbRegFile.lcount=frame->lcount;
+       gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
+       //All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
+       gdbRegFile.sar=frame->sar;
+       commonRegfile();
+       gdbRegFile.expstate=frame->exccause; //ToDo
+}
 
 //Send the reason execution is stopped to GDB.
 static void sendReason() {
@@ -251,13 +259,114 @@ static void sendReason() {
        gdbPacketChar('T');
        i=gdbRegFile.expstate&0x7f;
        if (i<sizeof(exceptionSignal)) {
-               gdbPacketHex(exceptionSignal[i], 8); 
+               gdbPacketHex(exceptionSignal[i], 8);
        } else {
                gdbPacketHex(11, 8);
        }
        gdbPacketEnd();
 }
 
+static int sendPacket(const char * text) {
+       gdbPacketStart();
+       if (text != NULL) gdbPacketStr(text);
+       gdbPacketEnd();
+       return ST_OK;
+}
+
+#if CONFIG_GDBSTUB_SUPPORT_TASKS
+
+#define STUB_TASKS_NUM  CONFIG_GDBSTUB_MAX_TASKS
+
+//Remember the exception frame that caused panic since it's not saved in TCB
+static XtExcFrame paniced_frame;
+
+//Allows GDBStub to disable task support after a crash
+//(e.g. if GDBStub crashes while trying to get task list, e.g. due to corrupted list structures)
+static enum {
+       HANDLER_NOT_STARTED,
+       HANDLER_STARTED,
+       HANDLER_TASK_SUPPORT_DISABLED
+} handlerState;
+
+static void dumpTaskToRegfile(XtSolFrame *frame) {
+       int i;
+       long *frameAregs=&frame->a0;
+       gdbRegFile.pc=(frame->pc & 0x3fffffffU)|0x40000000U;
+       for (i=0; i<4; i++) gdbRegFile.a[i]=frameAregs[i];
+       for (i=4; i<64; i++) gdbRegFile.a[i]=0xDEADBEEF;
+       gdbRegFile.lbeg=0;
+       gdbRegFile.lend=0;
+       gdbRegFile.lcount=0;
+       gdbRegFile.ps=(frame->ps & PS_UM) ? (frame->ps & ~PS_EXCM) : frame->ps;
+       //All windows have been spilled to the stack by the ISR routines. The following values should indicate that.
+       gdbRegFile.sar=0;
+       commonRegfile();
+       gdbRegFile.expstate=0; //ToDo
+}
+
+// Fetch the task status. Returns the total number of tasks.
+static unsigned getTaskInfo(unsigned index, unsigned * handle, const char ** name, unsigned * coreId) {
+       static unsigned taskCount = 0;
+       static TaskSnapshot_t tasks[STUB_TASKS_NUM];
+
+       if (!taskCount) {
+               unsigned tcbSize = 0;
+               taskCount = uxTaskGetSnapshotAll(tasks, STUB_TASKS_NUM, &tcbSize);
+       }
+       if (index < taskCount) {
+               TaskHandle_t h = (TaskHandle_t)tasks[index].pxTCB;
+               if (handle) *handle = (unsigned)h;
+               if (name) *name = pcTaskGetTaskName(h);
+               if (coreId) *coreId = xTaskGetAffinity(h);
+       }
+       return taskCount;
+}
+
+typedef struct
+{
+       uint8_t * topOfStack;
+} DumpTCB;
+
+
+static void dumpTCBToRegFile(unsigned handle) {
+       // A task handle is a pointer to a TCB in FreeRTOS
+       DumpTCB * tcb = (DumpTCB*)handle;
+       uint8_t * pxTopOfStack = tcb->topOfStack;
+
+       //Deduced from coredump code
+       XtExcFrame * frame = (XtExcFrame*)pxTopOfStack;
+       if (frame->exit) {
+               // It's an exception frame
+               dumpHwToRegfile(frame);
+       } else {
+               XtSolFrame * taskFrame = (XtSolFrame*)pxTopOfStack;
+               dumpTaskToRegfile(taskFrame);
+       }
+}
+
+#define CUR_TASK_INDEX_NOT_SET -2
+#define CUR_TASK_INDEX_UNKNOWN -1
+
+// Get the index of the task currently running on the current CPU, and cache the result
+static int findCurrentTaskIndex() {
+       static int curTaskIndex = CUR_TASK_INDEX_NOT_SET;
+       if (curTaskIndex == CUR_TASK_INDEX_NOT_SET) {
+               unsigned curHandle = (unsigned)xTaskGetCurrentTaskHandleForCPU(xPortGetCoreID());
+               unsigned handle;
+               unsigned count = getTaskInfo(0, 0, 0, 0);
+               for(int k=0; k<(int)count; k++) {
+                       if (getTaskInfo(k, &handle, 0, 0) && curHandle == handle) {
+                               curTaskIndex = k;
+                               return curTaskIndex;
+                       }
+               }
+               curTaskIndex = CUR_TASK_INDEX_UNKNOWN;
+       }
+       return curTaskIndex;
+}
+
+#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
+
 //Handle a command as received from GDB.
 static int gdbHandleCommand(unsigned char *cmd, int len) {
        //Handle a command
@@ -270,10 +379,8 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
                gdbPacketEnd();
        } else if (cmd[0]=='G') {       //receive content for all registers from gdb
                int *p=(int*)&gdbRegFile;
-               for (i=0; i<sizeof(GdbRegFile)/4; i++) *p++=iswap(gdbGetHexVal(&data, 32));;
-               gdbPacketStart();
-               gdbPacketStr("OK");
-               gdbPacketEnd();
+               for (i=0; i<sizeof(GdbRegFile)/4; i++) *p++=iswap(gdbGetHexVal(&data, 32));
+               sendPacket("OK");
        } else if (cmd[0]=='m') {       //read memory to gdb
                i=gdbGetHexVal(&data, -1);
                data++;
@@ -285,11 +392,91 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
                gdbPacketEnd();
        } else if (cmd[0]=='?') {       //Reply with stop reason
                sendReason();
+#if CONFIG_GDBSTUB_SUPPORT_TASKS
+       } else if (handlerState != HANDLER_TASK_SUPPORT_DISABLED) {
+               if (cmd[0]=='H') { //Continue with task
+                       if (cmd[1]=='g' || cmd[1]=='c') {
+                               const char * ret = "OK";
+                               data++;
+                               i=gdbGetHexVal(&data, -1);
+                               handlerState = HANDLER_STARTED; //Hg0 is the first packet received after connect
+                               j = findCurrentTaskIndex();
+                               if (i == j || (j == CUR_TASK_INDEX_UNKNOWN && i == 0)) {
+                                       //GDB has asked us for the current task on this CPU.
+                                       //This task either was executing when we have entered the panic handler,
+                                       //or was already switched out and we have paniced during the context switch.
+                                       //Either way we are interested in the stack frame where panic has happened,
+                                       //so obtain the state from the exception frame rather than the TCB.
+                                       dumpHwToRegfile(&paniced_frame);
+                               } else {
+                                       unsigned handle, count;
+                                       //Get the handle for that task
+                                       count = getTaskInfo(i, &handle, 0, 0);
+                                       //Then extract TCB and gdbRegFile from it
+                                       if (i < count) dumpTCBToRegFile(handle);
+                                       else ret = "E00";
+                               }
+                               return sendPacket(ret);
+                       }
+                       return sendPacket(NULL);
+               } else if (cmd[0]=='T') {       //Task alive check
+                       unsigned count;
+                       data++;
+                       i=gdbGetHexVal(&data, -1);
+                       count = getTaskInfo(i, 0, 0, 0);
+                       return sendPacket(i < count ? "OK": "E00");
+               } else if (cmd[0]=='q') {       //Extended query
+                       // React to qThreadExtraInfo or qfThreadInfo or qsThreadInfo or qC, without using strcmp
+                       if (len > 16 && cmd[1] == 'T' && cmd[2] == 'h' && cmd[3] == 'r' && cmd[7] == 'E' && cmd[12] == 'I' && cmd[16] == ',') {
+                               data=&cmd[17];
+                               i=gdbGetHexVal(&data, -1);
+
+                               unsigned handle = 0, coreId = 3;
+                               const char * name = 0;
+                               // Extract the task name and CPU from freeRTOS
+                               unsigned tCount = getTaskInfo(i, &handle, &name, &coreId);
+                               if (i < tCount) {
+                                       gdbPacketStart();
+                                       for(k=0; name[k]; k++)  gdbPacketHex(name[k], 8);
+                                       gdbPacketStr("20435055"); // CPU
+                                       gdbPacketStr(coreId == 0 ? "30": coreId == 1 ? "31" : "78"); // 0 or 1 or x
+                                       gdbPacketEnd();
+                                       return ST_OK;
+                               }
+                       } else if (len >= 12 && (cmd[1] == 'f' || cmd[1] == 's') && (cmd[2] == 'T' && cmd[3] == 'h' && cmd[4] == 'r' && cmd[5] == 'e' && cmd[6] == 'a' && cmd[7] == 'd' && cmd[8] == 'I')) {
+                               // Only react to qfThreadInfo and qsThreadInfo, not using strcmp here since it can be in ROM
+                               // Extract the number of task from freeRTOS
+                               static int taskIndex = 0;
+                               unsigned tCount = 0;
+                               if (cmd[1] == 'f') {
+                                       taskIndex = 0;
+                                       handlerState = HANDLER_STARTED; //It seems it's the first request GDB is sending
+                               }
+                               tCount = getTaskInfo(0, 0, 0, 0);
+                               if (taskIndex < tCount) {
+                                       gdbPacketStart();
+                                       gdbPacketStr("m");
+                                       gdbPacketHex(taskIndex, 32);
+                                       gdbPacketEnd();
+                                       taskIndex++;
+                               } else return sendPacket("l");
+                       } else if (len >= 2 && cmd[1] == 'C') {
+                               // Get current task id
+                               gdbPacketStart();
+                               k = findCurrentTaskIndex();
+                               if (k != CUR_TASK_INDEX_UNKNOWN) {
+                                       gdbPacketStr("QC");
+                                       gdbPacketHex(k, 32);
+                               } else gdbPacketStr("bad");
+                               gdbPacketEnd();
+                               return ST_OK;
+                       }
+                       return sendPacket(NULL);
+               }
+#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
        } else {
                //We don't recognize or support whatever GDB just sent us.
-               gdbPacketStart();
-               gdbPacketEnd();
-               return ST_ERR;
+               return sendPacket(NULL);
        }
        return ST_OK;
 }
@@ -297,7 +484,7 @@ static int gdbHandleCommand(unsigned char *cmd, int len) {
 
 //Lower layer: grab a command packet and check the checksum
 //Calls gdbHandleCommand on the packet if the checksum is OK
-//Returns ST_OK on success, ST_ERR when checksum fails, a 
+//Returns ST_OK on success, ST_ERR when checksum fails, a
 //character if it is received instead of the GDB packet
 //start char.
 static int gdbReadCommand() {
@@ -344,9 +531,21 @@ static int gdbReadCommand() {
 }
 
 
-
 void esp_gdbstub_panic_handler(XtExcFrame *frame) {
+#if CONFIG_GDBSTUB_SUPPORT_TASKS
+       if (handlerState == HANDLER_STARTED) {
+               //We have re-entered GDB Stub. Try disabling task support.
+               handlerState = HANDLER_TASK_SUPPORT_DISABLED;
+               gdbPacketEnd(); // Ends up any pending GDB packet (this creates a garbage value)
+       } else if (handlerState == HANDLER_NOT_STARTED) {
+               //Need to remember the frame that panic'd since gdb will ask for all threads before ours
+               memcpy(&paniced_frame, frame, sizeof(paniced_frame));
+               dumpHwToRegfile(&paniced_frame);
+       }
+#else // CONFIG_GDBSTUB_SUPPORT_TASKS
        dumpHwToRegfile(frame);
+#endif // CONFIG_GDBSTUB_SUPPORT_TASKS
+
        //Make sure txd/rxd are enabled
        gpio_pullup_dis(1);
        PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
@@ -356,4 +555,3 @@ void esp_gdbstub_panic_handler(XtExcFrame *frame) {
        while(gdbReadCommand()!=ST_CONT);
        while(1);
 }
-
diff --git a/components/esp32/include/esp_coexist_adapter.h b/components/esp32/include/esp_coexist_adapter.h
new file mode 100644 (file)
index 0000000..f2a38c3
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright 2019 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.
+
+#ifndef __ESP_COEXIST_ADAPTER_H__
+#define __ESP_COEXIST_ADAPTER_H__
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define COEX_ADAPTER_VERSION  0x00000001
+#define COEX_ADAPTER_MAGIC    0xDEADBEAF
+
+#define COEX_ADAPTER_FUNCS_TIME_BLOCKING      0xffffffff
+
+typedef struct {
+    int32_t _version;
+    void *(* _spin_lock_create)(void);
+    void (* _spin_lock_delete)(void *lock);
+    uint32_t (*_int_disable)(void *mux);
+    void (*_int_enable)(void *mux, uint32_t tmp);
+    void (*_task_yield_from_isr)(void);
+    void *(*_semphr_create)(uint32_t max, uint32_t init);
+    void (*_semphr_delete)(void *semphr);
+    int32_t (*_semphr_take_from_isr)(void *semphr, void *hptw);
+    int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
+    int32_t (*_semphr_take)(void *semphr, uint32_t block_time_tick);
+    int32_t (*_semphr_give)(void *semphr);
+    int32_t (* _is_in_isr)(void);
+    void * (* _malloc_internal)(size_t size);
+    void (* _free)(void *p);
+    void (* _timer_disarm)(void *timer);
+    void (* _timer_done)(void *ptimer);
+    void (* _timer_setfn)(void *ptimer, void *pfunction, void *parg);
+    void (* _timer_arm_us)(void *ptimer, uint32_t us, bool repeat);
+    int64_t (* _esp_timer_get_time)(void);
+    int32_t _magic;
+} coex_adapter_funcs_t;
+
+extern coex_adapter_funcs_t g_coex_adapter_funcs;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_COEXIST_ADAPTER_H__ */
diff --git a/components/esp32/include/esp_coexist_internal.h b/components/esp32/include/esp_coexist_internal.h
new file mode 100644 (file)
index 0000000..1d94d6d
--- /dev/null
@@ -0,0 +1,163 @@
+// Copyright 2018-2018 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.
+
+#ifndef __ESP_COEXIST_INTERNAL_H__
+#define __ESP_COEXIST_INTERNAL_H__
+
+#include <stdbool.h>
+#include "esp_coexist_adapter.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    COEX_PREFER_WIFI = 0,
+    COEX_PREFER_BT,
+    COEX_PREFER_BALANCE,
+    COEX_PREFER_NUM,
+} coex_prefer_t;
+
+typedef void (* coex_func_cb_t)(uint32_t event, int sched_cnt);
+
+/**
+ * @brief Init software coexist
+ *        extern function for internal use.
+ *
+ * @return Init ok or failed.
+ */
+esp_err_t coex_init(void);
+
+/**
+ * @brief De-init software coexist
+ *        extern function for internal use.
+ */
+void coex_deinit(void);
+
+/**
+ * @brief Pause software coexist
+ *        extern function for internal use.
+ */
+void coex_pause(void);
+
+/**
+ * @brief Resume software coexist
+ *        extern function for internal use.
+ */
+void coex_resume(void);
+
+/**
+ * @brief Get software coexist version string
+ *        extern function for internal use.
+ * @return : version string
+ */
+const char *coex_version_get(void);
+
+/**
+ * @brief Coexist performance preference set from libbt.a
+ *        extern function for internal use.
+ *
+ *  @param prefer : the prefer enumeration value
+ *  @return : ESP_OK - success, other - failed
+ */
+esp_err_t coex_preference_set(coex_prefer_t prefer);
+
+/**
+ * @brief Get software coexist status.
+ * @return : software coexist status
+ */
+uint32_t coex_status_get(void);
+
+/**
+ * @brief WiFi requests coexistence.
+ *
+ *  @param event : WiFi event
+ *  @param latency : WiFi will request coexistence after latency
+ *  @param duration : duration for WiFi to request coexistence
+ *  @return : 0 - success, other - failed
+ */
+int coex_wifi_request(uint32_t event, uint32_t latency, uint32_t duration);
+
+/**
+ * @brief WiFi release coexistence.
+ *
+ *  @param event : WiFi event
+ *  @return : 0 - success, other - failed
+ */
+int coex_wifi_release(uint32_t event);
+
+/**
+ * @brief Blue tooth requests coexistence.
+ *
+ *  @param event : blue tooth event
+ *  @param latency : blue tooth will request coexistence after latency
+ *  @param duration : duration for blue tooth to request coexistence
+ *  @return : 0 - success, other - failed
+ */
+int coex_bt_request(uint32_t event, uint32_t latency, uint32_t duration);
+
+/**
+ * @brief Blue tooth release coexistence.
+ *
+ *  @param event : blue tooth event
+ *  @return : 0 - success, other - failed
+ */
+int coex_bt_release(uint32_t event);
+
+/**
+ * @brief Register callback function for blue tooth.
+ *
+ *  @param cb : callback function
+ *  @return : 0 - success, other - failed
+ */
+int coex_register_bt_cb(coex_func_cb_t cb);
+
+/**
+ * @brief Lock before reset base band.
+ *
+ *  @return : lock value
+ */
+uint32_t coex_bb_reset_lock(void);
+
+/**
+ * @brief Unlock after reset base band.
+ *
+ *  @param restore : lock value
+ */
+void coex_bb_reset_unlock(uint32_t restore);
+
+/**
+ * @brief Register coexistence adapter functions.
+ *
+ *  @param funcs : coexistence adapter functions
+ *  @return : ESP_OK - success, other - failed
+ */
+esp_err_t esp_coex_adapter_register(coex_adapter_funcs_t *funcs);
+
+/**
+  * @brief     Check the MD5 values of the coexistence adapter header files in IDF and WiFi library
+  *
+  * @attention 1. It is used for internal CI version check
+  *
+  * @return
+  *     - ESP_OK : succeed
+  *     - ESP_WIFI_INVALID_ARG : MD5 check fail
+  */
+esp_err_t esp_coex_adapter_funcs_md5_check(const char *md5);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_COEXIST_INTERNAL_H__ */
diff --git a/components/esp32/include/esp_core_dump.h b/components/esp32/include/esp_core_dump.h
deleted file mode 100644 (file)
index 4c798f5..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright 2015-2016 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.
-#ifndef ESP_CORE_DUMP_H_
-#define ESP_CORE_DUMP_H_
-
-
-/**************************************************************************************/
-/******************************** EXCEPTION MODE API **********************************/
-/**************************************************************************************/
-
-/**
- * @brief  Initializes core dump module internal data.
- *
- * @note  Should be called at system startup.
- */
-void esp_core_dump_init();
-
-/**
- * @brief  Saves core dump to flash.
- *
- * The structure of data stored in flash is as follows:
- *
- * |  TOTAL_LEN |  TASKS_NUM | TCB_SIZE |
- * | TCB_ADDR_1 | STACK_TOP_1 | STACK_END_1 | TCB_1 | STACK_1 |
- * .            .       .         .
- * .            .       .         .
- * | TCB_ADDR_N | STACK_TOP_N | STACK_END_N | TCB_N | STACK_N |
- * |    CRC32   |
- *
- * Core dump in flash consists of header and data for every task in the system at the moment of crash.
- * For flash data integrity control CRC is used at the end of core the dump data.
- * The structure of core dump data is described below in details.
- * 1) Core dump starts with header:
- * 1.1) TOTAL_LEN is total length of core dump data in flash including CRC. Size is 4 bytes.
- * 1.2) TASKS_NUM is the number of tasks for which data are stored. Size is 4 bytes.
- * 1.3) TCB_SIZE is the size of task's TCB structure. Size is 4 bytes.
- * 2) Core dump header is followed by the data for every task in the system.
- *    Task data are started with task header:
- * 2.1) TCB_ADDR is the address of TCB in memory. Size is 4 bytes.
- * 2.2) STACK_TOP is the top of task's stack (address of the topmost stack item). Size is 4 bytes.
- * 2.2) STACK_END is the end of task's stack (address from which task's stack starts). Size is 4 bytes.
- * 3) Task header is followed by TCB data. Size is TCB_SIZE bytes.
- * 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
- * 5) CRC is placed at the end of the data.
- */
-void esp_core_dump_to_flash();
-
-/**
- * @brief  Print base64-encoded core dump to UART.
- *
- * The structure of core dump data is the same as for data stored in flash (@see esp_core_dump_to_flash) with some notes:
- * 1) CRC is not present in core dump printed to UART.
- * 2) Since CRC is omitted TOTAL_LEN does not include its size.
- * 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
- */
-void esp_core_dump_to_uart();
-
-
-/**************************************************************************************/
-/*********************************** USER MODE API ************************************/
-/**************************************************************************************/
-
-/**
- * @brief  Retrieves address and size of coredump data in flash.
- *         This function is always available, even when core dump is disabled in menuconfig.
- *
- * @param  out_addr   pointer to store image address in flash.
- * @param  out_size   pointer to store image size in flash (including CRC). In bytes.
- *
- * @return ESP_OK on success, otherwise \see esp_err_t
- */
-esp_err_t esp_core_dump_image_get(size_t* out_addr, size_t *out_size);
-
-#endif
index 3bb2a77b9ff6fee1d96d4f3302429078a365b5ae..9da5230315b2adf4626d918e415e1e7bb381122f 100644 (file)
@@ -120,6 +120,10 @@ typedef struct {
     uint8_t mac[6];           /**< MAC address of the station which send probe request */
 } system_event_ap_probe_req_rx_t;
 
+typedef struct {
+    ip4_addr_t ip; 
+} system_event_ap_staipassigned_t;
+
 typedef union {
     system_event_sta_connected_t               connected;          /**< ESP32 station connected to AP */
     system_event_sta_disconnected_t            disconnected;       /**< ESP32 station disconnected to AP */
@@ -131,6 +135,7 @@ typedef union {
     system_event_ap_staconnected_t             sta_connected;      /**< a station connected to ESP32 soft-AP */
     system_event_ap_stadisconnected_t          sta_disconnected;   /**< a station disconnected to ESP32 soft-AP */
     system_event_ap_probe_req_rx_t             ap_probereqrecved;  /**< ESP32 soft-AP receive probe request packet */
+    system_event_ap_staipassigned_t            ap_staipassigned;   /**< ESP32 soft-AP assign an IP to the station*/
     system_event_got_ip6_t                     got_ip6;            /**< ESP32 station or ap or ethernet ipv6 addr state change to preferred */
 } system_event_info_t;
 
index 67bfd926d28387a2d55fdf85b0394803b6657eca..979d0134edd2485868089e875872a4646beb7840 100644 (file)
@@ -249,6 +249,15 @@ void *wifi_realloc( void *ptr, size_t size );
   */
 void *wifi_calloc( size_t n, size_t size );
 
+/**
+  * @brief     Update WiFi MAC time
+  *
+  * @param     uint32_t time_delta : time duration since the WiFi/BT common clock is disabled
+  *
+  * @return    Always returns ESP_OK
+  */
+typedef esp_err_t (* wifi_mac_time_update_cb_t)( uint32_t time_delta );
+
 /**
   * @brief     Update WiFi MAC time
   *
index 1dd522c49c0b1a8bf32608871121a877d177759b..752ccf990d77c3612d4916cf996f5671db08909d 100644 (file)
@@ -21,7 +21,7 @@
 extern "C" {
 #endif
 
-#define ESP_WIFI_OS_ADAPTER_VERSION  0x00000001
+#define ESP_WIFI_OS_ADAPTER_VERSION  0x00000002
 #define ESP_WIFI_OS_ADAPTER_MAGIC    0xDEADBEAF
 
 #define OSI_FUNCS_TIME_BLOCKING      0xffffffff
@@ -39,12 +39,9 @@ typedef struct {
     void (* _spin_lock_delete)(void *lock);
     uint32_t (*_wifi_int_disable)(void *wifi_int_mux);
     void (*_wifi_int_restore)(void *wifi_int_mux, uint32_t tmp);
-    void (*_task_yield)(void);
     void (*_task_yield_from_isr)(void);
     void *(*_semphr_create)(uint32_t max, uint32_t init);
     void (*_semphr_delete)(void *semphr);
-    int32_t (*_semphr_take_from_isr)(void *semphr, void *hptw);
-    int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
     int32_t (*_semphr_take)(void *semphr, uint32_t block_time_tick);
     int32_t (*_semphr_give)(void *semphr);
     void *(*_mutex_create)(void);
@@ -59,7 +56,6 @@ typedef struct {
     int32_t (* _queue_send_to_back)(void *queue, void *item, uint32_t block_time_tick);
     int32_t (* _queue_send_to_front)(void *queue, void *item, uint32_t block_time_tick);
     int32_t (* _queue_recv)(void *queue, void *item, uint32_t block_time_tick);
-    int32_t (* _queue_recv_from_isr)(void *queue, void * const item, int32_t * const hptw);
     uint32_t (* _queue_msg_waiting)(void *queue);
     void *(* _event_group_create)(void);
     void (* _event_group_delete)(void *event);
@@ -73,19 +69,15 @@ typedef struct {
     int32_t (* _task_ms_to_tick)(uint32_t ms);
     void *(* _task_get_current_task)(void);
     int32_t (* _task_get_max_priority)(void);
-    int32_t (* _is_in_isr)(void);
     void *(* _malloc)(uint32_t size);
     void (* _free)(void *p);
     uint32_t (* _get_free_heap_size)(void);
     uint32_t (* _rand)(void);
     void (* _dport_access_stall_other_cpu_start_wrap)(void);
     void (* _dport_access_stall_other_cpu_end_wrap)(void);
-    int32_t (* _phy_rf_init)(const void * init_data, uint32_t mode, void * calibration_data, uint32_t module);
     int32_t (* _phy_rf_deinit)(uint32_t module);
     void (* _phy_load_cal_and_init)(uint32_t module);
     int32_t (* _read_mac)(uint8_t* mac, uint32_t type);
-    void (* _timer_init)(void);
-    void (* _timer_deinit)(void);
     void (* _timer_arm)(void *timer, uint32_t tmout, bool repeat);
     void (* _timer_disarm)(void *timer);
     void (* _timer_done)(void *ptimer);
@@ -127,6 +119,9 @@ typedef struct {
     int32_t (* _modem_sleep_deregister)(uint32_t module);
     void (* _sc_ack_send)(void *param);
     void (* _sc_ack_send_stop)(void);
+    uint32_t (* _coex_status_get)(void);
+    int32_t (* _coex_wifi_request)(uint32_t event, uint32_t latency, uint32_t duration);
+    int32_t (* _coex_wifi_release)(uint32_t event);
     int32_t _magic;
 } wifi_osi_funcs_t;
 
index 84e17882de550c3163673663042e5a5f02873b15..faa1e8c351b31ffb478e77bddc5b36ed41c60199 100644 (file)
@@ -30,15 +30,48 @@ extern "C" {
   */
 
 
-/* Standard CRC8/16/32 algorithms. */
-// CRC-8        x8+x2+x1+1              0x07
-// CRC16-CCITT  x16+x12+x5+1   1021   ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS
-// CRC32:
-//G(x) = x32 +x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x1 + 1
-//If your buf is not continuous, you can use the first result to be the second parameter.
+/*           Notes about CRC APIs usage
+ * The ESP32 ROM include some CRC tables and CRC APIs to speed up CRC calculation.
+ * The CRC APIs include CRC8, CRC16, CRC32 algorithms for both little endian and big endian modes.
+ * Here are the polynomials for the algorithms:
+ * CRC-8        x8+x2+x1+1                                              0x07
+ * CRC16-CCITT  x16+x12+x5+1                                            0x1021
+ * CRC32        x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1     0x04c11db7
+ * 
+ * These group of CRC APIs are designed to calculate the data in buffers either continuous or not.
+ * To make it easy, we had added a `~` at the beginning and the end of the functions.
+ * To calculate non-continuous buffers, we can write the code like this:
+ *     init = ~init;
+ *     crc = crc32_le(init, buf0, length0);
+ *     crc = crc32_le(crc, buf1, length1);
+ *     crc = ~crc;
+ *
+ * However, it is not easy to select which API to use and give the correct parameters.
+ * A specific CRC algorithm will include this parameters: width, polynomials, init, refin, refout, xorout
+ *     refin and refout show the endian of the algorithm:
+ *         if both of them are true, please use the little endian API.
+ *         if both of them are false, please use the big endian API.
+ *     xorout is the value which you need to be xored to the raw result.
+ * However, these group of APIs need one '~' before and after the APIs.
+ *
+ * Here are some examples for CRC16:
+ * CRC-16/CCITT, poly = 0x1021, init = 0x0000, refin = true, refout = true, xorout = 0x0000
+ *     crc = ~crc16_le((uint16_t)~0x0000, buf, length);
+ * 
+ * CRC-16/CCITT-FALSE, poly = 0x1021, init = 0xffff, refin = false, refout = false, xorout = 0x0000
+ *     crc = ~crc16_be((uint16_t)~0xffff, buf, length);
+ *
+ * CRC-16/X25, poly = 0x1021, init = 0xffff, refin = true, refout = true, xorout = 0xffff
+ *     crc = (~crc16_le((uint16_t)~(0xffff), buf, length))^0xffff;
+ *
+ * CRC-16/XMODEM, poly= 0x1021, init = 0x0000, refin = false, refout = false, xorout = 0x0000
+ *     crc = ~crc16_be((uint16_t)~0x0000, buf, length);
+ *
+ *     
+ */
 
 /**
-  * @brief Crc32 value that is in little endian.
+  * @brief CRC32 value that is in little endian.
   *
   * @param  uint32_t crc : init crc value, use 0 at the first use.
   *
@@ -51,7 +84,7 @@ extern "C" {
 uint32_t crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len);
 
 /**
-  * @brief Crc32 value that is in big endian.
+  * @brief CRC32 value that is in big endian.
   *
   * @param  uint32_t crc : init crc value, use 0 at the first use.
   *
@@ -64,7 +97,7 @@ uint32_t crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len);
 uint32_t crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len);
 
 /**
-  * @brief Crc16 value that is in little endian.
+  * @brief CRC16 value that is in little endian.
   *
   * @param  uint16_t crc : init crc value, use 0 at the first use.
   *
@@ -77,7 +110,7 @@ uint32_t crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len);
 uint16_t crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len);
 
 /**
-  * @brief Crc16 value that is in big endian.
+  * @brief CRC16 value that is in big endian.
   *
   * @param  uint16_t crc : init crc value, use 0 at the first use.
   *
@@ -90,7 +123,7 @@ uint16_t crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len);
 uint16_t crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len);
 
 /**
-  * @brief Crc8 value that is in little endian.
+  * @brief CRC8 value that is in little endian.
   *
   * @param  uint8_t crc : init crc value, use 0 at the first use.
   *
@@ -103,7 +136,7 @@ uint16_t crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len);
 uint8_t crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len);
 
 /**
-  * @brief Crc8 value that is in big endian.
+  * @brief CRC8 value that is in big endian.
   *
   * @param  uint32_t crc : init crc value, use 0 at the first use.
   *
index c6097332214f0b7c6e719843c20c9004d2b00a51..3260ca809c6d94668d3bbd27918433049ebeebcb 100644 (file)
@@ -118,7 +118,7 @@ const static int_desc_t int_desc[32]={
     { 3, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_NORMAL} }, //23
     { 4, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_NORMAL} }, //24
     { 4, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //25
-    { 5, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //26
+    { 5, INTTP_LEVEL, {INTDESC_NORMAL, INTDESC_RESVD } }, //26
     { 3, INTTP_LEVEL, {INTDESC_RESVD,  INTDESC_RESVD } }, //27
     { 4, INTTP_EDGE,  {INTDESC_NORMAL, INTDESC_NORMAL} }, //28
     { 3, INTTP_NA,    {INTDESC_SPECIAL,INTDESC_SPECIAL}}, //29
index aa6fe8cd2ec3f8a7e01490c81a5a83a5c322e8c6..61530b0bddb1de1cdcc73b8aa5f290da970bd1fe 160000 (submodule)
@@ -1 +1 @@
-Subproject commit aa6fe8cd2ec3f8a7e01490c81a5a83a5c322e8c6
+Subproject commit 61530b0bddb1de1cdcc73b8aa5f290da970bd1fe
index d72f60dc0c2e682c0788000208476b874db03a02..18b3fa8b43e7dcc3c686a3edf4f858fdb3034284 100644 (file)
 #include "freertos/portmacro.h"
 #include "phy.h"
 #include "phy_init_data.h"
-#include "coexist_internal.h"
+#include "esp_coexist_internal.h"
 #include "driver/periph_ctrl.h"
 #include "esp_wifi_internal.h"
 
+extern wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb;
 
 static const char* TAG = "phy_init";
 
@@ -92,7 +93,9 @@ static inline void phy_update_wifi_mac_time(bool en_clock_stopped, int64_t now)
         if (s_common_clock_disable_time) {
             uint32_t diff = (uint64_t)now - s_common_clock_disable_time;
 
-            esp_wifi_internal_update_mac_time(diff);
+            if (s_wifi_mac_time_update_cb) {
+                s_wifi_mac_time_update_cb(diff);
+            }
             s_common_clock_disable_time = 0;
             ESP_LOGD(TAG, "wifi mac time delta: %u", diff);
         }
@@ -159,14 +162,6 @@ esp_err_t esp_phy_rf_init(const esp_phy_init_data_t* init_data, esp_phy_calibrat
 #endif
             }
 
-
-extern esp_err_t wifi_osi_funcs_register(wifi_osi_funcs_t *osi_funcs);
-            status = wifi_osi_funcs_register(&g_wifi_osi_funcs);
-            if(status != ESP_OK) {
-                ESP_LOGE(TAG, "failed to register wifi os adapter, ret(%d)", status);
-                _lock_release(&s_phy_rf_init_lock);
-                return ESP_FAIL;
-            }
             coex_bt_high_prio();
         }
     }
index 939b386a5694e7db3c6506f589218883983ba99d..b99e2888b6ecbccadea7ae6d09f57019fcbbfcdb 100644 (file)
@@ -21,9 +21,16 @@ execute_process(COMMAND md5sum ${IDF_PATH}/components/esp32/include/esp_wifi_cry
                 COMMAND cut -c 1-7
                 OUTPUT_VARIABLE WIFI_CRYPTO_MD5
                 OUTPUT_STRIP_TRAILING_WHITESPACE)
+                
+# Calculate MD5 value of header file esp_coexist_adapter.h
+execute_process(COMMAND md5sum ${IDF_PATH}/components/esp32/include/esp_coexist_adapter.h
+                COMMAND cut -c 1-7
+                OUTPUT_VARIABLE COEX_ADAPTER_MD5
+                OUTPUT_STRIP_TRAILING_WHITESPACE)
 
 add_definitions(-DWIFI_OS_ADAPTER_MD5=\"${WIFI_OS_ADAPTER_MD5}\")
 add_definitions(-DWIFI_CRYPTO_MD5=\"${WIFI_CRYPTO_MD5}\")
+add_definitions(-DCOEX_ADAPTER_MD5=\"${COEX_ADAPTER_MD5}\")
 
 add_custom_target(esp32_test_logo DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/test_tjpgd_logo.h")
 
index 11e0f7ed7c430a0b56c2af386667fe7a5dad137a..6fb41f30a6ab4c3be3847417dace663a3854e540 100644 (file)
@@ -16,6 +16,9 @@ CFLAGS+=-DWIFI_OS_ADAPTER_MD5=$(WIFI_OS_ADAPTER_MD5_VAL)
 WIFI_CRYPTO_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp32/include/esp_wifi_crypto_types.h | cut -c 1-7)\"
 CFLAGS+=-DWIFI_CRYPTO_MD5=$(WIFI_CRYPTO_MD5_VAL)
 
+# Calculate MD5 value of header file esp_coexist_adapter.h
+COEX_ADAPTER_MD5_VAL=\"$(shell md5sum $(IDF_PATH)/components/esp32/include/esp_coexist_adapter.h | cut -c 1-7)\"
+CFLAGS+=-DCOEX_ADAPTER_MD5=$(COEX_ADAPTER_MD5_VAL)
 
 test_tjpgd.o: test_tjpgd_logo.h
 
index 009de0ea59e47dfd42d68f8e5b744e26273b9d72..c2d80350ac190a48192e652d40b984b96fa73a0a 100644 (file)
@@ -4,6 +4,7 @@
 #include "unity.h"
 #include "esp_log.h"
 #include "esp_wifi_internal.h"
+#include "esp_coexist_internal.h"
 
 static const char* TAG = "test_header_files_md5";
 
@@ -26,3 +27,13 @@ TEST_CASE("wifi crypto types MD5","[wifi]")
 
     ESP_LOGI(TAG, "test passed...");
 }
+
+TEST_CASE("coexist adapter MD5","[coex]")
+{
+    const char *test_coex_adapter_funcs_md5 = COEX_ADAPTER_MD5;
+
+    ESP_LOGI(TAG, "test coexist adapter MD5...");
+    TEST_ESP_OK(esp_coex_adapter_funcs_md5_check(test_coex_adapter_funcs_md5));
+
+    ESP_LOGI(TAG, "test passed...");
+}
index 2b3dae6b01edc5c19298434dd64fcdea20e7cb2f..cf5d79b7b8ceca4eacb6d6c9dd50273ed0ccffc6 100644 (file)
@@ -27,6 +27,9 @@ mesh_event_cb_t g_mesh_event_cb = NULL;
 static esp_pm_lock_handle_t s_wifi_modem_sleep_lock;
 #endif
 
+/* Callback function to update WiFi MAC time */
+wifi_mac_time_update_cb_t s_wifi_mac_time_update_cb = NULL;
+
 static void __attribute__((constructor)) s_set_default_wifi_log_level()
 {
     /* WiFi libraries aren't compiled to know CONFIG_LOG_DEFAULT_LEVEL,
@@ -97,7 +100,10 @@ esp_err_t esp_wifi_init(const wifi_init_config_t *config)
 #endif
     esp_event_set_default_wifi_handlers();
     esp_err_t result = esp_wifi_init_internal(config);
-    esp_wifi_set_debug_log();
+    if (result == ESP_OK) {
+        esp_wifi_set_debug_log();
+        s_wifi_mac_time_update_cb = esp_wifi_internal_update_mac_time;
+    }
 
     return result;
 }
index 2921c0d33508566b931e61a2255c7cdc7f3d8cf4..91d344e055da21c9960c25fe769a4473e94e3dc9 100644 (file)
@@ -487,7 +487,9 @@ esp_http_client_handle_t esp_http_client_init(const esp_http_client_config_t *co
         goto error;
     }
 
-    if (config->cert_pem) {
+    if (config->use_global_ca_store == true) {
+        esp_transport_ssl_enable_global_ca_store(ssl);
+    } else if (config->cert_pem) {
         esp_transport_ssl_set_cert_data(ssl, config->cert_pem, strlen(config->cert_pem));
     }
 
index 77e9d85208564dba2a3bb3d5956473726926c1b4..160d16fa5940a1c760c28fd2b19c413119658deb 100644 (file)
@@ -117,6 +117,7 @@ typedef struct {
     int                         buffer_size;              /*!< HTTP buffer size (both send and receive) */
     void                        *user_data;               /*!< HTTP user_data context */
     bool                        is_async;                 /*!< Set asynchronous mode, only supported with HTTPS for now */
+    bool                        use_global_ca_store;      /*!< Use a global ca_store for all the connections in which this bool is set. */
 } esp_http_client_config_t;
 
 
index 842848c59077a1bcbb886eb4ca415bea2e523997..4094d9ef82263a60209abf347631320968579323 100644 (file)
@@ -362,6 +362,18 @@ typedef struct httpd_req {
      * function for freeing the session context, please specify that here.
      */
     httpd_free_ctx_fn_t free_ctx;
+
+    /**
+     * Flag indicating if Session Context changes should be ignored
+     *
+     * By default, if you change the sess_ctx in some URI handler, the http server
+     * will internally free the earlier context (if non NULL), after the URI handler
+     * returns. If you want to manage the allocation/reallocation/freeing of
+     * sess_ctx yourself, set this flag to true, so that the server will not
+     * perform any checks on it. The context will be cleared by the server
+     * (by calling free_ctx or free()) only if the socket gets closed.
+     */
+    bool ignore_sess_ctx_changes;
 } httpd_req_t;
 
 /**
index 0a13361bb62d3b763d52ef2c8eb5f56b97f550df..d0cdfd0fda7251d9a9e85f755583b20879c9145e 100644 (file)
@@ -60,6 +60,7 @@ struct thread_data {
 struct sock_db {
     int fd;                                 /*!< The file descriptor for this socket */
     void *ctx;                              /*!< A custom context for this socket */
+    bool ignore_sess_ctx_changes;           /*!< Flag indicating if session context changes should be ignored */
     void *transport_ctx;                    /*!< A custom 'transport' context for this socket, to be used by send/recv/pending */
     httpd_handle_t handle;                  /*!< Server handle */
     httpd_free_ctx_fn_t free_ctx;      /*!< Function for freeing the context */
index aa40809f1e872578c76652ba6b8c28f6d67855f5..2837778e040f091074206bcd5af168dd1cdb0dad 100644 (file)
@@ -588,6 +588,7 @@ static void init_req(httpd_req_t *r, httpd_config_t *config)
     r->user_ctx = 0;
     r->sess_ctx = 0;
     r->free_ctx = 0;
+    r->ignore_sess_ctx_changes = 0;
 }
 
 static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
@@ -607,13 +608,14 @@ static void httpd_req_cleanup(httpd_req_t *r)
 {
     struct httpd_req_aux *ra = r->aux;
 
-    /* Retrieve session info from the request into the socket database */
-    if (ra->sd->ctx != r->sess_ctx) {
-        /* Free previous context */
+    /* Check if the context has changed and needs to be cleared */ 
+    if ((r->ignore_sess_ctx_changes == false) && (ra->sd->ctx != r->sess_ctx)) {
         httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
-        ra->sd->ctx = r->sess_ctx;
     }
+    /* Retrieve session info from the request into the socket database. */
+    ra->sd->ctx = r->sess_ctx;
     ra->sd->free_ctx = r->free_ctx;
+    ra->sd->ignore_sess_ctx_changes = r->ignore_sess_ctx_changes;
 
     /* Clear out the request and request_aux structures */
     ra->sd = NULL;
@@ -641,6 +643,7 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
     /* Copy session info to the request */
     r->sess_ctx = sd->ctx;
     r->free_ctx = sd->free_ctx;
+    r->ignore_sess_ctx_changes = sd->ignore_sess_ctx_changes;
     /* Parse request */
     esp_err_t err = httpd_parse_req(hd);
     if (err != ESP_OK) {
index f44812466c051892381ad4741d7689f523338336..010be37e27637d108b2fcba623255b744d8a75cc 100644 (file)
@@ -36,8 +36,8 @@ esp_err_t esp_https_ota(const esp_http_client_config_t *config)
     }
 
 #if !CONFIG_OTA_ALLOW_HTTP
-    if (!config->cert_pem) {
-        ESP_LOGE(TAG, "Server certificate not found in esp_http_client config");
+    if (!config->cert_pem && !config->use_global_ca_store) {
+        ESP_LOGE(TAG, "Server certificate not found, either through configuration or global CA store");
         return ESP_ERR_INVALID_ARG;
     }
 #endif
index 5201f1e94d68fe60151f3b29da7239c7c6e4e02b..e19b45c98adb4f71a0505b87ab271aa05c13df90 100644 (file)
 #ifndef ESP_CORE_DUMP_H_
 #define ESP_CORE_DUMP_H_
 
+#include <stddef.h>
+#include "esp_err.h"
+#include "freertos/xtensa_context.h"
+
 /**************************************************************************************/
 /******************************** EXCEPTION MODE API **********************************/
 /**************************************************************************************/
@@ -54,7 +58,7 @@ void esp_core_dump_init();
  * 4) Task's stack is placed after TCB data. Size is (STACK_END - STACK_TOP) bytes.
  * 5) CRC is placed at the end of the data.
  */
-void esp_core_dump_to_flash();
+void esp_core_dump_to_flash(XtExcFrame *frame);
 
 /**
  * @brief  Print base64-encoded core dump to UART.
@@ -64,7 +68,7 @@ void esp_core_dump_to_flash();
  * 2) Since CRC is omitted TOTAL_LEN does not include its size.
  * 3) Printed base64 data are surrounded with special messages to help user recognize the start and end of actual data.
  */
-void esp_core_dump_to_uart();
+void esp_core_dump_to_uart(XtExcFrame *frame);
 
 
 /**************************************************************************************/
index 71072ab0a67b709927037f4bb6fe8646ee9997fc..30d13caefcc814b4ce20e5f104eb8889f449f214 100644 (file)
@@ -3,4 +3,5 @@ archive: libespcoredump.a
 entries: 
     core_dump_uart (noflash_text)
     core_dump_flash (noflash_text)
-    core_dump_common (noflash_text)
\ No newline at end of file
+    core_dump_common (noflash_text)
+    core_dump_port (noflash_text)
\ No newline at end of file
index ff6da5b8a2acd3aa7f092c24223371962ea2b6b6..2d05f11a73f01e856ef0dfcc88726c6f27aa121a 100644 (file)
@@ -5,9 +5,9 @@ endif()
 # Set some global esptool.py variables
 #
 # Many of these are read when generating flash_app_args & flash_project_args
-set(ESPTOOLPY "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
-set(ESPSECUREPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
-set(ESPEFUSEPY "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
+set(ESPTOOLPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/esptool.py" --chip esp32)
+set(ESPSECUREPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
+set(ESPEFUSEPY ${PYTHON} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
 
 set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE})
 set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ})
index c7965a1f23420d43c379fdfaf976a539646b3a60..0d8173a6543fbcc3cb0a8dd122caa4abe6b48946 100644 (file)
 #define MB_ENTER_CRITICAL(mux)      portENTER_CRITICAL(mux)
 #define MB_EXIT_CRITICAL(mux)       portEXIT_CRITICAL(mux)
 
-#define ENTER_CRITICAL_SECTION( )   ( vMBPortEnterCritical() )
-#define EXIT_CRITICAL_SECTION( )    ( vMBPortExitCritical() )
+#define ENTER_CRITICAL_SECTION( ) { ESP_LOGD(MB_PORT_TAG,"%s: Port enter critical.", __func__); \
+                                    vMBPortEnterCritical(); }
+
+#define EXIT_CRITICAL_SECTION( )  { vMBPortExitCritical(); \
+                                    ESP_LOGD(MB_PORT_TAG,"%s: Port exit critical", __func__); }
 
 typedef char    BOOL;
 
index e4b90e64c074f608d32637d1083f90fa6c7bea89..a789545598beaff5e1c5454bdf60b4d07dc47fab 100644 (file)
 #include <stdlib.h>
 #include <freertos/FreeRTOS.h>
 #include <freertos/task.h>
-#include <freertos/semphr.h>
 
 /* ----------------------- Modbus includes ----------------------------------*/
 #include "mb.h"
 #include "mbport.h"
+#include "sys/lock.h"
 
 /* ----------------------- Modbus includes ----------------------------------*/
 
 /* ----------------------- Variables ----------------------------------------*/
-static portMUX_TYPE mb_mutex = portMUX_INITIALIZER_UNLOCKED;
+static _lock_t s_port_lock;
 
 /* ----------------------- Start implementation -----------------------------*/
 
@@ -52,16 +52,16 @@ bMBPortIsWithinException( void )
     return bIsWithinException;
 }
 
-void
+inline void
 vMBPortEnterCritical( void )
 {
-    portENTER_CRITICAL(&mb_mutex);
+    _lock_acquire(&s_port_lock);
 }
 
-void
+inline void
 vMBPortExitCritical( void )
 {
-    portEXIT_CRITICAL(&mb_mutex);
+    _lock_release(&s_port_lock);
 }
 
 void
index 3543135ee3deaf1009f810c43e3e2af15f2cca8b..dee5fdd365e86dd990f72334e099e04506382993 100644 (file)
@@ -74,7 +74,6 @@ static USHORT uiRxBufferPos = 0;    // position in the receiver buffer
 void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
 {
     // This function can be called from xMBRTUTransmitFSM() of different task
-    ENTER_CRITICAL_SECTION();
     if (bRxEnable) {
         //uart_enable_rx_intr(ucUartNumber);
         bRxStateEnabled = TRUE;
@@ -88,7 +87,6 @@ void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable)
     } else {
         bTxStateEnabled = FALSE;
     }
-    EXIT_CRITICAL_SECTION();
 }
 
 static void vMBPortSerialRxPoll(size_t xEventSize)
index 63f01a68542cdaa6ee1b0000f4aeda347b235429..5e0c1a6780bdec8e645f5d58ff5cea34ac60ea8a 100644 (file)
@@ -475,7 +475,9 @@ static void send_offer(struct dhcps_msg *m, u16_t len)
     u8_t *data;
     u16_t cnt = 0;
     u16_t i;
+#if DHCPS_DEBUG
     err_t SendOffer_err_t;
+#endif
     create_msg(m);
 
     end = add_msg_type(&m->options[4], DHCPOFFER);
@@ -523,8 +525,12 @@ static void send_offer(struct dhcps_msg *m, u16_t len)
 
     ip_addr_t ip_temp = IPADDR4_INIT(0x0);
     ip4_addr_set(ip_2_ip4(&ip_temp), &broadcast_dhcps);
+#if DHCPS_DEBUG
     SendOffer_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
     DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t);
+#else
+    udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
+#endif
 
     if (p->ref != 0) {
 #if DHCPS_DEBUG
index e2a24de6603c896a5ddacac296c0304002376eae..fe9a58cb7abdc74e7a2196b7c4e0a29ff9042f88 160000 (submodule)
@@ -1 +1 @@
-Subproject commit e2a24de6603c896a5ddacac296c0304002376eae
+Subproject commit fe9a58cb7abdc74e7a2196b7c4e0a29ff9042f88
index 84d578b3c26d7959cb2c2b5ad2564e8df8b4c653..40b2cc038f2d1420956425fe35dee20de88521a4 100644 (file)
@@ -3074,7 +3074,7 @@ static void _mdns_search_free(mdns_search_once_t * search)
     free(search->instance);
     free(search->service);
     free(search->proto);
-    vSemaphoreDelete(search->lock);
+    vSemaphoreDelete(search->done_semaphore);
     free(search);
 }
 
@@ -3090,8 +3090,8 @@ static mdns_search_once_t * _mdns_search_init(const char * name, const char * se
     }
     memset(search, 0, sizeof(mdns_search_once_t));
 
-    search->lock = xSemaphoreCreateMutex();
-    if (!search->lock) {
+    search->done_semaphore = xSemaphoreCreateBinary();
+    if (!search->done_semaphore) {
         free(search);
         return NULL;
     }
@@ -3130,8 +3130,6 @@ static mdns_search_once_t * _mdns_search_init(const char * name, const char * se
     search->started_at = xTaskGetTickCount() * portTICK_PERIOD_MS;
     search->next = NULL;
 
-    xSemaphoreTake(search->lock, 0);
-
     return search;
 }
 
@@ -3142,7 +3140,7 @@ static void _mdns_search_finish(mdns_search_once_t * search)
 {
     search->state = SEARCH_OFF;
     queueDetach(mdns_search_once_t, _mdns_server->search_once, search);
-    xSemaphoreGive(search->lock);
+    xSemaphoreGive(search->done_semaphore);
 }
 
 /**
@@ -4148,7 +4146,7 @@ void mdns_free()
         free(h->instance);
         free(h->service);
         free(h->proto);
-        vSemaphoreDelete(h->lock);
+        vSemaphoreDelete(h->done_semaphore);
         if (h->result) {
             mdns_query_results_free(h->result);
         }
@@ -4543,7 +4541,7 @@ esp_err_t mdns_query(const char * name, const char * service, const char * proto
         _mdns_search_free(search);
         return ESP_ERR_NO_MEM;
     }
-    xSemaphoreTake(search->lock, portMAX_DELAY);
+    xSemaphoreTake(search->done_semaphore, portMAX_DELAY);
 
     *results = search->result;
     _mdns_search_free(search);
index 934b9427e2bcf1f4edddbc05c412e9119d3f5988..9efd23ae70cdc5466f2f56c6c1698aef506ce8eb 100644 (file)
 #define PCB_STATE_IS_ANNOUNCING(s) (s->state > PCB_PROBE_3 && s->state < PCB_RUNNING)
 #define PCB_STATE_IS_RUNNING(s) (s->state == PCB_RUNNING)
 
-#define MDNS_SEARCH_LOCK()      xSemaphoreTake(_mdns_server->search.lock, portMAX_DELAY)
-#define MDNS_SEARCH_UNLOCK()    xSemaphoreGive(_mdns_server->search.lock)
-
 #ifndef HOOK_MALLOC_FAILED
 #define HOOK_MALLOC_FAILED  ESP_LOGE(TAG, "Cannot allocate memory (line: %d, free heap: %d bytes)", __LINE__, esp_get_free_heap_size());
 #endif
@@ -318,7 +315,7 @@ typedef struct mdns_search_once_s {
     uint32_t started_at;
     uint32_t sent_at;
     uint32_t timeout;
-    SemaphoreHandle_t lock;
+    SemaphoreHandle_t done_semaphore;
     uint16_t type;
     uint8_t max_results;
     uint8_t num_results;
index 34045ae7778396649572e185b0be08e05afd7c71..c42fd09353e257ddaa02694e39ae5a5fbaa82c71 100644 (file)
@@ -40,6 +40,13 @@ esp_transport_handle_t esp_transport_ssl_init();
  */
 void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len);
 
+/**
+ * @brief      Enable global CA store for SSL connection
+ *
+ * @param      t    ssl transport
+ */
+void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t);
+
 /**
  * @brief      Set SSL client certificate data for mutual authentication (as PEM format).
  *             Note that, this function stores the pointer to data, rather than making a copy.
index 59ff64de5dd22a72eb481a671c1ec7903504f68b..1ea40498780b290fa3989db335421faaf74ecf01 100644 (file)
@@ -155,6 +155,14 @@ static int ssl_destroy(esp_transport_handle_t t)
     return 0;
 }
 
+void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t)
+{
+    transport_ssl_t *ssl = esp_transport_get_context_data(t);
+    if (t && ssl) {
+        ssl->cfg.use_global_ca_store = true;
+    }
+}
+
 void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len)
 {
     transport_ssl_t *ssl = esp_transport_get_context_data(t);
index 70ea3830c89ac810b35a8421259f8de77a9bc598..443fa54bb45eb8c73791ac48b05b37c9169f3669 100644 (file)
@@ -91,7 +91,9 @@ static void tcpip_adapter_dhcps_cb(u8_t client_ip[4])
     ESP_LOGI(TAG,"softAP assign IP to station,IP is: %d.%d.%d.%d",
                 client_ip[0],client_ip[1],client_ip[2],client_ip[3]);
     system_event_t evt;
+    memset(&evt, 0, sizeof(system_event_t));
     evt.event_id = SYSTEM_EVENT_AP_STAIPASSIGNED;
+    memcpy((char *)&evt.event_info.ap_staipassigned.ip.addr, (char *)client_ip, sizeof(evt.event_info.ap_staipassigned.ip.addr));
     esp_event_send(&evt);
 }
 
@@ -429,6 +431,7 @@ esp_err_t tcpip_adapter_set_ip_info(tcpip_adapter_if_t tcpip_if, const tcpip_ada
         if (tcpip_if == TCPIP_ADAPTER_IF_STA || tcpip_if == TCPIP_ADAPTER_IF_ETH) {
             if (!(ip4_addr_isany_val(ip_info->ip) || ip4_addr_isany_val(ip_info->netmask) || ip4_addr_isany_val(ip_info->gw))) {
                 system_event_t evt;
+                memset(&evt, 0, sizeof(system_event_t));
                 if (tcpip_if == TCPIP_ADAPTER_IF_STA) {
                     evt.event_id = SYSTEM_EVENT_STA_GOT_IP;
                 } else if (tcpip_if == TCPIP_ADAPTER_IF_ETH) {
@@ -461,6 +464,7 @@ static void tcpip_adapter_nd6_cb(struct netif *p_netif, uint8_t ip_idex)
     tcpip_adapter_ip6_info_t *ip6_info;
 
     system_event_t evt;
+    memset(&evt, 0, sizeof(system_event_t));
     //notify event
 
     evt.event_id = SYSTEM_EVENT_GOT_IP6;
@@ -896,6 +900,7 @@ static void tcpip_adapter_dhcpc_cb(struct netif *netif)
                 !ip4_addr_cmp(ip_2_ip4(&netif->netmask), (&ip_info->netmask)) ||
                 !ip4_addr_cmp(ip_2_ip4(&netif->gw), (&ip_info->gw)) ) {
             system_event_t evt;
+            memset(&evt, 0, sizeof(system_event_t));
 
             ip4_addr_set(&ip_info->ip, ip_2_ip4(&netif->ip_addr));
             ip4_addr_set(&ip_info->netmask, ip_2_ip4(&netif->netmask));
@@ -971,6 +976,7 @@ static void tcpip_adapter_ip_lost_timer(void *arg)
 
         if ( (!netif) || (netif && ip4_addr_cmp(ip_2_ip4(&netif->ip_addr), IP4_ADDR_ANY4))){
             system_event_t evt;
+            memset(&evt, 0, sizeof(system_event_t));
 
             ESP_LOGD(TAG, "if%d ip lost tmr: raise ip lost event", tcpip_if);
             memset(&esp_ip_old[tcpip_if], 0, sizeof(tcpip_adapter_ip_info_t));
index b4cfcd4bafe969ba80904e48634b50b1b23e793f..49654e84f4bbb3f01246fa1305fc0543bea86fd8 100644 (file)
@@ -28,7 +28,7 @@ if(NOT as_version STREQUAL as_supported_version)
                     the toolchain, or proceed at your own risk.")
 endif()
 
-set(ULP_MAP_GEN ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
+set(ULP_MAP_GEN ${PYTHON} ${IDF_PATH}/components/ulp/esp32ulp_mapgen.py)
 set(ULP_LD_TEMPLATE ${IDF_PATH}/components/ulp/ld/esp32.ulp.ld)
 
 get_filename_component(sdkconfig_dir ${SDKCONFIG} DIRECTORY)
diff --git a/docs/_static/jtag-debugging-overview_zh.jpg b/docs/_static/jtag-debugging-overview_zh.jpg
new file mode 100644 (file)
index 0000000..6a50e6a
Binary files /dev/null and b/docs/_static/jtag-debugging-overview_zh.jpg differ
index 87bf6b3974a7aec0ff7352fe0e12c28fb15a4bf4..4d22b290372b5f4543aa3ba441adf665d3a3f1da 100755 (executable)
@@ -18,8 +18,7 @@ fi
 # the Sphinx warning log
 # (escape char removal from https://www.commandlinefu.com/commands/view/6141/remove-color-codes-special-characters-with-sed
 sed -r 's:\x1B\[[0-9;]*[mK]::g' sphinx-warning-log.txt | \
-    sed -E "s~${IDF_PATH}~\${IDF_PATH}~" | \
-    sed -E "s/:[0-9]+:/:line:/" > sphinx-warning-log-sanitized.txt
+    sed -E "s/.*\/(.*):[0-9]+:/\1:line:/" > sphinx-warning-log-sanitized.txt
 
 # diff sanitized warnings, ignoring lines which only appear in ../sphinx-known-warnings.txt
 
index 14b138ca804c3a932fca57972ea29a13e20e7378..813857b617dd5c1d84438a92d6c388d1f55f4596 100644 (file)
@@ -1,6 +1,7 @@
 Build System (CMake)
 ********************
 
+:link_to_translation:`zh_CN:[中文]`
 .. include:: ../cmake-warning.rst
 
 .. include:: ../cmake-pending-features.rst
@@ -161,7 +162,7 @@ When adding custom non-build steps like "flash" to the IDE, it is recommended to
 
 For more detailed information about integrating ESP-IDF with CMake into an IDE, see `Build System Metadata`_.
 
-.. setting-python-interpreter:
+.. _setting-python-interpreter:
 
 Setting the Python Interpreter
 ------------------------------
@@ -232,7 +233,6 @@ Minimal Example CMakeLists
 Minimal project::
 
       cmake_minimum_required(VERSION 3.5)
-
       include($ENV{IDF_PATH}/tools/cmake/project.cmake)
       project(myProject)
 
@@ -242,9 +242,9 @@ Minimal project::
 Mandatory Parts
 ---------------
 
-The inclusion of these four lines, in the order shown above, is necessary for every project:
+The inclusion of these three lines, in the order shown above, is necessary for every project:
 
-- ``cmake_minimum_required(VERSION 3.5)`` tells CMake what version is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file.
+- ``cmake_minimum_required(VERSION 3.5)`` tells CMake the minimum version that is required to build the project. ESP-IDF is designed to work with CMake 3.5 or newer. This line must be the first line in the CMakeLists.txt file.
 - ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` pulls in the rest of the CMake functionality to configure the project, discover all the components, etc.
 - ``project(myProject)`` creates the project itself, and specifies the project name. The project name is used for the final binary output files of the app - ie ``myProject.elf``, ``myProject.bin``. Only one project can be defined per CMakeLists file.
 
@@ -330,22 +330,22 @@ Preset Component Variables
 
 The following component-specific variables are available for use inside component CMakeLists, but should not be modified:
 
-- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``component.mk``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable.
+- ``COMPONENT_PATH``: The component directory. Evaluates to the absolute path of the directory containing ``CMakeLists.txt``. The component path cannot contain spaces. This is the same as the ``CMAKE_CURRENT_SOURCE_DIR`` variable.
 - ``COMPONENT_NAME``: Name of the component. Same as the name of the component directory.
 - ``COMPONENT_TARGET``: Name of the library target created internally by the build system for the component.
 
 The following variables are set at the project level, but available for use in component CMakeLists:
 
 - ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
-- ``PROJECT_PATH``: Absolute path of the project directory containing the project Makefile. Same as the ``CMAKE_SOURCE_DIR`` variable.
+- ``PROJECT_PATH``: Absolute path of the project directory containing the project CMakeLists. Same as the ``CMAKE_SOURCE_DIR`` variable.
 - ``COMPONENTS``: Names of all components that are included in this build, formatted as a semicolon-delimited CMake list.
-- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in make. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
+- ``CONFIG_*``: Each value in the project configuration has a corresponding variable available in cmake. All names begin with ``CONFIG_``. :doc:`More information here </api-reference/kconfig>`.
 - ``IDF_VER``: Git version of ESP-IDF (produced by ``git describe``)
 - ``IDF_TARGET``: Name of the target for which the project is being built.
 - ``PROJECT_VER``: Project version.
 
-  * If ``PROJECT_VER`` variable set in project CMakeLists.txt file, its value will be used.
-  * Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
+  * If ``PROJECT_VER`` variable is set in project CMakeLists.txt file, its value will be used.
+  * Else, if the ``$(PROJECT_PATH}/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
   * Else, if the project is located inside a Git repository, the output of git describe will be used.
   * Otherwise, ``PROJECT_VER`` will be "1".
 
@@ -367,7 +367,7 @@ If you modify any of these variables inside ``CMakeLists.txt`` then this will no
 Optional Component-Specific Variables
 -------------------------------------
 
-The following variables can be set inside ``component.mk`` to control the build of that component:
+The following variables can be set inside ``CMakeLists.txt`` to control the build of that component:
 
 - ``COMPONENT_PRIV_INCLUDEDIRS``: Directory paths, must be relative to
   the component directory, which will be added to the include search
@@ -426,10 +426,8 @@ Preprocessor Definitions
 
 The ESP-IDF build system adds the following C preprocessor definitions on the command line:
 
-- ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF.
-- ``IDF_VER`` — Defined to a git version string.  E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit.
-- ``PROJECT_VER``: The project version, see `Preset Component Variables`_ for more details.
-- ``PROJECT_NAME``: Name of the project, as set in project CMakeLists.txt file.
+- ``ESP_PLATFORM`` : Can be used to detect that build happens within ESP-IDF.
+- ``IDF_VER`` : Defined to a git version string.  E.g. ``v2.0`` for a tagged release or ``v1.0-275-g0efaa4f`` for an arbitrary commit.
 
 Component Requirements
 ======================
@@ -458,6 +456,7 @@ When creating a project
 
 - By default, every component is included in the build.
 - If you set the ``COMPONENTS`` variable to a minimal list of components used directly by your project, then the build will include:
+
   - Components mentioned explicitly in ``COMPONENTS``.
   - Those components' requirements (evaluated recursively).
   - The "common" components that every component depends on.
@@ -600,9 +599,9 @@ depending on the options selected in the project configuration.
 
     if(CONFIG_FOO_ENABLE_BAR)
         list(APPEND COMPONENT_SRCS "bar.c")
-    endif(CONFIG_FOO_ENABLE_BAR)
+    endif()
 
-This example makes use of the CMake `if function <cmake if_>`_ and `list APPEND <cmake list_>`_ function.
+This example makes use of the CMake `if <cmake if_>`_ function and `list APPEND <cmake list_>`_ function.
 
 This can also be used to select or stub out an implementation, as such:
 
@@ -722,8 +721,8 @@ For an example of using this technique, see :example:`protocols/https_request` -
 Code and Data Placements
 ------------------------
 
-ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through 
-linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking 
+ESP-IDF has a feature called linker script generation that enables components to define where its code and data will be placed in memory through
+linker fragment files. These files are processed by the build system, and is used to augment the linker script used for linking
 app binary. See :doc:`Linker Script Generation <linker-script-generation>` for a quick start guide as well as a detailed discussion
 of the mechanism.
 
@@ -767,7 +766,7 @@ the ESP-IDF build system entirely by using a CMake feature called ExternalProjec
 (The above CMakeLists.txt can be used to create a component named ``quirc`` that builds the quirc_ project using its own Makefile.)
 
 - ``externalproject_add`` defines an external build system.
-  
+
   - ``SOURCE_DIR``, ``CONFIGURE_COMMAND``, ``BUILD_COMMAND`` and ``INSTALL_COMMAND`` should always be set. ``CONFIGURE_COMMAND`` can be set to an empty string if the build system has no "configure" step. ``INSTALL_COMMAND`` will generally be empty for ESP-IDF builds.
   - Setting ``BUILD_IN_SOURCE`` means the build directory is the same as the source directory. Otherwise you can set ``BUILD_DIR``.
   - Consult the ExternalProject_ documentation for more details about ``externalproject_add()``
@@ -875,7 +874,7 @@ Using Third-Party CMake Projects with Components
 ================================================
 
 CMake is used for a lot of open-source C and C++ projects — code that users can tap into for their applications. One of the benefits of having a CMake build system
-is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may 
+is the ability to import these third-party projects, sometimes even without modification! This allows for users to be able to get functionality that may
 not yet be provided by a component, or use another library for the same functionality.
 
 .. highlight:: cmake
@@ -888,7 +887,7 @@ Importing a library might look like this for a hypothetical library ``foo`` to b
   # Set values of hypothetical variables that control the build of `foo`
   set(FOO_BUILD_STATIC OFF)
   set(FOO_BUILD_TESTS OFF)
-  
+
   # Create and import the library targets
   add_subdirectory(foo)
 
@@ -904,7 +903,7 @@ For an actual example, take a look at :example:`build_system/cmake/import_lib`.
 the library may vary. It is recommended to read up on the library's documentation for instructions on how to
 import it from other projects. Studying the library's CMakeLists.txt and build structure can also be helpful.
 
-It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for 
+It is also possible to wrap a third-party library to be used as a component in this manner. For example, the :component:`mbedtls` component is a wrapper for
 Espressif's fork of `mbedtls <https://github.com/ARMmbed/mbedtls>`_. See its :component_file:`component CMakeLists.txt <mbedtls/CMakeLists.txt>`.
 
 The CMake variable ``ESP_PLATFORM`` is set to 1 whenever the ESP-IDF build system is being used. Tests such as ``if (ESP_PLATFORM)`` can be used in generic CMake code if special IDF-specific logic is required.
@@ -915,7 +914,7 @@ Using ESP-IDF in Custom CMake Projects
 
 ESP-IDF provides a template CMake project for easily creating an application. However, in some instances the user might already
 have an existing CMake project or may want to create one. In these cases it is desirable to be able to consume IDF components
-as libraries to be linked to the user's targets (libraries/ executables). 
+as libraries to be linked to the user's targets (libraries/ executables).
 
 .. highlight:: cmake
 
@@ -957,7 +956,7 @@ parameters which can be set, the full list of which is as follows:
 - ``IDF_COMPONENT_REQUIRES_COMMON``: List of components that every component requires. Components in this list (and their dependencies) are imported regardless of the value of ``IDF_COMPONENTS``. By default, this variable is set to the minimal set of core "system" components.
 - ``IDF_SDKCONFIG_DEFAULTS``: Path to the configuration override file. If unset, components are built with default configurations.
 - ``IDF_BUILD_TESTS``: Include component tests in the build. By default, all component tests are included. The component tests are filtered using ``IDF_TEST_COMPONENTS`` and ``IDF_TEST_EXCLUDE_COMPONENTS``.
-- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. 
+- ``IDF_TEST_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, only component tests in this list will be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set.
 - ``IDF_TEST_EXCLUDE_COMPONENTS``: If ``IDF_BUILD_TESTS`` is set, component tests in this list will not be included in the build. Ignored if ``IDF_BUILD_TESTS`` is not set. This variable takes precedence over ``IDF_TEST_COMPONENTS``. This means that a component test in this list will not be included in the build even if it is also present in ``IDF_TEST_COMPONENTS``.
 
 The example in :example:`build_system/cmake/idf_as_lib` demonstrates the creation of an application equivalent to :example:`hello world application <get-started/hello_world>`
@@ -980,7 +979,7 @@ This preference reflects the `CMake best practice <https://gist.github.com/mbinn
 
   set(COMPONENT_SRCDIRS library platform)
 
-This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build. 
+This uses globbing behind the scenes to find source files in the specified directories. Be aware, however, that if a new source file is added and this method is used, then CMake won't know to automatically re-run and this file won't be added to the build.
 
 The trade-off is acceptable when you're adding the file yourself, because you can trigger a clean build or run ``idf.py reconfigure`` to manually re-run CMake_. However, the problem gets harder when you share your project with others who may check out a new version using a source control tool like Git...
 
@@ -1127,7 +1126,7 @@ Flashing from make
 .. _esptool.py: https://github.com/espressif/esptool/#readme
 .. _CMake v3.5 documentation: https://cmake.org/cmake/help/v3.5/index.html
 .. _cmake command line documentation: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options
-.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/project.html
+.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html
 .. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html
 .. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html
 .. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html
@@ -1144,4 +1143,3 @@ Flashing from make
 .. _quirc: https://github.com/dlbeer/quirc
 .. _pyenv: https://github.com/pyenv/pyenv#README
 .. _virtualenv: https://virtualenv.pypa.io/en/stable/
-
index 70eac2755ba54a35f3cba3939a89db2f601c3bf1..8c85c65d3c3e17fb2014b07c359aa8e4ae2b4cd3 100644 (file)
@@ -190,10 +190,10 @@ The following variables are set at the project level, but exported for use in th
 - ``IDF_VER``: ESP-IDF version, retrieved from either ``$(IDF_PATH)/version.txt`` file (if present) else using git command ``git describe``. Recommended format here is single liner that specifies major IDF release version, e.g. ``v2.0`` for a tagged release or ``v2.0-275-g0efaa4f`` for an arbitrary commit. Application can make use of this by calling :cpp:func:`esp_get_idf_version`.
 - ``PROJECT_VER``: Project version. 
 
-* If ``PROJECT_VER`` variable set in project Makefile file, its value will be used.
-* Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
-* Else, if the project is located inside a Git repository, the output of git describe will be used.
-* Otherwise, ``PROJECT_VER`` will be "1".
+  * If ``PROJECT_VER`` variable is set in project Makefile file, its value will be used.
+  * Else, if the ``$PROJECT_PATH/version.txt`` exists, its contents will be used as ``PROJECT_VER``.
+  * Else, if the project is located inside a Git repository, the output of git describe will be used.
+  * Otherwise, ``PROJECT_VER`` will be "1".
 
 If you modify any of these variables inside ``component.mk`` then this will not prevent other components from building but it may make your component hard to build and/or debug.
 
@@ -309,8 +309,6 @@ ESP-IDF build systems adds the following C preprocessor definitions on the comma
 
 - ``ESP_PLATFORM`` — Can be used to detect that build happens within ESP-IDF.
 - ``IDF_VER`` — ESP-IDF version, see `Preset Component Variables`_ for more details.
-- ``PROJECT_VER``: The project version, see `Preset Component Variables`_ for more details.
-- ``PROJECT_NAME``: Name of the project, as set in project Makefile.
 
 Build Process Internals
 -----------------------
index ddeab4c8e9ad7492381d2ae06f2d668dc83954dd..2d094bc331ad360f2659a62dc6dc9d930881c04d 100644 (file)
@@ -32,7 +32,7 @@ Using these symbols is done by creating an assembly file (suffix .S) and definin
         rfi     5
 
 
-For a real-life example, see the components/esp32/panic_highint_hdl.S file; the panic handler iunterrupt is implemented there.
+For a real-life example, see the :component_file:`esp32/dport_panic_highint_hdl.S` file; the panic handler interrupt is implemented there.
 
 Notes
 -----
index ca6a087775a63ae6f49530bdb416319d9b0f42d8..754c1c5cf7076847bf5dc4f3aced5779c8019a7c 100644 (file)
@@ -1,8 +1,9 @@
 ***************************************
 Building OpenOCD from Sources for Linux
 ***************************************
+:link_to_translation:`zh_CN:[中文]`
 
-The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-linux`.
+The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-linux`.
 
 
 .. highlight:: bash
index 5ff74ebc6579f58f55141fa89be2b24eb25bf44f..ab5656661fc3c7bdbbf493bd9ac5826b2d2fdcf6 100644 (file)
@@ -1,8 +1,9 @@
 ***************************************
 Building OpenOCD from Sources for MacOS
 ***************************************
+:link_to_translation:`zh_CN:[中文]`
 
-The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-macos`.
+The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-macos`.
 
 .. highlight:: bash
 
@@ -22,7 +23,7 @@ Install Dependencies
 
 Install packages that are required to compile OpenOCD using Homebrew::
 
-       brew install automake libtool libusb wget gcc@4.9 pkg-config
+    brew install automake libtool libusb wget gcc@4.9 pkg-config
 
 Build OpenOCD
 =============
@@ -51,4 +52,4 @@ Next Steps
 
 To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-configuring-esp32-target`.
 
-    
+    
\ No newline at end of file
index 61dab53deb5554fcff3d48518209c7d74a392707..a04b89df6242c2ab75a9f1a29de69b147fe25198 100644 (file)
@@ -1,8 +1,9 @@
 *****************************************
 Building OpenOCD from Sources for Windows
 *****************************************
+:link_to_translation:`zh_CN:[中文]`
 
-The following instructions are alternative to downloading binary OpenOCD from Espressif website. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-windows`.
+The following instructions are alternative to downloading binary OpenOCD from `Espressif GitHub <https://github.com/espressif/openocd-esp32/releases>`_. To quickly setup the binary OpenOCD, instead of compiling it yourself, backup and proceed to section :doc:`setup-openocd-windows`.
 
 
 .. highlight:: bash
@@ -29,16 +30,16 @@ Install packages that are required to compile OpenOCD:
 
 ::
 
-       pacman -S libtool
-       pacman -S autoconf
-       pacman -S automake
-       pacman -S texinfo
-       pacman -S mingw-w64-i686-libusb-compat-git
-       pacman -S pkg-config
+    pacman -S libtool
+    pacman -S autoconf
+    pacman -S automake
+    pacman -S texinfo
+    pacman -S mingw-w64-i686-libusb-compat-git
+    pacman -S pkg-config
 
 .. note::
 
-       Installation of ``pkg-config`` is breaking operation of esp-idf toolchain. After building of OpenOCD it should be uninstalled. It be covered at the end of this instruction. To build OpenOCD again, you will need to run ``pacman -S pkg-config`` once more. This issue does not concern other packages installed in this step (before ``pkg-config``).
+    Installation of ``pkg-config`` is breaking operation of esp-idf toolchain. After building of OpenOCD it should be uninstalled. It be covered at the end of this instruction. To build OpenOCD again, you will need to run ``pacman -S pkg-config`` once more. This issue does not concern other packages installed in this step (before ``pkg-config``).
 
 
 Build OpenOCD
@@ -65,7 +66,7 @@ Once ``make`` process is successfully completed, the executable of OpenOCD will
 
 Remove ``pkg-config``, as discussed during installation of dependencies::
 
-       pacman -Rs pkg-config
+    pacman -Rs pkg-config
 
 
 Next Steps
index 2fad48399a5e5b7d2eeb645764cc07610266bc97..8c199de6bff807785c145681d1398f98ff45d101 100644 (file)
@@ -1,5 +1,6 @@
 Configure Other JTAG Interface
 ==============================
+:link_to_translation:`zh_CN:[中文]`
 
 Refer to section :ref:`jtag-debugging-selecting-jtag-adapter` for guidance what JTAG interface to select, so it is able to operate with OpenOCD and ESP32. Then follow three configuration steps below to get it working. 
 
index bdfad5249e776c70c67202029faa9b045dff9218..d6cf1115475914e75c291d8c719f5055e8cd5484 100644 (file)
@@ -1,7 +1,8 @@
 Configure WROVER JTAG Interface
 ===============================
+:link_to_translation:`zh_CN:[中文]`
 
-All versions of ESP32 WROVER KIT boards have JTAG functionality build in. Putting it to work requires setting  jumpers to enable JTAG functionality, setting SPI flash voltage and configuring USB drivers. Please refer to step by step instructions below.
+All versions of ESP-WROVER-KIT boards have JTAG functionality build in. Putting it to work requires setting  jumpers to enable JTAG functionality, setting SPI flash voltage and configuring USB drivers. Please refer to step by step instructions below.
 
 
 Configure Hardware
@@ -29,17 +30,17 @@ Configure Hardware
 Configure USB Drivers
 ^^^^^^^^^^^^^^^^^^^^^
 
-Install and configure USB drivers, so OpenOCD is able to communicate with JTAG interface on ESP32 WROVER KIT board as well as with UART interface used to upload application for flash. Follow steps below specific to your operating system.
+Install and configure USB drivers, so OpenOCD is able to communicate with JTAG interface on ESP-WROVER-KIT board as well as with UART interface used to upload application for flash. Follow steps below specific to your operating system.
 
-.. note:: ESP32 WROVER KIT uses an FT2232 adapter. The following instructions can also be used for other FT2232 based JTAG adapters.
+.. note:: ESP-WROVER-KIT uses an FT2232 adapter. The following instructions can also be used for other FT2232 based JTAG adapters.
 
 
 Windows
 """""""
 
-1.  Using standard USB A / micro USB B cable connect ESP32 WROVER KIT to the computer. Switch the WROVER KIT on.
+1.  Using standard USB A / micro USB B cable connect ESP-WROVER-KIT to the computer. Switch the WROVER KIT on.
 
-2.  Wait until USB ports of WROVER KIT are recognized by Windows and drives are installed. If they do not install automatically, then then download them from http://www.ftdichip.com/Drivers/D2XX.htm and install manually.
+2.  Wait until USB ports of WROVER KIT are recognized by Windows and drives are installed. If they do not install automatically, then download them from http://www.ftdichip.com/Drivers/D2XX.htm and install manually.
 
 3.  Download Zadig tool (Zadig_X.X.exe) from http://zadig.akeo.ie/ and run it.
 
@@ -60,13 +61,13 @@ Windows
 
     Do not change the second device "Dual RS232-HS (Interface 1)". It is routed to ESP32's serial port (UART) used for upload of application to ESP32's flash.
 
-Now ESP32 WROVER KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
+Now ESP-WROVER-KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
 
 
 Linux
 """""
 
-1.  Using standard USB A / micro USB B cable connect ESP32 WROVER KIT board to the computer. Power on the board.
+1.  Using standard USB A / micro USB B cable connect ESP-WROVER-KIT board to the computer. Power on the board.
 
 .. highlight:: none
 
@@ -79,7 +80,7 @@ Linux
         crw-rw---- 1 root dialout 188, 1 Jul 10 19:04 /dev/ttyUSB1
 
 
-3.  Following section "Permissions delegation" in OpenOCD's README, set up the access permissions to both USB ports.
+3.  Following section "Permissions delegation" in `OpenOCD's README <https://sourceforge.net/p/openocd/code/ci/master/tree/README>`_, set up the access permissions to both USB ports.
 
 4.  Log off and login, then cycle the power to the board to make the changes effective. In terminal enter again ``ls -l /dev/ttyUSB*`` command to verify, if group-owner has changed from ``dialout`` to ``plugdev``:
 
@@ -93,13 +94,13 @@ Linux
 
     The ``/dev/ttyUSBn`` interface with lower number is used for JTAG communication. The other interface is routed to ESP32's serial port (UART) used for upload of application to ESP32's flash.
 
-Now ESP32 WROVER KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
+Now ESP-WROVER-KIT's JTAG interface should be available to the OpenOCD. To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
 
 
 MacOS
 """""
 
-On macOS, using FT2232 for JTAG and serial port at the same time needs some additional steps. When the OS loads FTDI serial port driver, it does so for both channels of FT2232 chip. However only one of these channels is used as a serial port, while the other is used as JTAG. If the OS has loaded FTDI serial port driver for the channel used for JTAG, OpenOCD will not be able to connect to to the chip. There are two ways around this:
+On macOS, using FT2232 for JTAG and serial port at the same time needs some additional steps. When the OS loads FTDI serial port driver, it does so for both channels of FT2232 chip. However only one of these channels is used as a serial port, while the other is used as JTAG. If the OS has loaded FTDI serial port driver for the channel used for JTAG, OpenOCD will not be able to connect to the chip. There are two ways around this:
 
 1. Manually unload the FTDI serial port driver before starting OpenOCD, start OpenOCD, then load the serial port driver.
 
@@ -195,4 +196,3 @@ In a nutshell, this approach requires modification to FTDI driver configuration
 After these steps, serial port and JTAG can be used at the same time.
 
 To carry on with debugging environment setup, proceed to section :ref:`jtag-debugging-run-openocd`.
-
index 067a3740cc6b405bec73c02a7749dc8f6e55a61d..a8d3d2a29de3ee009110b2caa640ae4aaedb5b0f 100644 (file)
@@ -1,5 +1,6 @@
 Debugging Examples
 ==================
+:link_to_translation:`zh_CN:[中文]`
 
 This section describes debugging with GDB from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
 
@@ -34,8 +35,8 @@ Examples in this section
 
 .. _jtag-debugging-examples-eclipse-01:
 
-Navigating though the code, call stack and threads
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Navigating through the code, call stack and threads
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 When the target is halted, debugger shows the list of threads in "Debug" window. The line of code where program halted is highlighted in another window below, as shown on the following picture. The LED stops blinking. 
 
@@ -59,7 +60,7 @@ By expanding threads you can navigate throughout the application. Expand Thread
 
 In another window on right, you can see the disassembled machine code no matter if your project provides it in source or only the binary form.
 
-Go back to the ``app_main()`` in Thread #1 to familiar code of ``blink.c`` file that will be examined in more details in the following examples. Debugger makes it easy to navigate through the code of entire application. This comes handy when stepping though the code and working with breakpoints and will be discussed below.
+Go back to the ``app_main()`` in Thread #1 to familiar code of ``blink.c`` file that will be examined in more details in the following examples. Debugger makes it easy to navigate through the code of entire application. This comes handy when stepping through the code and working with breakpoints and will be discussed below.
 
 
 .. _jtag-debugging-examples-eclipse-02:
@@ -163,7 +164,7 @@ Now resume program by pressing F8 and observe "Monitor" tab.
     :alt: Observing memory location 0x3FF44004 changing one bit to ON"
     :figclass: align-center
 
-    Observing memory location 0x3FF44004 changing one bit to ON"
+    Observing memory location 0x3FF44004 changing one bit to "ON"
 
 You should see one bit being flipped over at memory location ``0x3FF44004`` (and LED changing the state) each time F8 is pressed.
 
@@ -172,7 +173,7 @@ You should see one bit being flipped over at memory location ``0x3FF44004`` (and
     :alt: Observing memory location 0x3FF44004 changing one bit to ON"
     :figclass: align-center
 
-    Observing memory location 0x3FF44004 changing one bit to ON"
+    Observing memory location 0x3FF44004 changing one bit to "OFF"
 
 To set memory use the same "Monitor" tab and the same memory location. Type in alternate bit pattern as previously observed. Immediately after pressing enter you will see LED changing the state. 
 
@@ -182,7 +183,7 @@ To set memory use the same "Monitor" tab and the same memory location. Type in a
 Watching and setting program variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``loop(1)`` of this function to get ``i`` incremented on each blink.
+A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``while(1)`` of this function to get ``i`` incremented on each blink.
 
 Exit debugger, so it is not confused with new code, build and flash the code to the ESP and restart debugger. There is no need to restart OpenOCD.
 
@@ -227,9 +228,9 @@ Command Line
 
 Verify if your target is ready and loaded with :example:`get-started/blink` example. Configure and start debugger following steps in section :ref:`jtag-debugging-using-debugger-command-line`. Pick up where target was left by debugger, i.e. having the application halted at breakpoint established at ``app_main()``::
 
-       Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
-       43          xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
-       (gdb) 
+    Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
+    43      xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
+    (gdb) 
 
 
 
@@ -247,123 +248,123 @@ Examples in this section
 
 .. _jtag-debugging-examples-command-line-01:
 
-Navigating though the code, call stack and threads
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Navigating through the code, call stack and threads
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 When you see the ``(gdb)`` prompt, the application is halted. LED should not be blinking. 
 
 To find out where exactly the code is halted, enter ``l`` or ``list``, and debugger will show couple of lines of code around the halt point (line 43 of code in file ``blink.c``) ::
 
-       (gdb) l
-       38          }
-       39      }
-       40      
-       41      void app_main()
-       42      {
-       43          xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
-       44      }
-       (gdb) 
+    (gdb) l
+    38      }
+    39  }
+    40  
+    41  void app_main()
+    42  {
+    43      xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
+    44  }
+    (gdb) 
 
 
 Check how code listing works by entering, e.g. ``l 30, 40`` to see particular range of lines of code.
 
 You can use ``bt`` or ``backtrace`` to see what function calls lead up to this code::
 
-       (gdb) bt
-       #0  app_main () at /home/user-name/esp/blink/main/./blink.c:43
-       #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
-       (gdb) 
+    (gdb) bt
+    #0  app_main () at /home/user-name/esp/blink/main/./blink.c:43
+    #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
+    (gdb) 
 
 Line #0 of output provides the last function call before the application halted, i.e. ``app_main ()`` we have listed previously. The ``app_main ()`` was in turn called by function ``main_task`` from line 339 of code located in file ``cpu_start.c``. 
 
 To get to the context of ``main_task`` in file ``cpu_start.c``, enter ``frame  N``, where N = 1, because the ``main_task`` is listed under #1)::
 
-       (gdb) frame 1
-       #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
-       339         app_main();
-       (gdb)
+    (gdb) frame 1
+    #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
+    339     app_main();
+    (gdb)
 
 Enter ``l`` and this will reveal the piece of code that called ``app_main()`` (in line 339)::
 
-       (gdb) l
-       334             ;
-       335         }
-       336     #endif
-       337         //Enable allocation in region where the startup stacks were located.
-       338         heap_caps_enable_nonos_stack_heaps();
-       339         app_main();
-       340         vTaskDelete(NULL);
-       341     }
-       342     
-       (gdb) 
+    (gdb) l
+    334         ;
+    335     }
+    336 #endif
+    337     //Enable allocation in region where the startup stacks were located.
+    338     heap_caps_enable_nonos_stack_heaps();
+    339     app_main();
+    340     vTaskDelete(NULL);
+    341 }
+    342 
+    (gdb) 
 
 By listing some lines before, you will see the function name ``main_task`` we have been looking for::
 
-       (gdb) l 326, 341
-       326     static void main_task(void* args)
-       327     {
-       328         // Now that the application is about to start, disable boot watchdogs
-       329         REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
-       330         REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
-       331     #if !CONFIG_FREERTOS_UNICORE
-       332         // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
-       333         while (port_xSchedulerRunning[1] == 0) {
-       334             ;
-       335         }
-       336     #endif
-       337         //Enable allocation in region where the startup stacks were located.
-       338         heap_caps_enable_nonos_stack_heaps();
-       339         app_main();
-       340         vTaskDelete(NULL);
-       341     }
-       (gdb) 
+    (gdb) l 326, 341
+    326 static void main_task(void* args)
+    327 {
+    328     // Now that the application is about to start, disable boot watchdogs
+    329     REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
+    330     REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
+    331 #if !CONFIG_FREERTOS_UNICORE
+    332     // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
+    333     while (port_xSchedulerRunning[1] == 0) {
+    334         ;
+    335     }
+    336 #endif
+    337     //Enable allocation in region where the startup stacks were located.
+    338     heap_caps_enable_nonos_stack_heaps();
+    339     app_main();
+    340     vTaskDelete(NULL);
+    341 }
+    (gdb) 
 
 To see the other code, enter ``i threads``. This will show the list of threads running on target::
 
-       (gdb) i threads
-         Id   Target Id         Frame 
-         8    Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
-           at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
-         7    Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200, 
-           xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
-         6    Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
-           at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
-         5    Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
-         4    Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
-           at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
-         3    Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
-           at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
-         2    Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
-           at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
-       * 1    Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
-       (gdb) 
+    (gdb) i threads
+      Id   Target Id         Frame 
+      8    Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
+        at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
+      7    Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200, 
+        xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
+      6    Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
+        at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
+      5    Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
+      4    Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
+        at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
+      3    Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
+        at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
+      2    Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
+        at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
+    * 1    Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
+    (gdb) 
 
 The thread list shows the last function calls per each thread together with the name of C source file if available.
 
 You can navigate to specific thread by entering  ``thread N``, where ``N`` is the thread Id. To see how it works go to thread thread 5::
 
-       (gdb) thread 5
-       [Switching to thread 5 (Thread 1073410208)]
-       #0  0x4000bfea in ?? ()
-       (gdb)
+    (gdb) thread 5
+    [Switching to thread 5 (Thread 1073410208)]
+    #0  0x4000bfea in ?? ()
+    (gdb)
 
 Then check the backtrace::
 
-       (gdb) bt
-       #0  0x4000bfea in ?? ()
-       #1  0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
-       #2  0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
-       #3  0x4008532b in _frxt_dispatch ()
-       #4  0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
-       #5  0x4000000c in ?? ()
-       #6  0x4000000c in ?? ()
-       #7  0x4000000c in ?? ()
-       #8  0x4000000c in ?? ()
-       (gdb) 
+    (gdb) bt
+    #0  0x4000bfea in ?? ()
+    #1  0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
+    #2  0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
+    #3  0x4008532b in _frxt_dispatch ()
+    #4  0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
+    #5  0x4000000c in ?? ()
+    #6  0x4000000c in ?? ()
+    #7  0x4000000c in ?? ()
+    #8  0x4000000c in ?? ()
+    (gdb) 
 
 As you see, the backtrace  may contain several entries. This will let you check what exact sequence of function calls lead to the code where the target halted. Question marks ``??`` instead of a function name indicate that application is available only in binary format, without any source file in C language. The value like ``0x4000bfea`` is the memory address of the function call.
 
-Using ``bt``, ``i threads``, ``thread N`` and ``list`` commands we are now able to navigate through the code of entire application. This comes handy when stepping though the code and working with breakpoints and will be discussed below.
+Using ``bt``, ``i threads``, ``thread N`` and ``list`` commands we are now able to navigate through the code of entire application. This comes handy when stepping through the code and working with breakpoints and will be discussed below.
 
 
 .. _jtag-debugging-examples-command-line-02:
@@ -430,22 +431,22 @@ When debugging, you may resume application and enter code waiting for some event
 
 To check it delete all breakpoints and enter ``c`` to resume application. Then enter Ctrl+C. Application will be halted at some random point and LED will stop blinking. Debugger will print the following::
 
-       (gdb) c
-       Continuing.
-       ^CTarget halted. PRO_CPU: PC=0x400D0C00             APP_CPU: PC=0x400D0C00 (active)
-       [New Thread 1073433352]
+    (gdb) c
+    Continuing.
+    ^CTarget halted. PRO_CPU: PC=0x400D0C00             APP_CPU: PC=0x400D0C00 (active)
+    [New Thread 1073433352]
 
-       Program received signal SIGINT, Interrupt.
-       [Switching to Thread 1073413512]
-       0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
-       52              asm("waiti 0");
-       (gdb) 
+    Program received signal SIGINT, Interrupt.
+    [Switching to Thread 1073413512]
+    0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
+    52          asm("waiti 0");
+    (gdb) 
 
 In particular case above, the application has been halted in line 52 of code in file ``freertos_hooks.c``. Now you can resume it again by enter ``c`` or do some debugging as discussed below.
 
 .. note::
 
-       In MSYS2 shell Ctrl+C does not halt the target but exists debugger. To resolve this issue consider debugging with :ref:`jtag-debugging-examples-eclipse` or check a workaround under http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt.
+    In MSYS2 shell Ctrl+C does not halt the target but exists debugger. To resolve this issue consider debugging with :ref:`jtag-debugging-examples-eclipse` or check a workaround under http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt.
 
 
 .. _jtag-debugging-examples-command-line-04:
@@ -556,7 +557,7 @@ You should see the LED to turn on immediately after entering ``set {unsigned int
 Watching and setting program variables
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``loop(1)`` of this function to get ``i`` incremented on each blink.
+A common debugging tasks is checking the value of a program variable as the program runs. To be able to demonstrate this functionality, update file ``blink.c`` by adding a declaration of a global variable ``int i`` above definition of function ``blink_task``. Then add ``i++`` inside ``while(1)`` of this function to get ``i`` incremented on each blink.
 
 Exit debugger, so it is not confused with new code, build and flash the code to the ESP and restart debugger. There is no need to restart OpenOCD.
 
index 42bcc84eb0d7d16bef11e5ab84e2b7f43860526b..ba12c4cb259a8a245923d9e66028c317dc513c81 100644 (file)
@@ -1,5 +1,6 @@
 JTAG Debugging
 ==============
+:link_to_translation:`zh_CN:[中文]`
 
 This document provides a guide to installing OpenOCD for ESP32 and debugging using
 GDB. The document is structured as follows:
@@ -17,7 +18,7 @@ GDB. The document is structured as follows:
 :ref:`jtag-debugging-launching-debugger`
     Steps to start up a debug session with GDB from :ref:`jtag-debugging-using-debugger-eclipse` and from :ref:`jtag-debugging-using-debugger-command-line`.
 :ref:`jtag-debugging-examples`
-    If you are not familiar with GDB, check this section for debugging examples provided from from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
+    If you are not familiar with GDB, check this section for debugging examples provided from :ref:`jtag-debugging-examples-eclipse` as well as from :ref:`jtag-debugging-examples-command-line`.
 :ref:`jtag-debugging-building-openocd`
     Procedure to build OpenOCD from sources for :doc:`Windows <building-openocd-windows>`, :doc:`Linux <building-openocd-linux>` and :doc:`MacOS <building-openocd-macos>` operating systems.
 :ref:`jtag-debugging-tips-and-quirks`
@@ -59,7 +60,7 @@ Under "Application Loading and Monitoring" there is another software and hardwar
 
 Debugging using JTAG and application loading / monitoring is integrated under the `Eclipse <https://www.eclipse.org/>`_ environment, to provide quick and easy transition from writing, compiling and loading the code to debugging, back to writing the code, and so on. All the software is available for Windows, Linux and MacOS platforms.
 
-If the :doc:`ESP32 WROVER KIT <../../hw-reference/modules-and-boards>` is used, then connection from PC to ESP32 is done effectively with a single USB cable thanks to FT2232H chip installed on WROVER, which provides two USB channels, one for JTAG and the second for UART connection.
+If the :doc:`ESP-WROVER-KIT <../../hw-reference/modules-and-boards>` is used, then connection from PC to ESP32 is done effectively with a single USB cable thanks to FT2232H chip installed on WROVER, which provides two USB channels, one for JTAG and the second for UART connection.
 
 Depending on user preferences, both `debugger` and `make` can be operated directly from terminal / command line, instead from Eclipse.
 
@@ -69,11 +70,11 @@ Depending on user preferences, both `debugger` and `make` can be operated direct
 Selecting JTAG Adapter
 ----------------------
 
-The quickest and most convenient way to start with JTAG debugging is by using :doc:`ESP32 WROVER KIT <../../hw-reference/modules-and-boards>`. Each version of this development board has JTAG interface already build in. No need for an external JTAG adapter and extra wiring / cable to connect JTAG to ESP32. WROVER KIT is using FT2232H JTAG interface operating at 20 MHz clock speed, which is difficult to achieve with an external adapter.
+The quickest and most convenient way to start with JTAG debugging is by using :doc:`ESP-WROVER-KIT <../../hw-reference/modules-and-boards>`. Each version of this development board has JTAG interface already build in. No need for an external JTAG adapter and extra wiring / cable to connect JTAG to ESP32. WROVER KIT is using FT2232H JTAG interface operating at 20 MHz clock speed, which is difficult to achieve with an external adapter.
 
-If you decide to use separate JTAG adapter, look for one that is compatible with both the voltage levels on the ESP32 as well as with the OpenOCD software. The JTAG port on the ESP32 is an industry-standard JTAG port which lacks (and does not need) the TRST pin. The JTAG I/O pins all are powered from the VDD_3P3_RTC pin (which normally would be powered by a 3.3V rail) so the JTAG adapter needs to be able to work with JTAG pins in that voltage range. 
+If you decide to use separate JTAG adapter, look for one that is compatible with both the voltage levels on the ESP32 as well as with the OpenOCD software. The JTAG port on the ESP32 is an industry-standard JTAG port which lacks (and does not need) the TRST pin. The JTAG I/O pins all are powered from the VDD_3P3_RTC pin (which normally would be powered by a 3.3 V rail) so the JTAG adapter needs to be able to work with JTAG pins in that voltage range. 
 
-On the software side, OpenOCD supports a fair amount of JTAG adapters. See http://openocd.org/doc/html/Debug-Adapter-Hardware.html for an (unfortunately slightly incomplete) list of the adapters OpenOCD works with. This page lists SWD-compatible adapters as well; take note that the ESP32 does not support SWD. JTAG adapters that are hardcoded to a specific product line, e.g. STM32 debugging adapters, will not work.
+On the software side, OpenOCD supports a fair amount of JTAG adapters. See http://openocd.org/doc/html/Debug-Adapter-Hardware.html for an (unfortunately slightly incomplete) list of the adapters OpenOCD works with. This page lists SWD-compatible adapters as well; take note that the ESP32 does not support SWD. JTAG adapters that are hardcoded to a specific product line, e.g. ST-LINK debugging adapters for STM32 families, will not work.
 
 The minimal signalling to get a working JTAG connection are TDI, TDO, TCK, TMS and GND. Some JTAG debuggers also need a connection from the ESP32 power line to a line called e.g. Vtar to set the working voltage. SRST can optionally be connected to the CH_PD of the ESP32, although for now, support in OpenOCD for that line is pretty minimal.
 
@@ -169,7 +170,7 @@ Open terminal, go to directory where OpenOCD is installed and start it up::
 
 .. highlight:: none
 
-You should now see similar output (this log is for ESP32 WROVER KIT)::
+You should now see similar output (this log is for ESP-WROVER-KIT)::
 
     user-name@computer-name:~/esp/openocd-esp32$ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
     Open On-Chip Debugger 0.10.0-dev-ged7b1a9 (2017-07-10-07:16)
index a9b8286d97afa2c2ccff9805f4dabdf8c4008e95..1e265ccdb7abaf21e6564a159cd8d777ad105606 100644 (file)
@@ -1,7 +1,7 @@
 ************************
 Set up OpenOCD for Linux
 ************************
-
+:link_to_translation:`zh_CN:[中文]`
 
 Set up OpenOCD
 ==============
index 64ecc4eff10a8ca2f498a7977b23147177476c1b..aa4090c2dd9b02e1b751599db4542f5bf5cd33c0 100644 (file)
@@ -1,7 +1,7 @@
 ************************
 Set up OpenOCD for MacOS
 ************************
-
+:link_to_translation:`zh_CN:[中文]`
 
 Install libusb
 ==============
index 6b7b83af842bce41728b8774ab05156df88e3e7d..fc77d702d18b4d6cb875c459b596ed1e8667d065 100644 (file)
@@ -1,13 +1,14 @@
 **************************
 Set up OpenOCD for Windows
 **************************
+:link_to_translation:`zh_CN:[中文]`
 
 IDF Tools Installer
 ===================
 
 If you are using CMake build system and followed the :doc:`/get-started-cmake/windows-setup` with the ``ESP-IDF Tools Installer`` V1.2 or newer, then by default you will already have ``openocd`` installed.
 
-``ESP-IDF Tools Installer`` adds ``openocd` to the ``PATH`` so that it can be run from any directory.
+``ESP-IDF Tools Installer`` adds ``openocd`` to the ``PATH`` so that it can be run from any directory.
 
 Set up OpenOCD
 ==============
index 1c7111742e53198cccb85d8df05e238fa282dc58..3911191d79ef485324715f13feb5fbe66dbcb7bd 100644 (file)
@@ -1,5 +1,6 @@
 Tips and Quirks
 ---------------
+:link_to_translation:`zh_CN:[中文]`
 
 This section provides collection of all tips and quirks referred to from various parts of this guide.
 
@@ -54,7 +55,7 @@ Support options for OpenOCD at compile time
 
 ESP-IDF has some support options for OpenOCD debugging which can be set at compile time:
 
-* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` is enabled by default. If a panic or unhandled exception is thrown and a JTAG debugger is connected (ie openocd is running), ESP-IDF will break into the debugger.
+* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` is enabled by default. If a panic or unhandled exception is thrown and a JTAG debugger is connected (ie  OpenOCD is running), ESP-IDF will break into the debugger.
 * :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` (disabled by default) sets watchpoint index 1 (the second of two) at the end of any task stack. This is the most accurate way to debug task stack overflows. Click the link for more details.
 
 Please see the :ref:`make menuconfig <get-started-configure>` menu for more details on setting compile-time options.
@@ -72,11 +73,11 @@ OpenOCD has explicit support for the ESP-IDF FreeRTOS. GDB can see FreeRTOS task
 Why to set SPI flash voltage in OpenOCD configuration?
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-The MTDI pin of ESP32, being among four pins used for JTAG communication, is also one of ESP32's bootstrapping pins. On power up ESP32 is sampling binary level on MTDI to set it's internal voltage regulator used to supply power to external SPI flash chip. If binary level on MDTI pin on power up is low, the voltage regulator is set to deliver 3.3V, if it is high, then the voltage is set to 1.8V. The MTDI pin should have a pull-up or may rely on internal weak pull down resistor (see ESP32 Datasheet for details), depending on the type of SPI chip used. Once JTAG is connected, it overrides the pull-up or pull-down resistor that is supposed to do the bootstrapping. 
+The MTDI pin of ESP32, being among four pins used for JTAG communication, is also one of ESP32's bootstrapping pins. On power up ESP32 is sampling binary level on MTDI to set it's internal voltage regulator used to supply power to external SPI flash chip. If binary level on MDTI pin on power up is low, the voltage regulator is set to deliver 3.3 V, if it is high, then the voltage is set to 1.8 V. The MTDI pin should have a pull-up or may rely on internal weak pull down resistor (see `ESP32 Series Datasheet <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf>`_ for details), depending on the type of SPI chip used. Once JTAG is connected, it overrides the pull-up or pull-down resistor that is supposed to do the bootstrapping. 
 
 To handle this issue OpenOCD's board configuration file (e.g. ``boards\esp-wroom-32.cfg`` for ESP32-WROOM-32 module) provides ``ESP32_FLASH_VOLTAGE`` parameter to set the idle state of the ``TDO`` line to a specified binary level, therefore reducing the chance of a bad bootup of application due to incorrect flash voltage.
 
-Check specification of ESP32 module connected to JTAG, what is the power supply voltage of SPI flash chip. Then set ``ESP32_FLASH_VOLTAGE`` accordingly. Most WROOM modules use 3.3V flash, while WROVER modules use 1.8V flash. 
+Check specification of ESP32 module connected to JTAG, what is the power supply voltage of SPI flash chip. Then set ``ESP32_FLASH_VOLTAGE`` accordingly. Most WROOM modules use 3.3 V flash, while WROVER modules use 1.8 V flash. 
 
 
 .. _jtag-debugging-tip-optimize-jtag-speed:
@@ -160,7 +161,7 @@ Power supply voltage of ESP32's SPI flash chip
 
     set ESP32_FLASH_VOLTAGE 1.8
 
-Comment out this line to set 3.3V, ref: :ref:`jtag-debugging-tip-code-flash-voltage`
+Comment out this line to set 3.3 V, ref: :ref:`jtag-debugging-tip-code-flash-voltage`
 
 
 Configuration file for ESP32 targets
index 2492867a62917b2a8ce3a1c9bea5c22b8e2be7d3..703259bc9ae32e032310225bc1f780b19eccabc0 100644 (file)
@@ -1,5 +1,6 @@
 Using Debugger
 --------------
+:link_to_translation:`zh_CN:[中文]`
 
 This section covers configuration and running debugger either from :ref:`jtag-debugging-using-debugger-eclipse`
 or :ref:`jtag-debugging-using-debugger-command-line`. It is recommended to first check if debugger works from :ref:`jtag-debugging-using-debugger-command-line` and then move to using Eclipse.
index c98a5f181846eb53e32740f039a54d843429d372..aa2407791046961dbc0aa77c8061319be4fe6fb9 100644 (file)
@@ -1,5 +1,6 @@
 Linker Script Generation
 ========================
+:link_to_translation:`zh_CN:[中文]`
 
 Overview
 --------
@@ -49,6 +50,10 @@ For CMake set the variable ``COMPONENT_ADD_LDFRAGMENTS`` to your linker file/s b
 
     register_component()
 
+It is also possible to specify fragment files from the project CMakeLists.txt or component project_include.cmake using the function `ldgen_add_fragment_files`::
+
+    ldgen_add_fragment_files(target files ...)
+
 
 Specifying placements
 ^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +69,7 @@ For the following text, suppose we have the following:
     - a component named ``component`` that is archived as library ``libcomponent.a`` during build
     - three object files archived under the library, ``object1.o``, ``object2.o`` and ``object3.o``
     - under ``object1.o``, the function ``function1`` is defined; under ``object2.o``, the function ``function2`` is defined
-    - there exists configuration ``PERFORMANCE_MODE`` and ``PERFORMANCE_LEVEL`` in one of the IDF KConfig files, with the set value indicated by entries ``CONFIG_PERFORMANCE_MODE`` and ``CONFIG_PERFORMANCE_LEVEL`` in the project sdkconfig
+    - there exist configuration ``PERFORMANCE_MODE`` and ``PERFORMANCE_LEVEL`` in one of the IDF KConfig files, with the set value indicated by entries ``CONFIG_PERFORMANCE_MODE`` and ``CONFIG_PERFORMANCE_LEVEL`` in the project sdkconfig
 
 In the created linker fragment file, we write:
 
@@ -82,8 +87,7 @@ will still be used for ``libcomponent.a``, unless the ``entries`` key is populat
 Placing object files
 """"""""""""""""""""
 
-Suppose the entirety of ``object1.o``  is performance-critical, so it is desirable to place it in RAM. On the other hand, all of ``object2.o``
-contains things to be executed coming out of deep sleep, so it needs to be put under RTC memory. We can write:
+Suppose the entirety of ``object1.o``  is performance-critical, so it is desirable to place it in RAM. On the other hand, suppose all of ``object2.o`` contains things to be executed coming out of deep sleep, so it needs to be put under RTC memory. We can write:
 
 .. code-block:: none
 
@@ -114,7 +118,7 @@ can be achieved for placing data by writing the variable name instead of the fun
 
 .. warning::
 
-    There are :ref:`limitations<ldgen-type3-limitations>` in placing code/data using their symbol names. In order to ensure proper placements, an alternative would be to group
+    There are :ref:`limitations<ldgen-type1-limitations>` in placing code/data using their symbol names. In order to ensure proper placements, an alternative would be to group
     relevant code and data into source files, and :ref:`use object file placement<ldgen-placing-object-files>`.
 
 Placing entire component
@@ -394,7 +398,7 @@ Expanding the sections fragment with its entries definition:
             
             ...)           # and so on
 
-.. _ldgen-type3-limitations :
+.. _ldgen-type1-limitations :
 
 **On** ``Type I`` **Mapping Entries**
 
@@ -413,7 +417,7 @@ However, this is not the case for static data declared in function scope, as the
 **Condition Entries**
 
 Condition entries enable the linker script generation to be configuration-aware. Depending on whether expressions involving configuration values
-are true or not, a particular set of mapping entries can be used. The evaluation uses ``eval_string`` from ``:idf_file:`tools/kconfig_new/kconfiglib.py``` and adheres to its required syntax and limitations.
+are true or not, a particular set of mapping entries can be used. The evaluation uses ``eval_string`` from :idf_file:`tools/kconfig_new/kconfiglib.py` and adheres to its required syntax and limitations.
 
 All mapping entries defined after a condition entry until the next one or the end of the mapping fragment belongs to that condition entry. During processing 
 conditions are tested sequentially, and the mapping entries under the first condition that evaluates to ``TRUE`` are used.
@@ -540,5 +544,5 @@ put under the build directory of the same component. Modifying this linker scrip
 
 Linker Fragment File
 ^^^^^^^^^^^^^^^^^^^^
-Any component can add a fragment file to the build. In order to add a fragment file to process, use the command ``ldgen_add_fragment_file`` as mentioned :ref:`here<ldgen-add-fragment-file>`.
+Any component can add a fragment file to the build. In order to add a fragment file to process, set COMPONENT_ADD_LDFRAGMENTS or use the function ``ldgen_add_fragment_files`` (CMake only) as mentioned :ref:`here <ldgen-add-fragment-file>`.
 Modifying any fragment file presented to the build system triggers a re-link of the app binary.
index e1fd2bebc0ab48eeb2e6832444759ad3fdfaa7b3..44d4df812d53afb1b47f3086ac98ba0965d612f8 100644 (file)
@@ -248,9 +248,15 @@ The number of bits not included in square brackets is free (bits in EFUSE_BLK0 a
 Debug eFuse & Unit tests
 ------------------------
 
-eFuse manager have option :envvar:`CONFIG_EFUSE_VIRTUAL` in Kconfig which will make an operation write is virtual. It can help to debug app and unit tests.
+Virtual eFuses
+^^^^^^^^^^^^^^
 
-esptool have an useful tool for reading/writing ESP32 eFuse bits - `espefuse.py <https://github.com/espressif/esptool/wiki/espefuse>`_.
+The Kconfig option :envvar:`CONFIG_EFUSE_VIRTUAL` will virtualize eFuse values inside the eFuse Manager, so writes are emulated and no eFuse values are permanently changed. This can be useful for debugging app and unit tests.
+
+espefuse.py
+^^^^^^^^^^^
+
+esptool includes a useful tool for reading/writing ESP32 eFuse bits - `espefuse.py <https://github.com/espressif/esptool/wiki/espefuse>`_.
 
 ::
 
index 1a2f9c480a1dbe446f7f7380f2fe5a6f61d30c90..a15860e8a15438f5790e92bb36a7606f94570818 100644 (file)
@@ -114,12 +114,12 @@ App version
 Application version is stored in :cpp:class:`esp_app_desc_t` structure. It is located in DROM sector and has a fixed offset from the beginning of the binary file. 
 The structure is located after :cpp:class:`esp_image_header_t` and :cpp:class:`esp_image_segment_header_t` structures. The field version has string type and max length 32 chars.
 
-To set version in your project manually you need set ``PROJECT_VER`` varible in your project Makefile/CMakeLists.txt:
+To set version in your project manually you need to set ``PROJECT_VER`` variable in your project Makefile/CMakeLists.txt:
 
 * For Make build system: in application Makefile put ``PROJECT_VER = "0.1.0.1"`` before including project.mk 
 * For Cmake build system: in application CMakeLists.txt put ``set(PROJECT_VER "0.1.0.1")`` before including project.cmake. 
 
-If ``PROJECT_VER`` variable did not set in project Makefile/CMakeLists.txt then it can retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
+If ``PROJECT_VER`` variable is not set in project Makefile/CMakeLists.txt then it will be retrieved from either ``$(PROJECT_PATH)/version.txt`` file (if present) else using git command ``git describe``. If neither is available then ``PROJECT_VER`` will be set to "1". Application can make use of this by calling :cpp:func:`esp_ota_get_app_description` or :cpp:func:`esp_ota_get_partition_description` functions.
 
 API Reference
 -------------
index 0c71ad5b6be8021994479afd4d7fff1b88e7fdb3..e36f9c983650bce61bc9fb8fbe534e05ed1d92c4 100644 (file)
@@ -19,11 +19,11 @@ To compile with ESP-IDF you need to get the following packages:
 
 - Ubuntu and Debian::
 
-    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
+    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
 
 .. note::
     CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".
@@ -41,7 +41,7 @@ Compile the Toolchain from Source
 
         sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool make
 
-  - Ubuntu 16.04::
+  - Ubuntu 16.04 or newer::
 
         sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin make
 
index c8dd5b5615a5d3d331463e5879bf57093921a409..8418378b210260fd04d0ec405a95b075d6439bce 100644 (file)
@@ -17,11 +17,11 @@ To compile with ESP-IDF you need to get the following packages:
 
 - Ubuntu and Debian::
 
-    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
+    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
 
 .. note::
     CMake version 3.5 or newer is required for use with ESP-IDF. Older Linux distributions may require updating, enabling of a "backports" repository, or installing of a "cmake3" package rather than "cmake".
index 5462ca025a1bf9aaac00b75809b40416058ae71f..71028e64df3cf8a8db4242de4efc86d4b9a76440 100644 (file)
@@ -14,11 +14,11 @@ To compile with ESP-IDF you need to get the following packages:
 
 - Ubuntu and Debian::
 
-    sudo apt-get install git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing
+    sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
 
 .. note::
 
@@ -39,7 +39,7 @@ Compile the Toolchain from Source
 
         sudo apt-get install gawk gperf grep gettext libncurses-dev python python-dev automake bison flex texinfo help2man libtool
 
-  - Ubuntu 16.04::
+  - Ubuntu 16.04 or newer::
 
         sudo apt-get install gawk gperf grep gettext python python-dev automake bison flex texinfo help2man libtool libtool-bin
 
index 6a4de8f3f6ee0a582745d556ea207f2c9cc92294..c495384eac8b18a5441aeb4d2efd43a1f1dbd9cb 100644 (file)
@@ -1,12 +1,12 @@
 # This is a list of python packages used to generate documentation. This file is used with pip:
 # pip install --user -r requirements.txt
 #
-sphinx==1.6.5
+sphinx>=1.6.5
 sphinx-rtd-theme
-breathe==4.7.3
-sphinxcontrib-blockdiag==1.5.3
-sphinxcontrib-seqdiag==0.8.5
-sphinxcontrib-actdiag==0.8.5
-sphinxcontrib-nwdiag==0.9.5
+breathe>=4.7.3
+sphinxcontrib-blockdiag>=1.5.3
+sphinxcontrib-seqdiag>=0.8.5
+sphinxcontrib-actdiag>=0.8.5
+sphinxcontrib-nwdiag>=0.9.5
 recommonmark
 future>=0.16.0 # for ../tools/gen_esp_err_to_name.py
index 2dcc2368a49894c95298a70586a846c6c51f4eba..72fb40a5b6cdae0c07af6c7cc2af5debbdefdea1 100644 (file)
@@ -2,7 +2,7 @@
 #
 # Build will fail if sphinx-warning-log.txt contains any lines
 # which are not in this file. Lines are pre-sanitized by
-# check_doc_warnings.sh to remove formatting, paths, line numbers.
+# check_doc_warnings.sh to remove formatting, paths and line numbers.
 #
 # Warnings in this file must be in the same overall order as the log file.
 #
 #
 # Sphinx known issue https://github.com/sphinx-doc/sphinx/issues/2683
 #
-_build/inc/esp_a2dp_api.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
+# Note: warnings below will be gone after upgrade
+#       to the following package==version
+#
+#       sphinx==1.8.4
+#       breathe==4.11.1
+#
+esp_a2dp_api.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
   union esp_a2d_mcc_t::@1  esp_a2d_mcc_t::cie
   ---------------------^
-_build/inc/esp_bt_defs.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
+esp_bt_defs.inc:line: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
   union esp_bt_uuid_t::@0  esp_bt_uuid_t::uuid
   ---------------------^
+
+#
+# Breathe known issue: https://github.com/michaeljones/breathe/issues/405
+# Sphinx known issue: https://github.com/sphinx-doc/sphinx/pull/5901
+#
+# Note: warnings below have been identified after upgrade
+#       to the following package==version
+#
+#       sphinx==1.8.4
+#       breathe==4.11.1
+#
+ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_load_binary(uint32_t load_addr, const uint8_t * program_binary, size_t program_size)
+ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point)
+ulp-cmake.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_set_wakeup_period(size_t period_index, uint32_t period_us)
+README.rst:line: WARNING: Duplicate declaration, esp_err_t ulp_run(uint32_t entry_point)
+#
+# Issue present only when building on msys2 / mingw32 START >>>
+#
+esp_spp_api.inc:line: WARNING: Error in type declaration.
+If typedef-like declaration:
+  Type must be either just a name or a typedef-like declaration.
+  If just a name:
+    Error in declarator or parameters and qualifiers
+    Invalid definition: Expected identifier in nested name, got keyword: void [error at 4]
+      void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+      ----^
+  If typedef-like declaration:
+    Error in declarator
+    If pointer to member declarator:
+      Invalid definition: Expected identifier in nested name. [error at 4]
+        void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+        ----^
+    If declId, parameters, and qualifiers:
+      Invalid definition: Expected identifier in nested name. [error at 4]
+        void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+        ----^
+    If parenthesis in noptr-declarator:
+      Error in declarator or parameters and qualifiers
+      If pointer to member declarator:
+        Invalid definition: Expected identifier in nested name. [error at 5]
+          void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+          -----^
+      If declarator-id:
+        Invalid definition: Expected identifier in nested name. [error at 5]
+          void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+          -----^
+If type alias or template alias:
+  Invalid definition: Expected identifier in nested name, got keyword: void [error at 4]
+    void() esp_spp_cb_t(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
+    ----^
+#
+# Issue present only when building on msys2 / mingw32 END <<<
+#
+spi_master.inc:line: WARNING: Duplicate declaration, struct spi_transaction_t spi_transaction_t
+spi_slave.inc:line: WARNING: Duplicate declaration, struct spi_slave_transaction_t spi_slave_transaction_t
+wear-levelling.rst:line: WARNING: Duplicate declaration, bool esp_vfs_fat_mount_config_t::format_if_mount_failed
+wear-levelling.rst:line: WARNING: Duplicate declaration, int esp_vfs_fat_mount_config_t::max_files
+wear-levelling.rst:line: WARNING: Duplicate declaration, size_t esp_vfs_fat_mount_config_t::allocation_unit_size
+wear-levelling.rst:line: WARNING: Duplicate declaration, esp_vfs_fat_mount_config_t
index d70290e6e6e9e745e24a951cb0a6256f36879a20..1764a70341f7779d91c4a71400cbc339ba199538 100644 (file)
@@ -1 +1,1083 @@
-.. include:: ../../en/api-guides/build-system-cmake.rst
+构建系统(CMake 版)
+********************
+:link_to_translation:`en:[English]`
+
+.. include:: ../cmake-warning.rst
+
+.. include:: ../cmake-pending-features.rst
+
+本文档将介绍基于 CMake 的 ESP-IDF 构建系统的实现原理以及 ``组件`` 等相关概念,此外 ESP-IDF 还支持 :doc:`基于 GNU Make 的构建系统 <build-system>`。
+
+如需您想了解如何使用 CMake 构建系统来组织和构建新的 ESP-IDF 项目或组件,请阅读本文档。
+
+概述
+====
+
+一个 ESP-IDF 项目可以看作是多个不同组件的集合,例如一个显示当前湿度的网页服务器会包含以下组件:
+
+- ESP32 基础库,包括 libc、ROM bindings 等
+- Wi-Fi 驱动
+- TCP/IP 协议栈
+- FreeRTOS 操作系统
+- 网页服务器
+- 湿度传感器的驱动
+- 负责将上述组件整合到一起的主程序
+
+ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会前往 ESP-IDF 目录、项目目录和用户自定义目录(可选)中查找所有组件,允许用户通过文本菜单系统配置 ESP-IDF 项目中用到的每个组件。在所有组件配置结束后,构建系统开始编译整个项目。
+
+概念
+----
+
+- ``项目`` 特指一个目录,其中包含了构建可执行应用程序所需的全部文件和配置,以及其他支持型文件,例如分区表、数据/文件系统分区和引导程序。
+- ``项目配置`` 保存在项目根目录下名为 ``sdkconfig`` 的文件中,可以通过 ``idf.py menuconfig`` 进行修改,且一个项目只能包含一个项目配置。
+- ``应用程序`` 是由 ESP-IDF 构建得到的可执行文件。一个项目通常会构建两个应用程序:项目应用程序(可执行的主文件,即用户自定义的固件)和引导程序(启动并初始化项目应用程序)。
+- ``组件`` 是模块化且独立的代码,会被编译成静态库(.a 文件)并链接到应用程序。部分组件由 ESP-IDF 官方提供,其他组件则来源于其它开源项目。
+- ``目标`` 特指运行构建后应用程序的硬件设备。ESP-IDF 当前仅支持 ``ESP32`` 这一个硬件目标。
+
+请注意,以下内容并不属于项目的组成部分:
+
+- ``ESP-IDF`` 并不是项目的一部分,它独立于项目,通过 ``IDF_PATH`` 环境变量(保存 ``esp-idf`` 目录的路径)链接到项目,从而将 IDF 框架与项目分离。
+- 交叉编译工具链并不是项目的组成部分,它应该被安装在系统 PATH 环境变量中。
+
+使用构建系统
+============
+
+.. _idf.py:
+
+idf.py
+------
+
+``idf.py`` 命令行工具提供了一个前端,可以帮助您轻松管理项目的构建过程,它管理了以下工具:
+
+- CMake_,配置待构建的系统
+- 命令行构建工具(Ninja_ 或 `GNU Make`)
+- `esptool.py`_,烧录 ESP32
+
+:ref:`入门指南 <get-started-configure-cmake>` 简要介绍了如何设置 ``idf.py`` 用于配置、构建并烧录项目。
+
+``idf.py`` 应运行在 ESP-IDF 的 ``项目`` 目录下,即包含 ``CMakeLists.txt`` 文件的目录。仅包含 Makefile 的老式项目并不支持 ``idf.py``。
+
+运行 ``idf.py --help`` 查看完整的命令列表。下面总结了最常用的命令:
+
+- ``idf.py menuconfig`` 会运行 ``menuconfig`` 工具来配置项目。
+- ``idf.py build`` 会构建在当前目录下找到的项目,它包括以下步骤:
+
+  - 根据需要创建 ``build`` 构建目录,它用于保存构建过程的输出文件,可以使用 ``-B`` 选项修改默认的构建目录。
+  - 根据需要运行 CMake_ 配置命令,为主构建工具生成构建文件。
+  - 运行主构建工具(Ninja_ 或 `GNU Make`)。默认情况下,构建工具会被自动检测,可以使用 ``-G`` 选项显式地指定构建工具。
+
+  构建过程是增量式的,如果自上次构建以来源文件或项目配置没有发生改变,则不会执行任何操作。
+
+- ``idf.py clean`` 会把构建输出的文件从构建目录中删除,从而清理整个项目。下次构建时会强制“重新完整构建”这个项目。清理时,不会删除 CMake 配置输出及其他文件。
+- ``idf.py fullclean`` 会将整个 ``build`` 目录下的内容全部删除,包括所有 CMake 的配置输出文件。下次构建项目时,CMake 会从头开始配置项目。请注意,该命令会递归删除构建目录下的 *所有文件*,请谨慎使用。项目配置文件不会被删除。
+- ``idf.py flash`` 会在必要时自动构建项目,并将生成的二进制程序烧录进 ESP32 设备中。``-p`` 和 ``-b`` 选项可分别设置串口的设备名和烧录时的波特率。
+- ``idf.py monitor`` 用于显示 ESP32 设备的串口输出。``-p`` 选项可用于设置主机端串口的设备名,按下 ``Ctrl-]`` 可退出监视器。更多有关监视器的详情,请参阅 :doc:`/get-started/idf-monitor`。
+
+多个 ``idf.py`` 命令可合并成一个,例如,``idf.py -p COM4 clean flash monitor`` 会依次清理源码树,构建项目,烧录进 ESP32 设备,最后运行串口监视器。
+
+.. Note:: 环境变量 ``ESPPORT`` 和 ``ESPBAUD`` 可分别用作 ``-p`` 和 ``-b`` 选项的默认值。在命令行中,重新为这两个选项赋值,会覆盖其默认值。
+
+.. _idf.py-size:
+
+高级命令
+^^^^^^^^
+
+- ``idf.py app``,``idf.py bootloader``,``idf.py partition_table`` 仅可用于从适用的项目中构建应用程序、引导程序或分区表。
+- ``idf.py app-flash`` 等匹配命令,仅将项目的特定部分烧录至 ESP32。
+- ``idf.py -p PORT erase_flash`` 会使用 esptool.py 擦除 ESP32 的整个 Flash。
+- ``idf.py size`` 会打印应用程序相关的大小信息,``idf.py size-components`` 和 ``idf.py size-files`` 这两个命令相似,分别用于打印每个组件或源文件的详细信息。
+- ``idf.py reconfigure`` 命令会重新运行 CMake_ (即便无需重新运行)。正常使用时,并不需要运行此命令,但当源码树中添加/删除文件后或更改 CMake cache 变量时,此命令会非常有用,例如,``idf.py -DNAME='VALUE' reconfigure`` 会将 CMake cache 中的变量 ``NAME`` 的值设置为 ``VALUE``。
+
+同时调用多个 ``idf.py`` 命令时,命令的输入顺序并不重要,它们会按照正确的顺序依次执行,并保证每一条命令都生效(即先构建后烧录,先擦除后烧录等)。
+
+直接使用 CMake
+--------------
+
+为了方便,:ref:`idf.py` 已经封装了 CMake_ 命令,但是您愿意,也可以直接调用 CMake。
+
+.. highlight:: bash
+
+当 ``idf.py`` 在执行某些操作时,它会打印出其运行的每条命令以便参考。例如运行 ``idf.py build`` 命令与在 bash shell(或者 Windows Command Prompt)中运行以下命令是相同的::
+
+    mkdir -p build
+    cd build
+    cmake .. -G Ninja   # 或者 'Unix Makefiles'
+    ninja
+
+在上面的命令列表中,``cmake`` 命令对项目进行配置,并生成用于最终构建工具的构建文件。在这个例子中,最终构建工具是 Ninja_: 运行 ``ninja`` 来构建项目。
+
+没有必要多次运行 ``cmake``。第一次构建后,往后每次只需运行 ``ninja`` 即可。如果项目需要重新配置,``ninja`` 会自动重新调用 ``cmake``。
+
+若在 CMake 中使用 ``ninja`` 或 ``make``,则多数 ``idf.py`` 子命令也会有其对应的目标,例如在构建目录下运行 ``make menuconfig`` 或 ``ninja menuconfig`` 与运行 ``idf.py menuconfig`` 是相同的。
+
+.. Note::
+    如果您已经熟悉了 CMake_,那么可能会发现 ESP-IDF 的 CMake 构建系统不同寻常,为了减少样板文件,该系统封装了 CMake 的许多功能。请参考 :ref:`write-pure-cmake-component` 以编写更多 ``CMake 风格`` 的组件。
+
+.. _flash-with-ninja-or-make:
+
+使用 Ninja/Make 来烧录
+^^^^^^^^^^^^^^^^^^^^^^
+
+您可以直接使用 ninja 或 make 运行如下命令来构建项目并烧录::
+
+    ninja flash
+
+或::
+
+    make app-flash
+
+可用的目标还包括:``flash``、``app-flash`` (仅用于 app)、``bootloader-flash`` (仅用于 bootloader)。
+
+以这种方式烧录时,可以通过设置 ``ESPPORT`` 和 ``ESPBAUD`` 环境变量来指定串口设备和波特率。您可以在操作系统或 IDE 项目中设置该环境变量,或者直接在命令行中进行设置::
+
+    ESPPORT=/dev/ttyUSB0 ninja flash
+
+.. Note:: 在命令的开头为环境变量赋值属于 Bash shell 的语法,可在 Linux 、macOS 和 Windows 的类 Bash shell 中运行,但在 Windows Command Prompt 中无法运行。
+
+或::
+
+    make -j3 app-flash ESPPORT=COM4 ESPBAUD=2000000
+
+.. Note:: 在命令末尾为变量赋值属于 ``make`` 的语法,适用于所有平台的 ``make``。
+
+在 IDE 中使用 CMake
+-------------------
+
+您还可以使用集成了 CMake 的 IDE,仅需将项目 ``CMakeLists.txt`` 文件的路径告诉 IDE 即可。集成 CMake 的 IDE 通常会有自己的构建工具(CMake 称之为“生成器”),它是组成 IDE 的一部分,用来构建源文件。
+
+向 IDE 中添加除 ``build`` 目标以外的自定义目标(如添加 “Flash” 目标到 IDE)时,建议调用 ``idf.py`` 命令来执行这些“特殊”的操作。
+
+有关将ESP-IDF 同 CMake 集成到 IDE 中的详细信息,请参阅 :ref:`build_system_metadata`。
+
+.. _setting-python-interpreter:
+
+设置 Python 解释器
+------------------
+
+目前,ESP-IDF 仅适用于 Python 2.7,如果系统中默认的 ``python`` 解释器是 Python 3.x,可能会出现问题。
+
+如果使用了 ``idf.py``,并以 ``python2 $IDF_PATH/tools/idf.py ...`` 的方式运行 ``idf.py`` 则会解决这个问题(``idf.py`` 会通知其余 Python 进程使用相同的 Python 解释器)。你可以通过设置 shell 别名或其他脚本来简化该命令。
+
+如果直接使用 CMake,运行 ``cmake -D PYTHON=python2 ...``,CMake 会使用传入的值覆盖默认的 Python 解释器。
+
+如果使用集成 CMake 的 IDE,可以在 IDE 的图形用户界面中给名为 ``PYTHON`` 的 CMake cache 变量设置新的值来覆盖默认的 Python 解释器。
+
+如果想在命令行中更优雅地管理 Python 的各个版本,请查看 pyenv_ 或 virtualenv_ 工具,它们会帮助您更改默认的 python 版本。
+
+.. _example-project-structure:
+
+示例项目
+========
+
+.. highlight:: none
+
+示例项目的目录树结构可能如下所示::
+
+    - myProject/
+                 - CMakeLists.txt
+                 - sdkconfig
+                 - components/ - component1/ - CMakeLists.txt
+                                             - Kconfig
+                                             - src1.c
+                               - component2/ - CMakeLists.txt
+                                             - Kconfig
+                                             - src1.c
+                                             - include/ - component2.h
+                 - main/       - src1.c
+                               - src2.c
+                 - build/
+
+该示例项目 ``myproject`` 包含以下组成部分:
+
+- 顶层项目 CMakeLists.txt 文件,这是 CMake 用于学习如何构建项目的主要文件,可以在这个文件中设置项目全局的 CMake 变量。顶层项目 CMakeLists.txt 文件会导入 :idf_file:`/tools/cmake/project.cmake` 文件,由它负责实现构建系统的其余部分。该文件最后会设置项目的名称,并定义该项目。
+- ``sdkconfig`` 项目配置文件,执行 ``idf.py menuconfig`` 时会创建或更新此文件,文件中保存了项目中所有组件(包括 ESP-IDF 本身)的配置信息。 ``sdkconfig`` 文件可能会也可能不会被添加到项目的源码管理系统中。
+- 可选的 ``component`` 目录中包含了项目的部分自定义组件,并不是每个项目都需要这种自定义组件,但它组件有助于构建可复用的代码或者导入第三方(不属于 ESP-IDF)的组件。
+- ``main`` 目录是一个特殊的 ``伪组件``,包含项目本身的源代码。``main`` 是默认名称,CMake 变量 ``COMPONENT_DIRS`` 默认包含此组件,但您可以修改此变量。或者,您也可以在顶层 CMakeLists.txt 中设置 ``EXTRA_COMPONENT_DIRS`` 变量以查找其他指定位置处的组件。有关详细信息,请参阅 :ref:`重命名 main 组件 <rename-main-cmake>`。如果项目中源文件较多,建议将其归于组件中,而不是全部放在 ``main`` 中。
+- ``build`` 目录是存放构建输出的地方,如果没有此目录,``idf.py`` 会自动创建。CMake 会配置项目,并在此目录下生成临时的构建文件。随后,在主构建进程的运行期间,该目录还会保存临时目标文件、库文件以及最终输出的二进制文件。此目录通常不会添加到项目的源码管理系统中,也不会随项目源码一同发布。
+
+每个组件目录都包含一个 ``CMakeLists.txt`` 文件,里面会定义一些变量以控制该组件的构建过程,以及其与整个项目的集成。更多详细信息请参阅 :ref:`component-directories-cmake`。
+
+每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的 :ref:`component-configuration-cmake` 选项。某些组件可能还会包含 ``Kconfig.projbuild`` 和 ``project_include.cmake`` 特殊文件,它们用于 :ref:`override_project_config`。
+
+项目 CMakeLists 文件
+====================
+
+每个项目都有一个顶层 ``CMakeLists.txt`` 文件,包含整个项目的构建设置。默认情况下,项目 CMakeLists 文件会非常小。
+
+最小 CMakeLists 文件示例
+------------------------
+
+.. highlight:: cmake
+
+最小项目::
+
+        cmake_minimum_required(VERSION 3.5)
+        include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+        project(myProject)
+
+
+.. _project-mandatory-parts:
+
+必要部分
+--------
+
+每个项目都要按照上面显示的顺序添加上述三行代码:
+
+- ``cmake_minimum_required(VERSION 3.5)`` 必须放在 CMakeLists.txt 文件的第一行,它会告诉 CMake 构建该项目所需要的最小版本号。ESP-IDF 支持 CMake 3.5 或更高的版本。
+- ``include($ENV{IDF_PATH}/tools/cmake/project.cmake)`` 会导入 CMake 的其余功能来完成配置项目、检索组件等任务。
+- ``project(myProject)`` 会创建项目本身,并指定项目名称。该名称会作为最终输出的二进制文件的名字,即 ``myProject.elf`` 和 ``myProject.bin``。每个 CMakeLists 文件只能定义一个项目。
+
+.. _optional_project_variable:
+
+可选的项目变量
+--------------
+
+以下这些变量都有默认值,用户可以覆盖这些变量值以自定义构建行为。更多实现细节,请参阅 :idf_file:`/tools/cmake/project.cmake` 文件。
+
+- ``COMPONENT_DIRS``:组件的搜索目录,默认为 ``${IDF_PATH}/components``、``${PROJECT_PATH}/components`` 和 ``EXTRA_COMPONENT_DIRS``。如果您不想在这些位置搜索组件,请覆盖此变量。
+- ``EXTRA_COMPONENT_DIRS``:用于搜索组件的其它可选目录列表。路径可以是相对于项目目录的相对路径,也可以是绝对路径。
+- ``COMPONENTS``:要构建进项目中的组件名称列表,默认为 ``COMPONENT_DIRS`` 目录下检索到的所有组件。使用此变量可以“精简”项目以缩短构建时间。请注意,如果一个组件通过 ``COMPONENT_REQUIRES`` 指定了它依赖的另一个组件,则会自动将其添加到 ``COMPONENTS`` 中,所以 ``COMPONENTS`` 列表可能会非常短。
+- ``COMPONENT_REQUIRES_COMMON``:每个组件都需要的通用组件列表,这些通用组件会自动添加到每个组件的 ``COMPONENT_PRIV_REQUIRES`` 列表中以及项目的 ``COMPONENTS`` 列表中。默认情况下,此变量设置为 ESP-IDF 项目所需的最小核心“系统”组件集。通常您无需在项目中更改此变量。
+
+以上变量中的路径可以是绝对路径,或者是相对于项目目录的相对路径。
+
+请使用 `cmake 中的 set 命令 <cmake set_>`_ 来设置这些变量,即 ``set(VARIABLE "VALUE")``。请注意,``set()`` 命令需放在 ``include(...)`` 之前,``cmake_minimum(...)`` 之后。
+
+.. _rename-main-cmake:
+
+重命名 ``main`` 组件
+--------------------
+
+构建系统会对 ``main`` 组件进行特殊处理。假如 ``main`` 组件位于预期的位置(即 `${PROJECT_PATH}/main`),那么它会被自动添加到构建系统中。其他组件也会作为其依赖项被添加到构建系统中,这使用户免于处理依赖关系,并提供即时可用的构建功能。重命名 ``main`` 组件会减轻上述这些幕后工作量,但要求用户指定重命名后的组件位置,并手动为其添加依赖项。重命名 ``main`` 组件的步骤如下:
+
+1. 重命名 ``main`` 目录。
+2. 在项目 CMakeLists.txt 文件中设置 ``EXTRA_COMPONENT_DIRS``,并添加重命名后的 ``main`` 目录。
+3. 在组件的 CMakeLists.txt 文件中设置 ``COMPONENT_REQUIRES`` 或 ``COMPONENT_PRIV_REQUIRES`` 以指定依赖项。
+
+
+.. _component-directories-cmake:
+
+组件 CMakeLists 文件
+====================
+
+每个项目都包含一个或多个组件,这些组件可以是 ESP-IDF 的一部分,可以是项目自身组件目录的一部分,也可以从自定义组件目录添加( :ref:`见上文 <component-directories-cmake>`)。
+
+组件是 ``COMPONENT_DIRS`` 列表中包含 ``CMakeLists.txt`` 文件的任何目录。
+
+搜索组件
+--------
+
+搜索 ``COMPONENT_DIRS`` 中的目录列表以查找项目的组件,此列表中的目录可以是组件自身(即包含 `CMakeLists.txt` 文件的目录),也可以是子目录为组件的顶级目录。
+
+当 CMake 运行项目配置时,它会记录本次构建包含的组件列表,它可用于调试某些组件的添加/排除。
+
+同名组件
+--------
+
+ESP-IDF 在搜索所有待构建的组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先搜索 ESP-IDF 内部组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改以覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。
+
+.. _minimum_cmakelists:
+
+最小的组件 CMakeLists 文件
+--------------------------
+
+.. highlight:: cmake
+
+最小组件 ``CMakeLists.txt`` 文件内容如下::
+
+    set(COMPONENT_SRCS "foo.c")
+    set(COMPONENT_ADD_INCLUDEDIRS "include")
+    register_component()
+
+- ``COMPONENT_SRCS`` 是用空格分隔的源文件列表(``*.c``,``*.cpp``,``*.cc``,``*.S``),里面所有的源文件都将会编译进组件库中。
+- ``COMPONENT_ADD_INCLUDEDIRS`` 是用空格分隔的目录列表,里面的路径会被添加到所有需要该组件的组件(包括 main 组件)全局 include 搜索路径中。
+- ``register_component()`` 使用上述设置的变量将组件添加到构建系统中,构建生成与组件同名的库,并最终被链接到应用程序中。如果因为使用了 `CMake 中的 if 命令 <cmake if_>`_ 或类似命令而跳过了这一步,那么该组件将不会被添加到构建系统中。
+
+上述目录通常设置为相对于 ``CMakeLists.txt`` 文件的相对路径,当然也可以设置为绝对路径。
+
+有关更完整的 ``CMakeLists.txt`` 示例,请参阅 :ref:`component_cmakelists_example`。
+
+.. _preset_component_variables:
+
+预设的组件变量
+--------------
+
+以下专用于组件的变量可以在组件 CMakeLists 中使用,但不建议修改:
+
+- ``COMPONENT_PATH``:组件目录,即包含 ``CMakeLists.txt`` 文件的绝对路径,它与 ``CMAKE_CURRENT_SOURCE_DIR`` 变量一样,路径中不能包含空格。
+- ``COMPONENT_NAME``:组件名,与组件目录名相同。
+- ``COMPONENT_TARGET``:库目标名,它由构建系统在内部为组件创建。
+
+以下变量在项目级别中被设置,但可在组件 CMakeLists 中使用:
+
+- ``PROJECT_NAME``:项目名,在项目 CMakeLists.txt 文件中设置。
+- ``PROJECT_PATH``:项目目录(包含项目 CMakeLists 文件)的绝对路径,与 ``CMAKE_SOURCE_DIR`` 变量相同。
+- ``COMPONENTS``:此次构建中包含的所有组件的名称,具体格式为用分号隔开的 CMake 列表。
+- ``CONFIG_*``:项目配置中的每个值在 cmake 中都对应一个以 ``CONFIG_`` 开头的变量。更多详细信息请参阅 :doc:`Kconfig </api-reference/kconfig>`。
+- ``IDF_VER``:ESP-IDF 的 git 版本号,由 ``git describe`` 命令生成。
+- ``IDF_TARGET``:项目的硬件目标名称。
+- ``PROJECT_VER``:项目版本号。
+
+  * 如果在项目 CMakeLists.txt 文件中设置了 ``PROJECT_VER`` 变量,则该变量值可以使用。
+  * 或者,如果 ``${PROJECT_PATH}/version.txt`` 文件存在,其内容会用作 ``PROJECT_VER`` 的值。
+  * 或者,如果项目位于某个 Git 仓库中,则使用 ``git describe`` 命令的输出作为 ``PROJECT_VER`` 的值。
+  * 否则,``PROJECT_VER`` 的值为空。
+
+如果您在组件的 ``CMakeLists.txt`` 中修改以上变量,并不会影响其他组件的构建,但可能会使该组件变得难以构建或调试。
+
+- ``COMPONENT_ADD_INCLUDEDIRS``:相对于组件目录的相对路径,为被添加到所有需要该组件的其他组件的全局 include 搜索路径中。如果某个 include 路径仅仅在编译当前组件时需要,请将其添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。
+- ``COMPONENT_REQUIRES`` 是一个用空格分隔的组件列表,列出了当前组件依赖的其他组件。如果当前组件有一个头文件位于 ``COMPONENT_ADD_INCLUDEDIRS`` 目录下,且该头文件包含了另一个组件的头文件,那么这个被依赖的组件需要在 ``COMPONENT_REQUIRES`` 中指出。这种依赖关系可以是递归的。
+
+  ``COMPONENT_REQUIRES`` 可以为空,因为所有的组件都需要一些常用的组件(如 newlib 组件提供的 libc 库、freertos 组件提供的 RTOS 功能),这些通用组件已经在项目级变量 ``COMPONENT_REQUIRES_COMMON`` 中被设置。
+
+  如果一个组件仅需要额外组件的头文件来编译其源文件(而不是全局引入它们的头文件),则这些被依赖的组件需要在 ``COMPONENT_PRIV_REQUIRES`` 中指出。
+
+  请参阅 :ref:`component_dependency`,查看详细信息。
+
+可选的组件特定变量
+------------------
+
+以下变量可在 ``CMakeLists.txt`` 中进行设置,用以控制该组件的构建行为:
+
+- ``COMPONENT_PRIV_INCLUDEDIRS``:相对于组件目录的相对路径,仅会被添加到该组件的 include 搜索路径中。
+- ``COMPONENT_PRIV_REQUIRES``:以空格分隔的组件列表,用于编译或链接当前组件的源文件。这些组件的头文件路径不会传递给其余需要它的组件,仅用于编译当前组件的源代码。更多详细信息请参阅 :ref:`component_dependency`。
+- ``COMPONENT_SRCS``:要编译进当前组件的源文件的路径,推荐使用此方法向构建系统中添加源文件。
+- ``COMPONENT_SRCDIRS``:相对于组件目录的源文件目录路径,用于搜索源文件(``*.cpp``,``*.c``,``*.S``)。匹配成功的源文件会替代 ``COMPONENT_SRCS`` 中指定的源文件,进而被编译进组件。即设置 ``COMPONENT_SRCDIRS`` 会导致 ``COMPONENT_SRCS`` 会被忽略。此方法可以很容易地将源文件整体导入到组件中,但并不推荐使用(详情请参阅 :ref:`cmake-file-globbing`)。
+- ``COMPONENT_SRCEXCLUDE``:需要从组件中剔除的源文件路径。当某个目录中有大量的源文件需要被导入组件中,但同时又有个别文件不需要导入时,可以配合 ``COMPONENT_SRCDIRS`` 变量一起设置。路径可以是相对于组件目录的相对路径,也可以是绝对路径。
+- ``COMPONENT_ADD_LDFRAGMENTS``:组件使用的链接片段文件的路径,用于自动生成链接器脚本文件。详细信息请参阅 :doc:`链接脚本生成机制 <linker-script-generation>`。
+
+.. Note::
+
+    如果没有设置 ``COMPONENT_SRCDIRS`` 或 ``COMPONENT_SRCS``,组件不会被编译成库文件,但仍可以被添加到 include 路径中,以便在编译其他组件时使用。
+
+.. _component_build_control:
+
+组件编译控制
+------------
+
+.. highlight:: cmake
+
+在编译特定组件的源文件时,可以使用 ``component_compile_options`` 命令来传递编译器选项::
+
+    component_compile_options(-Wno-unused-variable)
+
+这条命令封装了 CMake 的 `target_compile_options`_ 命令。
+
+如果给单个源文件指定编译器标志,可以使用 CMake 的 `set_source_files_properties`_ 命令::
+
+    set_source_files_properties(mysrc.c
+        PROPERTIES COMPILE_FLAGS
+        -Wno-unused-variable
+    )
+
+如果上游代码在编译的时候发出了警告,那这么做可能会很有效。
+
+请注意,上述两条命令只能在组件 CMakeLists 文件的 ``register_component()`` 命令之后调用。
+
+.. _component-configuration-cmake:
+
+组件配置
+========
+
+每个组件都可以包含一个 ``Kconfig`` 文件,和 ``CMakeLists.txt`` 放在同一目录下。``Kconfig`` 文件中包含要添加到该组件配置菜单中的一些配置设置信息。
+
+运行 menuconfig 时,可以在 ``Component Settings`` 菜单栏下找到这些设置。
+
+创建一个组件的 Kconfig 文件,最简单的方法就是使用 ESP-IDF 中现有的 Kconfig 文件作为模板,在这基础上进行修改。
+
+有关示例请参阅 :ref:`add_conditional_config`。
+
+预处理器定义
+============
+
+ESP-IDF 构建系统会在命令行中添加以下 C 预处理器定义:
+
+- ``ESP_PLATFORM``:可以用来检测在 ESP-IDF 内发生了构建行为。
+- ``IDF_VER``:定义 git 版本字符串,例如:``v2.0`` 用于标记已发布的版本,``v1.0-275-g0efaa4f`` 则用于标记任意某次的提交记录。
+- ``PROJECT_VER``:项目版本号,详细信息请参阅 :ref:`preset_component_variables`。
+- ``PROJECT_NAME``:项目名称,定义在项目 CMakeLists.txt 文件中。
+
+.. _component_dependency:
+
+组件依赖
+========
+
+编译各个组件时,ESP-IDF 系统会递归评估其组件。
+
+每个组件的源文件都会使用以下路径中的头文件进行编译:
+
+- 当前组件的 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_PRIV_INCLUDEDIRS``。
+- 当前组件的 ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 变量指定的其他组件(即当前组件的所有公共和私有依赖项)所设置的 ``COMPONENT_ADD_INCLUDEDIRS``。
+- 所有组件的 ``COMPONENT_REQUIRES`` 做递归操作,即该组件递归运算后的所有公共依赖项。
+
+编写组件
+--------
+
+- ``COMPONENT_REQUIRES`` 需要包含所有被当前组件的公共头文件 `#include` 的头文件所在的组件。
+- ``COMPONENT_PRIV_REQUIRES`` 需要包含被当前组件的源文件 `#include` 的头文件所在的组件(除非已经被设置在了 ``COMPONENT_PRIV_REQUIRES`` 中)。或者是当前组件正常工作必须要链接的组件。
+- ``COMPONENT_REQUIRES``、``COMPONENT_PRIV_REQUIRES`` 需要在调用 ``register_component()`` 之前设置。
+- ``COMPONENT_REQUIRES`` 和 ``COMPONENT_PRIV_REQUIRES`` 的值不能依赖于任何配置选项(``CONFIG_xxx``),这是因为在配置加载之前,依赖关系就已经被展开。其它组件变量(比如 ``COMPONENT_SRCS`` 和 ``COMPONENT_ADD_INCLUDEDIRS``)可以依赖配置选择。
+- 如果当前组件除了 ``COMPONENT_REQUIRES_COMMON`` 中设置的通用组件(比如 RTOS、libc 等)外,并不依赖其它组件,那么上述两个 ``REQUIRES`` 变量可以为空。
+
+如果组件仅支持某些硬件目标(即依赖于特定的 ``IDF_TARGET``),则可以调用 ``require_idf_targets(NAMES...)`` CMake 函数来声明这个需求。在这种情况下,如果构建系统导入了不支持当前硬件目标的组件时就会报错。
+
+创建项目
+--------
+
+- 默认情况下,每个组件都会包含在构建系统中。
+- 如果将 ``COMPONENTS`` 变量设置为项目直接使用的最小组件列表,那么构建系统会导入:
+
+  * ``COMPONENTS`` 中明确提及的组件。
+  * 这些组件的依赖项(以及递归运算后的组件)。
+  * 每个组件都依赖的通用组件。
+
+- 将 ``COMPONENTS`` 设置为所需组件的最小列表,可以显著减少项目的构建时间。
+
+.. _component-requirements-implementation:
+
+构建系统中依赖处理的实现细节
+----------------------------
+
+- 在 CMake 配置进程的早期阶段会运行 ``expand_requirements.cmake`` 脚本。该脚本会对所有组件的 CMakeLists.txt 文件进行局部的运算,得到一张组件依赖关系图(此图可能会有闭环)。此图用于在构建目录中生成 ``component_depends.cmake`` 文件。
+- CMake 主进程会导入该文件,并以此来确定要包含到构建系统中的组件列表(内部使用的 ``BUILD_COMPONENTS`` 变量)。``BUILD_COMPONENTS`` 变量已排好序,依赖组件会排在前面。由于组件依赖关系图中可能存在闭环,因此不能保证每个组件都满足该排序规则。如果给定相同的组件集和依赖关系,那么最终的排序结果应该是确定的。
+- CMake 会将 ``BUILD_COMPONENTS`` 的值以 “Component names:” 的形式打印出来。
+- 然后执行构建系统中包含的每个组件的配置。
+- 每个组件都被正常包含在构建系统中,然后再次执行 CMakeLists.txt 文件,将组件库加入构建系统。
+
+组件依赖顺序
+^^^^^^^^^^^^
+
+``BUILD_COMPONENTS`` 变量中组件的顺序决定了构建过程中的其它顺序,包括:
+
+- 项目导入 :ref:`project_include.cmake` 文件的顺序。
+- 生成用于编译(通过 ``-I`` 参数)的头文件路径列表的顺序。请注意,对于给定组件的源文件,仅需将该组件的依赖组件的头文件路径告知编译器。
+- 组件目标归档文件传递给链接器的顺序。请注意,构建系统还会将 ``--start-group`` 和 ``--end-group`` 传递给链接器,以允许链接依赖存在闭环,但其基本顺序还是由 ``BUILD_COMPONENTS`` 决定的。
+
+构建的内部过程
+==============
+
+关于 CMake_ 以及 CMake 命令的详细信息,请参阅 `CMake v3.5 官方文档`_ 。
+
+project.cmake 的内容
+--------------------
+
+当项目 CMakeLists 文件导入 ``project.cmake`` 文件时,``project.cmake`` 会定义一些实用的模块和全局变量。如果系统环境中没有设置 ``IDF_PATH``,那么它还会自动设置 ``IDF_PATH`` 变量。
+
+``project.cmake`` 文件还重写了 CMake_ 内置的 ``project`` 函数,以添加所有 ESP-IDF 项目特有的功能。
+
+project 函数
+------------
+
+自定义的 ``project()`` 函数会执行以下步骤:
+
+- 确定硬件目标(由 ``IDF_TARGET`` 环境变量设置),并将其保存在 CMake cache 中。如果环境变量中设置的硬件目标与 CMake cache 中的不匹配,则会报错并退出。
+- 计算组件依赖,并构造 ``BUILD_COMPONENTS`` 变量,它是包含所有需要导入到构建系统中的组件列表(:ref:`详情请见上文<component-requirements-implementation>`)。
+- 查找项目中所有的组件(搜索 ``COMPONENT_DIRS``,并按 ``COMPONENTS`` 进行过滤(前提是设置了该变量)。
+- 从 ``sdkconfig`` 文件中加载项目配置信息,生成 ``sdkconfig.cmake`` 和 ``sdkconfig.h`` 文件,分别用在 CMake 和 C/C++ 中定义配置项。如果项目配置发生了更改,CMake 会自动重新运行,重新生成上述两个文件,接着重新配置项目。
+- 根据硬件目标(``IDF_TARGET``)的值,将 `CMAKE_TOOLCHAIN_FILE`_ 变量设置为相应的工具链文件。
+- 调用 `CMake 的 project 函数 <cmake project_>`_ 声明实际的 CMake-level 项目。
+- 加载 git 版本号。如果在 git 中检出了新的版本,就会使用一些技巧重新运行 CMake。详情请参考 :ref:`cmake-file-globbing`。
+- 从包含有 :ref:`project_include.cmake` 文件的组件中导入该文件。
+- 将每个组件都添加到构建系统中。每个组件的 CMakeLists 文件都会调用 ``register_component`` 函数,它会调用 CMake 的 `add_library <cmake add_library_>`_ 函数来添加一个库,然后添加源文件、编译选项等。
+- 将最终的应用程序可执行文件添加到构建系统中。
+- 返回并为组件之间指定依赖关系(将每个组件的公共头文件目录添加到其他组件中)。
+
+更多详细信息请参阅 :idf_file:`/tools/cmake/project.cmake` 文件和 :idf_file:`/tools/cmake/idf_functions.cmake` 文件。
+
+CMake 调试
+----------
+
+调试 ESP-IDF CMake 构建系统的一些技巧:
+
+- CMake 运行时,会打印大量诊断信息,包括组件列表和组件路径。
+- 运行 ``cmake -DDEBUG=1``,IDF 构建系统会生成更详细的诊断输出。
+- 运行 ``cmake`` 时指定 ``--trace`` 或 ``--trace-expand`` 选项会提供大量有关控制流信息。详情请参考 `CMake 命令行文档`_。
+
+.. _warn-undefined-variables-cmake:
+
+警告未定义的变量
+^^^^^^^^^^^^^^^^
+
+默认情况下,``idf.py`` 在调用 CMake_ 时会给它传递 ``--warn-uninitialized`` 标志,如果在构建的过程中引用了未定义的变量,CMake_ 会打印警告。这对查找有错误的 CMake 文件非常有用。
+
+如果您不想启用此功能,可以给 ``idf.py`` 传递 ``--no-warnings`` 标志。
+
+.. _override_project_config:
+
+覆盖项目的部分设置
+------------------
+
+.. _project_include.cmake:
+
+project_include.cmake
+^^^^^^^^^^^^^^^^^^^^^
+
+如果组件的某些构建行为需要在组件 CMakeLists 文件之前被执行,您可以在组件目录下创建名为 ``project_include.cmake`` 的文件,``project.cmake`` 在运行过程中会导入此 CMake 文件。
+
+``project_include.cmake`` 文件在 ESP-IDF 内部使用,以定义项目范围内的构建功能,比如 ``esptool.py`` 的命令行参数和 ``bootloader`` 这个特殊的应用程序。
+
+与组件 ``CMakeLists.txt`` 文件有所不同,在导入``project_include.cmake`` 文件的时候,当前源文件目录(即 ``CMAKE_CURRENT_SOURCE_DIR``)和工作目录为项目目录。如果想获得当前组件的绝对路径,可以使用 ``COMPONENT_PATH`` 变量。
+
+请注意,``project_include.cmake`` 对于大多数常见的组件并不是必需的。例如给项目添加 include 搜索目录,给最终的链接步骤添加 ``LDFLAGS`` 选项等等都可以通过 ``CMakeLists.txt`` 文件来自定义。详细信息请参考 :ref:`optional_project_variable`。
+
+``project_include.cmake`` 文件会按照 ``BUILD_COMPONENTS`` 变量中组件的顺序(由 CMake 记录)依次导入。即只有在当前组件所有依赖组件的 ``project_include.cmake`` 文件都被导入后,当前组件的 ``project_include.cmake`` 文件才会被导入,除非两个组件在同一个依赖闭环中。如果某个 ``project_include.cmake`` 文件依赖于另一组件设置的变量,则要特别注意上述情况。更多详情请参阅 :ref:`component-requirements-implementation`。
+
+在 ``project_include.cmake`` 文件中设置变量或目标时要格外小心,这些值被包含在项目的顶层 CMake 文件中,因此他们会影响或破坏所有组件的功能。
+
+KConfig.projbuild
+^^^^^^^^^^^^^^^^^
+
+与 ``project_include.cmake`` 类似,也可以为组件定义一个 KConfig 文件以实现全局的 :ref:`component-configuration-cmake`。如果要在 menuconfig 的顶层添加配置选项,而不是在 “Component Configuration” 子菜单中,则可以在 ``CMakeLists.txt`` 文件所在目录的 KConfig.projbuild 文件中定义这些选项。
+
+在此文件中添加配置时要小心,因为这些配置会包含在整个项目配置中。在可能的情况下,请为 :ref:`component-configuration-cmake` 创建 KConfig 文件。
+
+.. _config_only_component:
+
+仅配置组件
+^^^^^^^^^^
+
+仅配置组件是一类不包含源文件的特殊组件,仅包含 ``Kconfig.projbuild``、``KConfig`` 和 ``CMakeLists.txt`` 文件,该 ``CMakeLists.txt`` 文件仅有一行代码,调用了 ``register_config_only_component()`` 函数。此函数会将组件导入到项目构建中,但不会构建任何库,也不会将头文件添加到任何 include 搜索路径中。
+
+如果 CMakeLists.txt 文件没有调用 ``register_component()`` 或 ``register_config_only_component()``,那么该文件将会被排除在项目构建之外。根据项目的配置,有时可能需要这么做。
+
+.. _component_cmakelists_example:
+
+组件 CMakeLists 示例
+====================
+
+因为构建环境试图设置大多数情况都能工作的合理默认值,所以组件 ``CMakeLists.txt`` 文件可能非常小,甚至是空的,请参考 :ref:`minimum_cmakelists`。但有些功能往往需要覆盖 :ref:`preset_component_variables` 才能实现。
+
+以下是组件 CMakeLists 文件的更高级的示例。
+
+.. _add_conditional_config:
+
+添加条件配置
+------------
+
+配置系统可用于根据项目配置中选择的选项有条件地编译某些文件。
+
+.. highlight:: none
+
+``Kconfig``::
+
+    config FOO_ENABLE_BAR
+        bool "Enable the BAR feature."
+        help
+            This enables the BAR feature of the FOO component.
+
+``CMakeLists.txt``::
+
+    set(COMPONENT_SRCS "foo.c" "more_foo.c")
+
+    if(CONFIG_FOO_ENABLE_BAR)
+        list(APPEND COMPONENT_SRCS "bar.c")
+    endif()
+
+上述示例使用了 CMake 的 `if <cmake if_>`_ 函数和 `list APPEND <cmake list_>`_ 函数。
+
+也可用于选择或删除某一实现,如下所示:
+
+``Kconfig``::
+
+    config ENABLE_LCD_OUTPUT
+        bool "Enable LCD output."
+        help
+            Select this if your board has a LCD.
+
+    config ENABLE_LCD_CONSOLE
+        bool "Output console text to LCD"
+        depends on ENABLE_LCD_OUTPUT
+        help
+            Select this to output debugging output to the lcd
+
+    config ENABLE_LCD_PLOT
+        bool "Output temperature plots to LCD"
+        depends on ENABLE_LCD_OUTPUT
+        help
+            Select this to output temperature plots
+
+.. highlight:: cmake
+
+``CMakeLists.txt``::
+
+    if(CONFIG_ENABLE_LCD_OUTPUT)
+        set(COMPONENT_SRCS lcd-real.c lcd-spi.c)
+    else()
+        set(COMPONENT_SRCS lcd-dummy.c)
+    endif()
+
+    # 如果启用了控制台或绘图功能,则需要加入字体
+    if(CONFIG_ENABLE_LCD_CONSOLE OR CONFIG_ENABLE_LCD_PLOT)
+        list(APPEND COMPONENT_SRCS "font.c")
+    endif()
+
+
+硬件目标的的条件判断
+--------------------
+
+CMake 文件可以使用 ``IDF_TARGET`` 变量来获取当前的硬件目标。
+
+此外,如果当前的硬件目标是 ``xyz``(即 ``IDF_TARGET=xyz``),那么 Kconfig 变量 ``CONFIG_IDF_TARGET_XYZ`` 同样也会被设置。
+
+请注意,组件可以依赖 ``IDF_TARGET`` 变量,但不能依赖这个 Kconfig 变量。同样也不可在 CMake 文件的 ``include`` 语句中使用 Kconfig 变量,在这种上下文中可以使用 ``IDF_TARGET``。
+
+
+生成源代码
+----------
+
+有些组件的源文件可能并不是由组件本身提供,而必须从另外的文件生成。假设组件需要一个头文件,该文件由 BMP 文件转换后(使用 bmp2h 工具)的二进制数据组成,然后将头文件包含在名为 graphics_lib.c 的文件中::
+
+    add_custom_command(OUTPUT logo.h
+        COMMAND bmp2h -i ${COMPONENT_PATH}/logo.bmp -o log.h
+        DEPENDS ${COMPONENT_PATH}/logo.bmp
+        VERBATIM)
+
+    add_custom_target(logo DEPENDS logo.h)
+    add_dependencies(${COMPONENT_TARGET} logo)
+
+    set_property(DIRECTORY "${COMPONENT_PATH}" APPEND PROPERTY
+        ADDITIONAL_MAKE_CLEAN_FILES logo.h)
+
+这个示例改编自 `CMake 的一则 FAQ <cmake faq generated files_>`_,其中还包含了一些同样适用于 ESP-IDF 构建系统的示例。
+
+这个示例会在当前目录(构建目录)中生成 logo.h 文件,而 logo.bmp 会随组件一起提供在组件目录中。因为 logo.h 是一个新生成的文件,一旦项目需要清理,该文件也应该要被清除。因此,要将该文件添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 属性中。
+
+.. Note::
+
+   如果需要生成文件作为项目 CMakeLists.txt 的一部分,而不是作为组件 CMakeLists.txt 的一部分,此时需要使用 ``${PROJECT_PATH}`` 替代 ``${COMPONENT_PATH}``,使用 ``${PROJECT_NAME}.elf`` 替代 ``${COMPONENT_TARGET}``。
+
+如果某个源文件是从其他组件中生成,且包含 ``logo.h`` 文件,则需要调用 ``add_dependencies``, 在这两个组件之间添加一个依赖项,以确保组件源文件按照正确顺序进行编译。
+
+嵌入二进制数据
+---------------------
+
+有时您的组件希望使用一个二进制文件或者文本文件,但是您又不希望将它们重新格式化为 C 源文件,这时,您可以在组件 CMakeLists 中添加 ``COMPONENT_EMBED_FILES`` 变量,指定要嵌入的文件名称(以空格分隔)::
+
+    set(COMPONENT_EMBED_FILES server_root_cert.der)
+
+或者,如果文件是字符串,则可以设置 ``COMPONENT_EMBED_TXTFILES`` 变量,把文件的内容转成以 null 结尾的字符串嵌入::
+
+    set(COMPONENT_EMBED_TXTFILES server_root_cert.pem)
+
+.. highlight:: c
+
+文件的内容会被添加到 Flash 的 .rodata 段,用户可以通过符号名来访问,如下所示::
+
+    extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
+    extern const uint8_t server_root_cert_pem_end[]   asm("_binary_server_root_cert_pem_end");
+
+符号名会根据文件全名生成,如 ``COMPONENT_EMBED_FILES`` 中所示,字符 ``/``、``.`` 等都会被下划线替代。符号名称中的 _binary 前缀由 objcopy 命令添加,对文本文件和二进制文件都是如此。
+
+.. highlight:: cmake
+
+如果要将文件嵌入到项目中,而非组件中,可以调用 ``target_add_binary_data`` 函数::
+
+    target_add_binary_data(myproject.elf "main/data.bin" TEXT)
+
+并这行代码放在项目 CMakeLists.txt 的 ``project()`` 命令之后,修改 ``myproject.elf`` 为你自己的项目名。如果最后一个参数是 ``TEXT``,那么构建系统会嵌入以 null 结尾的字符串,如果最后一个参数被设置为 ``BINARY``,则将文件内容按照原样嵌入。
+
+有关使用此技术的示例,请参考 :example:`protocols/https_request`,证书文件的内容会在编译时从 .pem 文件中加载。
+
+代码和数据的存放
+----------------
+
+ESP-IDF 还支持自动生成链接脚本,它允许组件通过链接片段文件定义其代码和数据在内存中的存放位置。构建系统会处理这些链接片段文件,并将处理后的结果扩充进链接脚本,从而指导应用程序二进制文件的链接过程。更多详细信息与快速上手指南,请参阅 :doc:`链接脚本生成机制 <linker-script-generation>`。
+
+.. _component-build-full-override:
+
+完全覆盖组件的构建过程
+----------------------
+
+.. highlight:: cmake
+
+当然,在有些情况下,上面提到的方法不一定够用。如果组件封装了另一个第三方组件,而这个第三方组件并不能直接在 ESP-IDF 的构建系统中工作,在这种情况下,就需要放弃 ESP-IDF 的构建系统,改为使用 CMake 的 ExternalProject_ 功能。组件 CMakeLists 示例如下::
+
+    # 用于 quirc 的外部构建过程,在源目录中运行并生成 libquirc.a
+    externalproject_add(quirc_build
+        PREFIX ${COMPONENT_PATH}
+        SOURCE_DIR ${COMPONENT_PATH}/quirc
+        CONFIGURE_COMMAND ""
+        BUILD_IN_SOURCE 1
+        BUILD_COMMAND make CC=${CMAKE_C_COMPILER} libquirc.a
+        INSTALL_COMMAND ""
+        )
+
+    # 将 libquirc.a 添加到构建系统中
+    add_library(quirc STATIC IMPORTED GLOBAL)
+    add_dependencies(quirc quirc_build)
+
+    set_target_properties(quirc PROPERTIES IMPORTED_LOCATION
+        ${COMPONENT_PATH}/quirc/libquirc.a)
+    set_target_properties(quirc PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
+        ${COMPONENT_PATH}/quirc/lib)
+
+    set_directory_properties( PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
+        "${COMPONENT_PATH}/quirc/libquirc.a")
+
+(上述 CMakeLists.txt 可用于创建名为 ``quirc`` 的组件,该组件使用自己的 Makefile 构建 quirc_ 项目。)
+
+- ``externalproject_add`` 定义了一个外部构建系统。
+
+  - 设置 ``SOURCE_DIR``、``CONFIGURE_COMMAND``、``BUILD_COMMAND`` 和 ``INSTALL_COMMAND``。如果外部构建系统没有配置这一步骤,可以将 ``CONFIGURE_COMMAND`` 设置为空字符串。在 ESP-IDF 的构建系统中,一般会将 ``INSTALL_COMMAND`` 变量设置为空。
+  - 设置 ``BUILD_IN_SOURCE``,即构建目录与源目录相同。否则,您也可以设置 ``BUILD_DIR`` 变量。
+  - 有关 ``externalproject_add()`` 命令的详细信息,请参阅 ExternalProject_。
+
+- 第二组命令添加了一个目标库,指向外部构建系统生成的库文件。为了添加 include 目录,并告知 CMake 该文件的位置,需要再设置一些属性。
+- 最后,生成的库被添加到 `ADDITIONAL_MAKE_CLEAN_FILES`_ 中。即执行 ``make clean`` 后会删除该库。请注意,构建系统中的其他目标文件不会被删除。
+
+.. note:: 当外部构建系统使用 PSRAM 时,请记得将 ``-mfix-esp32-psram-cache-issue`` 添加到 C 编译器的参数中。关于该标志的更多详细信息,请参考 :ref:`CONFIG_SPIRAM_CACHE_WORKAROUND`。
+
+.. _ADDITIONAL_MAKE_CLEAN_FILES_note:
+
+ExternalProject 的依赖与构建清理
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+对于外部项目的构建,CMake 会有一些不同寻常的行为:
+
+- `ADDITIONAL_MAKE_CLEAN_FILES`_ 仅在使用 Make 构建系统时有效。如果使用 Ninja_ 或 IDE 自带的构建系统,执行项目清理时,这些文件不会被删除。
+- ExternalProject_ 会在 clean 运行后自动重新运行配置和构建命令。
+- 可以采用以下两种方法来配置外部构建命令:
+
+  1. 将外部 ``BUILD_COMMAND`` 命令设置为对所有源代码完整的重新编译。如果传递给 ``externalproject_add`` 命令的 ``DEPENDS`` 的依赖项发生了改变,或者当前执行的是项目清理操作(即运行了 ``idf.py clean``、``ninja clean`` 或者 ``make clean``),那么就会执行该命令。
+  2. 将外部 ``BUILD_COMMAND`` 命令设置为增量式构建命令,并给 ``externalproject_add`` 传递 ``BUILD_ALWAYS 1`` 参数。即不管实际的依赖情况,每次构建时,都会构建外部项目。这种方式仅当外部构建系统具备增量式构建的能力,且运行时间不会很长时才推荐。
+
+构建外部项目的最佳方法取决于项目本身、其构建系统,以及是否需要频繁重新编译项目。
+
+.. _custom-sdkconfig-defaults-cmake:
+
+自定义 sdkconfig 的默认值
+=========================
+
+对于示例工程或者其他您不想指定完整 sdkconfig 配置的项目,但是您确实希望覆盖 ESP-IDF 默认值中的某些键值,则可以在项目中创建 ``sdkconfig.defaults`` 文件。重新创建新配置时将会用到此文件,另外在 ``sdkconfig`` 没有设置新配置值时,上述文件也会被用到。
+
+如若需要覆盖此文件的名称,请设置 ``SDKCONFIG_DEFAULTS`` 环境变量。
+
+依赖于硬件目标的 sdkconfig 默认值
+---------------------------------
+
+除了 ``sdkconfig.defaults`` 之外,构建系统还将从 ``sdkconfig.defaults.TARGET_NAME`` 文件加载默认值,其中 ``IDF_TARGET`` 的值为 ``TARGET_NAME``。例如,对于 ``ESP32`` 这个硬件目标,sdkconfig 的默认值会首先从 ``sdkconfig.defaults`` 获取,然后再从 ``sdkconfig.defaults.esp32`` 获取。
+
+如果使用 ``SDKCONFIG_DEFAULTS`` 覆盖了 sdkconfig 默认文件的名称,则硬件目标的 sdkconfig 默认文件名也会从 ``SDKCONFIG_DEFAULTS`` 值中派生。
+
+.. _flash_parameters:
+
+Flash 参数
+==========
+
+有些情况下,我们希望在没有 IDF 时也能烧写目标板卡,为此,我们希望可以保存已构建的二进制文件、esptool.py 和 esptool write_flash 命令的参数。可以通过编写一段简单的脚本来保存二进制文件和 esptool.py。
+
+运行项目构建之后,构建目录将包含项目二进制输出文件(``.bin`` 文件),同时也包含以下烧录数据文件:
+
+- ``flash_project_args`` 包含烧录整个项目的参数,包括应用程序 (app)、引导程序 (bootloader)、分区表,如果设置了 PHY 数据,也会包含此数据。
+- ``flash_app_args`` 只包含烧录应用程序的参数。
+- ``flash_bootloader_args`` 只包含烧录引导程序的参数。
+
+.. highlight:: bash
+
+您可以参照如下命令将任意烧录参数文件传递给 ``esptool.py``::
+
+    python esptool.py --chip esp32 write_flash @build/flash_project_args
+
+也可以手动复制参数文件中的数据到命令行中执行。
+
+构建目录中还包含生成的 ``flasher_args.json`` 文件,此文件包含 JSON 格式的项目烧录信息,可用于 ``idf.py`` 和其它需要项目构建信息的工具。
+
+构建 Bootloader
+===============
+
+引导程序默认作为 ``idf.py build`` 的一部分被构建,也可以通过 ``idf.py bootloader`` 来单独构建。
+
+引导程序是 :idf:`/components/bootloader/subproject` 内部独特的“子项目”,它有自己的项目 CMakeLists.txt 文件,能够构建独立于主项目的 ``.ELF`` 和 ``.BIN`` 文件,同时它又与主项目共享配置和构建目录。
+
+子项目通过 :idf_file:`/components/bootloader/project_include.cmake` 文件作为外部项目插入到项目的顶层,主构建进程会运行子项目的 CMake,包括查找组件(主项目使用的组件的子集),生成引导程序专用的配置文件(从主 ``sdkconfig`` 文件中派生)。
+
+选择硬件目标
+============
+
+当前 ESP-IDF 仅支持一个硬件目标,即 ``esp32``,这也是构建系统默认的硬件目标。开发人员可以按照如下方法来添加对新硬件目标的支持::
+
+    rm sdkconfig
+    idf.py -DIDF_TARGET=new_target reconfigure
+
+.. _write-pure-cmake-component:
+
+编写纯 CMake 组件
+=================
+
+ESP-IDF 构建系统用“组件”的概念“封装”了 CMake,并提供了很多帮助函数来自动将这些组件集成到项目构建当中。
+
+然而,“组件”概念的背后是一个完整的 CMake 构建系统,因此可以制作纯 CMake 组件。
+
+.. highlight:: cmake
+
+下面是使用纯 CMake 语法为 ``json`` 组件编写的最小 CMakeLists 文件的示例::
+
+    add_library(json STATIC
+    cJSON/cJSON.c
+    cJSON/cJSON_Utils.c)
+
+    target_include_directories(json PUBLIC cJSON)
+
+- 这实际上与 IDF 中的 :idf_file:`json 组件 </components/json/CMakeLists.txt>` 是等效的。
+- 因为组件中的源文件不多,所以这个 CMakeLists 文件非常简单。对于具有大量源文件的组件而言,ESP-IDF 支持的组件通配符,可以简化组件 CMakeLists 的样式。
+- 每当组件中新增一个与组件同名的库目标时,ESP-IDF 构建系统会自动将其添加到构建中,并公开公共的 include 目录。如果组件想要添加一个与组件不同名的库目标,就需要使用 CMake 命令手动添加依赖关系。
+
+组件中使用第三方 CMake 项目
+===========================
+
+CMake 在许多开源的 C/C++ 项目中广泛使用,用户可以在自己的应用程序中使用开源代码。CMake 构建系统的一大好处就是可以导入这些第三方的项目,有时候甚至不用做任何改动。这就允许用户使用当前 ESP-IDF 组件尚未提供的功能,或者使用其它库来实现相同的功能。
+
+.. highlight:: cmake
+
+假设 ``main`` 组件需要导入一个假想库 ``foo``,相应的组件 CMakeLists 文件如下所示::
+
+    # 注册组件
+    register_component()
+
+    # 设置 `foo` 项目中的一些 CMake 变量,以控制 `foo` 的构建过程
+    set(FOO_BUILD_STATIC OFF)
+    set(FOO_BUILD_TESTS OFF)
+
+    # 创建并导入第三方库目标
+    add_subdirectory(foo)
+
+    # 将 IDF 全局的编译器设置、宏定义及其它选项传递给 `foo` 目标
+    target_include_directories(foo ${IDF_INCLUDE_DIRECTORIES})
+    target_compile_options(foo ${IDF_COMPILE_OPTIONS})
+    target_compile_definitions(foo ${IDF_COMPILE_DEFINITIONS})
+
+    # 将 `foo` 目标链接至 `main` 组件
+    target_link_libraries(main foo)
+
+实际的案例请参考 :example:`build_system/cmake/import_lib`。请注意,导入第三方库所需要做的工作可能会因库的不同而有所差异。建议仔细阅读第三方库的文档,了解如何将其导入到其它项目中。阅读第三方库的 CMakeLists.txt 文件以及构建结构也会有所帮助。
+
+用这种方式还可以将第三方库封装成 ESP-IDF 的组件。例如 :component:`mbedtls` 组件就是封装了 `mbedtls 项目 <https://github.com/ARMmbed/mbedtls>`_ 得到的。详情请参考 :component_file:`mbedtls 组件的 CMakeLists.txt 文件 <mbedtls/CMakeLists.txt>`。
+
+每当使用 ESP-IDF 构建系统时,CMake 变量 ``ESP_PLATFORM`` 都会被设置为 1。如果要在通用的 CMake 代码加入 IDF 特定的代码时,可以采用 ``if (ESP_PLATFORM)`` 的形式加以分隔。
+
+在自定义 CMake 项目中使用 ESP-IDF
+=================================
+
+ESP-IDF 提供了一个模板 CMake 项目,可以基于此轻松创建应用程序。然而在有些情况下,用户可能已有一个现成的 CMake 项目,或者想自己创建一个 CMake 项目,此时就希望将 IDF 中的组件以库的形式链接到用户目标(库/可执行文件)。
+
+.. highlight:: cmake
+
+使用 :idf_file:`tools/cmake/idf_functions.cmake` 中提供的 ``idf_import_components`` 和 ``idf_link_components`` 函数可以实现上述功能,例如::
+
+    cmake_minimum_required(VERSION 3.5)
+    project(my_custom_app C)
+
+    # 源文件 main.c 包含有 app_main() 函数的定义
+    add_executable(${CMAKE_PROJECT_NAME}.elf main.c)
+
+    # 提供 idf_import_components 及 idf_link_components 函数
+    include($ENV{IDF_PATH}/tools/cmake/idf_functions.cmake)
+
+    # 为 idf_import_components 做一些配置
+    # 使能创建构件(不是每个项目都必须)
+    set(IDF_BUILD_ARTIFACTS ON)
+    set(IDF_PROJECT_EXECUTABLE ${CMAKE_PROJECT_NAME}.elf)
+    set(IDF_BUILD_ARTIFACTS_DIR ${CMAKE_BINARY_DIR})
+
+    # idf_import_components 封装了 add_subdirectory(),为组件创建库目标,然后使用给定的变量接收“返回”的库目标。
+    # 在本例中,返回的库目标被保存在“component”变量中。
+    idf_import_components(components $ENV{IDF_PATH} esp-idf)
+
+    # idf_link_components 封装了 target_link_libraries(),将被 idf_import_components 处理过的组件链接到目标
+    idf_link_components(${CMAKE_PROJECT_NAME}.elf "${components}")
+
+上述代码片段导入了 ESP-IDF 目录下的所有组件,并使用了 KConfig 中的默认值,同时还允许创建其它一些构件(比如分区表、包含项目信息的 json 文件、引导程序等)。除此以外,用户还可以设置其它的构建参数,其完整列表如下:
+
+- ``IDF_BUILD_ARTIFACTS``:构建工件,例如引导加载程序、分区表二进制文件、分区二进制数据、将二进制文件烧录到目标芯片时所需的包含项目信息的 json 文件等。同时需要设置 ``IDF_PROJECT_EXECUTABLE`` 和 ``IDF_BUILD_ARTIFACTS_DIR`` 变量。
+- ``IDF_PROJECT_EXECUTABLE``:最终可执行文件的名称。某些工件在创建的时候需要此参数。
+- ``IDF_BUILD_ARTIFACTS_DIR``:创建的构件被存放的位置。
+- ``IDF_EXTRA_COMPONENTS_DIR``:在 :idf:`默认组件目录 <components>` 之外的组件搜索路径。
+- ``IDF_COMPONENTS``:要导入的组件列表,设置此变量可以精简导入的组件,仅导入需要的组件,加快构建的速度。如果没有设置该变量,将会导入默认组件目录以及 ``IDF_EXTRA_COMPONENTS_DIR`` (如果设置了该变量)中找到的所有组件。请注意,该列表中组件的依赖组件(除了 ``IDF_COMPONENT_REQUIRES_COMMON`` 之外)也会被加入到构建之中。
+- ``IDF_COMPONENT_REQUIRES_COMMON``:通用组件依赖列表。无论 ``IDF_COMPONENTS`` 的值是什么,此列表中的组件及其依赖组件都会被导入到构建中。默认情况下,此变量被设置为核心“系统”组件的最小集合。
+- ``IDF_SDKCONFIG_DEFAULTS``:配置文件的覆盖路径,如果未设置,组件将会使用默认的配置选项来构建。
+- ``IDF_BUILD_TESTS``:在构建中包含组件的测试。默认情况下,所有的组件测试都会被包含。组件测试可通过 ``IDF_TEST_COMPONENTS`` 和 ``IDF_TEST_EXCLUDE_COMPONENTS`` 进行过滤。
+- ``IDF_TEST_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,构建中只会包含此列表中的组件测试。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。
+- ``IDF_TEST_EXCLUDE_COMPONENTS``:如果设置了 ``IDF_BUILD_TESTS``,此列表中的组件测试将不会包含在构建中。如果没有设置 ``IDF_BUILD_TESTS``,请忽略此项。该变量的优先级高于 ``IDF_TEST_COMPONENTS``,这意味着,即使 ``IDF_TEST_COMPONENTS`` 中也存在此列表中的组件测试,它也不会被包含到构建之中。
+
+:example:`build_system/cmake/idf_as_lib` 中的示例演示了如何在自定义的 CMake 项目创建一个类似于 :example:`Hello World <get-started/hello_world>` 的应用程序。
+
+.. _cmake-file-globbing:
+
+文件通配符 & 增量构建
+=====================
+
+.. highlight:: cmake
+
+在 ESP-IDF 组件中添加源文件的首选方法是在 ``COMPONENT_SRCS`` 中手动列出它们::
+
+    set(COMPONENT_SRCS library/a.c library/b.c platform/platform.c)
+
+这是在 CMake 中手动列出源文件的 `最佳实践 <https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1/>`_。然而,当有许多源文件都需要添加到构建中时,这种方法就会很不方便。ESP-IDF 构建系统因此提供了另一种替代方法,即使用 ``COMPONENT_SRCDIRS`` 来指定源文件::
+
+    set(COMPONENT_SRCDIRS library platform)
+
+后台会使用通配符在指定的目录中查找源文件。但是请注意,在使用这种方法的时候,如果组件中添加了一个新的源文件,CMake 并不知道重新运行配置,最终该文件也没有被加入构建中。
+
+如果是自己添加的源文件,这种折衷还是可以接受的,因为用户可以触发一次干净的构建,或者运行 ``idf.py reconfigure`` 来手动重启 CMake_。但是,如果你需要与其他使用 Git 等版本控制工具的开发人员共享项目时,问题就会变得更加困难,因为开发人员有可能会拉取新的版本。
+
+ESP-IDF 中的组件使用了第三方的 Git CMake 集成模块(:idf_file:`/tools/cmake/third_party/GetGitRevisionDescription.cmake`),任何时候源码仓库的提交记录发生了改变,该模块就会自动重新运行 CMake。即只要 拉取了新的 ESP-IDF 版本,CMake 就会重新运行。
+
+对于不属于 ESP-IDF 的项目组件,有以下几个选项供参考:
+
+- 如果项目文件保存在 Git 中,ESP-IDF 会自动跟踪 Git 修订版本,并在它发生变化时重新运行 CMake。
+- 如果一些组件保存在第三方 Git 仓库中(不在项目仓库或 ESP-IDF 仓库),则可以在组件 CMakeLists 文件中调用 ``git_describe`` 函数,以便在 Git 修订版本发生变化时自动重启 CMake。
+- 如果没有使用 Git,请记住在源文件发生变化时手动运行 ``idf.py reconfigure``。
+- 使用 ``COMPONENT_SRCS`` 在项目组件中列出所有源文件,可以完全避免这一问题。
+
+具体选择哪一方式,就要取决于项目本身,以及项目用户。
+
+.. _build_system_metadata:
+
+构建系统的元数据
+================
+
+为了将 ESP-IDF 集成到 IDE 或者其它构建系统中,CMake 在构建的过程中会在 ``build/`` 目录下生成大量元数据文件。运行 ``cmake`` 或 ``idf.py reconfigure`` (或任何其它 ``idf.py`` 构建命令),可以重新生成这些元数据文件。
+
+- ``compile_commands.json`` 是标准格式的 JSON 文件,它描述了在项目中参与编译的每个源文件。CMake 其中的一个功能就是生成此文件,许多 IDE 都知道如何解析此文件。
+- ``project_description.json`` 包含有关 ESP-IDF 项目、已配置路径等的一些常规信息。
+- ``flasher_args.json`` 包含 esptool.py 工具用于烧录项目二进制文件的参数,此外还有 ``flash_*_args`` 文件,可直接与 esptool.py 一起使用。更多详细信息请参阅 :ref:`flash_parameters`。
+- ``CMakeCache.txt`` 是 CMake 的缓存文件,包含 CMake 进程、工具链等其它信息。
+- ``config/sdkconfig.json`` 包含 JSON 格式的项目配置结果。
+- ``config/kconfig_menus.json`` 是在 menuconfig 中显示菜单的 JSON 格式版本,用于外部 IDE 的 UI。
+
+JSON 配置服务器
+---------------
+
+.. highlight :: json
+
+``confserver.py`` 工具可以帮助 IDE 轻松地与配置系统的逻辑进行集成,它运行在后台,通过使用 stdin 和 stdout 读写 JSON 文件的方式与调用进程交互。
+
+您可以通过 ``idf.py confserver`` 或 ``ninja confserver`` 从项目中运行 ``confserver.py``,也可以使用不同的构建生成器来触发类似的目标。
+
+配置服务器会向 stderr 输出方便阅读的错误和警告信息,向 stdout 输出 JSON 文件。启动时,配置服务器将以 JSON 字典的形式输出系统中每个配置项的完整值,以及范围受限的值的可用范围。``sdkconfig.json`` 中包含有相同的信息::
+
+    {"version": 1, "values": { "ITEM": "value", "ITEM_2": 1024, "ITEM_3": false }, "ranges" : { "ITEM_2" : [ 0, 32768 ] } }
+
+配置服务器仅发送可见的配置项,其它不可见的或者被禁用的配置项可从 ``kconfig_menus.json`` 静态文件中解析得到,此文件还包含菜单结构和其它元数据(描述、类型、范围等)。
+
+然后配置服务器将等待客户端的输入,客户端会发起请求,要求更改一个或多个配置项的值,内容的格式是个 JSON 对象,后面跟一个换行符::
+
+    {"version": "1", "set": {"SOME_NAME": false, "OTHER_NAME": true } }
+
+配置服务器将解析此请求,更新 ``sdkconfig`` 文件,并返回完整的变更列表::
+
+    {"version": 1, "values": {"SOME_NAME": false, "OTHER_NAME": true , "DEPENDS_ON_SOME_NAME": null}}
+
+当前不可见或者禁用的配置项会返回 ``null``,任何新的可见配置项则会返回其当前新的可见值。
+
+如果配置项的取值范围因另一个值的变化发生了改变,那么配置服务器会发送::
+
+    {"version": 1, "values": {"OTHER_NAME": true }, "ranges" : { "HAS_RANGE" : [ 3, 4 ] } }
+
+如果传递的数据无效,那么 JSON 对象中会有 ``error`` 字段::
+
+    {"version": 1, "values": {}, "error": ["The following config symbol(s) were not visible so were not updated: NOT_VISIBLE_ITEM"]}
+
+默认情况下,变更后的配置不会被写进 sdkconfig 文件。更改的内容在发出 “save” 命令之前会先储存在内存中::
+
+    {"version": 1, "save": null }
+
+若要从已保存的文件中重新加载配置值,并丢弃内存中的任何更改,可以发送 “load” 命令::
+
+    {"version": 1, "load": null }
+
+“load” 和 “save” 的值可以是新的路径名,也可以设置为 "null" 用以加载/保存之前使用的路径名。
+
+配置服务器对 “load” 命令的响应始终是完整的配置值和取值范围的集合,这与服务器初始启动阶段的响应相同。
+
+“load”、“set” 和 “save” 的任意组合可以在一条单独的命令中发送出去,服务器按照组合中的顺序执行命令。因此,可以使用一条命令实现从文件中加载配置,更新配置值,然后将其保存到文件中。
+
+.. Note:: 配置服务器不会自动加载外部对 ``sdkconfig`` 文件的任何更改。如果文件被外部编辑,则需要发送 “load” 命令或重启服务器。
+
+.. Note:: ``sdkconfig`` 文件更新后,配置服务器不会重新运行 CMake 来生成其它的构建文件和元数据文件。这些文件会在下一次运行 ``CMake`` 或 ``idf.py`` 时自动生成。
+
+.. _gnu-make-to-cmake:
+
+从 ESP-IDF GNU Make 构建系统迁移到 CMake 构建系统
+=================================================
+
+ESP-IDF CMake 构建系统与旧版的 GNU Make 构建系统在某些方面非常相似,例如将 ``component.mk`` 文件改写 ``CMakeLists.txt``,像 ``COMPONENT_ADD_INCLUDEDIRS`` 和 ``COMPONENT_SRCDIRS`` 等变量可以保持不变,只需将语法改为 CMake 语法即可。
+
+自动转换工具
+------------
+
+.. highlight:: bash
+
+:idf_file:`/tools/cmake/convert_to_cmake.py` 中提供了一个项目自动转换工具。运行此命令时需要加上项目路径,如下所示::
+
+    $IDF_PATH/tools/cmake/convert_to_cmake.py /path/to/project_dir
+
+项目目录必须包含 Makefile 文件,并确保主机已安装 GNU Make (``make``) 工具,并且被添加到了 PATH 环境变量中。
+
+该工具会将项目 Makefile 文件和所有组件的 ``component.mk`` 文件转换为对应的 ``CMakeLists.txt`` 文件。
+
+转换过程如下:该工具首先运行 ``make`` 来展开 ESP-IDF 构建系统设置的变量,然后创建相应的 CMakelists 文件来设置相同的变量。
+
+转换工具并不能处理复杂的 Makefile 逻辑或异常的目标,这些需要手动转换。
+
+CMake 中不可用的功能
+--------------------
+
+有些功能已从 CMake 构建系统中移除,或者已经发生很大改变。GNU Make 构建系统中的以下变量已从 CMake 构建系统中删除:
+
+- ``COMPONENT_BUILD_DIR``:由 ``CMAKE_CURRENT_BINARY_DIR`` 替代。
+- ``COMPONENT_LIBRARY``:默认为 ``$(COMPONENT_NAME).a`` 但是库名可以被组件覆盖。在 CMake 构建系统中,组件库名称不可再被组件覆盖。
+- ``CC``、``LD``、``AR``、``OBJCOPY``:gcc xtensa 交叉工具链中每个工具的完整路径。CMake 使用 ``CMAKE_C_COMPILER``、``CMAKE_C_LINK_EXECUTABLE`` 和 ``CMAKE_OBJCOPY`` 进行替代。完整列表请参阅 `CMake 语言变量 <cmake language variables_>`_。
+- ``HOSTCC``、``HOSTLD``、``HOSTAR``:宿主机本地工具链中每个工具的全名。CMake 系统不再提供此变量,外部项目需要手动检测所需的宿主机工具链。
+- ``COMPONENT_ADD_LDFLAGS``:用于覆盖链接标志。CMake 中使用 `target_link_libraries`_ 命令替代。
+- ``COMPONENT_ADD_LINKER_DEPS``:链接过程依赖的文件列表。`target_link_libraries`_ 通常会自动推断这些依赖。对于链接脚本,可以使用自定义的 CMake 函数 ``target_linker_scripts``。
+- ``COMPONENT_SUBMODULES``:不再使用。CMake 会自动枚举 ESP-IDF 仓库中所有的子模块。
+- ``COMPONENT_EXTRA_INCLUDES``:曾是 ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的替代版本,仅支持绝对路径。CMake 系统中统一使用 ``COMPONENT_PRIV_INCLUDEDIRS`` (可以是相对路径,也可以是绝对路径)。
+- ``COMPONENT_OBJS``:以前,可以以目标文件列表的方式指定组件源,现在,可以通过 ``COMPONENT_SRCS`` 以源文件列表的形式指定组件源。
+- ``COMPONENT_OBJEXCLUDE``:已被 ``COMPONENT_SRCEXCLUDE`` 替换。用于指定源文件(绝对路径或组件目录的相对路径)。
+- ``COMPONENT_EXTRA_CLEAN``:已被 ``ADDITIONAL_MAKE_CLEAN_FILES`` 属性取代,注意,:ref:`CMake 对此项功能有部分限制 <ADDITIONAL_MAKE_CLEAN_FILES_note>`。
+- ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``:已被 CMake `外部项目 <ExternalProject>`_ 替代,详细内容请参阅 :ref:`component-build-full-override`。
+- ``COMPONENT_CONFIG_ONLY``:已被 ``register_config_only_component()`` 函数替代,请参阅 :ref:`config_only_component`。
+- ``CFLAGS``、``CPPFLAGS``、``CXXFLAGS``:已被相应的 CMake 命令替代,请参阅 :ref:`component_build_control`。
+
+无默认值的变量
+--------------
+
+以下变量不再具有默认值:
+
+- ``COMPONENT_SRCDIRS``
+- ``COMPONENT_ADD_INCLUDEDIRS``
+
+不再需要的变量
+--------------
+
+如果设置了 ``COMPONENT_SRCS``,就不需要再设置 ``COMPONENT_SRCDIRS``。实际上,CMake 构建系统中如果设置了 ``COMPONENT_SRCDIRS``,那么 ``COMPONENT_SRCS`` 就会被忽略。
+
+从 Make 中烧录
+--------------
+
+仍然可以使用 ``make flash`` 或者类似的目标来构建和烧录,但是项目 ``sdkconfig`` 不能再用来指定串口和波特率。可以使用环境变量来覆盖串口和波特率的设置,详情请参阅 :ref:`flash-with-ninja-or-make`。
+
+.. _esp-idf-template: https://github.com/espressif/esp-idf-template
+.. _Cmake: https://cmake.org
+.. _ninja: https://ninja-build.org
+.. _esptool.py: https://github.com/espressif/esptool/#readme
+.. _CMake v3.5 官方文档: https://cmake.org/cmake/help/v3.5/index.html
+.. _cmake 命令行文档: https://cmake.org/cmake/help/v3.5/manual/cmake.1.html#options
+.. _cmake add_library: https://cmake.org/cmake/help/v3.5/command/add_library.html
+.. _cmake if: https://cmake.org/cmake/help/v3.5/command/if.html
+.. _cmake list: https://cmake.org/cmake/help/v3.5/command/list.html
+.. _cmake project: https://cmake.org/cmake/help/v3.5/command/project.html
+.. _cmake set: https://cmake.org/cmake/help/v3.5/command/set.html
+.. _cmake string: https://cmake.org/cmake/help/v3.5/command/string.html
+.. _cmake faq generated files: https://cmake.org/Wiki/CMake_FAQ#How_can_I_generate_a_source_file_during_the_build.3F
+.. _ADDITIONAL_MAKE_CLEAN_FILES: https://cmake.org/cmake/help/v3.5/prop_dir/ADDITIONAL_MAKE_CLEAN_FILES.html
+.. _ExternalProject: https://cmake.org/cmake/help/v3.5/module/ExternalProject.html
+.. _cmake language variables: https://cmake.org/cmake/help/v3.5/manual/cmake-variables.7.html#variables-for-languages
+.. _set_source_files_properties: https://cmake.org/cmake/help/v3.5/command/set_source_files_properties.html
+.. _target_compile_options: https://cmake.org/cmake/help/v3.5/command/target_compile_options.html
+.. _target_link_libraries: https://cmake.org/cmake/help/v3.5/command/target_link_libraries.html#command:target_link_libraries
+.. _cmake_toolchain_file: https://cmake.org/cmake/help/v3.5/variable/CMAKE_TOOLCHAIN_FILE.html
+.. _quirc: https://github.com/dlbeer/quirc
+.. _pyenv: https://github.com/pyenv/pyenv#README
+.. _virtualenv: https://virtualenv.pypa.io/en/stable/
index a677f3a28f338244b095ec23e32210eab6b749f3..366f7d79f63b7ca3104eae8079bb9c7f0ff1153c 100644 (file)
@@ -1,17 +1,17 @@
-编译系统
+构建系统
 ========
 :link_to_translation:`en:[English]`
 
-本文将介绍乐鑫物联网开发框架中的``编译系统``和``组件``的相关概念。
+本文将介绍乐鑫物联网开发框架中的 ``构建系统`` 和 ``组件`` 的相关概念。
 
 如果您想了解如何构建一个新的 ESP-IDF 项目,请阅读本文档。
 
 我们建议您使用 `ESP-IDF 模板工程 <https://github.com/espressif/esp-idf-template>`_ 来开始您的新项目。
 
-使用编译系统
+使用构建系统
 ------------
 
-ESP-IDF 的 :idf_file:`README.md` 文件对如何使用编译系统来构建项目作了简要的说明。
+ESP-IDF 的 :idf_file:`README.md` 文件对如何使用构建系统来构建项目作了简要的说明。
 
 概述
 ----
@@ -26,7 +26,7 @@ ESP-IDF 的 :idf_file:`README.md` 文件对如何使用编译系统来构建项
 -  湿度传感器的驱动
 -  将上述组件组织在一起的主代码
 
-ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,编译系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,编译系统开始编译整个项目。
+ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,构建系统会查找 ESP-IDF 目录、项目目录和用户自定义目录(可选)中所有的组件,然后使用基于文本的菜单系统让用户配置 ESP-IDF 项目中需要的每个组件。在配置结束后,构建系统开始编译整个项目。
 
 概念
 ~~~~
@@ -65,12 +65,11 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
                 - main/       - src1.c
                               - src2.c
                               - component.mk
-
                 - build/
 
 该示例项目 ``myProject`` 包含以下组成部分:
 
--  项目顶层 Makefile,该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 编译系统的剩余部分。
+-  项目顶层 Makefile,该 Makefile 设置了 ``PROJECT_NAME`` 变量,还可以定义作用于整个项目的其它 make 变量(可选)。顶层 Makefile 会导入核心 Makefile 文件 ``$(IDF_PATH)/make/project.mk`` ,由它负责实现 ESP-IDF 构建系统的剩余部分。
 
 -  项目配置文件 sdkconfig,执行 ``make menuconfig`` 后会创建或更新此文件,该文件中保存了项目中所有组件的配置信息(包括 ESP-IDF 本身)。``sdkconfig`` 文件可能会也可能不会被添加到项目的源代码管理系统中。
 
@@ -78,9 +77,9 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
 
 -  ``main`` 目录是一个特殊的 ``伪组件``,它包含项目本身的源代码。``main`` 是默认名称,Makefile 变量 ``COMPONENT_DIRS`` 默认会导入此组件,但您也可以修改此变量(或者设置 ``EXTRA_COMPONENT_DIRS`` )以查找其他位置的组件。
 
--  ``build`` 目录在项目编译的时候创建或者更新,里面包含有编译生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。
+-  ``build`` 目录在项目构建的时候创建或者更新,里面包含有构建生成的临时目标文件和库以及最终输出的二进制文件。此目录通常不会被添加到项目的源代码管理系统中,也不会随着项目源代码被发布。
 
-组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的编译过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_。
+组件目录中会包含组件自己的 Makefile 文件 ``component.mk`` ,里面会定义一些变量来控制该组件的构建过程,以及它与整个项目的集成。更多详细信息请参考 `组件 Makefiles <#component-makefiles>`_。
 
 每个组件还可以包含一个 ``Kconfig`` 文件,它用于定义 ``menuconfig`` 时展示的组件配置信息的选项规则。某些组件还可能还会包含 ``Kconfig.projbuild`` 和 ``Makefile.projbuild`` 特殊文件,他们可以用来覆盖项目的部分配置。
 
@@ -106,15 +105,15 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
 可选的项目变量
 ^^^^^^^^^^^^^^
 
-以下这些变量都有默认值,用户可以重写这些变量以自定义编译行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。
+以下这些变量都有默认值,用户可以重写这些变量以自定义构建行为。查看 ``make/project.mk`` 文件可以获得所有的实现细节。
 
 -  ``PROJECT_PATH``: 顶层项目目录,默认是包含 Makefile 文件的目录,许多其他的项目变量都基于此变量。注意,项目路径中不能包含有空格。
 -  ``BUILD_DIR_BASE``: 所有对象、库、二进制文件的输出目录,默认为 ``$(PROJECT_PATH)/build``。
--  ``COMPONENT_DIRS``: 搜索组件的目录,默认为 ``$(IDF_PATH)/components``,``$(PROJECT_PATH)/components``,``$(PROJECT_PATH)/main`` 和 ``EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。
+-  ``COMPONENT_DIRS``: 组件的搜索目录,默认为 ``$(IDF_PATH)/components``,``$(PROJECT_PATH)/components``,``$(PROJECT_PATH)/main`` 和 ``EXTRA_COMPONENT_DIRS`` 。如果您不希望从这些目录中搜索组件,请重写此变量。
 -  ``EXTRA_COMPONENT_DIRS``: 组件额外的搜索路径,可选。
--  ``COMPONENTS``: 要编译进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。
--  ``EXCLUDE_COMPONENTS``: 在编译的过程中需要剔除的组件列表,可选。请注意这只会减少编译的时间,并不会减少最终二进制文件的大小。
--  ``TEST_EXCLUDE_COMPONENTS``: 在单元测试的编译过程中需要剔除的组件列表,可选。
+-  ``COMPONENTS``: 要构建进项目中的组件列表,默认为 ``COMPONENT_DIRS`` 指定目录中所有的组件。
+-  ``EXCLUDE_COMPONENTS``: 在构建的过程中需要剔除的组件列表,可选。请注意这只会减少构建的时间,并不会减少最终二进制文件的大小。
+-  ``TEST_EXCLUDE_COMPONENTS``: 在构建单元测试的过程中需要剔除的组件列表,可选。
 
 以上这些 Makefile 变量中的任何路径都要使用绝对路径,您可以使用 ``$(PROJECT_PATH)/xxx``,``$(IDF_PATH)/xxx``,或者使用 Make 内置函数 ``$(abspath xxx)`` 将相对路径转换为绝对路径。
 
@@ -136,8 +135,8 @@ ESP-IDF 可以显式地指定和配置每个组件。在构建项目的时候,
 
 运行 ``make list-components`` 命令可以查询这些变量的值,这有助于调试组件的搜索路径是否正确。
 
\85·æ\9c\89ç\9b¸å\90\8cå\90\8då­\97ç\9a\84å¤\9a个组件
-^^^^^^^^^^^^^^^^^^^^^^
\90\8cå\90\8d组件
+^^^^^^^^
 
 ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进行,这意味着在默认情况下,首先是 ESP-IDF 组件,然后是项目组件,最后是 ``EXTRA_COMPONENT_DIRS`` 中的组件。如果这些目录中的两个或者多个包含具有相同名字的组件,则使用搜索到的最后一个位置的组件。这就允许将组件复制到项目目录中再修改来覆盖 ESP-IDF 组件,如果使用这种方式,ESP-IDF 目录本身可以保持不变。
 
@@ -146,7 +145,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
 最小组件 Makefile
 ^^^^^^^^^^^^^^^^^
 
-最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认编译行为会被设置为:
+最简单的 ``component.mk`` 文件可以是一个空文件,如果文件为空,则组件的默认构建行为会被设置为:
 
 -  makefile 所在目录中的所有源文件(``*.c``,``*.cpp``,``*.cc``,``*.S``)将会被编译进组件库中。
 -  子目录 ``include`` 将被添加到其他组件的全局头文件搜索路径中。
@@ -154,7 +153,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
 
 更完整的组件 makefile 可以查看 `组件 Makefile 示例 <#example-component-makefile>`_。
 
-请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件编译行为,后者不会发生默认的组件编译行为。一个组件中如果只包含影响项目配置或编译过程的文件,那么它可以没有 ``component.mk`` 文件。
+请注意,空的 ``component.mk`` 文件同没有 ``component.mk`` 文件之间存在本质差异,前者会调用默认的组件构建行为,后者不会发生默认的组件构建行为。一个组件中如果只包含影响项目配置或构建过程的文件,那么它可以没有 ``component.mk`` 文件。
 
 .. _preset-component-variables:
 
@@ -165,50 +164,50 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
 
 -  ``COMPONENT_PATH``: 组件的目录,即包含 ``component.mk`` 文件的绝对路径,路径中不能包含空格。
 -  ``COMPONENT_NAME``: 组件的名字,默认为组件目录的名称。
--  ``COMPONENT_BUILD_DIR``: 组件的编译目录,即存放组件编译输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是编译组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。
--  ``COMPONENT_LIBRARY``: 组件编译后的静态库文件(相对于组件的编译目录)的名字,默认为 ``$(COMPONENT_NAME).a``。
+-  ``COMPONENT_BUILD_DIR``: 组件的构建目录,即存放组件构建输出的绝对路径,它是 `$(BUILD_DIR_BASE)` 的子目录。该变量也是构建组件时的当前工作目录,所以 make 中的相对路径都以此目录为基础。
+-  ``COMPONENT_LIBRARY``: 组件构建后的静态库文件(相对于组件的构建目录)的名字,默认为 ``$(COMPONENT_NAME).a``。
 
-以下变量在项目顶层中设置,并被导出到组件中编译时使用:
+以下变量在项目顶层中设置,并被导出到组件中构建时使用:
 
 -  ``PROJECT_NAME``: 项目名称,在项目的 Makefile 中设置。
 -  ``PROJECT_PATH``: 包含项目 Makefile 的目录的绝对路径。
--  ``COMPONENTS``: 此次编译中包含的所有组件的名字。
+-  ``COMPONENTS``: 此次构建中包含的所有组件的名字。
 -  ``CONFIG_*``: 项目配置中的每个值在 make 中都对应一个以 ``CONFIG_`` 开头的变量。
 -  ``CC``,``LD``,``AR``,``OBJCOPY``: gcc xtensa 交叉编译工具链中每个工具的完整路径。
 -  ``HOSTCC``,``HOSTLD``,``HOSTAR``: 主机本地工具链中每个工具的全名。
 -  ``IDF_VER``: ESP-IDF 的版本号,可以通过检索 ``$(IDF_PATH)/version.txt`` 文件(假如存在的话)或者使用 git 命令 ``git describe`` 来获取。这里推荐的格式是在一行中指定主 IDF 的发布版本号,例如标记为 ``v2.0`` 的发布版本或者是标记任意一次提交记录的 ``v2.0-275-g0efaa4f``。应用程序可以通过调用 :cpp:func:`esp_get_idf_version` 函数来使用该变量。
 
-如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的编译,但可能会使您的组件变得难以编译或调试。
+如果您在 ``component.mk`` 文件中修改这些变量,这并不会影响其它组件的构建,但可能会使您的组件变得难以构建或调试。
 
 .. _optional-project-wide-component-variables:
 
 可选的项目通用组件变量
 ^^^^^^^^^^^^^^^^^^^^^^
 
-可以在 ``component.mk`` 中设置以下变量来控制整个项目的编译行为:
+可以在 ``component.mk`` 中设置以下变量来控制整个项目的构建行为:
 
 -  ``COMPONENT_ADD_INCLUDEDIRS``: 相对于组件目录的路径,将被添加到项目中所有组件的头文件搜索路径中。如果该变量未被覆盖,则默认为 ``include`` 目录。如果一个头文件路径仅仅为当前组件所用,那么应该将该路径添加到 ``COMPONENT_PRIV_INCLUDEDIRS`` 中。
 -  ``COMPONENT_ADD_LDFLAGS``: 添加链接参数到全局 ``LDFLAGS`` 中用以指导链接最终的可执行文件,默认为 ``-l$(COMPONENT_NAME)``。如果将预编译好的库添加到此目录,请使用它们为绝对路径,即 ``$(COMPONENT_PATH)/libwhatever.a``。
--  ``COMPONENT_DEPENDS``: 需要在当前组件之前编译的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。
+-  ``COMPONENT_DEPENDS``: 需要在当前组件之前构建的组件列表,这对于处理链接时的依赖不是必需的,因为所有组件的头文件目录始终可用。如果一个组件会生成一个头文件,然后另外一个组件需要使用它,此时该变量就有必要进行设置。大多数的组件不需要设置此变量。
 -  ``COMPONENT_ADD_LINKER_DEPS``: 保存一些文件的路径,当这些文件发生改变时,会触发 ELF 文件重新链接。该变量通常用于链接脚本文件和二进制文件,大多数的组件不需要设置此变量。
 
 以下变量仅适用于属于 ESP-IDF 的组件:
 
--  ``COMPONENT_SUBMODULES``: 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在编译的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。
+-  ``COMPONENT_SUBMODULES``: 组件使用的 git 子模块的路径列表(相对于 ``COMPONENT_PATH``)。这些路径会在构建的过程中被检查(并在必要的时候初始化)。如果组件位于 ``IDF_PATH`` 目录之外,则忽略此变量。
 
 
 可选的组件特定变量
 ^^^^^^^^^^^^^^^^^^
 
-以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的编译行为:
+以下变量可以在 ``component.mk`` 中进行设置,用以控制该组件的构建行为:
 
 -  ``COMPONENT_PRIV_INCLUDEDIRS``: 相对于组件目录的目录路径,该目录仅会被添加到该组件源文件的头文件搜索路径中。
 -  ``COMPONENT_EXTRA_INCLUDES``: 编译组件的源文件时需要指定的额外的头文件搜索路径,这些路径将以 ``-l`` 为前缀传递给编译器。这和  ``COMPONENT_PRIV_INCLUDEDIRS`` 变量的功能有些类似,但是这些路径不会相对于组件目录进行扩展。
 -  ``COMPONENT_SRCDIRS``: 相对于组件目录的目录路径,这些路径用于搜索源文件(``*.cpp``,``*.c``,``*.S``),默认为 ``.``,即组件目录本身。重写该变量可以指定包含源文件的不同目录列表。
 -  ``COMPONENT_OBJS``: 要编译生成的目标文件,默认是 ``COMPONENT_SRCDIRS`` 中每个源文件的 .o 文件。重写该变量将允许您剔除 ``COMPONENT_SRCDIRS`` 中的某些源文件,否则他们将会被编译。相关示例请参阅 `指定需要编译的组件源文件 <#specify-source-files>`_。
--  ``COMPONENT_EXTRA_CLEAN``: 相对于组件编译目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_。
+-  ``COMPONENT_EXTRA_CLEAN``: 相对于组件构建目录的路径,指向 ``component.mk`` 文件中自定义 make 规则生成的任何文件,它们也是 ``make clean`` 命令需要删除的文件。相关示例请参阅 `源代码生成 <#source-code-generation>`_。
 -  ``COMPONENT_OWNBUILDTARGET`` & ``COMPONENT_OWNCLEANTARGET``: 这些目标允许您完全覆盖组件的默认编译行为。有关详细信息,请参阅 `完全覆盖组件的 Makefile <#fully-overriding-component-makefile>`_。
--  ``COMPONENT_CONFIG_ONLY``: 如果设置了此标志,则表示组件根本不会产生编译输出(即不会编译得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。
+-  ``COMPONENT_CONFIG_ONLY``: 如果设置了此标志,则表示组件根本不会产生构建输出(即不会构建得到 ``COMPONENT_LIBRARY``),并且会忽略大多数其它组件变量。此标志用于 IDF 内部组件,其中仅包含 ``KConfig.projbuild`` 和/或 ``Makefile.projbuild`` 文件来配置项目,但是没有源文件。
 -  ``CFLAGS``: 传递给 C 编译器的标志。根据项目设置已经定义一组默认的 ``CFLAGS``,可以通过 ``CFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
 -  ``CPPFLAGS``: 传递给 C 预处理器的标志(用于 ``.c``,``.cpp`` 和 ``.S`` 文件)。根据项目设置已经定义一组默认的 ``CPPFLAGS`` ,可以通过 ``CPPFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
 -  ``CXXFLAGS``: 传递给 C++ 编译器的标志。根据项目设置已经定义一组默认的 ``CXXFLAGS`` ,可以通过 ``CXXFLAGS +=`` 来为组件添加特定的标志,也可以完全重写该变量(尽管不推荐这么做)。
@@ -217,7 +216,7 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
 
 .. code:: makefile
 
-   apps/dhcpserver.o: CFLAGS += -Wno-unused-variable
+    apps/dhcpserver.o: CFLAGS += -Wno-unused-variable
 
 如果上游代码在编译的时候发出了警告,那这么做可能会很有效。
 
@@ -235,12 +234,12 @@ ESP-IDF 搜索组件时,会按照 ``COMPONENT_DIRS`` 指定的顺序依次进
 预处理器定义
 ~~~~~~~~~~~~
 
-ESP-IDF 编译系统会在命令行中添加以下 C 预处理定义:
+ESP-IDF 构建系统会在命令行中添加以下 C 预处理定义:
 
--  ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的编译行为。
+-  ``ESP_PLATFORM`` — 可以用来检测在 ESP-IDF 内发生的构建行为。
 -  ``IDF_VER`` — ESP-IDF 的版本,请参阅 `预设的组件变量 <#preset-component-variables>`_。
 
-编译的内部过程
+构建的内部过程
 ~~~~~~~~~~~~~~
 
 顶层:项目 Makefile
@@ -286,14 +285,14 @@ ESP-IDF 编译系统会在命令行中添加以下 C 预处理定义:
 构建目标的进阶用法
 ~~~~~~~~~~~~~~~~~~
 
-- ``make app``,``make bootloader``,``make partition table`` 可以根据需要为项目单独编译生成应用程序文件、启动引导文件和分区表文件。
+- ``make app``,``make bootloader``,``make partition table`` 可以根据需要为项目单独构建生成应用程序文件、启动引导文件和分区表文件。
 - ``make erase_flash`` 和 ``make erase_ota`` 会调用 esptool.py 脚本分别擦除整块闪存芯片或者其中 OTA 分区的内容。
 - ``make size`` 会打印应用程序的大小信息。``make size-components`` 和 ``make size-files`` 两者功能相似,分别打印每个组件或者每个源文件大小的详细信息。
 
 调试 Make 的过程
 ~~~~~~~~~~~~~~~~
 
-调试 ESP-IDF 编译系统的一些技巧:
+调试 ESP-IDF 构建系统的一些技巧:
 
 -  将 ``V=1`` 添加到 make 的参数中(或将其设置为环境变量)将使 make 回显所有已经执行的命令,以及为子 make 输入的每个目录。
 -  运行 ``make -w`` 将导致 make 在为子 make 输入时回显每个目录——与 ``V=1`` 相同但不回显所有命令。
@@ -360,13 +359,13 @@ Makefile.componentbuild
 增加源文件目录
 ^^^^^^^^^^^^^^
 
-默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知编译系统:
+默认情况下,将忽略子目录。如果您的项目在子目录中而不是在组件的根目录中有源文件,那么您可以通过设置 ``COMPONENT_SRCDIRS`` 将其告知构建系统:
 
 .. code:: 
 
    COMPONENT_SRCDIRS := src1 src2
 
-编译系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。
+构建系统将会编译 src1/ 和 src2/ 子目录中的所有源文件。
 
 .. _specify-source-files:
 
@@ -502,7 +501,7 @@ Makefile.componentbuild
 完全覆盖组件的 Makefile
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 编译系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build`` 和 ``clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。
+显然,在某些情况下,所有这些配置都不足以满足某个组件,例如,当组件基本上是另一个第三方组件的包装器时,该第三方组件最初不打算在 ESP-IDF 构建系统下工作,在这种情况下,可以通过设置 ``COMPONENT_OWNBUILDTARGET`` 和可能的 ``COMPONENT_OWNCLEANTARGET``,并在 ``component.mk`` 中定义名为 ``build`` 和 ``clean`` 的目标。构建目标可以执行任何操作,只要它为项目生成了 ``$(COMPONENT_LIBRARY)`` ,并最终被链接到应用程序二进制文件中即可。
 
 (实际上,这并不是必须的 - 如果 ``COMPONENT_ADD_LDFLAGS`` 变量被覆盖,那么组件可以指示链接器链接其他二进制文件。)
 
@@ -530,10 +529,10 @@ Makefile.componentbuild
 
    python esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x1000 bootloader/bootloader.bin 0x10000 example_app.bin 0x8000 partition_table_unit_test_app.bin
 
-编译 Bootloader
+构建 Bootloader
 ---------------
 
-引导程序默认作为 ``make all`` 的一部分被编译,或者也可以通过 ``make bootloader-clean`` 来独立构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。
+引导程序默认作为 ``make all`` 的一部分被构建,或者也可以通过 ``make bootloader-clean`` 来单独构建,此外还可以通过 ``make bootloader-list-components`` 来查看构建引导程序时包含的组件。
 
 引导程序是一个特殊的组件,因为主项目中的二级引导程序拥有单独的 .EFL 和 .BIN 文件。但是它与主项目共享配置和构建目录。
 
index 2c2eae64f9360aebfaf25496b7fdafe6c13eeaf2..bc205d50eeace5dd06479ebc410dc00d7ded9deb 100644 (file)
@@ -6,8 +6,8 @@ API 指南
    :maxdepth: 1
 
    一般注意事项 <general-notes>
-   编译系统 <build-system>
-   编译系统 (CMake) <build-system-cmake>
+   构建系统 <build-system>
+   构建系统 (CMake) <build-system-cmake>
    错误处理 <error-handling>
    Fatal Errors <fatal-errors>
    Deep Sleep Wake Stubs <deep-sleep-stub>
@@ -16,7 +16,7 @@ API 指南
    FreeRTOS SMP Changes <freertos-smp>
    Thread Local Storage <thread-local-storage>
    High Level Interrupts <hlinterrupts>
-   JTAG Debugging <jtag-debugging/index>
+   JTAG 调试 <jtag-debugging/index>
    Bootloader <bootloader>
    分区表 <partition-tables>
    Secure Boot <../security/secure-boot>
@@ -32,4 +32,4 @@ API 指南
    ESP-MESH <mesh>
    BluFi <blufi>
    External SPI-connected RAM <external-ram>
-   Linker Script Generation <linker-script-generation>
+   链接脚本生成机制 <linker-script-generation>
index 36c4701ad8db838dd075f61ed3ce32b826b5399f..f237599b69cc8731e3d6951a9bf3d0fc0264f498 100644 (file)
@@ -1 +1,76 @@
-.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-linux.rst
\ No newline at end of file
+******************************
+Linux 环境下从源码编译 OpenOCD
+******************************
+:link_to_translation:`en:[English]`
+
+除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-linux` 章节查阅。
+
+
+.. highlight:: bash
+
+下载 OpenOCD 源码
+=================
+
+支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
+
+    cd ~/esp
+    git clone --recursive https://github.com/espressif/openocd-esp32.git
+
+克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
+
+
+安装依赖的软件包
+================
+
+安装编译 OpenOCD 所需的软件包。
+
+.. note::
+
+    依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。
+
+::
+
+    sudo apt-get install make
+    sudo apt-get install libtool
+    sudo apt-get install pkg-config
+    sudo apt-get install autoconf
+    sudo apt-get install automake
+    sudo apt-get install texinfo
+    sudo apt-get install libusb-1.0
+
+.. note::
+
+    * pkg-config 应为 0.2.3 或以上的版本。
+    * autoconf 应为 2.6.4 或以上的版本。
+    * automake 应为 1.9 或以上的版本。
+    * 当使用 USB-Blaster,ASIX Presto,OpenJTAG 和 FT2232 作为适配器时,需要下载安装 libFTDI 和 FTD2XX 的驱动。
+    * 当使用 CMSIS-DAP 时,需要安装 HIDAPI。
+
+
+构建 OpenOCD
+============
+
+配置和构建 OpenOCD 的流程如下::
+
+    cd ~/esp/openocd-esp32
+    ./bootstrap
+    ./configure
+    make
+
+你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。
+
+.. note::
+
+    * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
+    * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
+    * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
+    * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
+    * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README``。
+
+一旦 ``make`` 过程成功结束,OpenOCD 的可执行文件会被保存到 ``~/openocd-esp32/bin`` 目录中。
+
+
+下一步
+======
+
+想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
index 70481a7bf3fd267f94863918e7bc774cb2a70e36..95c42b7e36a802c2c239f555a725c483a9657599 100644 (file)
@@ -1 +1,54 @@
-.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-macos.rst
\ No newline at end of file
+******************************
+MacOS 环境下从源码编译 OpenOCD
+******************************
+:link_to_translation:`en:[English]`
+
+除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-macos` 章节查阅。
+
+.. highlight:: bash
+
+下载 OpenOCD 源码
+=================
+
+支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
+
+    cd ~/esp
+    git clone --recursive https://github.com/espressif/openocd-esp32.git
+
+克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
+
+
+安装依赖的软件包
+================
+
+使用 Homebrew 安装编译 OpenOCD 所需的软件包::
+
+       brew install automake libtool libusb wget gcc@4.9 pkg-config
+
+构建 OpenOCD
+=============
+
+配置和构建 OpenOCD 的流程如下::
+
+    cd ~/esp/openocd-esp32
+    ./bootstrap
+    ./configure
+    make
+
+你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。
+
+.. note::
+
+    * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
+    * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
+    * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
+    * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
+    * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.OSX``。
+
+一旦 ``make`` 过程成功结束,OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。
+
+下一步
+======
+
+想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
+    
\ No newline at end of file
index 34cef1021fdc62afdbcb8e246b70ed9af8f95df2..a9a44c842eaf081d0d89940689773b2fecfb497f 100644 (file)
@@ -1 +1,75 @@
-.. include:: ../../../en/api-guides/jtag-debugging/building-openocd-windows.rst
\ No newline at end of file
+********************************
+Windows 环境下从源码编译 OpenOCD
+********************************
+:link_to_translation:`en:[English]`
+
+除了从 `Espressif 官方 <https://github.com/espressif/openocd-esp32/releases>`_ 直接下载 OpenOCD 可执行文件,你还可以选择从源码编译得到 OpenOCD。如果想要快速设置 OpenOCD 而不是自行编译,请备份好当前文件,前往 :doc:`setup-openocd-windows` 章节查阅。
+
+
+.. highlight:: bash
+
+下载 OpenOCD 源码
+=================
+
+支持 ESP32 的 OpenOCD 源代码可以从乐鑫官方的 GitHub 获得,网址为 https://github.com/espressif/openocd-esp32。请使用以下命令来下载源代码::
+
+    cd ~/esp
+    git clone --recursive https://github.com/espressif/openocd-esp32.git
+
+克隆后的源代码被保存在 ``~/esp/openocd-esp32`` 目录中。
+
+
+安装依赖的软件包
+================
+
+安装编译 OpenOCD 所需的软件包。
+
+.. note::
+
+    依次安装以下软件包,检查安装是否成功,然后继续下一个软件包的安装。在进行下一步操作之前,要先解决当前报告的问题。
+
+::
+
+       pacman -S libtool
+       pacman -S autoconf
+       pacman -S automake
+       pacman -S texinfo
+       pacman -S mingw-w64-i686-libusb-compat-git
+       pacman -S pkg-config
+
+.. note::
+
+       安装 ``pkg-config`` 会破坏 esp-idf 的工具链,因而在 OpenOCD 构建完成后,应将其卸载。详见文末进一步说明。如果想要再次构建 OpenOCD,你需要再次运行 ``pacman -S pkg-config``。此步骤安装的其他软件包(在 ``pkg-config`` 之前)并不会出现这一问题。
+
+
+构建 OpenOCD
+============
+
+配置和构建 OpenOCD 的流程如下::
+
+    cd ~/esp/openocd-esp32
+    ./bootstrap
+    ./configure
+    make
+
+你可以选择最后再执行 ``sudo make install`` ,如果你已经安装过别的开发平台的 OpenOCD,请跳过这个步骤,因为它可能会覆盖掉原来的 OpenOCD。
+
+.. note::
+
+    * 如果发生错误,请解决后再次尝试编译,直到 ``make`` 成功为止。
+    * 如果 OpenOCD 存在子模块问题,请 ``cd`` 到 ``openocd-esp32`` 目录,并输入 ``git submodule update --init`` 命令。
+    * 如果 ``./configure`` 成功运行,JTAG 被使能的信息会被打印在 ``OpenOCD configuration summary`` 下面。
+    * 如果您的设备信息未显示在日志中,请根据 ``../openocd-esp32/doc/INSTALL.txt`` 文中的描述使用 ``./configure`` 启用它。
+    * 有关编译 OpenOCD 的详细信息,请参阅 ``openocd-esp32/README.Windows``。
+
+一旦 ``make`` 过程成功完成,OpenOCD 的可执行文件会被保存到 ``~/esp/openocd-esp32/src/openocd`` 目录中。
+
+如安装依赖步骤所述,最后还需要移除 ``pkg-config`` 软件包::
+
+       pacman -Rs pkg-config
+
+
+下一步
+======
+
+想要进一步配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
index 720df4b505afed3b930af624b600e4928f02466f..6c549d235c1ff15548cabc4c7c15e21f7fcad0c6 100644 (file)
@@ -1 +1,46 @@
-.. include:: ../../../en/api-guides/jtag-debugging/configure-other-jtag.rst
\ No newline at end of file
+配置其它 JTAG 接口
+==================
+:link_to_translation:`en:[English]`
+
+关于适配 OpenOCD 和 ESP32 的 JTAG 接口选择问题,请参考 :ref:`jtag-debugging-selecting-jtag-adapter` 章节,确保 JTAG 适配器能够与 OpenOCD 和 ESP32 一同工作。然后按照以下三个步骤进行设置,使其正常工作。 
+
+
+配置硬件
+^^^^^^^^
+
+1.  找到 JTAG 接口和 ESP32 板上需要相互连接并建立通信的引脚/信号。 
+
+    +---+---------------+-----------+
+    |   | ESP32 引脚    | JTAG 信号 |
+    +===+===============+===========+
+    | 1 | CHIP_PU       | TRST_N    |
+    +---+---------------+-----------+
+    | 2 | MTDO / GPIO15 | TDO       |
+    +---+---------------+-----------+
+    | 3 | MTDI / GPIO12 | TDI       |
+    +---+---------------+-----------+
+    | 4 | MTCK / GPIO13 | TCK       |
+    +---+---------------+-----------+
+    | 5 | MTMS / GPIO14 | TMS       |
+    +---+---------------+-----------+
+    | 6 | GND           | GND       |
+    +---+---------------+-----------+
+
+2.  检查 ESP32 上用于 JTAG 通信的的引脚是否被连接到了其它硬件上,这可能会影响 JTAG 的工作。
+
+3.  连接 ESP32 和 JTAG 接口上的引脚/信号。
+
+
+配置驱动
+^^^^^^^^
+你可能还需要安装软件驱动,才能使 JTAG 在计算机上正常工作,请参阅你所使用的 JTAG 适配器的有关文档,获取相关详细信息。
+
+
+连接
+^^^^
+
+将 JTAG 接口连接到计算机,打开 ESP32 和 JTAG 接口板上的电源,然后检查计算机是否可以识别到 JTAG 接口。
+
+
+要继续设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
+
index d79518837d58a7929b535fff3ea02594e9e69de0..f1ff08c2415491c77989c838cb422df74133d26e 100644 (file)
@@ -1 +1,198 @@
-.. include:: ../../../en/api-guides/jtag-debugging/configure-wrover.rst
\ No newline at end of file
+配置 WROVER 上的 JTAG 接口
+==========================
+:link_to_translation:`en:[English]`
+
+所有版本的 ESP-WROVER-KIT 板子都内置了 JTAG 调试功能,要使其正常工作,还需要设置相关跳帽来启用 JTAG 功能,设置 SPI 闪存电压和配置 USB 驱动程序。具体步骤请参考以下说明。
+
+
+配置硬件
+^^^^^^^^
+
+1.  根据 :doc:`../../get-started/get-started-wrover-kit` 文档中 :ref:`get-started-esp-wrover-kit-setup-options` 章节所描述的信息,设置 JP8 便可以启用 JTAG 功能。 
+
+2.  检查 ESP32 上用于 JTAG 通信的引脚是否被接到了其它硬件上,这可能会影响 JTAG 的工作。
+
+    +---+---------------+-----------+
+    |   | ESP32 引脚    | JTAG 信号 |
+    +===+===============+===========+
+    | 1 | CHIP_PU       | TRST_N    |
+    +---+---------------+-----------+
+    | 2 | MTDO / GPIO15 | TDO       |
+    +---+---------------+-----------+
+    | 3 | MTDI / GPIO12 | TDI       |
+    +---+---------------+-----------+
+    | 4 | MTCK / GPIO13 | TCK       |
+    +---+---------------+-----------+
+    | 5 | MTMS / GPIO14 | TMS       |
+    +---+---------------+-----------+
+
+
+配置 USB 驱动
+^^^^^^^^^^^^^
+
+安装和配置 USB 驱动,这样 OpenOCD 才能够与 ESP-WROVER-KIT 板上的 JTAG 接口通信,并且使用 UART 接口上传待烧写的镜像文件。请根据你的操作系统按照以下步骤进行安装配置。
+
+.. note:: ESP-WROVER-KIT 使用了 FT2232 芯片实现了 JTAG 适配器,所以以下说明同样适用于其他基于 FT2232 的 JTAG 适配器。
+
+
+Windows
+"""""""
+
+1.  使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。
+
+2.  等待 Windows 识别出 ESP-WROVER-KIT 并且为其安装驱动。如果驱动没有被自动安装,请前往 `官网 <http://www.ftdichip.com/Drivers/D2XX.htm>`_ 下载并手动安装。
+
+3.  从 `Zadig 官网 <http://zadig.akeo.ie/>`_ 下载 Zadig 工具(Zadig_X.X.exe)并运行。
+
+4.  在 Zadig 工具中,进入 “Options” 菜单中选中 “List All Devices”。
+
+5.  检查设备列表,其中应该包含两条与 ESP-WROVER-KIT 相关的条目:“Dual RS232-HS (Interface 0)” 和 “Dual RS232-HS (Interface 1)”。驱动的名字应该是 “FTDIBUS (vxxxx)” 并且 USB ID 为:0403 6010。
+
+    .. figure:: ../../../_static/jtag-usb-configuration-zadig.jpg
+        :align: center
+        :alt: Configuration of JTAG USB driver in Zadig tool
+        :figclass: align-center
+
+        在 Zadig 工具中配置 JTAG USB 驱动
+
+6.  第一个设备 “Dual RS232-HS(Interface 0)” 连接到了 ESP32 的 JTAG 端口,此设备原来的 “FTDIBUS (vxxxx)” 驱动需要替换成 "WinUSB (v6xxxxx)"。为此,请选择 “Dual RS232-HS (Interface 0)” 并将驱动重新安装为 “WinUSB (v6xxxxx)”,具体可以参考上图。
+
+.. note::
+
+    请勿更改第二个设备 “Dual RS232-HS(Interface 1)” 的驱动,它被连接到 ESP32 的串口(UART),用于上传应用程序映像给 ESP32 进行烧写。
+
+现在,ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
+
+
+Linux
+"""""
+
+1.  使用标准 USB A / micro USB B 线将 ESP-WROVER-KIT 与计算机相连接,并打开板子的电源。
+
+.. highlight:: none
+
+2.  打开终端,输入 ``ls -l /dev/ttyUSB*`` 命令检查操作系统是否能够识别板子的 USB 端口。类似识别结果如下:
+
+    ::
+
+        user-name@computer-name:~/esp$ ls -l /dev/ttyUSB*
+        crw-rw---- 1 root dialout 188, 0 Jul 10 19:04 /dev/ttyUSB0
+        crw-rw---- 1 root dialout 188, 1 Jul 10 19:04 /dev/ttyUSB1
+
+
+3.  根据 `OpenOCD README 文档 <https://sourceforge.net/p/openocd/code/ci/master/tree/README>`_ 中 “Permissions delegation” 小节的介绍,设置这两个 USB 端口的访问权限。
+
+4.  注销并重新登录 Linux 系统,然后重新插拔板子的电源使之前的改动生效。在终端再次输入 ``ls -l /dev/ttyUSB*`` 命令进行验证,查看这两个设备的组所有者是否已经从 ``dialout`` 更改为 ``plugdev``:
+
+    ::
+
+        user-name@computer-name:~/esp$ ls -l /dev/ttyUSB*
+        crw-rw-r-- 1 root plugdev 188, 0 Jul 10 19:07 /dev/ttyUSB0
+        crw-rw-r-- 1 root plugdev 188, 1 Jul 10 19:07 /dev/ttyUSB1
+
+    如果看到类似的输出结果,并且你也是 ``plugdev`` 组的成员, 那么设置工作就完成了。
+
+    具有较低编号的 ``/dev/ttyUSBn`` 接口用于 JTAG 通信,另一路接口被连接到 ESP32 的串口(UART),用于上传应用程序映像给 ESP32 进行烧写。
+
+现在,ESP-WROVER-KIT 的 JTAG 接口应该可以被 OpenOCD 使用了,想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
+
+
+MacOS
+"""""
+
+在 macOS 上,同时使用 FT2232 的 JTAG 接口和串口还需另外进行其它操作。当操作系统加载 FTDI 串口驱动的时候,它会对 FT2232 芯片的两个通道做相同的操作。但是,这两个通道中只有一个是被用作串口,而另一个用于 JTAG,如果操作系统已经为用于 JTAG 的通道加载了 FTDI 串口驱动的话,OpenOCD 将无法连接到芯片。有两个方法可以解决这个问题: 
+
+1. 在启动 OpenOCD 之前手动卸载 FTDI 串口驱动程序,然后启动 OpenOCD,再加载串口驱动程序。
+
+2. 修改 FTDI 驱动程序的配置,使其不会为 FT2232 芯片的通道 B 进行自我加载,该通道用于 ESP-WROVER-KIT 板上的 JTAG 通道。 
+
+手动卸载驱动程序
+................
+
+1. 从 `FTDI 官网 <http://www.ftdichip.com/Drivers/VCP.htm>`_ 安装驱动。
+
+2. 使用 USB 线连接 ESP-WROVER-KIT。
+
+3. 卸载串口驱动 ::
+
+    sudo kextunload -b com.FTDI.driver.FTDIUSBSerialDriver
+
+   有时,您可能还需要卸载苹果的 FTDI 驱动::
+
+    sudo kextunload -b com.apple.driver.AppleUSBFTDI
+
+4. 运行 OpenOCD(以下路径为 Github 上可供下载的预编译后的 OpenOCD)::
+
+    bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
+
+   如果 OpenOCD 是从源码编译得到的,那么路径需要做相应修改::
+
+    src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
+
+5. 在另一个终端窗口,再一次加载 FTDI 串口驱动::
+
+    sudo kextload -b com.FTDI.driver.FTDIUSBSerialDriver
+
+.. include:: ./windows-openocd-note.rst
+
+.. note::
+
+   如果你需要重启 OpenOCD,则无需再次卸载 FTDI 驱动程序,只需停止 OpenOCD 并再次启动它。只有在重新连接 ESP-WROVER-KIT 或者切换了电源的情况下才需要再次卸载驱动。
+
+你也可以根据自身需求,将此过程包装进 shell 脚本中。
+
+修改 FTDI 驱动
+..............
+
+简而言之,这种方法需要修改 FTDI 驱动程序的配置文件,这样可以防止为 FT2232H 的通道 B 自动加载串口驱动。
+
+.. note:: 其他板子可能将通道 A 用于 JTAG,因此请谨慎使用此选项。
+
+.. warning:: 此方法还需要操作系统禁止对驱动进行签名验证,因此可能无法被所有的用户所接受。
+
+
+1. 使用文本编辑器打开 FTDI 驱动的配置文件(注意 ``sudo``)::
+
+    sudo nano /Library/Extensions/FTDIUSBSerialDriver.kext/Contents/Info.plist
+
+2. 找到并删除以下几行::
+
+        <key>FT2232H_B</key>
+        <dict>
+            <key>CFBundleIdentifier</key>
+            <string>com.FTDI.driver.FTDIUSBSerialDriver</string>
+            <key>IOClass</key>
+            <string>FTDIUSBSerialDriver</string>
+            <key>IOProviderClass</key>
+            <string>IOUSBInterface</string>
+            <key>bConfigurationValue</key>
+            <integer>1</integer>
+            <key>bInterfaceNumber</key>
+            <integer>1</integer>
+            <key>bcdDevice</key>
+            <integer>1792</integer>
+            <key>idProduct</key>
+            <integer>24592</integer>
+            <key>idVendor</key>
+            <integer>1027</integer>
+        </dict>
+
+3. 保存并关闭文件
+
+4. 禁用驱动的签名认证:
+
+   1. 点击苹果的 logo,选择 “Restart...”
+
+   2. 重启后当听到响铃时,立即按下键盘上的 CMD+R 组合键
+
+   3. 进入恢复模式后,打开终端
+
+   4. 运行命令::
+
+       csrutil enable --without kext
+
+   5. 再一次重启系统
+
+完成这些步骤后,可以同时使用串口和 JTAG 接口了。
+
+想要进一步设置调试环境,请前往 :ref:`jtag-debugging-run-openocd` 章节。
index ee8c9594c055a36d56e68cd2d8ad4dd890dc30a8..c79d40d7759e003d5c8e4ecd987af0069795d98f 100644 (file)
@@ -1 +1,655 @@
-.. include:: ../../../en/api-guides/jtag-debugging/debugging-examples.rst
\ No newline at end of file
+调试示例
+========
+:link_to_translation:`en:[English]`
+
+本节将介绍如何在 :ref:`Eclipse <jtag-debugging-examples-eclipse>` 和 :ref:`命令行 <jtag-debugging-examples-command-line>` 中使用 GDB 进行调试的示例。
+
+.. highlight:: none
+
+.. _jtag-debugging-examples-eclipse:
+
+使用 Eclipse 的调试示例
+-----------------------
+
+请检查目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-eclipse` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止。
+
+.. figure:: ../../../_static/debug-perspective.jpg
+    :align: center
+    :alt: Debug Perspective in Eclipse
+    :figclass: align-center
+
+    Eclipse 中的 Debug 视图
+
+
+本小节的示例
+^^^^^^^^^^^^
+
+1. :ref:`jtag-debugging-examples-eclipse-01`
+2. :ref:`jtag-debugging-examples-eclipse-02`
+3. :ref:`jtag-debugging-examples-eclipse-03`
+4. :ref:`jtag-debugging-examples-eclipse-04`
+5. :ref:`jtag-debugging-examples-eclipse-05`
+6. :ref:`jtag-debugging-examples-eclipse-06`
+7. :ref:`jtag-debugging-examples-eclipse-07`
+
+
+.. _jtag-debugging-examples-eclipse-01:
+
+浏览代码,查看堆栈和线程
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+当目标暂停时,调试器会在 “Debug” 窗口中显示线程的列表,程序暂停的代码行在下面的另一个窗口中被高亮显示,如下图所示。此时板子上的 LED 停止了闪烁。 
+
+.. figure:: ../../../_static/debugging-target-halted.jpg
+    :align: center
+    :alt: Target halted during debugging
+    :figclass: align-center
+
+    调试时目标停止
+
+暂停的程序所在线程也会被展开,显示函数调用的堆栈,它表示直到目标暂停所在代码行(下图高亮处)为止的相关函数的调用关系。1 号线程下函数调用堆栈的第一行包含了最后一个调用的函数 ``app_main()``,根据下一行显示,它又是在函数 ``main_task()`` 中被调用的。堆栈的每一行还包含调用函数的文件名和行号。通过单击每个堆栈的条目,在下面的窗口中,你将看到此文件的内容。 
+
+通过展开线程,你可以浏览整个应用程序。展开 5 号线程,它包含了更长的函数调用堆栈,你可以看到函数调用旁边的数字,比如 ``0x4000000c``,它们代表未以源码形式提供的二进制代码所在的内存地址。
+
+.. figure:: ../../../_static/debugging-navigate-through-the-stack.jpg
+    :align: center
+    :alt: Navigate through the call stack
+    :figclass: align-center
+
+    浏览函数调用堆栈
+
+无论项目是以源代码还是仅以二进制形式提供,在右边一个窗口中,都可以看到反汇编后的机器代码。
+
+回到 1 号线程中的 ``app_main()`` 函数所在的 ``blink.c`` 源码文件,下面的示例将会以该文件为例介绍调试的常用功能。调试器可以轻松浏览整个应用程序的代码,这给单步调试代码和设置断点带来了很大的便利,下面将一一展开讨论。
+
+
+.. _jtag-debugging-examples-eclipse-02:
+
+设置和清除断点
+^^^^^^^^^^^^^^
+
+在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。
+
+我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。按住键盘上的 “Control” 键,双击 blink.c 文件中的行号 33,并在弹出的对话框中点击 “OK” 按钮进行确定。如果你不想看到此对话框,双击行号即可。执行同样操作,在第 36 行设置另外一个断点。
+
+.. figure:: ../../../_static/debugging-setting-breakpoint.jpg
+    :align: center
+    :alt: Setting a breakpoint
+    :figclass: align-center
+
+    设置断点
+
+断点的数量和位置信息会显示在右上角的“断点”窗口中。单击 “Show Breakpoints Supported by Selected Target” 图标可以刷新此列表。除了刚才设置的两个断点外,列表中可能还包含在调试器启动时设置在 ``app_main()`` 函数处的临时断点。由于最多只允许设置两个断点(详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`),你需要将其删除,否则调试会失败。
+
+.. figure:: ../../../_static/debugging-three-breakpoints-set.jpg
+    :align: center
+    :alt: Three breakpoints are set / maximum two are allowed
+    :figclass: align-center
+
+    设置了三个断点 / 最多允许两个断点
+
+单击 “Resume”(如果 “Resume” 按钮是灰色的,请先单击 8 号线程的 ``blink_task()`` 函数)后处理器将开始继续运行,并在断点处停止。再一次单击 “Resume” 按钮,使程序再次运行,然后停在第二个断点处,依次类推。
+
+每次单击 “Resume” 按钮恢复程序运行后,都会看到 LED 切换状态。
+
+更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints` 和 :ref:`jtag-debugging-tip-where-breakpoints`。
+
+
+.. _jtag-debugging-examples-eclipse-03:
+
+手动暂停目标
+^^^^^^^^^^^^
+
+在调试时,你可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。后者,如果想要返回调试模式,可以通过单击 “Suspend” 按钮来手动中断程序的运行。
+
+在此之前,请删除所有的断点,然后单击 “Resume” 按钮。接着单击 “Suspend” 按钮,应用程序会停止在某个随机的位置,此时 LED 也将停止闪烁。调试器将展开线程并高亮显示停止的代码行。
+
+.. figure:: ../../../_static/debugging-target-halted-manually.jpg
+    :align: center
+    :alt: Target halted manually
+    :figclass: align-center
+
+    手动暂停目标
+
+在上图所示的情况中,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在你可以通过单击 “Resume” 按钮再次将其恢复运行或者进行下面要介绍的调试工作。
+
+
+.. _jtag-debugging-examples-eclipse-04:
+
+单步执行代码
+^^^^^^^^^^^^
+
+我们还可以使用 “Step Into (F5)” 和 “Step Over (F6)” 命令单步执行代码, 这两者之间的区别是执行 “Step Into (F5)” 命令会进入调用的子程序,而执行 “Step Over (F6)” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。
+
+在继续演示此功能之前,请参照上文所述确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点。
+
+按下 F8 键让程序继续运行然后在断点处停止运行,多次按下 “Step Over (F6)” 按钮,观察调试器是如何单步执行一行代码的。
+
+.. figure:: ../../../_static/debugging-step-over.jpg
+    :align: center
+    :alt: Stepping through the code with "Step Over (F6)"
+    :figclass: align-center
+
+    使用 “Step Over (F6)” 单步执行代码
+
+如果你改用 "Step Into (F5)",那么调试器将会进入调用的子程序内部。
+
+.. figure:: ../../../_static/debugging-step-into.jpg
+    :align: center
+    :alt: Stepping through the code with "Step Into (F5)"
+    :figclass: align-center
+
+    使用 “Step Into (F5)” 单步执行代码
+
+在上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。
+
+请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。
+
+
+.. _jtag-debugging-examples-eclipse-05:
+
+查看并设置内存
+^^^^^^^^^^^^^^
+
+要显示或者设置内存的内容,请使用“调试”视图中位于底部的 “Memory” 选项卡。
+
+在 “Memory” 选项卡下,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf>`_ 中的 IO_MUX 和 GPIO Matrix 章节。
+
+同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点,单击 “Memory” 选项卡,然后单击 “Add Memory Monitor” 按钮,在弹出的对话框中输入 ``0x3FF44004``。
+
+按下 F8 按键恢复程序运行,并观察 “Monitor” 选项卡。
+
+.. figure:: ../../../_static/debugging-memory-location-on.jpg
+    :align: center
+    :alt: Observing memory location 0x3FF44004 changing one bit to ON"
+    :figclass: align-center
+
+    观察内存地址 0x3FF44004 处的某个比特被置高
+
+每按一下 F8,你就会看到在内存 ``0x3FF44004`` 地址处的一个比特位被翻转(并且 LED 会改变状态)。
+
+.. figure:: ../../../_static/debugging-memory-location-off.jpg
+    :align: center
+    :alt: Observing memory location 0x3FF44004 changing one bit to ON"
+    :figclass: align-center
+
+    观察内存地址 0x3FF44004 处的某个比特被置低
+
+要修改内存的数值,请在 “Monitor” 选项卡中找到待修改的内存地址,如前面观察的结果一样,输入特定比特翻转后的值。当按下回车键后,将立即看到 LED 的状态发生了改变。
+
+.. _jtag-debugging-examples-eclipse-06:
+
+观察和设置程序变量
+^^^^^^^^^^^^^^^^^^
+
+常见的调试任务是在程序运行期间检查程序中某个变量的值,为了演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。
+
+退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。
+
+一旦程序停止运行,在代码 ``i++`` 处添加一个断点。
+
+下一步,在 “Breakpoints” 所在的窗口中,选择 “Expressions” 选项卡。如果该选项卡不存在,请在顶部菜单栏的 Window > Show View > Expressions 中添加这一选项卡。然后在该选项卡中单击 “Add new expression”,并输入 ``i``。
+
+按下 F8 继续运行程序,每次程序停止时,都会看到变量 ``i`` 的值在递增。
+
+.. figure:: ../../../_static/debugging-watch-variable.jpg
+    :align: center
+    :alt: Watching program variable "i"
+    :figclass: align-center
+
+    观察程序变量 “i”
+
+
+如想更改 ``i`` 的值,可以在 “Value” 一栏中输入新的数值。按下 “Resume (F8)” 后,程序将从新输入的数字开始递增 ``i``。
+
+
+.. _jtag-debugging-examples-eclipse-07:
+
+设置条件断点
+^^^^^^^^^^^^
+
+接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点,然后让程序停止运行。右击断点打开上下文菜单,选择 “Breakpoint Properties”,将 “Type:” 改选为 “Hardware” 然后在 “Condition:” 一栏中输入条件表达式,例如 ``i == 2``。
+
+.. figure:: ../../../_static/debugging-setting-conditional-breakpoint.jpg
+    :align: center
+    :alt: Setting a conditional breakpoint
+    :figclass: align-center
+
+    设置条件断点
+
+如果当前 ``i`` 的值小于 ``2`` (如果有需要也可以更改这个阈值)并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处。
+
+
+.. _jtag-debugging-examples-command-line:
+
+使用命令行的调试示例
+--------------------
+
+请检查您的目标板是否已经准备好,并加载了 :example:`get-started/blink` 示例代码,然后按照 :ref:`jtag-debugging-using-debugger-command-line` 中介绍的步骤配置和启动调试器,最后选择让应用程序在 ``app_main()`` 建立的断点处停止运行 ::
+
+       Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
+       43          xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
+       (gdb) 
+
+
+
+本小节的示例
+^^^^^^^^^^^^
+
+1. :ref:`jtag-debugging-examples-command-line-01`
+2. :ref:`jtag-debugging-examples-command-line-02`
+3. :ref:`jtag-debugging-examples-command-line-03`
+4. :ref:`jtag-debugging-examples-command-line-04`
+5. :ref:`jtag-debugging-examples-command-line-05`
+6. :ref:`jtag-debugging-examples-command-line-06`
+7. :ref:`jtag-debugging-examples-command-line-07`
+
+
+.. _jtag-debugging-examples-command-line-01:
+
+浏览代码,查看堆栈和线程
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+当看到 ``(gdb)`` 提示符的时候,应用程序已停止运行,LED 也停止闪烁。 
+
+要找到代码暂停的位置,输入 ``l`` 或者 ``list`` 命令,调试器会打印出停止点(``blink.c`` 代码文件的第 43 行)附近的几行代码 ::
+
+       (gdb) l
+       38          }
+       39      }
+       40      
+       41      void app_main()
+       42      {
+       43          xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
+       44      }
+       (gdb) 
+
+
+也可以通过输入 ``l 30, 40`` 等命令来查看特定行号范围内的代码。
+
+使用 ``bt`` 或者 ``backtrace`` 来查看哪些函数最终导致了此代码被调用::
+
+       (gdb) bt
+       #0  app_main () at /home/user-name/esp/blink/main/./blink.c:43
+       #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
+       (gdb) 
+
+输出的第 0 行表示应用程序暂停之前调用的最后一个函数,即我们之前列出的 ``app_main ()``。``app_main ()`` 又被位于 ``cpu_start.c`` 文件第 339 行的 ``main_task`` 函数调用。 
+
+想查看 ``cpu_start.c`` 文件中 ``main_task`` 函数的上下文,需要输入 ``frame  N``,其中 N = 1,因为根据前面的输出,``main_task`` 位于 #1 下::
+
+       (gdb) frame 1
+       #1  0x400d057e in main_task (args=0x0) at /home/user-name/esp/esp-idf/components/esp32/./cpu_start.c:339
+       339         app_main();
+       (gdb)
+
+输入 ``l`` 将显示一段名为 ``app_main()`` 的代码(在第 339 行)::
+
+       (gdb) l
+       334             ;
+       335         }
+       336     #endif
+       337         //Enable allocation in region where the startup stacks were located.
+       338         heap_caps_enable_nonos_stack_heaps();
+       339         app_main();
+       340         vTaskDelete(NULL);
+       341     }
+       342     
+       (gdb) 
+
+通过打印前面的一些行,你会看到我们一直在寻找的 ``main_task`` 函数::
+
+       (gdb) l 326, 341
+       326     static void main_task(void* args)
+       327     {
+       328         // Now that the application is about to start, disable boot watchdogs
+       329         REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
+       330         REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
+       331     #if !CONFIG_FREERTOS_UNICORE
+       332         // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
+       333         while (port_xSchedulerRunning[1] == 0) {
+       334             ;
+       335         }
+       336     #endif
+       337         //Enable allocation in region where the startup stacks were located.
+       338         heap_caps_enable_nonos_stack_heaps();
+       339         app_main();
+       340         vTaskDelete(NULL);
+       341     }
+       (gdb) 
+
+如果要查看其他代码,可以输入 ``i threads`` 命令,则会输出目标板上运行的线程列表::
+
+       (gdb) i threads
+         Id   Target Id         Frame 
+         8    Thread 1073411336 (dport) 0x400d0848 in dport_access_init_core (arg=<optimized out>)
+           at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:170
+         7    Thread 1073408744 (ipc0) xQueueGenericReceive (xQueue=0x3ffae694, pvBuffer=0x0, xTicksToWait=1644638200, 
+           xJustPeeking=0) at /home/user-name/esp/esp-idf/components/freertos/./queue.c:1452
+         6    Thread 1073431096 (Tmr Svc) prvTimerTask (pvParameters=0x0)
+           at /home/user-name/esp/esp-idf/components/freertos/./timers.c:445
+         5    Thread 1073410208 (ipc1 : Running) 0x4000bfea in ?? ()
+         4    Thread 1073432224 (dport) dport_access_init_core (arg=0x0)
+           at /home/user-name/esp/esp-idf/components/esp32/./dport_access.c:150
+         3    Thread 1073413156 (IDLE) prvIdleTask (pvParameters=0x0)
+           at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
+         2    Thread 1073413512 (IDLE) prvIdleTask (pvParameters=0x0)
+           at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:3282
+       * 1    Thread 1073411772 (main : Running) app_main () at /home/user-name/esp/blink/main/./blink.c:43
+       (gdb) 
+
+线程列表显示了每个线程最后一个被调用的函数以及所在的 C 源文件名(如果存在的话)。
+
+您可以通过输入 ``thread N`` 进入特定的线程,其中 ``N`` 是线程 ID。我们进入 5 号线程来看一下它是如何工作的::
+
+       (gdb) thread 5
+       [Switching to thread 5 (Thread 1073410208)]
+       #0  0x4000bfea in ?? ()
+       (gdb)
+
+然后查看回溯::
+
+       (gdb) bt
+       #0  0x4000bfea in ?? ()
+       #1  0x40083a85 in vPortCPUReleaseMutex (mux=<optimized out>) at /home/user-name/esp/esp-idf/components/freertos/./port.c:415
+       #2  0x40083fc8 in vTaskSwitchContext () at /home/user-name/esp/esp-idf/components/freertos/./tasks.c:2846
+       #3  0x4008532b in _frxt_dispatch ()
+       #4  0x4008395c in xPortStartScheduler () at /home/user-name/esp/esp-idf/components/freertos/./port.c:222
+       #5  0x4000000c in ?? ()
+       #6  0x4000000c in ?? ()
+       #7  0x4000000c in ?? ()
+       #8  0x4000000c in ?? ()
+       (gdb) 
+
+如上所示,回溯可能会包含多个条目,方便查看直至目标停止运行的函数调用顺序。如果找不到某个函数的源码文件,将会使用问号 ``??`` 替代,这表示该函数是以二进制格式提供的。像 ``0x4000bfea`` 这样的值是被调用函数所在的内存地址。
+
+使用诸如 ``bt``, ``i threads``, ``thread N`` 和 ``list`` 命令可以浏览整个应用程序的代码。这给单步调试代码和设置断点带来很大的便利,下面将一一展开来讨论。
+
+
+.. _jtag-debugging-examples-command-line-02:
+
+设置和清除断点
+^^^^^^^^^^^^^^
+
+在调试时,我们希望能够在关键的代码行停止应用程序,然后检查特定的变量、内存、寄存器和外设的状态。为此我们需要使用断点,以便在特定某行代码处快速访问和停止应用程序。
+
+我们在控制 LED 状态发生变化的两处代码行分别设置一个断点。基于以上代码列表,这两处分别为第 33 和 36 代码行。使用命令 ``break M`` 设置断点,其中 M 是具体的代码行::
+
+    (gdb) break 33
+    Breakpoint 2 at 0x400db6f6: file /home/user-name/esp/blink/main/./blink.c, line 33.
+    (gdb) break 36
+    Breakpoint 3 at 0x400db704: file /home/user-name/esp/blink/main/./blink.c, line 36.
+
+输入命令 ``c``,处理器将运行并在断点处停止。再次输入 ``c`` 将使其再次运行,并在第二个断点处停止,依此类推::
+
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB6F6 (active)    APP_CPU: PC=0x400D10D8 
+
+    Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33
+    33          gpio_set_level(BLINK_GPIO, 0);
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB6F8 (active)    APP_CPU: PC=0x400D10D8 
+    Target halted. PRO_CPU: PC=0x400DB704 (active)    APP_CPU: PC=0x400D10D8 
+
+    Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36
+    36          gpio_set_level(BLINK_GPIO, 1);
+    (gdb) 
+
+只有在输入命令 ``c`` 恢复程序运行后才能看到 LED 改变状态。
+
+查看已设置断点的数量和位置,请使用命令 ``info break``::
+
+    (gdb) info break
+    Num     Type           Disp Enb Address    What
+    2       breakpoint     keep y   0x400db6f6 in blink_task at /home/user-name/esp/blink/main/./blink.c:33
+        breakpoint already hit 1 time
+    3       breakpoint     keep y   0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36
+        breakpoint already hit 1 time
+    (gdb) 
+
+请注意,断点序号(在 ``Num`` 栏列出)从 2 开始,这是因为在调试器启动时执行 ``thb app_main`` 命令已经在 ``app_main()`` 函数处建立了第一个断点。由于它是一个临时断点,已经被自动删除,所以没有被列出。
+
+要删除一个断点,请输入 ``delete N`` 命令(或者简写成 ``d N``),其中 ``N`` 代表断点序号:: 
+
+    (gdb) delete 1
+    No breakpoint number 1.
+    (gdb) delete 2
+    (gdb) 
+
+更多关于断点的信息,请参阅 :ref:`jtag-debugging-tip-breakpoints` 和 :ref:`jtag-debugging-tip-where-breakpoints`。
+
+
+.. _jtag-debugging-examples-command-line-03:
+
+暂停和恢复应用程序的运行
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+在调试时,可以恢复程序运行并输入代码等待某个事件发生或者保持无限循环而不设置任何断点。对于后者,想要返回调试模式,可以通过输入 Ctrl+C 手动中断程序的运行。
+
+在此之前,请删除所有的断点,然后输入 ``c`` 恢复程序运行。接着输入 Ctrl+C,应用程序会停止在某个随机的位置,此时 LED 也将停止闪烁。调试器会打印如下信息::
+
+       (gdb) c
+       Continuing.
+       ^CTarget halted. PRO_CPU: PC=0x400D0C00             APP_CPU: PC=0x400D0C00 (active)
+       [New Thread 1073433352]
+
+       Program received signal SIGINT, Interrupt.
+       [Switching to Thread 1073413512]
+       0x400d0c00 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
+       52              asm("waiti 0");
+       (gdb) 
+
+在上图所示的情况下,应用程序已经在 ``freertos_hooks.c`` 文件的第 52 行暂停运行,现在您可以通过输入 ``c`` 再次将其恢复运行或者进行如下所述的一些调试工作。
+
+.. note::
+
+       在 MSYS2 的 shell 中输入 Ctrl+C 并不会暂停目标的运行,而是会退出调试器。解决这个问题的方法可以通过 :ref:`使用 Eclipse 来调试 <jtag-debugging-examples-eclipse>` 或者参考 http://www.mingw.org/wiki/Workaround_for_GDB_Ctrl_C_Interrupt 里的解决方案。
+
+
+.. _jtag-debugging-examples-command-line-04:
+
+单步执行代码
+^^^^^^^^^^^^
+
+我们还可以使用 ``step`` 和 ``next`` 命令(可以简写成 ``s`` 和 ``n``)单步执行代码, 这两者之间的区别是执行 “step” 命令会进入调用的子程序内部,而执行 “next” 命令则会直接将子程序看成单个源码行,单步就能将其运行结束。
+
+在继续演示此功能之前,请使用前面介绍的 ``break`` 和 ``delete`` 命令,确保目前只在 ``blink.c`` 文件的第 36 行设置了一个断点::
+
+    (gdb) info break
+    Num     Type           Disp Enb Address    What
+    3       breakpoint     keep y   0x400db704 in blink_task at /home/user-name/esp/blink/main/./blink.c:36
+        breakpoint already hit 1 time
+    (gdb) 
+
+输入 ``c`` 恢复程序运行然后等它在断点处停止运行::
+
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB754 (active)    APP_CPU: PC=0x400D1128 
+
+    Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:36
+    36          gpio_set_level(BLINK_GPIO, 1);
+    (gdb) 
+
+然后输入 ``n`` 多次,观察调试器是如何单步执行一行代码的::
+
+    (gdb) n
+    Target halted. PRO_CPU: PC=0x400DB756 (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB758 (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DC04C (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB75B (active)    APP_CPU: PC=0x400D1128 
+    37          vTaskDelay(1000 / portTICK_PERIOD_MS);
+    (gdb) n
+    Target halted. PRO_CPU: PC=0x400DB75E (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400846FC (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB761 (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB746 (active)    APP_CPU: PC=0x400D1128 
+    33          gpio_set_level(BLINK_GPIO, 0);
+    (gdb) 
+
+如果你输入 ``s``,那么调试器将进入子程序::
+
+    (gdb) s
+    Target halted. PRO_CPU: PC=0x400DB748 (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB74B (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DC04C (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DC04F (active)    APP_CPU: PC=0x400D1128 
+    gpio_set_level (gpio_num=GPIO_NUM_4, level=0) at /home/user-name/esp/esp-idf/components/driver/./gpio.c:183
+    183     GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
+    (gdb) 
+
+上述例子中,调试器进入 ``gpio_set_level(BLINK_GPIO, 0)`` 代码内部,同时代码窗口快速切换到 ``gpio.c`` 驱动文件。
+
+请参阅 :ref:`jtag-debugging-tip-why-next-works-as-step` 文档以了解 ``next`` 命令的潜在局限。
+
+
+.. _jtag-debugging-examples-command-line-05:
+
+查看并设置内存
+^^^^^^^^^^^^^^
+
+使用命令 ``x`` 可以显示内存的内容,配合其余参数还可以调整所显示内存位置的格式和数量。运行 ``help x`` 可以查看更多相关细节。与 ``x`` 命令配合使用的命令是 ``set``,它允许你将值写入内存。
+
+为了演示 ``x`` 和 ``set`` 的使用,我们将在内存地址 ``0x3FF44004`` 处读取和写入内容。该地址也是 ``GPIO_OUT_REG`` 寄存器的地址,可以用来控制(设置或者清除)某个 GPIO 的电平。关于该寄存器的更多详细信息,请参阅 `ESP32 技术参考手册 <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf>`_ 中的 IO_MUX 和 GPIO Matrix章节。
+
+同样在 ``blink.c`` 项目文件中,在两个 ``gpio_set_level`` 语句的后面各设置一个断点。输入两次 ``c`` 命令后停止在断点处,然后输入 ``x /1wx 0x3FF44004`` 来显示 ``GPIO_OUT_REG`` 寄存器的值::
+
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB75E (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB74E (active)    APP_CPU: PC=0x400D1128 
+
+    Breakpoint 2, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34
+    34          vTaskDelay(1000 / portTICK_PERIOD_MS);
+    (gdb) x /1wx 0x3FF44004
+    0x3ff44004: 0x00000000
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB751 (active)    APP_CPU: PC=0x400D1128 
+    Target halted. PRO_CPU: PC=0x400DB75B (active)    APP_CPU: PC=0x400D1128 
+
+    Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:37
+    37          vTaskDelay(1000 / portTICK_PERIOD_MS);
+    (gdb) x /1wx 0x3FF44004
+    0x3ff44004: 0x00000010
+    (gdb) 
+
+如果闪烁的 LED 连接到了 GPIO4,那么每次 LED 改变状态时你会看到第 4 比特被翻转::
+
+    0x3ff44004: 0x00000000
+    ...
+    0x3ff44004: 0x00000010
+
+现在,当 LED 熄灭时,与之对应地会显示 ``0x3ff44004: 0x00000000``,尝试使用 ``set`` 命令向相同的内存地址写入 ``0x00000010`` 来将该比特置高::
+
+    (gdb) x /1wx 0x3FF44004
+    0x3ff44004: 0x00000000
+    (gdb) set {unsigned int}0x3FF44004=0x000010
+
+在输入 ``set {unsigned int}0x3FF44004=0x000010`` 命令后,你会立即看到 LED 亮起。
+
+
+.. _jtag-debugging-examples-command-line-06:
+
+观察和设置程序变量
+^^^^^^^^^^^^^^^^^^
+
+常见的调试任务是在程序运行期间检查程序中某个变量的值,为了能够演示这个功能,更新 ``blink.c`` 文件,在 ``blink_task`` 函数的上面添加一个全局变量的声明 ``int i``,然后在 ``while(1)`` 里添加 ``i++``,这样每次 LED 改变状态的时候,变量 ``i`` 都会增加 1。
+
+退出调试器,这样就不会与新代码混淆,然后重新构建并烧写代码到 ESP32 中,接着重启调试器。注意,这里不需要我们重启 OpenOCD。
+
+一旦程序停止运行,输入命令 ``watch i``::
+
+    (gdb) watch i
+    Hardware watchpoint 2: i
+    (gdb)
+
+这会在所有变量 ``i`` 发生改变的代码处插入所谓的“观察点”。现在输入 ``continue`` 命令来恢复应用程序的运行并观察它停止::
+
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB751 (active)    APP_CPU: PC=0x400D0811 
+    [New Thread 1073432196]
+
+    Program received signal SIGTRAP, Trace/breakpoint trap.
+    [Switching to Thread 1073432196]
+    0x400db751 in blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:33
+    33          i++;
+    (gdb)
+
+多次恢复程序运行后,变量 ``i`` 的值会增加,现在你可以输入 ``print i`` (简写 ``p i``)来查看当前 ``i`` 的值::
+
+    (gdb) p i
+    $1 = 3
+    (gdb) 
+
+要修改 ``i`` 的值,请使用 ``set`` 命令,如下所示(可以将其打印输出来查看是否确已修改)::
+
+    (gdb) set var i = 0
+    (gdb) p i
+    $3 = 0
+    (gdb) 
+
+最多可以使用两个观察点,详细信息请参阅 :ref:`jtag-debugging-tip-breakpoints`。
+
+
+.. _jtag-debugging-examples-command-line-07:
+
+设置条件断点
+^^^^^^^^^^^^
+
+接下来的内容更为有趣,你可能想在一定条件满足的情况下设置断点。请先删除已有的断点,然后尝试如下命令::
+
+    (gdb) break blink.c:34 if (i == 2)
+    Breakpoint 3 at 0x400db753: file /home/user-name/esp/blink/main/./blink.c, line 34.
+    (gdb)
+
+以上命令在 ``blink.c`` 文件的 ``34`` 处设置了一个条件断点,当 ``i==2`` 条件满足时,程序会停止运行。
+
+如果当前 ``i`` 的值小于 ``2`` 并且程序被恢复运行,那么 LED 就会循环闪烁,直到 ``i == 2`` 条件成立,最后程序停止在该处::
+
+    (gdb) set var i = 0
+    (gdb) c
+    Continuing.
+    Target halted. PRO_CPU: PC=0x400DB755 (active)    APP_CPU: PC=0x400D112C 
+    Target halted. PRO_CPU: PC=0x400DB753 (active)    APP_CPU: PC=0x400D112C 
+    Target halted. PRO_CPU: PC=0x400DB755 (active)    APP_CPU: PC=0x400D112C 
+    Target halted. PRO_CPU: PC=0x400DB753 (active)    APP_CPU: PC=0x400D112C 
+
+    Breakpoint 3, blink_task (pvParameter=0x0) at /home/user-name/esp/blink/main/./blink.c:34
+    34          gpio_set_level(BLINK_GPIO, 0);
+    (gdb) 
+
+
+获得命令的帮助信息
+^^^^^^^^^^^^^^^^^^
+
+目前所介绍的都是些非常基础的命令,目的在于让您快速上手 JTAG 调试。如果想获得特定命令的语法和功能相关的信息,请在 ``(gdb)`` 提示符下输入 ``help`` 和命令名::
+
+    (gdb) help next
+    Step program, proceeding through subroutine calls.
+    Usage: next [N]
+    Unlike "step", if the current source line calls a subroutine,
+    this command does not enter the subroutine, but instead steps over
+    the call, in effect treating it as a single source line.
+    (gdb) 
+
+只需输入 ``help`` 命令,即可获得高级命令列表,帮助你了解更多详细信息。此外,还可以参考一些 GDB 命令速查表,比如 http://darkdust.net/files/GDB%20Cheat%20Sheet.pdf。虽然不是所有命令都适用于嵌入式环境,但还是会有所裨益。
+
+
+结束调试会话
+^^^^^^^^^^^^
+
+输入命令 ``q`` 可以退出调试器:: 
+
+    (gdb) q
+    A debugging session is active.
+
+        Inferior 1 [Remote target] will be detached.
+
+    Quit anyway? (y or n) y
+    Detaching from program: /home/user-name/esp/blink/build/blink.elf, Remote target
+    Ending remote debugging.
+    user-name@computer-name:~/esp/blink$ 
index 8a42b5678f59713fc809c71d1479f0ea4154d7c7..4d2eb79fe00cadd45370d2856a9b5108cddbe39a 100644 (file)
@@ -1 +1,308 @@
-.. include:: ../../../en/api-guides/jtag-debugging/index.rst
\ No newline at end of file
+JTAG 调试
+=========
+:link_to_translation:`en:[English]`
+
+本文将指导安装 ESP32 的 OpenOCD 调试环境,并介绍如何使用 GDB 来调试 ESP32 的应用程序。本文的组织结构如下:
+
+:ref:`jtag-debugging-introduction`
+    介绍本指南主旨。
+:ref:`jtag-debugging-how-it-works`
+    介绍 ESP32,JTAG(Joint Test Action Group)接口,OpenOCD 和 GDB 是如何相互连接从而实现 ESP32 的调试功能。
+:ref:`jtag-debugging-selecting-jtag-adapter`
+    介绍有关 JTAG 硬件适配器的选择及参照标准。
+:ref:`jtag-debugging-setup-openocd`
+    介绍如何在 :doc:`Windows <setup-openocd-windows>`,:doc:`Linux <setup-openocd-linux>` 和 :doc:`MacOS <setup-openocd-macos>` 操作系统上安装预编译好的 OpenOCD 软件包。
+:ref:`jtag-debugging-configuring-esp32-target`
+    介绍如何设置 OpenOCD 软件并安装 JTAG 硬件适配器,这两者共同组成最终的调试目标。
+:ref:`jtag-debugging-launching-debugger`
+    介绍如何从 :ref:`Eclipse 集成开发环境 <jtag-debugging-using-debugger-eclipse>` 和 :ref:`命令行终端 <jtag-debugging-using-debugger-command-line>` 启动 GDB 调试会话。
+:ref:`jtag-debugging-examples`
+    如果你对 GDB 不太熟悉,本小节会分别针对 :ref:`Eclipse 集成开发环境 <jtag-debugging-examples-eclipse>` 和 :ref:`命令行终端 <jtag-debugging-examples-command-line>` 来讲解调试的范例。
+:ref:`jtag-debugging-building-openocd`
+    介绍如何在 :doc:`Windows <building-openocd-windows>`,:doc:`Linux <building-openocd-linux>` 和 :doc:`MacOS <building-openocd-macos>` 操作系统上从源码构建 OpenOCD。
+:ref:`jtag-debugging-tips-and-quirks`
+    介绍使用 OpenOCD 和 GDB 通过 JTAG 接口调试 ESP32 时的注意事项和补充内容。
+
+.. _jtag-debugging-introduction:
+
+引言
+----
+
+ESP32 具有两个强大的 Xtensa 内核,支持多种程序架构。ESP-IDF 自带的 FreeRTOS 操作系统具有多核抢占式多线程的功能,它允许用户以更加直观的方式编写软件。
+
+与此相对地,简便的编程方式会给程序的调试带来困难(如果没有合适的工具),比如找出由两个线程引起的错误,并且这两个线程在单独的 CPU 核上同时运行,仅凭 ``printf`` 语句会花费很长的时间来定位到该错误。在大多数情况下,调试此类问题更快的方法是使用调试器,连接到处理器的调试端口。
+
+乐鑫已经为 ESP32 处理器和多核 FreeRTOS 架构移植好了 OpenOCD,它将成为大多数 ESP32 应用程序的基础。此外,乐鑫还提供了一些 OpenOCD 本身并不支持的工具来进一步丰富调试的功能。
+
+本文将指导如何在 Linux,Windows 和 MacOS 环境下为 ESP32 安装 OpenOCD,并使用 GDB 进行软件调试。除了个别操作系统的安装过程有所差别以外,软件用户界面和使用流程都是一样的。
+
+.. note::
+    本文使用的图片素材来自于 Ubuntu 16.04 LTE 上 Eclipse Neon 3 软件的截图,不同的操作系统(Windows, MacOS 或者 Linux)和 Eclipse 软件版本在用户界面上可能会有细微的差别。
+
+.. _jtag-debugging-how-it-works:
+
+工作原理
+--------
+
+通过 JTAG(Joint Test Action Group)接口使用 OpenOCD 调试 ESP32 时所需要的一些关键的软件和硬件包括 **xtensa-esp32-elf-gdb
+调试器**,**OpenOCD 片上调试器** 和连接到 **ESP32** 目标的 **JTAG 适配器**。
+
+.. figure:: ../../../_static/jtag-debugging-overview_zh.jpg
+    :align: center
+    :alt: JTAG debugging - overview diagram 
+    :figclass: align-center
+
+    JTAG 调试 - 概述图
+
+在 “Application Loading and Monitoring” 下还有另外一组软件和硬件,它们用来编译、构建和烧写应用程序到 ESP32 上,以及监视来自 ESP32 的运行诊断信息。
+
+`Eclipse <https://www.eclipse.org/>`__ 环境集成了 JTAG 调试和应用程序加载、监视的功能,它使得软件从编写、编译、加载到调试的迭代过程变得更加快速而简单。所有的软件均适用于 Windows,Linux 和 MacOS 平台。
+
+如果你使用的是 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,得益于板载的 FT232H 芯片,PC 和 ESP32 的连接仅仅需要一根 USB 线即可完成。FT232H 提供了两路 USB 通道,一路连接到 JTAG,另一路连接到 UART。
+
+根据用户的喜好,除了使用 Eclipse 集成开发环境,上述的调试工具和构建工具还可以直接在命令行终端运行。
+
+.. _jtag-debugging-selecting-jtag-adapter:
+
+选择 JTAG 适配器
+----------------
+
+上手 JTAG 最快速便捷的方式是使用 :doc:`ESP-WROVER-KIT 开发板 <../../hw-reference/modules-and-boards>`,因为它板载了 JTAG 调试接口,无需使用外部的 JTAG 硬件适配器和额外的线缆来连接 JTAG 与 ESP32。ESP-WROVER-KIT 采用 FT2232H 提供的 JTAG 接口,可以稳定运行在 20 MHz 的时钟频率,外接的适配器很难达到这个速度。
+
+如果你想使用单独的 JTAG 适配器,请确保其与 ESP32 的电平电压和 OpenOCD 软件都兼容。ESP32 使用的是业界标准的 JTAG 接口,它省略了(实际上也并不需要)TRST 信号脚。JTAG 使用的 IO 引脚由 VDD_3P3_RTC 电源引脚供电(通常连接到外部 3.3 V 的电源轨),因此 JTAG 硬件适配器的引脚需要能够在该电压范围内正常工作。
+
+在软件方面,OpenOCD 支持相当多数量的 JTAG 适配器,可以参阅 `OpenOCD 支持的适配器列表 <http://openocd.org/doc/html/Debug-Adapter-Hardware.html>`_ (尽管上面显示的器件不太完整),这个页面还列出了兼容 SWD 接口的适配器,但是请注意,ESP32 目前并不支持 SWD。此外那些被硬编码为只支持特定产品线的 JTAG 适配器也不能在 ESP32 上工作,比如用于 STM32 产品家族的 ST-LINK 适配器。
+
+JTAG 正常工作至少需要连接的信号线有:TDI,TDO,TCK,TMS 和 GND。某些 JTAG 适配器还需要 ESP32 提供一路电源到适配器的某个引脚上(比如 Vtar)用以设置适配器的工作电压。SRST 信号线是可选的,它可以连接到 ESP32 的 CH_PD 引脚上,尽管目前 OpenOCD 对该信号线的支持还非常有限。
+
+
+.. _jtag-debugging-setup-openocd:
+
+安装 OpenOCD
+------------
+
+本节会介绍 OpenOCD 软件包的安装,如果你想从源码构建 OpenOCD,请参阅 :ref:`jtag-debugging-building-openocd`。默认所有 OpenOCD 相关的文件都会被存放到 ``~/esp/openocd-esp32`` 目录下,你也可以选择任何其它的目录,但相应地,你也需要调整本文档示例中使用的相对路径。
+
+.. toctree::
+    :hidden:
+
+    Windows <setup-openocd-windows>
+    Linux <setup-openocd-linux> 
+    MacOS <setup-openocd-macos> 
+
+从下面选择你使用的操作系统,并按照提示进一步设置 OpenOCD。
+
++-------------------+-------------------+-------------------+
+| |windows-logo|    | |linux-logo|      | |macos-logo|      |
++-------------------+-------------------+-------------------+
+| `Windows`_        | `Linux`_          | `Mac OS`_         |
++-------------------+-------------------+-------------------+
+
+.. |windows-logo| image:: ../../../_static/windows-logo.png
+    :target: ../jtag-debugging/setup-openocd-windows.html
+
+.. |linux-logo| image:: ../../../_static/linux-logo.png
+    :target: ../jtag-debugging/setup-openocd-linux.html
+
+.. |macos-logo| image:: ../../../_static/macos-logo.png
+    :target: ../jtag-debugging/setup-openocd-macos.html
+
+.. _Windows: setup-openocd-windows.html
+.. _Linux: setup-openocd-linux.html
+.. _Mac OS: setup-openocd-macos.html
+
+安装完成后,请熟悉一下 ``openocd-esp32`` 安装路径下的两个关键目录:
+
+-  ``bin`` 目录下包含了 OpenOCD 的可执行文件
+-  ``share\openocd\scripts`` 目录下包含了一些配置文件,它们会作为命令行参数与 OpenOCD 一同被调用
+
+.. note::
+
+    上面的目录名称和结构特定于 OpenOCD 的二进制发行版,它们会被用在本指南中的 OpenOCD 示例中。从源码构建得到的 OpenOCD 存放的目录可能会不一样,所以调用 OpenOCD 的方式也会略有不同。更多详细信息请参阅 :ref:`jtag-debugging-building-openocd`。
+
+
+.. _jtag-debugging-configuring-esp32-target:
+
+配置 ESP32 目标板
+-----------------
+
+安装好 OpenOCD 之后就可以配置 ESP32 目标(即带 JTAG 接口的 ESP32 板),具体可以通过以下三个步骤进行:
+
+-  配置并连接 JTAG 接口
+-  运行 OpenOCD
+-  上传待调试的应用程序
+
+
+配置并连接 JTAG 接口
+~~~~~~~~~~~~~~~~~~~~
+
+此步骤取决于您使用的 JTAG 和 ESP32 板,请参考以下两种情况。
+
+.. toctree::
+    :maxdepth: 1
+
+    configure-wrover
+    configure-other-jtag
+
+
+.. _jtag-debugging-run-openocd:
+
+运行 OpenOCD
+~~~~~~~~~~~~
+
+配置完目标并将其连接到电脑后,即可启动 OpenOCD。
+
+.. highlight:: bash
+
+打开终端,进入安装目录并启动 OpenOCD::
+
+    cd ~/esp/openocd-esp32
+    bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
+
+.. note::
+
+    如上所示,``-f`` 后面的文件是特定于板载 :ref:`ESP-WROOM-32 <esp-modules-and-boards-esp32-wroom-32>` 模组的 ESP-WROVER-KIT 开发板的。您可能需要根据具体使用的硬件而提供不同的配置文件,相关指导请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`。
+
+.. include:: ./windows-openocd-note.rst
+
+.. highlight:: none
+
+现在应该可以看到类似下面的输出(此日志来自 ESP-WROVER-KIT)::
+
+    user-name@computer-name:~/esp/openocd-esp32$ bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f  board/esp-wroom-32.cfg
+    Open On-Chip Debugger 0.10.0-dev-ged7b1a9 (2017-07-10-07:16)
+    Licensed under GNU GPL v2
+    For bug reports, read
+            http://openocd.org/doc/doxygen/bugs.html
+    none separate
+    adapter speed: 20000 kHz
+    force hard breakpoints
+    Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
+    Info : clock speed 20000 kHz
+    Info : JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
+    Info : JTAG tap: esp32.cpu1 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
+    Info : esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
+    Info : esp32: Core was reset (pwrstat=0x5F, after clear 0x0F).
+
+-  如果出现指示权限问题的错误,请参阅 ``~/esp/openocd-esp32`` 目录下 OpenOCD README 文件中关于 “Permissions delegation” 的说明。
+-  如果发现配置文件有错误,例如 ``Can't find interface/ftdi/esp32_devkitj_v1.cfg``,请检查 ``-s`` 后面的路径,OpenOCD 会根据此路径来查找 ``-f`` 指定的文件。此外,还需要检查配置文件是否确实位于该路径下。
+-  如果看到 JTAG 错误(输出全是 1 或者全是 0),请检查硬件连接,除了 ESP32 的引脚之外是否还有其他信号连接到了 JTAG,并查看是否所有器件都已经上电。
+
+
+.. _jtag-upload-app-debug:
+
+上传待调试的应用程序
+~~~~~~~~~~~~~~~~~~~~
+
+您可以像往常一样构建并上传 ESP32 应用程序,具体请参阅 :ref:`get-started-build-flash` 章节。
+
+除此以外,还支持使用 OpenOCD 通过 JTAG 接口将应用程序镜像烧写到闪存中,命令如下::
+
+    cd ~/esp/openocd-esp32
+    bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "program_esp32  filename.bin 0x10000 verify exit"
+
+.. include:: ./windows-openocd-note.rst
+
+其中 OpenOCD 的烧写命令 ``program_esp32`` 具有以下格式:
+
+``program_esp32 <image_file> <offset> [verify] [reset] [exit]``
+
+    -  ``image_file`` - 程序镜像文件存放的路径
+    -  ``offset`` - 镜像烧写到闪存中的偏移地址
+    -  ``verify`` - 烧写完成后校验闪存中的内容(可选)
+    -  ``reset`` - 烧写完成后重启目标(可选)
+    -  ``exit`` - 烧写完成后退出 OpenOCD(可选)
+
+现在可以进行应用程序的调试了,请按照以下章节中讲解的步骤进行操作。
+
+
+.. _jtag-debugging-launching-debugger:
+
+启动调试器
+----------
+
+ESP32 的工具链中带有 GNU 调试器(简称 GDB) ``xtensa-esp32-elf-gdb``,它和其它工具链软件存放在同一个 bin 目录下。除了直接在命令行终端中调用并操作 GDB 外,还可以在 IDE (例如 Eclipse,Visual Studio Code 等)中调用它,在图形用户界面的帮助下间接操作 GDB,无需在终端中输入任何命令。
+
+关于以上两种调试器的使用方法,详见以下链接。
+
+* :ref:`jtag-debugging-using-debugger-eclipse`
+* :ref:`jtag-debugging-using-debugger-command-line`
+
+建议首先检查调试器是否能在 :ref:`命令行终端 <jtag-debugging-using-debugger-command-line>` 下正常工作,然后再转到使用 Eclipse 等 :ref:`集成开发环境 <jtag-debugging-using-debugger-eclipse>` 下进行调试工作。
+
+
+.. _jtag-debugging-examples:
+
+调试范例
+--------
+
+本节适用于不熟悉 GDB 的用户,将使用 :example:`get-started/blink` 下简单的应用程序来演示 :ref:`调试会话的工作流程 <jtag-debugging-examples-eclipse>`,同时会介绍以下常用的调试操作:
+
+1. :ref:`jtag-debugging-examples-eclipse-01`
+2. :ref:`jtag-debugging-examples-eclipse-02`
+3. :ref:`jtag-debugging-examples-eclipse-03`
+4. :ref:`jtag-debugging-examples-eclipse-04`
+5. :ref:`jtag-debugging-examples-eclipse-05`
+6. :ref:`jtag-debugging-examples-eclipse-06`
+7. :ref:`jtag-debugging-examples-eclipse-07`
+
+此外还会提供 :ref:`在命令行终端进行调试 <jtag-debugging-examples-command-line>` 的案例。
+
+在演示之前,请设置好 ESP32 目标板并加载 :example:`get-started/blink` 至 ESP32 中。
+
+
+.. _jtag-debugging-building-openocd:
+
+从源码构建 OpenOCD
+------------------
+
+请参阅以下文档,它们分别介绍了在各大操作系统平台上从源码构建 OpenOCD 的流程。
+
+.. toctree::
+    :maxdepth: 1
+
+    Windows <building-openocd-windows>
+    Linux <building-openocd-linux>
+    MacOS <building-openocd-macos>
+
+.. note::
+
+    本文档演示所使用的 OpenOCD 是 :ref:`jtag-debugging-setup-openocd` 章节中介绍的预编译好的二进制发行版,如果要使用本地从源代码构建得到的 OpenOCD 程序,需要将相应可执行文件的路径修改为 ``src/openocd``,并将配置文件的路径修改为 ``-s tcl``。
+
+    具体使用示例如下::
+
+        src/openocd -s tcl -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
+
+
+.. _jtag-debugging-tips-and-quirks:
+
+注意事项和补充内容
+--------------------
+
+本节列出了本指南中提到的所有注意事项和补充内容的链接。
+
+* :ref:`jtag-debugging-tip-breakpoints`
+* :ref:`jtag-debugging-tip-where-breakpoints`
+* :ref:`jtag-debugging-tip-flash-mappings`
+* :ref:`jtag-debugging-tip-why-next-works-as-step`
+* :ref:`jtag-debugging-tip-code-options`
+* :ref:`jtag-debugging-tip-freertos-support`
+* :ref:`jtag-debugging-tip-code-flash-voltage`
+* :ref:`jtag-debugging-tip-optimize-jtag-speed`
+* :ref:`jtag-debugging-tip-debugger-startup-commands`
+* :ref:`jtag-debugging-tip-openocd-configure-target`
+* :ref:`jtag-debugging-tip-reset-by-debugger`
+* :ref:`jtag-debugging-tip-jtag-pins-reconfigured`
+* :ref:`jtag-debugging-tip-reporting-issues`
+
+
+相关文档
+--------
+
+.. toctree::
+    :maxdepth: 1
+
+    using-debugger
+    debugging-examples
+    tips-and-quirks
+    ../app_trace
index 16059fc9c50cbacd4d30856f70f457cf98101d63..f61d6eece2dc13f005204984531d9de3dd9081c7 100644 (file)
@@ -1 +1,34 @@
-.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-linux.rst
\ No newline at end of file
+***************************
+在 Linux 环境下安装 OpenOCD
+***************************
+:link_to_translation:`en:[English]`
+
+安装 OpenOCD
+============
+
+64 位 Linux 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
+
+https://github.com/espressif/openocd-esp32/releases
+
+下载文件名称包含 `linux64` 字样的最新发布的归档文件,例如 `openocd-esp32-linux64-0.10.0-esp32-20180418.tar.gz`。
+
+将该文件解压缩到 ``~/esp/`` 目录下::
+
+    cd ~/esp
+    tar -xzf ~/Downloads/openocd-esp32-linux64-<version>.tar.gz 
+
+
+下一步
+======
+
+进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
+
+
+相关文档
+========
+
+.. toctree::
+    :maxdepth: 1
+
+    building-openocd-linux
+
index fd8f49ba618423e9cc09dd8d66fdf940dbd9f7ac..5f46715cc0ce7aa515ddab233bf31f4c9f4619ba 100644 (file)
@@ -1 +1,39 @@
-.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-macos.rst
\ No newline at end of file
+***************************
+在 MacOS 环境下安装 OpenOCD
+***************************
+:link_to_translation:`en:[English]`
+
+安装 libusb
+===========
+
+使用 `Homebrew <https://brew.sh/>`_ 或者 `Macports <https://www.macports.org/>`_ 来安装 `libusb` 软件包。
+
+安装 OpenOCD
+============
+
+MacOS 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
+
+https://github.com/espressif/openocd-esp32/releases
+
+下载文件名包含 `macos` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-esp32-20180418.tar.gz`。
+
+将该文件解压缩到 ``~/esp/`` 目录下::
+
+    cd ~/esp
+    tar -xzf ~/Downloads/openocd-esp32-macos-<version>.tar.gz 
+
+
+下一步
+======
+
+进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
+
+
+相关文档
+========
+
+.. toctree::
+    :maxdepth: 1
+
+    building-openocd-macos
+
index cb3368c6ae839725499935daec5596c8f2637832..740af5b5e6a57e45779544888c20c09ede135acf 100644 (file)
@@ -1 +1,39 @@
-.. include:: ../../../en/api-guides/jtag-debugging/setup-openocd-windows.rst
\ No newline at end of file
+*****************************
+在 Windows 环境下安装 OpenOCD
+*****************************
+:link_to_translation:`en:[English]`
+
+IDF 工具安装程序
+================
+
+如果您正在使用 CMake 构建系统,并遵循 :doc:`/get-started-cmake/windows-setup` 章节的指导使用了 ``ESP-IDF Tools Installer`` 的 V1.2 及其以上版本,那么默认情况下您已经安装好了 ``OpenOCD`` 软件。
+
+``ESP-IDF Tools Installer`` 会将 ``OpenOCD`` 添加到环境变量 ``PATH`` 中,这样你就可以在任何目录运行它。
+
+安装 OpenOCD
+============
+
+Windows 系统版本的 OpenOCD 可以直接从以下 Github 链接中下载:
+
+https://github.com/espressif/openocd-esp32/releases
+
+下载文件名包含 `win32` 字样的最新发布的归档文件,例如 `openocd-esp32-macos-0.10.0-win32-20180418.zip`。
+
+将该文件解压缩到 ``~/esp/`` 目录下::
+
+    cd ~/esp
+    unzip /c/Users/<user>/Downloads/openocd-esp32-win32-<version>.zip
+
+下一步
+======
+
+进一下配置调试环境,请前往 :ref:`jtag-debugging-configuring-esp32-target` 章节。
+
+
+相关文档
+========
+
+.. toctree::
+    :maxdepth: 1
+
+    building-openocd-windows
index aaf7dfadfdd028b3c19b4abe2ccf85d53f26e66a..fe04714c817fc84e1f69002bca926a1fd5ba6833 100644 (file)
@@ -1 +1,282 @@
-.. include:: ../../../en/api-guides/jtag-debugging/tips-and-quirks.rst
\ No newline at end of file
+注意事项和补充内容
+------------------
+:link_to_translation:`en:[English]`
+
+本节提供了本指南中各部分提到的一些注意事项和补充内容。
+
+.. _jtag-debugging-tip-breakpoints:
+
+可用的断点和观察点
+^^^^^^^^^^^^^^^^^^
+
+ESP32 调试器支持 2 个硬件断点和 64 个软件断点。硬件断点是由 ESP32 芯片内部的逻辑电路实现的,能够设置在代码的任何位置:闪存或者 IRAM 的代码区域。除此以外,OpenOCD 实现了两种软件断点:闪存断点(最多 32 个)和 IRAM 断点(最多 32 个)。目前 GDB 无法在闪存中设置软件断点,因此除非解决此限制,否则这些断点只能由 OpenOCD 模拟为硬件断点。(详细信息可以参阅 :ref:`下面 <jtag-debugging-tip-where-breakpoints>`)。ESP32 还支持 2 个观察点,所以可以观察两个变量的变化或者通过 GDB 命令 ``watch myVariable`` 来读取变量的值。请注意 menuconfig 中的 :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 选项会使用第二个观察点,如果你想在 OpenOCD 或者 GDB 中再次尝试使用这个观察点,可能不会得到预期的结果。详情请查看 menuconfig 中的帮助文档。
+
+
+.. _jtag-debugging-tip-where-breakpoints:
+
+关于断点的补充知识
+^^^^^^^^^^^^^^^^^^
+
+使用软件闪存模拟部分硬件断点的意思就是当使用 GDB 命令 ``hb myFunction`` 给某个函数设置硬件断点时,如果该函数位于闪存中,并且此时还有可用的硬件断点,那调试器就会使用硬件断点,否则就使用 32 个软件闪存断点中的一个来模拟。这个规则同样适用于 ``b myFunction`` 之类的命令,在这种情况下,GDB 会自己决定该使用哪种类型的断点。如果 ``myFunction`` 位于可写区域(IRAM),那就会使用软件 IRAM 断点,否则就会像处理 ``hb`` 命令一样使用硬件断点或者软件闪存断点。
+
+
+.. _jtag-debugging-tip-flash-mappings:
+
+闪存映射 vs 软件闪存断点
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+为了在闪存中设置或者清除软件断点,OpenOCD 需要知道它们在闪存中的地址。为了完成从 ESP32 的地址空间到闪存地址的转换,OpenOCD 使用闪存中程序代码区域的映射。这些映射被保存在程序映像的头部,位于二进制数据(代码段和数据段)之前,并且特定于写入闪存的每一个应用程序的映像。因此,为了支持软件闪存断点,OpenOCD 需要知道待调试的应用程序映像在闪存中的位置。默认情况下,OpenOCD 会在 0x8000 处读取分区表并使用第一个找到的应用程序映像的映射,但是也可能会存在无法工作的情况,比如分区表不在标准的闪存位置,甚至可能有多个映像:一个出厂映像和两个 OTA 映像,你可能想要调试其中的任意一个。为了涵盖所有可能的调试情况,OpenOCD 支持特殊的命令,用于指定待调试的应用程序映像在闪存中的具体位置。该命令具有以下格式: 
+
+``esp32 appimage_offset <offset>`` 
+
+偏移量应为十六进制格式,如果要恢复默认行为,可以将偏移地址设置为 ``-1`` 。
+
+.. note::
+
+    由于 GDB 在连接 OpenOCD 时仅仅请求一次内存映射,所以可以在 TCL 配置文件中指定该命令,或者通过命令行传递给 OpenOCD。对于后者,命令行示例如下:
+
+    ``bin/openocd -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg -c "init; halt; esp32 appimage_offset 0x210000"``
+
+    另外还可以通过 OpenOCD 的 telnet 会话执行该命令,然后再连接 GDB, 不过这种方式似乎没有那么便捷。
+
+.. _jtag-debugging-tip-why-next-works-as-step:
+
+“next” 命令无法跳过子程序的原因
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+当使用 ``next`` 命令单步执行代码时, GDB 会在子程序的前面设置一个断点(两个中可用的一个),这样就可以跳过进入子程序内部的细节。如果这两个断点已经用在代码的其它位置,那么 ``next`` 命令将不起作用。在这种情况下,请删掉一个断点以使其中一个变得可用。当两个断点都已经被使用时,``next`` 命令会像 ``step`` 命令一样工作,调试器就会进入子程序内部。
+
+
+.. _jtag-debugging-tip-code-options:
+
+OpenOCD 支持的编译时的选项
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ESP-IDF 有一些针对 OpenOCD 调试功能的选项可以在编译时进行设置:
+
+* :ref:`CONFIG_ESP32_DEBUG_OCDAWARE` 默认会被使能。如果程序抛出了不可修复或者未处理的异常,并且此时已经连接上了 JTAG 调试器(即 OpenOCD 正在运行),那么 ESP-IDF 将会进入调试器工作模式。
+* :ref:`CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK` 默认没有使能。在所有任务堆栈的末尾设置观察点,从 1 号开始索引。这是调试任务堆栈溢出的最准确的方式。
+
+更多有关设置编译时的选项的信息,请参阅 :ref:`make menuconfig <get-started-configure>`。
+
+.. _jtag-debugging-tip-freertos-support:
+
+支持FreeRTOS
+^^^^^^^^^^^^
+
+OpenOCD 完全支持 ESP-IDF 自带的 FreeRTOS 操作系统,GDB 会将 FreeRTOS 中的任务当做线程。使用 GDB 命令 ``i threads`` 可以查看所有的线程,使用命令 ``thread n`` 可以切换到某个具体任务的堆栈,其中 ``n`` 是线程的编号。检测 FreeRTOS 的功能可以在配置目标时被禁用。更多详细信息,请参阅 :ref:`jtag-debugging-tip-openocd-configure-target`.
+
+
+.. _jtag-debugging-tip-code-flash-voltage:
+
+在 OpenOCD 的配置文件中设置 SPI 闪存的工作电压
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ESP32 的 MTDI 引脚是用于 JTAG 通信的四个引脚之一,同时也是 ESP32 的 bootstrapping 引脚。上电时,ESP32 会在 MTDI 引脚上采样二进制电平,据此来设置内部的稳压器,用于给外部的 SPI 闪存芯片供电。如果上电时 MTDI 引脚上的二进制电平为低电平,则稳压器会被设置为 3.3 V;如果 MTDI 引脚为高电平,则稳压器会被设置为 1.8 V。MTDI 引脚通常需要一个上拉电阻或者直接使能内部的弱下拉电阻(详见 `ESP32 系列芯片技术规格书 <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_cn.pdf>`_ ),具体取决于所使用的 SPI 芯片的类型。但是一旦连接上 JTAG 后,原来用于实现 bootstrapping 功能的上拉或者下拉电阻都会被覆盖掉。 
+
+为了解决这个问题,OpenOCD 的板级配置文件(例如 ESP32-WROOM-32 模组的 ``boards\esp-wroom-32.cfg``)提供了 ``ESP32_FLASH_VOLTAGE`` 参数来设置 ``TDO`` 信号线在空闲状态下的二进制电平,这样就可以减少由于闪存电压不正确而导致的应用程序启动不良的几率。
+
+查看 JTAG 连接的 ESP32 模组的规格书,检查其 SPI 闪存芯片的供电电压值,然后再相应的设置 ``ESP32_FLASH_VOLTAGE``。大多数的 WROOM 模组使用 3.3 V 的闪存芯片,但是 WROVER 模组使用 1.8 V 的闪存芯片。 
+
+
+.. _jtag-debugging-tip-optimize-jtag-speed:
+
+优化 JTAG 的速度
+^^^^^^^^^^^^^^^^
+
+为了实现更高的数据通信速率同时最小化丢包数,建议优化 JTAG 时钟频率的设置,使其达到 JTAG 能稳定运行的最大值。为此,请参考以下建议。
+
+1.  如果 CPU 以 80 MHz 运行,则 JTAG 时钟频率的上限为 20 MHz;如果 CPU 以 160 MHz 或者 240 MHz 运行,则上限为 26 MHz。
+2.  根据特定的 JTAG 适配器和连接线缆的长度,你可能需要将 JTAG 的工作频率降低至 20 / 26 MHz 以下。
+3.  在某些特殊情况下,如果你看到 DSR/DIR 错误(并且它并不是由 OpenOCD 试图从一个没有物理存储器映射的地址空间读取数据而导致的),请降低 JTAG 的工作频率。
+4.  ESP-WROVER-KIT 能够稳定运行在 20 / 26 MHz 频率下。
+
+
+.. _jtag-debugging-tip-debugger-startup-commands:
+
+调试器的启动命令的含义
+^^^^^^^^^^^^^^^^^^^^^^
+
+在启动时,调试器发出一系列命令来复位芯片并使其在特定的代码行停止运行。这个命令序列(如下所示)支持自定义,用户可以选择在最方便合适的代码行开始调试工作。
+
+* ``set remote hardware-watchpoint-limit 2`` — 限制 GDB 仅使用 ESP32 支持的两个硬件观察点。更多详细信息,请查阅 `GDB 配置远程目标 <https://sourceware.org/gdb/onlinedocs/gdb/Remote-Configuration.html>`_ 。
+* ``mon reset halt`` — 复位芯片并使 CPU 停止运行。
+* ``flushregs`` — monitor (``mon``) 命令无法通知 GDB 目标状态已经更改,GDB 会假设在 ``mon reset halt`` 之前所有的任务堆栈仍然有效。实际上,复位后目标状态将发生变化。执行 ``flushregs`` 是一种强制 GDB 从目标获取最新状态的方法。
+* ``thb app_main`` — 在 ``app_main`` 处插入一个临时的硬件断点,如果有需要,可以将其替换为其他函数名。
+* ``c`` — 恢复程序运行,它将会在 ``app_main`` 的断点处停止运行。
+
+
+.. _jtag-debugging-tip-openocd-configure-target:
+
+针对特定目标的 OpenOCD 配置
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+OpenOCD 需要知道当前使用的 JTAG 适配器的类型,以及其连接的目标板和处理器的类型。为此,请使用位于 OpenOCD 安装目录下 ``share/openocd/scripts/interface`` 和 ``share/openocd/scripts/board`` 文件夹中现有的配置文件。
+
+例如,如果使用板载 ESP-WROOM-32 模组的 ESP-WROVER-KIT 开发板(详见 :ref:`esp-modules-and-boards-esp-wrover-kit-v1`),请使用以下配置文件:
+
+* ``interface/ftdi/esp32_devkitj_v1.cfg``
+* ``board/esp-wroom-32.cfg``
+
+当然也可以使用自定义的配置文件,建议在已有配置文件的基础上进行修改,以匹配你的硬件。下面列举一些常用的板级配置参数。
+
+
+.. highlight:: none
+
+适配器的时钟速度
+""""""""""""""""
+
+::
+
+    adapter_khz 20000
+
+请参阅 :ref:`jtag-debugging-tip-optimize-jtag-speed` 以获取有关如何设置此值的指导。
+
+
+单核调试
+""""""""
+
+::
+
+    set ESP32_ONLYCPU 1
+
+如果是双核调试,请注释掉这一行。
+
+
+禁用 RTOS 支持
+""""""""""""""
+
+::
+
+    set ESP32_RTOS none
+
+如果要支持 RTOS, 请注释掉这一行。
+
+
+ESP32 的 SPI 闪存芯片的电源电压
+"""""""""""""""""""""""""""""""
+
+::
+
+    set ESP32_FLASH_VOLTAGE 1.8
+
+如果 SPI 闪存芯片的电源电压为 3.3 V, 请注释掉这一行,更多信息请参阅: :ref:`jtag-debugging-tip-code-flash-voltage`。
+
+
+ESP32 的目标配置文件
+""""""""""""""""""""
+
+::
+
+    source [find target/esp32.cfg]
+
+.. note::
+
+    除非你熟悉 OpenOCD 内部的工作原理,否则请不要更改 ``source [find target/esp32.cfg]`` 这一行。
+
+目前 ``target/esp32.cfg`` 仍然是 ESP32 目标(esp108 和 esp32)的唯一配置文件。支持的配置矩阵如下所示:
+
+    +---------------+---------------+---------------+
+    | Dual/single   | RTOS          | Target used   |
+    +===============+===============+===============+
+    | dual          | FreeRTOS      | esp32         |
+    +---------------+---------------+---------------+
+    | single        | FreeRTOS      | esp108 (*)    |
+    +---------------+---------------+---------------+
+    | dual          | none          | esp108        |
+    +---------------+---------------+---------------+
+    | single        | none          | esp108        |
+    +---------------+---------------+---------------+
+
+    (*) — 我们计划修复此问题,并在后续提交中添加对 esp32 目标的单核调试的支持。
+
+更多信息,请查看 ``board/esp-wroom-32.cfg`` 配置文件的注释部分。
+
+
+.. _jtag-debugging-tip-reset-by-debugger:
+
+复位 ESP32
+^^^^^^^^^^
+
+通过在 GDB 中输入 ``mon reset`` 或者 ``mon reset halt`` 来复位板子。
+
+
+.. _jtag-debugging-tip-jtag-pins-reconfigured:
+
+不要将 JTAG 引脚用于其他功能
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+如果除了 ESP32 模组和 JTAG 适配器之外的其他硬件也连接到了 JTAG 引脚,那么 JTAG 的操作可能会受到干扰。ESP32 JTAG 使用以下引脚:
+
+    +---+----------------+-------------+
+    |   | ESP32 JTAG Pin | JTAG Signal |
+    +===+================+=============+
+    | 1 | MTDO / GPIO15  | TDO         |
+    +---+----------------+-------------+
+    | 2 | MTDI / GPIO12  | TDI         |
+    +---+----------------+-------------+
+    | 3 | MTCK / GPIO13  | TCK         |
+    +---+----------------+-------------+
+    | 4 | MTMS / GPIO14  | TMS         |
+    +---+----------------+-------------+
+
+如果用户应用程序更改了 JTAG 引脚的配置,JTAG 通信可能会失败。如果 OpenOCD 正确初始化(检测到两个 Tensilica 内核),但在程序运行期间失去了同步并报出大量 DTR/DIR 错误,则应用程序可能将 JTAG 引脚重新配置为其他功能或者用户忘记将 Vtar 连接到 JTAG 适配器。 
+
+.. highlight:: none
+
+下面是 GDB 在应用程序进入重新配置 MTDO/GPIO15 作为输入代码后报告的一系列错误摘录::
+
+    cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
+    cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
+    cpu0: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!
+    cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates target still busy!
+    cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an exception!
+    cpu1: xtensa_resume (line 431): DSR (FFFFFFFF) indicates DIR instruction generated an overrun!
+
+
+.. _jtag-debugging-tip-reporting-issues:
+
+报告 OpenOCD / GDB 的问题
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+如果你遇到 OpenOCD 或者 GDB 程序本身的问题,并且在网上没有找到可用的解决方案,请前往 https://github.com/espressif/openocd-esp32/issues 新建一个议题。
+
+1.  请在问题报告中提供你使用的配置的详细信息:
+
+    a. JTAG 适配器类型。
+    b. 用于编译和加载正在调试的应用程序的 ESP-IDF 版本号。
+    c. 用于调试的操作系统的详细信息。
+    d. 操作系统是在本地计算机运行还是在虚拟机上运行?
+
+2.  创建一个能够演示问题的简单示例工程,描述复现该问题的步骤。且这个调试示例不能受到 Wi-Fi 协议栈引入的非确定性行为的影响,因而再次遇到同样问题时,更容易复现。
+
+.. highlight:: bash
+
+3.  在启动命令中添加额外的参数来输出调试日志。
+
+    OpenOCD 端:
+
+        ::
+
+            bin/openocd -l openocd_log.txt -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg
+
+        这种方式会将日志输出到文件,但是它会阻止调试信息打印在终端上。当有大量信息需要输出的时候(比如调试等级提高到 ``-d 3``)这是个不错的选择。如果你仍然希望在屏幕上看到调试日志,请改用以下命令:
+
+        ::
+
+            bin/openocd -d 3 -s share/openocd/scripts -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg 2>&1 | tee openocd.log
+
+        .. note::
+
+            如果运行的 OpenOCD 是从源码自行编译的,命令的格式会有些许不同,具体请参阅: :ref:`jtag-debugging-building-openocd`。
+
+    Debugger 端:
+
+        ::
+
+           xtensa-esp32-elf-gdb -ex "set remotelogfile gdb_log.txt" <all other options>
+
+        也可以将命令 ``remotelogfile gdb_log.txt`` 添加到 ``gdbinit`` 文件中。
+
+
+4.  请将 ``openocd_log.txt`` 和 ``gdb_log.txt`` 文件附在你的问题报告中。
index e34bc097319aa6a4bd63b6abbfbab28b1c0c6bf0..0b17f5f5f5c1297cb41bdc8570c5b75946f4470a 100644 (file)
@@ -1 +1,190 @@
-.. include:: ../../../en/api-guides/jtag-debugging/using-debugger.rst
\ No newline at end of file
+使用调试器
+----------
+:link_to_translation:`en:[English]`
+
+本节会在 :ref:`Eclipse <jtag-debugging-using-debugger-eclipse>` 和 :ref:`命令行 <jtag-debugging-using-debugger-command-line>` 中分别介绍配置和运行调试器的方法。我们建议你首先通过 :ref:`命令行 <jtag-debugging-using-debugger-command-line>` 检查调试器是否正常工作,然后再转到使用 :ref:`Eclipse <jtag-debugging-using-debugger-eclipse>` 平台。
+
+
+.. _jtag-debugging-using-debugger-eclipse:
+
+在 Eclipse 中使用 GDB
+^^^^^^^^^^^^^^^^^^^^^
+
+标准的 Eclipse 安装流程默认安装调试功能,另外我们还可以使用插件来调试,比如 “GDB Hardware Debugging”。这个插件用起来非常方便,本指南会详细介绍该插件的使用方法。
+
+首先,通过打开 Eclipse 并转到 “Help” > “Install New Software” 来安装 “GDB Hardware Debugging” 插件。
+
+安装完成后,按照以下步骤配置调试会话。请注意,一些配置参数是通用的,有些则针对特定项目。我们会通过配置 "blink" 示例项目的调试环境来进行展示,请先按照 :doc:`使用 Eclipse IDE 编译和烧写 <../../get-started/eclipse-setup>` 文章介绍的方法将该示例项目添加到 Eclipse 的工作空间。示例项目 :example:`get-started/blink` 的源代码可以在 ESP-IDF 仓库的 :idf:`examples` 目录下找到。
+
+1.  在 Eclipse 中,进入 `Run` > `Debug Configuration`,会出现一个新的窗口。在窗口的左侧窗格中,双击 “GDB Hardware Debugging” (或者选择 “GDB Hardware Debugging” 然后按下 “New” 按钮)来新建一个配置。
+
+2.  在右边显示的表单中,“Name:” 一栏中输入配置的名称,例如: “Blink checking”。
+
+3.  在下面的 “Main” 选项卡中, 点击 “Project:” 边上的 “Browse” 按钮,然后选择当前的 “blink” 项目。
+
+4.  在下一行的 “C/C++ Application:” 中,点击 “Browse” 按钮,选择 “blink.elf” 文件。如果 “blink.elf” 文件不存在,那么很有可能该项目还没有编译,请参考 :doc:`使用 Eclipse IDE 编辑和烧写 <../../get-started/eclipse-setup>` 指南中的介绍。
+
+5.  最后,在 “Build (if required) before launching” 下面点击 “Disable auto build”。
+
+    上述步骤 1 - 5 的示例输入如下图所示。
+
+    .. figure:: ../../../_static/hw-debugging-main-tab.jpg
+        :align: center
+        :alt: Configuration of GDB Hardware Debugging - Main tab
+        :figclass: align-center
+
+        GDB 硬件调试的配置 - Main 选项卡
+
+6.  点击 “Debugger” 选项卡,在 “GDB Command” 栏中输入 ``xtensa-esp32-elf-gdb`` 来调用调试器。
+
+7.  更改 “Remote host” 的默认配置,在 “Port number” 下面输入 ``3333``。
+
+    上述步骤 6 - 7 的示例输入如下图所示。
+
+    .. figure:: ../../../_static/hw-debugging-debugger-tab.jpg
+        :align: center
+        :alt: Configuration of GDB Hardware Debugging - Debugger tab
+        :figclass: align-center
+
+        GDB 硬件调试的配置 - Debugger 选项卡
+
+8.  最后一个需要更改默认配置的选项卡是 “Startup” 选项卡。在 “Initialization Commands” 下,取消选中 “Reset and Delay (seconds)” 和 “Halt”,然后在下面一栏中输入以下命令:
+
+    ::
+
+        mon reset halt
+        flushregs
+        set remote hardware-watchpoint-limit 2
+
+    .. note::
+        如果你想在启动新的调试会话之前自动更新闪存中的镜像,请在 “Initialization Commands” 文本框的开头添加以下命令行::
+
+            mon reset halt
+            mon program_esp32 ${workspace_loc:blink/build/blink.bin} 0x10000 verify
+
+
+    有关 ``program_esp32`` 命令的说明请参考 :ref:`jtag-upload-app-debug` 章节。
+
+9.  在 “Load Image and Symbols” 下,取消选中 “Load image” 选项。
+
+10. 在同一个选项卡中继续往下浏览,建立一个初始断点用来在调试器复位后暂停 CPU。插件会根据 “Set break point at:” 一栏中输入的函数名,在该函数的开头设置断点。选中这一选项,并在相应的字段中输入 ``app_main``。
+
+11. 选中 “Resume” 选项,这会使得程序在每次调用步骤 8 中的 ``mon reset halt`` 之后恢复,然后在 ``app_main`` 的断点处停止。
+
+    上述步骤 8 - 11 的示例输入如下图所示。
+
+    .. figure:: ../../../_static/hw-debugging-startup-tab.jpg
+        :align: center
+        :alt: Configuration of GDB Hardware Debugging - Startup tab
+        :figclass: align-center
+
+        GDB 硬件调试的配置 - Startup 选项卡
+
+    上面的启动序列看起来有些复杂,如果你对其中的初始化命令不太熟悉,请查阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节获取更多说明。
+
+12. 如果你前面已经完成 :ref:`jtag-debugging-configuring-esp32-target` 中介绍的步骤,那么目标正在运行并准备与调试器进行对话。按下 “Debug” 按钮就可以直接调试。否则请按下 “Apply” 按钮保存配置,返回 :ref:`jtag-debugging-configuring-esp32-target` 章节进行配置,最后再回到这里开始调试。
+
+一旦所有 1 - 12 的配置步骤都已经完成,Eclipse 就会打开 “Debug” 视图,如下图所示。 
+
+.. figure:: ../../../_static/debug-perspective.jpg
+    :align: center
+    :alt: Debug Perspective in Eclipse
+    :figclass: align-center
+
+    Eclipse 中的调试视图
+
+如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-eclipse` 文章中的调试示例章节 :ref:`jtag-debugging-examples`。
+
+
+.. _jtag-debugging-using-debugger-command-line:
+
+在命令行中使用 GDB
+^^^^^^^^^^^^^^^^^^
+
+1.  为了能够启动调试会话,需要先启动并运行目标,如果还没有完成,请按照 :ref:`jtag-debugging-configuring-esp32-target` 中的介绍进行操作。
+
+.. highlight:: bash
+
+2.  打开一个新的终端会话并前往待调试的项目目录,比如:
+
+    ::
+
+        cd ~/esp/blink
+
+.. highlight:: none
+
+3.  当启动调试器时,通常需要提供几个配置参数和命令,为了避免每次都在命令行中逐行输入这些命令,我们可以新建一个配置文件,并将其命名为 ``gdbinit``:
+
+    ::
+
+        target remote :3333
+        set remote hardware-watchpoint-limit 2
+        mon reset halt
+        flushregs
+        thb app_main
+        c
+
+    将此文件保存在当前目录中。 
+
+    有关 ``gdbinit`` 文件内部的更多详细信息,请参阅 :ref:`jtag-debugging-tip-debugger-startup-commands` 章节。
+
+.. highlight:: bash
+
+4.  准备好启动 GDB,请在终端中输入以下内容:
+
+    ::
+
+        xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
+
+.. highlight:: none
+
+5.  如果前面的步骤已经正确完成,你会看到如下所示的输出日志,在日志的最后会出现 ``(gdb)`` 提示符:
+
+    ::
+
+        user-name@computer-name:~/esp/blink$ xtensa-esp32-elf-gdb -x gdbinit build/blink.elf
+        GNU gdb (crosstool-NG crosstool-ng-1.22.0-61-gab8375a) 7.10
+        Copyright (C) 2015 Free Software Foundation, Inc.
+        License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
+        This is free software: you are free to change and redistribute it.
+        There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
+        and "show warranty" for details.
+        This GDB was configured as "--host=x86_64-build_pc-linux-gnu --target=xtensa-esp32-elf".
+        Type "show configuration" for configuration details.
+        For bug reporting instructions, please see:
+        <http://www.gnu.org/software/gdb/bugs/>.
+        Find the GDB manual and other documentation resources online at:
+        <http://www.gnu.org/software/gdb/documentation/>.
+        For help, type "help".
+        Type "apropos word" to search for commands related to "word"...
+        Reading symbols from build/blink.elf...done.
+        0x400d10d8 in esp_vApplicationIdleHook () at /home/user-name/esp/esp-idf/components/esp32/./freertos_hooks.c:52
+        52          asm("waiti 0");
+        JTAG tap: esp32.cpu0 tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
+        JTAG tap: esp32.slave tap/device found: 0x120034e5 (mfg: 0x272 (Tensilica), part: 0x2003, ver: 0x1)
+        esp32: Debug controller was reset (pwrstat=0x5F, after clear 0x0F).
+        esp32: Core was reset (pwrstat=0x5F, after clear 0x0F).
+        Target halted. PRO_CPU: PC=0x5000004B (active)    APP_CPU: PC=0x00000000 
+        esp32: target state: halted
+        esp32: Core was reset (pwrstat=0x1F, after clear 0x0F).
+        Target halted. PRO_CPU: PC=0x40000400 (active)    APP_CPU: PC=0x40000400 
+        esp32: target state: halted
+        Hardware assisted breakpoint 1 at 0x400db717: file /home/user-name/esp/blink/main/./blink.c, line 43.
+        0x0:    0x00000000
+        Target halted. PRO_CPU: PC=0x400DB717 (active)    APP_CPU: PC=0x400D10D8 
+        [New Thread 1073428656]
+        [New Thread 1073413708]
+        [New Thread 1073431316]
+        [New Thread 1073410672]
+        [New Thread 1073408876]
+        [New Thread 1073432196]
+        [New Thread 1073411552]
+        [Switching to Thread 1073411996]
+
+        Temporary breakpoint 1, app_main () at /home/user-name/esp/blink/main/./blink.c:43
+        43      xTaskCreate(&blink_task, "blink_task", 512, NULL, 5, NULL);
+        (gdb) 
+
+注意上面日志的倒数第三行显示了调试器已经在 ``app_main()`` 函数的断点处停止,该断点在 ``gdbinit`` 文件中设定。由于处理器已经暂停运行,LED 也不会闪烁。如果这也是你看到的现象,你可以开始调试了。
+
+如果你不太了解 GDB 的常用方法,请查阅 :ref:`jtag-debugging-examples-command-line` 文章中的调试示例章节 :ref:`jtag-debugging-examples`。
index f81ed5ca65b03f15af83a7fff6c48bc160866429..1fe3676cc4d06ae1ceb6f0d63d959f7449f09def 100644 (file)
@@ -1 +1,3 @@
-.. include:: ../../../en/api-guides/jtag-debugging/windows-openocd-note.rst
+.. note::
+
+   如果您在 Windows 上使用 ``ESP-IDF Tools Installer`` 安装的 OpenOCD,则无需切换目录即可运行 ``openocd -f interface/ftdi/esp32_devkitj_v1.cfg -f board/esp-wroom-32.cfg`` ,也无需使用 ``-s share/openocd/scripts`` 参数指定脚本文件的搜索路径。
index 00802895c79463a11f25669461217735cd8f07dd..33a3527d5c26c5e0b46e270a8125924f13743e47 100644 (file)
@@ -1 +1,498 @@
-.. include:: ../../en/api-guides/linker-script-generation.rst
+链接脚本生成机制
+================
+:link_to_translation:`en:[English]`
+
+概述
+----
+
+ESP32 的代码和数据可以存放在多个 :ref:`内存区域 <memory-layout>`。通常,代码和只读数据存放在 flash 区域,可写数据存放在内存中。我们经常需要更改代码或者数据的默认映射区域,例如为了提高性能,将关键部分的代码和只读数据放置到内存中,或者将代码、数据和只读数据存放到 RTC 内存中以便在 :doc:`唤醒桩 <deep-sleep-stub>` 和 :doc:`ULP 协处理器 <ulp>` 中使用。
+
+IDF 的链接脚本生成机制允许用户在组件级别定义代码和数据的存放区域。组件通过 :ref:`链接片段文件 <ldgen-fragment-files>` 描述如何映射目标文件的输入段(甚至可以是某个具体的函数或者数据)。在构建应用程序时,链接片段文件会被收集、解析并处理,然后扩充到 :ref:`链接脚本模板 <ldgen-script-templates>` 中形成最终的链接脚本文件,该链接脚本会被用于链接最终的二进制应用程序。
+
+快速上手
+--------
+
+本节将指导如何快速将代码和数据放入 RAM 和 RTC 内存中,并演示如何使这些放置规则依赖于项目的配置。本节内容重在指导快速入门,因此并未在使用前详细介绍所有涉及的术语和概念,但在首次提及此类术语或概念时,均提供了相应链接,以帮助您的理解。
+
+.. _ldgen-add-fragment-file :
+
+准备工作
+^^^^^^^^
+
+Make
+""""
+
+在组件目录中新建一个链接片段文件,该文件是一个扩展名为 ``.lf`` 的文本文件。为了能够让构建系统收集到此片段文件,需要为组件添加一个条目,在调用 ``register_component`` 之前设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量的值,使其指向刚才的链接片段文件。
+
+.. code-block:: make
+
+    # 文件路径相对于组件的 Makefile
+    COMPONENT_ADD_LDFRAGMENTS += "path/to/linker_fragment_file.lf" "path/to/another_linker_fragment_file.lf"
+
+CMake
+"""""
+
+对于 CMake 构建系统来说,需要在调用 ``register_component`` 之前设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量的值,使其指向链接片段文件。
+
+.. code-block:: cmake
+
+    # 文件路径相对于组件的 CMakeLists.txt
+    set(COMPONENT_ADD_LDFRAGMENTS "path/to/linker_fragment_file.lf" "path/to/another_linker_fragment_file.lf")
+
+    register_component()
+
+也可以使用函数 ``ldgen_add_fragment_files`` 在项目的 CMakeLists.txt 文件或者组件的 project_include.cmake 文件中指定该片段文件 ::
+
+    ldgen_add_fragment_files(target files ...)
+
+
+指定放置区域
+^^^^^^^^^^^^
+
+链接脚本生成机制允许指定以下条目的存放位置:
+
+    - 组件中的一个或多个目标文件
+    - 一个或多个函数/变量(使用它们的名字来指定)
+    - 整个组件库
+
+在继续讲解之前,假设我们的组件包含以下内容:
+
+    - 一个名为 ``component`` 的组件,在构建期间被归档为 ``libcomponent.a`` 库文件
+    - 该库中有三个存档的目标文件: ``object1.o``,``object2.o`` 和 ``object3.o``
+    - ``object1.o`` 中定义了 ``function1`` 函数,``object2.o`` 中定义了 ``function2`` 函数
+    - 在其中的一个 IDF KConfig 文件中存在 ``PERFORMANCE_MODE`` 和 ``PERFORMANCE_LEVEL`` 两个配置,相应地,项目的 sdkconfig 文件会通过 ``CONFIG_PERFORMANCE_MODE`` 和 ``CONFIG_PERFORMANCE_LEVEL`` 这两个宏来指示当前设置的值
+
+在新建的链接片段文件中输入以下内容:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+
+这会创建一个空的 :ref:`mapping 片段 <ldgen-mapping-fragment>`,它并不会执行任何操作。在链接期间,会使用 :ref:`默认的存放规则 <ldgen-default-placements>` 来映射 ``libcomponent.a``,除非填充了 ``entries`` 字段。
+
+.. _ldgen-placing-object-files :
+
+放置目标文件
+""""""""""""
+
+假设整个 ``object1.o`` 目标文件对性能至关重要,所以最好把它放在 RAM 中。另一方面,假设``object2.o`` 目标文件包含有从深度睡眠唤醒所需的数据,因此需要将它存放到 RTC 内存中。可以在链接片段文件中写入以下内容:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        object1 (noflash)     # 将所有代码和只读数据放置在 IRAM 和 DRAM 中
+        object2 (rtc)         # 将所有代码、数据和只读数据放置到 RTC 快速内存和 RTC 慢速内存中
+
+那么 ``object3.o`` 放在哪里呢?由于未指定放置规则,它会被存放到默认区域。
+
+放置函数和数据
+""""""""""""""
+
+假设在 ``object1.o`` 目标文件中只有 ``function1`` 是与性能密切相关,且在 ``object2.o`` 目标文件中只有 ``function2`` 需要在深度睡眠唤醒后执行。可以在链接片段文件中写入以下内容:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        object1:function1 (noflash) 
+        object2:function2 (rtc) 
+
+``object1.o`` 和 ``object2.o`` 的剩余函数以及整个 ``object3.o`` 目标文件会被存放到默认区域。指定数据存放区域的方法很类似,仅需将 ``:`` 之后的函数名,替换为变量名即可。
+
+.. warning::
+
+    使用符号名来指定放置区域有一定的 :ref:`局限 <ldgen-type1-limitations>`。因此,您也可以将相关代码和数据集中在源文件中,然后根据 :ref:`使用目标文件的放置规则 <ldgen-placing-object-files>` 进行放置。
+
+放置整个组件
+""""""""""""
+
+在这个例子中,假设我们需要将整个组件存放到 RAM 中,可以这样写:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        * (noflash)
+
+类似的,下面的写法可以将整个组件存放到 RTC 内存中:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        * (rtc)
+
+依赖于具体配置的存放方式
+""""""""""""""""""""""""
+
+假设只有当 sdkconfig 文件中存在 ``CONFIG_PERFORMANCE_MODE == y`` 时,整个组件才会被放置到指定区域,可以这样写:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        : PERFORMANCE_MODE = y
+        * (noflash)
+
+其含义可以通过如下伪代码来表述:
+
+.. code-block:: none
+
+    if PERFORMANCE_MODE = y
+        place entire libcomponent.a in RAM
+    else
+        use default placements
+
+此外,您还可以设置多个判断条件。假设有如下需求:当 ``CONFIG_PERFORMANCE_LEVEL == 1`` 时,只有 ``object1.o`` 存放到 RAM 中;当 ``CONFIG_PERFORMANCE_LEVEL == 2`` 时,``object1.o`` 和 ``object2.o`` 会被存放到 RAM 中;当 ``CONFIG_PERFORMANCE_LEVEL == 3`` 时,归档中的所有目标文件都会被存放到 RAM 中;当这三个条件都不满足时,将整个组件库存放到 RTC 内存中。虽然这种使用场景很罕见,不过,还是可以通过以下方式实现:
+
+.. code-block:: none
+
+    [mapping]
+    archive: libcomponent.a
+    entries:
+        : PERFORMANCE_LEVEL = 3
+        * (noflash)
+        : PERFORMANCE_LEVEL = 2
+        object1 (noflash)
+        object2 (noflash)
+        : PERFORMANCE_LEVEL = 1
+        object1 (noflash)
+        : default
+        * (rtc)
+
+用伪代码可以表述为:
+
+.. code-block:: none
+
+    if CONFIG_PERFORMANCE_LEVEL == 3
+        place entire libcomponent.a in RAM
+    else if CONFIG_PERFORMANCE_LEVEL == 2
+        only place object1.o and object2.o in RAM
+    else if CONFIG_PERFORMANCE_LEVEL == 1
+        only place object1.o in RAM
+    else
+        place entire libcomponent.a in RTC memory 
+
+条件测试还支持 :ref:`其他操作 <ldgen-condition-entries>`。
+
+.. _ldgen-default-placements:
+
+默认的存放规则
+^^^^^^^^^^^^^^
+
+到目前为止,“默认存放规则”一直作为未指定 ``rtc`` 和 ``noflash`` 存放规则时的备选放置方式。``noflash`` 或者 ``rtc`` 标记不仅仅是链接脚本生成机制中的关键字,实际上还是由用户指定且被称为 :ref:`scheme 片段 <ldgen-scheme-fragment>` 的对象。由于这些存放规则非常常用,所以 IDF 中已经预定义了这些规则。
+
+类似地,还有一个名为 ``default`` 的 scheme 片段,它定义了默认的存放规则,详情请见 :ref:`默认 scheme <ldgen-default-scheme>`。
+
+.. note::
+    有关使用此功能的 IDF 组件的示例,请参阅 :component_file:`freertos/CMakeLists.txt`。为了提高性能,``freertos`` 组件通过该机制将所有目标文件中的代码、字面量和只读数据存放到 IRAM 中。
+
+快速入门指南到此结束,下面的文章将进一步详细讨论这个机制,例如它的组件、基本概念、语法、如何集成到构建系统中等等。以下部分有助于创建自定义的映射或者修改默认行为。
+
+组件
+----
+
+.. _ldgen-fragment-files :
+
+链接片段文件
+^^^^^^^^^^^^
+
+“链接片段文件”包含称为“片段”的对象,每个片段含有多条信息,放在一起时即可形成寻访规则,共同描述目标文件各个段在二进制输出文件中的存放位置。
+
+换言之,处理“链接片段文件”也就是在 GNU LD 的 ``SECTIONS`` 命令中,创建段的存放规则,并将其放在一个内部 ``target`` token 中。
+
+下面讨论三种类型的片段。
+
+.. note::
+
+    片段具有名称属性(mapping 片段除外)并且是全局可见的。片段的命名遵循 C 语言的基本变量命名规则,即区分大小写;必须以字母或者下划线开头;允许非初始字符使用字母、数字和下划线;不能使用空格等特殊字符。此外,每种片段都有自己的独立命名空间,如果多个片段的类型和名称相同,就会引发异常。
+
+.. _ldgen-sections-fragment :
+
+I. sections 片段
+""""""""""""""""
+
+sections 片段定义了 GCC 编译器输出的目标文件段的列表,可以是默认的段(比如 ``.text`` 段、``.data`` 段),也可以是用户通过 ``__attribute__`` 关键字自定义的段。 
+
+此外,用户还可以在某类段后增加一个 ``+``,表示囊括列表中的“所有这类段”和“所有以这类段开头的段”。相较于显式地罗列所有的段,我们更推荐使用这种方式。
+
+**语法**
+
+.. code-block:: none
+
+    [sections:name]
+    entries:
+        .section+
+        .section
+        ...
+
+**示例**
+
+.. code-block:: none
+
+    # 不推荐的方式
+    [sections:text]
+    entries:
+        .text
+        .text.*
+        .literal
+        .literal.*
+
+    # 推荐的方式,效果与上面等同
+    [sections:text]
+    entries:
+        .text+              # 即 .text 和 .text.*
+        .literal+           # 即 .literal 和 .literal.*
+
+.. _ldgen-scheme-fragment :
+
+II. scheme 片段
+"""""""""""""""
+
+scheme 片段定义了为每个 sections 指定的 ``target``。 
+
+**语法**
+
+.. code-block:: none
+
+    [scheme:name]
+    entries:
+        sections -> target
+        sections -> target
+        ...
+
+**示例**
+
+.. code-block:: none
+
+    [scheme:noflash]
+    entries:
+        text -> iram0_text          # 名为 text 的 sections 片段下的所有条目均归入 iram0_text
+        rodata -> dram0_data        # 名为 rodata 的 sections 片段下的所有条目均归入 dram0_data
+
+.. _ldgen-default-scheme:
+
+**default scheme**
+
+注意,有一个名为 ``default`` 的 scheme 很特殊,特殊在于 catch-all 存放规则都是从这个 scheme 中的条目生成的。这意味着,如果该 scheme 有一条 ``text -> flash_text`` 条目,则将为目标 ``flash_text`` 生成如下的存放规则 :
+
+.. code-block:: none
+
+    *(.literal .literal.* .text .text.*)
+
+此后,这些生成的 catch-all 规则将用于未指定映射规则的情况。 
+
+.. note::
+
+    ``default`` scheme 是在 :component:`esp32/ld/esp32_fragments.lf` 文件中定义的,此外,快速上手指南中提到的内置 ``noflash`` scheme 片段和 ``rtc`` scheme 片段也是在这个文件中定义的。
+
+.. _ldgen-mapping-fragment :
+
+III. mapping 片段
+"""""""""""""""""
+
+mapping 片段定义了可映射实体(即目标文件、函数名、变量名)对应的 scheme 片段。具体来说,mapping 片段有两种类型的条目,分别为映射条目和条件条目。
+
+.. note::
+
+    mapping 片段没有具体的名称属性,内部会根据归档条目的值构造其名称。
+
+**语法**
+
+.. code-block:: none
+
+    [mapping]
+    archive: archive                # 构建后输出的存档文件的名称(即 libxxx.a)
+    entries:
+        : condition                 # 条件条目,非默认
+        object:symbol (scheme)      # 映射条目,Type I
+        object (scheme)             # 映射条目,Type II
+        * (scheme)                  # 映射条目,Type III
+
+        # 为了提高可读性,可以适当增加分隔行或注释,非必须
+
+        : default                   # 条件条目,默认
+        * (scheme)                  # 映射条目,Type III
+
+.. _ldgen-mapping-entries :
+
+**映射条目**
+
+mapping 片段的映射条目共有三种类型,分别为:
+
+    ``Type I``
+        同时指定了目标文件名和符号名。其中,符号名可以是函数名或者变量名。
+
+    ``Type II``
+        仅指定了目标文件名。
+
+    ``Type III``
+        指定了 ``*``,也就是指定了归档文件中所有目标文件。
+
+接下来,让我们通过展开一个 ``Type II`` 映射条目,更好地理解映射条目的含义。最初: 
+
+.. code-block:: none
+
+    object (scheme)
+
+接着,让我们根据条目定义,将这个 scheme 片段展开:
+
+.. code-block:: none
+
+    object (sections -> target, 
+            sections -> target, 
+            ...)
+
+然后再根据条目定义,将这个 sections 片段展开:
+
+.. code-block:: none
+
+    object (.section,
+            .section,
+            ... -> target, # 根据目标文件将这里所列出的所有段放在该目标位置
+            
+            .section,
+            .section,
+            ... -> target, # 同样的方法指定其他段 
+            
+            ...)           # 直至所有段均已展开
+
+.. _ldgen-type1-limitations :
+
+**有关 Type I 映射条目的局限性**
+
+``Type I`` 映射条目可以工作的大前提是编译器必须支持 ``-ffunction-sections`` 和 ``-ffdata-sections`` 选项。因此,如果用户主动禁用了这两个选项,``Type I`` 映射条目就无法工作。此外,值得注意的是,``Type I`` 映射条目的实现还与输出段有关。因此,有时及时用户在编译时没有选择禁用这两个选项,也有可能无法使用 ``Type I`` 映射条目。
+
+例如,当使用 ``-ffunction-sections`` 选项时,编译器会给每个函数都输出一个单独的段,根据段名的构造规则,这些段的名称应该类似 ``.text.{func_name}`` 或 ``.literal.{func_name}``。然而,对于函数中的字符串文字,情况并非如此,因为它们会使用池化后或者新创建的段名。
+
+当使用 ``-fdata-sections`` 选项时,编译器会给每一个全局可见的数据输出一个单独的段,名字类似于 ``.data.{var_name}``、 ``.rodata.{var_name}`` 或者 ``.bss.{var_name}``。这种情况下,``Type I`` 映射条目可以使用。然而,对于在函数作用域中声明的静态数据,编译器在为其生成段名时会同时使用其变量名和其他信息,因此当涉及在函数作用域中定义的静态数据时就会出现问题。
+
+.. _ldgen-condition-entries :
+
+**条件条目**
+
+条件条目允许根据具体项目配置生成不同的链接脚本。也就是说,可以根据一些配置表达式的值,选择使用一套不同的映射条目。由于检查配置的过程是通过 :idf_file:`tools/kconfig_new/kconfiglib.py` 文件中的 ``eval_string`` 完成的,因此条件表达式也必须遵循 ``eval_string`` 的语法和限制。
+
+在一个 mapping 片段中,跟着一个条件条目后定义的所有映射条目均属于该条件条目,直至下一个条件条目的出现或者是该 mapping 片段的结束。在检查配置时,编译器将逐条检查这个 mapping 片段中的所有条件条目,直至找到一个满足条件的条件条目(即表达式为 ``TRUE``),然后使用该条件条目下定义的映射条目。另外,尽管每个映射都已包含一个隐式的空映射,但用户还是可以自定义一个默认条件,即所有条件条目均不满足时(即没有表达式为 ``TRUE``)使用的映射条目。
+
+**示例**
+
+.. code-block:: none
+
+    [scheme:noflash]
+    entries:
+        text -> iram0_text
+        rodata -> dram0_data
+
+    [mapping:lwip]
+    archive: liblwip.a
+    entries:
+        : LWIP_IRAM_OPTIMIZATION = y         # 如果 CONFIG_LWIP_IRAM_OPTIMIZATION 在 sdkconfig 中被定义为 'y' 
+        ip4:ip4_route_src_hook (noflash)     # 将 ip4.o:ip4_route_src_hook,ip4.o:ip4_route_src 和
+        ip4:ip4_route_src (noflash)          # ip4.o:ip4_route 映射到 noflash scheme
+        ip4:ip4_route (noflash)              # 该 scheme 会将他们存放到 RAM 中
+        
+        : default                            # 否则不使用特殊的映射规则
+
+.. _ldgen-script-templates :
+
+链接脚本模板
+^^^^^^^^^^^^
+
+链接脚本模板与其他链接脚本没有本质区别,但带有特定的标记语法,可以指示放置生成的存放规则的位置,是指定存放规则的放置位置的框架。
+
+**语法**
+
+如需引用一个 ``target`` token 下的所有存放规则,请使用以下语法:
+
+.. code-block:: none
+
+    mapping[target]
+
+**示例**
+
+以下示例是某个链接脚本模板的摘录。该链接脚定义了一个输出段 ``.iram0.text``,里面包含一个引用目标 ``iram0_text`` 的标记。
+
+.. code-block:: none
+
+    .iram0.text :
+    {
+        /* 标记 IRAM 的边界 */
+        _iram_text_start = ABSOLUTE(.);
+
+        /* 引用 iram0_text */
+        mapping[iram0_text]
+
+        _iram_text_end = ABSOLUTE(.);
+    } > iram0_0_seg
+
+下面,让我们更具体一点。假设某个链接脚本生成器收集到了以下片段:
+
+.. code-block:: none
+
+    [sections:text]
+        .text+
+        .literal+
+
+    [sections:iram]
+        .iram1+
+
+    [scheme:default]
+    entries:
+        text -> flash_text
+        iram -> iram0_text
+
+    [scheme:noflash]
+    entries:
+        text -> iram0_text
+
+    [mapping:freertos]
+    archive: libfreertos.a
+    entries:
+        * (noflash)
+
+则该脚本生成器生成的链接脚本文件,其摘录应如下所示:
+
+.. code-block:: c
+
+    .iram0.text :
+    {
+        /* 标记 IRAM 的边界 */
+        _iram_text_start = ABSOLUTE(.);
+
+        /* 将链接片段处理生成的存放规则放置在模板标记的位置处 */
+        *(.iram1 .iram1.*)
+        *libfreertos.a:(.literal .text .literal.* .text.*)
+
+        _iram_text_end = ABSOLUTE(.);
+    } > iram0_0_seg
+
+``*libfreertos.a:(.literal .text .literal.* .text.*)``
+
+    这是从 ``freertos`` mapping 片段的 ``* (noflash)`` 条目中生成的规则。``libfreertos.a`` 归档文件下的所有目标文件的 ``text`` 段会被收集到 ``iram0_text`` 目标下(假设采用 ``noflash`` scheme),并放在模板中被 ``iram0_text`` 标记的地方。
+
+``*(.iram1 .iram1.*)``
+
+    这是从 ``default`` scheme 的 ``iram -> iram0_text`` 条目生成的规则,因为 ``default`` scheme 指定了一个 ``iram -> iram0_text`` 条目,因此生成的规则也将放在被 ``iram0_text`` 标记的地方。值得注意的是,由于该规则是从 ``default`` scheme 中生成的,因此在同一目标下收集的所有规则下排在第一位。
+
+
+与构建系统的集成
+----------------
+
+链接脚本是在应用程序的构建过程中生成的,此时尚未链接形成最终的二进制文件。实现该机制的工具位于 ``$(IDF_PATH)/tools/ldgen`` 目录下。
+
+链接脚本模板
+^^^^^^^^^^^^
+目前使用的链接脚本模板是 :component:`esp32/ld/esp32.common.ld.in`,仅用于应用程序的构建,生成的链接脚本文件将放在同一组件的构建目录下。值得注意的是,修改此链接描述文件模板会触发应用程序的二进制文件的重新链接。
+
+链接片段文件
+^^^^^^^^^^^^
+任何组件都可以将片段文件添加到构建系统中,方法有两种:设置 ``COMPONENT_ADD_LDFRAGMENTS`` 变量或者使用 ``ldgen_add_fragment_files`` 函数(仅限 CMake),具体可以参考 :ref:`添加片段文件 <ldgen-add-fragment-file>` 小节中的介绍。值得注意的是,修改构建系统中的任何片段文件都会触发应用程序的二进制文件的重新链接。
index d281889175a884551ff9a1de9273ce9969536f77..5c11a1573a74a7edb901957775c3642c1aeb59a6 100644 (file)
@@ -1,10 +1,10 @@
 .. important::
-   目前,CMake 编译系统尚不支持以下功能:
+    目前,CMake 编译系统尚不支持以下功能:
 
-   - Eclipse IDE 文档
-   - 安全启动
-   - Flash 加密
+    - Eclipse IDE 文档
+    - 安全启动
+    - Flash 加密
 
-   未来,CMake 编译系统将在 ESP-IDF v4.0 发布后取代现有基于 GNU Make 的编译系统,成为默认编译系统。我们会在 ESP-IDF v4.0 发布前逐步完善上述功能。
+    未来,CMake 编译系统将在 ESP-IDF v4.0 发布后取代现有基于 GNU Make 的编译系统,成为默认编译系统。我们会在 ESP-IDF v4.0 发布前逐步完善上述功能。
 
 
index 5eab20e486233ac54625de8bd53f5160e49a608d..8815c8ae998657d5fe6433afc01fa07cf36aacbd 100644 (file)
@@ -1,4 +1,4 @@
 .. note::
-   本文档介绍了 CMake 编译系统的使用。目前,CMake 编译系统仍处于预览发布阶段,如您在使用中遇到任何问题,请前往 ESP-IDF 提交 `Issues <https://github.com/espressif/esp-idf/issues>`_。
+    本文档将介绍如何使用 CMake 编译系统。目前,CMake 编译系统仍处于预览发布阶段,如您在使用中遇到任何问题,请前往 ESP-IDF 提交 `Issues <https://github.com/espressif/esp-idf/issues>`_。
 
-   未来,CMake 编译系统将在 ESP-IDF v4.0 发布后过渡为默认编译系统,现行基于 GNU Make 的编译系统将在 ESP-IDF v5.0 后弃用。
+    未来,CMake 编译系统将在 ESP-IDF v4.0 发布后过渡为默认编译系统,现行基于 GNU Make 的编译系统将在 ESP-IDF v5.0 后弃用。
index 48ac2c3653fd21bfba37167d14169c5610fe6277..05bcc281d2edebab685b8a3986de156424175612 100644 (file)
 
 - Ubuntu 和 Debian::
 
-    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
+    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
 
 .. note::
     使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。
index 0180fb954c04c5719720e8c6a94f2bd051bbdaf8..acc1cd3bf5665108875a6f89dfd33c301199b234 100644 (file)
@@ -17,11 +17,11 @@ Linux 平台工具链的标准设置 (CMake)
 
 - Ubuntu 和 Debian::
 
-    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing cmake ninja-build ccache
+    sudo apt-get install git wget libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing cmake ninja-build ccache
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing cmake ninja ccache
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing cmake ninja ccache
 
 .. note::
     使用 ESP-IDF 需要 CMake 3.5 或以上版本。较早版本的 Linux 可能需要升级才能向后移植仓库,或安装 "cmake3" 软件包,而不是安装 "cmake"。
index ca3dbcebb4e2301cc4026e044bba45637a9f94e1..f79816892eeca8db49a671500e00667aa0c35ae6 100644 (file)
 
 - Ubuntu 和 Debian::
 
-    sudo apt-get install git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing
+    sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
 
 .. note::
 
index 0bd18e0a910f8e3dabce8c879e22e615b9ea28e4..62bf8ed7384028ffe853a95b1b329511943e05a3 100644 (file)
@@ -16,11 +16,11 @@ Linux 平台工具链的标准设置
 
 - Ubuntu and Debian::
 
-    sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-pyparsing
+    sudo apt-get install gcc git wget make libncurses-dev flex bison gperf python python-pip python-setuptools python-serial python-cryptography python-future python-pyparsing
 
 - Arch::
 
-    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-pyparsing
+    sudo pacman -S --needed gcc git make ncurses flex bison gperf python2-pyserial python2-cryptography python2-future python2-pyparsing
 
 .. note::
 
index 39316b7e673778e791b5bbd7473f9b005580bd10..ae7e0cac92b59741214f6319e2afc16cd26fe132 100644 (file)
  *
  */
 
+/** 
+ * Note:
+ * 1. Win10 does not support vendor report , So SUPPORT_REPORT_VENDOR is always set to FALSE, it defines in hidd_le_prf_int.h
+ * 2. Update connection parameters are not allowed during iPhone HID encryption, slave turns 
+ * off the ability to automatically update connection parameters during encryption.
+ * 3. After our HID device is connected, the iPhones write 1 to the Report Characteristic Configuration Descriptor, 
+ * even if the HID encryption is not completed. This should actually be written 1 after the HID encryption is completed.
+ * we modify the permissions of the Report Characteristic Configuration Descriptor to `ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE_ENCRYPTED`.
+ * if you got `GATT_INSUF_ENCRYPTION` error, please ignore.
+ */
+
 #define HID_DEMO_TAG "HID_DEMO"
 
 
@@ -324,7 +335,7 @@ void app_main()
 
     //init the gpio pin
     gpio_demo_init();
-   xTaskCreate(&hid_demo_task, "hid_task", 2048, NULL, 5, NULL);
+    xTaskCreate(&hid_demo_task, "hid_task", 2048, NULL, 5, NULL);
 
 }
 
index 8d112fad875928e162a19ceb03015c2058935998..8041e7b5e617b1f7f44434980942a1d8cceb6cf0 100644 (file)
@@ -168,7 +168,9 @@ static const uint8_t hidReportMap[] = {
     0x81, 0x00,   //     Input (Data, Ary, Abs)
     0xC0,           //   End Collection
     0x81, 0x03,   //   Input (Const, Var, Abs)
-    0xC0,            // End Collection
+    0xC0,            // End Collectionq
+
+#if (SUPPORT_REPORT_VENDOR == true)
     0x06, 0xFF, 0xFF, // Usage Page(Vendor defined)
     0x09, 0xA5,       // Usage(Vendor Defined)
     0xA1, 0x01,       // Collection(Application)
@@ -179,6 +181,8 @@ static const uint8_t hidReportMap[] = {
     0x95, 0x7F,   // Report Count = 127 Btyes
     0x91, 0x02,   // Output(Data, Variable, Absolute)
     0xC0,         // End Collection
+#endif
+
 };
 
 /// Battery Service Attributes Indexes
@@ -239,8 +243,11 @@ static uint8_t hidReportRefKeyIn[HID_REPORT_REF_LEN] =
 static uint8_t hidReportRefLedOut[HID_REPORT_REF_LEN] =
              { HID_RPT_ID_LED_OUT, HID_REPORT_TYPE_OUTPUT };
 
+#if (SUPPORT_REPORT_VENDOR  == true)
+
 static uint8_t hidReportRefVendorOut[HID_REPORT_REF_LEN] =
              {HID_RPT_ID_VENDOR_OUT, HID_REPORT_TYPE_OUTPUT};
+#endif
 
 // HID Report Reference characteristic descriptor, Feature
 static uint8_t hidReportRefFeature[HID_REPORT_REF_LEN] =
@@ -436,6 +443,7 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] =
                                                                        ESP_GATT_PERM_READ,
                                                                        sizeof(hidReportRefLedOut), sizeof(hidReportRefLedOut),
                                                                        hidReportRefLedOut}},
+#if (SUPPORT_REPORT_VENDOR  == true)
     // Report Characteristic Declaration
     [HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR]        = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid,
                                                                          ESP_GATT_PERM_READ,
@@ -449,8 +457,8 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] =
                                                                        ESP_GATT_PERM_READ,
                                                                        sizeof(hidReportRefVendorOut), sizeof(hidReportRefVendorOut),
                                                                        hidReportRefVendorOut}},
-
-        // Report Characteristic Declaration
+#endif
+    // Report Characteristic Declaration
     [HIDD_LE_IDX_REPORT_CC_IN_CHAR]         = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid,
                                                                          ESP_GATT_PERM_READ,
                                                                          CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE,
@@ -462,7 +470,7 @@ static esp_gatts_attr_db_t hidd_le_gatt_db[HIDD_LE_IDX_NB] =
                                                                        NULL}},
     // Report KEY INPUT Characteristic - Client Characteristic Configuration Descriptor
     [HIDD_LE_IDX_REPORT_CC_IN_CCC]              = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid,
-                                                                      (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE),
+                                                                      (ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE_ENCRYPTED),
                                                                       sizeof(uint16_t), 0,
                                                                       NULL}},
      // Report Characteristic - Report Reference Descriptor
@@ -538,6 +546,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
 {
     switch(event) {
         case ESP_GATTS_REG_EVT: {
+            esp_ble_gap_config_local_icon (ESP_BLE_APPEARANCE_GENERIC_HID);
             esp_hidd_cb_param_t hidd_param;
             hidd_param.init_finish.state = param->reg.status;
             if(param->reg.app_id == HIDD_APP_ID) {
@@ -584,6 +593,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
         case ESP_GATTS_CLOSE_EVT:
             break;
         case ESP_GATTS_WRITE_EVT: {
+#if (SUPPORT_REPORT_VENDOR == true)
             esp_hidd_cb_param_t cb_param = {0};
             if (param->write.handle == hidd_le_env.hidd_inst.att_tbl[HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL] &&
                 hidd_le_env.hidd_cb != NULL) {
@@ -593,6 +603,7 @@ void esp_hidd_prf_cb_hdl(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
                 cb_param.vendor_write.data = param->write.value;
                 (hidd_le_env.hidd_cb)(ESP_HIDD_EVENT_BLE_VENDOR_REPORT_WRITE_EVT, &cb_param);
             }
+#endif
             break;
         }
         case ESP_GATTS_CREAT_ATTR_TAB_EVT: {
index 4482be55ae6a51caac7377b540c172b446407263..89e7cc20dfa5a4199b68dbe1df2d52d1d3e923e9 100644 (file)
 
 #ifndef __HID_DEVICE_LE_PRF__
 #define __HID_DEVICE_LE_PRF__
+#include <stdbool.h>
 #include "esp_gatts_api.h"
 #include "esp_gatt_defs.h"
 #include "esp_hidd_prf_api.h"
 #include "esp_gap_ble_api.h"
 #include "hid_dev.h"
 
+#define SUPPORT_REPORT_VENDOR                 false
 //HID BLE profile log tag
 #define HID_LE_PRF_TAG                        "HID_LE_PRF"
 
@@ -141,11 +143,12 @@ enum {
     HIDD_LE_IDX_REPORT_LED_OUT_VAL,
     HIDD_LE_IDX_REPORT_LED_OUT_REP_REF,
 
+#if (SUPPORT_REPORT_VENDOR  == true)
     /// Report Vendor
     HIDD_LE_IDX_REPORT_VENDOR_OUT_CHAR,
     HIDD_LE_IDX_REPORT_VENDOR_OUT_VAL,
     HIDD_LE_IDX_REPORT_VENDOR_OUT_REP_REF,
-
+#endif
     HIDD_LE_IDX_REPORT_CC_IN_CHAR,
     HIDD_LE_IDX_REPORT_CC_IN_VAL,
     HIDD_LE_IDX_REPORT_CC_IN_CCC,
index c121d4fbe42cbf393ef505c3ee9920e00c63cc3c..20a0b94ebfb5a60791a09e42165312dc0a4a6711 100644 (file)
@@ -17,7 +17,7 @@
 */
 #define BLINK_GPIO CONFIG_BLINK_GPIO
 
-void blink_task(void *pvParameter)
+void app_main()
 {
     /* Configure the IOMUX register for pad BLINK_GPIO (some pads are
        muxed to GPIO on reset already, but some default to other
@@ -30,15 +30,12 @@ void blink_task(void *pvParameter)
     gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
     while(1) {
         /* Blink off (output low) */
+       printf("Turning off the LED\n");
         gpio_set_level(BLINK_GPIO, 0);
         vTaskDelay(1000 / portTICK_PERIOD_MS);
         /* Blink on (output high) */
+       printf("Turning on the LED\n");
         gpio_set_level(BLINK_GPIO, 1);
         vTaskDelay(1000 / portTICK_PERIOD_MS);
     }
 }
-
-void app_main()
-{
-    xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
-}
index 52be40efd4affc891e51c26746c3519823f67b62..039c6b94bf48318142dedeaa7bb05c84370618e0 100644 (file)
 #include "esp_event_loop.h"
 #include "cmd_wifi.h"
 
+#define JOIN_TIMEOUT_MS (10000)
+
 static EventGroupHandle_t wifi_event_group;
 const int CONNECTED_BIT = BIT0;
 
 static esp_err_t event_handler(void *ctx, system_event_t *event)
 {
-    switch(event->event_id) {
+    switch (event->event_id) {
     case SYSTEM_EVENT_STA_GOT_IP:
         xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
         break;
@@ -57,13 +59,13 @@ static void initialise_wifi(void)
     initialized = true;
 }
 
-static bool wifi_join(const char* ssid, const char* pass, int timeout_ms)
+static bool wifi_join(const char *ssid, const char *pass, int timeout_ms)
 {
     initialise_wifi();
     wifi_config_t wifi_config = { 0 };
-    strncpy((char*) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
+    strncpy((char *) wifi_config.sta.ssid, ssid, sizeof(wifi_config.sta.ssid));
     if (pass) {
-        strncpy((char*) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
+        strncpy((char *) wifi_config.sta.password, pass, sizeof(wifi_config.sta.password));
     }
 
     ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
@@ -71,7 +73,7 @@ static bool wifi_join(const char* ssid, const char* pass, int timeout_ms)
     ESP_ERROR_CHECK( esp_wifi_connect() );
 
     int bits = xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
-            1, 1, timeout_ms / portTICK_PERIOD_MS);
+                                   pdFALSE, pdTRUE, timeout_ms / portTICK_PERIOD_MS);
     return (bits & CONNECTED_BIT) != 0;
 }
 
@@ -83,19 +85,24 @@ static struct {
     struct arg_end *end;
 } join_args;
 
-static int connect(int argc, char** argv)
+static int connect(int argc, char **argv)
 {
-    int nerrors = arg_parse(argc, argv, (void**) &join_args);
+    int nerrors = arg_parse(argc, argv, (void **) &join_args);
     if (nerrors != 0) {
         arg_print_errors(stderr, join_args.end, argv[0]);
         return 1;
     }
     ESP_LOGI(__func__, "Connecting to '%s'",
-            join_args.ssid->sval[0]);
+             join_args.ssid->sval[0]);
+
+    /* set default value*/
+    if (join_args.timeout->count == 0) {
+        join_args.timeout->ival[0] = JOIN_TIMEOUT_MS;
+    }
 
     bool connected = wifi_join(join_args.ssid->sval[0],
-                           join_args.password->sval[0],
-                           join_args.timeout->ival[0]);
+                               join_args.password->sval[0],
+                               join_args.timeout->ival[0]);
     if (!connected) {
         ESP_LOGW(__func__, "Connection timed out");
         return 1;
@@ -107,7 +114,6 @@ static int connect(int argc, char** argv)
 void register_wifi()
 {
     join_args.timeout = arg_int0(NULL, "timeout", "<t>", "Connection timeout, ms");
-    join_args.timeout->ival[0] = 5000; // set default value
     join_args.ssid = arg_str1(NULL, NULL, "<ssid>", "SSID of AP");
     join_args.password = arg_str0(NULL, NULL, "<pass>", "PSK of AP");
     join_args.end = arg_end(2);
index 71bcaa043233f6e898a6d5ab55dbc4996a15d1fb..e03c124967ce406962771aee56787de2d8a0d391 100644 (file)
@@ -133,9 +133,10 @@ void app_main()
 {
     // Initialize NVS.
     esp_err_t err = nvs_flash_init();
-    if (err == ESP_ERR_NVS_NO_FREE_PAGES) {
-        // OTA app partition table has a smaller NVS partition size than the non-OTA
+    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        // 1.OTA app partition table has a smaller NVS partition size than the non-OTA
         // partition table. This size mismatch may cause NVS initialization to fail.
+        // 2.NVS partition contains data in new format and cannot be recognized by this version of code.
         // If this happens, we erase NVS partition and initialize NVS again.
         ESP_ERROR_CHECK(nvs_flash_erase());
         err = nvs_flash_init();
index 068838a77d8e6647d82401e7cd8429cad853702a..3a15dbe993c41df8ed350513409147e6472cb987 100755 (executable)
@@ -54,13 +54,15 @@ git submodule init
 # 2
 # Replacing each submodule URL of the current repository
 # according to the one found in the MIRRORLIST
-
-#   SED parses the strings like:
-#
-#-b991c67c1d91574ef22336cc3a5944d1e63230c9 roms/ipxe
-#b991c67c1d91574ef22336cc3a5944d1e63230c9 roms/ipxe (v1.0.0-2388-gb991c67)
 #
-for SUBPATH in $(git submodule status | sed -E 's/.*[[:space:]](.*)([[:space:]].*|$)/\1/')
+# Selecting paths among lines:
+# ...
+#submodule.components/esp32/lib.path
+#submodule.components/esp32/lib.url
+#submodule.components/esptool_py/esptool.path
+#submodule.components/esptool_py/esptool.url
+#...
+for SUBPATH in $(git config -f .gitmodules --list --name-only | grep "\.path" | sed 's/^submodule\.\([^ ]*\)\.path$/\1/')
 do
     SUBMIRROR=$(join -o"2.2" <(echo ${SUBPATH}) <(sort ${MIRRORLIST}))
     [ ${SUBMIRROR} ] || continue
index f63aae7f95ee0cdf1d7de4ef73d41c7e47397586..3dd1bea577dd54f31b1ea0a927781b124782b8a4 100755 (executable)
@@ -107,19 +107,27 @@ function run_tests()
        idf.py build || failure "Failed to rebuild with changed app version"
     assert_rebuilt ${APP_BINS}
     assert_not_rebuilt ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a
-    
+
     print_status "Re-building does not change app.bin"
     take_build_snapshot
     idf.py build
     assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a
     rm -f ${TESTDIR}/template/version.txt
-    
+
     print_status "Get the version of app from git describe. Project is not inside IDF and do not have a tag only a hash commit."
     idf.py build >> log.log || failure "Failed to build"
     version="Project version: "
     version+=$(git describe --always --tags --dirty)
     grep "${version}" log.log || failure "Project version should have a hash commit"
 
+    print_status "Can set COMPONENT_SRCS with spaces"
+    clean_build_dir
+    touch main/main2.c
+    sed -i 's/^set(COMPONENT_SRCS.*/set(COMPONENT_SRCS "main.c main2.c")/' main/CMakeLists.txt
+    idf.py build || failure "Set COMPONENT_SRCS with spaces build failed"
+    git checkout -- main/CMakeLists.txt
+    rm main/main2.c
+
     print_status "Moving BUILD_DIR_BASE out of tree"
     clean_build_dir
     OUTOFTREE_BUILD=${TESTDIR}/alt_build
@@ -327,17 +335,33 @@ function run_tests()
     idf.py reconfigure > /dev/null;
     grep "CONFIG_PARTITION_TABLE_OFFSET=0x10000" sdkconfig || failure "The define from sdkconfig.defaults should be into sdkconfig"
     grep "CONFIG_PARTITION_TABLE_TWO_OTA=y" sdkconfig || failure "The define from sdkconfig should be into sdkconfig"
+    rm sdkconfig;
+    rm sdkconfig.defaults;
 
     print_status "Building a project with CMake library imported and PSRAM workaround, all files compile with workaround"
-    cp sdkconfig sdkconfig.psram
     rm -rf build
-    echo "CONFIG_SPIRAM_SUPPORT=y" >> sdkconfig.psram
-    echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> sdkconfig.psram
+    echo "CONFIG_SPIRAM_SUPPORT=y" >> sdkconfig.defaults
+    echo "CONFIG_SPIRAM_CACHE_WORKAROUND=y" >> sdkconfig.defaults
     # note: we do 'reconfigure' here, as we just need to run cmake
-    idf.py -C $IDF_PATH/examples/build_system/cmake/import_lib -B `pwd`/build reconfigure -D SDKCONFIG="`pwd`/sdkconfig.psram"
+    idf.py -C $IDF_PATH/examples/build_system/cmake/import_lib -B `pwd`/build reconfigure -D SDKCONFIG_DEFAULTS="`pwd`/sdkconfig.defaults"
     grep -q '"command"' build/compile_commands.json || failure "compile_commands.json missing or has no no 'commands' in it"
     (grep '"command"' build/compile_commands.json | grep -v mfix-esp32-psram-cache-issue) && failure "All commands in compile_commands.json should use PSRAM cache workaround"
-    rm sdkconfig.psram
+    rm sdkconfig.defaults
+
+    print_status "Make sure a full build never runs '/usr/bin/env python' or similar"
+    OLDPATH="$PATH"
+    PYTHON="$(which python)"
+    rm -rf build
+    cat > ./python << EOF
+    #!/bin/sh
+    echo "The build system has executed '/usr/bin/env python' or similar"
+    exit 1
+EOF
+    chmod +x ./python
+    export PATH="$(pwd):$PATH"
+    ${PYTHON} $IDF_PATH/tools/idf.py build || failure "build failed"
+    export PATH="$OLDPATH"
+    rm ./python
 
     print_status "All tests completed"
     if [ -n "${FAILURES}" ]; then
index 82d0fbcaaa4affa5bf2d79b7591cf1f63d2b5703..4abc5990a6db89718e3aae9400d3690307f10efb 100644 (file)
@@ -17,6 +17,7 @@ endfunction()
 function(register_component)
     get_filename_component(component_dir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
 
+    spaces2list(COMPONENT_SRCS)
     spaces2list(COMPONENT_SRCDIRS)
     spaces2list(COMPONENT_ADD_INCLUDEDIRS)
     spaces2list(COMPONENT_SRCEXCLUDE)
@@ -175,4 +176,4 @@ endfunction()
 function(component_get_target var component)
     get_property(prefix GLOBAL PROPERTY __IDF_COMPONENTS_PREFIX)
     set(${var} ${prefix}_${component} PARENT_SCOPE)
-endfunction()
\ No newline at end of file
+endfunction()
index 8cc277986e74e727ed07aef07df2c76fbd29e25c..6a00eacfe6c5ffaebb8dc8f8a0f98df0735b49cf 100644 (file)
@@ -53,7 +53,7 @@ function(ldgen_process_template template output)
     # Create command to invoke the linker script generator tool.
     add_custom_command(
         OUTPUT ${output}
-        COMMAND ${IDF_PATH}/tools/ldgen/ldgen.py
+        COMMAND ${PYTHON} ${IDF_PATH}/tools/ldgen/ldgen.py
         --config    ${SDKCONFIG}
         --fragments "$<JOIN:$<TARGET_PROPERTY:ldgen,FRAGMENT_FILES>,\t>"
         --input     ${template}
index 2d31d6671365c56c206fe9c390ba4bc00cc3dc27..af3fc1f2932f3af326b366670e18583f0fe7b66d 100755 (executable)
@@ -560,7 +560,20 @@ def main():
 
 if __name__ == "__main__":
     try:
-        main()
+        # On MSYS2 we need to run idf.py with "winpty" in order to be able to cancel the subprocesses properly on
+        # keyboard interrupt (CTRL+C).
+        # Using an own global variable for indicating that we are running with "winpty" seems to be the most suitable
+        # option as os.environment['_'] contains "winpty" only when it is run manually from console.
+        WINPTY_VAR = 'WINPTY'
+        WINPTY_EXE = 'winpty'
+        if ('MSYSTEM' in os.environ) and (not os.environ['_'].endswith(WINPTY_EXE) and WINPTY_VAR not in os.environ):
+            os.environ[WINPTY_VAR] = '1'    # the value is of no interest to us
+            # idf.py calls itself with "winpty" and WINPTY global variable set
+            ret = subprocess.call([WINPTY_EXE, sys.executable] + sys.argv, env=os.environ)
+            if ret:
+                raise SystemExit(ret)
+        else:
+            main()
     except FatalError as e:
         print(e)
         sys.exit(2)
index 432553f2e73a356985a7e728a19955b98bb96a2c..f449687824529bb3ac57f7cb07d550df4d8dac5e 100644 (file)
@@ -5,7 +5,7 @@
 nvs,        data, nvs,      0x9000,  0x4000
 otadata,    data, ota,      0xd000,  0x2000
 phy_init,   data, phy,      0xf000,  0x1000
-factory,    0,    0,        0x10000, 0x240000
+factory,    0,    0,        0x10000, 0x250000
 # these OTA partitions are used for tests, but can't fit real OTA apps in them
 # (done this way to reduce total flash usage.)
 ota_0,      0,    ota_0,    ,        64K
index 86e352d7f31b8cd3168cce25479db20d8f8ab8f2..777d28f9b36260179be4b608867957541df6ba40 100755 (executable)
@@ -293,6 +293,7 @@ def run_unit_test_cases(env, extra_data):
                 failed_cases.append(one_case["name"])
             except Exception as e:
                 junit_test_case.add_failure_info("Unexpected exception: " + str(e))
+                failed_cases.append(one_case["name"])
             finally:
                 TinyFW.JunitReport.test_case_finish(junit_test_case)
 
@@ -420,7 +421,7 @@ def get_dut(duts, env, name, ut_config, app_bin=None):
     return dut
 
 
-def run_one_multiple_devices_case(duts, ut_config, env, one_case, failed_cases, app_bin, junit_test_case):
+def run_one_multiple_devices_case(duts, ut_config, env, one_case, app_bin, junit_test_case):
     lock = threading.RLock()
     threads = []
     send_signal_list = []
@@ -442,12 +443,9 @@ def run_one_multiple_devices_case(duts, ut_config, env, one_case, failed_cases,
         if not thread.result:
             [thd.stop() for thd in threads]
 
-    if result:
-        Utility.console_log("Success: " + one_case["name"], color="green")
-    else:
-        failed_cases.append(one_case["name"])
+    if not result:
         junit_test_case.add_failure_info(output)
-        Utility.console_log("Failed: " + one_case["name"], color="red")
+    return result
 
 
 @IDF.idf_unit_test(env_tag="UT_T2_1", junit_report_by_case=True)
@@ -478,13 +476,19 @@ def run_multiple_devices_cases(env, extra_data):
     for ut_config in case_config:
         Utility.console_log("Running unit test for config: " + ut_config, "O")
         for one_case in case_config[ut_config]:
+            result = False
             junit_test_case = TinyFW.JunitReport.create_test_case("[{}] {}".format(ut_config, one_case["name"]))
             try:
-                run_one_multiple_devices_case(duts, ut_config, env, one_case, failed_cases,
-                                              one_case.get('app_bin'), junit_test_case)
+                result = run_one_multiple_devices_case(duts, ut_config, env, one_case,
+                                                       one_case.get('app_bin'), junit_test_case)
             except Exception as e:
                 junit_test_case.add_failure_info("Unexpected exception: " + str(e))
             finally:
+                if result:
+                    Utility.console_log("Success: " + one_case["name"], color="green")
+                else:
+                    failed_cases.append(one_case["name"])
+                    Utility.console_log("Failed: " + one_case["name"], color="red")
                 TinyFW.JunitReport.test_case_finish(junit_test_case)
 
     if failed_cases:
@@ -631,6 +635,7 @@ def run_multiple_stage_cases(env, extra_data):
                 failed_cases.append(one_case["name"])
             except Exception as e:
                 junit_test_case.add_failure_info("Unexpected exception: " + str(e))
+                failed_cases.append(one_case["name"])
             finally:
                 TinyFW.JunitReport.test_case_finish(junit_test_case)