Merge remote-tracking branch 'remotes/espressif/master'
Bring in the heap task tracking code accepted from PR 1498.
This commit is contained in:
commit
4c532a59b2
|
@ -319,6 +319,17 @@ test_report:
|
||||||
- git push origin master
|
- git push origin master
|
||||||
- test "${TEST_RESULT}" = "Pass" || exit 1
|
- 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:
|
push_master_to_github:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG
|
||||||
|
|
|
@ -156,6 +156,7 @@
|
||||||
// ALSO SEE example usage of application tracing module in 'components/app_trace/README.rst'
|
// ALSO SEE example usage of application tracing module in 'components/app_trace/README.rst'
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include "soc/soc.h"
|
#include "soc/soc.h"
|
||||||
#include "soc/dport_reg.h"
|
#include "soc/dport_reg.h"
|
||||||
#include "eri.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) {
|
while (1) {
|
||||||
uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down);
|
uint32_t sz = esp_apptrace_rb_read_size_get(&s_trace_buf.rb_down);
|
||||||
if (sz != 0) {
|
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) {
|
if (!ptr) {
|
||||||
assert(false && "Failed to consume bytes from down buffer!");
|
assert(false && "Failed to consume bytes from down buffer!");
|
||||||
}
|
}
|
||||||
*size = sz;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// may need to flush
|
// may need to flush
|
||||||
|
|
|
@ -1847,6 +1847,8 @@ void bta_av_dereg_comp(tBTA_AV_DATA *p_data)
|
||||||
|
|
||||||
/* make sure that the timer is not active */
|
/* make sure that the timer is not active */
|
||||||
bta_sys_stop_timer(&p_scb->timer);
|
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]);
|
utl_freebuf((void **)&p_cb->p_scb[p_scb->hdi]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,10 @@ error_exit:;
|
||||||
vQueueDelete(btc_aa_snk_ctrl_queue);
|
vQueueDelete(btc_aa_snk_ctrl_queue);
|
||||||
btc_aa_snk_ctrl_queue = NULL;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +295,9 @@ void btc_a2dp_sink_shutdown(void)
|
||||||
|
|
||||||
vQueueDelete(btc_aa_snk_ctrl_queue);
|
vQueueDelete(btc_aa_snk_ctrl_queue);
|
||||||
btc_aa_snk_ctrl_queue = NULL;
|
btc_aa_snk_ctrl_queue = NULL;
|
||||||
|
|
||||||
|
vQueueDelete(btc_aa_snk_queue_set);
|
||||||
|
btc_aa_snk_queue_set = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
|
@ -348,7 +348,10 @@ error_exit:;
|
||||||
vQueueDelete(btc_aa_src_ctrl_queue);
|
vQueueDelete(btc_aa_src_ctrl_queue);
|
||||||
btc_aa_src_ctrl_queue = NULL;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +370,9 @@ void btc_a2dp_source_shutdown(void)
|
||||||
|
|
||||||
vQueueDelete(btc_aa_src_ctrl_queue);
|
vQueueDelete(btc_aa_src_ctrl_queue);
|
||||||
btc_aa_src_ctrl_queue = NULL;
|
btc_aa_src_ctrl_queue = NULL;
|
||||||
|
|
||||||
|
vQueueDelete(btc_aa_src_queue_set);
|
||||||
|
btc_aa_src_queue_set = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
|
@ -631,7 +631,7 @@ static void btc_gattc_prepare_write_char_descr(btc_ble_gattc_args_t *arg)
|
||||||
arg->prep_write_descr.auth_req);
|
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);
|
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);
|
btc_gattc_prepare_write_char_descr(arg);
|
||||||
break;
|
break;
|
||||||
case BTC_GATTC_ACT_EXECUTE_WRITE:
|
case BTC_GATTC_ACT_EXECUTE_WRITE:
|
||||||
btc_gattc_execute_wrtie(arg);
|
btc_gattc_execute_write(arg);
|
||||||
break;
|
break;
|
||||||
case BTC_GATTC_ACT_REG_FOR_NOTIFY:
|
case BTC_GATTC_ACT_REG_FOR_NOTIFY:
|
||||||
btc_gattc_reg_for_notify(arg);
|
btc_gattc_reg_for_notify(arg);
|
||||||
|
|
|
@ -49,7 +49,7 @@ static const char* I2S_TAG = "I2S";
|
||||||
#define I2S_EXIT_CRITICAL() portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
|
#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_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 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_MAX_FREQ (500000000)
|
||||||
#define APLL_I2S_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware
|
#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 bytes_per_sample; /*!< Bytes per sample*/
|
||||||
int bits_per_sample; /*!< Bits per sample*/
|
int bits_per_sample; /*!< Bits per sample*/
|
||||||
i2s_mode_t mode; /*!< I2S Working mode*/
|
i2s_mode_t mode; /*!< I2S Working mode*/
|
||||||
int use_apll; /*!< I2S use APLL clock */
|
|
||||||
uint32_t sample_rate; /*!< I2S sample rate */
|
uint32_t sample_rate; /*!< I2S sample rate */
|
||||||
|
bool use_apll; /*!< I2S use APLL clock */
|
||||||
|
int fixed_mclk; /*!< I2S fixed MLCK clock */
|
||||||
} i2s_obj_t;
|
} i2s_obj_t;
|
||||||
|
|
||||||
static i2s_obj_t *p_i2s_obj[I2S_NUM_MAX] = {0};
|
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 portMUX_TYPE i2s_spinlock[I2S_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
|
||||||
static int _i2s_adc_unit = -1;
|
static int _i2s_adc_unit = -1;
|
||||||
static int _i2s_adc_channel = -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 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);
|
static esp_err_t i2s_destroy_dma_queue(i2s_port_t i2s_num, i2s_dma_t *dma);
|
||||||
|
@ -185,13 +172,13 @@ esp_err_t i2s_enable_tx_intr(i2s_port_t i2s_num)
|
||||||
return ESP_OK;
|
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);
|
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;
|
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);
|
uint32_t is_rev0 = (GET_PERI_REG_BITS2(EFUSE_BLK0_RDATA3_REG, 1, 15) == 0);
|
||||||
|
@ -201,10 +188,10 @@ 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);
|
float fout = f_xtal * (sdm2 + sdm1 / 256.0f + sdm0 / 65536.0f + 4);
|
||||||
if (fout < APLL_MIN_FREQ || fout > APLL_MAX_FREQ) {
|
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)
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,7 +218,7 @@ static float i2s_get_apll_real_rate(int bits_per_sample, int sdm0, int sdm1, int
|
||||||
* also by taking the average of the largest and smallest frequencies closer to the desired frequency.
|
* 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
|
* 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[in] bits_per_sample The bits per sample
|
||||||
* @param[out] sdm0 The sdm 0
|
* @param[out] sdm0 The sdm 0
|
||||||
* @param[out] sdm1 The sdm 1
|
* @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
|
* @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 avg;
|
||||||
float min_rate, max_rate, min_diff;
|
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;
|
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;
|
*sdm0 = 0;
|
||||||
*sdm1 = 0;
|
*sdm1 = 0;
|
||||||
*sdm2 = 0;
|
*sdm2 = 0;
|
||||||
*odir = 0;
|
*odir = 0;
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
|
|
||||||
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
|
for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, _sdm2, 0);
|
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0);
|
||||||
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, _sdm2, 31);
|
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31);
|
||||||
avg = (max_rate + min_rate)/2;
|
avg = (max_rate + min_rate)/2;
|
||||||
if(abs(avg - rate) < min_diff) {
|
if(abs(avg - rate) < min_diff) {
|
||||||
min_diff = abs(avg - rate);
|
min_diff = abs(avg - rate);
|
||||||
*sdm2 = _sdm2;
|
*sdm2 = _sdm2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
min_diff = 99999;
|
min_diff = APLL_MAX_FREQ;
|
||||||
for (_odir = 0; _odir < 32; _odir ++) {
|
for (_odir = 0; _odir < 32; _odir ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, 255, *sdm2, _odir);
|
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir);
|
||||||
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, 0, *sdm2, _odir);
|
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir);
|
||||||
avg = (max_rate + min_rate)/2;
|
avg = (max_rate + min_rate)/2;
|
||||||
if(abs(avg - rate) < min_diff) {
|
if(abs(avg - rate) < min_diff) {
|
||||||
min_diff = abs(avg - rate);
|
min_diff = abs(avg - rate);
|
||||||
|
@ -286,10 +263,10 @@ 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 ++) {
|
for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) {
|
||||||
max_rate = i2s_get_apll_real_rate(bits_per_sample, 255, _sdm1, *sdm2, *odir);
|
max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, _sdm1, *sdm2, *odir);
|
||||||
min_rate = i2s_get_apll_real_rate(bits_per_sample, 0, _sdm1, *sdm2, *odir);
|
min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, _sdm1, *sdm2, *odir);
|
||||||
avg = (max_rate + min_rate)/2;
|
avg = (max_rate + min_rate)/2;
|
||||||
if (abs(avg - rate) < min_diff) {
|
if (abs(avg - rate) < min_diff) {
|
||||||
min_diff = abs(avg - rate);
|
min_diff = abs(avg - rate);
|
||||||
|
@ -297,9 +274,9 @@ 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 (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) {
|
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) {
|
if (abs(avg - rate) < min_diff) {
|
||||||
min_diff = abs(avg - rate);
|
min_diff = abs(avg - rate);
|
||||||
*sdm0 = _sdm0;
|
*sdm0 = _sdm0;
|
||||||
|
@ -308,7 +285,6 @@ static esp_err_t i2s_apll_calculate(int rate, int bits_per_sample, int *sdm0, in
|
||||||
|
|
||||||
return ESP_OK;
|
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)
|
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)
|
int factor = (256%bits)? 384 : 256; // According to hardware codec requirement(supported 256fs or 384fs)
|
||||||
|
@ -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;
|
mclk = clkmInteger + denom * clkmDecimals;
|
||||||
bck = factor/(bits * channel);
|
bck = factor/(bits * channel);
|
||||||
}
|
}
|
||||||
int sdm0, sdm1, sdm2, odir;
|
int sdm0, sdm1, sdm2, odir, m_scale = 8;
|
||||||
if(p_i2s_obj[i2s_num]->use_apll && i2s_apll_calculate(rate, bits, &sdm0, &sdm1, &sdm2, &odir) == ESP_OK) {
|
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);
|
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_num = 1;
|
||||||
I2S[i2s_num]->clkm_conf.clkm_div_b = 0;
|
I2S[i2s_num]->clkm_conf.clkm_div_b = 0;
|
||||||
I2S[i2s_num]->clkm_conf.clkm_div_a = 1;
|
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.tx_bck_div_num = m_scale;
|
||||||
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = 8;
|
I2S[i2s_num]->sample_rate_conf.rx_bck_div_num = m_scale;
|
||||||
I2S[i2s_num]->clkm_conf.clka_en = 1;
|
I2S[i2s_num]->clkm_conf.clka_en = 1;
|
||||||
double real_rate = i2s_get_apll_real_rate(bits, sdm0, sdm1, sdm2, odir);
|
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: %u, MCLK: %0.3f, SCLK: %f, diva: %d, divb: %d",
|
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, real_rate, bits, 1, 8, (double)I2S_BASE_CLK / mclk, real_rate*bits*channel, 1, 0);
|
rate, fi2s_rate/bits/channel/m_scale, bits, 1, m_scale, fi2s_rate, fi2s_rate/8, 1, 0);
|
||||||
} else {
|
} else {
|
||||||
I2S[i2s_num]->clkm_conf.clka_en = 0;
|
I2S[i2s_num]->clkm_conf.clka_en = 0;
|
||||||
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
|
I2S[i2s_num]->clkm_conf.clkm_div_a = 63;
|
||||||
|
@ -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]->use_apll = i2s_config->use_apll;
|
||||||
|
p_i2s_obj[i2s_num]->fixed_mclk = i2s_config->fixed_mclk;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 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_count; /*!< I2S DMA Buffer Count */
|
||||||
int dma_buf_len; /*!< I2S DMA Buffer Length */
|
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;
|
} i2s_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
396
components/esp32/esp_err_to_name.c
Normal file
396
components/esp32/esp_err_to_name.c
Normal 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 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;
|
||||||
|
}
|
53
components/esp32/esp_err_to_name.c.in
Normal file
53
components/esp32/esp_err_to_name.c.in
Normal 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;
|
||||||
|
}
|
|
@ -42,6 +42,39 @@ typedef int32_t esp_err_t;
|
||||||
|
|
||||||
#define ESP_ERR_WIFI_BASE 0x3000 /*!< Starting number of WiFi error codes */
|
#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));
|
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
|
#ifndef __ASSERT_FUNC
|
||||||
|
|
|
@ -54,12 +54,12 @@ typedef enum {
|
||||||
* @brief Sleep wakeup cause
|
* @brief Sleep wakeup cause
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ESP_SLEEP_WAKEUP_UNDEFINED, //! In case of deep sleep, reset was not caused by exit from deep sleep
|
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_EXT0, //!< Wakeup caused by external signal using RTC_IO
|
||||||
ESP_SLEEP_WAKEUP_EXT1, //! Wakeup caused by external signal using RTC_CNTL
|
ESP_SLEEP_WAKEUP_EXT1, //!< Wakeup caused by external signal using RTC_CNTL
|
||||||
ESP_SLEEP_WAKEUP_TIMER, //! Wakeup caused by timer
|
ESP_SLEEP_WAKEUP_TIMER, //!< Wakeup caused by timer
|
||||||
ESP_SLEEP_WAKEUP_TOUCHPAD, //! Wakeup caused by touchpad
|
ESP_SLEEP_WAKEUP_TOUCHPAD, //!< Wakeup caused by touchpad
|
||||||
ESP_SLEEP_WAKEUP_ULP, //! Wakeup caused by ULP program
|
ESP_SLEEP_WAKEUP_ULP, //!< Wakeup caused by ULP program
|
||||||
} esp_sleep_wakeup_cause_t;
|
} esp_sleep_wakeup_cause_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
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);
|
gpio_matrix_out(mdc_gpio, EMAC_MDC_O_IDX, 0, 0);
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdc_gpio], PIN_FUNC_GPIO);
|
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_out(mdio_gpio, EMAC_MDO_O_IDX, 0, 0);
|
||||||
gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0);
|
gpio_matrix_in(mdio_gpio, EMAC_MDI_I_IDX, 0);
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdio_gpio], PIN_FUNC_GPIO);
|
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[mdio_gpio], PIN_FUNC_GPIO);
|
||||||
|
|
|
@ -8,7 +8,7 @@ ifndef CONFIG_HEAP_POISONING_DISABLED
|
||||||
COMPONENT_OBJS += multi_heap_poisoning.o
|
COMPONENT_OBJS += multi_heap_poisoning.o
|
||||||
|
|
||||||
ifdef CONFIG_HEAP_TASK_TRACKING
|
ifdef CONFIG_HEAP_TASK_TRACKING
|
||||||
COMPONENT_OBJS += esp_heap_debug.o
|
COMPONENT_OBJS += heap_task_info.o
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -55,19 +55,6 @@ IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len)
|
||||||
return (void *)(iptr + 1);
|
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)
|
bool heap_caps_match(const heap_t *heap, uint32_t caps)
|
||||||
{
|
{
|
||||||
return heap->heap != NULL && ((get_all_caps(heap) & caps) == caps);
|
return heap->heap != NULL && ((get_all_caps(heap) & caps) == caps);
|
||||||
|
|
|
@ -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);
|
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,
|
Because we don't want to add _another_ known allocation method to the stack of functions to trace wrt memory tracing,
|
||||||
|
|
129
components/heap/heap_task_info.c
Normal file
129
components/heap/heap_task_info.c
Normal 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, ®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
|
98
components/heap/include/esp_heap_task_info.h
Normal file
98
components/heap/include/esp_heap_task_info.h
Normal 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
|
|
@ -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)
|
size_t multi_heap_minimum_free_size(multi_heap_handle_t heap)
|
||||||
__attribute__((alias("multi_heap_minimum_free_size_impl")));
|
__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")));
|
__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;
|
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);
|
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));
|
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);
|
heap_block_t *next = get_next_block(block);
|
||||||
/* check for valid free last block to avoid assert in assert_valid_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))
|
if (next == heap->last_block && is_last_block(next) && is_free(next)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
assert_valid_block(heap, next);
|
assert_valid_block(heap, next);
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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_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_minimum_free_size_impl(multi_heap_handle_t heap);
|
||||||
size_t multi_heap_get_allocated_size_impl(multi_heap_handle_t heap, void *p);
|
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 */
|
/* 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);
|
bool multi_heap_is_free(const multi_heap_block_handle_t block);
|
||||||
|
|
||||||
/* Get the data address of a heap 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 */
|
/* 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);
|
||||||
|
|
|
@ -65,12 +65,12 @@ inline static void multi_heap_assert(bool condition, const char *format, int lin
|
||||||
|
|
||||||
#ifdef CONFIG_HEAP_TASK_TRACKING
|
#ifdef CONFIG_HEAP_TASK_TRACKING
|
||||||
#define MULTI_HEAP_BLOCK_OWNER TaskHandle_t task;
|
#define MULTI_HEAP_BLOCK_OWNER TaskHandle_t task;
|
||||||
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) HEAD->task = xTaskGetCurrentTaskHandle()
|
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD) (HEAD)->task = xTaskGetCurrentTaskHandle()
|
||||||
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (HEAD->task)
|
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) ((HEAD)->task)
|
||||||
#else
|
#else
|
||||||
#define MULTI_HEAP_BLOCK_OWNER
|
#define MULTI_HEAP_BLOCK_OWNER
|
||||||
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD)
|
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD)
|
||||||
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD)
|
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else // ESP_PLATFORM
|
#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_BLOCK_OWNER
|
||||||
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD)
|
#define MULTI_HEAP_SET_BLOCK_OWNER(HEAD)
|
||||||
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD)
|
#define MULTI_HEAP_GET_BLOCK_OWNER(HEAD) (NULL)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -260,7 +260,7 @@ void *multi_heap_realloc(multi_heap_handle_t heap, void *p, size_t size)
|
||||||
return result;
|
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);
|
char *head = multi_heap_get_block_address_impl(block);
|
||||||
return head + sizeof(poison_head_t);
|
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;
|
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((poison_head_t*)multi_heap_get_block_address_impl(block));
|
||||||
return MULTI_HEAP_GET_BLOCK_OWNER(head);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
multi_heap_handle_t multi_heap_register(void *start, size_t size)
|
multi_heap_handle_t multi_heap_register(void *start, size_t size)
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
|
||||||
|
|
||||||
#include <stddef.h> /* for size_t */
|
#include <stddef.h> /* for size_t */
|
||||||
|
#include <string.h> /* for FD_ZERO */
|
||||||
|
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
|
|
@ -29,7 +29,6 @@ typedef void X509_STORE;
|
||||||
typedef void RSA;
|
typedef void RSA;
|
||||||
|
|
||||||
typedef void STACK;
|
typedef void STACK;
|
||||||
typedef void BIO;
|
|
||||||
|
|
||||||
#define ossl_inline inline
|
#define ossl_inline inline
|
||||||
|
|
||||||
|
@ -84,6 +83,9 @@ typedef struct pkey_method_st PKEY_METHOD;
|
||||||
struct ssl_alpn_st;
|
struct ssl_alpn_st;
|
||||||
typedef struct ssl_alpn_st SSL_ALPN;
|
typedef struct ssl_alpn_st SSL_ALPN;
|
||||||
|
|
||||||
|
struct bio_st;
|
||||||
|
typedef struct bio_st BIO;
|
||||||
|
|
||||||
struct stack_st {
|
struct stack_st {
|
||||||
|
|
||||||
char **data;
|
char **data;
|
||||||
|
@ -106,6 +108,8 @@ struct x509_st {
|
||||||
void *x509_pm;
|
void *x509_pm;
|
||||||
|
|
||||||
const X509_METHOD *method;
|
const X509_METHOD *method;
|
||||||
|
|
||||||
|
int ref_counter;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct cert_st {
|
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;
|
typedef enum { ALPN_INIT, ALPN_ENABLE, ALPN_DISABLE, ALPN_ERROR } ALPN_STATUS;
|
||||||
struct ssl_alpn_st {
|
struct ssl_alpn_st {
|
||||||
ALPN_STATUS alpn_status;
|
ALPN_STATUS alpn_status;
|
||||||
|
|
|
@ -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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "ssl_methods.h"
|
#include "ssl_methods.h"
|
||||||
#include "ssl_dbg.h"
|
#include "ssl_dbg.h"
|
||||||
#include "ssl_port.h"
|
#include "ssl_port.h"
|
||||||
|
#include "ssl.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief show X509 certification information
|
* @brief show X509 certification information
|
||||||
|
@ -39,6 +40,8 @@ X509* __X509_new(X509 *ix)
|
||||||
goto no_mem;
|
goto no_mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x->ref_counter = 1;
|
||||||
|
|
||||||
if (ix)
|
if (ix)
|
||||||
x->method = ix->method;
|
x->method = ix->method;
|
||||||
else
|
else
|
||||||
|
@ -73,6 +76,10 @@ void X509_free(X509 *x)
|
||||||
{
|
{
|
||||||
SSL_ASSERT3(x);
|
SSL_ASSERT3(x);
|
||||||
|
|
||||||
|
if (--x->ref_counter > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
X509_METHOD_CALL(free, x);
|
X509_METHOD_CALL(free, x);
|
||||||
|
|
||||||
ssl_mem_free(x);
|
ssl_mem_free(x);
|
||||||
|
@ -314,3 +321,108 @@ X509 *SSL_get_peer_certificate(const SSL *ssl)
|
||||||
return ssl->session->peer;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,15 @@ config PHY_DATA_OFFSET
|
||||||
default PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET if PARTITION_TABLE_CUSTOM
|
default PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET if PARTITION_TABLE_CUSTOM
|
||||||
default 0xf000 # this is the factory app offset used by the default tables
|
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
|
endmenu
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,12 @@
|
||||||
#
|
#
|
||||||
.PHONY: partition_table partition_table-flash partition_table-clean
|
.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
|
# 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
|
# Has a matching value in bootloader_support esp_flash_partitions.h
|
||||||
PARTITION_TABLE_OFFSET := 0x8000
|
PARTITION_TABLE_OFFSET := 0x8000
|
||||||
|
|
|
@ -35,6 +35,7 @@ MD5_PARTITION_BEGIN = b"\xEB\xEB" + b"\xFF" * 14 # The first 2 bytes are like ma
|
||||||
__version__ = '1.0'
|
__version__ = '1.0'
|
||||||
|
|
||||||
quiet = False
|
quiet = False
|
||||||
|
md5sum = True
|
||||||
|
|
||||||
def status(msg):
|
def status(msg):
|
||||||
""" Print status message to stderr """
|
""" Print status message to stderr """
|
||||||
|
@ -123,7 +124,7 @@ class PartitionTable(list):
|
||||||
raise InputError("Partition table length must be a multiple of 32 bytes")
|
raise InputError("Partition table length must be a multiple of 32 bytes")
|
||||||
if data == b'\xFF'*32:
|
if data == b'\xFF'*32:
|
||||||
return result # got end marker
|
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():
|
if data[16:] == md5.digest():
|
||||||
continue # the next iteration will check for the end marker
|
continue # the next iteration will check for the end marker
|
||||||
else:
|
else:
|
||||||
|
@ -135,7 +136,8 @@ class PartitionTable(list):
|
||||||
|
|
||||||
def to_binary(self):
|
def to_binary(self):
|
||||||
result = b"".join(e.to_binary() for e in 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:
|
if len(result )>= MAX_PARTITION_LENGTH:
|
||||||
raise InputError("Binary partition table length (%d) longer than max" % len(result))
|
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
|
result += b"\xFF" * (MAX_PARTITION_LENGTH - len(result)) # pad the sector, for signing
|
||||||
|
@ -345,8 +347,10 @@ def parse_int(v, keywords={}):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global quiet
|
global quiet
|
||||||
|
global md5sum
|
||||||
parser = argparse.ArgumentParser(description='ESP32 partition table utility')
|
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('--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')
|
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()
|
args = parser.parse_args()
|
||||||
|
|
||||||
quiet = args.quiet
|
quiet = args.quiet
|
||||||
|
md5sum = not args.disable_md5sum
|
||||||
input = args.input.read()
|
input = args.input.read()
|
||||||
input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES
|
input_is_binary = input[0:2] == PartitionDefinition.MAGIC_BYTES
|
||||||
if input_is_binary:
|
if input_is_binary:
|
||||||
|
|
|
@ -18,14 +18,14 @@ SPI flash access APIs
|
||||||
|
|
||||||
This is the set of APIs for working with data in flash:
|
This is the set of APIs for working with data in flash:
|
||||||
|
|
||||||
- ``spi_flash_read`` used to read data from flash to RAM
|
- :cpp:func:`spi_flash_read` used to read data from flash to RAM
|
||||||
- ``spi_flash_write`` used to write data from RAM to flash
|
- :cpp:func:`spi_flash_write` used to write data from RAM to flash
|
||||||
- ``spi_flash_erase_sector`` used to erase individual sectors of flash
|
- :cpp:func:`spi_flash_erase_sector` used to erase individual sectors of flash
|
||||||
- ``spi_flash_erase_range`` used to erase range of addresses in flash
|
- :cpp:func:`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_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
|
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
|
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
|
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
|
written to flash, and the header is updated with the correct
|
||||||
size. Alternatively, it is possible to generate a fixed flash size by disabling
|
size. Alternatively, it is possible to generate a fixed flash size by setting
|
||||||
detection in ``make menuconfig`` (under Serial Flasher Config).
|
:ref:`CONFIG_ESPTOOLPY_FLASHSIZE` in ``make menuconfig``.
|
||||||
|
|
||||||
If it is necessary to override the configured flash size at runtime, is is
|
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
|
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 &
|
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
|
means that both CPUs must be running code from IRAM and only reading data from
|
||||||
DRAM while flash write operations occur.
|
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
|
Refer to the :ref:`application memory layout <memory-layout>` documentation for
|
||||||
an explanation of the differences between IRAM, DRAM and flash cache.
|
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
|
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).
|
garbage data to be read (for constant data which should be in DRAM).
|
||||||
|
|
||||||
|
.. _flash-partition-apis:
|
||||||
|
|
||||||
Partition table 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
|
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``:
|
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
|
specific type, returns an opaque iterator
|
||||||
- ``esp_partition_get`` returns a structure describing the partition, for the given iterator
|
- :cpp:func:`esp_partition_get` returns a structure describing the partition, for the given iterator
|
||||||
- ``esp_partition_next`` advances iterator to the next partition found
|
- :cpp:func:`esp_partition_next` advances iterator to the next partition found
|
||||||
- ``esp_partition_iterator_release`` releases iterator returned by ``esp_partition_find``
|
- :cpp:func:`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_find_first` is a convenience function which returns structure
|
||||||
describing the first partition found by esp_partition_find
|
describing the first partition found by esp_partition_find
|
||||||
- ``esp_partition_read``, ``esp_partition_write``, ``esp_partition_erase_range``
|
- :cpp:func:`esp_partition_read`, :cpp:func:`esp_partition_write`, :cpp:func:`esp_partition_erase_range`
|
||||||
are equivalent to ``spi_flash_read``, ``spi_flash_write``,
|
are equivalent to :cpp:func:`spi_flash_read`, :cpp:func:`spi_flash_write`,
|
||||||
``spi_flash_erase_range``, but operate within partition boundaries
|
:cpp:func:`spi_flash_erase_range`, but operate within partition boundaries
|
||||||
|
|
||||||
Most application code should use ``esp_partition_*`` APIs instead of lower level
|
.. note::
|
||||||
``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct
|
Most application code should use these ``esp_partition_*`` APIs instead of lower level
|
||||||
offsets in flash based on data stored in partition table.
|
``spi_flash_*`` APIs. Partition APIs do bounds checking and calculate correct
|
||||||
|
offsets in flash based on data stored in partition table.
|
||||||
|
|
||||||
SPI Flash Encryption
|
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``:
|
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
|
- :cpp:func:`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
|
- :cpp:func:`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:`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
|
- :cpp:func:`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:`esp_partition_mmap` may be given any arbitrary offset within the partition,
|
||||||
it will adjust returned pointer to mapped memory as necessary
|
it will adjust returned pointer to mapped memory as necessary
|
||||||
|
|
||||||
Note that because memory mapping happens in 64KB blocks, it may be possible to
|
Note that because memory mapping happens in 64KB blocks, it may be possible to
|
||||||
|
|
|
@ -77,12 +77,16 @@ esp_err_t spi_flash_erase_range(size_t start_address, size_t size);
|
||||||
/**
|
/**
|
||||||
* @brief Write data to Flash.
|
* @brief Write data to Flash.
|
||||||
*
|
*
|
||||||
* @note If source address is in DROM, this function will return
|
* @note For fastest write performance, write a 4 byte aligned size at a
|
||||||
* ESP_ERR_INVALID_ARG.
|
* 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.
|
* @note Writing more than 8KB at a time will be split into multiple
|
||||||
* @param src pointer to the source buffer.
|
* write operations to avoid disrupting other tasks in the system.
|
||||||
* @param size length of data, in bytes. Must be a multiple of 4 bytes.
|
*
|
||||||
|
* @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
|
* @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
|
* absolute best performance, both dest_addr and size arguments should
|
||||||
* be multiples of 32 bytes.
|
* be multiples of 32 bytes.
|
||||||
*
|
*
|
||||||
* @param dest_addr destination address in Flash. 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 src Pointer to the source buffer.
|
||||||
* @param size length of data, in bytes. Must be a multiple of 16 bytes.
|
* @param size Length of data, in bytes. Must be a multiple of 16 bytes.
|
||||||
*
|
*
|
||||||
* @return esp_err_t
|
* @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.
|
* @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 src_addr source address of the data in Flash.
|
||||||
* @param dest pointer to the destination buffer
|
* @param dest pointer to the destination buffer
|
||||||
* @param size length of data
|
* @param size length of data
|
||||||
*
|
*
|
||||||
|
*
|
||||||
* @return esp_err_t
|
* @return esp_err_t
|
||||||
*/
|
*/
|
||||||
esp_err_t spi_flash_read(size_t src_addr, void *dest, size_t size);
|
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
|
* @brief Map region of flash memory into data or instruction address space
|
||||||
*
|
*
|
||||||
* This function allocates sufficient number of 64k MMU pages and configures
|
* This function allocates sufficient number of 64kB MMU pages and configures
|
||||||
* them to map request region of flash memory into data address space or into
|
* them to map the requested region of flash memory into the address space.
|
||||||
* instruction address space. It may reuse MMU pages which already provide
|
* It may reuse MMU pages which already provide the required mapping.
|
||||||
* required mapping. As with any allocator, there is possibility of fragmentation
|
*
|
||||||
* of address space if mmap/munmap are heavily used. To troubleshoot issues with
|
* As with any allocator, if mmap/munmap are heavily used then the address space
|
||||||
* page allocation, use spi_flash_mmap_dump function.
|
* 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.
|
* @param src_addr Physical address in flash where requested region starts.
|
||||||
* This address *must* be aligned to 64kB boundary
|
* This address *must* be aligned to 64kB boundary
|
||||||
* (SPI_FLASH_MMU_PAGE_SIZE).
|
* (SPI_FLASH_MMU_PAGE_SIZE)
|
||||||
* @param size Size of region which has to be mapped. This size will be rounded
|
* @param size Size of region to be mapped. This size will be rounded
|
||||||
* up to a 64k boundary.
|
* up to a 64kB boundary
|
||||||
* @param memory Memory space where the region should be mapped
|
* @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_ptr Output, pointer to the mapped memory region
|
||||||
* @param out_handle Output, handle which should be used for spi_flash_munmap call
|
* @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
|
* @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
|
* This function allocates sufficient number of 64kB MMU pages and configures
|
||||||
* them to map the indicated pages of flash memory contiguously into data address
|
* them to map the indicated pages of flash memory contiguously into address space.
|
||||||
* space or into instruction address space. In this respect, it works in a similar
|
* In this respect, it works in a similar way as spi_flash_mmap() but it allows mapping
|
||||||
* way as spi_flash_mmap but it allows mapping a (maybe non-contiguous) set of pages
|
* a (maybe non-contiguous) set of pages into a contiguous region of memory.
|
||||||
* into a contiguous region of memory.
|
|
||||||
*
|
*
|
||||||
* @param pages An array of numbers indicating the 64K pages in flash to be mapped
|
* @param pages An array of numbers indicating the 64kB pages in flash to be mapped
|
||||||
* contiguously into memory. These indicate the indexes of the 64K pages,
|
* contiguously into memory. These indicate the indexes of the 64kB pages,
|
||||||
* not the byte-size addresses as used in other functions.
|
* not the byte-size addresses as used in other functions.
|
||||||
* @param pagecount Size of the pages array
|
* @param pagecount Number of entries in the pages array
|
||||||
* @param memory Memory space where the region should be mapped
|
* @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_ptr Output, pointer to the mapped memory region
|
||||||
* @param out_handle Output, handle which should be used for spi_flash_munmap call
|
* @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.
|
* @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.
|
* @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.
|
* 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 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
|
* @return
|
||||||
* - NULL if the physical address is invalid or not mapped to flash cache of the specified memory type.
|
* - 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.
|
* @brief SPI flash critical section enter function.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
typedef void (*spi_flash_guard_start_func_t)(void);
|
typedef void (*spi_flash_guard_start_func_t)(void);
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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 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
|
Flashing the partition table
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ Expressions, Math
|
||||||
Control
|
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 - *start for block*
|
||||||
- FOR variable = start TO end STEP value - *start for block with step*
|
- FOR variable = start TO end STEP value - *start for block with step*
|
||||||
- NEXT - *end of for block*
|
- NEXT - *end of for block*
|
||||||
|
|
|
@ -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.
|
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
|
Application Example
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -37,7 +39,7 @@ Short example of I2S configuration:
|
||||||
.intr_alloc_flags = 0, // default interrupt priority
|
.intr_alloc_flags = 0, // default interrupt priority
|
||||||
.dma_buf_count = 8,
|
.dma_buf_count = 8,
|
||||||
.dma_buf_len = 64,
|
.dma_buf_len = 64,
|
||||||
.use_apll = 0
|
.use_apll = false
|
||||||
};
|
};
|
||||||
|
|
||||||
static const i2s_pin_config_t pin_config = {
|
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
|
.intr_alloc_flags = 0, // default interrupt priority
|
||||||
.dma_buf_count = 8,
|
.dma_buf_count = 8,
|
||||||
.dma_buf_len = 64,
|
.dma_buf_len = 64,
|
||||||
.use_apll = 0
|
.use_apll = false
|
||||||
};
|
};
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
|
@ -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.)
|
* 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.
|
* 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.)
|
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.)
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ ESP-IDF 将会被下载到 ``~/esp/esp-idf``。
|
||||||
将 :example:`get-started/hello_world` 拷贝到 ``~/esp`` 目录: ::
|
将 :example:`get-started/hello_world` 拷贝到 ``~/esp`` 目录: ::
|
||||||
|
|
||||||
cd ~/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` 目录下有一系列示例工程,都可以按照上面的方法进行创建。
|
ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ static void bt_app_task_handler(void *arg)
|
||||||
void bt_app_task_start_up(void)
|
void bt_app_task_start_up(void)
|
||||||
{
|
{
|
||||||
bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ static void bt_app_task_handler(void *arg)
|
||||||
void bt_app_task_start_up(void)
|
void bt_app_task_start_up(void)
|
||||||
{
|
{
|
||||||
bt_app_task_queue = xQueueCreate(10, sizeof(bt_app_msg_t));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ void app_main()
|
||||||
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
|
||||||
.dma_buf_count = 6,
|
.dma_buf_count = 6,
|
||||||
.dma_buf_len = 60,
|
.dma_buf_len = 60,
|
||||||
.use_apll = 0,
|
.use_apll = false,
|
||||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
|
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
|
||||||
};
|
};
|
||||||
i2s_pin_config_t pin_config = {
|
i2s_pin_config_t pin_config = {
|
||||||
|
|
|
@ -94,6 +94,7 @@ static int tasks_info(int argc, char** argv)
|
||||||
ESP_LOGE(__func__, "failed to allocate buffer for vTaskList output");
|
ESP_LOGE(__func__, "failed to allocate buffer for vTaskList output");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
fputs("Task Name\tStatus\tPrio\tHWM\tTask Number\n", stdout);
|
||||||
vTaskList(task_list_buffer);
|
vTaskList(task_list_buffer);
|
||||||
fputs(task_list_buffer, stdout);
|
fputs(task_list_buffer, stdout);
|
||||||
free(task_list_buffer);
|
free(task_list_buffer);
|
||||||
|
|
300
tools/gen_esp_err_to_name.py
Executable file
300
tools/gen_esp_err_to_name.py
Executable 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()
|
|
@ -23,6 +23,7 @@
|
||||||
import argparse, sys, subprocess, re
|
import argparse, sys, subprocess, re
|
||||||
import os.path
|
import os.path
|
||||||
import pprint
|
import pprint
|
||||||
|
import operator
|
||||||
|
|
||||||
DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-"
|
DEFAULT_TOOLCHAIN_PREFIX = "xtensa-esp32-elf-"
|
||||||
|
|
||||||
|
@ -204,27 +205,30 @@ def print_detailed_sizes(sections, key, header):
|
||||||
"& rodata",
|
"& rodata",
|
||||||
"Total")
|
"Total")
|
||||||
print("%24s %10s %6s %6s %10s %8s %7s" % headings)
|
print("%24s %10s %6s %6s %10s %8s %7s" % headings)
|
||||||
for k in sorted(sizes.keys()):
|
result = {}
|
||||||
|
for k in (sizes.keys()):
|
||||||
v = sizes[k]
|
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
|
if ":" in k: # print subheadings for key of format archive:file
|
||||||
sh,k = k.split(":")
|
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],
|
print("%24s %10d %6d %6d %10d %8d %7d" % (k[:24],
|
||||||
data,
|
v["data"],
|
||||||
bss,
|
v["bss"],
|
||||||
iram,
|
v["iram"],
|
||||||
flash_text,
|
v["flash_text"],
|
||||||
flash_rodata,
|
v["flash_rodata"],
|
||||||
total))
|
v["total"]))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
Loading…
Reference in a new issue