From 0519a73334776e07c3bb5015ec94ed2f11bd0977 Mon Sep 17 00:00:00 2001 From: baohongde Date: Wed, 7 Feb 2018 17:03:48 +0800 Subject: [PATCH 01/19] component/bt: Fix mem leak of bt --- components/bt/bluedroid/bta/av/bta_av_act.c | 2 ++ .../bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c | 8 +++++++- .../bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c | 8 +++++++- examples/bluetooth/a2dp_sink/main/bt_app_core.c | 4 ++-- examples/bluetooth/a2dp_source/main/bt_app_core.c | 2 +- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/components/bt/bluedroid/bta/av/bta_av_act.c b/components/bt/bluedroid/bta/av/bta_av_act.c index 9b00d62ce..b86875870 100644 --- a/components/bt/bluedroid/bta/av/bta_av_act.c +++ b/components/bt/bluedroid/bta/av/bta_av_act.c @@ -1847,6 +1847,8 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data) /* make sure that the timer is not active */ bta_sys_stop_timer(&p_scb->timer); + list_free(p_scb->a2d_list); + p_scb->a2d_list = NULL; utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]); } diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c index 671584448..d52391a86 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_sink.c @@ -273,7 +273,10 @@ error_exit:; vQueueDelete(btc_aa_snk_ctrl_queue); btc_aa_snk_ctrl_queue = NULL; } - + if (btc_aa_snk_queue_set) { + vQueueDelete(btc_aa_snk_queue_set); + btc_aa_snk_queue_set = NULL; + } return false; } @@ -292,6 +295,9 @@ void btc_a2dp_sink_shutdown(void) vQueueDelete(btc_aa_snk_ctrl_queue); btc_aa_snk_ctrl_queue = NULL; + + vQueueDelete(btc_aa_snk_queue_set); + btc_aa_snk_queue_set = NULL; } /***************************************************************************** diff --git a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c index d40591783..cbcce6220 100644 --- a/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c +++ b/components/bt/bluedroid/btc/profile/std/a2dp/btc_a2dp_source.c @@ -348,7 +348,10 @@ error_exit:; vQueueDelete(btc_aa_src_ctrl_queue); btc_aa_src_ctrl_queue = NULL; } - + if (btc_aa_src_queue_set) { + vQueueDelete(btc_aa_src_queue_set); + btc_aa_src_queue_set = NULL; + } return false; } @@ -367,6 +370,9 @@ void btc_a2dp_source_shutdown(void) vQueueDelete(btc_aa_src_ctrl_queue); btc_aa_src_ctrl_queue = NULL; + + vQueueDelete(btc_aa_src_queue_set); + btc_aa_src_queue_set = NULL; } /***************************************************************************** diff --git a/examples/bluetooth/a2dp_sink/main/bt_app_core.c b/examples/bluetooth/a2dp_sink/main/bt_app_core.c index 6c48d9a70..b04d5c89a 100644 --- a/examples/bluetooth/a2dp_sink/main/bt_app_core.c +++ b/examples/bluetooth/a2dp_sink/main/bt_app_core.c @@ -27,7 +27,7 @@ static xTaskHandle bt_app_task_handle = NULL; bool bt_app_work_dispatch(bt_app_cb_t p_cback, uint16_t event, void *p_params, int param_len, bt_app_copy_cb_t p_copy_cback) { ESP_LOGD(BT_APP_CORE_TAG, "%s event 0x%x, param len %d", __func__, event, param_len); - + bt_app_msg_t msg; memset(&msg, 0, sizeof(bt_app_msg_t)); @@ -96,7 +96,7 @@ static void bt_app_task_handler(void *arg) void bt_app_task_start_up(void) { bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t)); - xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, bt_app_task_handle); + xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &bt_app_task_handle); return; } diff --git a/examples/bluetooth/a2dp_source/main/bt_app_core.c b/examples/bluetooth/a2dp_source/main/bt_app_core.c index be699ef8a..b04d5c89a 100644 --- a/examples/bluetooth/a2dp_source/main/bt_app_core.c +++ b/examples/bluetooth/a2dp_source/main/bt_app_core.c @@ -96,7 +96,7 @@ static void bt_app_task_handler(void *arg) void bt_app_task_start_up(void) { bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t)); - xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, bt_app_task_handle); + xTaskCreate(bt_app_task_handler, "BtAppT", 2048, NULL, configMAX_PRIORITIES - 3, &bt_app_task_handle); return; } From cb3f09485dd913ec4133707fe4511c38ce3d80b3 Mon Sep 17 00:00:00 2001 From: Frank Sautter Date: Thu, 8 Feb 2018 00:54:10 +0100 Subject: [PATCH 02/19] Set direction of SMI pins MDC and MDIO correctly. Merges https://github.com/espressif/esp-idf/pull/1594 --- components/ethernet/eth_phy/phy_common.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/ethernet/eth_phy/phy_common.c b/components/ethernet/eth_phy/phy_common.c index 88e5d0c73..26a7a304d 100644 --- a/components/ethernet/eth_phy/phy_common.c +++ b/components/ethernet/eth_phy/phy_common.c @@ -40,8 +40,12 @@ void phy_rmii_configure_data_interface_pins(void) void phy_rmii_smi_configure_pins(uint8_t mdc_gpio, uint8_t mdio_gpio) { + // setup SMI MDC pin + gpio_set_direction(mdc_gpio, GPIO_MODE_OUTPUT); gpio_matrix_out(mdc_gpio, EMAC_MDC_O_IDX, 0, 0); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdc_gpio], PIN_FUNC_GPIO); + // setup SMI MDIO pin + gpio_set_direction(mdio_gpio, GPIO_MODE_INPUT_OUTPUT); gpio_matrix_out(mdio_gpio, EMAC_MDO_O_IDX, 0, 0); gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0); PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdio_gpio], PIN_FUNC_GPIO); From 475e3cc43e86b1752f4003491724c91f69d175c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ing=2E=20Jaroslav=20=C5=A0afka?= Date: Thu, 1 Feb 2018 11:00:29 +0100 Subject: [PATCH 03/19] Fix function name typo. Closes https://github.com/espressif/esp-idf/issue/1572 --- components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c index a49f3ed1b..6a4d51974 100644 --- a/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c +++ b/components/bt/bluedroid/btc/profile/std/gatt/btc_gattc.c @@ -631,7 +631,7 @@ static void btc_gattc_prepare_write_char_descr(btc_ble_gattc_args_t *arg) arg->prep_write_descr.auth_req); } -static void btc_gattc_execute_wrtie(btc_ble_gattc_args_t *arg) +static void btc_gattc_execute_write(btc_ble_gattc_args_t *arg) { BTA_GATTC_ExecuteWrite(arg->exec_write.conn_id, arg->exec_write.is_execute); } @@ -711,7 +711,7 @@ void btc_gattc_call_handler(btc_msg_t *msg) btc_gattc_prepare_write_char_descr(arg); break; case BTC_GATTC_ACT_EXECUTE_WRITE: - btc_gattc_execute_wrtie(arg); + btc_gattc_execute_write(arg); break; case BTC_GATTC_ACT_REG_FOR_NOTIFY: btc_gattc_reg_for_notify(arg); From ef080c0841920c0c73e386be977d445ba5b61049 Mon Sep 17 00:00:00 2001 From: SmallRoomLabs Date: Fri, 9 Feb 2018 13:01:52 +0100 Subject: [PATCH 04/19] Remove the THEN keyword from IF. Closes https://github.com/espressif/esp-idf/issue/1606 Both the TinyBasicPlus and the ESP32 variant don't use the THEN keyword in a IF statement --- docs/api-guides/romconsole.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guides/romconsole.rst b/docs/api-guides/romconsole.rst index 37fd5694e..d33ca0000 100644 --- a/docs/api-guides/romconsole.rst +++ b/docs/api-guides/romconsole.rst @@ -44,7 +44,7 @@ Expressions, Math Control ------- -- IF expression THEN statement - *perform statement if expression is true* +- IF expression statement - *perform statement if expression is true* - FOR variable = start TO end - *start for block* - FOR variable = start TO end STEP value - *start for block with step* - NEXT - *end of for block* From 37b98f7306f8f2743ea8f0e672da5e06c732baea Mon Sep 17 00:00:00 2001 From: njyq2008 Date: Tue, 13 Feb 2018 16:35:28 +0800 Subject: [PATCH 05/19] Update index-cn.rst. Closes https://github.com/espressif/esp-idf/issue/1620 --- docs/get-started/index-cn.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/get-started/index-cn.rst b/docs/get-started/index-cn.rst index 5a0bbbe62..5d2a21da3 100644 --- a/docs/get-started/index-cn.rst +++ b/docs/get-started/index-cn.rst @@ -142,7 +142,7 @@ ESP-IDF 将会被下载到 ``~/esp/esp-idf``。 将 :example:`get-started/hello_world` 拷贝到 ``~/esp`` 目录: :: cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world + cp -r $IDF_PATH/examples/get-started/hello_world . ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。 From 10ab4c085b462e869e24cc1b01adfb510edd60cd Mon Sep 17 00:00:00 2001 From: "Michael (Xiao Xufeng)" Date: Tue, 13 Feb 2018 15:54:44 +0800 Subject: [PATCH 06/19] example(console): print column name for tasks. --- examples/system/console/main/cmd_system.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/system/console/main/cmd_system.c b/examples/system/console/main/cmd_system.c index e7192b9fe..ceb5a4ac9 100644 --- a/examples/system/console/main/cmd_system.c +++ b/examples/system/console/main/cmd_system.c @@ -94,6 +94,7 @@ static int tasks_info(int argc, char** argv) ESP_LOGE(__func__, "failed to allocate buffer for vTaskList output"); return 1; } + fputs("Task Name\tStatus\tPrio\tHWM\tTask Number\n", stdout); vTaskList(task_list_buffer); fputs(task_list_buffer, stdout); free(task_list_buffer); From 4322e31c983b97053ab03722fb1cca672ca9eec5 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Thu, 1 Feb 2018 13:14:47 +0100 Subject: [PATCH 07/19] Make it easier to look up error messages tools/gen_esp_err_to_name.py generates components/esp32/esp_err_to_name.c for lookup of the error codes from all of the IDF project and easily identify all codes in one place --- .gitlab-ci.yml | 11 + components/esp32/esp_err_to_name.c | 396 ++++++++++++++++++++++++++ components/esp32/esp_err_to_name.c.in | 53 ++++ components/esp32/include/esp_err.h | 33 +++ tools/gen_esp_err_to_name.py | 300 +++++++++++++++++++ 5 files changed, 793 insertions(+) create mode 100644 components/esp32/esp_err_to_name.c create mode 100644 components/esp32/esp_err_to_name.c.in create mode 100755 tools/gen_esp_err_to_name.py diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2153a3d4e..09711b6b7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -319,6 +319,17 @@ test_report: - git push origin master - test "${TEST_RESULT}" = "Pass" || exit 1 +test_esp_err_to_name_on_host: + stage: test + image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + tags: + - build + dependencies: [] + script: + - cd tools/ + - ./gen_esp_err_to_name.py + - git diff --exit-code -- ../components/esp32/esp_err_to_name.c || (echo 'Differences found. Please run gen_esp_err_to_name.py and commit the changes.'; exit 1) + push_master_to_github: stage: deploy image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG diff --git a/components/esp32/esp_err_to_name.c b/components/esp32/esp_err_to_name.c new file mode 100644 index 000000000..a706a68a5 --- /dev/null +++ b/components/esp32/esp_err_to_name.c @@ -0,0 +1,396 @@ +//Do not edit this file because it is autogenerated by gen_esp_err_to_name.py + +#include +#if __has_include("soc/soc.h") +#include "soc/soc.h" +#endif +#if __has_include("esp32/ulp.h") +#include "esp32/ulp.h" +#endif +#if __has_include("esp_err.h") +#include "esp_err.h" +#endif +#if __has_include("esp_image_format.h") +#include "esp_image_format.h" +#endif +#if __has_include("esp_now.h") +#include "esp_now.h" +#endif +#if __has_include("esp_ota_ops.h") +#include "esp_ota_ops.h" +#endif +#if __has_include("esp_ping.h") +#include "esp_ping.h" +#endif +#if __has_include("esp_spi_flash.h") +#include "esp_spi_flash.h" +#endif +#if __has_include("esp_wifi.h") +#include "esp_wifi.h" +#endif +#if __has_include("esp_wps.h") +#include "esp_wps.h" +#endif +#if __has_include("nvs.h") +#include "nvs.h" +#endif +#if __has_include("tcpip_adapter.h") +#include "tcpip_adapter.h" +#endif + +#define ERR_TBL_IT(err) {err, #err} + +typedef struct { + esp_err_t code; + const char *msg; +} esp_err_msg_t; + +static const esp_err_msg_t esp_err_msg_table[] = { + // components/esp32/include/esp_err.h +# ifdef ESP_FAIL + ERR_TBL_IT(ESP_FAIL), /* -1 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_FAIL + ERR_TBL_IT(ESP_ERR_WIFI_FAIL), /* -1 General fail code */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_OK + ERR_TBL_IT(ESP_OK), /* 0 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_OK + ERR_TBL_IT(ESP_ERR_WIFI_OK), /* 0 No error */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_NO_MEM + ERR_TBL_IT(ESP_ERR_NO_MEM), /* 257 0x101 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NO_MEM + ERR_TBL_IT(ESP_ERR_WIFI_NO_MEM), /* 257 0x101 Out of memory */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_INVALID_ARG + ERR_TBL_IT(ESP_ERR_INVALID_ARG), /* 258 0x102 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_ARG + ERR_TBL_IT(ESP_ERR_WIFI_ARG), /* 258 0x102 Invalid argument */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_INVALID_STATE + ERR_TBL_IT(ESP_ERR_INVALID_STATE), /* 259 0x103 */ +# endif +# ifdef ESP_ERR_INVALID_SIZE + ERR_TBL_IT(ESP_ERR_INVALID_SIZE), /* 260 0x104 */ +# endif +# ifdef ESP_ERR_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NOT_FOUND), /* 261 0x105 */ +# endif +# ifdef ESP_ERR_NOT_SUPPORTED + ERR_TBL_IT(ESP_ERR_NOT_SUPPORTED), /* 262 0x106 */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NOT_SUPPORT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_SUPPORT), /* 262 0x106 Indicates that API is not supported yet */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_TIMEOUT + ERR_TBL_IT(ESP_ERR_TIMEOUT), /* 263 0x107 */ +# endif +# ifdef ESP_ERR_INVALID_RESPONSE + ERR_TBL_IT(ESP_ERR_INVALID_RESPONSE), /* 264 0x108 */ +# endif +# ifdef ESP_ERR_INVALID_CRC + ERR_TBL_IT(ESP_ERR_INVALID_CRC), /* 265 0x109 */ +# endif +# ifdef ESP_ERR_INVALID_VERSION + ERR_TBL_IT(ESP_ERR_INVALID_VERSION), /* 266 0x10a */ +# endif +# ifdef ESP_ERR_INVALID_MAC + ERR_TBL_IT(ESP_ERR_INVALID_MAC), /* 267 0x10b */ +# endif + // components/nvs_flash/include/nvs.h +# ifdef ESP_ERR_NVS_BASE + ERR_TBL_IT(ESP_ERR_NVS_BASE), /* 4352 0x1100 Starting number of error codes */ +# endif +# ifdef ESP_ERR_NVS_NOT_INITIALIZED + ERR_TBL_IT(ESP_ERR_NVS_NOT_INITIALIZED), /* 4353 0x1101 The storage driver is not initialized */ +# endif +# ifdef ESP_ERR_NVS_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NVS_NOT_FOUND), /* 4354 0x1102 Id namespace doesn’t exist yet and mode is + NVS_READONLY */ +# endif +# ifdef ESP_ERR_NVS_TYPE_MISMATCH + ERR_TBL_IT(ESP_ERR_NVS_TYPE_MISMATCH), /* 4355 0x1103 The type of set or get operation doesn't + match the type of value stored in NVS */ +# endif +# ifdef ESP_ERR_NVS_READ_ONLY + ERR_TBL_IT(ESP_ERR_NVS_READ_ONLY), /* 4356 0x1104 Storage handle was opened as read only */ +# endif +# ifdef ESP_ERR_NVS_NOT_ENOUGH_SPACE + ERR_TBL_IT(ESP_ERR_NVS_NOT_ENOUGH_SPACE), /* 4357 0x1105 There is not enough space in the underlying + storage to save the value */ +# endif +# ifdef ESP_ERR_NVS_INVALID_NAME + ERR_TBL_IT(ESP_ERR_NVS_INVALID_NAME), /* 4358 0x1106 Namespace name doesn’t satisfy constraints */ +# endif +# ifdef ESP_ERR_NVS_INVALID_HANDLE + ERR_TBL_IT(ESP_ERR_NVS_INVALID_HANDLE), /* 4359 0x1107 Handle has been closed or is NULL */ +# endif +# ifdef ESP_ERR_NVS_REMOVE_FAILED + ERR_TBL_IT(ESP_ERR_NVS_REMOVE_FAILED), /* 4360 0x1108 The value wasn’t updated because flash + write operation has failed. The value was + written however, and update will be finished + after re-initialization of nvs, provided + that flash operation doesn’t fail again. */ +# endif +# ifdef ESP_ERR_NVS_KEY_TOO_LONG + ERR_TBL_IT(ESP_ERR_NVS_KEY_TOO_LONG), /* 4361 0x1109 Key name is too long */ +# endif +# ifdef ESP_ERR_NVS_PAGE_FULL + ERR_TBL_IT(ESP_ERR_NVS_PAGE_FULL), /* 4362 0x110a Internal error; never returned by nvs_ API + functions */ +# endif +# ifdef ESP_ERR_NVS_INVALID_STATE + ERR_TBL_IT(ESP_ERR_NVS_INVALID_STATE), /* 4363 0x110b NVS is in an inconsistent state due to a + previous error. Call nvs_flash_init and + nvs_open again, then retry. */ +# endif +# ifdef ESP_ERR_NVS_INVALID_LENGTH + ERR_TBL_IT(ESP_ERR_NVS_INVALID_LENGTH), /* 4364 0x110c String or blob length is not sufficient to + store data */ +# endif +# ifdef ESP_ERR_NVS_NO_FREE_PAGES + ERR_TBL_IT(ESP_ERR_NVS_NO_FREE_PAGES), /* 4365 0x110d NVS partition doesn't contain any empty + pages. This may happen if NVS partition was + truncated. Erase the whole partition and + call nvs_flash_init again. */ +# endif +# ifdef ESP_ERR_NVS_VALUE_TOO_LONG + ERR_TBL_IT(ESP_ERR_NVS_VALUE_TOO_LONG), /* 4366 0x110e String or blob length is longer than + supported by the implementation */ +# endif +# ifdef ESP_ERR_NVS_PART_NOT_FOUND + ERR_TBL_IT(ESP_ERR_NVS_PART_NOT_FOUND), /* 4367 0x110f Partition with specified name is not found + in the partition table */ +# endif + // components/ulp/include/esp32/ulp.h +# ifdef ESP_ERR_ULP_BASE + ERR_TBL_IT(ESP_ERR_ULP_BASE), /* 4608 0x1200 Offset for ULP-related error codes */ +# endif +# ifdef ESP_ERR_ULP_SIZE_TOO_BIG + ERR_TBL_IT(ESP_ERR_ULP_SIZE_TOO_BIG), /* 4609 0x1201 Program doesn't fit into RTC memory reserved + for the ULP */ +# endif +# ifdef ESP_ERR_ULP_INVALID_LOAD_ADDR + ERR_TBL_IT(ESP_ERR_ULP_INVALID_LOAD_ADDR), /* 4610 0x1202 Load address is outside of RTC memory + reserved for the ULP */ +# endif +# ifdef ESP_ERR_ULP_DUPLICATE_LABEL + ERR_TBL_IT(ESP_ERR_ULP_DUPLICATE_LABEL), /* 4611 0x1203 More than one label with the same number was + defined */ +# endif +# ifdef ESP_ERR_ULP_UNDEFINED_LABEL + ERR_TBL_IT(ESP_ERR_ULP_UNDEFINED_LABEL), /* 4612 0x1204 Branch instructions references an undefined label */ +# endif +# ifdef ESP_ERR_ULP_BRANCH_OUT_OF_RANGE + ERR_TBL_IT(ESP_ERR_ULP_BRANCH_OUT_OF_RANGE), /* 4613 0x1205 Branch target is out of range of B + instruction (try replacing with BX) */ +# endif + // components/app_update/include/esp_ota_ops.h +# ifdef ESP_ERR_OTA_BASE + ERR_TBL_IT(ESP_ERR_OTA_BASE), /* 5376 0x1500 Base error code for ota_ops api */ +# endif +# ifdef ESP_ERR_OTA_PARTITION_CONFLICT + ERR_TBL_IT(ESP_ERR_OTA_PARTITION_CONFLICT), /* 5377 0x1501 Error if request was to write or erase the + current running partition */ +# endif +# ifdef ESP_ERR_OTA_SELECT_INFO_INVALID + ERR_TBL_IT(ESP_ERR_OTA_SELECT_INFO_INVALID), /* 5378 0x1502 Error if OTA data partition contains invalid + content */ +# endif +# ifdef ESP_ERR_OTA_VALIDATE_FAILED + ERR_TBL_IT(ESP_ERR_OTA_VALIDATE_FAILED), /* 5379 0x1503 Error if OTA app image is invalid */ +# endif + // components/bootloader_support/include/esp_image_format.h +# ifdef ESP_ERR_IMAGE_BASE + ERR_TBL_IT(ESP_ERR_IMAGE_BASE), /* 8192 0x2000 */ +# endif +# ifdef ESP_ERR_IMAGE_FLASH_FAIL + ERR_TBL_IT(ESP_ERR_IMAGE_FLASH_FAIL), /* 8193 0x2001 */ +# endif +# ifdef ESP_ERR_IMAGE_INVALID + ERR_TBL_IT(ESP_ERR_IMAGE_INVALID), /* 8194 0x2002 */ +# endif + // components/esp32/include/esp_err.h +# ifdef ESP_ERR_WIFI_BASE + ERR_TBL_IT(ESP_ERR_WIFI_BASE), /* 12288 0x3000 Starting number of WiFi error codes */ +# endif + // components/esp32/include/esp_wifi.h +# ifdef ESP_ERR_WIFI_NOT_INIT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_INIT), /* 12289 0x3001 WiFi driver was not installed by esp_wifi_init */ +# endif +# ifdef ESP_ERR_WIFI_NOT_STARTED + ERR_TBL_IT(ESP_ERR_WIFI_NOT_STARTED), /* 12290 0x3002 WiFi driver was not started by esp_wifi_start */ +# endif +# ifdef ESP_ERR_WIFI_NOT_STOPPED + ERR_TBL_IT(ESP_ERR_WIFI_NOT_STOPPED), /* 12291 0x3003 WiFi driver was not stopped by esp_wifi_stop */ +# endif +# ifdef ESP_ERR_WIFI_IF + ERR_TBL_IT(ESP_ERR_WIFI_IF), /* 12292 0x3004 WiFi interface error */ +# endif +# ifdef ESP_ERR_WIFI_MODE + ERR_TBL_IT(ESP_ERR_WIFI_MODE), /* 12293 0x3005 WiFi mode error */ +# endif +# ifdef ESP_ERR_WIFI_STATE + ERR_TBL_IT(ESP_ERR_WIFI_STATE), /* 12294 0x3006 WiFi internal state error */ +# endif +# ifdef ESP_ERR_WIFI_CONN + ERR_TBL_IT(ESP_ERR_WIFI_CONN), /* 12295 0x3007 WiFi internal control block of station or + soft-AP error */ +# endif +# ifdef ESP_ERR_WIFI_NVS + ERR_TBL_IT(ESP_ERR_WIFI_NVS), /* 12296 0x3008 WiFi internal NVS module error */ +# endif +# ifdef ESP_ERR_WIFI_MAC + ERR_TBL_IT(ESP_ERR_WIFI_MAC), /* 12297 0x3009 MAC address is invalid */ +# endif +# ifdef ESP_ERR_WIFI_SSID + ERR_TBL_IT(ESP_ERR_WIFI_SSID), /* 12298 0x300a SSID is invalid */ +# endif +# ifdef ESP_ERR_WIFI_PASSWORD + ERR_TBL_IT(ESP_ERR_WIFI_PASSWORD), /* 12299 0x300b Password is invalid */ +# endif +# ifdef ESP_ERR_WIFI_TIMEOUT + ERR_TBL_IT(ESP_ERR_WIFI_TIMEOUT), /* 12300 0x300c Timeout error */ +# endif +# ifdef ESP_ERR_WIFI_WAKE_FAIL + ERR_TBL_IT(ESP_ERR_WIFI_WAKE_FAIL), /* 12301 0x300d WiFi is in sleep state(RF closed) and wakeup fail */ +# endif +# ifdef ESP_ERR_WIFI_WOULD_BLOCK + ERR_TBL_IT(ESP_ERR_WIFI_WOULD_BLOCK), /* 12302 0x300e The caller would block */ +# endif +# ifdef ESP_ERR_WIFI_NOT_CONNECT + ERR_TBL_IT(ESP_ERR_WIFI_NOT_CONNECT), /* 12303 0x300f Station still in disconnect status */ +# endif + // components/esp32/include/esp_wps.h +# ifdef ESP_ERR_WIFI_REGISTRAR + ERR_TBL_IT(ESP_ERR_WIFI_REGISTRAR), /* 12339 0x3033 WPS registrar is not supported */ +# endif +# ifdef ESP_ERR_WIFI_WPS_TYPE + ERR_TBL_IT(ESP_ERR_WIFI_WPS_TYPE), /* 12340 0x3034 WPS type error */ +# endif +# ifdef ESP_ERR_WIFI_WPS_SM + ERR_TBL_IT(ESP_ERR_WIFI_WPS_SM), /* 12341 0x3035 WPS state machine is not initialized */ +# endif + // components/esp32/include/esp_now.h +# ifdef ESP_ERR_ESPNOW_NOT_INIT + ERR_TBL_IT(ESP_ERR_ESPNOW_NOT_INIT), /* 12389 0x3065 ESPNOW is not initialized. */ +# endif +# ifdef ESP_ERR_ESPNOW_BASE + ERR_TBL_IT(ESP_ERR_ESPNOW_BASE), /* 12389 0x3065 ESPNOW error number base. */ +# endif +# ifdef ESP_ERR_ESPNOW_ARG + ERR_TBL_IT(ESP_ERR_ESPNOW_ARG), /* 12390 0x3066 Invalid argument */ +# endif +# ifdef ESP_ERR_ESPNOW_NO_MEM + ERR_TBL_IT(ESP_ERR_ESPNOW_NO_MEM), /* 12391 0x3067 Out of memory */ +# endif +# ifdef ESP_ERR_ESPNOW_FULL + ERR_TBL_IT(ESP_ERR_ESPNOW_FULL), /* 12392 0x3068 ESPNOW peer list is full */ +# endif +# ifdef ESP_ERR_ESPNOW_NOT_FOUND + ERR_TBL_IT(ESP_ERR_ESPNOW_NOT_FOUND), /* 12393 0x3069 ESPNOW peer is not found */ +# endif +# ifdef ESP_ERR_ESPNOW_INTERNAL + ERR_TBL_IT(ESP_ERR_ESPNOW_INTERNAL), /* 12394 0x306a Internal error */ +# endif +# ifdef ESP_ERR_ESPNOW_EXIST + ERR_TBL_IT(ESP_ERR_ESPNOW_EXIST), /* 12395 0x306b ESPNOW peer has existed */ +# endif +# ifdef ESP_ERR_ESPNOW_IF + ERR_TBL_IT(ESP_ERR_ESPNOW_IF), /* 12396 0x306c Interface error */ +# endif + // components/tcpip_adapter/include/tcpip_adapter.h +# ifdef ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS), /* 20480 0x5000 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_BASE + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_BASE), /* 20480 0x5000 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY), /* 20481 0x5001 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCPC_START_FAILED), /* 20482 0x5002 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED), /* 20483 0x5003 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED), /* 20484 0x5004 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_NO_MEM + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_NO_MEM), /* 20485 0x5005 */ +# endif +# ifdef ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED + ERR_TBL_IT(ESP_ERR_TCPIP_ADAPTER_DHCP_NOT_STOPPED), /* 20486 0x5006 */ +# endif + // components/lwip/apps/ping/esp_ping.h +# ifdef ESP_ERR_PING_INVALID_PARAMS + ERR_TBL_IT(ESP_ERR_PING_INVALID_PARAMS), /* 24576 0x6000 */ +# endif +# ifdef ESP_ERR_PING_BASE + ERR_TBL_IT(ESP_ERR_PING_BASE), /* 24576 0x6000 */ +# endif +# ifdef ESP_ERR_PING_NO_MEM + ERR_TBL_IT(ESP_ERR_PING_NO_MEM), /* 24577 0x6001 */ +# endif + // components/spi_flash/include/esp_spi_flash.h +# ifdef ESP_ERR_FLASH_BASE + ERR_TBL_IT(ESP_ERR_FLASH_BASE), /* 65552 0x10010 */ +# endif +# ifdef ESP_ERR_FLASH_OP_FAIL + ERR_TBL_IT(ESP_ERR_FLASH_OP_FAIL), /* 65553 0x10011 */ +# endif +# ifdef ESP_ERR_FLASH_OP_TIMEOUT + ERR_TBL_IT(ESP_ERR_FLASH_OP_TIMEOUT), /* 65554 0x10012 */ +# endif +}; + +static const char esp_unknown_msg[] = "UNKNOWN ERROR"; + +const char *esp_err_to_name(esp_err_t code) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + return esp_err_msg_table[i].msg; + } + } + + return esp_unknown_msg; +} + +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + strlcpy(buf, esp_err_msg_table[i].msg, buflen); + return buf; + } + } + + if (strerror_r(code, buf, buflen) == 0) { + return buf; + } + + snprintf(buf, buflen, "Unknown error %d", code); + + return buf; +} diff --git a/components/esp32/esp_err_to_name.c.in b/components/esp32/esp_err_to_name.c.in new file mode 100644 index 000000000..86085bb88 --- /dev/null +++ b/components/esp32/esp_err_to_name.c.in @@ -0,0 +1,53 @@ +@COMMENT@ + +#include +#if __has_include("soc/soc.h") +#include "soc/soc.h" +#endif +@HEADERS@ + +#define ERR_TBL_IT(err) {err, #err} + +typedef struct { + esp_err_t code; + const char *msg; +} esp_err_msg_t; + +static const esp_err_msg_t esp_err_msg_table[] = { +@ERROR_ITEMS@ +}; + +static const char esp_unknown_msg[] = "UNKNOWN ERROR"; + +const char *esp_err_to_name(esp_err_t code) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + return esp_err_msg_table[i].msg; + } + } + + return esp_unknown_msg; +} + +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen) +{ + int i; + + for (i = 0; i < sizeof(esp_err_msg_table)/sizeof(esp_err_msg_table[0]); ++i) { + if (esp_err_msg_table[i].code == code) { + strlcpy(buf, esp_err_msg_table[i].msg, buflen); + return buf; + } + } + + if (strerror_r(code, buf, buflen) == 0) { + return buf; + } + + snprintf(buf, buflen, "Unknown error %d", code); + + return buf; +} diff --git a/components/esp32/include/esp_err.h b/components/esp32/include/esp_err.h index 5486b1410..8bed65cd3 100644 --- a/components/esp32/include/esp_err.h +++ b/components/esp32/include/esp_err.h @@ -42,6 +42,39 @@ typedef int32_t esp_err_t; #define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */ +/** + * @brief Returns string for esp_err_t error codes + * + * This function finds the error code in a pre-generated lookup-table and + * returns its string representation. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @return string error message + */ +const char *esp_err_to_name(esp_err_t code); + +/** + * @brief Returns string for esp_err_t and system error codes + * + * This function finds the error code in a pre-generated lookup-table of + * esp_err_t errors and returns its string representation. If the error code + * is not found then it is attempted to be found among system errors. + * + * The function is generated by the Python script + * tools/gen_esp_err_to_name.py which should be run each time an esp_err_t + * error is modified, created or removed from the IDF project. + * + * @param code esp_err_t error code + * @param[out] buf buffer where the error message should be written + * @param buflen Size of buffer buf. At most buflen bytes are written into the buf buffer (including the terminating null byte). + * @return buf containing the string error message + */ +const char *esp_err_to_name_r(esp_err_t code, char *buf, size_t buflen); + void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression) __attribute__((noreturn)); #ifndef __ASSERT_FUNC diff --git a/tools/gen_esp_err_to_name.py b/tools/gen_esp_err_to_name.py new file mode 100755 index 000000000..1dfe15bab --- /dev/null +++ b/tools/gen_esp_err_to_name.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python +# +# Copyright 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. + +import os +import argparse +import mmap +import re +import fnmatch +import string +import collections +import textwrap + +# list files here which should not be parsed +ignore_files = [ 'components/mdns/test_afl_fuzz_host/esp32_compat.h' ] + +# macros from here have higher priorities in case of collisions +priority_headers = [ 'components/esp32/include/esp_err.h' ] + +err_dict = collections.defaultdict(list) #identified errors are stored here; mapped by the error code +rev_err_dict = dict() #map of error string to error code +unproc_list = list() #errors with unknown codes which depend on other errors + +class ErrItem: + """ + Contains information about the error: + - name - error string + - file - relative path inside the IDF project to the file which defines this error + - comment - (optional) comment for the error + - rel_str - (optional) error string which is a base for the error + - rel_off - (optional) offset in relation to the base error + """ + def __init__(self, name, file, comment, rel_str = "", rel_off = 0): + self.name = name + self.file = file + self.comment = comment + self.rel_str = rel_str + self.rel_off = rel_off + def __str__(self): + ret = self.name + " from " + self.file + if (self.rel_str != ""): + ret += " is (" + self.rel_str + " + " + str(self.rel_off) + ")" + if self.comment != "": + ret += " // " + self.comment + return ret + def __cmp__(self, other): + if self.file in priority_headers and other.file not in priority_headers: + return -1 + elif self.file not in priority_headers and other.file in priority_headers: + return 1 + + base = "_BASE" + + if self.file == other.file: + if self.name.endswith(base) and not(other.name.endswith(base)): + return 1 + elif not(self.name.endswith(base)) and other.name.endswith(base): + return -1 + + self_key = self.file + self.name + other_key = other.file + other.name + if self_key < other_key: + return -1 + elif self_key > other_key: + return 1 + else: + return 0 + +class InputError(RuntimeError): + """ + Represents and error on the input + """ + def __init__(self, p, e): + super(InputError, self).__init__(p + ": " + e) + +def process(line, idf_path): + """ + Process a line of text from file idf_path (relative to IDF project). + Fills the global list unproc_list and dictionaries err_dict, rev_err_dict + """ + if idf_path.endswith(".c"): + # We would not try to include a C file + raise InputError(idf_path, "This line should be in a header file: %s" % line) + + words = re.split(r' +', line, 2) + # words[1] is the error name + # words[2] is the rest of the line (value, base + value, comment) + if len(words) < 2: + raise InputError(idf_path, "Error at line %s" % line) + + line = "" + todo_str = words[2] + + comment = "" + # identify possible comment + m = re.search(r'/\*!<(.+?(?=\*/))', todo_str) + if m: + comment = string.strip(m.group(1)) + todo_str = string.strip(todo_str[:m.start()]) # keep just the part before the comment + + # identify possible parentheses () + m = re.search(r'\((.+)\)', todo_str) + if m: + todo_str = m.group(1) #keep what is inside the parentheses + + # identify BASE error code, e.g. from the form BASE + 0x01 + m = re.search(r'\s*(\w+)\s*\+(.+)', todo_str) + if m: + related = m.group(1) # BASE + todo_str = m.group(2) # keep and process only what is after "BASE +" + + # try to match a hexadecimal number + m = re.search(r'0x([0-9A-Fa-f]+)', todo_str) + if m: + num = int(m.group(1), 16) + else: + # Try to match a decimal number. Negative value is possible for some numbers, e.g. ESP_FAIL + m = re.search(r'(-?[0-9]+)', todo_str) + if m: + num = int(m.group(1), 10) + elif re.match(r'\w+', todo_str): + # It is possible that there is no number, e.g. #define ERROR BASE + related = todo_str # BASE error + num = 0 # (BASE + 0) + else: + raise InputError(idf_path, "Cannot parse line %s" % line) + + try: + related + except NameError: + # The value of the error is known at this moment because it do not depends on some other BASE error code + err_dict[num].append(ErrItem(words[1], idf_path, comment)) + rev_err_dict[words[1]] = num + else: + # Store the information available now and compute the error code later + unproc_list.append(ErrItem(words[1], idf_path, comment, related, num)) + +def process_remaining_errors(): + """ + Create errors which could not be processed before because the error code + for the BASE error code wasn't known. + This works for sure only if there is no multiple-time dependency, e.g.: + #define BASE1 0 + #define BASE2 (BASE1 + 10) + #define ERROR (BASE2 + 10) - ERROR will be processed successfully only if it processed later than BASE2 + """ + for item in unproc_list: + if item.rel_str in rev_err_dict: + base_num = rev_err_dict[item.rel_str] + base = err_dict[base_num][0] + num = base_num + item.rel_off + err_dict[num].append(ErrItem(item.name, item.file, item.comment)) + rev_err_dict[item.name] = num + else: + print(item.rel_str + " referenced by " + item.name + " in " + item.file + " is unknown") + + del unproc_list[:] + +def path_to_include(path): + """ + Process the path (relative to the IDF project) in a form which can be used + to include in a C file. Using just the filename does not work all the + time because some files are deeper in the tree. This approach tries to + find an 'include' parent directory an include its subdirectories, e.g. + "components/XY/include/esp32/file.h" will be transported into "esp32/file.h" + So this solution works only works when the subdirectory or subdirectories + are inside the "include" directory. Other special cases need to be handled + here when the compiler gives an unknown header file error message. + """ + spl_path = string.split(path, os.sep) + try: + i = spl_path.index('include') + except ValueError: + # no include in the path -> use just the filename + return os.path.basename(path) + else: + return str(os.sep).join(spl_path[i+1:]) # subdirectories and filename in "include" + +def print_warning(error_list, error_code): + """ + Print warning about errors with the same error code + """ + print("[WARNING] The following errors have the same code (%d):" % error_code) + for e in error_list: + print(" " + str(e)) + +def max_string_width(): + max = 0 + for k in err_dict.keys(): + for e in err_dict[k]: + x = len(e.name) + if x > max: + max = x + return max + +def generate_output(fin, fout): + """ + Writes the output to fout based on th error dictionary err_dict and + template file fin. + """ + # make includes unique by using a set + includes = set() + for k in err_dict.keys(): + for e in err_dict[k]: + includes.add(path_to_include(e.file)) + + # The order in a set in non-deterministic therefore it could happen that the + # include order will be different in other machines and false difference + # in the output file could be reported. In order to avoid this, the items + # are sorted in a list. + include_list = list(includes) + include_list.sort() + + max_width = max_string_width() + 17 + 1 # length of " ERR_TBL_IT()," with spaces is 17 + max_decdig = max(len(str(k)) for k in err_dict.keys()) + + for line in fin: + if re.match(r'@COMMENT@', line): + fout.write("//Do not edit this file because it is autogenerated by " + os.path.basename(__file__) + "\n") + + elif re.match(r'@HEADERS@', line): + for i in include_list: + fout.write("#if __has_include(\"" + i + "\")\n#include \"" + i + "\"\n#endif\n") + elif re.match(r'@ERROR_ITEMS@', line): + last_file = "" + for k in sorted(err_dict.keys()): + if len(err_dict[k]) > 1: + err_dict[k].sort() + print_warning(err_dict[k], k) + for e in err_dict[k]: + if e.file != last_file: + last_file = e.file + fout.write(" // %s\n" % last_file) + table_line = (" ERR_TBL_IT(" + e.name + "), ").ljust(max_width) + "/* " + str(k).rjust(max_decdig) + fout.write("# ifdef %s\n" % e.name) + fout.write(table_line) + hexnum_length = 0 + if k > 0: # negative number and zero should be only ESP_FAIL and ESP_OK + hexnum = " 0x%x" % k + hexnum_length = len(hexnum) + fout.write(hexnum) + if e.comment != "": + if len(e.comment) < 50: + fout.write(" %s" % e.comment) + else: + indent = " " * (len(table_line) + hexnum_length + 1) + w = textwrap.wrap(e.comment, width=120, initial_indent = indent, subsequent_indent = indent) + # this couldn't be done with initial_indent because there is no initial_width option + fout.write(" %s" % w[0].strip()) + for i in range(1, len(w)): + fout.write("\n%s" % w[i]) + fout.write(" */\n# endif\n") + else: + fout.write(line) + +def main(): + parser = argparse.ArgumentParser(description='ESP32 esp_err_to_name lookup generator for esp_err_t') + parser.add_argument('input', help='Path to the esp_err_to_name.c.in template input.', default=os.environ['IDF_PATH'] + '/components/esp32/esp_err_to_name.c.in', nargs='?') + parser.add_argument('output', help='Path to the esp_err_to_name.c output.', default=os.environ['IDF_PATH'] + '/components/esp32/esp_err_to_name.c', nargs='?') + args = parser.parse_args() + + for root, dirnames, filenames in os.walk(os.environ['IDF_PATH']): + for filename in fnmatch.filter(filenames, '*.[ch]'): + full_path = os.path.join(root, filename) + idf_path = os.path.relpath(full_path, os.environ['IDF_PATH']) + if idf_path in ignore_files: + continue + with open(full_path, "r+b") as f: + try: + map = mmap.mmap(f.fileno(), 0, prot=mmap.ACCESS_READ) + except ValueError: + pass # An empty file cannot be mmaped + else: + for line in iter(map.readline, ""): + # match also ESP_OK and ESP_FAIL because some of ESP_ERRs are referencing them + if re.match(r"\s*#define\s+(ESP_ERR_|ESP_OK|ESP_FAIL)", line): + try: + process(str.strip(line), idf_path) + except InputError as e: + print (e) + + process_remaining_errors() + + with open(args.input, 'r') as fin, open(args.output, 'w') as fout: + generate_output(fin, fout) + +if __name__ == "__main__": + main() From 0bde61e3ca5ddd64a1094ee7e4e57b2430fc5e4d Mon Sep 17 00:00:00 2001 From: STB3 Date: Thu, 15 Feb 2018 21:13:01 +0100 Subject: [PATCH 08/19] Update eclipse-setup.rst Chapter Flash from Eclipse: Changed "Select Make Targets -> ..." to "Select Build Targets -> ..." to match the Eclipse wording. Same with "Project -> Make Target" replace Make by build to match the Eclipse wording. --- docs/get-started/eclipse-setup.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/get-started/eclipse-setup.rst b/docs/get-started/eclipse-setup.rst index b0781e3d0..67d3094ae 100644 --- a/docs/get-started/eclipse-setup.rst +++ b/docs/get-started/eclipse-setup.rst @@ -86,11 +86,11 @@ You can integrate the "make flash" target into your Eclipse project to flash usi * Right-click your project in Project Explorer (important to make sure you select the project, not a directory in the project, or Eclipse may find the wrong Makefile.) -* Select Make Targets -> Create from the context menu. +* Select Build Targets -> Create... from the context menu. * Type "flash" as the target name. Leave the other options as their defaults. -* Now you can use Project -> Make Target -> Build (Shift+F9) to build the custom flash target, which will compile and flash the project. +* Now you can use Project -> Build Target -> Build (Shift+F9) to build the custom flash target, which will compile and flash the project. Note that you will need to use "make menuconfig" to set the serial port and other config options for flashing. "make menuconfig" still requires a command line terminal (see the instructions for your platform.) From dcc466a6737fae9ab769a488b4a704e6f6d8b303 Mon Sep 17 00:00:00 2001 From: h3ndrik Date: Wed, 7 Feb 2018 14:14:41 +0100 Subject: [PATCH 09/19] i2s: fix type mismatch of intr_alloc_flags Merges https://github.com/espressif/esp-idf/pull/1589 --- components/driver/i2s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index b6d01c19c..9d1590f1a 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -185,7 +185,7 @@ esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num) return ESP_OK; } -static esp_err_t i2s_isr_register(i2s_port_t i2s_num, uint8_t intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) +static esp_err_t i2s_isr_register(i2s_port_t i2s_num, int intr_alloc_flags, void (*fn)(void*), void * arg, i2s_isr_handle_t *handle) { return esp_intr_alloc(ETS_I2S0_INTR_SOURCE + i2s_num, intr_alloc_flags, fn, arg, handle); } From a76d5a33c9e8fdee9965a4eae80d23e9ff66307c Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Tue, 9 Jan 2018 13:00:54 -0800 Subject: [PATCH 10/19] heap: Correct the sense of a comment --- components/heap/multi_heap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/heap/multi_heap.c b/components/heap/multi_heap.c index 36bff005d..4cd9964b0 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -284,7 +284,7 @@ size_t multi_heap_get_allocated_size_impl(multi_heap_handle_t heap, void *p) heap_block_t *pb = get_block(p); assert_valid_block(heap, pb); - MULTI_HEAP_ASSERT(!is_free(pb), pb); // block should be free + MULTI_HEAP_ASSERT(!is_free(pb), pb); // block shouldn't be free return block_data_size(pb); } From c9e6ed7d60d6d2be7858cabfe8739e4e839f4f4f Mon Sep 17 00:00:00 2001 From: Kedar Sovani Date: Fri, 16 Feb 2018 15:28:25 +0530 Subject: [PATCH 11/19] idf_size: Sort output on total-size instead of filename --- tools/idf_size.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/tools/idf_size.py b/tools/idf_size.py index aa1d76759..90721bf0d 100755 --- a/tools/idf_size.py +++ b/tools/idf_size.py @@ -23,6 +23,7 @@ import argparse, sys, subprocess, re import os.path import pprint +import operator DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-" @@ -204,27 +205,30 @@ def print_detailed_sizes(sections, key, header): "& rodata", "Total") print("%24s %10s %6s %6s %10s %8s %7s" % headings) - for k in sorted(sizes.keys()): + result = {} + for k in (sizes.keys()): v = sizes[k] + result[k] = {} + result[k]["data"] = v.get(".dram0.data", 0) + result[k]["bss"] = v.get(".dram0.bss", 0) + result[k]["iram"] = sum(t for (s,t) in v.items() if s.startswith(".iram0")) + result[k]["flash_text"] = v.get(".flash.text", 0) + result[k]["flash_rodata"] = v.get(".flash.rodata", 0) + result[k]["total"] = sum(result[k].values()) + + def return_total_size(elem): + val = elem[1] + return val["total"] + for k,v in sorted(result.items(), key=return_total_size, reverse=True): if ":" in k: # print subheadings for key of format archive:file sh,k = k.split(":") - if sh != sub_heading: - print(sh) - sub_heading = sh - - data = v.get(".dram0.data", 0) - bss = v.get(".dram0.bss", 0) - iram = sum(t for (s,t) in v.items() if s.startswith(".iram0")) - flash_text = v.get(".flash.text", 0) - flash_rodata = v.get(".flash.rodata", 0) - total = data + bss + iram + flash_text + flash_rodata print("%24s %10d %6d %6d %10d %8d %7d" % (k[:24], - data, - bss, - iram, - flash_text, - flash_rodata, - total)) + v["data"], + v["bss"], + v["iram"], + v["flash_text"], + v["flash_rodata"], + v["total"])) if __name__ == "__main__": main() From bc2879a956039963e54ee5f3bbbc529c53bc5e20 Mon Sep 17 00:00:00 2001 From: Stephen Casner Date: Wed, 10 Jan 2018 01:14:47 -0800 Subject: [PATCH 12/19] heap: Add task tracking option for heap usage monitoring Add back a feature that was available in the old heap implementation in release/v2.1 and earlier: keep track of which task allocates each block from the heap. The task handle is conditionally added as another word in the heap poisoning header under this configuration option CONFIG_HEAP_TASK_TRACKING. To allow custom monitoring and debugging code to be added, add helper functions in multi_heap.c and multi_heap_poisoning.c to provide access to information in the block headers. Add esp_heap_debug_dump_totals() to monitor heap usage esp_heap_debug_dump_totals() dumps into a user-provided data structure a summary of the amound of heap memory in region type that is used by each task. Optionally it will also dump into another data structure the metadata about each allocated block for a given list of tasks or for all tasks (limited by available space). Address change requests on PR #1498 This set of changes fixes the files in e3b702c to just add the CONFIG_HEAP_TASK_TRACKING option without adding the new function heap_caps_get_per_task_info() in case that is the only portion of the PR that will be accepted. Part of the change is to remove the new .c and .h files containing that function and to remove the line to compile it from components/heap/component.mk since it should not have been included in e3b702c. One or more additional commits to add the new function will follow. The other changes here: - uint32_t get_all_caps() moves to heap_private.h - replace "void* foo" with "void *foo" - add braces around single-line "if" blocks - replace tab characters with spaces Address change requests on PR #1498, part 2 This set of changes fixes the files in cdf32aa to add the new function heap_caps_get_per_task_info() with its new name and to add the line to compile it in components/heap/component.mk. This does not address all the suggested changes because there are some needing further discussion. This commit does not include the suggested change to move the declaration of the new function into esp_heap_caps.h because the new function references TaskHandle_t so esp_heap_caps.h would have to include freertos/FreeRTOS.h and freertos/task.h, but FreeRTOS.h includes esp_heap_caps.h through two other header files which results in compilation errors because not all of FreeRTOS.h has been read yet. Change heap_caps_get_per_task_info() to take struct of params In addition to moving the large number of function parameters into a struct as the single parameter, the following changes were made: - Clear out the totals for any prepopulated tasks so the app code doesn't have to do it. - Rather than partitioning the per-task totals into a predetermined set of heap capabilities, take a list of pairs to compare the caps to the heap capabilities as masked. This lets the caller configure the desired partitioning, or none. - Allow the totals array pointer or the blocks array pointer to be NULL to indicate not to collect that part of the information. - In addition to returning the total space allocated by each task, return the number of blocks allocated by each task. - Don't need to return the heap capabilities as part of the details for each block since the heap region (and therefore its capabilities) can be determined from the block address. - Renamed heap_task_info.h to esp_heap_task_info.h to fit the naming convention, and renamed the structs for totals and block details to better fit the revised function name. - Provide full Doxygen commenting for the function and parameter structs. Add copyright header to new files Merges https://github.com/espressif/esp-idf/pull/1498 --- components/heap/Kconfig | 9 ++ components/heap/component.mk | 4 + components/heap/heap_caps.c | 13 -- components/heap/heap_private.h | 12 ++ components/heap/heap_task_info.c | 129 +++++++++++++++++++ components/heap/include/esp_heap_task_info.h | 98 ++++++++++++++ components/heap/multi_heap.c | 34 +++++ components/heap/multi_heap_internal.h | 21 +++ components/heap/multi_heap_platform.h | 15 +++ components/heap/multi_heap_poisoning.c | 13 ++ 10 files changed, 335 insertions(+), 13 deletions(-) create mode 100644 components/heap/heap_task_info.c create mode 100644 components/heap/include/esp_heap_task_info.h diff --git a/components/heap/Kconfig b/components/heap/Kconfig index 8a8d1325f..8745561ed 100644 --- a/components/heap/Kconfig +++ b/components/heap/Kconfig @@ -37,4 +37,13 @@ config HEAP_TRACING_STACK_DEPTH More stack frames uses more memory in the heap trace buffer (and slows down allocation), but can provide useful information. +config HEAP_TASK_TRACKING + bool "Enable heap task tracking" + depends on !HEAP_POISONING_DISABLED + help + Enables tracking the task responsible for each heap allocation. + + This function depends on heap poisoning being enabled and adds four more bytes of overhead for each block + allocated. + endmenu diff --git a/components/heap/component.mk b/components/heap/component.mk index b5e61aa72..8c57271d4 100644 --- a/components/heap/component.mk +++ b/components/heap/component.mk @@ -6,6 +6,10 @@ COMPONENT_OBJS := heap_caps_init.o heap_caps.o multi_heap.o heap_trace.o ifndef CONFIG_HEAP_POISONING_DISABLED COMPONENT_OBJS += multi_heap_poisoning.o + +ifdef CONFIG_HEAP_TASK_TRACKING +COMPONENT_OBJS += heap_task_info.o +endif endif ifdef CONFIG_HEAP_TRACING diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 31cfa8d55..ad971c176 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -55,19 +55,6 @@ IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len) return (void *)(iptr + 1); } -/* return all possible capabilities (across all priorities) for a given heap */ -inline static uint32_t get_all_caps(const heap_t *heap) -{ - if (heap->heap == NULL) { - return 0; - } - uint32_t all_caps = 0; - for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { - all_caps |= heap->caps[prio]; - } - return all_caps; -} - bool heap_caps_match(const heap_t *heap, uint32_t caps) { return heap->heap != NULL && ((get_all_caps(heap) & caps) == caps); diff --git a/components/heap/heap_private.h b/components/heap/heap_private.h index 47d8cc55f..5103cfd17 100644 --- a/components/heap/heap_private.h +++ b/components/heap/heap_private.h @@ -48,6 +48,18 @@ extern SLIST_HEAD(registered_heap_ll, heap_t_) registered_heaps; bool heap_caps_match(const heap_t *heap, uint32_t caps); +/* return all possible capabilities (across all priorities) for a given heap */ +inline static uint32_t get_all_caps(const heap_t *heap) +{ + if (heap->heap == NULL) { + return 0; + } + uint32_t all_caps = 0; + for (int prio = 0; prio < SOC_MEMORY_TYPE_NO_PRIOS; prio++) { + all_caps |= heap->caps[prio]; + } + return all_caps; +} /* Because we don't want to add _another_ known allocation method to the stack of functions to trace wrt memory tracing, diff --git a/components/heap/heap_task_info.c b/components/heap/heap_task_info.c new file mode 100644 index 000000000..5914e6646 --- /dev/null +++ b/components/heap/heap_task_info.c @@ -0,0 +1,129 @@ +// Copyright 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. + +#include +#include +#include +#include "multi_heap_internal.h" +#include "heap_private.h" +#include "esp_heap_task_info.h" + +#ifdef CONFIG_HEAP_TASK_TRACKING + +/* + * Return per-task heap allocation totals and lists of blocks. + * + * For each task that has allocated memory from the heap, return totals for + * allocations within regions matching one or more sets of capabilities. + * + * Optionally also return an array of structs providing details about each + * block allocated by one or more requested tasks, or by all tasks. + * + * Returns the number of block detail structs returned. + */ +size_t heap_caps_get_per_task_info(heap_task_info_params_t *params) +{ + heap_t *reg; + heap_task_block_t *blocks = params->blocks; + size_t count = *params->num_totals; + size_t remaining = params->max_blocks; + + // Clear out totals for any prepopulated tasks. + if (params->totals) { + for (size_t i = 0; i < count; ++i) { + for (size_t type = 0; type < NUM_HEAP_TASK_CAPS; ++type) { + params->totals[i].size[type] = 0; + params->totals[i].count[type] = 0; + } + } + } + + SLIST_FOREACH(reg, ®istered_heaps, next) { + multi_heap_handle_t heap = reg->heap; + if (heap == NULL) { + continue; + } + + // Find if the capabilities of this heap region match on of the desired + // sets of capabilities. + uint32_t caps = get_all_caps(reg); + uint32_t type; + for (type = 0; type < NUM_HEAP_TASK_CAPS; ++type) { + if ((caps & params->mask[type]) == params->caps[type]) { + break; + } + } + if (type == NUM_HEAP_TASK_CAPS) { + continue; + } + + multi_heap_block_handle_t b = multi_heap_get_first_block(heap); + multi_heap_internal_lock(heap); + for ( ; b ; b = multi_heap_get_next_block(heap, b)) { + if (multi_heap_is_free(b)) { + continue; + } + void *p = multi_heap_get_block_address(b); // Safe, only arithmetic + size_t bsize = multi_heap_get_allocated_size(heap, p); // Validates + TaskHandle_t btask = (TaskHandle_t)multi_heap_get_block_owner(b); + + // Accumulate per-task allocation totals. + if (params->totals) { + size_t i; + for (i = 0; i < count; ++i) { + if (params->totals[i].task == btask) { + break; + } + } + if (i < count) { + params->totals[i].size[type] += bsize; + params->totals[i].count[type] += 1; + } + else { + if (count < params->max_totals) { + params->totals[count].task = btask; + params->totals[count].size[type] = bsize; + params->totals[i].count[type] = 1; + ++count; + } + } + } + + // Return details about allocated blocks for selected tasks. + if (blocks && remaining > 0) { + if (params->tasks) { + size_t i; + for (i = 0; i < params->num_tasks; ++i) { + if (btask == params->tasks[i]) { + break; + } + } + if (i == params->num_tasks) { + continue; + } + } + blocks->task = btask; + blocks->address = p; + blocks->size = bsize; + ++blocks; + --remaining; + } + } + multi_heap_internal_unlock(heap); + } + *params->num_totals = count; + return params->max_blocks - remaining; +} + +#endif // CONFIG_HEAP_TASK_TRACKING diff --git a/components/heap/include/esp_heap_task_info.h b/components/heap/include/esp_heap_task_info.h new file mode 100644 index 000000000..fca9a43ba --- /dev/null +++ b/components/heap/include/esp_heap_task_info.h @@ -0,0 +1,98 @@ +// Copyright 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. +#pragma once + +#ifdef CONFIG_HEAP_TASK_TRACKING + +#ifdef __cplusplus +extern "C" { +#endif + +// This macro controls how much space is provided for partitioning the per-task +// heap allocation info according to one or more sets of heap capabilities. +#define NUM_HEAP_TASK_CAPS 4 + +/** @brief Structure to collect per-task heap allocation totals partitioned by selected caps */ +typedef struct { + TaskHandle_t task; ///< Task to which these totals belong + size_t size[NUM_HEAP_TASK_CAPS]; ///< Total allocations partitioned by selected caps + size_t count[NUM_HEAP_TASK_CAPS]; ///< Number of blocks partitioned by selected caps +} heap_task_totals_t; + +/** @brief Structure providing details about a block allocated by a task */ +typedef struct { + TaskHandle_t task; ///< Task that allocated the block + void *address; ///< User address of allocated block + uint32_t size; ///< Size of the allocated block +} heap_task_block_t; + +/** @brief Structure to provide parameters to heap_caps_get_per_task_info + * + * The 'caps' and 'mask' arrays allow partitioning the per-task heap allocation + * totals by selected sets of heap region capabilities so that totals for + * multiple regions can be accumulated in one scan. The capabilities flags for + * each region ANDed with mask[i] are compared to caps[i] in order; the + * allocations in that region are added to totals->size[i] and totals->count[i] + * for the first i that matches. To collect the totals without any + * partitioning, set mask[0] and caps[0] both to zero. The allocation totals + * are returned in the 'totals' array of heap_task_totals_t structs. To allow + * easily comparing the totals array between consecutive calls, that array can + * be left populated from one call to the next so the order of tasks is the + * same even if some tasks have freed their blocks or have been deleted. The + * number of blocks prepopulated is given by num_totals, which is updated upon + * return. If there are more tasks with allocations than the capacity of the + * totals array (given by max_totals), information for the excess tasks will be + * not be collected. The totals array pointer can be NULL if the totals are + * not desired. + * + * The 'tasks' array holds a list of handles for tasks whose block details are + * to be returned in the 'blocks' array of heap_task_block_t structs. If the + * tasks array pointer is NULL, block details for all tasks will be returned up + * to the capacity of the buffer array, given by max_blocks. The function + * return value tells the number of blocks filled into the array. The blocks + * array pointer can be NULL if block details are not desired, or max_blocks + * can be set to zero. + */ +typedef struct { + int32_t caps[NUM_HEAP_TASK_CAPS]; ///< Array of caps for partitioning task totals + int32_t mask[NUM_HEAP_TASK_CAPS]; ///< Array of masks under which caps must match + TaskHandle_t *tasks; ///< Array of tasks whose block info is returned + size_t num_tasks; ///< Length of tasks array + heap_task_totals_t *totals; ///< Array of structs to collect task totals + size_t *num_totals; ///< Number of task structs currently in array + size_t max_totals; ///< Capacity of array of task totals structs + heap_task_block_t *blocks; ///< Array of task block details structs + size_t max_blocks; ///< Capacity of array of task block info structs +} heap_task_info_params_t; + +/** + * @brief Return per-task heap allocation totals and lists of blocks. + * + * For each task that has allocated memory from the heap, return totals for + * allocations within regions matching one or more sets of capabilities. + * + * Optionally also return an array of structs providing details about each + * block allocated by one or more requested tasks, or by all tasks. + * + * @param params Structure to hold all the parameters for the function + * (@see heap_task_info_params_t). + * @return Number of block detail structs returned (@see heap_task_block_t). + */ +extern size_t heap_caps_get_per_task_info(heap_task_info_params_t *params); + +#ifdef __cplusplus +} +#endif + +#endif // CONFIG_HEAP_TASK_TRACKING diff --git a/components/heap/multi_heap.c b/components/heap/multi_heap.c index 4cd9964b0..77dd9d82c 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -54,6 +54,14 @@ size_t multi_heap_free_size(multi_heap_handle_t heap) size_t multi_heap_minimum_free_size(multi_heap_handle_t heap) __attribute__((alias("multi_heap_minimum_free_size_impl"))); +void *multi_heap_get_block_address(multi_heap_block_handle_t block) + __attribute__((alias("multi_heap_get_block_address_impl"))); + +void *multi_heap_get_block_owner(multi_heap_block_handle_t block) +{ + return NULL; +} + #endif #define ALIGN(X) ((X) & ~(sizeof(void *)-1)) @@ -279,6 +287,11 @@ static void split_if_necessary(heap_t *heap, heap_block_t *block, size_t size, h heap->free_bytes += block_data_size(new_block); } +void *multi_heap_get_block_address_impl(multi_heap_block_handle_t block) +{ + return ((char *)block + offsetof(heap_block_t, data)); +} + size_t multi_heap_get_allocated_size_impl(multi_heap_handle_t heap, void *p) { heap_block_t *pb = get_block(p); @@ -339,6 +352,27 @@ void inline multi_heap_internal_unlock(multi_heap_handle_t heap) MULTI_HEAP_UNLOCK(heap->lock); } +multi_heap_block_handle_t multi_heap_get_first_block(multi_heap_handle_t heap) +{ + return &heap->first_block; +} + +multi_heap_block_handle_t multi_heap_get_next_block(multi_heap_handle_t heap, multi_heap_block_handle_t block) +{ + heap_block_t *next = get_next_block(block); + /* check for valid free last block to avoid assert in assert_valid_block */ + if (next == heap->last_block && is_last_block(next) && is_free(next)) { + return NULL; + } + assert_valid_block(heap, next); + return next; +} + +bool multi_heap_is_free(multi_heap_block_handle_t block) +{ + return is_free(block); +} + void *multi_heap_malloc_impl(multi_heap_handle_t heap, size_t size) { heap_block_t *best_block = NULL; diff --git a/components/heap/multi_heap_internal.h b/components/heap/multi_heap_internal.h index e9aa38cee..a69a05259 100644 --- a/components/heap/multi_heap_internal.h +++ b/components/heap/multi_heap_internal.h @@ -13,6 +13,9 @@ // limitations under the License. #pragma once +/* Opaque handle to a heap block */ +typedef const struct heap_block *multi_heap_block_handle_t; + /* Internal definitions for the "implementation" of the multi_heap API, as defined in multi_heap.c. @@ -28,6 +31,7 @@ void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info) size_t multi_heap_free_size_impl(multi_heap_handle_t heap); size_t multi_heap_minimum_free_size_impl(multi_heap_handle_t heap); size_t multi_heap_get_allocated_size_impl(multi_heap_handle_t heap, void *p); +void *multi_heap_get_block_address_impl(multi_heap_block_handle_t block); /* Some internal functions for heap poisoning use */ @@ -45,3 +49,20 @@ void multi_heap_internal_poison_fill_region(void *start, size_t size, bool is_fr void multi_heap_internal_lock(multi_heap_handle_t heap); void multi_heap_internal_unlock(multi_heap_handle_t heap); + +/* Some internal functions for heap debugging code to use */ + +/* Get the handle to the first (fixed free) block in a heap */ +multi_heap_block_handle_t multi_heap_get_first_block(multi_heap_handle_t heap); + +/* Get the handle to the next block in a heap, with validation */ +multi_heap_block_handle_t multi_heap_get_next_block(multi_heap_handle_t heap, multi_heap_block_handle_t block); + +/* Test if a heap block is free */ +bool multi_heap_is_free(const multi_heap_block_handle_t block); + +/* Get the data address of a heap block */ +void *multi_heap_get_block_address(multi_heap_block_handle_t block); + +/* Get the owner identification for a heap block */ +void *multi_heap_get_block_owner(multi_heap_block_handle_t block); diff --git a/components/heap/multi_heap_platform.h b/components/heap/multi_heap_platform.h index 874fd535b..6a17522b4 100644 --- a/components/heap/multi_heap_platform.h +++ b/components/heap/multi_heap_platform.h @@ -63,6 +63,16 @@ inline static void multi_heap_assert(bool condition, const char *format, int lin multi_heap_assert((CONDITION), "CORRUPT HEAP: multi_heap.c:%d detected at 0x%08x\n", \ __LINE__, (intptr_t)(ADDRESS)) +#ifdef CONFIG_HEAP_TASK_TRACKING +#define MULTI_HEAP_BLOCK_OWNER TaskHandle_t task; +#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) (HEAD)->task = xTaskGetCurrentTaskHandle() +#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) ((HEAD)->task) +#else +#define MULTI_HEAP_BLOCK_OWNER +#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) +#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (NULL) +#endif + #else // ESP_PLATFORM #include @@ -73,4 +83,9 @@ inline static void multi_heap_assert(bool condition, const char *format, int lin #define MULTI_HEAP_UNLOCK(PLOCK) #define MULTI_HEAP_ASSERT(CONDITION, ADDRESS) assert((CONDITION) && "Heap corrupt") + +#define MULTI_HEAP_BLOCK_OWNER +#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) +#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (NULL) + #endif diff --git a/components/heap/multi_heap_poisoning.c b/components/heap/multi_heap_poisoning.c index a2be07079..240598222 100644 --- a/components/heap/multi_heap_poisoning.c +++ b/components/heap/multi_heap_poisoning.c @@ -47,6 +47,7 @@ typedef struct { uint32_t head_canary; + MULTI_HEAP_BLOCK_OWNER size_t alloc_size; } poison_head_t; @@ -67,6 +68,7 @@ static uint8_t *poison_allocated_region(poison_head_t *head, size_t alloc_size) poison_tail_t *tail = (poison_tail_t *)(data + alloc_size); head->alloc_size = alloc_size; head->head_canary = HEAD_CANARY_PATTERN; + MULTI_HEAP_SET_BLOCK_OWNER(head); uint32_t tail_canary = TAIL_CANARY_PATTERN; if ((intptr_t)tail % sizeof(void *) == 0) { @@ -258,6 +260,12 @@ void *multi_heap_realloc(multi_heap_handle_t heap, void *p, size_t size) return result; } +void *multi_heap_get_block_address(multi_heap_block_handle_t block) +{ + char *head = multi_heap_get_block_address_impl(block); + return head + sizeof(poison_head_t); +} + size_t multi_heap_get_allocated_size(multi_heap_handle_t heap, void *p) { poison_head_t *head = verify_allocated_region(p, true); @@ -269,6 +277,11 @@ size_t multi_heap_get_allocated_size(multi_heap_handle_t heap, void *p) return 0; } +void *multi_heap_get_block_owner(multi_heap_block_handle_t block) +{ + return MULTI_HEAP_GET_BLOCK_OWNER((poison_head_t*)multi_heap_get_block_address_impl(block)); +} + multi_heap_handle_t multi_heap_register(void *start, size_t size) { if (start != NULL) { From f0ebf613f42af2275f8e8bf21f8819311410fb9c Mon Sep 17 00:00:00 2001 From: Jitin George Date: Thu, 8 Feb 2018 14:06:14 +0530 Subject: [PATCH 13/19] OpenSSL API addition --- .../openssl/include/internal/ssl_types.h | 11 +- .../openssl/include/internal/ssl_x509.h | 67 +++++++++++ components/openssl/library/ssl_x509.c | 112 ++++++++++++++++++ 3 files changed, 189 insertions(+), 1 deletion(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index b08c4d0e2..21ba69f4c 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -29,7 +29,6 @@ typedef void X509_STORE; typedef void RSA; typedef void STACK; -typedef void BIO; #define ossl_inline inline @@ -84,6 +83,9 @@ typedef struct pkey_method_st PKEY_METHOD; struct ssl_alpn_st; typedef struct ssl_alpn_st SSL_ALPN; +struct bio_st; +typedef struct bio_st BIO; + struct stack_st { char **data; @@ -106,6 +108,8 @@ struct x509_st { void *x509_pm; const X509_METHOD *method; + + int ref_counter; }; struct cert_st { @@ -147,6 +151,11 @@ struct X509_VERIFY_PARAM_st { }; +struct bio_st { + const unsigned char * data; + int dlen; +}; + typedef enum { ALPN_INIT, ALPN_ENABLE, ALPN_DISABLE, ALPN_ERROR } ALPN_STATUS; struct ssl_alpn_st { ALPN_STATUS alpn_status; diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 840fbf1ec..877c4fbb7 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -101,6 +101,73 @@ int SSL_add_client_CA(SSL *ssl, X509 *x); */ int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + +/** + * @brief set SSL context client CA certification + * + * @param store - pointer to X509_STORE + * @param x - pointer to X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int X509_STORE_add_cert(X509_STORE *store, X509 *x); + +/** + * @brief load data in BIO + * + * Normally BIO_write should append data but that doesn't happen here, and + * 'data' cannot be freed after the function is called, it should remain valid + * until BIO object is in use. + * + * @param b - pointer to BIO + * @param data - pointer to data + * @param dlen - data bytes + * + * @return result + * 0 : failed + * 1 : OK + */ +int BIO_write(BIO *b, const void *data, int dlen); + +/** + * @brief load a character certification context into system context. + * + * If '*cert' is pointed to the certification, then load certification + * into it, or create a new X509 certification object. + * + * @param bp - pointer to BIO + * @param buffer - pointer to the certification context memory + * @param cb - pointer to a callback which queries pass phrase used + for encrypted PEM structure + * @param u - pointer to arbitary data passed by application to callback + * + * @return X509 certification object point + */ +X509 * PEM_read_bio_X509(BIO *bp, X509 **x, void *cb, void *u); + +/** + * @brief create a BIO object + * + * @param method - pointer to BIO_METHOD + * + * @return pointer to BIO object + */ +BIO *BIO_new(void * method); + +/** + * @brief get the memory BIO method function + */ +void *BIO_s_mem(); + +/** + * @brief free a BIO object + * + * @param x - pointer to BIO object + */ +void BIO_free(BIO *b); + #ifdef __cplusplus } #endif diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 50cf2203e..0b49bb8fe 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -16,6 +16,7 @@ #include "ssl_methods.h" #include "ssl_dbg.h" #include "ssl_port.h" +#include "ssl.h" /** * @brief show X509 certification information @@ -39,6 +40,8 @@ X509* __X509_new(X509 *ix) goto no_mem; } + x->ref_counter = 1; + if (ix) x->method = ix->method; else @@ -73,6 +76,10 @@ void X509_free(X509 *x) { SSL_ASSERT3(x); + if (--x->ref_counter > 0) { + return; + } + X509_METHOD_CALL(free, x); ssl_mem_free(x); @@ -314,3 +321,108 @@ X509 *SSL_get_peer_certificate(const SSL *ssl) return ssl->session->peer; } +/** + * @brief set SSL context client CA certification + */ +int X509_STORE_add_cert(X509_STORE *store, X509 *x) { + + x->ref_counter++; + + SSL_CTX *ctx = (SSL_CTX *)store; + SSL_ASSERT1(ctx); + SSL_ASSERT1(x); + + if (ctx->client_CA == x) { + return 1; + } + + if (ctx->client_CA!=NULL) { + X509_free(ctx->client_CA); + } + + ctx->client_CA = x; + return 1; +} + +/** + * @brief create a BIO object + */ +BIO *BIO_new(void *method) { + BIO *b = (BIO *)malloc(sizeof(BIO)); + return b; +} + +/** + * @brief load data into BIO. + * + * Normally BIO_write should append data but doesn't happen here, and + * 'data' cannot be freed after the function is called, it should remain valid + * until BIO object is in use. + */ +int BIO_write(BIO *b, const void * data, int dlen) { + b->data = data; + b->dlen = dlen; + return 1; +} + +/** + * @brief load a character certification context into system context. + * + * If '*cert' is pointed to the certification, then load certification + * into it, or create a new X509 certification object. + */ +X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, void *cb, void *u) { + int m = 0; + int ret; + X509 *x; + + SSL_ASSERT2(bp->data); + SSL_ASSERT2(bp->dlen); + + if (cert && *cert) { + x = *cert; + } else { + x = X509_new(); + if (!x) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_new() return NULL"); + goto failed; + } + m = 1; + } + + ret = X509_METHOD_CALL(load, x, bp->data, bp->dlen); + if (ret) { + SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "X509_METHOD_CALL(load) return %d", ret); + goto failed; + } + + return x; + +failed: + if (m) { + X509_free(x); + } + + return NULL; +} + +/** + * @brief get the memory BIO method function + */ +void *BIO_s_mem() { + return NULL; +} + +/** + * @brief get the SSL context object X509 certification storage + */ +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { + return (X509_STORE *)ctx; +} + +/** + * @brief free a BIO object + */ +void BIO_free(BIO *b) { + free(b); +} From bd0b3a7d6bfc9965be2a9acedda593abd66b15f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Eeden?= Date: Sun, 18 Feb 2018 13:12:57 +0100 Subject: [PATCH 14/19] Fix esp_sleep_wakeup_cause_t docs. Merges https://github.com/espressif/esp-idf/pull/1634 value and description didn't match --- components/esp32/include/esp_sleep.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esp32/include/esp_sleep.h b/components/esp32/include/esp_sleep.h index 1e3f4efdc..d2c4b122f 100644 --- a/components/esp32/include/esp_sleep.h +++ b/components/esp32/include/esp_sleep.h @@ -54,12 +54,12 @@ typedef enum { * @brief Sleep wakeup cause */ typedef enum { - ESP_SLEEP_WAKEUP_UNDEFINED, //! In case of deep sleep, reset was not caused by exit from deep sleep - ESP_SLEEP_WAKEUP_EXT0, //! Wakeup caused by external signal using RTC_IO - ESP_SLEEP_WAKEUP_EXT1, //! Wakeup caused by external signal using RTC_CNTL - ESP_SLEEP_WAKEUP_TIMER, //! Wakeup caused by timer - ESP_SLEEP_WAKEUP_TOUCHPAD, //! Wakeup caused by touchpad - ESP_SLEEP_WAKEUP_ULP, //! Wakeup caused by ULP program + ESP_SLEEP_WAKEUP_UNDEFINED, //!< In case of deep sleep, reset was not caused by exit from deep sleep + ESP_SLEEP_WAKEUP_EXT0, //!< Wakeup caused by external signal using RTC_IO + ESP_SLEEP_WAKEUP_EXT1, //!< Wakeup caused by external signal using RTC_CNTL + ESP_SLEEP_WAKEUP_TIMER, //!< Wakeup caused by timer + ESP_SLEEP_WAKEUP_TOUCHPAD, //!< Wakeup caused by touchpad + ESP_SLEEP_WAKEUP_ULP, //!< Wakeup caused by ULP program } esp_sleep_wakeup_cause_t; From 4e544f82bbd70431817a6f21614fec55741d5997 Mon Sep 17 00:00:00 2001 From: Alexey Gerenkov Date: Wed, 14 Feb 2018 18:11:28 +0300 Subject: [PATCH 15/19] esp32: Fixes apptrace down buffer management --- components/app_trace/app_trace.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/components/app_trace/app_trace.c b/components/app_trace/app_trace.c index 1e792dd86..d5a56471b 100644 --- a/components/app_trace/app_trace.c +++ b/components/app_trace/app_trace.c @@ -156,6 +156,7 @@ // ALSO SEE example usage of application tracing module in 'components/app_trace/README.rst' #include +#include #include "soc/soc.h" #include "soc/dport_reg.h" #include "eri.h" @@ -583,11 +584,11 @@ static uint8_t *esp_apptrace_trax_down_buffer_get(uint32_t *size, esp_apptrace_t while (1) { uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down); if (sz != 0) { - ptr = esp_apptrace_rb_consume(&s_trace_buf.rb_down, sz > *size ? *size : sz); + *size = MIN(*size, sz); + ptr = esp_apptrace_rb_consume(&s_trace_buf.rb_down, *size); if (!ptr) { assert(false && "Failed to consume bytes from down buffer!"); } - *size = sz; break; } // may need to flush From b52b4ea2cc1280b8d134e233aaa19b28528ea5b6 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 20 Feb 2018 10:30:02 +1100 Subject: [PATCH 16/19] spi_flash: Update docs --- components/spi_flash/README.rst | 59 ++++++++------- components/spi_flash/include/esp_spi_flash.h | 75 ++++++++++++-------- 2 files changed, 79 insertions(+), 55 deletions(-) diff --git a/components/spi_flash/README.rst b/components/spi_flash/README.rst index 6de4e9281..ef4015049 100644 --- a/components/spi_flash/README.rst +++ b/components/spi_flash/README.rst @@ -18,14 +18,14 @@ SPI flash access APIs This is the set of APIs for working with data in flash: -- ``spi_flash_read`` used to read data from flash to RAM -- ``spi_flash_write`` used to write data from RAM to flash -- ``spi_flash_erase_sector`` used to erase individual sectors of flash -- ``spi_flash_erase_range`` used to erase range of addresses in flash -- ``spi_flash_get_chip_size`` returns flash chip size, in bytes, as configured in menuconfig +- :cpp:func:`spi_flash_read` used to read data from flash to RAM +- :cpp:func:`spi_flash_write` used to write data from RAM to flash +- :cpp:func:`spi_flash_erase_sector` used to erase individual sectors of flash +- :cpp:func:`spi_flash_erase_range` used to erase range of addresses in flash +- :cpp:func:`spi_flash_get_chip_size` returns flash chip size, in bytes, as configured in menuconfig Generally, try to avoid using the raw SPI flash functions in favour of -partition-specific functions. +:ref:`partition-specific functions `. SPI Flash Size -------------- @@ -35,8 +35,8 @@ image header, flashed at offset 0x1000. By default, the SPI flash size is detected by esptool.py when this bootloader is written to flash, and the header is updated with the correct -size. Alternatively, it is possible to generate a fixed flash size by disabling -detection in ``make menuconfig`` (under Serial Flasher Config). +size. Alternatively, it is possible to generate a fixed flash size by setting +:ref:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``. If it is necessary to override the configured flash size at runtime, is is possible to set the ``chip_size`` member of ``g_rom_flashchip`` structure. This @@ -47,10 +47,14 @@ Concurrency Constraints ----------------------- Because the SPI flash is also used for firmware execution (via the instruction & -data caches), these caches much be disabled while reading/writing/erasing. This +data caches), these caches must be disabled while reading/writing/erasing. This means that both CPUs must be running code from IRAM and only reading data from DRAM while flash write operations occur. +If you use the APIs documented here, then this happens automatically and +transparently. However note that it will have some performance impact on other +tasks in the system. + Refer to the :ref:`application memory layout ` documentation for an explanation of the differences between IRAM, DRAM and flash cache. @@ -99,6 +103,8 @@ handler reads from the flash cache during a flash operation, it will cause a crash due to Illegal Instruction exception (for code which should be in IRAM) or garbage data to be read (for constant data which should be in DRAM). +.. _flash-partition-apis: + Partition table APIs -------------------- @@ -109,20 +115,21 @@ More information about partition tables can be found :doc:`here Date: Fri, 16 Feb 2018 13:50:45 +0700 Subject: [PATCH 17/19] i2s: add support fixed_mclk configuration --- components/driver/i2s.c | 127 ++++++++---------- components/driver/include/driver/i2s.h | 7 +- docs/api-reference/peripherals/i2s.rst | 8 +- .../peripherals/i2s/main/i2s_example_main.c | 2 +- 4 files changed, 65 insertions(+), 79 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index b6d01c19c..88c50b578 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -49,7 +49,7 @@ static const char* I2S_TAG = "I2S"; #define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num]) #define I2S_FULL_DUPLEX_SLAVE_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_SLAVE) #define I2S_FULL_DUPLEX_MASTER_MODE_MASK (I2S_MODE_TX | I2S_MODE_RX | I2S_MODE_MASTER) -#define APLL_MIN_FREQ (350000000) +#define APLL_MIN_FREQ (250000000) #define APLL_MAX_FREQ (500000000) #define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware /** @@ -83,8 +83,9 @@ typedef struct { int bytes_per_sample; /*!< Bytes per sample*/ int bits_per_sample; /*!< Bits per sample*/ i2s_mode_t mode; /*!< I2S Working mode*/ - int use_apll; /*!< I2S use APLL clock */ uint32_t sample_rate; /*!< I2S sample rate */ + bool use_apll; /*!< I2S use APLL clock */ + int fixed_mclk; /*!< I2S fixed MLCK clock */ } i2s_obj_t; static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0}; @@ -92,20 +93,6 @@ static i2s_dev_t* I2S[I2S_NUM_MAX] = {&I2S0, &I2S1}; static portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED}; static int _i2s_adc_unit = -1; static int _i2s_adc_channel = -1; -/** - * @brief Pre define APLL parameters, save compute time - * | bits_per_sample | rate | sdm0 | sdm1 | sdm2 | odir - */ -static const int apll_predefine[][6] = { - {16, 11025, 38, 80, 5, 31}, - {16, 16000, 147, 107, 5, 21}, - {16, 22050, 130, 152, 5, 15}, - {16, 32000, 129, 212, 5, 10}, - {16, 44100, 15, 8, 5, 6}, - {16, 48000, 136, 212, 5, 6}, - {16, 96000, 143, 212, 5, 2}, - {0, 0, 0, 0, 0, 0} -}; static i2s_dma_t *i2s_create_dma_queue(i2s_port_t i2s_num, int dma_buf_count, int dma_buf_len); static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma); @@ -121,16 +108,16 @@ static esp_err_t i2s_reset_fifo(i2s_port_t i2s_num) return ESP_OK; } -inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) +inline static void gpio_matrix_out_check(uint32_t gpio, uint32_t signal_idx, bool out_inv, bool oen_inv) { //if pin = -1, do not need to configure if (gpio != -1) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); gpio_set_direction(gpio, GPIO_MODE_DEF_OUTPUT); gpio_matrix_out(gpio, signal_idx, out_inv, oen_inv); - } -} -inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv) + } +} +inline static void gpio_matrix_in_check(uint32_t gpio, uint32_t signal_idx, bool inv) { if (gpio != -1) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); @@ -191,7 +178,7 @@ static esp_err_t i2s_isr_register(i2s_port_t i2s_num, uint8_t intr_alloc_flags, } -static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) +static float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) { int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0); @@ -201,37 +188,37 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int } float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4); if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) { - return 9999999; + return APLL_MAX_FREQ; } float fpll = fout / (2 * (odir+2)); //== fi2s (N=1, b=0, a=1) - return fpll/(8*4*bits_per_sample); //fbck = fi2s/bck_div + return fpll/2; } /** * @brief APLL calculate function, was described by following: * APLL Output frequency is given by the formula: - * + * * apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) * apll_freq = fout / ((o_div + 2) * 2) - * + * * The dividend in this expression should be in the range of 240 - 600 MHz. * In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0. * * sdm0 frequency adjustment parameter, 0..255 * * sdm1 frequency adjustment parameter, 0..255 * * sdm2 frequency adjustment parameter, 0..63 * * o_div frequency divider, 0..31 - * - * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, - * then apply the above formula, finding the closest frequency to the desired one. + * + * The most accurate way to find the sdm0..2 and odir parameters is to loop through them all, + * then apply the above formula, finding the closest frequency to the desired one. * But 256*256*64*32 = 134.217.728 loops are too slow with ESP32 * 1. We will choose the parameters with the highest level of change, - * With 350MHzmode & I2S_MODE_RX) { save_rx = p_i2s_obj[i2s_num]->rx; - + p_i2s_obj[i2s_num]->rx = i2s_create_dma_queue(i2s_num, p_i2s_obj[i2s_num]->dma_buf_count, p_i2s_obj[i2s_num]->dma_buf_len); if (p_i2s_obj[i2s_num]->rx == NULL){ ESP_LOGE(I2S_TAG, "Failed to create rx dma buffer"); @@ -417,7 +393,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b i2s_destroy_dma_queue(i2s_num, save_rx); } } - + } double mclk; @@ -453,18 +429,24 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b mclk = clkmInteger + denom * clkmDecimals; bck = factor/(bits * channel); } - int sdm0, sdm1, sdm2, odir; - if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate(rate, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + int sdm0, sdm1, sdm2, odir, m_scale = 8; + int fi2s_clk = rate*channel*bits*m_scale; + if(p_i2s_obj[i2s_num]->use_apll && p_i2s_obj[i2s_num]->fixed_mclk) { + fi2s_clk = p_i2s_obj[i2s_num]->fixed_mclk; + m_scale = fi2s_clk/bits/rate/channel; + } + if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate_fi2s(fi2s_clk, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) { + ESP_LOGD(I2S_TAG, "sdm0=%d, sdm1=%d, sdm2=%d, odir=%d", sdm0, sdm1, sdm2, odir); rtc_clk_apll_enable(1, sdm0, sdm1, sdm2, odir); I2S[i2s_num]->clkm_conf.clkm_div_num = 1; I2S[i2s_num]->clkm_conf.clkm_div_b = 0; I2S[i2s_num]->clkm_conf.clkm_div_a = 1; - I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = 8; - I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = 8; + I2S[i2s_num]->sample_rate_conf.tx_bck_div_num = m_scale; + I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale; I2S[i2s_num]->clkm_conf.clka_en = 1; - double real_rate = i2s_get_apll_real_rate(bits, sdm0, sdm1, sdm2, odir); - ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", - rate, real_rate, bits, 1, 8, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 1, 0); + double fi2s_rate = i2s_apll_get_fi2s(bits, sdm0, sdm1, sdm2, odir); + ESP_LOGI(I2S_TAG, "APLL: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK_M: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", + rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0); } else { I2S[i2s_num]->clkm_conf.clka_en = 0; I2S[i2s_num]->clkm_conf.clkm_div_a = 63; @@ -476,10 +458,10 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b ESP_LOGI(I2S_TAG, "PLL_D2: Req RATE: %d, real rate: %0.3f, BITS: %u, CLKM: %u, BCK: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d", rate, real_rate, bits, clkmInteger, bck, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 64, clkmDecimals); } - + I2S[i2s_num]->sample_rate_conf.tx_bits_mod = bits; I2S[i2s_num]->sample_rate_conf.rx_bits_mod = bits; - + // wait all writing on-going finish if ((p_i2s_obj[i2s_num]->mode & I2S_MODE_TX) && p_i2s_obj[i2s_num]->tx) { xSemaphoreGive(p_i2s_obj[i2s_num]->tx->mux); @@ -930,7 +912,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co I2S[i2s_num]->conf.rx_right_first = 0; I2S[i2s_num]->conf.rx_slave_mod = 0; // Master I2S[i2s_num]->fifo_conf.rx_fifo_mod_force_en = 1; - + if (i2s_config->mode & I2S_MODE_SLAVE) { I2S[i2s_num]->conf.rx_slave_mod = 1;//RX Slave } @@ -1001,6 +983,7 @@ static esp_err_t i2s_param_config(i2s_port_t i2s_num, const i2s_config_t *i2s_co } p_i2s_obj[i2s_num]->use_apll = i2s_config->use_apll; + p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; return ESP_OK; } diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index f8f6b2a7c..ece69ae18 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -138,7 +138,8 @@ typedef struct { int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ int dma_buf_count; /*!< I2S DMA Buffer Count */ int dma_buf_len; /*!< I2S DMA Buffer Length */ - int use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ + bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ + int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ } i2s_config_t; /** @@ -391,7 +392,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); /** * @brief Set clock & bit width used for I2S RX and TX. - * + * * Similar to i2s_set_sample_rates(), but also sets bit width. * * @param i2s_num I2S_NUM_0, I2S_NUM_1 @@ -401,7 +402,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num); * @param bits I2S bit width (I2S_BITS_PER_SAMPLE_16BIT, I2S_BITS_PER_SAMPLE_24BIT, I2S_BITS_PER_SAMPLE_32BIT) * * @param ch I2S channel, (I2S_CHANNEL_MONO, I2S_CHANNEL_STEREO) - * + * * @return * - ESP_OK Success * - ESP_FAIL Parameter error diff --git a/docs/api-reference/peripherals/i2s.rst b/docs/api-reference/peripherals/i2s.rst index ccd817c55..335d6cb2d 100644 --- a/docs/api-reference/peripherals/i2s.rst +++ b/docs/api-reference/peripherals/i2s.rst @@ -10,7 +10,9 @@ The I2S peripheral supports DMA meaning it can stream sample data without requir I2S output can also be routed directly to the Digital/Analog Converter output channels (GPIO 25 & GPIO 26) to produce analog output directly, rather than via an external I2S codec. -.. note:: For high accuracy clock applications, APLL clock source can be used with `.use_apll = 1` and ESP32 will automatic caculate APLL parameter. +.. note:: For high accuracy clock applications, APLL clock source can be used with `.use_apll = true` and ESP32 will automatically calculate APLL parameter. + +.. note:: If `use_apll = true` and `fixed_mclk > 0`, then the Master clock output for I2S is fixed and equal to the fixed_mclk value. The audio clock rate (LRCK) is always the MCLK divisor and 0 < MCLK/LRCK/channels/bits_per_sample < 64 Application Example ------------------- @@ -37,7 +39,7 @@ Short example of I2S configuration: .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, - .use_apll = 0 + .use_apll = false }; static const i2s_pin_config_t pin_config = { @@ -73,7 +75,7 @@ Short example configuring I2S to use internal DAC for analog output:: .intr_alloc_flags = 0, // default interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, - .use_apll = 0 + .use_apll = false }; ... diff --git a/examples/peripherals/i2s/main/i2s_example_main.c b/examples/peripherals/i2s/main/i2s_example_main.c index 7bdd16c73..cf49a0885 100644 --- a/examples/peripherals/i2s/main/i2s_example_main.c +++ b/examples/peripherals/i2s/main/i2s_example_main.c @@ -87,7 +87,7 @@ void app_main() .communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB, .dma_buf_count = 6, .dma_buf_len = 60, - .use_apll = 0, + .use_apll = false, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1 }; i2s_pin_config_t pin_config = { From 4017cf35169ba275f17c99c432735155281a0cd7 Mon Sep 17 00:00:00 2001 From: Roland Dobai Date: Fri, 16 Feb 2018 11:12:16 +0100 Subject: [PATCH 18/19] partition_table: Optionally disable the MD5 checksum in partition tables --- components/partition_table/Kconfig.projbuild | 9 +++++++++ components/partition_table/Makefile.projbuild | 6 +++++- components/partition_table/gen_esp32part.py | 9 +++++++-- docs/api-guides/partition-tables.rst | 2 ++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/components/partition_table/Kconfig.projbuild b/components/partition_table/Kconfig.projbuild index a6176e0fd..09635d67a 100644 --- a/components/partition_table/Kconfig.projbuild +++ b/components/partition_table/Kconfig.projbuild @@ -62,6 +62,15 @@ config PHY_DATA_OFFSET default PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET if PARTITION_TABLE_CUSTOM default 0xf000 # this is the factory app offset used by the default tables +config PARTITION_TABLE_MD5 + bool "Generate an MD5 checksum for the partition table" + default y + help + Generate an MD5 checksum for the partition table for protecting the + integrity of the table. The generation should be turned off for legacy + bootloaders which cannot recognize the MD5 checksum in the partition + table. + endmenu diff --git a/components/partition_table/Makefile.projbuild b/components/partition_table/Makefile.projbuild index a7d4f2ecd..d1b7acdaa 100644 --- a/components/partition_table/Makefile.projbuild +++ b/components/partition_table/Makefile.projbuild @@ -8,8 +8,12 @@ # .PHONY: partition_table partition_table-flash partition_table-clean +ifneq ("$(CONFIG_PARTITION_TABLE_MD5)", "y") +MD5_OPT ?= "--disable-md5sum" +endif + # NB: gen_esp32part.py lives in the sdk/bin/ dir not component dir -GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q +GEN_ESP32PART := $(PYTHON) $(COMPONENT_PATH)/gen_esp32part.py -q $(MD5_OPT) # Has a matching value in bootloader_support esp_flash_partitions.h PARTITION_TABLE_OFFSET := 0x8000 diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index 7b80cabf8..a8607f360 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -35,6 +35,7 @@ MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like ma __version__ = '1.0' quiet = False +md5sum = True def status(msg): """ Print status message to stderr """ @@ -123,7 +124,7 @@ class PartitionTable(list): raise InputError("Partition table length must be a multiple of 32 bytes") if data == b'\xFF'*32: return result # got end marker - if data[:2] == MD5_PARTITION_BEGIN[:2]: #check only the magic number part + if md5sum and data[:2] == MD5_PARTITION_BEGIN[:2]: #check only the magic number part if data[16:] == md5.digest(): continue # the next iteration will check for the end marker else: @@ -135,7 +136,8 @@ class PartitionTable(list): def to_binary(self): result = b"".join(e.to_binary() for e in self) - result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest() + if md5sum: + result += MD5_PARTITION_BEGIN + hashlib.md5(result).digest() if len(result )>= MAX_PARTITION_LENGTH: raise InputError("Binary partition table length (%d) longer than max" % len(result)) result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing @@ -345,8 +347,10 @@ def parse_int(v, keywords={}): def main(): global quiet + global md5sum parser = argparse.ArgumentParser(description='ESP32 partition table utility') + parser.add_argument('--disable-md5sum', help='Disable md5 checksum for the partition table', default=False, action='store_true') parser.add_argument('--verify', '-v', help='Verify partition table fields', default=True, action='store_false') parser.add_argument('--quiet', '-q', help="Don't print status messages to stderr", action='store_true') @@ -358,6 +362,7 @@ def main(): args = parser.parse_args() quiet = args.quiet + md5sum = not args.disable_md5sum input = args.input.read() input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES if input_is_binary: diff --git a/docs/api-guides/partition-tables.rst b/docs/api-guides/partition-tables.rst index ee8863123..2893dbcaa 100644 --- a/docs/api-guides/partition-tables.rst +++ b/docs/api-guides/partition-tables.rst @@ -153,6 +153,8 @@ MD5 checksum The binary format of the partition table contains an MD5 checksum computed based on the partition table. This checksum is used for checking the integrity of the partition table during the boot. +The MD5 checksum generation can be disabled by the ``--disable-md5sum`` option of ``gen_esp32part.py`` or by the :ref:`CONFIG_PARTITION_TABLE_MD5` option. This is useful for example when one uses a legacy bootloader which cannot process MD5 checksums and the boot fails with the error message ``invalid magic number 0xebeb``. + Flashing the partition table ---------------------------- From 6dbb040890bc80f3469c2976e0fc866354765bed Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 14 Feb 2018 19:27:02 +0530 Subject: [PATCH 19/19] FD_ZERO: Fix a compilation warning Definition of memset is not found if string.h is not included anywhere Signed-off-by: Piyush Shah --- components/lwip/include/lwip/lwip/sockets.h | 1 + 1 file changed, 1 insertion(+) diff --git a/components/lwip/include/lwip/lwip/sockets.h b/components/lwip/include/lwip/lwip/sockets.h index 4dd013bcf..d8e4c7ffb 100755 --- a/components/lwip/include/lwip/lwip/sockets.h +++ b/components/lwip/include/lwip/lwip/sockets.h @@ -39,6 +39,7 @@ #if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ #include /* for size_t */ +#include /* for FD_ZERO */ #include "lwip/ip_addr.h" #include "lwip/err.h"