Merge remote-tracking branch 'remotes/espressif/master'

Bring in the heap task tracking code accepted from PR 1498.
This commit is contained in:
Stephen Casner 2018-02-23 21:57:43 -08:00
commit 4c532a59b2
42 changed files with 1468 additions and 205 deletions

View file

@ -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

View file

@ -156,6 +156,7 @@
// ALSO SEE example usage of application tracing module in 'components/app_trace/README.rst'
#include <string.h>
#include <sys/param.h>
#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

View file

@ -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]);
}

View file

@ -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;
}
/*****************************************************************************

View file

@ -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;
}
/*****************************************************************************

View file

@ -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);

View file

@ -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 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
* With 350MHz<fout<500MHz, we limit the sdm2 from 4 to 9,
* Take average frequency close to the desired frequency, and select sdm2
* 2. Next, we look for sequences of less influential and more detailed parameters,
* 2. Next, we look for sequences of less influential and more detailed parameters,
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
* 3. And finally, loop through all the most detailed of the parameters, finding the best desired frequency
*
* @param[in] rate The sample rate
* @param[in] rate The I2S Frequency (MCLK)
* @param[in] bits_per_sample The bits per sample
* @param[out] sdm0 The sdm 0
* @param[out] sdm1 The sdm 1
@ -240,45 +227,35 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int
*
* @return ESP_FAIL or ESP_OK
*/
static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
static esp_err_t i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, int *sdm1, int *sdm2, int *odir)
{
int _odir, _sdm0, _sdm1, _sdm2, i;
int _odir, _sdm0, _sdm1, _sdm2;
float avg;
float min_rate, max_rate, min_diff;
if (rate < APLL_I2S_MIN_RATE) {
if (rate/bits_per_sample/2/8 < APLL_I2S_MIN_RATE) {
return ESP_FAIL;
}
//check pre-define apll parameters
i = 0;
while (apll_predefine[i][0]) {
if (apll_predefine[i][0] == bits_per_sample && apll_predefine[i][0] == rate) {
*sdm0 = apll_predefine[i][1];
*sdm1 = apll_predefine[i][2];
*sdm2 = apll_predefine[i][3];
*odir = apll_predefine[i][4];
return ESP_OK;
}
i++;
}
*sdm0 = 0;
*sdm1 = 0;
*sdm2 = 0;
*odir = 0;
min_diff = 99999;
min_diff = APLL_MAX_FREQ;
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, _sdm2, 0);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, _sdm2, 31);
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm2 = _sdm2;
}
}
min_diff = 99999;
min_diff = APLL_MAX_FREQ;
for (_odir = 0; _odir < 32; _odir ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, *sdm2, _odir);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, *sdm2, _odir);
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir);
avg = (max_rate + min_rate)/2;
if(abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
@ -286,29 +263,28 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
}
}
min_diff = 99999;
min_diff = APLL_MAX_FREQ;
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, _sdm1, *sdm2, *odir);
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, _sdm1, *sdm2, *odir);
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, _sdm1, *sdm2, *odir);
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, _sdm1, *sdm2, *odir);
avg = (max_rate + min_rate)/2;
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm1 = _sdm1;
}
}
min_diff = 99999;
min_diff = APLL_MAX_FREQ;
for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
avg = i2s_get_apll_real_rate(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
avg = i2s_apll_get_fi2s(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir);
if (abs(avg - rate) < min_diff) {
min_diff = abs(avg - rate);
*sdm0 = _sdm0;
}
}
return ESP_OK;
}
esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t bits, i2s_channel_t ch)
{
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
@ -402,7 +378,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, i2s_bits_per_sample_t b
if (p_i2s_obj[i2s_num]->mode & 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;
}

View file

@ -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

View file

@ -0,0 +1,396 @@
//Do not edit this file because it is autogenerated by gen_esp_err_to_name.py
#include <string.h>
#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 doesnt 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 doesnt 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 wasnt 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 doesnt 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;
}

View file

@ -0,0 +1,53 @@
@COMMENT@
#include <string.h>
#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;
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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,

View file

@ -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 <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <multi_heap.h>
#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, &registered_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

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -39,6 +39,7 @@
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include <string.h> /* for FD_ZERO */
#include "lwip/ip_addr.h"
#include "lwip/err.h"

View file

@ -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;

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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 <flash-partition-apis>`.
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 <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 </api-guides/par
This component provides APIs to enumerate partitions found in the partition table
and perform operations on them. These functions are declared in ``esp_partition.h``:
- ``esp_partition_find`` used to search partition table for entries with
- :cpp:func:`esp_partition_find` used to search partition table for entries with
specific type, returns an opaque iterator
- ``esp_partition_get`` returns a structure describing the partition, for the given iterator
- ``esp_partition_next`` advances iterator to the next partition found
- ``esp_partition_iterator_release`` releases iterator returned by ``esp_partition_find``
- ``esp_partition_find_first`` is a convenience function which returns structure
- :cpp:func:`esp_partition_get` returns a structure describing the partition, for the given iterator
- :cpp:func:`esp_partition_next` advances iterator to the next partition found
- :cpp:func:`esp_partition_iterator_release` releases iterator returned by ``esp_partition_find``
- :cpp:func:`esp_partition_find_first` is a convenience function which returns structure
describing the first partition found by esp_partition_find
- ``esp_partition_read``, ``esp_partition_write``, ``esp_partition_erase_range``
are equivalent to ``spi_flash_read``, ``spi_flash_write``,
``spi_flash_erase_range``, but operate within partition boundaries
- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range`
are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`,
:cpp:func:`spi_flash_erase_range`, but operate within partition boundaries
Most application code should use ``esp_partition_*`` APIs instead of lower level
``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct
offsets in flash based on data stored in partition table.
.. note::
Most application code should use these ``esp_partition_*`` APIs instead of lower level
``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct
offsets in flash based on data stored in partition table.
SPI Flash Encryption
--------------------
@ -151,14 +158,14 @@ Decryption is performed at hardware level.
Memory mapping APIs are declared in ``esp_spi_flash.h`` and ``esp_partition.h``:
- ``spi_flash_mmap`` maps a region of physical flash addresses into instruction space or data space of the CPU
- ``spi_flash_munmap`` unmaps previously mapped region
- ``esp_partition_mmap`` maps part of a partition into the instruction space or data space of the CPU
- :cpp:func:`spi_flash_mmap` maps a region of physical flash addresses into instruction space or data space of the CPU
- :cpp:func:`spi_flash_munmap` unmaps previously mapped region
- :cpp:func:`esp_partition_mmap` maps part of a partition into the instruction space or data space of the CPU
Differences between ``spi_flash_mmap`` and ``esp_partition_mmap`` are as follows:
Differences between :cpp:func:`spi_flash_mmap` and :cpp:func:`esp_partition_mmap` are as follows:
- ``spi_flash_mmap`` must be given a 64KB aligned physical address
- ``esp_partition_mmap`` may be given an arbitrary offset within the partition,
- :cpp:func:`spi_flash_mmap` must be given a 64KB aligned physical address
- :cpp:func:`esp_partition_mmap` may be given any arbitrary offset within the partition,
it will adjust returned pointer to mapped memory as necessary
Note that because memory mapping happens in 64KB blocks, it may be possible to

View file

@ -77,12 +77,16 @@ esp_err_t spi_flash_erase_range(size_t start_address, size_t size);
/**
* @brief Write data to Flash.
*
* @note If source address is in DROM, this function will return
* ESP_ERR_INVALID_ARG.
* @note For fastest write performance, write a 4 byte aligned size at a
* 4 byte aligned offset in flash from a source buffer in DRAM. Varying any of
* these parameters will still work, but will be slower due to buffering.
*
* @param dest_addr destination address in Flash. Must be a multiple of 4 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 4 bytes.
* @note Writing more than 8KB at a time will be split into multiple
* write operations to avoid disrupting other tasks in the system.
*
* @param dest_addr Destination address in Flash.
* @param src Pointer to the source buffer.
* @param size Length of data, in bytes.
*
* @return esp_err_t
*/
@ -103,9 +107,9 @@ esp_err_t spi_flash_write(size_t dest_addr, const void *src, size_t size);
* absolute best performance, both dest_addr and size arguments should
* be multiples of 32 bytes.
*
* @param dest_addr destination address in Flash. Must be a multiple of 16 bytes.
* @param src pointer to the source buffer.
* @param size length of data, in bytes. Must be a multiple of 16 bytes.
* @param dest_addr Destination address in Flash. Must be a multiple of 16 bytes.
* @param src Pointer to the source buffer.
* @param size Length of data, in bytes. Must be a multiple of 16 bytes.
*
* @return esp_err_t
*/
@ -114,10 +118,22 @@ esp_err_t spi_flash_write_encrypted(size_t dest_addr, const void *src, size_t si
/**
* @brief Read data from Flash.
*
* @note For fastest read performance, all parameters should be
* 4 byte aligned. If source address and read size are not 4 byte
* aligned, read may be split into multiple flash operations. If
* destination buffer is not 4 byte aligned, a temporary buffer will
* be allocated on the stack.
*
* @note Reading more than 16KB of data at a time will be split
* into multiple reads to avoid disruption to other tasks in the
* system. Consider using spi_flash_mmap() to read large amounts
* of data.
*
* @param src_addr source address of the data in Flash.
* @param dest pointer to the destination buffer
* @param size length of data
*
*
* @return esp_err_t
*/
esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size);
@ -155,19 +171,20 @@ typedef uint32_t spi_flash_mmap_handle_t;
/**
* @brief Map region of flash memory into data or instruction address space
*
* This function allocates sufficient number of 64k MMU pages and configures
* them to map request region of flash memory into data address space or into
* instruction address space. It may reuse MMU pages which already provide
* required mapping. As with any allocator, there is possibility of fragmentation
* of address space if mmap/munmap are heavily used. To troubleshoot issues with
* page allocation, use spi_flash_mmap_dump function.
* This function allocates sufficient number of 64kB MMU pages and configures
* them to map the requested region of flash memory into the address space.
* It may reuse MMU pages which already provide the required mapping.
*
* As with any allocator, if mmap/munmap are heavily used then the address space
* may become fragmented. To troubleshoot issues with page allocation, use
* spi_flash_mmap_dump() function.
*
* @param src_addr Physical address in flash where requested region starts.
* This address *must* be aligned to 64kB boundary
* (SPI_FLASH_MMU_PAGE_SIZE).
* @param size Size of region which has to be mapped. This size will be rounded
* up to a 64k boundary.
* @param memory Memory space where the region should be mapped
* (SPI_FLASH_MMU_PAGE_SIZE)
* @param size Size of region to be mapped. This size will be rounded
* up to a 64kB boundary
* @param memory Address space where the region should be mapped (data or instruction)
* @param out_ptr Output, pointer to the mapped memory region
* @param out_handle Output, handle which should be used for spi_flash_munmap call
*
@ -179,17 +196,16 @@ esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t m
/**
* @brief Map sequences of pages of flash memory into data or instruction address space
*
* This function allocates sufficient number of 64k MMU pages and configures
* them to map the indicated pages of flash memory contiguously into data address
* space or into instruction address space. In this respect, it works in a similar
* way as spi_flash_mmap but it allows mapping a (maybe non-contiguous) set of pages
* into a contiguous region of memory.
* This function allocates sufficient number of 64kB MMU pages and configures
* them to map the indicated pages of flash memory contiguously into address space.
* In this respect, it works in a similar way as spi_flash_mmap() but it allows mapping
* a (maybe non-contiguous) set of pages into a contiguous region of memory.
*
* @param pages An array of numbers indicating the 64K pages in flash to be mapped
* contiguously into memory. These indicate the indexes of the 64K pages,
* @param pages An array of numbers indicating the 64kB pages in flash to be mapped
* contiguously into memory. These indicate the indexes of the 64kB pages,
* not the byte-size addresses as used in other functions.
* @param pagecount Size of the pages array
* @param memory Memory space where the region should be mapped
* @param pagecount Number of entries in the pages array
* @param memory Address space where the region should be mapped (instruction or data)
* @param out_ptr Output, pointer to the mapped memory region
* @param out_handle Output, handle which should be used for spi_flash_munmap call
*
@ -226,7 +242,7 @@ void spi_flash_mmap_dump();
/**
* @brief Given a memory address where flash is mapped, return the corresponding physical flash offset.
*
* Cache address does not have have been assigned via spi_flash_mmap(), any address in flash map space can be looked up.
* Cache address does not have have been assigned via spi_flash_mmap(), any address in memory mapped flash space can be looked up.
*
* @param cached Pointer to flashed cached memory.
*
@ -248,7 +264,7 @@ size_t spi_flash_cache2phys(const void *cached);
* phys_offs is not 4-byte aligned, then reading from the returned pointer will result in a crash.
*
* @param phys_offs Physical offset in flash memory to look up.
* @param memory Memory type to look up a flash cache address mapping for (IROM or DROM)
* @param memory Address space type to look up a flash cache address mapping for (instruction or data)
*
* @return
* - NULL if the physical address is invalid or not mapped to flash cache of the specified memory type.
@ -264,6 +280,7 @@ bool spi_flash_cache_enabled();
/**
* @brief SPI flash critical section enter function.
*
*/
typedef void (*spi_flash_guard_start_func_t)(void);
/**

View file

@ -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
----------------------------

View file

@ -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*

View file

@ -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
};
...

View file

@ -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.)

View file

@ -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` 目录下有一系列示例工程,都可以按照上面的方法进行创建。

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 = {

View file

@ -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);

300
tools/gen_esp_err_to_name.py Executable file
View file

@ -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()

View file

@ -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()