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/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 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/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); diff --git a/components/driver/i2s.c b/components/driver/i2s.c index b6d01c19c..39cd2fa26 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); @@ -185,13 +172,13 @@ 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); } -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/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/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; 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); diff --git a/components/heap/component.mk b/components/heap/component.mk index 33a639fda..8c57271d4 100644 --- a/components/heap/component.mk +++ b/components/heap/component.mk @@ -8,7 +8,7 @@ ifndef CONFIG_HEAP_POISONING_DISABLED COMPONENT_OBJS += multi_heap_poisoning.o ifdef CONFIG_HEAP_TASK_TRACKING -COMPONENT_OBJS += esp_heap_debug.o +COMPONENT_OBJS += heap_task_info.o endif endif 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 5e76beb05..77dd9d82c 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -54,10 +54,10 @@ 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) +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) +void *multi_heap_get_block_owner(multi_heap_block_handle_t block) { return NULL; } @@ -287,7 +287,7 @@ 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) +void *multi_heap_get_block_address_impl(multi_heap_block_handle_t block) { return ((char *)block + offsetof(heap_block_t, data)); } @@ -361,8 +361,9 @@ multi_heap_block_handle_t multi_heap_get_next_block(multi_heap_handle_t heap, mu { 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; + if (next == heap->last_block && is_last_block(next) && is_free(next)) { + return NULL; + } assert_valid_block(heap, next); return next; } diff --git a/components/heap/multi_heap_internal.h b/components/heap/multi_heap_internal.h index f55adbf66..a69a05259 100644 --- a/components/heap/multi_heap_internal.h +++ b/components/heap/multi_heap_internal.h @@ -31,7 +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); +void *multi_heap_get_block_address_impl(multi_heap_block_handle_t block); /* Some internal functions for heap poisoning use */ @@ -62,7 +62,7 @@ multi_heap_block_handle_t multi_heap_get_next_block(multi_heap_handle_t heap, mu 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); +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); +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 4045bbc2d..6a17522b4 100644 --- a/components/heap/multi_heap_platform.h +++ b/components/heap/multi_heap_platform.h @@ -65,12 +65,12 @@ inline static void multi_heap_assert(bool condition, const char *format, int lin #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) +#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) +#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (NULL) #endif #else // ESP_PLATFORM @@ -86,5 +86,6 @@ inline static void multi_heap_assert(bool condition, const char *format, int lin #define MULTI_HEAP_BLOCK_OWNER #define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) -#define MULTI_HEAP_GET_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 071a721f3..240598222 100644 --- a/components/heap/multi_heap_poisoning.c +++ b/components/heap/multi_heap_poisoning.c @@ -260,7 +260,7 @@ 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) +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); @@ -277,10 +277,9 @@ 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) +void *multi_heap_get_block_owner(multi_heap_block_handle_t block) { - poison_head_t *head = (poison_head_t*)multi_heap_get_block_address_impl(block); - return MULTI_HEAP_GET_BLOCK_OWNER(head); + 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) 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" 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); +} 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/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 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/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.) 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` 目录下有一系列示例工程,都可以按照上面的方法进行创建。 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; } 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 = { 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); 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() 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()