diff --git a/.github/main.workflow b/.github/main.workflow deleted file mode 100644 index d23b686c5c..0000000000 --- a/.github/main.workflow +++ /dev/null @@ -1,22 +0,0 @@ -workflow "Sync issues to JIRA" { - on = "issues" - resolves = ["Sync to JIRA"] -} - -workflow "Sync issue and PR comments to JIRA" { - on = "issue_comment" - resolves = ["Sync to JIRA"] -} - -workflow "Sync PRs to JIRA" { - on = "pull_request" - resolves = ["Sync to JIRA"] -} - -action "Sync to JIRA" { - uses = "espressif/github-actions/sync_issues_to_jira@master" - secrets = ["GITHUB_TOKEN", "JIRA_URL", "JIRA_USER", "JIRA_PASS"] - env = { - JIRA_PROJECT = "IDFGH" - } -} diff --git a/.github/workflows/issue_comment.yml b/.github/workflows/issue_comment.yml new file mode 100644 index 0000000000..16069f1f13 --- /dev/null +++ b/.github/workflows/issue_comment.yml @@ -0,0 +1,16 @@ +on: issue_comment +name: Sync issue and PR comments to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 0000000000..3ead596888 --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,16 @@ +on: issues +name: Sync issues to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000000..324639e08b --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,16 @@ +on: pull_request +name: Sync PRs to JIRA +jobs: + syncToJIRA: + name: Sync to JIRA + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Sync to JIRA + uses: espressif/github-actions/sync_issues_to_jira@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + JIRA_PASS: ${{ secrets.JIRA_PASS }} + JIRA_PROJECT: IDFGH + JIRA_URL: ${{ secrets.JIRA_URL }} + JIRA_USER: ${{ secrets.JIRA_USER }} diff --git a/README.md b/README.md index 19c9980dd2..4be36b48d3 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ See the Getting Started guide links above for a detailed setup guide. This is a * Install host build dependencies mentioned in Getting Started guide. * Add `tools/` directory to the PATH -* Run `python -m pip install requirements.txt` to install Python dependencies +* Run `python -m pip install -r requirements.txt` to install Python dependencies ## Configuring the Project diff --git a/components/app_trace/gcov/gcov_rtio.c b/components/app_trace/gcov/gcov_rtio.c index d01d7c6b6b..a6008b4634 100644 --- a/components/app_trace/gcov/gcov_rtio.c +++ b/components/app_trace/gcov/gcov_rtio.c @@ -21,6 +21,7 @@ #include "soc/timer_periph.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" +#include "hal/timer_ll.h" #if CONFIG_ESP32_GCOV_ENABLE @@ -124,13 +125,13 @@ void esp_gcov_dump(void) #endif while (!esp_apptrace_host_is_connected(ESP_APPTRACE_DEST_TRAX)) { // to avoid complains that task watchdog got triggered for other tasks - TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG0.wdt_feed=1; - TIMERG0.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_feed(&TIMERG0); + timer_ll_wdt_set_protect(&TIMERG0, true); // to avoid reboot on INT_WDT - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; + timer_ll_wdt_set_protect(&TIMERG1, false); + timer_ll_wdt_feed(&TIMERG1); + timer_ll_wdt_set_protect(&TIMERG1, true); } esp_dbg_stub_gcov_dump_do(); diff --git a/components/app_trace/test/test_trace.c b/components/app_trace/test/test_trace.c index 3037ab4315..2e19e58083 100644 --- a/components/app_trace/test/test_trace.c +++ b/components/app_trace/test/test_trace.c @@ -145,56 +145,16 @@ static void esp_apptrace_test_timer_isr(void *arg) } tim_arg->data.wr_cnt++; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_apptrace_test_timer_isr_crash(void *arg) { esp_apptrace_test_timer_arg_t *tim_arg = (esp_apptrace_test_timer_arg_t *)arg; - if (tim_arg->group == 0) { - if (tim_arg->id == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->id == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); if (tim_arg->data.wr_cnt < ESP_APPTRACE_TEST_BLOCKS_BEFORE_CRASH) { uint32_t *ts = (uint32_t *)(tim_arg->data.buf + sizeof(uint32_t)); *ts = (uint32_t)esp_apptrace_test_ts_get();//xthal_get_ccount();//xTaskGetTickCount(); @@ -850,28 +810,8 @@ static void esp_sysview_test_timer_isr(void *arg) //ESP_APPTRACE_TEST_LOGI("tim-%d: IRQ %d/%d\n", tim_arg->id, tim_arg->group, tim_arg->timer); - if (tim_arg->group == 0) { - if (tim_arg->timer == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (tim_arg->group == 1) { - if (tim_arg->timer == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->id); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->id); } static void esp_sysviewtrace_test_task(void *p) diff --git a/components/bootloader_support/src/bootloader_init.c b/components/bootloader_support/src/bootloader_init.c index 2d4502434e..9456650f7e 100644 --- a/components/bootloader_support/src/bootloader_init.c +++ b/components/bootloader_support/src/bootloader_init.c @@ -73,6 +73,7 @@ #include "bootloader_flash_config.h" #include "flash_qio_mode.h" +#include "hal/timer_ll.h" extern int _bss_start; extern int _bss_end; @@ -202,8 +203,8 @@ static esp_err_t bootloader_main(void) /* disable watch dog here */ rtc_wdt_disable(); #endif - REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY, TIMG_WDT_WKEY_VALUE); - REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); + timer_ll_wdt_set_protect(&TIMERG0, false); + timer_ll_wdt_flashboot_en(&TIMERG0, false); #ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH const uint32_t spiconfig = ets_efuse_get_spiconfig(); diff --git a/components/cxx/test/test_cxx.cpp b/components/cxx/test/test_cxx.cpp index 0f5cce3318..0bf92f324b 100644 --- a/components/cxx/test/test_cxx.cpp +++ b/components/cxx/test/test_cxx.cpp @@ -319,3 +319,31 @@ TEST_CASE("can call std::function and bind", "[cxx]") #endif +/* Tests below are done in the compile time, don't actually get run. */ +/* Check whether a enumerator flag can be used in C++ */ + + +template __attribute__((unused)) static void test_binary_operators() +{ + T flag1 = (T)0; + T flag2 = (T)0; + flag1 = ~flag1; + flag1 = flag1 | flag2; + flag1 = flag1 & flag2; + flag1 = flag1 ^ flag2; + flag1 = flag1 >> 2; + flag1 = flag1 << 2; + flag1 |= flag2; + flag1 &= flag2; + flag1 ^= flag2; + flag1 >>= 2; + flag1 <<= 2; +} + +//Add more types here. If any flags cannot pass the build, use FLAG_ATTR in esp_attr.h +#include "hal/timer_types.h" +template void test_binary_operators(); + + + + diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index 0bb3aee6bf..cf1f7e7c1a 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -18,6 +18,8 @@ set(srcs "timer.c" "uart.c") +set(includes "include") + if(CONFIG_IDF_TARGET_ESP32) # SDMMC and MCPWM are in ESP32 only. list(APPEND srcs "mcpwm.c" @@ -27,12 +29,14 @@ if(CONFIG_IDF_TARGET_ESP32) endif() if(CONFIG_IDF_TARGET_ESP32S2BETA) - list(APPEND srcs "${CONFIG_IDF_TARGET}/rtc_tempsensor.c" - "${CONFIG_IDF_TARGET}/rtc_touchpad.c") + list(APPEND srcs "esp32s2beta/rtc_tempsensor.c" + "esp32s2beta/rtc_touchpad.c") + # currently only S2 beta has its own target-specific includes + list(APPEND includes "esp32s2beta/include") endif() idf_component_register(SRCS "${srcs}" - INCLUDE_DIRS "include" "${CONFIG_IDF_TARGET}/include" + INCLUDE_DIRS ${includes} PRIV_INCLUDE_DIRS "include/driver" REQUIRES esp_ringbuf soc) #cannot totally hide soc headers, since there are a lot arguments in the driver are chip-dependent diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index c946226614..bb7e577547 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -53,6 +53,13 @@ typedef enum { LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock (80Mhz) */ } ledc_clk_src_t; +typedef enum { + LEDC_AUTO_CLK, /*!< The driver will automatically select the source clock(REF_TICK or APB) based on the giving resolution and duty parameter when init the timer*/ + LEDC_USE_REF_TICK, /*!< LEDC timer select REF_TICK clock as source clock*/ + LEDC_USE_APB_CLK, /*!< LEDC timer select APB clock as source clock*/ + LEDC_USE_RTC8M_CLK, /*!< LEDC timer select RTC8M_CLK as source clock. Only for low speed channels and this parameter must be the same for all low speed channels*/ +} ledc_clk_cfg_t; + typedef enum { LEDC_TIMER_0 = 0, /*!< LEDC timer 0 */ LEDC_TIMER_1, /*!< LEDC timer 1 */ @@ -129,6 +136,9 @@ typedef struct { }; ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3) */ uint32_t freq_hz; /*!< LEDC timer frequency (Hz) */ + ledc_clk_cfg_t clk_cfg; /*!< Configure LEDC source clock. + For low speed channels and high speed channels, you can specify the source clock using LEDC_USE_REF_TICK, LEDC_USE_APB_CLK or LEDC_AUTO_CLK. + For low speed channels, you can also specify the source clock using LEDC_USE_RTC8M_CLK, in this case, all low speed channel's source clock must be RTC8M_CLK*/ } ledc_timer_config_t; typedef intr_handle_t ledc_isr_handle_t; diff --git a/components/driver/include/driver/timer.h b/components/driver/include/driver/timer.h index b694bc8393..c760fb3898 100644 --- a/components/driver/include/driver/timer.h +++ b/components/driver/include/driver/timer.h @@ -19,6 +19,7 @@ #include "soc/soc.h" #include "soc/timer_periph.h" #include "esp_intr_alloc.h" +#include "hal/timer_types.h" #ifdef __cplusplus extern "C" { @@ -36,15 +37,6 @@ typedef enum { TIMER_GROUP_MAX, } timer_group_t; -/** - * @brief Select a hardware timer from timer groups - */ -typedef enum { - TIMER_0 = 0, /*!size); - bool write_protect = false; esp_err_t err = spiflash_start(chip); if (err != ESP_OK) { return err; } - err = esp_flash_get_chip_write_protect(chip, &write_protect); - - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - - if (err == ESP_OK) { - err = chip->chip_drv->erase_chip(chip); - } - + err = chip->chip_drv->erase_chip(chip); return spiflash_end(chip, err); } @@ -292,7 +282,6 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui CHECK_WRITE_ADDRESS(chip, start, len); uint32_t block_erase_size = chip->chip_drv->erase_block == NULL ? 0 : chip->chip_drv->block_erase_size; uint32_t sector_size = chip->chip_drv->sector_size; - bool write_protect = false; if (sector_size == 0 || (block_erase_size % sector_size) != 0) { return ESP_ERR_FLASH_NOT_INITIALISED; @@ -310,16 +299,9 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } - // Check for write protection on whole chip - if (chip->chip_drv->get_chip_write_protect != NULL) { - err = chip->chip_drv->get_chip_write_protect(chip, &write_protect); - if (err == ESP_OK && write_protect) { - err = ESP_ERR_FLASH_PROTECTED; - } - } - // Check for write protected regions overlapping the erase region - if (err == ESP_OK && chip->chip_drv->get_protected_regions != NULL && chip->chip_drv->num_protectable_regions > 0) { + if (chip->chip_drv->get_protected_regions != NULL && + chip->chip_drv->num_protectable_regions > 0) { uint64_t protected = 0; err = chip->chip_drv->get_protected_regions(chip, &protected); if (err == ESP_OK && protected != 0) { @@ -360,10 +342,10 @@ esp_err_t IRAM_ATTR esp_flash_erase_region(esp_flash_t *chip, uint32_t start, ui return err; } -esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protected) +esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *out_write_protected) { VERIFY_OP(get_chip_write_protect); - if (write_protected == NULL) { + if (out_write_protected == NULL) { return ESP_ERR_INVALID_ARG; } @@ -372,7 +354,7 @@ esp_err_t IRAM_ATTR esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *wr return err; } - err = chip->chip_drv->get_chip_write_protect(chip, write_protected); + err = chip->chip_drv->get_chip_write_protect(chip, out_write_protected); return spiflash_end(chip, err); } diff --git a/components/spi_flash/include/esp_flash.h b/components/spi_flash/include/esp_flash.h index efcfccc247..4a7c184de4 100644 --- a/components/spi_flash/include/esp_flash.h +++ b/components/spi_flash/include/esp_flash.h @@ -160,8 +160,6 @@ esp_err_t esp_flash_get_chip_write_protect(esp_flash_t *chip, bool *write_protec * @note Correct behaviour of this function depends on the SPI flash chip model and chip_drv in use (via the 'chip->drv' * field). * - * If write protection is enabled, destructive operations will fail with ESP_ERR_FLASH_PROTECTED. - * * Some SPI flash chips may require a power cycle before write protect status can be cleared. Otherwise, * write protection can be removed via a follow-up call to this function. * diff --git a/components/spi_flash/include/memspi_host_driver.h b/components/spi_flash/include/memspi_host_driver.h index 2347398aa1..434361d970 100644 --- a/components/spi_flash/include/memspi_host_driver.h +++ b/components/spi_flash/include/memspi_host_driver.h @@ -62,6 +62,8 @@ esp_err_t memspi_host_init_pointers(spi_flash_host_driver_t *host, memspi_host_d ******************************************************************************/ /** + * @brief Read the Status Register read from RDSR (05h). + * * High speed implementation of RDID through memspi interface relying on the * ``common_command``. * diff --git a/components/spi_flash/include/spi_flash_chip_driver.h b/components/spi_flash/include/spi_flash_chip_driver.h index fd5c1e4c92..9dd8ffa971 100644 --- a/components/spi_flash/include/spi_flash_chip_driver.h +++ b/components/spi_flash/include/spi_flash_chip_driver.h @@ -90,10 +90,10 @@ struct spi_flash_chip_t { uint32_t block_erase_size; /* Optimal (fastest) block size for multi-sector erases on this chip */ /* Read the write protect status of the entire chip. */ - esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *write_protected); + esp_err_t (*get_chip_write_protect)(esp_flash_t *chip, bool *out_write_protected); /* Set the write protect status of the entire chip. */ - esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool write_protect_chip); + esp_err_t (*set_chip_write_protect)(esp_flash_t *chip, bool chip_write_protect); /* Number of individually write protectable regions on this chip. Range 0-63. */ uint8_t num_protectable_regions; @@ -135,9 +135,6 @@ struct spi_flash_chip_t { /* Perform an encrypted write to the chip, using internal flash encryption hardware. */ esp_err_t (*write_encrypted)(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); - /* Set the write enable flag. This function is called internally by other functions in this structure, before a destructive - operation takes place. */ - esp_err_t (*set_write_protect)(esp_flash_t *chip, bool write_protect); /* Wait for the SPI flash chip to be idle (any write operation to be complete.) This function is both called from the higher-level API functions, and from other functions in this structure. diff --git a/components/spi_flash/include/spi_flash_chip_generic.h b/components/spi_flash/include/spi_flash_chip_generic.h index 676e173111..672ca6550b 100644 --- a/components/spi_flash/include/spi_flash_chip_generic.h +++ b/components/spi_flash/include/spi_flash_chip_generic.h @@ -66,7 +66,7 @@ esp_err_t spi_flash_chip_generic_reset(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); /** - * @brief Erase chip by using the generic erase chip (C7h) command. + * @brief Erase chip by using the generic erase chip command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @@ -77,7 +77,7 @@ esp_err_t spi_flash_chip_generic_detect_size(esp_flash_t *chip, uint32_t *size); esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); /** - * @brief Erase sector by using the generic sector erase (20h) command. + * @brief Erase sector by using the generic sector erase command. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the sector to erase @@ -89,7 +89,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip); esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address); /** - * @brief Erase block by using the generic 64KB block erase (D8h) command + * @brief Erase block by the generic 64KB block erase command * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param start_address Start address of the block to erase @@ -114,7 +114,7 @@ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_a esp_err_t spi_flash_chip_generic_read(esp_flash_t *chip, void *buffer, uint32_t address, uint32_t length); /** - * @brief Perform a page program using the page program (02h) command. + * @brief Perform a page program using the page program command. * * @note Length of each call should not excced the limitation in * ``chip->host->max_write_bytes``. This function is called in @@ -163,7 +163,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, uint32_t address, uint32_t length); /** - * @brief Send the write enable (06h) command and verify the expected bit (1) in + * @brief Send the write enable or write disable command and verify the expected bit (1) in * the status register is set. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. @@ -171,13 +171,26 @@ spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void *buffer, ui * * @return * - ESP_OK if success - * - or other error passed from the ``wait_idle``, ``read_status`` or ``set_write_protect`` function of host driver + * - or other error passed from the ``wait_idle``, ``read_status`` or + * ``set_write_protect`` function of host driver */ -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect); +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect); /** - * @brief Read flash status via the RDSR command (05h) and wait for bit 0 (write - * in progress bit) to be cleared. + * @brief Check whether WEL (write enable latch) bit is set in the Status Register read from RDSR. + * + * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. + * @param out_write_protect Output of whether the write protect is set. + * + * @return + * - ESP_OK if success + * - or other error passed from the ``read_status`` function of host driver + */ +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect); + +/** + * @brief Read flash status via the RDSR command and wait for bit 0 (write in + * progress bit) to be cleared. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * @param timeout_ms Time to wait before timeout, in ms. @@ -232,13 +245,15 @@ extern const spi_flash_chip_t esp_flash_chip_generic; esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ms); /** - * @brief Utility function for set_read_mode chip_drv function + * @brief Utility function for set_read_mode chip_drv function. If required, + * set and check the QE bit in the flash chip to enable the QIO/QOUT mode. * - * Most setting of read mode follows a common pattern, except for how to enable Quad I/O modes (QIO/QOUT). - * These use different commands to read/write the status register, and a different bit is set/cleared. + * Most chip QE enable follows a common pattern, though commands to read/write + * the status register may be different, as well as the position of QE bit. * - * This is a generic utility function to implement set_read_mode() for this pattern. Also configures host - * registers via spi_flash_common_configure_host_read_mode(). + * Registers to actually do Quad transtions and command to be sent in reading + * should also be configured via + * spi_flash_chip_generic_config_host_read_mode(). * * @param qe_rdsr_command SPI flash command to read status register * @param qe_wrsr_command SPI flash command to write status register @@ -250,7 +265,11 @@ esp_err_t spi_flash_generic_wait_host_idle(esp_flash_t *chip, uint32_t *timeout_ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_command, uint8_t qe_wrsr_command, uint8_t qe_sr_bitwidth, unsigned qe_sr_bit); /** - * @brief Configure the host to use the specified read mode set in the ``chip->read_mode``. + * @brief Configure the host registers to use the specified read mode set in + * the ``chip->read_mode``. + * + * Usually called in chip_drv read() functions before actual reading + * transactions. Also prepare the command to be sent in read functions. * * @param chip Pointer to SPI flash chip to use. If NULL, esp_flash_default_chip is substituted. * diff --git a/components/spi_flash/spi_flash_chip_generic.c b/components/spi_flash/spi_flash_chip_generic.c index 0e80e8eb1d..8bbb9d1374 100644 --- a/components/spi_flash/spi_flash_chip_generic.c +++ b/components/spi_flash/spi_flash_chip_generic.c @@ -82,7 +82,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) { esp_err_t err; - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -102,7 +102,7 @@ esp_err_t spi_flash_chip_generic_erase_chip(esp_flash_t *chip) esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -122,7 +122,7 @@ esp_err_t spi_flash_chip_generic_erase_sector(esp_flash_t *chip, uint32_t start_ esp_err_t spi_flash_chip_generic_erase_block(esp_flash_t *chip, uint32_t start_address) { - esp_err_t err = chip->chip_drv->set_write_protect(chip, false); + esp_err_t err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->wait_idle(chip, DEFAULT_IDLE_TIMEOUT); } @@ -185,7 +185,7 @@ esp_err_t spi_flash_chip_generic_write(esp_flash_t *chip, const void *buffer, ui page_len = page_size - (address % page_size); } - err = chip->chip_drv->set_write_protect(chip, false); + err = chip->chip_drv->set_chip_write_protect(chip, false); if (err == ESP_OK) { err = chip->chip_drv->program_page(chip, buffer, address, page_len); @@ -205,7 +205,7 @@ esp_err_t spi_flash_chip_generic_write_encrypted(esp_flash_t *chip, const void * return ESP_ERR_FLASH_UNSUPPORTED_HOST; // TODO } -esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_protect) +esp_err_t spi_flash_chip_generic_set_write_protect(esp_flash_t *chip, bool write_protect) { esp_err_t err = ESP_OK; @@ -215,17 +215,26 @@ esp_err_t spi_flash_chip_generic_write_enable(esp_flash_t *chip, bool write_prot chip->host->set_write_protect(chip->host, write_protect); } + bool wp_read; + err = chip->chip_drv->get_chip_write_protect(chip, &wp_read); + if (err == ESP_OK && wp_read != write_protect) { + // WREN flag has not been set! + err = ESP_ERR_NOT_FOUND; + } + return err; +} + +esp_err_t spi_flash_chip_generic_get_write_protect(esp_flash_t *chip, bool *out_write_protect) +{ + esp_err_t err = ESP_OK; uint8_t status; + assert(out_write_protect!=NULL); err = chip->host->read_status(chip->host, &status); if (err != ESP_OK) { return err; } - if ((status & SR_WREN) == 0) { - // WREN flag has not been set! - err = ESP_ERR_NOT_FOUND; - } - + *out_write_protect = ((status & SR_WREN) == 0); return err; } @@ -329,7 +338,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm ESP_EARLY_LOGV(TAG, "set_read_mode: status before 0x%x", sr); if ((sr & qe_sr_bit) == 0) { //some chips needs the write protect to be disabled before writing to Status Register - chip->chip_drv->set_write_protect(chip, false); + chip->chip_drv->set_chip_write_protect(chip, false); sr |= qe_sr_bit; spi_flash_trans_t t = { @@ -354,7 +363,7 @@ esp_err_t spi_flash_common_set_read_mode(esp_flash_t *chip, uint8_t qe_rdsr_comm return ESP_ERR_FLASH_NO_RESPONSE; } - chip->chip_drv->set_write_protect(chip, true); + chip->chip_drv->set_chip_write_protect(chip, true); } } return ESP_OK; @@ -383,8 +392,8 @@ const spi_flash_chip_t esp_flash_chip_generic = { .block_erase_size = 64 * 1024, // TODO: figure out if generic chip-wide protection bits exist across some manufacturers - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // Chip write protection regions do not appear to be standardised // at all, this is implemented in chip-specific drivers only. @@ -399,7 +408,6 @@ const spi_flash_chip_t esp_flash_chip_generic = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_generic_set_read_mode, }; diff --git a/components/spi_flash/spi_flash_chip_issi.c b/components/spi_flash/spi_flash_chip_issi.c index d32c3a1929..71684ec195 100644 --- a/components/spi_flash/spi_flash_chip_issi.c +++ b/components/spi_flash/spi_flash_chip_issi.c @@ -57,9 +57,8 @@ const spi_flash_chip_t esp_flash_chip_issi = { .sector_size = 4 * 1024, .block_erase_size = 64 * 1024, - // TODO: support get/set chip write protect for ISSI flash - .get_chip_write_protect = NULL, - .set_chip_write_protect = NULL, + .get_chip_write_protect = spi_flash_chip_generic_get_write_protect, + .set_chip_write_protect = spi_flash_chip_generic_set_write_protect, // TODO support protected regions on ISSI flash .num_protectable_regions = 0, @@ -73,7 +72,6 @@ const spi_flash_chip_t esp_flash_chip_issi = { .page_size = 256, .write_encrypted = spi_flash_chip_generic_write_encrypted, - .set_write_protect = spi_flash_chip_generic_write_enable, .wait_idle = spi_flash_chip_generic_wait_idle, .set_read_mode = spi_flash_chip_issi_set_read_mode, }; diff --git a/components/spi_flash/test/test_esp_flash.c b/components/spi_flash/test/test_esp_flash.c index 49d144c9c1..19a93c8bf4 100644 --- a/components/spi_flash/test/test_esp_flash.c +++ b/components/spi_flash/test/test_esp_flash.c @@ -366,6 +366,36 @@ TEST_CASE("SPI flash erase large region", "[esp_flash]") #endif } +static void test_write_protection(esp_flash_t* chip) +{ + bool wp = true; + esp_err_t ret = ESP_OK; + ret = esp_flash_get_chip_write_protect(chip, &wp); + TEST_ESP_OK(ret); + + for (int i = 0; i < 4; i ++) { + bool wp_write = !wp; + ret = esp_flash_set_chip_write_protect(chip, wp_write); + TEST_ESP_OK(ret); + + bool wp_read; + ret = esp_flash_get_chip_write_protect(chip, &wp_read); + TEST_ESP_OK(ret); + TEST_ASSERT(wp_read == wp_write); + wp = wp_read; + } +} + +TEST_CASE("Test esp_flash can enable/disable write protetion", "[esp_flash]") +{ + test_write_protection(NULL); +#ifndef SKIP_EXTENDED_CHIP_TEST + setup_new_chip(TEST_SPI_READ_MODE, TEST_SPI_SPEED); + test_write_protection(test_chip); + teardown_test_chip(); +#endif +} + static const uint8_t large_const_buffer[16400] = { 203, // first byte 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, @@ -491,5 +521,4 @@ static void test_write_large_buffer(esp_flash_t *chip, const uint8_t *source, si write_large_buffer(chip, part, source, length); read_and_check(chip, part, source, length); -} - +} \ No newline at end of file diff --git a/components/spi_flash/test/test_spi_flash.c b/components/spi_flash/test/test_spi_flash.c index f5143b21c1..a9ba4e3107 100644 --- a/components/spi_flash/test/test_spi_flash.c +++ b/components/spi_flash/test/test_spi_flash.c @@ -112,8 +112,8 @@ typedef struct { static void IRAM_ATTR timer_isr(void* varg) { block_task_arg_t* arg = (block_task_arg_t*) varg; - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0); + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_0); ets_delay_us(arg->delay_time_us); arg->repeat_count++; } diff --git a/components/tcp_transport/CMakeLists.txt b/components/tcp_transport/CMakeLists.txt index 9d5028a1b6..fe7e71bf31 100644 --- a/components/tcp_transport/CMakeLists.txt +++ b/components/tcp_transport/CMakeLists.txt @@ -5,5 +5,5 @@ idf_component_register(SRCS "transport.c" "transport_utils.c" "transport_strcasestr.c" INCLUDE_DIRS "include" - PRIVATE_INCLUDE_DIRS "private_include" + PRIV_INCLUDE_DIRS "private_include" REQUIRES lwip esp-tls) diff --git a/components/tcp_transport/include/esp_transport_ssl.h b/components/tcp_transport/include/esp_transport_ssl.h index c69749b4b3..a83e93882d 100644 --- a/components/tcp_transport/include/esp_transport_ssl.h +++ b/components/tcp_transport/include/esp_transport_ssl.h @@ -16,6 +16,7 @@ #define _ESP_TRANSPORT_SSL_H_ #include "esp_transport.h" +#include "esp_tls.h" #ifdef __cplusplus extern "C" { @@ -111,6 +112,20 @@ void esp_transport_ssl_set_client_key_data_der(esp_transport_handle_t t, const c */ void esp_transport_ssl_skip_common_name_check(esp_transport_handle_t t); +/** + * @brief Set PSK key and hint for PSK server/client verification in esp-tls component. + * Important notes: + * - This function stores the pointer to data, rather than making a copy. + * So this data must remain valid until after the connection is cleaned up + * - ESP_TLS_PSK_VERIFICATION config option must be enabled in menuconfig + * - certificate verification takes priority so it must not be configured + * to enable PSK method. + * + * @param t ssl transport + * @param[in] psk_hint_key psk key and hint structure defined in esp_tls.h + */ +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key); + #ifdef __cplusplus } #endif diff --git a/components/tcp_transport/transport_ssl.c b/components/tcp_transport/transport_ssl.c index f8543e92e0..d5b13490ac 100644 --- a/components/tcp_transport/transport_ssl.c +++ b/components/tcp_transport/transport_ssl.c @@ -169,6 +169,14 @@ void esp_transport_ssl_enable_global_ca_store(esp_transport_handle_t t) } } +void esp_transport_ssl_set_psk_key_hint(esp_transport_handle_t t, const psk_hint_key_t* psk_hint_key) +{ + transport_ssl_t *ssl = esp_transport_get_context_data(t); + if (t && ssl) { + ssl->cfg.psk_hint_key = psk_hint_key; + } +} + void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len) { transport_ssl_t *ssl = esp_transport_get_context_data(t); diff --git a/components/vfs/README.rst b/components/vfs/README.rst index 20bc9770e7..c296e81a68 100644 --- a/components/vfs/README.rst +++ b/components/vfs/README.rst @@ -66,9 +66,29 @@ Case 2: API functions are declared with an extra context pointer (the FS driver Synchronous input/output multiplexing ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you want to use synchronous input/output multiplexing by :cpp:func:`select` -then you need to register VFS with the functions :cpp:func:`start_select` and -:cpp:func:`end_select` similar to the following example: +Synchronous input/output multiplexing by :cpp:func:`select` is supported in the VFS component. The implementation +works in the following way. + +1. :cpp:func:`select` is called with file descriptors which could belong to various VFS drivers. +2. The file descriptors are divided into groups each belonging to one VFS driver. +3. The file descriptors belonging to non-socket VFS drivers are handed over to the given VFS drivers by :cpp:func:`start_select` + described later on this page. This function represents the driver-specific implementation of :cpp:func:`select` for + the given driver. This should be a non-blocking call which means the function should immediately return after setting up + the environment for checking events related to the given file descriptors. +4. The file descriptors belonging to the socket VFS driver are handed over to the socket driver by + :cpp:func:`socket_select` described later on this page. This is a blocking call which means that it will return only + if there is an event related to socket file descriptors or a non-socket driver signals :cpp:func:`socket_select` + to exit. +5. Results are collected from each VFS driver and all drivers are stopped by deinitiazation + of the environment for checking events. +6. The :cpp:func:`select` call ends and returns the appropriate results. + +Non-socket VFS drivers +"""""""""""""""""""""" + +If you want to use :cpp:func:`select` with a file descriptor belonging to a non-socket VFS driver +then you need to register the driver with functions :cpp:func:`start_select` and +:cpp:func:`end_select` similarly to the following example: .. highlight:: c @@ -81,25 +101,57 @@ then you need to register VFS with the functions :cpp:func:`start_select` and :cpp:func:`start_select` is called for setting up the environment for detection of read/write/error conditions on file descriptors belonging to the -given VFS. :cpp:func:`end_select` is called to stop/deinitialize/free the -environment which was setup by :cpp:func:`start_select`. Please refer to the +given VFS driver. + +:cpp:func:`end_select` is called to stop/deinitialize/free the +environment which was setup by :cpp:func:`start_select`. + +Please refer to the reference implementation for the UART peripheral in :component_file:`vfs/vfs_uart.c` and most particularly to the functions :cpp:func:`esp_vfs_dev_uart_register`, :cpp:func:`uart_start_select`, and -:cpp:func:`uart_end_select`. +:cpp:func:`uart_end_select` for more information. Please check the following examples that demonstrate the use of :cpp:func:`select` with VFS file descriptors: -- :example:`peripherals/uart_select` -- :example:`system/select` + - :example:`peripherals/uart/uart_select` + - :example:`system/select` -<<<<<<< HEAD -If :cpp:func:`select` is used for socket file descriptors only then one can -enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option which can reduce the code -======= -If you use :cpp:func:`select` for socket file descriptors, you can enable the :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code ->>>>>>> afc2fdf27... Review all the files in the esp-idf's api_ref/storage directory -size and improve performance. +Socket VFS drivers +"""""""""""""""""" +A socket VFS driver is using its own internal implementation of :cpp:func:`select` and non-socket VFS drivers notify +it upon read/write/error conditions. + +A socket VFS driver needs to be registered with the following functions defined: + +.. highlight:: c + +:: + + // In definition of esp_vfs_t: + .socket_select = &lwip_select, + .get_socket_select_semaphore = &lwip_get_socket_select_semaphore, + .stop_socket_select = &lwip_stop_socket_select, + .stop_socket_select_isr = &lwip_stop_socket_select_isr, + // ... other members initialized + +:cpp:func:`socket_select` is the internal implementation of :cpp:func:`select` for the socket driver. It works only +with file descriptors belonging to the socket VFS. + +:cpp:func:`get_socket_select_semaphore` returns the signalization object (semaphore) which will be used in non-socket +drivers to stop the waiting in :cpp:func:`socket_select`. + +:cpp:func:`stop_socket_select` call is used to stop the waiting in :cpp:func:`socket_select` by passing the object +returned by :cpp:func:`get_socket_select_semaphore`. + +:cpp:func:`stop_socket_select_isr` has the same functionality as :cpp:func:`stop_socket_select` but it can be used +from ISR. + +Please see :component_file:`lwip/port/esp32/vfs_lwip.c` for a reference socket driver implementation using LWIP. + +.. note:: + If you use :cpp:func:`select` for socket file descriptors only then you can enable the + :envvar:`CONFIG_LWIP_USE_ONLY_LWIP_SELECT` option to reduce the code size and improve performance. Paths ----- diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index e4eafb417c..2f39ca62f5 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -236,7 +236,7 @@ typedef struct #endif // CONFIG_VFS_SUPPORT_TERMIOS /** start_select is called for setting up synchronous I/O multiplexing of the desired file descriptors in the given VFS */ - esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem); + esp_err_t (*start_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t sem, void **end_select_args); /** socket select function for socket FDs with the functionality of POSIX select(); this should be set only for the socket VFS */ int (*socket_select)(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout); /** called by VFS to interrupt the socket_select call when select is activated from a non-socket VFS driver; set only for the socket driver */ @@ -246,7 +246,7 @@ typedef struct /** end_select is called to stop the I/O multiplexing and deinitialize the environment created by start_select for the given VFS */ void* (*get_socket_select_semaphore)(void); /** get_socket_select_semaphore returns semaphore allocated in the socket driver; set only for the socket driver */ - void (*end_select)(void); + esp_err_t (*end_select)(void *end_select_args); } esp_vfs_t; diff --git a/components/vfs/test/test_vfs_select.c b/components/vfs/test/test_vfs_select.c index bea17242e1..2ce2270b8a 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -31,6 +31,16 @@ typedef struct { xSemaphoreHandle sem; } test_task_param_t; +typedef struct { + fd_set *rdfds; + fd_set *wrfds; + fd_set *errfds; + int maxfds; + struct timeval *tv; + int select_ret; + xSemaphoreHandle sem; +} test_select_task_param_t; + static const char message[] = "Hello world!"; static int open_dummy_socket(void) @@ -420,73 +430,121 @@ TEST_CASE("poll() timeout", "[vfs]") deinit(uart_fd, socket_fd); } -static void select_task(void *param) +static void select_task(void *task_param) { - const test_task_param_t *test_task_param = param; - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000, - }; + const test_select_task_param_t *param = task_param; - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(test_task_param->fd, &rfds); + int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv); + TEST_ASSERT_EQUAL(param->select_ret, s); - int s = select(test_task_param->fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //timeout - - if (test_task_param->sem) { - xSemaphoreGive(test_task_param->sem); + if (param->sem) { + xSemaphoreGive(param->sem); } vTaskDelete(NULL); } -TEST_CASE("concurent selects work", "[vfs]") +static void inline start_select_task(test_select_task_param_t *param) { - struct timeval tv = { - .tv_sec = 0, - .tv_usec = 100000,//irrelevant - }; + xTaskCreate(select_task, "select_task", 4*1024, (void *) param, 5, NULL); +} +TEST_CASE("concurrent selects work", "[vfs]") +{ int uart_fd, socket_fd; init(&uart_fd, &socket_fd); - const int dummy_socket_fd = open_dummy_socket(); - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(uart_fd, &rfds); + { + // Two tasks will wait for the same UART FD for reading and they will time-out - test_task_param_t test_task_param = { - .fd = uart_fd, - .sem = xSemaphoreCreateBinary(), - }; - TEST_ASSERT_NOT_NULL(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + fd_set rdfds1; + FD_ZERO(&rdfds1); + FD_SET(uart_fd, &rdfds1); - int s = select(uart_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(-1, s); //this select should fail because two selects are accessing UART - //(the other one is waiting for the timeout) - TEST_ASSERT_EQUAL(EINTR, errno); + test_select_task_param_t param = { + .rdfds = &rdfds1, + .wrfds = NULL, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); - FD_ZERO(&rfds); - FD_SET(socket_fd, &rfds); + start_select_task(¶m); + vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() - test_task_param.fd = dummy_socket_fd; + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(0, s); // timeout here as well - xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL); - vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select() + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + } - s = select(socket_fd + 1, &rfds, NULL, NULL, &tv); - TEST_ASSERT_EQUAL(0, s); //this select should timeout as well as the concurrent one because - //concurrent socket select should work + { + // One tasks waits for UART reading and one for writing. The former will be successful and latter will + // time-out. - TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS)); - vSemaphoreDelete(test_task_param.sem); + struct timeval tv = { + .tv_sec = 0, + .tv_usec = 100000, + }; + + fd_set wrfds1; + FD_ZERO(&wrfds1); + FD_SET(uart_fd, &wrfds1); + + test_select_task_param_t param = { + .rdfds = NULL, + .wrfds = &wrfds1, + .errfds = NULL, + .maxfds = uart_fd + 1, + .tv = &tv, + .select_ret = 0, // expected timeout + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(param.sem); + + start_select_task(¶m); + + fd_set rdfds2; + FD_ZERO(&rdfds2); + FD_SET(uart_fd, &rdfds2); + FD_SET(socket_fd, &rdfds2); + FD_SET(dummy_socket_fd, &rdfds2); + + const test_task_param_t send_param = { + .fd = uart_fd, + .delay_ms = 50, + .sem = xSemaphoreCreateBinary(), + }; + TEST_ASSERT_NOT_NULL(send_param.sem); + start_task(&send_param); // This task will write to UART which will be detected by select() + + int s = select(MAX(MAX(uart_fd, dummy_socket_fd), socket_fd) + 1, &rdfds2, NULL, NULL, &tv); + TEST_ASSERT_EQUAL(1, s); + TEST_ASSERT(FD_ISSET(uart_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(socket_fd, &rdfds2)); + TEST_ASSERT_UNLESS(FD_ISSET(dummy_socket_fd, &rdfds2)); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(param.sem); + + TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(send_param.sem, 1000 / portTICK_PERIOD_MS)); + vSemaphoreDelete(send_param.sem); + } deinit(uart_fd, socket_fd); close(dummy_socket_fd); diff --git a/components/vfs/vfs.c b/components/vfs/vfs.c index c604b09738..681a9ec614 100644 --- a/components/vfs/vfs.c +++ b/components/vfs/vfs.c @@ -794,13 +794,16 @@ int truncate(const char *path, off_t length) return ret; } -static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple) +static void call_end_selects(int end_index, const fds_triple_t *vfs_fds_triple, void **driver_args) { for (int i = 0; i < end_index; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); const fds_triple_t *item = &vfs_fds_triple[i]; if (vfs && vfs->vfs.end_select && item->isset) { - vfs->vfs.end_select(); + esp_err_t err = vfs->vfs.end_select(driver_args[i]); + if (err != ESP_OK) { + ESP_LOGD(TAG, "end_select failed: %s", esp_err_to_name(err)); + } } } } @@ -855,6 +858,8 @@ static void esp_vfs_log_fd_set(const char *fds_name, const fd_set *fds) int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, struct timeval *timeout) { + // NOTE: Please see the "Synchronous input/output multiplexing" section of the ESP-IDF Programming Guide + // (API Reference -> Storage -> Virtual Filesystem) for a general overview of the implementation of VFS select(). int ret = 0; struct _reent* r = __getreent(); @@ -947,6 +952,15 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds } } + void **driver_args = calloc(s_vfs_count, sizeof(void *)); + + if (driver_args == NULL) { + free(vfs_fds_triple); + __errno_r(r) = ENOMEM; + ESP_LOGD(TAG, "calloc is unsuccessful for driver args"); + return -1; + } + for (int i = 0; i < s_vfs_count; ++i) { const vfs_entry_t *vfs = get_vfs_for_index(i); fds_triple_t *item = &vfs_fds_triple[i]; @@ -958,16 +972,18 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds esp_vfs_log_fd_set("readfds", &item->readfds); esp_vfs_log_fd_set("writefds", &item->writefds); esp_vfs_log_fd_set("errorfds", &item->errorfds); - esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem); + esp_err_t err = vfs->vfs.start_select(nfds, &item->readfds, &item->writefds, &item->errorfds, sel_sem, + driver_args + i); if (err != ESP_OK) { - call_end_selects(i, vfs_fds_triple); + call_end_selects(i, vfs_fds_triple, driver_args); (void) set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); if (sel_sem.is_sem_local && sel_sem.sem) { vSemaphoreDelete(sel_sem.sem); sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); __errno_r(r) = EINTR; ESP_LOGD(TAG, "start_select failed: %s", esp_err_to_name(err)); return -1; @@ -1006,7 +1022,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds xSemaphoreTake(sel_sem.sem, ticks_to_wait); } - call_end_selects(s_vfs_count, vfs_fds_triple); // for VFSs for start_select was called before + call_end_selects(s_vfs_count, vfs_fds_triple, driver_args); // for VFSs for start_select was called before if (ret >= 0) { ret += set_global_fd_sets(vfs_fds_triple, s_vfs_count, readfds, writefds, errorfds); } @@ -1015,6 +1031,7 @@ int esp_vfs_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds sel_sem.sem = NULL; } free(vfs_fds_triple); + free(driver_args); ESP_LOGD(TAG, "esp_vfs_select returns %d", ret); esp_vfs_log_fd_set("readfds", readfds); diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index 30ab4f8f9e..c9af488460 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -115,20 +115,21 @@ static vfs_uart_context_t* s_ctx[UART_NUM] = { #endif }; -/* Lock ensuring that uart_select is used from only one task at the time */ -static _lock_t s_one_select_lock; +typedef struct { + esp_vfs_select_sem_t select_sem; + fd_set *readfds; + fd_set *writefds; + fd_set *errorfds; + fd_set readfds_orig; + fd_set writefds_orig; + fd_set errorfds_orig; +} uart_select_args_t; -static esp_vfs_select_sem_t _select_sem = {.sem = NULL}; -static fd_set *_readfds = NULL; -static fd_set *_writefds = NULL; -static fd_set *_errorfds = NULL; -static fd_set *_readfds_orig = NULL; -static fd_set *_writefds_orig = NULL; -static fd_set *_errorfds_orig = NULL; - - -static void uart_end_select(void); +static uart_select_args_t **s_registered_selects = NULL; +static int s_registered_select_num = 0; +static portMUX_TYPE s_registered_select_lock = portMUX_INITIALIZER_UNLOCKED; +static esp_err_t uart_end_select(void *end_select_args); static int uart_open(const char * path, int flags, int mode) { @@ -347,132 +348,156 @@ static int uart_fsync(int fd) return 0; } -static void select_notif_callback(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +static esp_err_t register_select(uart_select_args_t *args) { - switch (uart_select_notif) { - case UART_SELECT_READ_NOTIF: - if (FD_ISSET(uart_num, _readfds_orig)) { - FD_SET(uart_num, _readfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_WRITE_NOTIF: - if (FD_ISSET(uart_num, _writefds_orig)) { - FD_SET(uart_num, _writefds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; - case UART_SELECT_ERROR_NOTIF: - if (FD_ISSET(uart_num, _errorfds_orig)) { - FD_SET(uart_num, _errorfds); - esp_vfs_select_triggered_isr(_select_sem, task_woken); - } - break; + esp_err_t ret = ESP_ERR_INVALID_ARG; + + if (args) { + portENTER_CRITICAL(&s_registered_select_lock); + const int new_size = s_registered_select_num + 1; + if ((s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *))) == NULL) { + ret = ESP_ERR_NO_MEM; + } else { + s_registered_selects[s_registered_select_num] = args; + s_registered_select_num = new_size; + ret = ESP_OK; + } + portEXIT_CRITICAL(&s_registered_select_lock); } + + return ret; } -static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, esp_vfs_select_sem_t select_sem) +static esp_err_t unregister_select(uart_select_args_t *args) { - if (_lock_try_acquire(&s_one_select_lock)) { - return ESP_ERR_INVALID_STATE; + esp_err_t ret = ESP_OK; + if (args) { + ret = ESP_ERR_INVALID_STATE; + portENTER_CRITICAL(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + if (s_registered_selects[i] == args) { + const int new_size = s_registered_select_num - 1; + // The item is removed by overwriting it with the last item. The subsequent rellocation will drop the + // last item. + s_registered_selects[i] = s_registered_selects[new_size]; + s_registered_selects = realloc(s_registered_selects, new_size * sizeof(uart_select_args_t *)); + if (s_registered_selects || new_size == 0) { + s_registered_select_num = new_size; + ret = ESP_OK; + } else { + ret = ESP_ERR_NO_MEM; + } + break; + } + } + portEXIT_CRITICAL(&s_registered_select_lock); } + return ret; +} - const int max_fds = MIN(nfds, UART_NUM); - - portENTER_CRITICAL(uart_get_selectlock()); - - if (_readfds || _writefds || _errorfds || _readfds_orig || _writefds_orig || _errorfds_orig || _select_sem.sem) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_INVALID_STATE; - } - - if ((_readfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_writefds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - if ((_errorfds_orig = malloc(sizeof(fd_set))) == NULL) { - portEXIT_CRITICAL(uart_get_selectlock()); - uart_end_select(); - return ESP_ERR_NO_MEM; - } - - //uart_set_select_notif_callback set the callbacks in UART ISR - for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, readfds) || FD_ISSET(i, writefds) || FD_ISSET(i, exceptfds)) { - uart_set_select_notif_callback(i, select_notif_callback); +static void select_notif_callback_isr(uart_port_t uart_num, uart_select_notif_t uart_select_notif, BaseType_t *task_woken) +{ + portENTER_CRITICAL_ISR(&s_registered_select_lock); + for (int i = 0; i < s_registered_select_num; ++i) { + uart_select_args_t *args = s_registered_selects[i]; + if (args) { + switch (uart_select_notif) { + case UART_SELECT_READ_NOTIF: + if (FD_ISSET(uart_num, &args->readfds_orig)) { + FD_SET(uart_num, args->readfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_WRITE_NOTIF: + if (FD_ISSET(uart_num, &args->writefds_orig)) { + FD_SET(uart_num, args->writefds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + case UART_SELECT_ERROR_NOTIF: + if (FD_ISSET(uart_num, &args->errorfds_orig)) { + FD_SET(uart_num, args->errorfds); + esp_vfs_select_triggered_isr(args->select_sem, task_woken); + } + break; + } } } + portEXIT_CRITICAL_ISR(&s_registered_select_lock); +} - _select_sem = select_sem; +static esp_err_t uart_start_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + esp_vfs_select_sem_t select_sem, void **end_select_args) +{ + const int max_fds = MIN(nfds, UART_NUM); + *end_select_args = NULL; - _readfds = readfds; - _writefds = writefds; - _errorfds = exceptfds; + uart_select_args_t *args = malloc(sizeof(uart_select_args_t)); - *_readfds_orig = *readfds; - *_writefds_orig = *writefds; - *_errorfds_orig = *exceptfds; + if (args == NULL) { + return ESP_ERR_NO_MEM; + } + args->select_sem = select_sem; + args->readfds = readfds; + args->writefds = writefds; + args->errorfds = exceptfds; + args->readfds_orig = *readfds; // store the original values because they will be set to zero + args->writefds_orig = *writefds; + args->errorfds_orig = *exceptfds; FD_ZERO(readfds); FD_ZERO(writefds); FD_ZERO(exceptfds); + portENTER_CRITICAL(uart_get_selectlock()); + + //uart_set_select_notif_callback sets the callbacks in UART ISR for (int i = 0; i < max_fds; ++i) { - if (FD_ISSET(i, _readfds_orig)) { + if (FD_ISSET(i, &args->readfds_orig) || FD_ISSET(i, &args->writefds_orig) || FD_ISSET(i, &args->errorfds_orig)) { + uart_set_select_notif_callback(i, select_notif_callback_isr); + } + } + + for (int i = 0; i < max_fds; ++i) { + if (FD_ISSET(i, &args->readfds_orig)) { size_t buffered_size; if (uart_get_buffered_data_len(i, &buffered_size) == ESP_OK && buffered_size > 0) { // signalize immediately when data is buffered - FD_SET(i, _readfds); - esp_vfs_select_triggered(_select_sem); + FD_SET(i, readfds); + esp_vfs_select_triggered(args->select_sem); } } } - portEXIT_CRITICAL(uart_get_selectlock()); - // s_one_select_lock is not released on successfull exit - will be - // released in uart_end_select() + esp_err_t ret = register_select(args); + if (ret != ESP_OK) { + portEXIT_CRITICAL(uart_get_selectlock()); + free(args); + return ret; + } + portEXIT_CRITICAL(uart_get_selectlock()); + + *end_select_args = args; return ESP_OK; } -static void uart_end_select(void) +static esp_err_t uart_end_select(void *end_select_args) { + uart_select_args_t *args = end_select_args; + + if (args) { + free(args); + } + portENTER_CRITICAL(uart_get_selectlock()); + esp_err_t ret = unregister_select(args); for (int i = 0; i < UART_NUM; ++i) { uart_set_select_notif_callback(i, NULL); } - - _select_sem.sem = NULL; - - _readfds = NULL; - _writefds = NULL; - _errorfds = NULL; - - if (_readfds_orig) { - free(_readfds_orig); - _readfds_orig = NULL; - } - - if (_writefds_orig) { - free(_writefds_orig); - _writefds_orig = NULL; - } - - if (_errorfds_orig) { - free(_errorfds_orig); - _errorfds_orig = NULL; - } portEXIT_CRITICAL(uart_get_selectlock()); - _lock_release(&s_one_select_lock); + + return ret; } #ifdef CONFIG_VFS_SUPPORT_TERMIOS diff --git a/components/wpa_supplicant/src/crypto/sha1-internal.c b/components/wpa_supplicant/src/crypto/sha1-internal.c index 9eb190039e..3bcd88116c 100644 --- a/components/wpa_supplicant/src/crypto/sha1-internal.c +++ b/components/wpa_supplicant/src/crypto/sha1-internal.c @@ -20,11 +20,17 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/sha1.h" +#endif + typedef struct SHA1Context SHA1_CTX; void SHA1Transform(u32 state[5], const unsigned char buffer[64]); + +#ifndef USE_MBEDTLS_CRYPTO /** * sha1_vector - SHA-1 hash for data vector * @num_elem: Number of elements in the data vector @@ -45,7 +51,49 @@ sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) SHA1Final(mac, &ctx); return 0; } +#else +/** + * sha1_vector - SHA-1 hash for data vector + * @num_elem: Number of elements in the data vector + * @addr: Pointers to the data areas + * @len: Lengths of the data blocks + * @mac: Buffer for the hash + * Returns: 0 on success, -1 of failure + */ +int +sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac) +{ + mbedtls_sha1_context ctx; + size_t i; + int ret; + mbedtls_sha1_init( &ctx ); + + if ((ret = mbedtls_sha1_starts_ret( &ctx)) != 0) { + goto exit; + } + + + for (i = 0; i < num_elem; i++) { + if ((ret = mbedtls_sha1_update_ret(&ctx, addr[i], len[i])) != 0) { + goto exit; + } + } + + if ((ret = mbedtls_sha1_finish_ret( &ctx, mac)) != 0) { + goto exit; + } + +exit: + mbedtls_sha1_free( &ctx ); + + if (ret) { + return -1; + } + + return 0; +} +#endif /* ===== start - public domain SHA1 implementation ===== */ @@ -309,5 +357,4 @@ SHA1Final(unsigned char digest[20], SHA1_CTX* context) os_memset(context->count, 0, 8); os_memset(finalcount, 0, 8); } - /* ===== end - public domain SHA1 implementation ===== */ diff --git a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c index ec7100142c..b842a57d4e 100644 --- a/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c +++ b/components/wpa_supplicant/src/crypto/sha1-pbkdf2.c @@ -18,10 +18,63 @@ #include "crypto/md5.h" #include "crypto/crypto.h" +#ifdef USE_MBEDTLS_CRYPTO +#include "mbedtls/pkcs5.h" + +/** + * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i + * @passphrase: ASCII passphrase + * @ssid: SSID + * @ssid_len: SSID length in bytes + * @iterations: Number of iterations to run + * @buf: Buffer for the generated key + * @buflen: Length of the buffer in bytes + * Returns: 0 on success, -1 of failure + * + * This function is used to derive PSK for WPA-PSK. For this protocol, + * iterations is set to 4096 and buflen to 32. This function is described in + * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. + */ +int +pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, + int iterations, u8 *buf, size_t buflen) +{ + + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if (info_sha1 == NULL) { + ret = -1; + goto exit; + } + + if ((ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0) { + ret = -1; + goto exit; + } + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, (const unsigned char*) passphrase, os_strlen(passphrase) , (const unsigned char*) ssid, + ssid_len, iterations, 32, buf ); + if (ret != 0) { + ret = -1; + goto exit; + } + +exit: + mbedtls_md_free( &sha1_ctx ); + + return ret; +} +#else + static int pbkdf2_sha1_f(const char *passphrase, const char *ssid, - size_t ssid_len, int iterations, unsigned int count, - u8 *digest) + size_t ssid_len, int iterations, unsigned int count, + u8 *digest) { unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; int i, j; @@ -99,3 +152,4 @@ pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len, return 0; } +#endif diff --git a/components/xtensa/include/esp_attr.h b/components/xtensa/include/esp_attr.h index 7a3ec771d1..34458948a7 100644 --- a/components/xtensa/include/esp_attr.h +++ b/components/xtensa/include/esp_attr.h @@ -34,6 +34,9 @@ // Forces data to be placed to DMA-capable places #define DMA_ATTR WORD_ALIGNED_ATTR DRAM_ATTR +// Forces a function to be inlined +#define FORCE_INLINE_ATTR static inline __attribute__((always_inline)) + // Forces a string into DRAM instead of flash // Use as ets_printf(DRAM_STR("Hello world!\n")); #define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;})) @@ -45,7 +48,7 @@ // Forces bss variable into external memory. " #define EXT_RAM_ATTR _SECTION_ATTR_IMPL(".ext_ram.bss", __COUNTER__) #else -#define EXT_RAM_ATTR +#define EXT_RAM_ATTR #endif // Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" @@ -73,6 +76,30 @@ // Forces to not inline function #define NOINLINE_ATTR __attribute__((noinline)) +// This allows using enum as flags in C++ +// Format: FLAG_ATTR(flag_enum_t) +#ifdef __cplusplus + +#define FLAG_ATTR_IMPL(TYPE, INT_TYPE) \ +constexpr TYPE operator~ (TYPE a) { return (TYPE)~(INT_TYPE)a; } \ +constexpr TYPE operator| (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a | (INT_TYPE)b); } \ +constexpr TYPE operator& (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a & (INT_TYPE)b); } \ +constexpr TYPE operator^ (TYPE a, TYPE b) { return (TYPE)((INT_TYPE)a ^ (INT_TYPE)b); } \ +constexpr TYPE operator>> (TYPE a, int b) { return (TYPE)((INT_TYPE)a >> b); } \ +constexpr TYPE operator<< (TYPE a, int b) { return (TYPE)((INT_TYPE)a << b); } \ +TYPE& operator|=(TYPE& a, TYPE b) { a = a | b; return a; } \ +TYPE& operator&=(TYPE& a, TYPE b) { a = a & b; return a; } \ +TYPE& operator^=(TYPE& a, TYPE b) { a = a ^ b; return a; } \ +TYPE& operator>>=(TYPE& a, int b) { a >>= b; return a; } \ +TYPE& operator<<=(TYPE& a, int b) { a <<= b; return a; } + +#define FLAG_ATTR_U32(TYPE) FLAG_ATTR_IMPL(TYPE, uint32_t) +#define FLAG_ATTR FLAG_ATTR_U32 + +#else +#define FLAG_ATTR(TYPE) +#endif + // Implementation for a unique custom section // // This prevents gcc producing "x causes a section type conflict with y" diff --git a/docs/_static/theme_overrides.css b/docs/_static/theme_overrides.css index df1cdd4425..011488e79e 100644 --- a/docs/_static/theme_overrides.css +++ b/docs/_static/theme_overrides.css @@ -40,3 +40,7 @@ a:hover { .logo { width: 240px !important; } + +a.internal::after{ + content: ' '; +} diff --git a/docs/conf_common.py b/docs/conf_common.py index 8fd13cbaf2..505dab8a0c 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -93,13 +93,16 @@ temp_sdkconfig_path = '{}/sdkconfig.tmp'.format(builddir) kconfigs = find_component_files("../../components", "Kconfig") kconfig_projbuilds = find_component_files("../../components", "Kconfig.projbuild") +sdkconfig_renames = find_component_files("../../components", "sdkconfig.rename") confgen_args = [sys.executable, "../../tools/kconfig_new/confgen.py", "--kconfig", "../../Kconfig", + "--sdkconfig-rename", "../../sdkconfig.rename", "--config", temp_sdkconfig_path, "--env", "COMPONENT_KCONFIGS={}".format(" ".join(kconfigs)), "--env", "COMPONENT_KCONFIGS_PROJBUILD={}".format(" ".join(kconfig_projbuilds)), + "--env", "COMPONENT_SDKCONFIG_RENAMES={}".format(" ".join(sdkconfig_renames)), "--env", "IDF_PATH={}".format(idf_path), "--output", "docs", kconfig_inc_path + '.in' ] diff --git a/docs/en/api-guides/build-system.rst b/docs/en/api-guides/build-system.rst index 8a28a1e163..2eed1fa5ab 100644 --- a/docs/en/api-guides/build-system.rst +++ b/docs/en/api-guides/build-system.rst @@ -453,68 +453,14 @@ The order of components in the ``BUILD_COMPONENTS`` variable determines other or - Order that :ref:`project_include.cmake` files are included into the project. - Order that the list of header paths is generated for compilation (via ``-I`` argument). (Note that for a given component's source files, only that component's dependency's header paths are passed to the compiler.) -Build Process Internals -======================= - -For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. - -project.cmake contents ----------------------- - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -project function ----------------- - -The custom ``project()`` function performs the following steps: - -- Determines the target (set by ``IDF_TARGET`` environment variable) and saves the target in CMake cache. If the target set in the environment does not match the one in cache, exits with an error. -- Evaluates component dependencies and builds the ``BUILD_COMPONENTS`` list of components to include in the build (see :ref:`above`). -- Finds all components in the project (searching ``COMPONENT_DIRS`` and filtering by ``COMPONENTS`` if this is set). -- Loads the project configuration from the ``sdkconfig`` file and generates a ``sdkconfig.cmake`` file and a ``sdkconfig.h`` header. These define configuration values in CMake and C/C++, respectively. If the project configuration changes, cmake will automatically be re-run to re-generate these files and re-configure the project. -- Sets the `CMAKE_TOOLCHAIN_FILE`_ variable to the correct toolchain file, depending on the target. -- Declares the actual cmake-level project by calling the `CMake project function `_. -- Loads the git version. This includes some magic which will automatically re-run CMake if a new revision is checked out in git. See `File Globbing & Incremental Builds`_. -- Includes :ref:`project_include.cmake` files from any components which have them. -- Adds each component to the build. Each component CMakeLists file calls ``idf_component_register``, calls the CMake `add_library `_ function to add a library and then adds source files, compile options, etc. -- Adds the final app executable to the build. -- Goes back and adds inter-component dependencies between components (ie adding the public header directories of each component to each other component). - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. - -Debugging CMake ---------------- - -Some tips for debugging the ESP-IDF CMake-based build system: - -- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. -- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. -- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. - -When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. - -It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. - -.. _warn-undefined-variables: - -Warning On Undefined Variables -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. - -If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. - -Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. Overriding Parts of the Project -------------------------------- +=============================== .. _project_include.cmake: project_include.cmake -^^^^^^^^^^^^^^^^^^^^^ +--------------------- For components that have build requirements which must be evaluated before any component CMakeLists files are evaluated, you can create a file called ``project_include.cmake`` in the @@ -531,7 +477,7 @@ Note that ``project_include.cmake`` isn't necessary for the most common componen Take great care when setting variables or targets in a ``project_include.cmake`` file. As the values are included into the top-level project CMake pass, they can influence or break functionality across all components! KConfig.projbuild -^^^^^^^^^^^^^^^^^ +----------------- This is an equivalent to ``project_include.cmake`` for :ref:`component-configuration` KConfig files. If you want to include configuration options at the top-level of menuconfig, rather than inside the "Component Configuration" sub-menu, then these can be defined in the KConfig.projbuild file alongside the ``CMakeLists.txt`` file. @@ -541,11 +487,41 @@ Take care when adding configuration values in this file, as they will be include ``project_include.cmake`` files are used inside ESP-IDF, for defining project-wide build features such as ``esptool.py`` command line arguments and the ``bootloader`` "special app". Configuration-Only Components -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +============================= Special components which contain no source files, only ``Kconfig.projbuild`` and ``KConfig``, can have a one-line ``CMakeLists.txt`` file which calls the function ``idf_component_register()`` with no arguments specified. This function will include the component in the project build, but no library will be built *and* no header files will be added to any include paths. + +Debugging CMake +=============== + +For full details about CMake_ and CMake commands, see the `CMake v3.5 documentation`_. + +Some tips for debugging the ESP-IDF CMake-based build system: + +- When CMake runs, it prints quite a lot of diagnostic information including lists of components and component paths. +- Running ``cmake -DDEBUG=1`` will produce more verbose diagnostic output from the IDF build system. +- Running ``cmake`` with the ``--trace`` or ``--trace-expand`` options will give a lot of information about control flow. See the `cmake command line documentation`_. + +When included from a project CMakeLists file, the ``project.cmake`` file defines some utility modules and global variables and then sets ``IDF_PATH`` if it was not set in the system environment. + +It also defines an overridden custom version of the built-in CMake_ ``project`` function. This function is overridden to add all of the ESP-IDF specific project functionality. + +.. _warn-undefined-variables: + +Warning On Undefined Variables +------------------------------ + +By default, ``idf.py`` passes the ``--warn-uninitialized`` flag to CMake_ so it will print a warning if an undefined variable is referenced in the build. This can be very useful to find buggy CMake files. + +If you don't want this behaviour, it can be disabled by passing ``--no-warnings`` to ``idf.py``. + +Browse the :idf_file:`/tools/cmake/project.cmake` file and supporting functions in :idf_file:`/tools/cmake/idf_functions.cmake` for more details. + +.. _gnu-make-to-cmake: + + Example Component CMakeLists ============================ @@ -1225,7 +1201,86 @@ Any combination of "load", "set", and "save" can be sent in a single command and .. note:: The configuration server does not re-run CMake to regenerate other build files or metadata files after ``sdkconfig`` is updated. This will happen automatically the next time ``CMake`` or ``idf.py`` is run. -.. _gnu-make-to-cmake: +Build System Internals +======================= + +Build Scripts +------------- + +The listfiles for the ESP-IDF build system reside in :idf:`/tools/cmake`. The modules which implement core build system functionality are as follows: + + - build.cmake - Build related commands i.e. build initialization, retrieving/setting build properties, build processing. + - component.cmake - Component related commands i.e. adding components, retrieving/setting component properties, registering components. + - kconfig.cmake - Generation of configuration files (sdkconfig, sdkconfig.h, sdkconfig.cmake, etc.) from Kconfig files. + - ldgen.cmake - Generation of final linker script from linker fragment files. + - target.cmake - Setting build target and toolchain file. + - utilities.cmake - Miscellaneous helper commands. + + Aside from these files, there are two other important CMake scripts in :idf:`/tools/cmake`: + + - idf.cmake - Sets up the build and includes the core modules listed above. Included in CMake projects in order to access ESP-IDF build system functionality. + - project.cmake - Includes ``idf.cmake`` and provides a custom ``project()`` command that takes care of all the heavy lifting of building an executable. Included in the top-level CMakeLists.txt of standard ESP-IDF projects. + +The rest of the files in :idf:`/tools/cmake` are support or third-party scripts used in the build process. + +Build Process +------------- + +This section describes the standard ESP-IDF application build process. The build process can be broken down roughly into four phases: + +.. blockdiag:: + :scale: 100% + :caption: ESP-IDF Build System Process + :align: center + + blockdiag idf-build-system-process { + Initialization -> Enumeration + Enumeration -> Processing + Processing -> Finalization + } + +Initialization +^^^^^^^^^^^^^^ + This phase sets up necessary parameters for the build. + + - Upon inclusion of ``idf.cmake`` in ``project.cmake``, the following steps are performed: + - Set ``IDF_PATH`` from environment variable or inferred from path to ``project.cmake`` included in the top-level CMakeLists.txt. + - Add :idf:`/tools/cmake` to ``CMAKE_MODULE_PATH`` and include core modules plus the various helper/third-party scripts. + - Set build tools/executables such as default Python interpreter, mconf, etc. + - Get ESP-IDF git revision and store as ``IDF_VER``. + - Set global build specifications i.e. compile options, compile definitions, include directories for all components in the build. + - Add components in :idf:`components` to the build. + - The initial part of the custom ``project()`` command performs the following steps: + - Set ``IDF_TARGET`` from environment variable or CMake cache and the corresponding ``CMAKE_TOOLCHAIN_FILE`` to be used. + - Add components in ``EXTRA_COMPONENTS_DIRS`` to the build. + - Prepare arguments for calling command ``idf_build_process()`` from variables such as ``COMPONENTS``/``EXCLUDE_COMPONENTS``, ``SDKCONFIG``, ``SDKCONFIG_DEFAULTS``. + + The call to ``idf_build_process()`` command marks the end of this phase. + +Enumeration +^^^^^^^^^^^ + This phase builds a final list of components to be processed in the build, and is performed in the first half of ``idf_build_process()``. + + - Retrieve each component's public and private requirements. A child process is created which executes each component's CMakeLists.txt in script mode. The values of ``idf_component_register`` REQUIRES and PRIV_REQUIRES argument is returned to the parent build process. This is called early expansion. The variable ``CMAKE_BUILD_EARLY_EXPANSION`` is defined during this step. + - Recursively include components based on public and private requirements. + +Processing +^^^^^^^^^^ + This phase processes the components in the build, and is the second half of ``idf_build_process()``. + + - Load project configuration from sdkconfig file and generate an sdkconfig.cmake and sdkconfig.h header. These define configuration variables/macros that are accessible from the build scripts and C/C++ source/header files, respectively. + - Include each component's ``project_include.cmake``. + - Add each component as a subdirectory, processing its CMakeLists.txt. The component CMakeLists.txt calls the registration command, ``idf_component_register`` which adds source files, include directories, creates component library, links dependencies, etc. + +Finalization +^^^^^^^^^^^^ + This phase is everything after ``idf_build_process()``. + + - Create executable and link the component libraries to it. + - Generate project metadata files such as project_description.json and display relevant information about the project built. + + +Browse :idf_file:`/tools/cmake/project.cmake` for more details. Migrating from ESP-IDF GNU Make System ====================================== @@ -1269,7 +1324,6 @@ Some features are significantly different or removed in the CMake-based system. - ``COMPONENT_CONFIG_ONLY``: Call ``register_config_only_component()`` instead. See `Configuration-Only Components`_. - ``CFLAGS``, ``CPPFLAGS``, ``CXXFLAGS``: Use equivalent CMake commands instead. See `Controlling Component Compilation`_. - No Default Values ----------------- diff --git a/docs/en/api-guides/index.rst b/docs/en/api-guides/index.rst index cc762d3b33..fdfd58c984 100644 --- a/docs/en/api-guides/index.rst +++ b/docs/en/api-guides/index.rst @@ -3,35 +3,35 @@ API Guides :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - General Notes - Build System - Build System (Legacy GNU Make) - Error Handling - Fatal Errors - Event Handling - Deep Sleep Wake Stubs - ESP32 Core Dump - Flash Encryption <../security/flash-encryption> - FreeRTOS SMP Changes - Thread Local Storage - High Level Interrupts - JTAG Debugging - Bootloader - Partition Tables - Secure Boot <../security/secure-boot> - ULP Coprocessor - ULP Coprocessor (Legacy GNU Make) - Unit Testing - Unit Testing (Legacy GNU Make) - Application Level Tracing - Console Component - ROM debug console - RF Calibration - WiFi Driver - ESP-MESH - BluFi - External SPI-connected RAM - Linker Script Generation - Tools + Application Level Tracing + BluFi + Bootloader + Build System + Build System (Legacy GNU Make) + Console Component + Deep Sleep Wake Stubs + Error Handling + ESP-MESH + ESP32 Core Dump + Event Handling + External SPI-connected RAM + Fatal Errors + Flash Encryption <../security/flash-encryption> + FreeRTOS SMP Changes + General Notes + High Level Interrupts + JTAG Debugging + Linker Script Generation + Partition Tables + RF Calibration + ROM debug console + Secure Boot <../security/secure-boot> + Thread Local Storage + Tools + ULP Coprocessor (Legacy GNU Make) + ULP Coprocessor + Unit Testing (Legacy GNU Make) + Unit Testing + WiFi Driver diff --git a/docs/en/api-reference/bluetooth/index.rst b/docs/en/api-reference/bluetooth/index.rst index da9f19d65c..d250083586 100644 --- a/docs/en/api-reference/bluetooth/index.rst +++ b/docs/en/api-reference/bluetooth/index.rst @@ -4,13 +4,13 @@ Bluetooth API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth Controller && VHCI - Bluetooth Common - Bluetooth LE - Bluetooth Classic - NimBLE + Bluetooth Controller && VHCI + Bluetooth Common + Bluetooth LE + Bluetooth Classic + NimBLE ESP-IDF currently supports two host stacks. The Bluedroid based stack (default) supports classic Bluetooth as well as BLE. On the other hand, Apache NimBLE based stack is BLE only. For users to make a choice: * For usecases involving classic Bluetooth as well as BLE, Bluedroid should be used. diff --git a/docs/en/api-reference/index.rst b/docs/en/api-reference/index.rst index a083fe82a2..92e57f8cc8 100644 --- a/docs/en/api-reference/index.rst +++ b/docs/en/api-reference/index.rst @@ -4,15 +4,15 @@ API Reference :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 2 + :maxdepth: 2 - Bluetooth - Networking - Peripherals - Protocols - Provisioning - Storage - System - Configuration Options - Error Codes Reference + Bluetooth + Networking + Peripherals + Protocols + Provisioning + Storage + System + Configuration Options + Error Codes Reference diff --git a/docs/en/api-reference/network/index.rst b/docs/en/api-reference/network/index.rst index f555a456c0..cb5c5801b3 100644 --- a/docs/en/api-reference/network/index.rst +++ b/docs/en/api-reference/network/index.rst @@ -7,12 +7,12 @@ Wi-Fi ===== .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Wi-Fi - Smart Config - ESP-NOW - ESP Mesh + Wi-Fi + Smart Config + ESP-NOW + ESP Mesh Code examples for the Wi-Fi API are provided in the :example:`wifi` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/peripherals/index.rst b/docs/en/api-reference/peripherals/index.rst index 77913eab91..6aff1448ae 100644 --- a/docs/en/api-reference/peripherals/index.rst +++ b/docs/en/api-reference/peripherals/index.rst @@ -4,27 +4,27 @@ Peripherals API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - ADC - CAN - DAC - GPIO (including RTC low power I/O) - I2C - I2S - LED Control - MCPWM - Pulse Counter - Remote Control - SDMMC Host - SD SPI Host - SDIO Slave - Sigma-delta Modulation - SPI Master - SPI Slave - Temp sensor - Timer - Touch Sensor - UART + ADC + CAN + DAC + GPIO (including RTC low power I/O) + I2C + I2S + LED Control + MCPWM + Pulse Counter + Remote Control + SD SPI Host + SDIO Slave + SDMMC Host + Sigma-delta Modulation + SPI Master + SPI Slave + Temp sensor + Timer + Touch Sensor + UART Code examples for this API section are provided in the :example:`peripherals` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst index 3fd76b0a06..658d94ea94 100644 --- a/docs/en/api-reference/peripherals/sd_pullup_requirements.rst +++ b/docs/en/api-reference/peripherals/sd_pullup_requirements.rst @@ -1,153 +1,268 @@ SD Pullup Requirements ====================== -CMD and DATA lines D0-D3 of the slave should be pulled up by 50KOhm resistor +CMD and DATA lines D0-D3 of the slave should be pulled up by 10 kOhm resistor even in 1-bit mode or SPI mode. The pullups of the slave cards should be connected even if they're not connected to the host. -The MTDI strapping pin is incompatible with DAT2 line pull-up by default -when the code flash is 3.3V. See :ref:`mtdi_strapping_pin` below. +The MTDI strapping pin by default is incompatible with DAT2 line pullup when +the flash is 3.3 V. See :ref:`technical_detail_sdio` below. -Pullup inside Official Modules ------------------------------- +.. _existing_issues_official_modules_sdio: -For Espressif official modules, different weak pullups / pulldowns are -connected to CMD, and DATA pins as below. To use these modules, -these pins are required to be pulled up by 50KOhm resistors, since internal -weak pullups are insufficient. +Possible Issues +--------------- -+-----------------------+-----+--------------------------+------+----------------------+------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+==========================+======+======================+======+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| At startup | WPU | WPD | WPD | PU for 1.8v flash; | WPU | -| | | | | WPD for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ -| Strapping requirement | | Low to download to flash | | High for 1.8v flash; | | -| | | | | Low for 3.3v flash | | -+-----------------------+-----+--------------------------+------+----------------------+------+ +Here is a list of Espressif chips, official modules and development kits and +the issues they may have during SDIO development. Since the requirements are +for the pullups on the SD bus, the issues should be resolved no matter if it +is a host or slave. Each issue is linked to its solution. The solution for a +specific issue may be different for host and slave. -- WPU: Weak pullup -- WPD: Weak pulldown -- PU: Pullup inside the module +Official modules are usually without the sufficient pullups on all 6 pins, it +is suggested to select one of the development kits for either host or slave +to provide such pullups. -For Wrover modules, they use 1.8v flash, and have pullup on GPIO12 inside. -For Wroom-32 Series, PICO-D4 modules, they use 3.3v flash, and is weakly -pulled down internally. See :ref:`mtdi_strapping_pin` below. +Chips +^^^^^ -Pullup on Official Devkit (WroverKit) --------------------------------------- + - ESP32 (except D2WD, see `ESP32 datasheet `_): + :ref:`sd_pullup_no_pullups`, whether the strapping conflicts with DAT2 is determined + by the flash you are using. Please see :ref:`strapping_conflicts_dat2` if + your flash chip is 3.3 V. -For official Wrover Kit (till version 3), some of the pullups are provided on -the board as the table below. For other devkits that don't have pullups, -please connect them yourselves. + - ESP32-D2WD: + :ref:`sd_pullup_no_pullups`, :ref:`no_pullup_on_gpio12` -+-----------------------+-----+------+------+------+---------+ -| GPIO | 15 | 2 | 4 | 12 | 13 | -+=======================+=====+======+======+======+=========+ -| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | -+-----------------------+-----+------+------+------+---------+ -| Pullup on the Kit | PU | PU | PU | | PU & PD | -+-----------------------+-----+------+------+------+---------+ + - ESP32-PICO-D4: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2` -- PU: Pullup -- PD: Pulldown +Modules +^^^^^^^ -The DAT3 pullup conflicts with JTAG pulldown in WroverKit v3 and earlier, please -either: + - ESP32-WROOM-32 Series: + Including ESP32-WROOM-32, ESP32-WROOM-32D, ESP32-WROOM-32U and + ESP32-SOLO-1. -1. pull it up by resistor less than 5KOhm (2kOhm suggested) in 4-bit mode. -2. pull it up or drive it high by host or VDD3.3V in 1-bit mode. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -.. _mtdi_strapping_pin: + - ESP32-WROVER Series: + Including ESP32-WROVER and ESP32-WROVER-I. -MTDI strapping pin ------------------- + :ref:`sd_pullup_no_pullups`. -MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an -internal regulator which powers the flash chip (VDD_SDIO). This pin has an -internal pulldown so if left unconnected it will read low at reset (selecting -default 3.3V operation). When adding a pullup to this pin for SD card -operation, consider the following: + - ESP32-WROVER-B Series: + Including ESP32-WROVER-B and ESP32-WROVER-IB. -- For boards which don't use the internal regulator (VDD_SDIO) to power the - flash, GPIO12 can be pulled high. -- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at - reset. This is fully compatible with SD card operation. -- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 - must be low at reset. This is incompatible with SD card operation. Please - check the table below to see whether your modules/kits use 3.3v flash. + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`. -+-----------------+---------------+--------------------------------------+ -| Module | Flash voltage | DAT2 connections | -+=================+===============+======================================+ -| PICO-D4 | 3.3V | Internal PD, change EFUSE and pullup | -+-----------------+ + or disable DAT2 line* + -| Wroom-32 Series | | | -+-----------------+---------------+--------------------------------------+ -| Wrover | 1.8V | Internal PU, pullup suggested | -+-----------------+---------------+--------------------------------------+ +.. _sdio_dev_kits: -Official devkits of different types and version mount different types of -modules, please refer to the table below to see whether your devkit can -support SDIO slave without steps above. +Development Boards +^^^^^^^^^^^^^^^^^^ -+--------------------------+-----------------+---------------+ -| Devkit | Module | Flash voltage | -+==========================+=================+===============+ -| PICO Kit | PICO-D4 | 3.3V | -+--------------------------+-----------------+ (see steps + -| DevKitC | Wroom-32 Series | below) | -+--------------------------+ + + -| WroverKit v2 and earlier | | | -+--------------------------+-----------------+---------------+ -| WroverKit v3 | Wrover | 1.8V | -+--------------------------+-----------------+---------------+ + - ESP32-PICO-KIT: + Including PICO-KIT v4.1, v4.0 and v3. -If your board requires internal regulator with 3.3v output, to make it -compatible with SD pullup, you can either: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - - **In the case using ESP32 host only**, external pullup can be omitted and an - internal pullup can be enabled using a ``gpio_pullup_en(GPIO_NUM_12);`` call. - Most SD cards work fine when an internal pullup on GPIO12 line is enabled. - Note that if ESP32 experiences a power-on reset while the SD card is - sending data, high level on GPIO12 can be latched into the bootstrapping - register, and ESP32 will enter a boot loop until external reset with - correct GPIO12 level is applied. - - **In the case using ESP32 slave in 1-bit mode**, speicfy - ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in the slave to avoid slave detecting on - DAT2 line. Note the host will not know 4-bit mode is not supported any more - by the standard CCCR register. You have to tell the host use 1-bit only. - - **For ESP32 host or slave**, another option is to burn the flash voltage - selection efuses. This will permanently select 3.3V output voltage for the - internal regulator, and GPIO12 will not be used as a bootstrapping pin. - Then it is safe to connect a pullup resistor to GPIO12. This option is - suggested for production use. NOTE this cannot be reverted once the EFUSE - is burnt. + - ESP32-DevKitC: + Including ESP32-DevKitC v4 and v2. - The following command can be used to program flash voltage selection efuses **to 3.3V**: + :ref:`sd_pullup_no_pullups`, :ref:`strapping_conflicts_dat2`, + :ref:`gpio2_strapping_pin`. - components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + - ESP-WROVER-KIT: + v4.1: Have pullups, but :ref:`pullup_conflicts_on_gpio13` , + :ref:`strapping_conflicts_dat2`. - This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and - `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal - VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See - the technical reference manual for more details. + v3: Have pullups, but :ref:`pullup_conflicts_on_gpio13`. - `espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script. + v2 and v1: Have pullups, but :ref:`pullup_conflicts_on_gpio13`, + :ref:`strapping_conflicts_dat2`, :ref:`gpio2_strapping_pin`. -GPIO2 Strapping pin -------------------- + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + + - ESP32-LyraTD-MSC: + :ref:`strapping_conflicts_dat2`. Have pullups. + + - ESP32-LyraT: + Have pullups, but :ref:`pullup_conflicts_on_gpio13` + +Non-Espressif Hosts +^^^^^^^^^^^^^^^^^^^ + +Please make sure that your 3rd party SDIO host has correct pullups for all +the signals. + +Solutions +--------- + +.. _sd_pullup_no_pullups: + +No Pullups +^^^^^^^^^^ + +When developing on boards without pullups, you can either: + +1. If your host and slave are on seperated boards, you can change one of them + to a board with pullups. Please see :ref:`sdio_dev_kits` to find Espressif + official boards with pullups. +2. Connect external pullups to VDD by yourself. Connect these pins without + pullups to the VDD through a 10 kOhm resistor. + +.. _pullup_conflicts_on_gpio13: + +Pullup Conflicts on GPIO13 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The DAT3 of slave may not be properly pulled up. You can either: + +1. Use 1-bit mode, and tie DAT3 of slave to VDD. +2. Use SPI mode. +3. Remove the pulldown resistors on GPIO13; or pull it up by resistor less + than 5 kOhm (2 kOhm suggested); or pull it up or drive it high by host or + VDD3.3V in 1-bit mode. + +.. _strapping_conflicts_dat2: + +Conflicts Between Bootstrap and SDIO on DAT2 +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The strapping requirements conflict with SDIO protocol. See +:ref:`mtdi_strapping_pin` for the details of this issue. You can either: + +1. (Recomended) Burn the flash voltage selection eFuses. This will + permanently select 3.3 V output voltage for the internal regulator, and GPIO12 + will not be used as a bootstrapping pin. Then connect a pullup resistor + to GPIO12. + + .. warning:: Burning eFuse is irreversible. The issue list above may be + out of date. Do make sure the module you are burning is using a 3.3 V flash + according to the information on http://www.espressif.com/. If you burn the + 3.3 V eFuses on an 1.8 V module, the module will get broken. + + Run the command below under your IDF folder: + :: + + components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V + + This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and + `XPD_SDIO_REG` eFuses. With all three burned to value 1, the internal + VDD_SDIO flash voltage regulator is permanently set to 3.3 V. You will + see the following log if the burning succeeds: + :: + + espefuse.py v2.6 + Connecting.... + + Enable internal flash voltage regulator (VDD_SDIO) to 3.3 V. + The following eFuses are burned: XPD_SDIO_FORCE, XPD_SDIO_REG, XPD_SDIO_TIEH. + This is an irreversible operation. + Type 'BURN' (all capitals) to continue. + BURN + VDD_SDIO setting complete. + + You can also run ``components/esptool_py/esptool/espefuse.py summary`` to + check the status of the eFuses above. + + `espefuse.py` has a ``--do-not-confirm`` option if running from an + automated flashing script. + + See the ESP32 Technical Reference Manual for more details. + +2. **When using 1-bit mode or SPI mode**, DAT2 signal is not needed (though it + still has to be pulled up). If the device works as the host, you can leave + the DAT2 of host floating, and directly connect DAT2 of slave to VDD; or if + the device works as the slave, specify ``SDIO_SLAVE_FLAG_DAT2_DISABLED`` in + the slave app to avoid slave detecting on DAT2 line. Note the host will + not know that 4-bit mode is not supported any more by the standard CCCR + register. You have to forbid the host from using 4-bit mode. + +.. _no_pullup_on_gpio12: + +No Pullup on GPIO12 +^^^^^^^^^^^^^^^^^^^ + +Your module is compatible with the SDIO protocol. Just connect GPIO12 to the +VDD through a 10 kOhm resistor. + +.. _gpio2_strapping_pin: + +Auto-program Not Working (minor issue) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. You may find it unable to enter the UART download mode if you -correctly connect the pullup of SD on GPIO2. For WroverKit v3, there are -dedicated circuits to pulldown the GPIO2 when downloading. For other boards, -one way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the -auto-reset circuit on most development boards will pull GPIO2 low along with -GPIO0, when entering download mode. +correctly connect the pullup of SD on GPIO2. -- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but - pulldown will interfere with D0 signals and must be removed. Check the - schematic of your development board for anything connected to GPIO2. +Some official kits pull down GPIO2 when downloading. For other boards, you +may try to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset +circuit on most development boards will pull GPIO2 low along with GPIO0, when +entering download mode. (Some boards have pulldown and/or LED on GPIO2. LED +is usually ok, but the pulldown resistor will interfere with D0 signals and +must be removed. Check the schematic of your development board for anything +connected to GPIO2.) + +If the above way is not working, please just turn off the other device and +remove the pullups on GPIO2 when you are programming the slave. + + +.. _technical_detail_sdio: + +Technical Details +----------------- + +.. _mtdi_strapping_pin: + +MTDI Strapping Pin +^^^^^^^^^^^^^^^^^^ + +MTDI (GPIO12) is used as a bootstrapping pin to select output voltage of an +internal regulator which powers the flash chip (VDD_SDIO). This pin has an +internal pulldown so if left unconnected it will read low at startup +(selecting default 3.3 V operation). + +For ESP32-WROVER modules, excluding ESP32-WROVER-B, they use 1.8 V flash, and +have pullup on GPIO12 inside. For other modules, which use 3.3 V flash, have +no pullups on GPIO12, and GPIO12 is weakly pulled down internally. + +When adding a pullup to this pin for SD card operation, consider the +following: + +- For boards which don't use the internal regulator (VDD_SDIO) to power the + flash, GPIO12 can be pulled high. +- For boards which use 1.8 V flash chip, GPIO12 needs to be pulled high at + reset. This is fully compatible with SD card operation. +- On boards which use the internal regulator and a 3.3 V flash chip, GPIO12 + must be low at reset. This is incompatible with SD card operation. Please + check :ref:`existing_issues_official_modules_sdio` to see whether your board + has this issue, and how to solve it. + +Internal Pullups and Strapping Requirements +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is never recommended to rely on internal weak pullups for SDIO +communications, since internal weak pullups are insufficient. But information +of the strapping requirements and internal pullups may be useful. For +Espressif official modules, different weak pullups / pulldowns are connected +to CMD, and DATA pins as below. + ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| GPIO | 15 | 2 | 4 | 12 | 13 | ++=======================+=====+==========================+======+=======================+======+ +| Name | CMD | DAT0 | DAT1 | DAT2 | DAT3 | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| At startup | WPU | WPD | WPD | PU for 1.8 V flash; | WPU | +| | | | | WPD for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ +| Strapping requirement | | Low to download to flash | | High for 1.8 V flash; | | +| | | | | Low for 3.3 V flash | | ++-----------------------+-----+--------------------------+------+-----------------------+------+ + +- WPU: Weak pullup +- WPD: Weak pulldown +- PU: Pullup inside the module \ No newline at end of file diff --git a/docs/en/api-reference/peripherals/sdio_slave.rst b/docs/en/api-reference/peripherals/sdio_slave.rst index 163cf11681..cd01a51d7c 100644 --- a/docs/en/api-reference/peripherals/sdio_slave.rst +++ b/docs/en/api-reference/peripherals/sdio_slave.rst @@ -8,42 +8,72 @@ The ESP32 SDIO Card peripherals (Host, Slave) shares two sets of pins as below t The first set is usually occupied by SPI0 bus which is responsible for the SPI flash holding the code to run. This means SDIO slave driver can only runs on the second set of pins while SDIO host is not using it. -+----------+-------+-------+ -| Pin Name | Slot1 | Slot2 | -+ +-------+-------+ -| | GPIO Number | -+==========+=======+=======+ -| CLK | 6 | 14 | -+----------+-------+-------+ -| CMD | 11 | 15 | -+----------+-------+-------+ -| DAT0 | 7 | 2 | -+----------+-------+-------+ -| DAT1 | 8 | 4 | -+----------+-------+-------+ -| DAT2 | 9 | 12 | -+----------+-------+-------+ -| DAT3 | 10 | 13 | -+----------+-------+-------+ - The SDIO slave can run under 3 modes: SPI, 1-bit SD and 4-bit SD modes, which is detected automatically by the hardware. According to the SDIO specification, CMD and DAT0-3 lines should be pulled up no matter in 1-bit, -4-bit or SPI mode. Then the host initialize the slave into SD mode by first -sending CMD0 with DAT3 pin high, while initialize the slave into SPI mode by -sending CMD0 with CS pin (the same pin as DAT3) low. +4-bit or SPI mode. -.. note:: CMD and DATA lines D0-D3 of the card should be pulled up by 50KOhm resistor - even in 1-bit mode or SPI mode. Most official devkits don't meet the pullup - requirements by default, and there are conflicts on strapping pins as well. - Please refer to :doc:`sd_pullup_requirements` to see how to setup your - system correctly. +Connections +^^^^^^^^^^^ + ++----------+---------------+-------+-------+ +| Pin Name | Corresponding | Slot1 | Slot2 | ++ + pins in SPI +-------+-------+ +| | mode | GPIO Number | ++==========+===============+=======+=======+ +| CLK | SCLK | 6 | 14 | ++----------+---------------+-------+-------+ +| CMD | MOSI | 11 | 15 | ++----------+---------------+-------+-------+ +| DAT0 | MISO | 7 | 2 | ++----------+---------------+-------+-------+ +| DAT1 | Interrupt | 8 | 4 | ++----------+---------------+-------+-------+ +| DAT2 | N.C. (pullup) | 9 | 12 | ++----------+---------------+-------+-------+ +| DAT3 | #CS | 10 | 13 | ++----------+---------------+-------+-------+ + +- 1-bit SD mode: Connect CLK, CMD, DAT0, DAT1 pins and the ground. +- 4-bit SD mode: Connect all pins and the ground. +- SPI mode: Connect SCLK, MOSI, MISO, Interrupt, #CS pins and the ground. + +.. note:: Please check if CMD and DATA lines D0-D3 of the card are properly + pulled up by 10 KOhm resistors. This should be ensured even in 1-bit mode + or SPI mode. Most official modules don't offer these pullups internally. + If you are using official development boards, check + :ref:`existing_issues_official_modules_sdio` to see whether your + development boards have such pullups. + +.. note:: Most official modules have conflicts on strapping pins with the + SDIO slave function. If you are using a ESP32 module with 3.3 V flash + inside, you have to burn the EFUSE when you are developing on the module + for the first time. See :ref:`existing_issues_official_modules_sdio` to + see how to make your modules compatible with the SDIO. + + Here is a list for modules/kits with 3.3 V flash: + + - Modules: ESP32-PICO-D4, ESP32-WROOM-32 series (including ESP32-SOLO-1), + ESP32-WROVER-B and ESP32-WROVER-IB + - Kits: ESP32-PICO-KIT, ESP32-DevKitC (till v4), ESP32-WROVER-KIT + (v4.1 (also known as ESP32-WROVER-KIT-VB), v2, v1 (also known as DevKitJ + v1)) + + You can tell the version of your ESP23-WROVER-KIT version from the module + on it: v4.1 are with ESP32-WROVER-B modules, v3 are with ESP32-WROVER + modules, while v2 and v1 are with ESP32-WROOM-32 modules. + +Refer to :doc:`sd_pullup_requirements` for more technical details of the pullups. .. toctree:: :hidden: sd_pullup_requirements +The host initialize the slave into SD mode by first sending CMD0 with DAT3 +pin high, or in SPI mode by sending CMD0 with CS pin (the same pin as DAT3) +low. + After the initialization, the host can enable the 4-bit SD mode by writing CCCR register 0x07 by CMD52. All the bus detection process are handled by the slave peripheral. @@ -97,7 +127,7 @@ SDIO initialization process (Sector 3.1.2 of `SDIO Simplified Specification `_), which is described briefly in :ref:`esp_slave_init`. -However, there's an ESP32-specific upper-level communication protocol upon +Furthermore, there's an ESP32-specific upper-level communication protocol upon the CMD52/CMD53 to Func 1. Please refer to :ref:`esp_slave_protocol_layer`, or example :example:`peripherals/sdio` when programming your host. diff --git a/docs/en/api-reference/protocols/index.rst b/docs/en/api-reference/protocols/index.rst index c35c954f35..36af219894 100644 --- a/docs/en/api-reference/protocols/index.rst +++ b/docs/en/api-reference/protocols/index.rst @@ -3,18 +3,18 @@ Application Protocols :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - mDNS - ESP-TLS - HTTP Client - Websocket Client - HTTP Server - HTTPS Server - ASIO - ESP-MQTT - Modbus - Local Control + ASIO + ESP-MQTT + ESP-TLS + HTTP Client + HTTP Server + HTTPS Server + Local Control + mDNS + Modbus + Websocket Client Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/provisioning/index.rst b/docs/en/api-reference/provisioning/index.rst index 0243ec19f6..c2341ad73a 100644 --- a/docs/en/api-reference/provisioning/index.rst +++ b/docs/en/api-reference/provisioning/index.rst @@ -4,10 +4,10 @@ Provisioning API :link_to_translation:`zh_CN:[中文]` .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - Unified Provisioning - Protocol Communication - Wi-Fi Provisioning + Protocol Communication + Unified Provisioning + Wi-Fi Provisioning Code examples for this API section are provided in the :example:`provisioning` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/storage/index.rst b/docs/en/api-reference/storage/index.rst index d80e30b56e..23cb38b647 100644 --- a/docs/en/api-reference/storage/index.rst +++ b/docs/en/api-reference/storage/index.rst @@ -2,17 +2,17 @@ Storage API *********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - SPI Flash and Partition APIs - SD/SDIO/MMC Driver - Non-Volatile Storage - NVS Partition Generation Utility - Virtual Filesystem - FAT Filesystem - Wear Levelling - SPIFFS Filesystem - Mass Manufacturing Utility + FAT Filesystem + Mass Manufacturing Utility + Non-Volatile Storage + NVS Partition Generation Utility + SD/SDIO/MMC Driver + SPI Flash and Partition APIs + SPIFFS Filesystem + Virtual Filesystem + Wear Levelling Code examples for this API section are provided in the :example:`storage` directory of ESP-IDF examples. diff --git a/docs/en/api-reference/system/index.rst b/docs/en/api-reference/system/index.rst index 1f2c25940f..8faac3a0b3 100644 --- a/docs/en/api-reference/system/index.rst +++ b/docs/en/api-reference/system/index.rst @@ -2,29 +2,29 @@ System API ********** .. toctree:: - :maxdepth: 1 + :maxdepth: 1 - FreeRTOS - FreeRTOS Additions - Heap Memory Allocation - Heap Memory Debugging - Himem (large external SPI RAM) API - Interrupt Allocation - Watchdogs - eFuse Manager - Inter-Processor Call - High Resolution Timer - Logging - Event Loop Library - Application Level Tracing - Power Management - Sleep Modes - Over The Air Updates (OTA) - ESP HTTPS OTA - ESP pthread - Error Codes and Helper Functions - App image format - Miscellaneous System APIs + App image format + Application Level Tracing + eFuse Manager + Error Codes and Helper Functions + ESP HTTPS OTA + ESP pthread + Event Loop Library + FreeRTOS + FreeRTOS Additions + Heap Memory Allocation + Heap Memory Debugging + High Resolution Timer + Himem (large external SPI RAM) API + Inter-Processor Call + Interrupt Allocation + Logging + Miscellaneous System APIs + Over The Air Updates (OTA) + Power Management + Sleep Modes + Watchdogs Code examples for this API section are provided in the :example:`system` directory of ESP-IDF examples. diff --git a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c index 64b989e741..f790e58e5b 100644 --- a/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c +++ b/examples/bluetooth/bluedroid/ble/blufi/main/blufi_security.c @@ -28,7 +28,7 @@ #include "mbedtls/aes.h" #include "mbedtls/dhm.h" #include "mbedtls/md5.h" -#include "esp32/rom/crc.h" +#include "esp_crc.h" /* The SEC_TYPE_xxx is for self-defined packet data type in the procedure of "BLUFI negotiate key" @@ -124,7 +124,7 @@ void blufi_dh_negotiate_data_handler(uint8_t *data, int len, uint8_t **output_da mbedtls_md5(blufi_sec->share_key, blufi_sec->share_len, blufi_sec->psk); mbedtls_aes_setkey_enc(&blufi_sec->aes, blufi_sec->psk, 128); - + /* alloc output data */ *output_data = &blufi_sec->self_public_key[0]; *output_len = blufi_sec->dhm.len; @@ -178,7 +178,7 @@ int blufi_aes_decrypt(uint8_t iv8, uint8_t *crypt_data, int crypt_len) uint16_t blufi_crc_checksum(uint8_t iv8, uint8_t *data, int len) { /* This iv8 ignore, not used */ - return crc16_be(0, data, len); + return esp_crc16_be(0, data, len); } esp_err_t blufi_security_init(void) diff --git a/examples/bluetooth/nimble/blecent/blecent_test.py b/examples/bluetooth/nimble/blecent/blecent_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blecent/blecent_test.py rename to examples/bluetooth/nimble/blecent/blecent_test_noci.py diff --git a/examples/bluetooth/nimble/blehr/blehr_test.py b/examples/bluetooth/nimble/blehr/blehr_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/blehr/blehr_test.py rename to examples/bluetooth/nimble/blehr/blehr_test_noci.py diff --git a/examples/bluetooth/nimble/bleprph/bleprph_test.py b/examples/bluetooth/nimble/bleprph/bleprph_test_noci.py similarity index 100% rename from examples/bluetooth/nimble/bleprph/bleprph_test.py rename to examples/bluetooth/nimble/bleprph/bleprph_test_noci.py diff --git a/examples/mesh/internal_communication/main/mesh_light.c b/examples/mesh/internal_communication/main/mesh_light.c index 490fd80e0f..b64c01fb96 100644 --- a/examples/mesh/internal_communication/main/mesh_light.c +++ b/examples/mesh/internal_communication/main/mesh_light.c @@ -42,8 +42,12 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_LOW_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; +#ifdef CONFIG_IDF_TARGET_ESP32 + ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; +#endif ledc_timer_config(&ledc_timer); ledc_channel_config_t ledc_channel = { diff --git a/examples/mesh/manual_networking/main/mesh_light.c b/examples/mesh/manual_networking/main/mesh_light.c index 20d5ab3a21..2ebed91a59 100644 --- a/examples/mesh/manual_networking/main/mesh_light.c +++ b/examples/mesh/manual_networking/main/mesh_light.c @@ -42,8 +42,12 @@ esp_err_t mesh_light_init(void) .bit_num = LEDC_TIMER_13_BIT, .freq_hz = 5000, .speed_mode = LEDC_LOW_SPEED_MODE, - .timer_num = LEDC_TIMER_0 + .timer_num = LEDC_TIMER_0, + .clk_cfg = LEDC_AUTO_CLK, }; +#ifdef CONFIG_IDF_TARGET_ESP32 + ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; +#endif ledc_timer_config(&ledc_timer); ledc_channel_config_t ledc_channel = { diff --git a/examples/peripherals/ledc/main/ledc_example_main.c b/examples/peripherals/ledc/main/ledc_example_main.c index 3d7c041f5c..97e3a07c6c 100644 --- a/examples/peripherals/ledc/main/ledc_example_main.c +++ b/examples/peripherals/ledc/main/ledc_example_main.c @@ -70,7 +70,8 @@ void app_main(void) .duty_resolution = LEDC_TIMER_13_BIT, // resolution of PWM duty .freq_hz = 5000, // frequency of PWM signal .speed_mode = LEDC_LS_MODE, // timer mode - .timer_num = LEDC_LS_TIMER // timer index + .timer_num = LEDC_LS_TIMER, // timer index + .clk_cfg = LEDC_AUTO_CLK, // Auto select the source clock }; // Set configuration of timer0 for high speed channels ledc_timer_config(&ledc_timer); diff --git a/examples/peripherals/pcnt/main/pcnt_example_main.c b/examples/peripherals/pcnt/main/pcnt_example_main.c index ea59792df2..7a298e6cea 100644 --- a/examples/peripherals/pcnt/main/pcnt_example_main.c +++ b/examples/peripherals/pcnt/main/pcnt_example_main.c @@ -100,6 +100,7 @@ static void ledc_init(void) ledc_timer.timer_num = LEDC_TIMER_1; ledc_timer.duty_resolution = LEDC_TIMER_10_BIT; ledc_timer.freq_hz = 1; // set output frequency at 1 Hz + ledc_timer.clk_cfg = LEDC_AUTO_CLK; ledc_timer_config(&ledc_timer); // Prepare and then apply the LEDC PWM channel configuration diff --git a/examples/peripherals/sdio/slave/main/Kconfig.projbuild b/examples/peripherals/sdio/slave/main/Kconfig.projbuild index 82a44877a6..b3485bd3c5 100644 --- a/examples/peripherals/sdio/slave/main/Kconfig.projbuild +++ b/examples/peripherals/sdio/slave/main/Kconfig.projbuild @@ -2,7 +2,7 @@ menu "Example Configuration" config SDIO_DAT2_DISABLED bool "Disable the DAT2 in SDIO slave" - default y + default n help SDIO slave DAT pin is unfortunately the same pin as MTDI, which controls the flash power voltage. For 3.3v flash devkits / modules / diff --git a/examples/peripherals/sdio/slave/main/app_main.c b/examples/peripherals/sdio/slave/main/app_main.c index 147f4aba49..3a6a7c7593 100644 --- a/examples/peripherals/sdio/slave/main/app_main.c +++ b/examples/peripherals/sdio/slave/main/app_main.c @@ -8,7 +8,6 @@ */ #include "driver/sdio_slave.h" #include "esp_log.h" -#include "esp32/rom/lldesc.h" #include "sys/queue.h" #include "soc/soc.h" #include "freertos/task.h" diff --git a/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt new file mode 100644 index 0000000000..cde4d0eed4 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/CMakeLists.txt @@ -0,0 +1,4 @@ +set(tjpgd_srcs "src/tjpgd.c") + +idf_component_register(SRCS "${tjpgd_srcs}" + INCLUDE_DIRS "include") diff --git a/examples/peripherals/spi_master/components/tjpgd/component.mk b/examples/peripherals/spi_master/components/tjpgd/component.mk new file mode 100644 index 0000000000..24cab8b637 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/component.mk @@ -0,0 +1,3 @@ +COMPONENT_ADD_INCLUDEDIRS := include + +COMPONENT_SRCDIRS := src diff --git a/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h new file mode 100644 index 0000000000..abb9dd4803 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/include/tjpgd.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor include file (C)ChaN, 2019 +/----------------------------------------------------------------------------*/ +#ifndef DEF_TJPGDEC +#define DEF_TJPGDEC +/*---------------------------------------------------------------------------*/ +/* System Configurations */ + +#define JD_SZBUF 512 /* Size of stream input buffer */ +#define JD_FORMAT 0 /* Output pixel format 0:RGB888 (3 BYTE/pix), 1:RGB565 (1 WORD/pix) */ +#define JD_USE_SCALE 1 /* Use descaling feature for output */ +#define JD_TBLCLIP 1 /* Use table for saturation (might be a bit faster but increases 1K bytes of code size) */ + +/*---------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_WIN32) /* Main development platform */ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned long uint32_t; +typedef long int32_t; +#else +#include "stdint.h" +#endif + +/* Error code */ +typedef enum { + JDR_OK = 0, /* 0: Succeeded */ + JDR_INTR, /* 1: Interrupted by output function */ + JDR_INP, /* 2: Device error or wrong termination of input stream */ + JDR_MEM1, /* 3: Insufficient memory pool for the image */ + JDR_MEM2, /* 4: Insufficient stream input buffer */ + JDR_PAR, /* 5: Parameter error */ + JDR_FMT1, /* 6: Data format error (may be damaged data) */ + JDR_FMT2, /* 7: Right format but not supported */ + JDR_FMT3 /* 8: Not supported JPEG standard */ +} JRESULT; + + + +/* Rectangular structure */ +typedef struct { + uint16_t left, right, top, bottom; +} JRECT; + + + +/* Decompressor object structure */ +typedef struct JDEC JDEC; +struct JDEC { + uint16_t dctr; /* Number of bytes available in the input buffer */ + uint8_t* dptr; /* Current data read ptr */ + uint8_t* inbuf; /* Bit stream input buffer */ + uint8_t dmsk; /* Current bit in the current read byte */ + uint8_t scale; /* Output scaling ratio */ + uint8_t msx, msy; /* MCU size in unit of block (width, height) */ + uint8_t qtid[3]; /* Quantization table ID of each component */ + int16_t dcv[3]; /* Previous DC element of each component */ + uint16_t nrst; /* Restart inverval */ + uint16_t width, height; /* Size of the input image (pixel) */ + uint8_t* huffbits[2][2]; /* Huffman bit distribution tables [id][dcac] */ + uint16_t* huffcode[2][2]; /* Huffman code word tables [id][dcac] */ + uint8_t* huffdata[2][2]; /* Huffman decoded data tables [id][dcac] */ + int32_t* qttbl[4]; /* Dequantizer tables [id] */ + void* workbuf; /* Working buffer for IDCT and RGB output */ + uint8_t* mcubuf; /* Working buffer for the MCU */ + void* pool; /* Pointer to available memory pool */ + uint16_t sz_pool; /* Size of momory pool (bytes available) */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t);/* Pointer to jpeg stream input function */ + void* device; /* Pointer to I/O device identifiler for the session */ +}; + + + +/* TJpgDec API functions */ +JRESULT jd_prepare (JDEC*, uint16_t(*)(JDEC*,uint8_t*,uint16_t), void*, uint16_t, void*); +JRESULT jd_decomp (JDEC*, uint16_t(*)(JDEC*,void*,JRECT*), uint8_t); + + +#ifdef __cplusplus +} +#endif + +#endif /* _TJPGDEC */ diff --git a/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c new file mode 100644 index 0000000000..dc87fe08e1 --- /dev/null +++ b/examples/peripherals/spi_master/components/tjpgd/src/tjpgd.c @@ -0,0 +1,960 @@ +/*----------------------------------------------------------------------------/ +/ TJpgDec - Tiny JPEG Decompressor R0.01c (C)ChaN, 2019 +/-----------------------------------------------------------------------------/ +/ The TJpgDec is a generic JPEG decompressor module for tiny embedded systems. +/ This is a free software that opened for education, research and commercial +/ developments under license policy of following terms. +/ +/ Copyright (C) 2019, ChaN, all right reserved. +/ +/ * The TJpgDec module is a free software and there is NO WARRANTY. +/ * No restriction on use. You can use, modify and redistribute it for +/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +/ * Redistributions of source code must retain the above copyright notice. +/ +/-----------------------------------------------------------------------------/ +/ Oct 04, 2011 R0.01 First release. +/ Feb 19, 2012 R0.01a Fixed decompression fails when scan starts with an escape seq. +/ Sep 03, 2012 R0.01b Added JD_TBLCLIP option. +/ Mar 16, 2019 R0.01c Supprted stdint.h. +/----------------------------------------------------------------------------*/ + +#include "tjpgd.h" + + +/*-----------------------------------------------*/ +/* Zigzag-order to raster-order conversion table */ +/*-----------------------------------------------*/ + +#define ZIG(n) Zig[n] + +static const uint8_t Zig[64] = { /* Zigzag-order to raster-order conversion table */ + 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 +}; + + + +/*-------------------------------------------------*/ +/* Input scale factor of Arai algorithm */ +/* (scaled up 16 bits for fixed point operations) */ +/*-------------------------------------------------*/ + +#define IPSF(n) Ipsf[n] + +static const uint16_t Ipsf[64] = { /* See also aa_idct.png */ + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(1.38704*8192), (uint16_t)(1.92388*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.08979*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.38268*8192), + (uint16_t)(1.30656*8192), (uint16_t)(1.81226*8192), (uint16_t)(1.70711*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.36048*8192), + (uint16_t)(1.17588*8192), (uint16_t)(1.63099*8192), (uint16_t)(1.53636*8192), (uint16_t)(1.38268*8192), (uint16_t)(1.17588*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.32442*8192), + (uint16_t)(1.00000*8192), (uint16_t)(1.38704*8192), (uint16_t)(1.30656*8192), (uint16_t)(1.17588*8192), (uint16_t)(1.00000*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.27590*8192), + (uint16_t)(0.78570*8192), (uint16_t)(1.08979*8192), (uint16_t)(1.02656*8192), (uint16_t)(0.92388*8192), (uint16_t)(0.78570*8192), (uint16_t)(0.61732*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.21677*8192), + (uint16_t)(0.54120*8192), (uint16_t)(0.75066*8192), (uint16_t)(0.70711*8192), (uint16_t)(0.63638*8192), (uint16_t)(0.54120*8192), (uint16_t)(0.42522*8192), (uint16_t)(0.29290*8192), (uint16_t)(0.14932*8192), + (uint16_t)(0.27590*8192), (uint16_t)(0.38268*8192), (uint16_t)(0.36048*8192), (uint16_t)(0.32442*8192), (uint16_t)(0.27590*8192), (uint16_t)(0.21678*8192), (uint16_t)(0.14932*8192), (uint16_t)(0.07612*8192) +}; + + + +/*---------------------------------------------*/ +/* Conversion table for fast clipping process */ +/*---------------------------------------------*/ + +#if JD_TBLCLIP + +#define BYTECLIP(v) Clip8[(uint16_t)(v) & 0x3FF] + +static const uint8_t Clip8[1024] = { + /* 0..255 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, + /* 256..511 */ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + /* -512..-257 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* -256..-1 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#else /* JD_TBLCLIP */ + +inline uint8_t BYTECLIP ( + int16_t val +) +{ + if (val < 0) val = 0; + if (val > 255) val = 255; + + return (uint8_t)val; +} + +#endif + + + +/*-----------------------------------------------------------------------*/ +/* Allocate a memory block from memory pool */ +/*-----------------------------------------------------------------------*/ + +static void* alloc_pool ( /* Pointer to allocated memory block (NULL:no memory available) */ + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t nd /* Number of bytes to allocate */ +) +{ + char *rp = 0; + + + nd = (nd + 3) & ~3; /* Align block size to the word boundary */ + + if (jd->sz_pool >= nd) { + jd->sz_pool -= nd; + rp = (char*)jd->pool; /* Get start of available memory pool */ + jd->pool = (void*)(rp + nd); /* Allocate requierd bytes */ + } + + return (void*)rp; /* Return allocated memory block (NULL:no memory to allocate) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create de-quantization and prescaling tables with a DQT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_qt_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the quantizer tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i; + uint8_t d, z; + int32_t *pb; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 65) return JDR_FMT1; /* Err: table size is unaligned */ + ndata -= 65; + d = *data++; /* Get table property */ + if (d & 0xF0) return JDR_FMT1; /* Err: not 8-bit resolution */ + i = d & 3; /* Get table ID */ + pb = alloc_pool(jd, 64 * sizeof (int32_t));/* Allocate a memory block for the table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->qttbl[i] = pb; /* Register the table */ + for (i = 0; i < 64; i++) { /* Load the table */ + z = ZIG(i); /* Zigzag-order to raster-order conversion */ + pb[z] = (int32_t)((uint32_t)*data++ * IPSF(z)); /* Apply scale factor of Arai algorithm to the de-quantizers */ + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Create huffman code tables with a DHT segment */ +/*-----------------------------------------------------------------------*/ + +static int create_huffman_tbl ( /* 0:OK, !0:Failed */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* data, /* Pointer to the packed huffman tables */ + uint16_t ndata /* Size of input data */ +) +{ + uint16_t i, j, b, np, cls, num; + uint8_t d, *pb, *pd; + uint16_t hc, *ph; + + + while (ndata) { /* Process all tables in the segment */ + if (ndata < 17) return JDR_FMT1; /* Err: wrong data size */ + ndata -= 17; + d = *data++; /* Get table number and class */ + if (d & 0xEE) return JDR_FMT1; /* Err: invalid class/number */ + cls = d >> 4; num = d & 0x0F; /* class = dc(0)/ac(1), table number = 0/1 */ + pb = alloc_pool(jd, 16); /* Allocate a memory block for the bit distribution table */ + if (!pb) return JDR_MEM1; /* Err: not enough memory */ + jd->huffbits[num][cls] = pb; + for (np = i = 0; i < 16; i++) { /* Load number of patterns for 1 to 16-bit code */ + np += (pb[i] = *data++); /* Get sum of code words for each code */ + } + ph = alloc_pool(jd, (uint16_t)(np * sizeof (uint16_t)));/* Allocate a memory block for the code word table */ + if (!ph) return JDR_MEM1; /* Err: not enough memory */ + jd->huffcode[num][cls] = ph; + hc = 0; + for (j = i = 0; i < 16; i++) { /* Re-build huffman code word table */ + b = pb[i]; + while (b--) ph[j++] = hc++; + hc <<= 1; + } + + if (ndata < np) return JDR_FMT1; /* Err: wrong data size */ + ndata -= np; + pd = alloc_pool(jd, np); /* Allocate a memory block for the decoded data */ + if (!pd) return JDR_MEM1; /* Err: not enough memory */ + jd->huffdata[num][cls] = pd; + for (i = 0; i < np; i++) { /* Load decoded data corresponds to each code ward */ + d = *data++; + if (!cls && d > 11) return JDR_FMT1; + *pd++ = d; + } + } + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract N bits from input stream */ +/*-----------------------------------------------------------------------*/ + +static int bitext ( /* >=0: extracted data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + int nbit /* Number of bits to extract (1 to 11) */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + nbit--; + } while (nbit); + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + + return (int)v; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Extract a huffman decoded data from input stream */ +/*-----------------------------------------------------------------------*/ + +static int16_t huffext ( /* >=0: decoded data, <0: error code */ + JDEC* jd, /* Pointer to the decompressor object */ + const uint8_t* hbits, /* Pointer to the bit distribution table */ + const uint16_t* hcode, /* Pointer to the code word table */ + const uint8_t* hdata /* Pointer to the data table */ +) +{ + uint8_t msk, s, *dp; + uint16_t dc, v, f, bl, nd; + + + msk = jd->dmsk; dc = jd->dctr; dp = jd->dptr; /* Bit mask, number of data available, read ptr */ + s = *dp; v = f = 0; + bl = 16; /* Max code length */ + do { + if (!msk) { /* Next byte? */ + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; /* Top of input buffer */ + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return 0 - (int16_t)JDR_INP; /* Err: read error or wrong stream termination */ + } else { + dp++; /* Next data ptr */ + } + dc--; /* Decrement number of available bytes */ + if (f) { /* In flag sequence? */ + f = 0; /* Exit flag sequence */ + if (*dp != 0) return 0 - (int16_t)JDR_FMT1; /* Err: unexpected flag is detected (may be collapted data) */ + *dp = s = 0xFF; /* The flag is a data 0xFF */ + } else { + s = *dp; /* Get next data byte */ + if (s == 0xFF) { /* Is start of flag sequence? */ + f = 1; continue; /* Enter flag sequence, get trailing byte */ + } + } + msk = 0x80; /* Read from MSB */ + } + v <<= 1; /* Get a bit */ + if (s & msk) v++; + msk >>= 1; + + for (nd = *hbits++; nd; nd--) { /* Search the code word in this bit length */ + if (v == *hcode++) { /* Matched? */ + jd->dmsk = msk; jd->dctr = dc; jd->dptr = dp; + return *hdata; /* Return the decoded data */ + } + hdata++; + } + bl--; + } while (bl); + + return 0 - (int16_t)JDR_FMT1; /* Err: code not found (may be collapted data) */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Apply Inverse-DCT in Arai Algorithm (see also aa_idct.png) */ +/*-----------------------------------------------------------------------*/ + +static void block_idct ( + int32_t* src, /* Input block data (de-quantized and pre-scaled for Arai Algorithm) */ + uint8_t* dst /* Pointer to the destination to store the block as byte array */ +) +{ + const int32_t M13 = (int32_t)(1.41421*4096), M2 = (int32_t)(1.08239*4096), M4 = (int32_t)(2.61313*4096), M5 = (int32_t)(1.84776*4096); + int32_t v0, v1, v2, v3, v4, v5, v6, v7; + int32_t t10, t11, t12, t13; + uint16_t i; + + /* Process columns */ + for (i = 0; i < 8; i++) { + v0 = src[8 * 0]; /* Get even elements */ + v1 = src[8 * 2]; + v2 = src[8 * 4]; + v3 = src[8 * 6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[8 * 7]; /* Get odd elements */ + v5 = src[8 * 1]; + v6 = src[8 * 5]; + v7 = src[8 * 3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + src[8 * 0] = v0 + v7; /* Write-back transformed values */ + src[8 * 7] = v0 - v7; + src[8 * 1] = v1 + v6; + src[8 * 6] = v1 - v6; + src[8 * 2] = v2 + v5; + src[8 * 5] = v2 - v5; + src[8 * 3] = v3 + v4; + src[8 * 4] = v3 - v4; + + src++; /* Next column */ + } + + /* Process rows */ + src -= 8; + for (i = 0; i < 8; i++) { + v0 = src[0] + (128L << 8); /* Get even elements (remove DC offset (-128) here) */ + v1 = src[2]; + v2 = src[4]; + v3 = src[6]; + + t10 = v0 + v2; /* Process the even elements */ + t12 = v0 - v2; + t11 = (v1 - v3) * M13 >> 12; + v3 += v1; + t11 -= v3; + v0 = t10 + v3; + v3 = t10 - v3; + v1 = t11 + t12; + v2 = t12 - t11; + + v4 = src[7]; /* Get odd elements */ + v5 = src[1]; + v6 = src[5]; + v7 = src[3]; + + t10 = v5 - v4; /* Process the odd elements */ + t11 = v5 + v4; + t12 = v6 - v7; + v7 += v6; + v5 = (t11 - v7) * M13 >> 12; + v7 += t11; + t13 = (t10 + t12) * M5 >> 12; + v4 = t13 - (t10 * M2 >> 12); + v6 = t13 - (t12 * M4 >> 12) - v7; + v5 -= v6; + v4 -= v5; + + dst[0] = BYTECLIP((v0 + v7) >> 8); /* Descale the transformed values 8 bits and output */ + dst[7] = BYTECLIP((v0 - v7) >> 8); + dst[1] = BYTECLIP((v1 + v6) >> 8); + dst[6] = BYTECLIP((v1 - v6) >> 8); + dst[2] = BYTECLIP((v2 + v5) >> 8); + dst[5] = BYTECLIP((v2 - v5) >> 8); + dst[3] = BYTECLIP((v3 + v4) >> 8); + dst[4] = BYTECLIP((v3 - v4) >> 8); + dst += 8; + + src += 8; /* Next row */ + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Load all blocks in the MCU into working buffer */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_load ( + JDEC* jd /* Pointer to the decompressor object */ +) +{ + int32_t *tmp = (int32_t*)jd->workbuf; /* Block working buffer for de-quantize and IDCT */ + int b, d, e; + uint16_t blk, nby, nbc, i, z, id, cmp; + uint8_t *bp; + const uint8_t *hb, *hd; + const uint16_t *hc; + const int32_t *dqf; + + + nby = jd->msx * jd->msy; /* Number of Y blocks (1, 2 or 4) */ + nbc = 2; /* Number of C blocks (2) */ + bp = jd->mcubuf; /* Pointer to the first block */ + + for (blk = 0; blk < nby + nbc; blk++) { + cmp = (blk < nby) ? 0 : blk - nby + 1; /* Component number 0:Y, 1:Cb, 2:Cr */ + id = cmp ? 1 : 0; /* Huffman table ID of the component */ + + /* Extract a DC element from input stream */ + hb = jd->huffbits[id][0]; /* Huffman table for the DC element */ + hc = jd->huffcode[id][0]; + hd = jd->huffdata[id][0]; + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded data (bit length) */ + if (b < 0) return 0 - b; /* Err: invalid code or input */ + d = jd->dcv[cmp]; /* DC value of previous block */ + if (b) { /* If there is any difference from previous block */ + e = bitext(jd, b); /* Extract data bits */ + if (e < 0) return 0 - e; /* Err: input */ + b = 1 << (b - 1); /* MSB position */ + if (!(e & b)) e -= (b << 1) - 1; /* Restore sign if needed */ + d += e; /* Get current value */ + jd->dcv[cmp] = (int16_t)d; /* Save current DC value for next block */ + } + dqf = jd->qttbl[jd->qtid[cmp]]; /* De-quantizer table ID for this component */ + tmp[0] = d * dqf[0] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + + /* Extract following 63 AC elements from input stream */ + for (i = 1; i < 64; tmp[i++] = 0) ; /* Clear rest of elements */ + hb = jd->huffbits[id][1]; /* Huffman table for the AC elements */ + hc = jd->huffcode[id][1]; + hd = jd->huffdata[id][1]; + i = 1; /* Top of the AC elements */ + do { + b = huffext(jd, hb, hc, hd); /* Extract a huffman coded value (zero runs and bit length) */ + if (b == 0) break; /* EOB? */ + if (b < 0) return 0 - b; /* Err: invalid code or input error */ + z = (uint16_t)b >> 4; /* Number of leading zero elements */ + if (z) { + i += z; /* Skip zero elements */ + if (i >= 64) return JDR_FMT1; /* Too long zero run */ + } + if (b &= 0x0F) { /* Bit length */ + d = bitext(jd, b); /* Extract data bits */ + if (d < 0) return 0 - d; /* Err: input device */ + b = 1 << (b - 1); /* MSB position */ + if (!(d & b)) d -= (b << 1) - 1;/* Restore negative value if needed */ + z = ZIG(i); /* Zigzag-order to raster-order converted index */ + tmp[z] = d * dqf[z] >> 8; /* De-quantize, apply scale factor of Arai algorithm and descale 8 bits */ + } + } while (++i < 64); /* Next AC element */ + + if (JD_USE_SCALE && jd->scale == 3) { + *bp = (uint8_t)((*tmp / 256) + 128); /* If scale ratio is 1/8, IDCT can be ommited and only DC element is used */ + } else { + block_idct(tmp, bp); /* Apply IDCT and store the block to the MCU buffer */ + } + + bp += 64; /* Next block */ + } + + return JDR_OK; /* All blocks have been loaded successfully */ +} + + + + +/*-----------------------------------------------------------------------*/ +/* Output an MCU: Convert YCrCb to RGB and output it in RGB form */ +/*-----------------------------------------------------------------------*/ + +static JRESULT mcu_output ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint16_t x, /* MCU position in the image (left of the MCU) */ + uint16_t y /* MCU position in the image (top of the MCU) */ +) +{ + const int16_t CVACC = (sizeof (int16_t) > 2) ? 1024 : 128; + uint16_t ix, iy, mx, my, rx, ry; + int16_t yy, cb, cr; + uint8_t *py, *pc, *rgb24; + JRECT rect; + + + mx = jd->msx * 8; my = jd->msy * 8; /* MCU size (pixel) */ + rx = (x + mx <= jd->width) ? mx : jd->width - x; /* Output rectangular size (it may be clipped at right/bottom end) */ + ry = (y + my <= jd->height) ? my : jd->height - y; + if (JD_USE_SCALE) { + rx >>= jd->scale; ry >>= jd->scale; + if (!rx || !ry) return JDR_OK; /* Skip this MCU if all pixel is to be rounded off */ + x >>= jd->scale; y >>= jd->scale; + } + rect.left = x; rect.right = x + rx - 1; /* Rectangular area in the frame buffer */ + rect.top = y; rect.bottom = y + ry - 1; + + + if (!JD_USE_SCALE || jd->scale != 3) { /* Not for 1/8 scaling */ + + /* Build an RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy++) { + pc = jd->mcubuf; + py = pc + iy * 8; + if (my == 16) { /* Double block height? */ + pc += 64 * 4 + (iy >> 1) * 8; + if (iy >= 8) py += 64; + } else { /* Single block height */ + pc += mx * 8 + iy * 8; + } + for (ix = 0; ix < mx; ix++) { + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + if (mx == 16) { /* Double block width? */ + if (ix == 8) py += 64 - 8; /* Jump to next block if double block heigt */ + pc += ix & 1; /* Increase chroma pointer every two pixels */ + } else { /* Single block width */ + pc++; /* Increase chroma pointer every pixel */ + } + yy = *py++; /* Get Y component */ + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr) / CVACC); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb) / CVACC); + } + } + + /* Descale the MCU rectangular if needed */ + if (JD_USE_SCALE && jd->scale) { + uint16_t x, y, r, g, b, s, w, a; + uint8_t *op; + + /* Get averaged RGB value of each square correcponds to a pixel */ + s = jd->scale * 2; /* Bumber of shifts for averaging */ + w = 1 << jd->scale; /* Width of square */ + a = (mx - w) * 3; /* Bytes to skip for next line in the square */ + op = (uint8_t*)jd->workbuf; + for (iy = 0; iy < my; iy += w) { + for (ix = 0; ix < mx; ix += w) { + rgb24 = (uint8_t*)jd->workbuf + (iy * mx + ix) * 3; + r = g = b = 0; + for (y = 0; y < w; y++) { /* Accumulate RGB value in the square */ + for (x = 0; x < w; x++) { + r += *rgb24++; + g += *rgb24++; + b += *rgb24++; + } + rgb24 += a; + } /* Put the averaged RGB value as a pixel */ + *op++ = (uint8_t)(r >> s); + *op++ = (uint8_t)(g >> s); + *op++ = (uint8_t)(b >> s); + } + } + } + + } else { /* For only 1/8 scaling (left-top pixel in each block are the DC value of the block) */ + + /* Build a 1/8 descaled RGB MCU from discrete comopnents */ + rgb24 = (uint8_t*)jd->workbuf; + pc = jd->mcubuf + mx * my; + cb = pc[0] - 128; /* Get Cb/Cr component and restore right level */ + cr = pc[64] - 128; + for (iy = 0; iy < my; iy += 8) { + py = jd->mcubuf; + if (iy == 8) py += 64 * 2; + for (ix = 0; ix < mx; ix += 8) { + yy = *py; /* Get Y component */ + py += 64; + + /* Convert YCbCr to RGB */ + *rgb24++ = /* R */ BYTECLIP(yy + ((int16_t)(1.402 * CVACC) * cr / CVACC)); + *rgb24++ = /* G */ BYTECLIP(yy - ((int16_t)(0.344 * CVACC) * cb + (int16_t)(0.714 * CVACC) * cr) / CVACC); + *rgb24++ = /* B */ BYTECLIP(yy + ((int16_t)(1.772 * CVACC) * cb / CVACC)); + } + } + } + + /* Squeeze up pixel table if a part of MCU is to be truncated */ + mx >>= jd->scale; + if (rx < mx) { + uint8_t *s, *d; + uint16_t x, y; + + s = d = (uint8_t*)jd->workbuf; + for (y = 0; y < ry; y++) { + for (x = 0; x < rx; x++) { /* Copy effective pixels */ + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + s += (mx - rx) * 3; /* Skip truncated pixels */ + } + } + + /* Convert RGB888 to RGB565 if needed */ + if (JD_FORMAT == 1) { + uint8_t *s = (uint8_t*)jd->workbuf; + uint16_t w, *d = (uint16_t*)s; + uint16_t n = rx * ry; + + do { + w = (*s++ & 0xF8) << 8; /* RRRRR----------- */ + w |= (*s++ & 0xFC) << 3; /* -----GGGGGG----- */ + w |= *s++ >> 3; /* -----------BBBBB */ + *d++ = w; + } while (--n); + } + + /* Output the RGB rectangular */ + return outfunc(jd, jd->workbuf, &rect) ? JDR_OK : JDR_INTR; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Process restart interval */ +/*-----------------------------------------------------------------------*/ + +static JRESULT restart ( + JDEC* jd, /* Pointer to the decompressor object */ + uint16_t rstn /* Expected restert sequense number */ +) +{ + uint16_t i, dc; + uint16_t d; + uint8_t *dp; + + + /* Discard padding bits and get two bytes from the input stream */ + dp = jd->dptr; dc = jd->dctr; + d = 0; + for (i = 0; i < 2; i++) { + if (!dc) { /* No input data is available, re-fill input buffer */ + dp = jd->inbuf; + dc = jd->infunc(jd, dp, JD_SZBUF); + if (!dc) return JDR_INP; + } else { + dp++; + } + dc--; + d = (d << 8) | *dp; /* Get a byte */ + } + jd->dptr = dp; jd->dctr = dc; jd->dmsk = 0; + + /* Check the marker */ + if ((d & 0xFFD8) != 0xFFD0 || (d & 7) != (rstn & 7)) { + return JDR_FMT1; /* Err: expected RSTn marker is not detected (may be collapted data) */ + } + + /* Reset DC offset */ + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; + + return JDR_OK; +} + + + + +/*-----------------------------------------------------------------------*/ +/* Analyze the JPEG image and Initialize decompressor object */ +/*-----------------------------------------------------------------------*/ + +#define LDB_WORD(ptr) (uint16_t)(((uint16_t)*((uint8_t*)(ptr))<<8)|(uint16_t)*(uint8_t*)((ptr)+1)) + + +JRESULT jd_prepare ( + JDEC* jd, /* Blank decompressor object */ + uint16_t (*infunc)(JDEC*, uint8_t*, uint16_t), /* JPEG strem input function */ + void* pool, /* Working buffer for the decompression session */ + uint16_t sz_pool, /* Size of working buffer */ + void* dev /* I/O device identifier for the session */ +) +{ + uint8_t *seg, b; + uint16_t marker; + uint32_t ofs; + uint16_t n, i, j, len; + JRESULT rc; + + + if (!pool) return JDR_PAR; + + jd->pool = pool; /* Work memroy */ + jd->sz_pool = sz_pool; /* Size of given work memory */ + jd->infunc = infunc; /* Stream input function */ + jd->device = dev; /* I/O device identifier */ + jd->nrst = 0; /* No restart interval (default) */ + + for (i = 0; i < 2; i++) { /* Nulls pointers */ + for (j = 0; j < 2; j++) { + jd->huffbits[i][j] = 0; + jd->huffcode[i][j] = 0; + jd->huffdata[i][j] = 0; + } + } + for (i = 0; i < 4; jd->qttbl[i++] = 0) ; + + jd->inbuf = seg = alloc_pool(jd, JD_SZBUF); /* Allocate stream input buffer */ + if (!seg) return JDR_MEM1; + + if (jd->infunc(jd, seg, 2) != 2) return JDR_INP;/* Check SOI marker */ + if (LDB_WORD(seg) != 0xFFD8) return JDR_FMT1; /* Err: SOI is not detected */ + ofs = 2; + + for (;;) { + /* Get a JPEG marker */ + if (jd->infunc(jd, seg, 4) != 4) return JDR_INP; + marker = LDB_WORD(seg); /* Marker */ + len = LDB_WORD(seg + 2); /* Length field */ + if (len <= 2 || (marker >> 8) != 0xFF) return JDR_FMT1; + len -= 2; /* Content size excluding length field */ + ofs += 4 + len; /* Number of bytes loaded */ + + switch (marker & 0xFF) { + case 0xC0: /* SOF0 (baseline JPEG) */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + jd->width = LDB_WORD(seg+3); /* Image width in unit of pixel */ + jd->height = LDB_WORD(seg+1); /* Image height in unit of pixel */ + if (seg[5] != 3) return JDR_FMT3; /* Err: Supports only Y/Cb/Cr format */ + + /* Check three image components */ + for (i = 0; i < 3; i++) { + b = seg[7 + 3 * i]; /* Get sampling factor */ + if (!i) { /* Y component */ + if (b != 0x11 && b != 0x22 && b != 0x21) { /* Check sampling factor */ + return JDR_FMT3; /* Err: Supports only 4:4:4, 4:2:0 or 4:2:2 */ + } + jd->msx = b >> 4; jd->msy = b & 15; /* Size of MCU [blocks] */ + } else { /* Cb/Cr component */ + if (b != 0x11) return JDR_FMT3; /* Err: Sampling factor of Cr/Cb must be 1 */ + } + b = seg[8 + 3 * i]; /* Get dequantizer table ID for this component */ + if (b > 3) return JDR_FMT3; /* Err: Invalid ID */ + jd->qtid[i] = b; + } + break; + + case 0xDD: /* DRI */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Get restart interval (MCUs) */ + jd->nrst = LDB_WORD(seg); + break; + + case 0xC4: /* DHT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create huffman tables */ + rc = create_huffman_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDB: /* DQT */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + /* Create de-quantizer tables */ + rc = create_qt_tbl(jd, seg, len); + if (rc) return rc; + break; + + case 0xDA: /* SOS */ + /* Load segment data */ + if (len > JD_SZBUF) return JDR_MEM2; + if (jd->infunc(jd, seg, len) != len) return JDR_INP; + + if (!jd->width || !jd->height) return JDR_FMT1; /* Err: Invalid image size */ + + if (seg[0] != 3) return JDR_FMT3; /* Err: Supports only three color components format */ + + /* Check if all tables corresponding to each components have been loaded */ + for (i = 0; i < 3; i++) { + b = seg[2 + 2 * i]; /* Get huffman table ID */ + if (b != 0x00 && b != 0x11) return JDR_FMT3; /* Err: Different table number for DC/AC element */ + b = i ? 1 : 0; + if (!jd->huffbits[b][0] || !jd->huffbits[b][1]) { /* Check dc/ac huffman table for this component */ + return JDR_FMT1; /* Err: Nnot loaded */ + } + if (!jd->qttbl[jd->qtid[i]]) { /* Check dequantizer table for this component */ + return JDR_FMT1; /* Err: Not loaded */ + } + } + + /* Allocate working buffer for MCU and RGB */ + n = jd->msy * jd->msx; /* Number of Y blocks in the MCU */ + if (!n) return JDR_FMT1; /* Err: SOF0 has not been loaded */ + len = n * 64 * 2 + 64; /* Allocate buffer for IDCT and RGB output */ + if (len < 256) len = 256; /* but at least 256 byte is required for IDCT */ + jd->workbuf = alloc_pool(jd, len); /* and it may occupy a part of following MCU working buffer for RGB output */ + if (!jd->workbuf) return JDR_MEM1; /* Err: not enough memory */ + jd->mcubuf = (uint8_t*)alloc_pool(jd, (uint16_t)((n + 2) * 64)); /* Allocate MCU working buffer */ + if (!jd->mcubuf) return JDR_MEM1; /* Err: not enough memory */ + + /* Pre-load the JPEG data to extract it from the bit stream */ + jd->dptr = seg; jd->dctr = 0; jd->dmsk = 0; /* Prepare to read bit stream */ + if (ofs %= JD_SZBUF) { /* Align read offset to JD_SZBUF */ + jd->dctr = jd->infunc(jd, seg + ofs, (uint16_t)(JD_SZBUF - ofs)); + jd->dptr = seg + ofs - 1; + } + + return JDR_OK; /* Initialization succeeded. Ready to decompress the JPEG image. */ + + case 0xC1: /* SOF1 */ + case 0xC2: /* SOF2 */ + case 0xC3: /* SOF3 */ + case 0xC5: /* SOF5 */ + case 0xC6: /* SOF6 */ + case 0xC7: /* SOF7 */ + case 0xC9: /* SOF9 */ + case 0xCA: /* SOF10 */ + case 0xCB: /* SOF11 */ + case 0xCD: /* SOF13 */ + case 0xCE: /* SOF14 */ + case 0xCF: /* SOF15 */ + case 0xD9: /* EOI */ + return JDR_FMT3; /* Unsuppoted JPEG standard (may be progressive JPEG) */ + + default: /* Unknown segment (comment, exif or etc..) */ + /* Skip segment data */ + if (jd->infunc(jd, 0, len) != len) { /* Null pointer specifies to skip bytes of stream */ + return JDR_INP; + } + } + } +} + + + + +/*-----------------------------------------------------------------------*/ +/* Start to decompress the JPEG picture */ +/*-----------------------------------------------------------------------*/ + +JRESULT jd_decomp ( + JDEC* jd, /* Initialized decompression object */ + uint16_t (*outfunc)(JDEC*, void*, JRECT*), /* RGB output function */ + uint8_t scale /* Output de-scaling factor (0 to 3) */ +) +{ + uint16_t x, y, mx, my; + uint16_t rst, rsc; + JRESULT rc; + + + if (scale > (JD_USE_SCALE ? 3 : 0)) return JDR_PAR; + jd->scale = scale; + + mx = jd->msx * 8; my = jd->msy * 8; /* Size of the MCU (pixel) */ + + jd->dcv[2] = jd->dcv[1] = jd->dcv[0] = 0; /* Initialize DC values */ + rst = rsc = 0; + + rc = JDR_OK; + for (y = 0; y < jd->height; y += my) { /* Vertical loop of MCUs */ + for (x = 0; x < jd->width; x += mx) { /* Horizontal loop of MCUs */ + if (jd->nrst && rst++ == jd->nrst) { /* Process restart interval if enabled */ + rc = restart(jd, rsc++); + if (rc != JDR_OK) return rc; + rst = 1; + } + rc = mcu_load(jd); /* Load an MCU (decompress huffman coded stream and apply IDCT) */ + if (rc != JDR_OK) return rc; + rc = mcu_output(jd, outfunc, x, y); /* Output the MCU (color space conversion, scaling and output) */ + if (rc != JDR_OK) return rc; + } + } + + return rc; +} + + + diff --git a/examples/peripherals/spi_master/main/decode_image.c b/examples/peripherals/spi_master/main/decode_image.c index 4a4b4daed9..179c3deb7a 100644 --- a/examples/peripherals/spi_master/main/decode_image.c +++ b/examples/peripherals/spi_master/main/decode_image.c @@ -7,72 +7,69 @@ CONDITIONS OF ANY KIND, either express or implied. */ - /* -The image used for the effect on the LCD in the SPI master example is stored in flash -as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG -decoder library in ROM to decode this JPEG into a format that can be sent to the display. +The image used for the effect on the LCD in the SPI master example is stored in flash +as a jpeg file. This file contains the decode_image routine, which uses the tiny JPEG +decoder library to decode this JPEG into a format that can be sent to the display. -Keep in mind that the decoder library cannot handle progressive files (will give +Keep in mind that the decoder library cannot handle progressive files (will give ``Image decoder: jd_prepare failed (8)`` as an error) so make sure to save in the correct format if you want to use a different image file. */ - #include "decode_image.h" -#include "esp32/rom/tjpgd.h" +#include "tjpgd.h" #include "esp_log.h" #include //Reference the binary-included jpeg file -extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); -extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); +extern const uint8_t image_jpg_start[] asm("_binary_image_jpg_start"); +extern const uint8_t image_jpg_end[] asm("_binary_image_jpg_end"); //Define the height and width of the jpeg file. Make sure this matches the actual jpeg //dimensions. #define IMAGE_W 336 #define IMAGE_H 256 - -const char *TAG="ImageDec"; - +const char *TAG = "ImageDec"; //Data that is passed from the decoder function to the infunc/outfunc functions. typedef struct { - const unsigned char *inData; //Pointer to jpeg data - int inPos; //Current position in jpeg data - uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values - int outW; //Width of the resulting file - int outH; //Height of the resulting file + const unsigned char *inData; //Pointer to jpeg data + uint16_t inPos; //Current position in jpeg data + uint16_t **outData; //Array of IMAGE_H pointers to arrays of IMAGE_W 16-bit pixel values + int outW; //Width of the resulting file + int outH; //Height of the resulting file } JpegDev; - //Input function for jpeg decoder. Just returns bytes from the inData field of the JpegDev structure. -static UINT infunc(JDEC *decoder, BYTE *buf, UINT len) +static uint16_t infunc(JDEC *decoder, uint8_t *buf, uint16_t len) { //Read bytes from input file - JpegDev *jd=(JpegDev*)decoder->device; - if (buf!=NULL) memcpy(buf, jd->inData+jd->inPos, len); - jd->inPos+=len; + JpegDev *jd = (JpegDev *)decoder->device; + if (buf != NULL) { + memcpy(buf, jd->inData + jd->inPos, len); + } + jd->inPos += len; return len; } //Output function. Re-encodes the RGB888 data from the decoder as big-endian RGB565 and //stores it in the outData array of the JpegDev structure. -static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) +static uint16_t outfunc(JDEC *decoder, void *bitmap, JRECT *rect) { - JpegDev *jd=(JpegDev*)decoder->device; - uint8_t *in=(uint8_t*)bitmap; - for (int y=rect->top; y<=rect->bottom; y++) { - for (int x=rect->left; x<=rect->right; x++) { + JpegDev *jd = (JpegDev *)decoder->device; + uint8_t *in = (uint8_t *)bitmap; + for (int y = rect->top; y <= rect->bottom; y++) { + for (int x = rect->left; x <= rect->right; x++) { //We need to convert the 3 bytes in `in` to a rgb565 value. - uint16_t v=0; - v|=((in[0]>>3)<<11); - v|=((in[1]>>2)<<5); - v|=((in[2]>>3)<<0); + uint16_t v = 0; + v |= ((in[0] >> 3) << 11); + v |= ((in[1] >> 2) << 5); + v |= ((in[2] >> 3) << 0); //The LCD wants the 16-bit value in big-endian, so swap bytes - v=(v>>8)|(v<<8); - jd->outData[y][x]=v; - in+=3; + v = (v >> 8) | (v << 8); + jd->outData[y][x] = v; + in += 3; } } return 1; @@ -82,68 +79,67 @@ static UINT outfunc(JDEC *decoder, void *bitmap, JRECT *rect) #define WORKSZ 3100 //Decode the embedded image into pixel lines that can be used with the rest of the logic. -esp_err_t decode_image(uint16_t ***pixels) +esp_err_t decode_image(uint16_t ***pixels) { - char *work=NULL; + char *work = NULL; int r; JDEC decoder; JpegDev jd; - *pixels=NULL; - esp_err_t ret=ESP_OK; - + *pixels = NULL; + esp_err_t ret = ESP_OK; //Alocate pixel memory. Each line is an array of IMAGE_W 16-bit pixels; the `*pixels` array itself contains pointers to these lines. - *pixels=calloc(IMAGE_H, sizeof(uint16_t*)); - if (*pixels==NULL) { + *pixels = calloc(IMAGE_H, sizeof(uint16_t *)); + if (*pixels == NULL) { ESP_LOGE(TAG, "Error allocating memory for lines"); - ret=ESP_ERR_NO_MEM; + ret = ESP_ERR_NO_MEM; goto err; } - for (int i=0; i> 32); - TIMERG0.hw_timer[timer_idx].alarm_low = (uint32_t) timer_counter_value; - } else if ((intr_status & BIT(timer_idx)) && timer_idx == TIMER_1) { + timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, timer_idx, timer_counter_value); + } else if (timer_intr & TIMER_INTR_T1) { evt.type = TEST_WITH_RELOAD; -#ifdef CONFIG_IDF_TARGET_ESP32 - TIMERG0.int_clr_timers.t1 = 1; -#elif defined CONFIG_IDF_TARGET_ESP32S2BETA - TIMERG0.int_clr.t1 = 1; -#endif + timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1); } else { evt.type = -1; // not supported even type } /* After the alarm has been triggered we need enable it again, so it is triggered the next time */ - TIMERG0.hw_timer[timer_idx].config.alarm_en = TIMER_ALARM_EN; + timer_group_enable_alarm_in_isr(TIMER_GROUP_0, timer_idx); /* Now just send the event data back to the main program task */ xQueueSendFromISR(timer_queue, &evt, NULL); @@ -115,7 +98,7 @@ void IRAM_ATTR timer_group0_isr(void *para) * auto_reload - should the timer auto reload on alarm? * timer_interval_sec - the interval of alarm to set */ -static void example_tg0_timer_init(int timer_idx, +static void example_tg0_timer_init(int timer_idx, bool auto_reload, double timer_interval_sec) { /* Select and initialize basic parameters of the timer */ @@ -138,7 +121,7 @@ static void example_tg0_timer_init(int timer_idx, /* Configure the alarm value and the interrupt on alarm. */ timer_set_alarm_value(TIMER_GROUP_0, timer_idx, timer_interval_sec * TIMER_SCALE); timer_enable_intr(TIMER_GROUP_0, timer_idx); - timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, + timer_isr_register(TIMER_GROUP_0, timer_idx, timer_group0_isr, (void *) timer_idx, ESP_INTR_FLAG_IRAM, NULL); timer_start(TIMER_GROUP_0, timer_idx); diff --git a/examples/protocols/mqtt/ssl_psk/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt new file mode 100644 index 0000000000..77934fa675 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/CMakeLists.txt @@ -0,0 +1,10 @@ +# The following four lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(mqtt_ssl_psk) diff --git a/examples/protocols/mqtt/ssl_psk/Makefile b/examples/protocols/mqtt/ssl_psk/Makefile new file mode 100644 index 0000000000..24bec17e9d --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# +PROJECT_NAME := mqtt_ssl_psk + +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common + +include $(IDF_PATH)/make/project.mk diff --git a/examples/protocols/mqtt/ssl_psk/README.md b/examples/protocols/mqtt/ssl_psk/README.md new file mode 100644 index 0000000000..c46688f035 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/README.md @@ -0,0 +1,76 @@ +# ESP-MQTT SSL example with PSK verification + +(See the README.md file in the upper level 'examples' directory for more information about examples.) + +This example connects to a local broker configured to PSK authentication + +## How to use example + +### Hardware Required + +This example can be executed on any ESP32 board, the only required interface is WiFi (or ethernet) to connect to a MQTT +broker with preconfigured PSK verification method. + +#### Mosquitto settings +In case of using mosquitto broker, here is how to enable PSK authentication in `mosquitto.config`, +``` +psk_hint hint +psk_file path_to_your_psk_file +allow_anonymous true +``` +Note: Last line enables anonymous mode, as this example does not use mqtt username and password. + +PSK file then has to contain pairs of hints and keys, as shown below: +``` +hint:BAD123 +``` + +Important note: Keys are stored as text hexadecimal values in PSK file, while the example code stores key as plain binary +as required by MQTT API. (See the example source for details: `"BAD123" -> 0xBA, 0xD1, 0x23`) + +### Configure the project + +* Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system) +* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details. +* When using Make build system, set `Default serial port` under `Serial flasher config`. + +### Build and Flash + + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (2160) example_connect: Ethernet Link Up +I (4650) example_connect: Connected to Ethernet +I (4650) example_connect: IPv4 address: 192.168.0.1 +I (4650) MQTTS_EXAMPLE: [APP] Free memory: 244792 bytes +I (4660) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE +D (4670) MQTT_CLIENT: MQTT client_id=ESP32_c6B4F8 +D (4680) MQTT_CLIENT: Core selection disabled +I (4680) MQTTS_EXAMPLE: Other event id:7 +D (4680) esp-tls: host:192.168.0.2: strlen 13 +D (4700) esp-tls: ssl psk authentication +D (4700) esp-tls: handshake in progress... +D (4720) MQTT_CLIENT: Transport connected to mqtts://192.168.0.2:8883 +I (4720) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000 +D (4720) MQTT_CLIENT: mqtt_message_receive: first byte: 0x20 +D (4730) MQTT_CLIENT: mqtt_message_receive: read "remaining length" byte: 0x2 +D (4730) MQTT_CLIENT: mqtt_message_receive: total message length: 4 (already read: 2) +D (4740) MQTT_CLIENT: mqtt_message_receive: read_len=2 +D (4750) MQTT_CLIENT: mqtt_message_receive: transport_read():4 4 +D (4750) MQTT_CLIENT: Connected +I (4760) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED +D (4760) MQTT_CLIENT: mqtt_enqueue id: 4837, type=8 successful +D (4770) OUTBOX: ENQUEUE msgid=4837, msg_type=8, len=18, size=18 +D (4770) MQTT_CLIENT: Sent subscribe topic=/topic/qos0, id: 4837, type=8 successful +I (4780) MQTTS_EXAMPLE: sent subscribe successful, msg_id=4837 +D (4790) MQTT_CLIENT: mqtt_enqueue id: 58982, type=8 successful +D (4790) OUTBOX: ENQUEUE msgid=58982, msg_type=8, len=18, size=36 +D (4800) MQTT_CLIENT: Sent subscribe topic=/topic/qos1, id: 58982, type=8 successful +I (4810) MQTTS_EXAMPLE: sent subscribe successful, msg_id=58982 +``` + diff --git a/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt new file mode 100644 index 0000000000..6b03500639 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/CMakeLists.txt @@ -0,0 +1,4 @@ +set(COMPONENT_SRCS "app_main.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/examples/protocols/mqtt/ssl_psk/main/app_main.c b/examples/protocols/mqtt/ssl_psk/main/app_main.c new file mode 100644 index 0000000000..7a08d17725 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/main/app_main.c @@ -0,0 +1,141 @@ +/* MQTT over SSL Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include +#include "esp_wifi.h" +#include "esp_system.h" +#include "nvs_flash.h" +#include "esp_event.h" +#include "tcpip_adapter.h" +#include "protocol_examples_common.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + +#include "lwip/sockets.h" +#include "lwip/dns.h" +#include "lwip/netdb.h" + +#include "esp_log.h" +#include "mqtt_client.h" +#include "esp_tls.h" + +/* + * Add here URI of mqtt broker which supports PSK authentication + */ +#define EXAMPLE_BROKER_URI "mqtts://192.168.0.2" + +static const char *TAG = "MQTTS_EXAMPLE"; + +/* + * Define psk key and hint as defined in mqtt broker + * example for mosquitto server, content of psk_file: + * hint:BAD123 + * + */ +static const uint8_t s_key[] = { 0xBA, 0xD1, 0x23 }; + +static const psk_hint_key_t psk_hint_key = { + .key = s_key, + .key_size = sizeof(s_key), + .hint = "hint" + }; + +static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event) +{ + esp_mqtt_client_handle_t client = event->client; + int msg_id; + // your_context_t *context = event->context; + switch (event->event_id) { + case MQTT_EVENT_CONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1); + ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id); + + msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1"); + ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); + break; + + case MQTT_EVENT_SUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); + msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0); + ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id); + break; + case MQTT_EVENT_UNSUBSCRIBED: + ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_PUBLISHED: + ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); + break; + case MQTT_EVENT_DATA: + ESP_LOGI(TAG, "MQTT_EVENT_DATA"); + printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); + printf("DATA=%.*s\r\n", event->data_len, event->data); + break; + case MQTT_EVENT_ERROR: + ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); + break; + default: + ESP_LOGI(TAG, "Other event id:%d", event->event_id); + break; + } + return ESP_OK; +} + + +static void mqtt_app_start(void) +{ + const esp_mqtt_client_config_t mqtt_cfg = { + .uri = EXAMPLE_BROKER_URI, + .event_handle = mqtt_event_handler, + .psk_hint_key = &psk_hint_key, + }; + + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); + esp_mqtt_client_start(client); +} + +void app_main(void) +{ + ESP_LOGI(TAG, "[APP] Startup.."); + ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size()); + ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version()); + + esp_log_level_set("*", ESP_LOG_INFO); + esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE); + esp_log_level_set("esp-tls", ESP_LOG_VERBOSE); + esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE); + esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE); + + ESP_ERROR_CHECK(nvs_flash_init()); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + mqtt_app_start(); +} diff --git a/examples/protocols/mqtt/ssl_psk/main/component.mk b/examples/protocols/mqtt/ssl_psk/main/component.mk new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults new file mode 100644 index 0000000000..1df83e8f39 --- /dev/null +++ b/examples/protocols/mqtt/ssl_psk/sdkconfig.defaults @@ -0,0 +1 @@ +CONFIG_ESP_TLS_PSK_VERIFICATION=y diff --git a/examples/system/console/components/cmd_system/cmd_system.c b/examples/system/console/components/cmd_system/cmd_system.c index caf8d70f23..e78e41bc16 100644 --- a/examples/system/console/components/cmd_system/cmd_system.c +++ b/examples/system/console/components/cmd_system/cmd_system.c @@ -20,7 +20,6 @@ #include "argtable3/argtable3.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" -#include "esp32/rom/uart.h" #include "cmd_system.h" #include "sdkconfig.h" @@ -292,7 +291,7 @@ static int light_sleep(int argc, char **argv) ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) ); } fflush(stdout); - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); esp_light_sleep_start(); esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); const char *cause_str; diff --git a/examples/system/himem/main/himem_test_main.c b/examples/system/himem/main/himem_test_main.c index 955046b2de..004409081b 100644 --- a/examples/system/himem/main/himem_test_main.c +++ b/examples/system/himem/main/himem_test_main.c @@ -16,7 +16,6 @@ #include "nvs_flash.h" #include "esp_heap_caps.h" #include "esp32/spiram.h" -#include "esp32/rom/cache.h" #include "sdkconfig.h" #include "esp32/himem.h" diff --git a/examples/system/light_sleep/main/light_sleep_example_main.c b/examples/system/light_sleep/main/light_sleep_example_main.c index 8fb02b47bb..4b8dc17115 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -16,7 +16,7 @@ #include "freertos/task.h" #include "esp_sleep.h" #include "esp_log.h" -#include "esp32/rom/uart.h" +#include "driver/uart.h" #include "driver/rtc_io.h" /* Most development boards have "boot" button attached to GPIO0. @@ -57,7 +57,7 @@ void app_main(void) /* To make sure the complete line is printed before entering sleep mode, * need to wait until UART TX FIFO is empty: */ - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); /* Get timestamp before entering sleep */ int64_t t_before_us = esp_timer_get_time(); diff --git a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c index 0387e3e681..aafa488883 100644 --- a/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c +++ b/examples/system/ota/advanced_https_ota/main/advanced_https_ota_example.c @@ -88,6 +88,11 @@ void advanced_ota_example_task(void *pvParameter) ESP_LOGD(TAG, "Image bytes read: %d", esp_https_ota_get_image_len_read(https_ota_handle)); } + if (esp_https_ota_is_complete_data_received(&https_ota_handle) != true) { + // the OTA image was not completely received and user can customise the response to this situation. + ESP_LOGE(TAG, "Complete data was not received."); + } + ota_end: ota_finish_err = esp_https_ota_finish(https_ota_handle); if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) { diff --git a/examples/system/ota/native_ota_example/main/native_ota_example.c b/examples/system/ota/native_ota_example/main/native_ota_example.c index fc42b7f3b0..9d84cc07c6 100644 --- a/examples/system/ota/native_ota_example/main/native_ota_example.c +++ b/examples/system/ota/native_ota_example/main/native_ota_example.c @@ -182,6 +182,11 @@ static void ota_example_task(void *pvParameter) } } ESP_LOGI(TAG, "Total Write binary data length : %d", binary_file_length); + if (esp_http_client_is_complete_data_received(client) != true) { + ESP_LOGE(TAG, "Error in receiving complete file"); + http_cleanup(client); + task_fatal_error(); + } if (esp_ota_end(update_handle) != ESP_OK) { ESP_LOGE(TAG, "esp_ota_end failed!"); diff --git a/examples/system/sysview_tracing/main/sysview_tracing.c b/examples/system/sysview_tracing/main/sysview_tracing.c index 3436b4cbcb..32c4562e12 100644 --- a/examples/system/sysview_tracing/main/sysview_tracing.c +++ b/examples/system/sysview_tracing/main/sysview_tracing.c @@ -107,32 +107,6 @@ static void example_timer_init(int timer_group, int timer_idx, uint32_t period) timer_enable_intr(timer_group, timer_idx); } -static void example_timer_rearm(int timer_group, int timer_idx) -{ - if (timer_group == 0) { - if (timer_idx == 0) { - TIMERG0.int_clr_timers.t0 = 1; - TIMERG0.hw_timer[0].update = 1; - TIMERG0.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG0.int_clr_timers.t1 = 1; - TIMERG0.hw_timer[1].update = 1; - TIMERG0.hw_timer[1].config.alarm_en = 1; - } - } - if (timer_group == 1) { - if (timer_idx == 0) { - TIMERG1.int_clr_timers.t0 = 1; - TIMERG1.hw_timer[0].update = 1; - TIMERG1.hw_timer[0].config.alarm_en = 1; - } else { - TIMERG1.int_clr_timers.t1 = 1; - TIMERG1.hw_timer[1].update = 1; - TIMERG1.hw_timer[1].config.alarm_en = 1; - } - } -} - static void example_timer_isr(void *arg) { example_event_data_t *tim_arg = (example_event_data_t *)arg; @@ -152,7 +126,8 @@ static void example_timer_isr(void *arg) } } // re-start timer - example_timer_rearm(tim_arg->group, tim_arg->timer); + timer_group_intr_clr_in_isr(tim_arg->group, tim_arg->timer); + timer_group_enable_alarm_in_isr(tim_arg->group, tim_arg->timer); } static void example_task(void *p) diff --git a/examples/wifi/espnow/main/espnow_example_main.c b/examples/wifi/espnow/main/espnow_example_main.c index fbfde5780c..ad540eb335 100644 --- a/examples/wifi/espnow/main/espnow_example_main.c +++ b/examples/wifi/espnow/main/espnow_example_main.c @@ -26,8 +26,7 @@ #include "esp_log.h" #include "esp_system.h" #include "esp_now.h" -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/crc.h" +#include "esp_crc.h" #include "espnow_example.h" static const char *TAG = "espnow_example"; @@ -123,7 +122,7 @@ int example_espnow_data_parse(uint8_t *data, uint16_t data_len, uint8_t *state, *magic = buf->magic; crc = buf->crc; buf->crc = 0; - crc_cal = crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); + crc_cal = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, data_len); if (crc_cal == crc) { return buf->type; @@ -146,7 +145,7 @@ void example_espnow_data_prepare(example_espnow_send_param_t *send_param) buf->magic = send_param->magic; /* Fill all remaining bytes after the data with random values */ esp_fill_random(buf->payload, send_param->len - sizeof(example_espnow_data_t)); - buf->crc = crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); + buf->crc = esp_crc16_le(UINT16_MAX, (uint8_t const *)buf, send_param->len); } static void example_espnow_task(void *pvParameter) diff --git a/make/project_config.mk b/make/project_config.mk index e590b401f4..7eede5ebbc 100644 --- a/make/project_config.mk +++ b/make/project_config.mk @@ -3,6 +3,7 @@ #Find all Kconfig files for all components COMPONENT_KCONFIGS := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig)) COMPONENT_KCONFIGS_PROJBUILD := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/Kconfig.projbuild)) +COMPONENT_SDKCONFIG_RENAMES := $(foreach component,$(COMPONENT_PATHS),$(wildcard $(component)/sdkconfig.rename)) ifeq ($(OS),Windows_NT) # kconfiglib requires Windows-style paths for kconfig files @@ -17,6 +18,8 @@ KCONFIG_TOOL_DIR=$(IDF_PATH)/tools/kconfig # unless it's overriden (happens for bootloader) SDKCONFIG ?= $(PROJECT_PATH)/sdkconfig +SDKCONFIG_RENAME ?= $(IDF_PATH)/sdkconfig.rename + # SDKCONFIG_DEFAULTS is an optional file containing default # overrides (usually used for esp-idf examples) SDKCONFIG_DEFAULTS ?= $(PROJECT_PATH)/sdkconfig.defaults @@ -48,8 +51,10 @@ define RunConfGen $(PYTHON) $(IDF_PATH)/tools/kconfig_new/confgen.py \ --kconfig $(IDF_PATH)/Kconfig \ --config $(SDKCONFIG) \ + --sdkconfig-rename $(SDKCONFIG_RENAME) \ --env "COMPONENT_KCONFIGS=$(strip $(COMPONENT_KCONFIGS))" \ --env "COMPONENT_KCONFIGS_PROJBUILD=$(strip $(COMPONENT_KCONFIGS_PROJBUILD))" \ + --env "COMPONENT_SDKCONFIG_RENAMES=$(strip $(COMPONENT_SDKCONFIG_RENAMES))" \ --env "IDF_CMAKE=n" \ --output config ${SDKCONFIG} \ --output makefile $(SDKCONFIG_MAKEFILE) \ diff --git a/make/version.mk b/make/version.mk index 9dcda422af..ce6d886092 100644 --- a/make/version.mk +++ b/make/version.mk @@ -1,3 +1,3 @@ IDF_VERSION_MAJOR := 4 -IDF_VERSION_MINOR := 0 +IDF_VERSION_MINOR := 1 IDF_VERSION_PATCH := 0 diff --git a/tools/ci/check_examples_rom_header.sh b/tools/ci/check_examples_rom_header.sh new file mode 100755 index 0000000000..131723e0db --- /dev/null +++ b/tools/ci/check_examples_rom_header.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Examples shouldn't include rom headers directly + +output=$(find ${IDF_PATH}/examples -name "*.[chS]" -o -name "*.cpp" -not -path "**/build/**") +files=$(grep ".*include.*rom.*h" ${output} | cut -d ":" -f 1) +found_rom=0 +for file in ${files} +do + echo "${file} contains rom headers!" + found_rom=`expr $found_rom + 1`; +done + +if [ $found_rom -eq 0 ]; then + echo "No rom headers found in examples" + exit 0 +fi + +exit 1 diff --git a/tools/ci/config/check.yml b/tools/ci/config/check.yml index ad4f71290c..7507c47ed4 100644 --- a/tools/ci/config/check.yml +++ b/tools/ci/config/check.yml @@ -42,6 +42,11 @@ check_examples_cmake_make: script: - tools/ci/check_examples_cmake_make.sh +check_examples_rom_header: + extends: .check_job_template_with_filter + script: + - tools/ci/check_examples_rom_header.sh + check_python_style: extends: .check_job_template_with_filter artifacts: diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 4e580c5a85..bcc257b3d4 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -35,6 +35,7 @@ tools/ci/build_examples_cmake.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/check_examples_cmake_make.sh +tools/ci/check_examples_rom_header.sh tools/ci/check_idf_version.sh tools/ci/check_ut_cmake_make.sh tools/ci/checkout_project_ref.py diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 5b2828d84a..bbe299b92f 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -510,6 +510,14 @@ endmenu\n" >> ${IDF_PATH}/Kconfig; mv CMakeLists.txt.bak CMakeLists.txt rm -rf CMakeLists.txt.bak + print_status "Component properties are set" + clean_build_dir + cp CMakeLists.txt CMakeLists.txt.bak + printf "\nidf_component_get_property(srcs main SRCS)\nmessage(STATUS SRCS:\${srcs})" >> CMakeLists.txt + (idf.py reconfigure | grep "SRCS:$(realpath main/main.c)") || failure "Component properties should be set" + rm -rf CMakeLists.txt + mv CMakeLists.txt.bak CMakeLists.txt + rm -rf CMakeLists.txt.bak print_status "All tests completed" if [ -n "${FAILURES}" ]; then diff --git a/tools/cmake/component.cmake b/tools/cmake/component.cmake index 6959af26c2..1ec7efcfca 100644 --- a/tools/cmake/component.cmake +++ b/tools/cmake/component.cmake @@ -232,10 +232,10 @@ function(__component_get_requirements) file(REMOVE ${component_requires_file}) endfunction() -# __component_add_sources, __component_check_target +# __component_add_sources, __component_check_target, __component_add_include_dirs # -# Utility macros for component registration. Adds source files and checks target requirements -# respectively. +# Utility macros for component registration. Adds source files and checks target requirements, +# and adds include directories respectively. macro(__component_add_sources sources) set(sources "") if(__SRCS) @@ -279,6 +279,16 @@ macro(__component_add_sources sources) list(REMOVE_DUPLICATES sources) endmacro() +macro(__component_add_include_dirs lib dirs type) + foreach(dir ${dirs}) + get_filename_component(_dir ${dir} ABSOLUTE BASE_DIR ${CMAKE_CURRENT_LIST_DIR}) + if(NOT IS_DIRECTORY ${_dir}) + message(FATAL_ERROR "Include directory '${_dir}' is not a directory.") + endif() + target_include_directories(${lib} ${type} ${_dir}) + endforeach() +endmacro() + macro(__component_check_target) if(__REQUIRED_IDF_TARGETS) idf_build_get_property(idf_target IDF_TARGET) @@ -324,6 +334,7 @@ macro(__component_set_all_dependencies) endif() endmacro() + # idf_component_get_property # # @brief Retrieve the value of the specified component property @@ -436,16 +447,16 @@ function(idf_component_register) if(sources OR __EMBED_FILES OR __EMBED_TXTFILES) add_library(${component_lib} STATIC ${sources}) __component_set_property(${component_target} COMPONENT_TYPE LIBRARY) - target_include_directories(${component_lib} PUBLIC ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} PRIVATE ${__PRIV_INCLUDE_DIRS}) - target_include_directories(${component_lib} PUBLIC ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" PUBLIC) + __component_add_include_dirs(${component_lib} "${__PRIV_INCLUDE_DIRS}" PRIVATE) + __component_add_include_dirs(${component_lib} "${config_dir}" PUBLIC) set_target_properties(${component_lib} PROPERTIES OUTPUT_NAME ${COMPONENT_NAME}) __ldgen_add_component(${component_lib}) else() add_library(${component_lib} INTERFACE) __component_set_property(${component_target} COMPONENT_TYPE CONFIG_ONLY) - target_include_directories(${component_lib} INTERFACE ${__INCLUDE_DIRS}) - target_include_directories(${component_lib} INTERFACE ${config_dir}) + __component_add_include_dirs(${component_lib} "${__INCLUDE_DIRS}" INTERFACE) + __component_add_include_dirs(${component_lib} "${config_dir}" INTERFACE) endif() # Alias the static/interface library created for linking to external targets. @@ -479,6 +490,8 @@ function(idf_component_register) # COMPONENT_TARGET is deprecated but is made available with same function # as COMPONENT_LIB for compatibility. set(COMPONENT_TARGET ${component_lib} PARENT_SCOPE) + + __component_set_properties() endfunction() # diff --git a/tools/cmake/kconfig.cmake b/tools/cmake/kconfig.cmake index 829635db81..b76f5bdc78 100644 --- a/tools/cmake/kconfig.cmake +++ b/tools/cmake/kconfig.cmake @@ -72,6 +72,7 @@ function(__kconfig_init) idf_build_get_property(idf_path IDF_PATH) idf_build_set_property(__ROOT_KCONFIG ${idf_path}/Kconfig) + idf_build_set_property(__ROOT_SDKCONFIG_RENAME ${idf_path}/sdkconfig.rename) idf_build_set_property(__OUTPUT_SDKCONFIG 1) endfunction() @@ -86,6 +87,8 @@ function(__kconfig_component_init component_target) __component_set_property(${component_target} KCONFIG "${kconfig}") file(GLOB kconfig "${component_dir}/Kconfig.projbuild") __component_set_property(${component_target} KCONFIG_PROJBUILD "${kconfig}") + file(GLOB sdkconfig_rename "${component_dir}/sdkconfig.rename") + __component_set_property(${component_target} SDKCONFIG_RENAME "${sdkconfig_rename}") endfunction() # @@ -100,12 +103,16 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) if(component_target IN_LIST build_component_targets) __component_get_property(kconfig ${component_target} KCONFIG) __component_get_property(kconfig_projbuild ${component_target} KCONFIG_PROJBUILD) + __component_get_property(sdkconfig_rename ${component_target} SDKCONFIG_RENAME) if(kconfig) list(APPEND kconfigs ${kconfig}) endif() if(kconfig_projbuild) list(APPEND kconfig_projbuilds ${kconfig_projbuild}) endif() + if(sdkconfig_rename) + list(APPEND sdkconfig_renames ${sdkconfig_rename}) + endif() endif() endforeach() @@ -118,6 +125,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) string(REPLACE ";" " " kconfigs "${kconfigs}") string(REPLACE ";" " " kconfig_projbuilds "${kconfig_projbuilds}") + string(REPLACE ";" " " sdkconfig_renames "${sdkconfig_renames}") # Place config-related environment arguments into config.env file # to work around command line length limits for execute_process @@ -135,11 +143,13 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) endif() idf_build_get_property(root_kconfig __ROOT_KCONFIG) + idf_build_get_property(root_sdkconfig_rename __ROOT_SDKCONFIG_RENAME) idf_build_get_property(python PYTHON) set(confgen_basecommand ${python} ${idf_path}/tools/kconfig_new/confgen.py --kconfig ${root_kconfig} + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} ${defaults_arg} --env-file ${config_env_path}) @@ -232,6 +242,7 @@ function(__kconfig_generate_config sdkconfig sdkconfig_defaults) COMMAND ${PYTHON} ${IDF_PATH}/tools/kconfig_new/confserver.py --env-file ${config_env_path} --kconfig ${IDF_PATH}/Kconfig + --sdkconfig-rename ${root_sdkconfig_rename} --config ${sdkconfig} VERBATIM USES_TERMINAL) diff --git a/tools/cmake/version.cmake b/tools/cmake/version.cmake index 265ab33b7b..07ce0b5821 100644 --- a/tools/cmake/version.cmake +++ b/tools/cmake/version.cmake @@ -1,3 +1,3 @@ set(IDF_VERSION_MAJOR 4) -set(IDF_VERSION_MINOR 0) +set(IDF_VERSION_MINOR 1) set(IDF_VERSION_PATCH 0) diff --git a/tools/kconfig_new/confgen.py b/tools/kconfig_new/confgen.py index 2c98ae0305..c4e279f717 100755 --- a/tools/kconfig_new/confgen.py +++ b/tools/kconfig_new/confgen.py @@ -22,7 +22,6 @@ # limitations under the License. from __future__ import print_function import argparse -import fnmatch import json import os import os.path @@ -46,15 +45,15 @@ class DeprecatedOptions(object): _RE_DEP_OP_BEGIN = re.compile(_DEP_OP_BEGIN) _RE_DEP_OP_END = re.compile(_DEP_OP_END) - def __init__(self, config_prefix, path_rename_files, ignore_dirs=()): + def __init__(self, config_prefix, path_rename_files=[]): self.config_prefix = config_prefix # r_dic maps deprecated options to new options; rev_r_dic maps in the opposite direction - self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files, ignore_dirs) + self.r_dic, self.rev_r_dic = self._parse_replacements(path_rename_files) # note the '=' at the end of regex for not getting partial match of configs self._RE_CONFIG = re.compile(r'{}(\w+)='.format(self.config_prefix)) - def _parse_replacements(self, repl_dir, ignore_dirs): + def _parse_replacements(self, repl_paths): rep_dic = {} rev_rep_dic = {} @@ -64,31 +63,24 @@ class DeprecatedOptions(object): raise RuntimeError('Error in {} (line {}): Config {} is not prefixed with {}' ''.format(rep_path, line_number, string, self.config_prefix)) - for root, dirnames, filenames in os.walk(repl_dir): - for filename in fnmatch.filter(filenames, self._REN_FILE): - rep_path = os.path.join(root, filename) + for rep_path in repl_paths: + with open(rep_path) as f_rep: + for line_number, line in enumerate(f_rep, start=1): + sp_line = line.split() + if len(sp_line) == 0 or sp_line[0].startswith('#'): + # empty line or comment + continue + if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): + raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) + if sp_line[0] in rep_dic: + raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' + 'replacement {} is defined'.format(rep_path, line_number, + rep_dic[sp_line[0]], sp_line[0], + sp_line[1])) - if rep_path.startswith(ignore_dirs): - print('Ignoring: {}'.format(rep_path)) - continue - - with open(rep_path) as f_rep: - for line_number, line in enumerate(f_rep, start=1): - sp_line = line.split() - if len(sp_line) == 0 or sp_line[0].startswith('#'): - # empty line or comment - continue - if len(sp_line) != 2 or not all(x.startswith(self.config_prefix) for x in sp_line): - raise RuntimeError('Syntax error in {} (line {})'.format(rep_path, line_number)) - if sp_line[0] in rep_dic: - raise RuntimeError('Error in {} (line {}): Replacement {} exist for {} and new ' - 'replacement {} is defined'.format(rep_path, line_number, - rep_dic[sp_line[0]], sp_line[0], - sp_line[1])) - - (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) - rep_dic[dep_opt] = new_opt - rev_rep_dic[new_opt] = dep_opt + (dep_opt, new_opt) = (remove_config_prefix(x) for x in sp_line) + rep_dic[dep_opt] = new_opt + rev_rep_dic[new_opt] = dep_opt return rep_dic, rev_rep_dic def get_deprecated_option(self, new_option): @@ -195,6 +187,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--output', nargs=2, action='append', help='Write output file (format and output filename)', metavar=('FORMAT', 'FILENAME'), @@ -240,10 +236,9 @@ def main(): raise RuntimeError("Defaults file not found: %s" % name) config.load_config(name, replace=False) - # don't collect rename options from examples because those are separate projects and no need to "stay compatible" - # with example projects - deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"], - ignore_dirs=(os.path.join(os.environ["IDF_PATH"], 'examples'))) + sdkconfig_renames = [args.sdkconfig_rename] if args.sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) # If config file previously exists, load it if args.config and os.path.exists(args.config): diff --git a/tools/kconfig_new/config.env.in b/tools/kconfig_new/config.env.in index d685c85d06..a066b47431 100644 --- a/tools/kconfig_new/config.env.in +++ b/tools/kconfig_new/config.env.in @@ -1,6 +1,7 @@ { "COMPONENT_KCONFIGS": "${kconfigs}", "COMPONENT_KCONFIGS_PROJBUILD": "${kconfig_projbuilds}", + "COMPONENT_SDKCONFIG_RENAMES": "${sdkconfig_renames}", "IDF_CMAKE": "y", "IDF_TARGET": "${idf_target}", "IDF_PATH": "${idf_path}" diff --git a/tools/kconfig_new/confserver.py b/tools/kconfig_new/confserver.py index 914a2dd735..2e0d24ad7e 100755 --- a/tools/kconfig_new/confserver.py +++ b/tools/kconfig_new/confserver.py @@ -29,6 +29,10 @@ def main(): help='KConfig file with config item definitions', required=True) + parser.add_argument('--sdkconfig-rename', + help='File with deprecated Kconfig options', + required=False) + parser.add_argument('--env', action='append', default=[], help='Environment to set when evaluating the config file', metavar='NAME=VAL') @@ -62,12 +66,14 @@ def main(): env = json.load(args.env_file) os.environ.update(env) - run_server(args.kconfig, args.config) + run_server(args.kconfig, args.config, args.sdkconfig_rename) -def run_server(kconfig, sdkconfig, default_version=MAX_PROTOCOL_VERSION): +def run_server(kconfig, sdkconfig, sdkconfig_rename, default_version=MAX_PROTOCOL_VERSION): config = kconfiglib.Kconfig(kconfig) - deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=os.environ["IDF_PATH"]) + sdkconfig_renames = [sdkconfig_rename] if sdkconfig_rename else [] + sdkconfig_renames += os.environ.get("COMPONENT_SDKCONFIG_RENAMES", "").split() + deprecated_options = confgen.DeprecatedOptions(config.config_prefix, path_rename_files=sdkconfig_renames) with tempfile.NamedTemporaryFile(mode='w+b') as f_o: with open(sdkconfig, mode='rb') as f_i: f_o.write(f_i.read())