Merge branch 'master' into feature/esp32s2beta_update
This commit is contained in:
commit
6990a7cd54
157 changed files with 4014 additions and 1316 deletions
22
.github/main.workflow
vendored
22
.github/main.workflow
vendored
|
@ -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"
|
||||
}
|
||||
}
|
16
.github/workflows/issue_comment.yml
vendored
Normal file
16
.github/workflows/issue_comment.yml
vendored
Normal file
|
@ -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 }}
|
16
.github/workflows/issues.yml
vendored
Normal file
16
.github/workflows/issues.yml
vendored
Normal file
|
@ -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 }}
|
16
.github/workflows/pull_request.yml
vendored
Normal file
16
.github/workflows/pull_request.yml
vendored
Normal file
|
@ -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 }}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<typename T> __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<timer_intr_t>();
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, /*!<Select timer0 of GROUPx*/
|
||||
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
|
||||
TIMER_MAX,
|
||||
} timer_idx_t;
|
||||
|
||||
/**
|
||||
* @brief Decides the direction of counter
|
||||
*/
|
||||
|
@ -54,14 +46,6 @@ typedef enum {
|
|||
TIMER_COUNT_MAX
|
||||
} timer_count_dir_t;
|
||||
|
||||
/**
|
||||
* @brief Decides whether timer is on or paused
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_PAUSE = 0, /*!<Pause timer counter*/
|
||||
TIMER_START = 1, /*!<Start timer counter*/
|
||||
} timer_start_t;
|
||||
|
||||
/**
|
||||
* @brief Decides whether to enable alarm mode
|
||||
*/
|
||||
|
@ -313,28 +297,30 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
|
|||
/** @brief Enable timer group interrupt, by enable mask
|
||||
*
|
||||
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
|
||||
* @param en_mask Timer interrupt enable mask.
|
||||
* Use TIMG_T0_INT_ENA_M to enable t0 interrupt
|
||||
* Use TIMG_T1_INT_ENA_M to enable t1 interrupt
|
||||
* @param intr_mask Timer interrupt enable mask.
|
||||
* - TIMER_INTR_T0: t0 interrupt
|
||||
* - TIMER_INTR_T1: t1 interrupt
|
||||
* - TIMER_INTR_WDT: watchdog interrupt
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask);
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t intr_mask);
|
||||
|
||||
/** @brief Disable timer group interrupt, by disable mask
|
||||
*
|
||||
* @param group_num Timer group number, 0 for TIMERG0 or 1 for TIMERG1
|
||||
* @param disable_mask Timer interrupt disable mask.
|
||||
* Use TIMG_T0_INT_ENA_M to disable t0 interrupt
|
||||
* Use TIMG_T1_INT_ENA_M to disable t1 interrupt
|
||||
* @param intr_mask Timer interrupt disable mask.
|
||||
* - TIMER_INTR_T0: t0 interrupt
|
||||
* - TIMER_INTR_T1: t1 interrupt
|
||||
* - TIMER_INTR_WDT: watchdog interrupt
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask);
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t intr_mask);
|
||||
|
||||
/** @brief Enable timer interrupt
|
||||
*
|
||||
|
@ -358,6 +344,52 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num);
|
|||
*/
|
||||
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num);
|
||||
|
||||
/** @cond */
|
||||
/* Utilities functions that can be used in the ISR */
|
||||
/* Preview, don't treat them as stable API. */
|
||||
|
||||
/**
|
||||
* Clear interrupt status bit.
|
||||
*/
|
||||
void timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num);
|
||||
|
||||
/**
|
||||
* Enable alarm.
|
||||
*/
|
||||
void timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num);
|
||||
|
||||
/**
|
||||
* Get the current counter value.
|
||||
*/
|
||||
uint64_t timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num);
|
||||
|
||||
/**
|
||||
* Set the alarm threshold for the timer.
|
||||
*/
|
||||
void timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val);
|
||||
|
||||
/**
|
||||
* Enable/disable a counter.
|
||||
*/
|
||||
void timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en);
|
||||
|
||||
/**
|
||||
* Get the masked interrupt status.
|
||||
*/
|
||||
timer_intr_t timer_group_intr_get_in_isr(timer_group_t group_num);
|
||||
|
||||
/**
|
||||
* Clear interrupt.
|
||||
*/
|
||||
void timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask);
|
||||
|
||||
/**
|
||||
* Get auto reload enable status.
|
||||
*/
|
||||
bool timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num);
|
||||
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -368,7 +368,7 @@ esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold);
|
|||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Touch pad parameter error
|
||||
* - ESP_ERR_INVALID_STATE This touch pad hardware connection is error, the value of "touch_value" is 0.
|
||||
p * - ESP_FAIL Touch pad not initialized
|
||||
* - ESP_FAIL Touch pad not initialized
|
||||
*/
|
||||
esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value);
|
||||
|
||||
|
|
|
@ -866,6 +866,14 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold);
|
|||
*/
|
||||
esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold);
|
||||
|
||||
/**
|
||||
* @brief Wait until UART tx memory empty and the last char send ok (polling mode).
|
||||
*
|
||||
* @param uart_num UART number
|
||||
*
|
||||
*/
|
||||
void uart_wait_tx_idle_polling(uart_port_t uart_num);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "soc/gpio_periph.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "soc/ledc_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char* LEDC_TAG = "ledc";
|
||||
|
@ -56,11 +57,16 @@ static ledc_isr_handle_t s_ledc_fade_isr_handle = NULL;
|
|||
#define LEDC_DUTY_CYCLE_MAX (LEDC_DUTY_CYCLE_LSCH0_V)
|
||||
#define LEDC_DUTY_SCALE_MAX (LEDC_DUTY_SCALE_LSCH0_V)
|
||||
#define LEDC_HPOINT_VAL_MAX (LEDC_HPOINT_LSCH1_V)
|
||||
#define DELAY_CLK8M_CLK_SWITCH (5)
|
||||
#define SLOW_CLK_CYC_CALIBRATE (13)
|
||||
#define LEDC_FADE_TOO_SLOW_STR "LEDC FADE TOO SLOW"
|
||||
#define LEDC_FADE_TOO_FAST_STR "LEDC FADE TOO FAST"
|
||||
static const char *LEDC_FADE_SERVICE_ERR_STR = "LEDC fade service not installed";
|
||||
static const char *LEDC_FADE_INIT_ERROR_STR = "LEDC fade channel init error, not enough memory or service not installed";
|
||||
|
||||
//This value will be calibrated when in use.
|
||||
static uint32_t s_ledc_slow_clk_8M = 0;
|
||||
|
||||
static void ledc_ls_timer_update(ledc_mode_t speed_mode, ledc_timer_t timer_sel)
|
||||
{
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
|
@ -75,6 +81,28 @@ static IRAM_ATTR void ledc_ls_channel_update(ledc_mode_t speed_mode, ledc_channe
|
|||
}
|
||||
}
|
||||
|
||||
//We know that CLK8M is about 8M, but don't know the actual value. So we need to do a calibration.
|
||||
static bool ledc_slow_clk_calibrate(void)
|
||||
{
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
//Enable CLK8M for LEDC
|
||||
SET_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_DIG_CLK8M_EN_M);
|
||||
//Waiting for CLK8M to turn on
|
||||
ets_delay_us(DELAY_CLK8M_CLK_SWITCH);
|
||||
uint32_t cal_val = rtc_clk_cal(RTC_CAL_8MD256, SLOW_CLK_CYC_CALIBRATE);
|
||||
if(cal_val == 0) {
|
||||
ESP_LOGE(LEDC_TAG, "CLK8M_CLK calibration failed");
|
||||
return false;
|
||||
}
|
||||
s_ledc_slow_clk_8M = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / cal_val;
|
||||
ESP_LOGD(LEDC_TAG, "Calibrate CLK8M_CLK : %d Hz", s_ledc_slow_clk_8M);
|
||||
return true;
|
||||
#else
|
||||
ESP_LOGE(LEDC_TAG, "CLK8M source currently only supported on ESP32");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
|
||||
{
|
||||
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
|
||||
|
@ -241,6 +269,62 @@ esp_err_t ledc_isr_register(void (*fn)(void*), void * arg, int intr_alloc_flags,
|
|||
return ret;
|
||||
}
|
||||
|
||||
// Setting the LEDC timer divisor with the given source clock, frequency and resolution.
|
||||
static esp_err_t ledc_set_timer_div(ledc_mode_t speed_mode, ledc_timer_t timer_num, ledc_clk_cfg_t clk_cfg, int freq_hz, int duty_resolution)
|
||||
{
|
||||
uint32_t div_param = 0;
|
||||
uint32_t precision = ( 0x1 << duty_resolution );
|
||||
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
|
||||
|
||||
// Calculate the divisor
|
||||
// User specified source clock(RTC8M_CLK) for low speed channel
|
||||
if ((speed_mode == LEDC_LOW_SPEED_MODE) && (clk_cfg == LEDC_USE_RTC8M_CLK)) {
|
||||
if(s_ledc_slow_clk_8M == 0) {
|
||||
if (ledc_slow_clk_calibrate() == false) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
div_param = ( (uint64_t) s_ledc_slow_clk_8M << 8 ) / freq_hz / precision;
|
||||
} else {
|
||||
// Automatically select APB or REF_TICK as the source clock.
|
||||
if (clk_cfg == LEDC_AUTO_CLK) {
|
||||
// Try calculating divisor based on LEDC_APB_CLK
|
||||
div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
if (div_param > LEDC_TIMER_DIV_NUM_MAX) {
|
||||
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
} else if (div_param < 256) {
|
||||
// divisor is too low
|
||||
goto error;
|
||||
}
|
||||
// User specified source clock(LEDC_APB_CLK_HZ or LEDC_REF_TICK)
|
||||
} else {
|
||||
timer_clk_src = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK : LEDC_REF_TICK;
|
||||
uint32_t sclk_freq = (clk_cfg == LEDC_USE_APB_CLK) ? LEDC_APB_CLK_HZ : LEDC_REF_CLK_HZ;
|
||||
div_param = ( (uint64_t) sclk_freq << 8 ) / freq_hz / precision;
|
||||
}
|
||||
}
|
||||
if (div_param < 256 || div_param > LEDC_TIMER_DIV_NUM_MAX) {
|
||||
goto error;
|
||||
}
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
// For low speed channels, if RTC_8MCLK is used as the source clock, the `slow_clk_sel` register should be cleared, otherwise it should be set.
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
LEDC.conf.slow_clk_sel = (clk_cfg == LEDC_USE_RTC8M_CLK) ? 0 : 1;
|
||||
}
|
||||
#endif
|
||||
//Set the divisor
|
||||
ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src);
|
||||
// reset the timer
|
||||
ledc_timer_rst(speed_mode, timer_num);
|
||||
return ESP_OK;
|
||||
error:
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d",
|
||||
(uint32_t ) div_param);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
|
||||
{
|
||||
LEDC_ARG_CHECK(timer_conf != NULL, "timer_conf");
|
||||
|
@ -249,6 +333,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
|
|||
uint32_t timer_num = timer_conf->timer_num;
|
||||
uint32_t speed_mode = timer_conf->speed_mode;
|
||||
LEDC_ARG_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "speed_mode");
|
||||
LEDC_ARG_CHECK(!((timer_conf->clk_cfg == LEDC_USE_RTC8M_CLK) && (speed_mode != LEDC_LOW_SPEED_MODE)), "Only low speed channel support RTC8M_CLK");
|
||||
periph_module_enable(PERIPH_LEDC_MODULE);
|
||||
if (freq_hz == 0 || duty_resolution == 0 || duty_resolution >= LEDC_TIMER_BIT_MAX) {
|
||||
ESP_LOGE(LEDC_TAG, "freq_hz=%u duty_resolution=%u", freq_hz, duty_resolution);
|
||||
|
@ -258,40 +343,7 @@ esp_err_t ledc_timer_config(const ledc_timer_config_t* timer_conf)
|
|||
ESP_LOGE(LEDC_TAG, "invalid timer #%u", timer_num);
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_err_t ret = ESP_OK;
|
||||
uint32_t precision = ( 0x1 << duty_resolution ); // 2**depth
|
||||
// Try calculating divisor based on LEDC_APB_CLK
|
||||
ledc_clk_src_t timer_clk_src = LEDC_APB_CLK;
|
||||
// div_param is a Q10.8 fixed point value
|
||||
uint64_t div_param = ( (uint64_t) LEDC_APB_CLK_HZ << 8 ) / freq_hz / precision;
|
||||
if (div_param < 256) {
|
||||
// divisor is too low
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try reducing freq_hz or duty_resolution. div_param=%d",
|
||||
(uint32_t ) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
if (div_param > LEDC_TIMER_DIV_NUM_MAX) {
|
||||
// APB_CLK results in divisor which too high. Try using REF_TICK as clock source.
|
||||
timer_clk_src = LEDC_REF_TICK;
|
||||
div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
|
||||
if (div_param < 256 || div_param > LEDC_TIMER_DIV_NUM_MAX) {
|
||||
ESP_LOGE(LEDC_TAG, "requested frequency and duty resolution can not be achieved, try increasing freq_hz or duty_resolution. div_param=%d",
|
||||
(uint32_t ) div_param);
|
||||
ret = ESP_FAIL;
|
||||
}
|
||||
} else {
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
if (speed_mode == LEDC_LOW_SPEED_MODE) {
|
||||
//for now, we only select 80mhz for slow clk of LEDC low speed channels.
|
||||
LEDC.conf.slow_clk_sel = 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// set timer parameters
|
||||
ledc_timer_set(speed_mode, timer_num, div_param, duty_resolution, timer_clk_src);
|
||||
// reset timer
|
||||
ledc_timer_rst(speed_mode, timer_num);
|
||||
return ret;
|
||||
return ledc_set_timer_div(timer_num, timer_num, timer_conf->clk_cfg, freq_hz, duty_resolution);
|
||||
}
|
||||
|
||||
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
|
||||
|
|
|
@ -533,6 +533,7 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config)
|
|||
|
||||
SLC.rx_dscr_conf.slc0_token_no_replace = 1;
|
||||
HINF.cfg_data1.highspeed_enable = 1;
|
||||
HINF.cfg_data1.sdio_ver = 0x232;
|
||||
|
||||
switch(config->timing) {
|
||||
case SDIO_SLAVE_TIMING_PSEND_PSAMPLE:
|
||||
|
|
|
@ -86,6 +86,7 @@ static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_
|
|||
.bit_num = timer_bit,
|
||||
.timer_num = timer,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
@ -126,6 +127,7 @@ static void timer_duty_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit,
|
|||
.bit_num = timer_bit,
|
||||
.timer_num = timer,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
@ -188,6 +190,7 @@ TEST_CASE("LEDC error log channel and timer config", "[ledc][test_env=UT_T1_LEDC
|
|||
ledc_time_config.duty_resolution = LEDC_TIMER_13_BIT;
|
||||
ledc_time_config.timer_num = LEDC_TIMER_0;
|
||||
ledc_time_config.freq_hz = 5000;
|
||||
ledc_time_config.clk_cfg = LEDC_AUTO_CLK;
|
||||
|
||||
ledc_timer_config_t temp_timer_config = ledc_time_config;
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
@ -228,6 +231,7 @@ TEST_CASE("LEDC normal channel and timer config", "[ledc][test_env=UT_T1_LEDC]")
|
|||
.bit_num = LEDC_TIMER_13_BIT,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
ledc_timer_config_t temp_time_config = ledc_time_config;
|
||||
|
||||
|
@ -297,6 +301,7 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
|
|||
.bit_num = 13,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
|
@ -347,6 +352,7 @@ TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]")
|
|||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
|
@ -392,6 +398,7 @@ TEST_CASE("LEDC fade with time(logic analyzer)", "[ledc][ignore]")
|
|||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
|
@ -429,6 +436,7 @@ TEST_CASE("LEDC fade with step(logic analyzer)", "[ledc][ignore]")
|
|||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
|
@ -470,6 +478,7 @@ TEST_CASE("LEDC memory test", "[ledc][test_env=UT_T1_LEDC]")
|
|||
.duty_resolution = LEDC_TIMER_13_BIT,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ static void produce_pulse(void)
|
|||
.timer_num = LEDC_TIMER_1,
|
||||
.duty_resolution = LEDC_TIMER_10_BIT,
|
||||
.freq_hz = 1,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
ledc_timer_config(&ledc_timer);
|
||||
|
||||
|
@ -160,6 +161,7 @@ static void count_mode_test(gpio_num_t ctl_io)
|
|||
.timer_num = LEDC_TIMER_1,
|
||||
.duty_resolution = LEDC_TIMER_10_BIT,
|
||||
.freq_hz = 100,
|
||||
.clk_cfg = LEDC_AUTO_CLK,
|
||||
};
|
||||
ledc_timer_config(&ledc_timer);
|
||||
|
||||
|
|
|
@ -11,68 +11,44 @@
|
|||
#define TIMER_DELTA 0.001
|
||||
static bool alarm_flag;
|
||||
|
||||
// group0 interruption
|
||||
static void test_timer_group0_isr(void *para)
|
||||
{
|
||||
int timer_idx = (int) para;
|
||||
uint64_t timer_val;
|
||||
double time;
|
||||
uint64_t alarm_value;
|
||||
alarm_flag = true;
|
||||
if (TIMERG0.hw_timer[timer_idx].config.autoreload == 1) {
|
||||
if (timer_idx == 0) {
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
} else {
|
||||
TIMERG0.int_clr_timers.t1 = 1;
|
||||
}
|
||||
ets_printf("This is TG0 timer[%d] reload-timer alarm!\n", timer_idx);
|
||||
timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time);
|
||||
ets_printf("time: %.8f S\n", time);
|
||||
} else {
|
||||
if (timer_idx == 0) {
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
} else {
|
||||
TIMERG0.int_clr_timers.t1 = 1;
|
||||
}
|
||||
ets_printf("This is TG0 timer[%d] count-up-timer alarm!\n", timer_idx);
|
||||
timer_get_counter_value(TIMER_GROUP_0, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(TIMER_GROUP_0, timer_idx, &time);
|
||||
timer_get_alarm_value(TIMER_GROUP_0, timer_idx, &alarm_value);
|
||||
ets_printf("time: %.8f S\n", time);
|
||||
double alarm_time = (double) alarm_value / TIMER_SCALE;
|
||||
ets_printf("alarm_time: %.8f S\n", alarm_time);
|
||||
}
|
||||
}
|
||||
typedef struct {
|
||||
timer_group_t timer_group;
|
||||
timer_idx_t timer_idx;
|
||||
} timer_info_t;
|
||||
|
||||
// group1 interruption
|
||||
static void test_timer_group1_isr(void *para)
|
||||
#define TIMER_INFO_INIT(TG, TID) {.timer_group = (TG), .timer_idx = (TID),}
|
||||
|
||||
static timer_info_t timer_info[4] = {
|
||||
TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_0),
|
||||
TIMER_INFO_INIT(TIMER_GROUP_0, TIMER_1),
|
||||
TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_0),
|
||||
TIMER_INFO_INIT(TIMER_GROUP_1, TIMER_1),
|
||||
};
|
||||
|
||||
#define GET_TIMER_INFO(TG, TID) (&timer_info[(TG)*2+(TID)])
|
||||
|
||||
// timer group interruption
|
||||
static void test_timer_group_isr(void *para)
|
||||
{
|
||||
int timer_idx = (int) para;
|
||||
timer_info_t* info = (timer_info_t*) para;
|
||||
const timer_group_t timer_group = info->timer_group;
|
||||
const timer_idx_t timer_idx = info->timer_idx;
|
||||
uint64_t timer_val;
|
||||
double time;
|
||||
uint64_t alarm_value;
|
||||
alarm_flag = true;
|
||||
if (TIMERG1.hw_timer[timer_idx].config.autoreload == 1) {
|
||||
if (timer_idx == 0) {
|
||||
TIMERG1.int_clr_timers.t0 = 1;
|
||||
} else {
|
||||
TIMERG1.int_clr_timers.t1 = 1;
|
||||
}
|
||||
ets_printf("This is TG1 timer[%d] reload-timer alarm!\n", timer_idx);
|
||||
timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time);
|
||||
if (timer_group_get_auto_reload_in_isr(timer_group, timer_idx)) {
|
||||
timer_group_intr_clr_in_isr(timer_group, timer_idx);
|
||||
ets_printf("This is TG%d timer[%d] reload-timer alarm!\n", timer_group, timer_idx);
|
||||
timer_get_counter_value(timer_group, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(timer_group, timer_idx, &time);
|
||||
ets_printf("time: %.8f S\n", time);
|
||||
} else {
|
||||
if (timer_idx == 0) {
|
||||
TIMERG1.int_clr_timers.t0 = 1;
|
||||
} else {
|
||||
TIMERG1.int_clr_timers.t1 = 1;
|
||||
}
|
||||
ets_printf("This is TG1 timer[%d] count-up-timer alarm!\n", timer_idx);
|
||||
timer_get_counter_value(TIMER_GROUP_1, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(TIMER_GROUP_1, timer_idx, &time);
|
||||
timer_get_alarm_value(TIMER_GROUP_1, timer_idx, &alarm_value);
|
||||
timer_group_intr_clr_in_isr(timer_group, timer_idx);
|
||||
ets_printf("This is TG%d timer[%d] count-up-timer alarm!\n", timer_group, timer_idx);
|
||||
timer_get_counter_value(timer_group, timer_idx, &timer_val);
|
||||
timer_get_counter_time_sec(timer_group, timer_idx, &time);
|
||||
timer_get_alarm_value(timer_group, timer_idx, &alarm_value);
|
||||
ets_printf("time: %.8f S\n", time);
|
||||
double alarm_time = (double) alarm_value / TIMER_SCALE;
|
||||
ets_printf("alarm_time: %.8f S\n", alarm_time);
|
||||
|
@ -86,13 +62,7 @@ static void tg_timer_init(int timer_group, int timer_idx, double alarm_time)
|
|||
timer_set_counter_value(timer_group, timer_idx, 0x0);
|
||||
timer_set_alarm_value(timer_group, timer_idx, alarm_time * TIMER_SCALE);
|
||||
timer_enable_intr(timer_group, timer_idx);
|
||||
if (timer_group == 0) {
|
||||
timer_isr_register(timer_group, timer_idx, test_timer_group0_isr,
|
||||
(void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
} else {
|
||||
timer_isr_register(timer_group, timer_idx, test_timer_group1_isr,
|
||||
(void *) timer_idx, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
}
|
||||
timer_isr_register(timer_group, timer_idx, test_timer_group_isr, GET_TIMER_INFO(timer_group, timer_idx), ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_start(timer_group, timer_idx);
|
||||
}
|
||||
|
||||
|
@ -747,8 +717,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]")
|
|||
// enable timer_intr0
|
||||
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, set_timer_val);
|
||||
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1.2 * TIMER_SCALE);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
|
||||
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr,
|
||||
GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(alarm_flag == true)
|
||||
|
@ -765,8 +735,8 @@ TEST_CASE("Timer enable timer interrupt", "[hw_timer]")
|
|||
// enable timer_intr1
|
||||
timer_set_counter_value(TIMER_GROUP_1, TIMER_1, set_timer_val);
|
||||
timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 1.2 * TIMER_SCALE);
|
||||
timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group1_isr,
|
||||
(void *) TIMER_1, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_isr_register(TIMER_GROUP_1, TIMER_1, test_timer_group_isr,
|
||||
GET_TIMER_INFO(TIMER_GROUP_1, TIMER_1), ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_start(TIMER_GROUP_1, TIMER_1);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(alarm_flag == true)
|
||||
|
@ -813,23 +783,21 @@ TEST_CASE("Timer enable timer group interrupt", "[hw_timer][ignore]")
|
|||
all_timer_set_alarm_value(1.2);
|
||||
|
||||
// enable timer group
|
||||
timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
|
||||
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(alarm_flag == true);
|
||||
|
||||
//test enable auto_reload
|
||||
alarm_flag = false;
|
||||
timer_group_intr_disable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
|
||||
timer_group_intr_disable(TIMER_GROUP_0, TIMER_INTR_T0);
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(alarm_flag == false);
|
||||
|
||||
timer_group_intr_enable(TIMER_GROUP_0, TIMG_T0_INT_ENA_M);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group0_isr,
|
||||
(void *) TIMER_0, ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_group_intr_enable(TIMER_GROUP_0, TIMER_INTR_T0);
|
||||
timer_isr_register(TIMER_GROUP_0, TIMER_0, test_timer_group_isr, GET_TIMER_INFO(TIMER_GROUP_0, TIMER_0), ESP_INTR_FLAG_LOWMED, NULL);
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT(alarm_flag == true);
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
#include "freertos/xtensa_api.h"
|
||||
#include "driver/timer.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "hal/timer_ll.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static const char* TIMER_TAG = "timer_group";
|
||||
#define TIMER_CHECK(a, str, ret_val) \
|
||||
|
@ -37,7 +37,7 @@ static const char* TIMER_TAG = "timer_group";
|
|||
#define TIMER_SCALE_ERROR "HW TIMER SCALE ERROR"
|
||||
#define TIMER_ALARM_ERROR "HW TIMER ALARM ERROR"
|
||||
#define DIVIDER_RANGE_ERROR "HW TIMER divider outside of [2, 65536] range error"
|
||||
static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
|
||||
DRAM_ATTR static timg_dev_t *TG[2] = {&TIMERG0, &TIMERG1};
|
||||
static portMUX_TYPE timer_spinlock[TIMER_GROUP_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
|
||||
|
||||
#define TIMER_ENTER_CRITICAL(mux) portENTER_CRITICAL_SAFE(mux);
|
||||
|
@ -274,7 +274,7 @@ esp_err_t timer_get_config(timer_group_t group_num, timer_idx_t timer_num, timer
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
|
||||
esp_err_t timer_group_intr_enable(timer_group_t group_num, timer_intr_t en_mask)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
|
@ -283,7 +283,7 @@ esp_err_t timer_group_intr_enable(timer_group_t group_num, uint32_t en_mask)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, uint32_t disable_mask)
|
||||
esp_err_t timer_group_intr_disable(timer_group_t group_num, timer_intr_t disable_mask)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
portENTER_CRITICAL(&timer_spinlock[group_num]);
|
||||
|
@ -296,12 +296,55 @@ esp_err_t timer_enable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
|||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
return timer_group_intr_enable(group_num, BIT(timer_num));
|
||||
return timer_group_intr_enable(group_num, TIMER_LL_GET_INTR(timer_num));
|
||||
}
|
||||
|
||||
esp_err_t timer_disable_intr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
TIMER_CHECK(group_num < TIMER_GROUP_MAX, TIMER_GROUP_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
TIMER_CHECK(timer_num < TIMER_MAX, TIMER_NUM_ERROR, ESP_ERR_INVALID_ARG);
|
||||
return timer_group_intr_disable(group_num, BIT(timer_num));
|
||||
return timer_group_intr_disable(group_num, TIMER_LL_GET_INTR(timer_num));
|
||||
}
|
||||
|
||||
timer_intr_t IRAM_ATTR timer_group_intr_get_in_isr(timer_group_t group_num)
|
||||
{
|
||||
return timer_ll_intr_status_get(TG[group_num]);
|
||||
}
|
||||
|
||||
void IRAM_ATTR timer_group_intr_clr_in_isr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
timer_ll_intr_status_clear(TG[group_num], TIMER_LL_GET_INTR(timer_num));
|
||||
}
|
||||
|
||||
void IRAM_ATTR timer_group_enable_alarm_in_isr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
timer_ll_set_alarm_enable(TG[group_num], timer_num, true);
|
||||
}
|
||||
|
||||
uint64_t IRAM_ATTR timer_group_get_counter_value_in_isr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
uint64_t val;
|
||||
timer_ll_get_counter_value(TG[group_num], timer_num, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void IRAM_ATTR timer_group_set_alarm_value_in_isr(timer_group_t group_num, timer_idx_t timer_num, uint64_t alarm_val)
|
||||
{
|
||||
timer_ll_set_alarm_value(TG[group_num], timer_num, alarm_val);
|
||||
}
|
||||
|
||||
void IRAM_ATTR timer_group_set_counter_enable_in_isr(timer_group_t group_num, timer_idx_t timer_num, timer_start_t counter_en)
|
||||
{
|
||||
timer_ll_set_counter_enable(TG[group_num], timer_num, counter_en);
|
||||
}
|
||||
|
||||
void IRAM_ATTR timer_group_clr_intr_sta_in_isr(timer_group_t group_num, timer_intr_t intr_mask)
|
||||
{
|
||||
timer_ll_intr_status_clear(TG[group_num], intr_mask);
|
||||
}
|
||||
|
||||
bool IRAM_ATTR timer_group_get_auto_reload_in_isr(timer_group_t group_num, timer_idx_t timer_num)
|
||||
{
|
||||
return timer_ll_get_auto_reload(TG[group_num], timer_num);
|
||||
}
|
||||
|
||||
|
|
|
@ -1688,3 +1688,12 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int *out_wakeup_thresh
|
|||
*out_wakeup_threshold = UART[uart_num]->sleep_conf.active_threshold + UART_MIN_WAKEUP_THRESH;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void uart_wait_tx_idle_polling(uart_port_t uart_num)
|
||||
{
|
||||
uint32_t status;
|
||||
do {
|
||||
status = READ_PERI_REG(UART_STATUS_REG(uart_num));
|
||||
/* either tx count or state is non-zero */
|
||||
} while ((status & (UART_ST_UTX_OUT_M | UART_TXFIFO_CNT_M)) != 0);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <assert.h>
|
||||
#include "esp_efuse_table.h"
|
||||
|
||||
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
|
||||
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
|
||||
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
|
||||
// If you want to change some fields, you need to change esp_efuse_table.csv file
|
||||
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
|
||||
|
@ -151,6 +151,10 @@ static const esp_efuse_desc_t CHIP_VER_REV1[] = {
|
|||
{EFUSE_BLK0, 111, 1}, // EFUSE_RD_CHIP_VER_REV1,
|
||||
};
|
||||
|
||||
static const esp_efuse_desc_t CHIP_VER_REV2[] = {
|
||||
{EFUSE_BLK0, 180, 1}, // EFUSE_RD_CHIP_VER_REV2,
|
||||
};
|
||||
|
||||
static const esp_efuse_desc_t XPD_SDIO_REG[] = {
|
||||
{EFUSE_BLK0, 142, 1}, // EFUSE_RD_XPD_SDIO_REG,
|
||||
};
|
||||
|
@ -336,6 +340,11 @@ const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[] = {
|
||||
&CHIP_VER_REV2[0], // EFUSE_RD_CHIP_VER_REV2
|
||||
NULL
|
||||
};
|
||||
|
||||
const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[] = {
|
||||
&XPD_SDIO_REG[0], // EFUSE_RD_XPD_SDIO_REG
|
||||
NULL
|
||||
|
|
|
@ -64,6 +64,7 @@ CHIP_VER_PKG, EFUSE_BLK0, 105, 3, EFUSE_RD_CHIP_VER_PKG
|
|||
CHIP_CPU_FREQ_LOW, EFUSE_BLK0, 108, 1, EFUSE_RD_CHIP_CPU_FREQ_LOW
|
||||
CHIP_CPU_FREQ_RATED, EFUSE_BLK0, 109, 1, EFUSE_RD_CHIP_CPU_FREQ_RATED
|
||||
CHIP_VER_REV1, EFUSE_BLK0, 111, 1, EFUSE_RD_CHIP_VER_REV1
|
||||
CHIP_VER_REV2, EFUSE_BLK0, 180, 1, EFUSE_RD_CHIP_VER_REV2
|
||||
XPD_SDIO_REG, EFUSE_BLK0, 142, 1, EFUSE_RD_XPD_SDIO_REG
|
||||
SDIO_TIEH, EFUSE_BLK0, 143, 1, EFUSE_RD_SDIO_TIEH
|
||||
SDIO_FORCE, EFUSE_BLK0, 144, 1, EFUSE_RD_SDIO_FORCE
|
||||
|
|
Can't render this file because it contains an unexpected character in line 7 and column 87.
|
|
@ -17,7 +17,7 @@ extern "C" {
|
|||
#endif
|
||||
|
||||
|
||||
// md5_digest_table 544d434da010ce22f7db1b14d38e1d66
|
||||
// md5_digest_table 2e23344575b3d07f01ecb695294e9770
|
||||
// This file was generated from the file esp_efuse_table.csv. DO NOT CHANGE THIS FILE MANUALLY.
|
||||
// If you want to change some fields, you need to change esp_efuse_table.csv file
|
||||
// then run `efuse_common_table` or `efuse_custom_table` command it will generate this file.
|
||||
|
@ -52,6 +52,7 @@ extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_PKG[];
|
|||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_LOW[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_CPU_FREQ_RATED[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV1[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_CHIP_VER_REV2[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_XPD_SDIO_REG[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_TIEH[];
|
||||
extern const esp_efuse_desc_t* ESP_EFUSE_SDIO_FORCE[];
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "esp_log.h"
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "bootloader_random.h"
|
||||
#include "soc/apb_ctrl_reg.h"
|
||||
|
||||
const static char *TAG = "efuse";
|
||||
|
||||
|
@ -31,8 +32,29 @@ const static char *TAG = "efuse";
|
|||
// Returns chip version from efuse
|
||||
uint8_t esp_efuse_get_chip_ver(void)
|
||||
{
|
||||
uint8_t chip_ver;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &chip_ver, 1);
|
||||
uint8_t eco_bit0, eco_bit1, eco_bit2;
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV1, &eco_bit0, 1);
|
||||
esp_efuse_read_field_blob(ESP_EFUSE_CHIP_VER_REV2, &eco_bit1, 1);
|
||||
eco_bit2 = (REG_READ(APB_CTRL_DATE_REG) & 80000000) >> 31;
|
||||
uint32_t combine_value = (eco_bit2 << 2) | (eco_bit1 << 1) | eco_bit0;
|
||||
uint8_t chip_ver = 0;
|
||||
switch (combine_value) {
|
||||
case 0:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
case 1:
|
||||
chip_ver = 1;
|
||||
break;
|
||||
case 3:
|
||||
chip_ver = 2;
|
||||
break;
|
||||
case 7:
|
||||
chip_ver = 3;
|
||||
break;
|
||||
default:
|
||||
chip_ver = 0;
|
||||
break;
|
||||
}
|
||||
return chip_ver;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "esp_efuse_utility.h"
|
||||
|
||||
#include "soc/efuse_periph.h"
|
||||
#include "esp32/clk.h"
|
||||
#include "esp_log.h"
|
||||
#include "assert.h"
|
||||
#include "sdkconfig.h"
|
||||
|
@ -209,6 +210,25 @@ void esp_efuse_utility_burn_efuses(void)
|
|||
}
|
||||
}
|
||||
#else
|
||||
// Update Efuse timing configuration
|
||||
uint32_t apb_freq_mhz = esp_clk_apb_freq() / 1000000;
|
||||
uint32_t clk_sel0, clk_sel1, dac_clk_div;
|
||||
if (apb_freq_mhz <= 26) {
|
||||
clk_sel0 = 250;
|
||||
clk_sel1 = 255;
|
||||
dac_clk_div = 52;
|
||||
} else if (apb_freq_mhz <= 40) {
|
||||
clk_sel0 = 160;
|
||||
clk_sel1 = 255;
|
||||
dac_clk_div = 80;
|
||||
} else {
|
||||
clk_sel0 = 80;
|
||||
clk_sel1 = 128;
|
||||
dac_clk_div = 100;
|
||||
}
|
||||
REG_SET_FIELD(EFUSE_DAC_CONF_REG, EFUSE_DAC_CLK_DIV, dac_clk_div);
|
||||
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL0, clk_sel0);
|
||||
REG_SET_FIELD(EFUSE_CLK_REG, EFUSE_CLK_SEL1, clk_sel1);
|
||||
// Permanently update values written to the efuse write registers
|
||||
REG_WRITE(EFUSE_CONF_REG, EFUSE_CONF_WRITE);
|
||||
REG_WRITE(EFUSE_CMD_REG, EFUSE_CMD_PGM);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
idf_component_register(SRCS "esp_tls.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIVATE_INCLUDE_DIRS "private_include"
|
||||
PRIV_INCLUDE_DIRS "private_include"
|
||||
REQUIRES mbedtls
|
||||
PRIV_REQUIRES lwip nghttp)
|
||||
|
|
|
@ -5,5 +5,16 @@ menu "ESP-TLS"
|
|||
help
|
||||
Enable support for creating server side SSL/TLS session
|
||||
|
||||
config ESP_TLS_PSK_VERIFICATION
|
||||
bool "Enable PSK verification"
|
||||
select MBEDTLS_PSK_MODES
|
||||
select MBEDTLS_KEY_EXCHANGE_PSK
|
||||
select MBEDTLS_KEY_EXCHANGE_DHE_PSK
|
||||
select MBEDTLS_KEY_EXCHANGE_ECDHE_PSK
|
||||
select MBEDTLS_KEY_EXCHANGE_RSA_PSK
|
||||
default n
|
||||
help
|
||||
Enable support for pre shared key ciphers
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
|
@ -426,6 +426,23 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls
|
|||
if (esp_ret != ESP_OK) {
|
||||
return esp_ret;
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
|
||||
} else if (cfg->psk_hint_key) {
|
||||
#if defined(CONFIG_ESP_TLS_PSK_VERIFICATION)
|
||||
//
|
||||
// PSK encryption mode is configured only if no certificate supplied and psk pointer not null
|
||||
ESP_LOGD(TAG, "ssl psk authentication");
|
||||
ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size,
|
||||
(const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
|
||||
if (ret != 0) {
|
||||
ESP_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%x", -ret);
|
||||
ESP_INT_EVENT_TRACKER_CAPTURE(tls->error_handle, ERR_TYPE_MBEDTLS, -ret);
|
||||
return ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED;
|
||||
}
|
||||
#else
|
||||
ESP_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable ESP_TLS_PSK_VERIFICATION option");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
#endif
|
||||
} else {
|
||||
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
|
||||
}
|
||||
|
@ -443,7 +460,7 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls
|
|||
};
|
||||
esp_err_t esp_ret = set_pki_context(tls, &pki);
|
||||
if (esp_ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set server pki context");
|
||||
ESP_LOGE(TAG, "Failed to set client pki context");
|
||||
return esp_ret;
|
||||
}
|
||||
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {
|
||||
|
|
|
@ -48,6 +48,7 @@ extern "C" {
|
|||
#define ESP_ERR_MBEDTLS_SSL_WRITE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0E) /*!< mbedtls api returned error */
|
||||
#define ESP_ERR_MBEDTLS_PK_PARSE_KEY_FAILED (ESP_ERR_ESP_TLS_BASE + 0x0F) /*!< mbedtls api returned failed */
|
||||
#define ESP_ERR_MBEDTLS_SSL_HANDSHAKE_FAILED (ESP_ERR_ESP_TLS_BASE + 0x10) /*!< mbedtls api returned failed */
|
||||
#define ESP_ERR_MBEDTLS_SSL_CONF_PSK_FAILED (ESP_ERR_ESP_TLS_BASE + 0x11) /*!< mbedtls api returned failed */
|
||||
|
||||
typedef struct esp_tls_last_error* esp_tls_error_handle_t;
|
||||
|
||||
|
@ -76,6 +77,15 @@ typedef enum esp_tls_role {
|
|||
ESP_TLS_SERVER,
|
||||
} esp_tls_role_t;
|
||||
|
||||
/**
|
||||
* @brief ESP-TLS preshared key and hint structure
|
||||
*/
|
||||
typedef struct psk_key_hint {
|
||||
const uint8_t* key; /*!< key in PSK authentication mode in binary format */
|
||||
const size_t key_size; /*!< length of the key */
|
||||
const char* hint; /*!< hint in PSK authentication mode in string format */
|
||||
} psk_hint_key_t;
|
||||
|
||||
/**
|
||||
* @brief ESP-TLS configuration parameters
|
||||
*
|
||||
|
@ -159,6 +169,11 @@ typedef struct esp_tls_cfg {
|
|||
If NULL, server certificate CN must match hostname. */
|
||||
|
||||
bool skip_common_name; /*!< Skip any validation of server certificate CN field */
|
||||
|
||||
const psk_hint_key_t* psk_hint_key; /*!< Pointer to PSK hint and key. if not NULL (and certificates are NULL)
|
||||
then PSK authentication is enabled with configured setup.
|
||||
Important note: the pointer must be valid for connection */
|
||||
|
||||
} esp_tls_cfg_t;
|
||||
|
||||
#ifdef CONFIG_ESP_TLS_SERVER
|
||||
|
|
|
@ -4,6 +4,34 @@ menu "ESP32-specific"
|
|||
# not working so we just hide all items here
|
||||
visible if IDF_TARGET_ESP32
|
||||
|
||||
choice ESP32_REV_MIN
|
||||
prompt "Minimum Supported ESP32 Revision"
|
||||
default ESP32_REV_MIN_0
|
||||
help
|
||||
Minimum revision that ESP-IDF would support.
|
||||
ESP-IDF performs different strategy on different esp32 revision.
|
||||
|
||||
config ESP32_REV_MIN_0
|
||||
bool "Rev 0"
|
||||
config ESP32_REV_MIN_1
|
||||
bool "Rev 1"
|
||||
config ESP32_REV_MIN_2
|
||||
bool "Rev 2"
|
||||
config ESP32_REV_MIN_3
|
||||
bool "Rev 3"
|
||||
endchoice
|
||||
|
||||
config ESP32_REV_MIN
|
||||
int
|
||||
default 0 if ESP32_REV_MIN_0
|
||||
default 1 if ESP32_REV_MIN_1
|
||||
default 2 if ESP32_REV_MIN_2
|
||||
default 3 if ESP32_REV_MIN_3
|
||||
|
||||
config ESP32_DPORT_WORKAROUND
|
||||
bool
|
||||
default "y" if !FREERTOS_UNICORE && ESP32_REV_MIN < 2
|
||||
|
||||
choice ESP32_DEFAULT_CPU_FREQ_MHZ
|
||||
prompt "CPU frequency"
|
||||
default ESP32_DEFAULT_CPU_FREQ_160
|
||||
|
|
|
@ -408,6 +408,16 @@ void start_cpu0_default(void)
|
|||
esp_flash_app_init();
|
||||
esp_err_t flash_ret = esp_flash_init_default_chip();
|
||||
assert(flash_ret == ESP_OK);
|
||||
|
||||
uint8_t revision = esp_efuse_get_chip_ver();
|
||||
ESP_LOGI(TAG, "Chip Revision: %d", revision);
|
||||
if (revision > CONFIG_ESP32_REV_MIN) {
|
||||
ESP_LOGW(TAG, "Chip revision is higher than the one configured in menuconfig. Suggest to upgrade it.");
|
||||
} else if(revision != CONFIG_ESP32_REV_MIN) {
|
||||
ESP_LOGE(TAG, "ESP-IDF can't support this chip revision. Modify minimum supported revision in menuconfig");
|
||||
abort();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_impl_init();
|
||||
#ifdef CONFIG_PM_DFS_INIT_AUTO
|
||||
|
|
|
@ -249,7 +249,7 @@ void IRAM_ATTR esp_dport_access_read_buffer(uint32_t *buff_out, uint32_t address
|
|||
*/
|
||||
uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
uint32_t apb;
|
||||
|
@ -295,7 +295,7 @@ uint32_t IRAM_ATTR esp_dport_access_reg_read(uint32_t reg)
|
|||
*/
|
||||
uint32_t IRAM_ATTR esp_dport_access_sequence_reg_read(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
uint32_t apb;
|
||||
|
|
|
@ -33,7 +33,7 @@ uint32_t esp_dport_access_sequence_reg_read(uint32_t reg);
|
|||
//only call in case of panic().
|
||||
void esp_dport_access_int_abort(void);
|
||||
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
#define DPORT_STALL_OTHER_CPU_START()
|
||||
#define DPORT_STALL_OTHER_CPU_END()
|
||||
#define DPORT_INTERRUPT_DISABLE()
|
||||
|
|
|
@ -30,10 +30,11 @@
|
|||
#include "driver/timer.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "hal/timer_ll.h"
|
||||
|
||||
#if CONFIG_ESP_INT_WDT
|
||||
|
||||
|
||||
#define TG1_WDT_TICK_US 500
|
||||
#define WDT_INT_NUM 24
|
||||
|
||||
|
||||
|
@ -48,11 +49,15 @@ static void IRAM_ATTR tick_hook(void) {
|
|||
} else {
|
||||
//Only feed wdt if app cpu also ticked.
|
||||
if (int_wdt_app_cpu_ticked) {
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
//Set timeout before interrupt
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 0,
|
||||
CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
|
||||
//Set timeout before reset
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 1,
|
||||
2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
|
||||
timer_ll_wdt_feed(&TIMERG1);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
int_wdt_app_cpu_ticked=false;
|
||||
}
|
||||
}
|
||||
|
@ -60,33 +65,36 @@ static void IRAM_ATTR tick_hook(void) {
|
|||
#else
|
||||
static void IRAM_ATTR tick_hook(void) {
|
||||
if (xPortGetCoreID()!=0) return;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config2=CONFIG_ESP_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt
|
||||
TIMERG1.wdt_config3=CONFIG_ESP_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
//Set timeout before interrupt
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 0, CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
|
||||
//Set timeout before reset
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 1, 2*CONFIG_ESP_INT_WDT_TIMEOUT_MS*1000/TG1_WDT_TICK_US);
|
||||
timer_ll_wdt_feed(&TIMERG1);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void esp_int_wdt_init(void) {
|
||||
periph_module_enable(PERIPH_TIMG1_MODULE);
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS
|
||||
TIMERG1.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||
TIMERG1.wdt_config0.level_int_en=1;
|
||||
TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
|
||||
TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
|
||||
TIMERG1.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||
//The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
|
||||
//it to their actual value.
|
||||
TIMERG1.wdt_config2=10000;
|
||||
TIMERG1.wdt_config3=10000;
|
||||
TIMERG1.wdt_config0.en=1;
|
||||
TIMERG1.wdt_feed=1;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
TIMERG1.int_clr_timers.wdt=1;
|
||||
timer_group_intr_enable(TIMER_GROUP_1, TIMG_WDT_INT_ENA_M);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_init(&TIMERG1);
|
||||
timer_ll_wdt_set_tick(&TIMERG1, TG1_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG1_WDT_TICK_US
|
||||
//1st stage timeout: interrupt
|
||||
timer_ll_wdt_set_timeout_behavior(&TIMERG1, 0, TIMER_WDT_INT);
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 0, 5*1000*1000/TG1_WDT_TICK_US);
|
||||
//2nd stage timeout: reset system
|
||||
timer_ll_wdt_set_timeout_behavior(&TIMERG1, 1, TIMER_WDT_RESET_SYSTEM);
|
||||
timer_ll_wdt_set_timeout(&TIMERG1, 1, 5*1000*1000/TG1_WDT_TICK_US);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, true);
|
||||
timer_ll_wdt_feed(&TIMERG1);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
|
||||
timer_ll_intr_status_clear(&TIMERG1, TIMER_INTR_WDT);
|
||||
timer_group_intr_enable(TIMER_GROUP_1, TIMER_INTR_WDT);
|
||||
}
|
||||
|
||||
void esp_int_wdt_cpu_init(void)
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include "esp_private/system_internal.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_ota_ops.h"
|
||||
#include "driver/timer.h"
|
||||
#include "hal/timer_ll.h"
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
#include "SEGGER_RTT.h"
|
||||
#endif
|
||||
|
@ -311,7 +313,7 @@ void panicHandler(XtExcFrame *frame)
|
|||
disableAllWdts();
|
||||
if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
|
||||
frame->exccause == PANIC_RSN_INTWDT_CPU1) {
|
||||
TIMERG1.int_clr_timers.wdt = 1;
|
||||
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_1, TIMER_INTR_WDT);
|
||||
}
|
||||
#if CONFIG_ESP32_APPTRACE_ENABLE
|
||||
#if CONFIG_SYSVIEW_ENABLE
|
||||
|
@ -401,19 +403,21 @@ static void illegal_instruction_helper(XtExcFrame *frame)
|
|||
*/
|
||||
static void reconfigureAllWdts(void)
|
||||
{
|
||||
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_feed = 1;
|
||||
TIMERG0.wdt_config0.sys_reset_length = 7; //3.2uS
|
||||
TIMERG0.wdt_config0.cpu_reset_length = 7; //3.2uS
|
||||
TIMERG0.wdt_config0.stg0 = TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
|
||||
TIMERG0.wdt_config1.clk_prescale = 80 * 500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||
TIMERG0.wdt_config2 = 2000; //1 second before reset
|
||||
TIMERG0.wdt_config0.en = 1;
|
||||
TIMERG0.wdt_wprotect = 0;
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false);
|
||||
timer_ll_wdt_feed(&TIMERG0);
|
||||
timer_ll_wdt_init(&TIMERG0);
|
||||
timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
|
||||
//1st stage timeout: reset system
|
||||
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_RESET_SYSTEM);
|
||||
//1 second before reset
|
||||
timer_ll_wdt_set_timeout(&TIMERG0, 0, 1000*1000/TG0_WDT_TICK_US);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, true);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true);
|
||||
|
||||
//Disable wdt 1
|
||||
TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en = 0;
|
||||
TIMERG1.wdt_wprotect = 0;
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -421,14 +425,16 @@ static void reconfigureAllWdts(void)
|
|||
*/
|
||||
static inline void disableAllWdts(void)
|
||||
{
|
||||
TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_config0.en = 0;
|
||||
TIMERG0.wdt_wprotect = 0;
|
||||
TIMERG1.wdt_wprotect = TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en = 0;
|
||||
TIMERG1.wdt_wprotect = 0;
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true);
|
||||
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
}
|
||||
|
||||
#if CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
|
||||
static void esp_panic_dig_reset(void) __attribute__((noreturn));
|
||||
|
||||
static void esp_panic_dig_reset(void)
|
||||
|
@ -444,6 +450,7 @@ static void esp_panic_dig_reset(void)
|
|||
;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void putEntry(uint32_t pc, uint32_t sp)
|
||||
{
|
||||
|
|
|
@ -508,6 +508,7 @@ static void IRAM_ATTR psram_gpio_config(psram_io_t *psram_io, psram_cache_mode_t
|
|||
spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
|
||||
} else if (rd_mode_reg & SPI_FREAD_DIO_M) {
|
||||
spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
|
||||
SET_PERI_REG_BITS(SPI_USER1_REG(0), SPI_USR_ADDR_BITLEN_V, SPI0_R_DIO_ADDR_BITSLEN, SPI_USR_ADDR_BITLEN_S);
|
||||
} else if (rd_mode_reg & (SPI_FREAD_QUAD_M | SPI_FREAD_DUAL_M)) {
|
||||
spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
|
||||
} else {
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "esp_private/system_internal.h"
|
||||
#include "esp_efuse.h"
|
||||
#include "esp_efuse_table.h"
|
||||
#include "hal/timer_ll.h"
|
||||
|
||||
static const char* TAG = "system_api";
|
||||
|
||||
|
@ -281,12 +282,13 @@ void IRAM_ATTR esp_restart_noos(void)
|
|||
esp_dport_access_int_abort();
|
||||
|
||||
// Disable TG0/TG1 watchdogs
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG0.wdt_config0.en = 0;
|
||||
TIMERG0.wdt_wprotect=0;
|
||||
TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
|
||||
TIMERG1.wdt_config0.en = 0;
|
||||
TIMERG1.wdt_wprotect=0;
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true);
|
||||
|
||||
timer_ll_wdt_set_protect(&TIMERG1, false);
|
||||
timer_ll_wdt_set_enable(&TIMERG1, false);
|
||||
timer_ll_wdt_set_protect(&TIMERG1, true);
|
||||
|
||||
// Flush any data left in UART FIFOs
|
||||
uart_tx_wait_idle(0);
|
||||
|
@ -366,35 +368,27 @@ const char* esp_get_idf_version(void)
|
|||
return IDF_VER;
|
||||
}
|
||||
|
||||
static void get_chip_info_esp32(esp_chip_info_t* out_info)
|
||||
void esp_chip_info(esp_chip_info_t* out_info)
|
||||
{
|
||||
uint32_t reg = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
uint32_t efuse_rd3 = REG_READ(EFUSE_BLK0_RDATA3_REG);
|
||||
memset(out_info, 0, sizeof(*out_info));
|
||||
|
||||
out_info->model = CHIP_ESP32;
|
||||
if ((reg & EFUSE_RD_CHIP_VER_REV1_M) != 0) {
|
||||
out_info->revision = 1;
|
||||
}
|
||||
if ((reg & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
|
||||
out_info->revision = esp_efuse_get_chip_ver();
|
||||
|
||||
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_APP_CPU_M) == 0) {
|
||||
out_info->cores = 2;
|
||||
} else {
|
||||
out_info->cores = 1;
|
||||
}
|
||||
out_info->features = CHIP_FEATURE_WIFI_BGN;
|
||||
if ((reg & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
|
||||
if ((efuse_rd3 & EFUSE_RD_CHIP_VER_DIS_BT_M) == 0) {
|
||||
out_info->features |= CHIP_FEATURE_BT | CHIP_FEATURE_BLE;
|
||||
}
|
||||
int package = (reg & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
|
||||
int package = (efuse_rd3 & EFUSE_RD_CHIP_VER_PKG_M) >> EFUSE_RD_CHIP_VER_PKG_S;
|
||||
if (package == EFUSE_RD_CHIP_VER_PKG_ESP32D2WDQ5 ||
|
||||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD2 ||
|
||||
package == EFUSE_RD_CHIP_VER_PKG_ESP32PICOD4) {
|
||||
out_info->features |= CHIP_FEATURE_EMB_FLASH;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_chip_info(esp_chip_info_t* out_info)
|
||||
{
|
||||
// Only ESP32 is supported now, in the future call one of the
|
||||
// chip-specific functions based on sdkconfig choice
|
||||
return get_chip_info_esp32(out_info);
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "driver/periph_ctrl.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "hal/timer_ll.h"
|
||||
|
||||
|
||||
static const char *TAG = "task_wdt";
|
||||
|
||||
|
@ -107,9 +109,9 @@ static twdt_task_t *find_task_in_twdt_list(TaskHandle_t handle, bool *all_reset)
|
|||
static void reset_hw_timer(void)
|
||||
{
|
||||
//All tasks have reset; time to reset the hardware timer.
|
||||
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);
|
||||
//Clear all has_reset flags in list
|
||||
for (twdt_task_t *task = twdt_config->list; task != NULL; task = task->next){
|
||||
task->has_reset=false;
|
||||
|
@ -137,11 +139,11 @@ static void task_wdt_isr(void *arg)
|
|||
twdt_task_t *twdttask;
|
||||
const char *cpu;
|
||||
//Reset hardware timer so that 2nd stage timeout is not reached (will trigger system reset)
|
||||
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);
|
||||
//Acknowledge interrupt
|
||||
TIMERG0.int_clr_timers.wdt=1;
|
||||
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_INTR_WDT);
|
||||
//We are taking a spinlock while doing I/O (ESP_EARLY_LOGE) here. Normally, that is a pretty
|
||||
//bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
|
||||
//something bad already happened and reporting this is considered more important
|
||||
|
@ -198,32 +200,33 @@ esp_err_t esp_task_wdt_init(uint32_t timeout, bool panic)
|
|||
|
||||
//Configure hardware timer
|
||||
periph_module_enable(PERIPH_TIMG0_MODULE);
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
|
||||
TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
|
||||
TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
|
||||
TIMERG0.wdt_config0.level_int_en=1;
|
||||
TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT; //1st stage timeout: interrupt
|
||||
TIMERG0.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
|
||||
TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
|
||||
TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt
|
||||
TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset
|
||||
TIMERG0.wdt_config0.en=1;
|
||||
TIMERG0.wdt_feed=1;
|
||||
TIMERG0.wdt_wprotect=0; //Enable write protection
|
||||
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
|
||||
timer_ll_wdt_init(&TIMERG0);
|
||||
timer_ll_wdt_set_tick(&TIMERG0, TG0_WDT_TICK_US); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
|
||||
//1st stage timeout: interrupt
|
||||
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 0, TIMER_WDT_INT);
|
||||
timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
|
||||
//2nd stage timeout: reset system
|
||||
timer_ll_wdt_set_timeout_behavior(&TIMERG0, 1, TIMER_WDT_RESET_SYSTEM);
|
||||
timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, true);
|
||||
timer_ll_wdt_feed(&TIMERG0);
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
|
||||
} else { //twdt_config previously initialized
|
||||
//Reconfigure task wdt
|
||||
twdt_config->panic = panic;
|
||||
twdt_config->timeout = timeout;
|
||||
|
||||
//Reconfigure hardware timer
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
|
||||
TIMERG0.wdt_config0.en=0; //Disable timer
|
||||
TIMERG0.wdt_config2=twdt_config->timeout*2000; //Set timeout before interrupt
|
||||
TIMERG0.wdt_config3=twdt_config->timeout*4000; //Set timeout before reset
|
||||
TIMERG0.wdt_config0.en=1; //Renable timer
|
||||
TIMERG0.wdt_feed=1; //Reset timer
|
||||
TIMERG0.wdt_wprotect=0; //Enable write protection
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer
|
||||
//Set timeout before interrupt
|
||||
timer_ll_wdt_set_timeout(&TIMERG0, 0, twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
|
||||
//Set timeout before reset
|
||||
timer_ll_wdt_set_timeout(&TIMERG0, 1, 2*twdt_config->timeout*1000*1000/TG0_WDT_TICK_US);
|
||||
timer_ll_wdt_set_enable(&TIMERG0, true); //Renable timer
|
||||
timer_ll_wdt_feed(&TIMERG0); //Reset timer
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
|
||||
}
|
||||
portEXIT_CRITICAL(&twdt_spinlock);
|
||||
return ESP_OK;
|
||||
|
@ -238,9 +241,9 @@ esp_err_t esp_task_wdt_deinit(void)
|
|||
ASSERT_EXIT_CRIT_RETURN((twdt_config->list == NULL), ESP_ERR_INVALID_STATE);
|
||||
|
||||
//Disable hardware timer
|
||||
TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; //Disable write protection
|
||||
TIMERG0.wdt_config0.en=0; //Disable timer
|
||||
TIMERG0.wdt_wprotect=0; //Enable write protection
|
||||
timer_ll_wdt_set_protect(&TIMERG0, false); //Disable write protection
|
||||
timer_ll_wdt_set_enable(&TIMERG0, false); //Disable timer
|
||||
timer_ll_wdt_set_protect(&TIMERG0, true); //Enable write protection
|
||||
|
||||
ESP_ERROR_CHECK(esp_intr_free(twdt_config->intr_handle)); //Unregister interrupt
|
||||
free(twdt_config); //Free twdt_config
|
||||
|
|
|
@ -55,24 +55,20 @@ static void timer_isr(void *arg)
|
|||
int timer_idx = (int)arg;
|
||||
count[timer_idx]++;
|
||||
if (timer_idx==0) {
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
TIMERG0.hw_timer[0].update=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);
|
||||
}
|
||||
if (timer_idx==1) {
|
||||
TIMERG0.int_clr_timers.t1 = 1;
|
||||
TIMERG0.hw_timer[1].update=1;
|
||||
TIMERG0.hw_timer[1].config.alarm_en = 1;
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_1);
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, TIMER_1);
|
||||
}
|
||||
if (timer_idx==2) {
|
||||
TIMERG1.int_clr_timers.t0 = 1;
|
||||
TIMERG1.hw_timer[0].update=1;
|
||||
TIMERG1.hw_timer[0].config.alarm_en = 1;
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_1, TIMER_0);
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_0);
|
||||
}
|
||||
if (timer_idx==3) {
|
||||
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(TIMER_GROUP_1, TIMER_1);
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_1, TIMER_1);
|
||||
}
|
||||
// ets_printf("int %d\n", timer_idx);
|
||||
}
|
||||
|
|
|
@ -280,11 +280,12 @@ static void timer_group_test_first_stage(void)
|
|||
//Start timer
|
||||
timer_start(TIMER_GROUP_0, TIMER_0);
|
||||
//Waiting for timer_group to generate an interrupt
|
||||
while( !TIMERG0.int_raw.t0 && loop_cnt++ < 100) {
|
||||
while( !(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0) &&
|
||||
loop_cnt++ < 100) {
|
||||
vTaskDelay(200);
|
||||
}
|
||||
//TIMERG0.int_raw.t0 == 1 means an interruption has occurred
|
||||
TEST_ASSERT_EQUAL(1, TIMERG0.int_raw.t0);
|
||||
TEST_ASSERT(timer_group_intr_get_in_isr(TIMER_GROUP_0) & TIMER_INTR_T0);
|
||||
esp_restart();
|
||||
}
|
||||
|
||||
|
|
113
components/esp_common/include/esp_crc.h
Normal file
113
components/esp_common/include/esp_crc.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32)
|
||||
#include "esp32/rom/crc.h"
|
||||
#endif
|
||||
|
||||
/******************* Polynomials Used in the CRC APIs ****************************
|
||||
* CRC-8 x8+x2+x1+1 0x07
|
||||
* CRC16-CCITT x16+x12+x5+1 0x1021
|
||||
* CRC32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x1+1 0x04c11db7
|
||||
********************************************************************************/
|
||||
|
||||
/**
|
||||
* @brief CRC32 value in little endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC32 value
|
||||
*/
|
||||
static inline uint32_t esp_crc32_le(uint32_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc32_le(crc, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC32 value in big endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC32 value
|
||||
*/
|
||||
static inline uint32_t esp_crc32_be(uint32_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc32_be(crc, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC16 value in little endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC16 value
|
||||
*/
|
||||
static inline uint16_t esp_crc16_le(uint16_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc16_le(crc, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC16 value in big endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC16 value
|
||||
*/
|
||||
static inline uint16_t esp_crc16_be(uint16_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc16_be(crc, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC8 value in little endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC8 value
|
||||
*/
|
||||
static inline uint8_t esp_crc8_le(uint8_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc8_le(crc, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CRC8 value in big endian.
|
||||
*
|
||||
* @param crc: Initial CRC value (result of last calculation or 0 for the first time)
|
||||
* @param buf: Data buffer that used to calculate the CRC value
|
||||
* @param len: Length of the data buffer
|
||||
* @return CRC8 value
|
||||
*/
|
||||
static inline uint8_t esp_crc8_be(uint8_t crc, uint8_t const *buf, uint32_t len)
|
||||
{
|
||||
return crc8_be(crc, buf, len);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -21,7 +21,7 @@ extern "C" {
|
|||
/** Major version number (X.x.x) */
|
||||
#define ESP_IDF_VERSION_MAJOR 4
|
||||
/** Minor version number (x.X.x) */
|
||||
#define ESP_IDF_VERSION_MINOR 0
|
||||
#define ESP_IDF_VERSION_MINOR 1
|
||||
/** Patch version number (x.x.X) */
|
||||
#define ESP_IDF_VERSION_PATCH 0
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ extern "C" {
|
|||
|
||||
#include "esp_system.h"
|
||||
|
||||
#define TG0_WDT_TICK_US 500
|
||||
|
||||
/**
|
||||
* @brief Internal function to restart PRO and APP CPUs.
|
||||
*
|
||||
|
|
|
@ -297,15 +297,11 @@ void IRAM_ATTR test_event_on_timer_alarm(void* para)
|
|||
{
|
||||
/* Retrieve the interrupt status and the counter value
|
||||
from the timer that reported the interrupt */
|
||||
TIMERG0.hw_timer[TIMER_0].update = 1;
|
||||
uint64_t timer_counter_value =
|
||||
((uint64_t) TIMERG0.hw_timer[TIMER_0].cnt_high) << 32
|
||||
| TIMERG0.hw_timer[TIMER_0].cnt_low;
|
||||
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
timer_group_get_counter_value_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_counter_value += (uint64_t) (TIMER_INTERVAL0_SEC * TIMER_SCALE);
|
||||
TIMERG0.hw_timer[TIMER_0].alarm_high = (uint32_t) (timer_counter_value >> 32);
|
||||
TIMERG0.hw_timer[TIMER_0].alarm_low = (uint32_t) timer_counter_value;
|
||||
timer_group_set_alarm_value_in_isr(TIMER_GROUP_0, TIMER_0, timer_counter_value);
|
||||
|
||||
int data = (int) para;
|
||||
// Posting events with data more than 4 bytes should fail.
|
||||
|
|
|
@ -205,13 +205,15 @@ static void handle_H_command(const unsigned char* cmd, int len)
|
|||
} else if (requested_task_index > s_scratch.task_count) {
|
||||
ret = "E00";
|
||||
} else {
|
||||
TaskHandle_t handle;
|
||||
TaskHandle_t handle = NULL;
|
||||
get_task_handle(requested_task_index, &handle);
|
||||
/* FIXME: for the task currently running on the other CPU, extracting the registers from TCB
|
||||
* isn't valid. Need to use some IPC mechanism to obtain the registers of the other CPU
|
||||
*/
|
||||
if (handle != NULL) {
|
||||
esp_gdbstub_tcb_to_regfile(handle, &s_scratch.regfile);
|
||||
}
|
||||
}
|
||||
esp_gdbstub_send_str_packet(ret);
|
||||
} else {
|
||||
esp_gdbstub_send_str_packet(NULL);
|
||||
|
|
|
@ -378,6 +378,10 @@ static void httpd_sess_close(void *arg)
|
|||
{
|
||||
struct sock_db *sock_db = (struct sock_db *)arg;
|
||||
if (sock_db) {
|
||||
if (sock_db->lru_counter == 0) {
|
||||
ESP_LOGD(TAG, "Skipping session close for %d as it seems to be a race condition", sock_db->fd);
|
||||
return;
|
||||
}
|
||||
int fd = sock_db->fd;
|
||||
struct httpd_data *hd = (struct httpd_data *) sock_db->handle;
|
||||
httpd_sess_delete(hd, fd);
|
||||
|
|
|
@ -110,6 +110,19 @@ esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_
|
|||
*/
|
||||
esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle);
|
||||
|
||||
/**
|
||||
* @brief Checks if complete data was received or not
|
||||
*
|
||||
* @note This API can be called just before esp_https_ota_finish() to validate if the complete image was indeed received.
|
||||
*
|
||||
* @param[in] https_ota_handle pointer to esp_https_ota_handle_t structure
|
||||
*
|
||||
* @return
|
||||
* - false
|
||||
* - true
|
||||
*/
|
||||
bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle);
|
||||
|
||||
/**
|
||||
* @brief Clean-up HTTPS OTA Firmware upgrade and close HTTPS connection
|
||||
*
|
||||
|
|
|
@ -85,17 +85,21 @@ static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client
|
|||
static esp_err_t _http_connect(esp_http_client_handle_t http_client)
|
||||
{
|
||||
esp_err_t err = ESP_FAIL;
|
||||
int status_code;
|
||||
int status_code, header_ret;
|
||||
do {
|
||||
err = esp_http_client_open(http_client, 0);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
|
||||
return err;
|
||||
}
|
||||
esp_http_client_fetch_headers(http_client);
|
||||
header_ret = esp_http_client_fetch_headers(http_client);
|
||||
if (header_ret < 0) {
|
||||
return header_ret;
|
||||
}
|
||||
status_code = esp_http_client_get_status_code(http_client);
|
||||
if (_http_handle_response_code(http_client, status_code) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
err = _http_handle_response_code(http_client, status_code);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
} while (process_again(status_code));
|
||||
return err;
|
||||
|
@ -276,6 +280,12 @@ esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)
|
||||
{
|
||||
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
||||
return esp_http_client_is_complete_data_received(handle->http_client);
|
||||
}
|
||||
|
||||
esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
|
||||
{
|
||||
esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
|
||||
|
|
|
@ -356,8 +356,8 @@ static int iterations;
|
|||
static void ringbuffer_isr(void *arg)
|
||||
{
|
||||
//Clear timer interrupt
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1;
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
|
||||
|
||||
//Test sending to buffer from ISR from ISR
|
||||
if (buf_type < NO_OF_RB_TYPES) {
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
--encrypt ${ESPTOOLPY_FLASH_PROJECT_OPTIONS}
|
||||
$<JOIN:$<TARGET_PROPERTY:flash_project_args_target,FLASH_PROJECT_ARGS>,
|
||||
$<JOIN:${FLASH_PROJECT_ARGS},
|
||||
>
|
||||
|
|
|
@ -64,27 +64,15 @@
|
|||
static const USHORT usTimerIndex = CONFIG_FMB_TIMER_INDEX; // Modbus Timer index used by stack
|
||||
static const USHORT usTimerGroupIndex = CONFIG_FMB_TIMER_GROUP; // Modbus Timer group index used by stack
|
||||
|
||||
static timg_dev_t *MB_TG[2] = {&TIMERG0, &TIMERG1};
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
static void IRAM_ATTR vTimerGroupIsr(void *param)
|
||||
{
|
||||
// Retrieve the interrupt status and the counter value
|
||||
// from the timer that reported the interrupt
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st.val;
|
||||
#endif
|
||||
if (intr_status & BIT(usTimerIndex)) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||
MB_TG[usTimerGroupIndex]->int_clr.val |= BIT(usTimerIndex);
|
||||
#endif
|
||||
assert((int)param == usTimerIndex);
|
||||
// Retrieve the counter value from the timer that reported the interrupt
|
||||
timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
|
||||
(void)pxMBPortCBTimerExpired(); // Timer callback function
|
||||
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN;
|
||||
}
|
||||
// Enable alarm
|
||||
timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -121,7 +109,7 @@ BOOL xMBPortTimersInit(USHORT usTim1Timerout50us)
|
|||
"failure to set alarm failure, timer_set_alarm_value() returned (0x%x).",
|
||||
(uint32_t)xErr);
|
||||
// Register ISR for timer
|
||||
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL);
|
||||
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex, vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"timer set value failure, timer_isr_register() returned (0x%x).",
|
||||
(uint32_t)xErr);
|
||||
|
|
|
@ -62,34 +62,16 @@ static USHORT usT35TimeOut50us;
|
|||
static const USHORT usTimerIndex = MB_TIMER_INDEX; // Initialize Modbus Timer index used by stack,
|
||||
static const USHORT usTimerGroupIndex = MB_TIMER_GROUP; // Timer group index used by stack
|
||||
|
||||
static timg_dev_t *MB_TG[2] = { &TIMERG0, &TIMERG1 };
|
||||
|
||||
/* ----------------------- static functions ---------------------------------*/
|
||||
|
||||
static void IRAM_ATTR vTimerGroupIsr(void *param)
|
||||
{
|
||||
// Retrieve the interrupt status and the counter value
|
||||
// from the timer that reported the interrupt
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st_timers.val;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||
uint32_t intr_status = MB_TG[usTimerGroupIndex]->int_st.val;
|
||||
#endif
|
||||
if (intr_status & BIT(usTimerIndex)) {
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
MB_TG[usTimerGroupIndex]->int_clr_timers.val |= BIT(usTimerIndex);
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||
MB_TG[usTimerGroupIndex]->int_clr.val |= BIT(usTimerIndex);
|
||||
#endif
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update = 1;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2BETA
|
||||
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].update.update = 1;
|
||||
#endif
|
||||
assert((int)param == usTimerIndex);
|
||||
// Retrieve the the counter value from the timer that reported the interrupt
|
||||
timer_group_intr_clr_in_isr(usTimerGroupIndex, usTimerIndex);
|
||||
(void)pxMBMasterPortCBTimerExpired(); // Timer expired callback function
|
||||
// Enable alarm
|
||||
MB_TG[usTimerGroupIndex]->hw_timer[usTimerIndex].config.alarm_en = TIMER_ALARM_EN;
|
||||
}
|
||||
timer_group_enable_alarm_in_isr(usTimerGroupIndex, usTimerIndex);
|
||||
}
|
||||
|
||||
/* ----------------------- Start implementation -----------------------------*/
|
||||
|
@ -128,7 +110,7 @@ BOOL xMBMasterPortTimersInit(USHORT usTimeOut50us)
|
|||
(uint32_t)xErr);
|
||||
// Register ISR for timer
|
||||
xErr = timer_isr_register(usTimerGroupIndex, usTimerIndex,
|
||||
vTimerGroupIsr, NULL, ESP_INTR_FLAG_IRAM, NULL);
|
||||
vTimerGroupIsr, (void*)(uint32_t)usTimerIndex, ESP_INTR_FLAG_IRAM, NULL);
|
||||
MB_PORT_CHECK((xErr == ESP_OK), FALSE,
|
||||
"timer set value failure, timer_isr_register() returned (0x%x).",
|
||||
(uint32_t)xErr);
|
||||
|
|
|
@ -138,9 +138,13 @@ typedef struct {
|
|||
/* owner field values:
|
||||
* 0 - Uninitialized (invalid)
|
||||
* portMUX_FREE_VAL - Mux is free, can be locked by either CPU
|
||||
* CORE_ID_PRO / CORE_ID_APP - Mux is locked to the particular core
|
||||
* CORE_ID_REGVAL_PRO / CORE_ID_REGVAL_APP - Mux is locked to the particular core
|
||||
*
|
||||
* Any value other than portMUX_FREE_VAL, CORE_ID_PRO, CORE_ID_APP indicates corruption
|
||||
* Note that for performance reasons we use the full Xtensa CORE ID values
|
||||
* (CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP) and not the 0,1 values which are used in most
|
||||
* other FreeRTOS code.
|
||||
*
|
||||
* Any value other than portMUX_FREE_VAL, CORE_ID_REGVAL_PRO, CORE_ID_REGVAL_APP indicates corruption
|
||||
*/
|
||||
uint32_t owner;
|
||||
/* count field:
|
||||
|
|
|
@ -185,7 +185,7 @@ typedef struct xTASK_STATUS
|
|||
StackType_t *pxStackBase; /*!< Points to the lowest address of the task's stack area. */
|
||||
uint32_t usStackHighWaterMark; /*!< The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
|
||||
#if configTASKLIST_INCLUDE_COREID
|
||||
BaseType_t xCoreID; /*!< Core this task is pinned to. This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */
|
||||
BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or -1 for tskNO_AFFINITY). This field is present if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID is set. */
|
||||
#endif
|
||||
} TaskStatus_t;
|
||||
|
||||
|
@ -324,7 +324,7 @@ is used in assert() statements. */
|
|||
*
|
||||
* @param xCoreID If the value is tskNO_AFFINITY, the created task is not
|
||||
* pinned to any CPU, and the scheduler can run it on any core available.
|
||||
* Other values indicate the index number of the CPU which the task should
|
||||
* Values 0 or 1 indicate the index number of the CPU which the task should
|
||||
* be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will
|
||||
* cause the function to fail.
|
||||
*
|
||||
|
@ -476,7 +476,7 @@ is used in assert() statements. */
|
|||
*
|
||||
* @param xCoreID If the value is tskNO_AFFINITY, the created task is not
|
||||
* pinned to any CPU, and the scheduler can run it on any core available.
|
||||
* Other values indicate the index number of the CPU which the task should
|
||||
* Values 0 or 1 indicate the index number of the CPU which the task should
|
||||
* be pinned to. Specifying values larger than (portNUM_PROCESSORS - 1) will
|
||||
* cause the function to fail.
|
||||
*
|
||||
|
|
|
@ -325,8 +325,17 @@ STRUCT_END(XtSolFrame)
|
|||
.endm
|
||||
#endif
|
||||
|
||||
#define CORE_ID_PRO 0xCDCD
|
||||
#define CORE_ID_APP 0xABAB
|
||||
/* Note: These are different to xCoreID used in ESP-IDF FreeRTOS, most places use
|
||||
0 and 1 which are determined by checking bit 13 (see previous comment)
|
||||
*/
|
||||
#define CORE_ID_REGVAL_PRO 0xCDCD
|
||||
#define CORE_ID_REGVAL_APP 0xABAB
|
||||
|
||||
/* Included for compatibility, recommend using CORE_ID_REGVAL_PRO instead */
|
||||
#define CORE_ID_PRO CORE_ID_REGVAL_PRO
|
||||
|
||||
/* Included for compatibility, recommend using CORE_ID_REGVAL_APP instead */
|
||||
#define CORE_ID_APP CORE_ID_REGVAL_APP
|
||||
|
||||
/*
|
||||
-------------------------------------------------------------------------------
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "soc/soc_memory_layout.h"
|
||||
|
||||
/* XOR one core ID with this value to get the other core ID */
|
||||
#define CORE_ID_XOR_SWAP (CORE_ID_PRO ^ CORE_ID_APP)
|
||||
#define CORE_ID_REGVAL_XOR_SWAP (CORE_ID_REGVAL_PRO ^ CORE_ID_REGVAL_APP)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) {
|
|||
|
||||
#ifdef CONFIG_FREERTOS_PORTMUX_DEBUG
|
||||
uint32_t owner = mux->owner;
|
||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) {
|
||||
ets_printf("ERROR: vPortCPUAcquireMutex: mux %p is uninitialized (0x%X)! Called from %s line %d.\n", mux, owner, fnName, line);
|
||||
mux->owner=portMUX_FREE_VAL;
|
||||
}
|
||||
|
@ -70,13 +70,13 @@ PORTMUX_AQUIRE_MUX_FN_NAME(portMUX_TYPE *mux, int timeout_cycles) {
|
|||
/* Spin until we own the core */
|
||||
|
||||
RSR(PRID, coreID);
|
||||
/* Note: coreID is the full 32 bit core ID (CORE_ID_PRO/CORE_ID_APP),
|
||||
/* Note: coreID is the full 32 bit core ID (CORE_ID_REGVAL_PRO/CORE_ID_REGVAL_APP),
|
||||
not the 0/1 value returned by xPortGetCoreID()
|
||||
*/
|
||||
otherCoreID = CORE_ID_XOR_SWAP ^ coreID;
|
||||
otherCoreID = CORE_ID_REGVAL_XOR_SWAP ^ coreID;
|
||||
do {
|
||||
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_PRO,
|
||||
CORE_ID_APP:
|
||||
/* mux->owner should be one of portMUX_FREE_VAL, CORE_ID_REGVAL_PRO,
|
||||
CORE_ID_REGVAL_APP:
|
||||
|
||||
- If portMUX_FREE_VAL, we want to atomically set to 'coreID'.
|
||||
- If "our" coreID, we can drop through immediately.
|
||||
|
@ -138,7 +138,7 @@ static inline void PORTMUX_RELEASE_MUX_FN_NAME(portMUX_TYPE *mux) {
|
|||
mux->lastLockedFn=fnName;
|
||||
mux->lastLockedLine=line;
|
||||
uint32_t owner = mux->owner;
|
||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_PRO && owner != CORE_ID_APP) {
|
||||
if (owner != portMUX_FREE_VAL && owner != CORE_ID_REGVAL_PRO && owner != CORE_ID_REGVAL_APP) {
|
||||
ets_printf("ERROR: vPortCPUReleaseMutex: mux %p is invalid (0x%x)!\n", mux, mux->owner);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -144,8 +144,8 @@ static bool test_clear_bits;
|
|||
static void IRAM_ATTR event_group_isr(void *arg)
|
||||
{
|
||||
portBASE_TYPE task_woken = pdFALSE;
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1;
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_0, TIMER_0);
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, xPortGetCoreID());
|
||||
|
||||
if(test_set_bits){
|
||||
xEventGroupSetBitsFromISR(eg, BITS, &task_woken);
|
||||
|
|
|
@ -103,16 +103,10 @@ static void receiver_task (void* arg){
|
|||
static void IRAM_ATTR sender_ISR (void *arg)
|
||||
{
|
||||
int curcore = xPortGetCoreID();
|
||||
if(curcore == 0){ //Clear timer interrupt
|
||||
//Clear intr and pause via direct reg access as IRAM ISR cannot access timer APIs
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
TIMERG0.hw_timer[0].config.enable = 0;
|
||||
}else{
|
||||
TIMERG0.int_clr_timers.t1 = 1;
|
||||
TIMERG0.hw_timer[1].config.enable = 0;
|
||||
}
|
||||
timer_group_intr_clr_in_isr(TIMER_GROUP_0, curcore);
|
||||
timer_group_set_counter_enable_in_isr(TIMER_GROUP_0, curcore, TIMER_PAUSE);
|
||||
//Re-enable alarm
|
||||
TIMERG0.hw_timer[curcore].config.alarm_en = 1;
|
||||
timer_group_enable_alarm_in_isr(TIMER_GROUP_0, curcore);
|
||||
|
||||
if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core
|
||||
notifs_sent++;
|
||||
|
|
|
@ -26,9 +26,8 @@ static volatile unsigned isr_count;
|
|||
mutex semaphore to wake up another counter task */
|
||||
static void timer_group0_isr(void *vp_arg)
|
||||
{
|
||||
TIMERG0.int_clr_timers.t0 = 1;
|
||||
TIMERG0.hw_timer[TIMER_0].update = 1;
|
||||
TIMERG0.hw_timer[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);
|
||||
portBASE_TYPE higher_awoken = pdFALSE;
|
||||
isr_count++;
|
||||
xSemaphoreGiveFromISR(isr_semaphore, &higher_awoken);
|
||||
|
|
|
@ -123,7 +123,7 @@ volatile bool timer_isr_fired;
|
|||
void IRAM_ATTR timer_group0_isr(void *vp_arg)
|
||||
{
|
||||
// Clear interrupt
|
||||
TIMERG0.int_clr_timers.val = TIMERG0.int_st_timers.val;
|
||||
timer_group_clr_intr_sta_in_isr(TIMER_GROUP_0, TIMER_0|TIMER_1);
|
||||
|
||||
timer_isr_fired = true;
|
||||
TaskHandle_t handle = vp_arg;
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA1_32KB 5000
|
||||
#define IDF_PERFORMANCE_MAX_ESP32_TIME_SHA512_32KB 4500
|
||||
// AES-CBC hardware throughput (accounts for worst-case performance with PSRAM workaround)
|
||||
#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.5
|
||||
#define IDF_PERFORMANCE_MIN_AES_CBC_THROUGHPUT_MBSEC 8.2
|
||||
// floating point instructions per divide and per sqrt (configured for worst-case with PSRAM workaround)
|
||||
#define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_DIV 70
|
||||
#define IDF_PERFORMANCE_MAX_ESP32_CYCLES_PER_SQRT 140
|
||||
|
|
|
@ -39,7 +39,7 @@ TEST_CASE("box tests", "[libsodium]")
|
|||
|
||||
extern int ed25519_convert_xmain(void);
|
||||
|
||||
TEST_CASE("ed25519_convert tests", "[libsodium]")
|
||||
TEST_CASE("ed25519_convert tests", "[libsodium][timeout=60]")
|
||||
{
|
||||
printf("Running ed25519_convert\n");
|
||||
TEST_ASSERT_EQUAL(0, ed25519_convert_xmain() );
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 61d840ff4778f4946c8743f7e412345abcd537f1
|
||||
Subproject commit 663b2fdb41177c82f2aa5939e41aef54427d15cd
|
|
@ -23,18 +23,19 @@ set_property(TARGET mbedtls PROPERTY SOURCES ${src_tls})
|
|||
set(mbedtls_targets mbedtls mbedcrypto mbedx509)
|
||||
|
||||
# Add port files to mbedtls targets
|
||||
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
|
||||
"${COMPONENT_PATH}/port/esp_sha.c"
|
||||
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c"
|
||||
"${COMPONENT_DIR}/port/net_sockets.c")
|
||||
|
||||
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
|
||||
"${COMPONENT_DIR}/port/esp_mem.c"
|
||||
"${COMPONENT_DIR}/port/esp_sha.c"
|
||||
"${COMPONENT_DIR}/port/esp_sha1.c"
|
||||
"${COMPONENT_DIR}/port/esp_sha256.c"
|
||||
"${COMPONENT_DIR}/port/esp_sha512.c"
|
||||
"${COMPONENT_DIR}/port/esp_timing.c"
|
||||
"${COMPONENT_DIR}/port/mbedtls_debug.c"
|
||||
"${COMPONENT_DIR}/port/net_sockets.c"
|
||||
"${COMPONENT_DIR}/port/${idf_target}/esp_bignum.c"
|
||||
"${COMPONENT_DIR}/port/${idf_target}/aes.c"
|
||||
"${COMPONENT_DIR}/port/${idf_target}/sha.c"
|
||||
"${COMPONENT_DIR}/port/${idf_target}/esp_bignum.c")
|
||||
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_mem.c")
|
||||
"${COMPONENT_DIR}/port/${idf_target}/sha.c")
|
||||
|
||||
foreach(target ${mbedtls_targets})
|
||||
target_compile_definitions(${target} PUBLIC -DMBEDTLS_CONFIG_FILE="mbedtls/esp_config.h")
|
||||
|
|
|
@ -49,6 +49,11 @@
|
|||
*/
|
||||
static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static inline bool valid_key_length(const esp_aes_context *ctx)
|
||||
{
|
||||
return ctx->key_bytes == 128/8 || ctx->key_bytes == 192/8 || ctx->key_bytes == 256/8;
|
||||
}
|
||||
|
||||
void esp_aes_acquire_hardware( void )
|
||||
{
|
||||
portENTER_CRITICAL(&aes_spinlock);
|
||||
|
@ -93,6 +98,7 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
|
|||
}
|
||||
ctx->key_bytes = keybits / 8;
|
||||
memcpy(ctx->key, key, ctx->key_bytes);
|
||||
ctx->key_in_hardware = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -102,28 +108,47 @@ int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key,
|
|||
*
|
||||
* Call only while holding esp_aes_acquire_hardware().
|
||||
*/
|
||||
static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode)
|
||||
static void esp_aes_setkey_hardware(esp_aes_context *ctx, int mode)
|
||||
{
|
||||
const uint32_t MODE_DECRYPT_BIT = 4;
|
||||
unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT;
|
||||
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
for (int i = 0; i < ctx->key_bytes/4; ++i) {
|
||||
DPORT_REG_WRITE(AES_KEY_BASE + i * 4, *(((uint32_t *)ctx->key) + i));
|
||||
ctx->key_in_hardware += 4;
|
||||
}
|
||||
|
||||
DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2));
|
||||
|
||||
/* Fault injection check: all words of key data should have been written to hardware */
|
||||
if (ctx->key_in_hardware < 16
|
||||
|| ctx->key_in_hardware != ctx->key_bytes) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/* Run a single 16 byte block of AES, using the hardware engine.
|
||||
*
|
||||
* Call only while holding esp_aes_acquire_hardware().
|
||||
*/
|
||||
static void esp_aes_block(const void *input, void *output)
|
||||
static int esp_aes_block(esp_aes_context *ctx, const void *input, void *output)
|
||||
{
|
||||
const uint32_t *input_words = (const uint32_t *)input;
|
||||
uint32_t i0, i1, i2, i3;
|
||||
uint32_t *output_words = (uint32_t *)output;
|
||||
|
||||
/* If no key is written to hardware yet, either the user hasn't called
|
||||
mbedtls_aes_setkey_enc/mbedtls_aes_setkey_dec - meaning we also don't
|
||||
know which mode to use - or a fault skipped the
|
||||
key write to hardware. Treat this as a fatal error and zero the output block.
|
||||
*/
|
||||
if (ctx->key_in_hardware != ctx->key_bytes) {
|
||||
bzero(output, 16);
|
||||
return MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH;
|
||||
}
|
||||
|
||||
/* Storing i0,i1,i2,i3 in registers not an array
|
||||
helps a lot with optimisations at -Os level */
|
||||
i0 = input_words[0];
|
||||
|
@ -152,11 +177,14 @@ static void esp_aes_block(const void *input, void *output)
|
|||
Bypassing this check requires at least one additional fault.
|
||||
*/
|
||||
if(i0 == output_words[0] && i1 == output_words[1] && i2 == output_words[2] && i3 == output_words[3]) {
|
||||
// calling two zeroing functions to narrow the
|
||||
// window for a double-fault here
|
||||
// calling zeroing functions to narrow the
|
||||
// window for a double-fault of the abort step, here
|
||||
memset(output, 0, 16);
|
||||
mbedtls_platform_zeroize(output, 16);
|
||||
abort();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -166,11 +194,18 @@ int esp_internal_aes_encrypt( esp_aes_context *ctx,
|
|||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void esp_aes_encrypt( esp_aes_context *ctx,
|
||||
|
@ -188,11 +223,18 @@ int esp_internal_aes_decrypt( esp_aes_context *ctx,
|
|||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
void esp_aes_decrypt( esp_aes_context *ctx,
|
||||
|
@ -202,7 +244,6 @@ void esp_aes_decrypt( esp_aes_context *ctx,
|
|||
esp_internal_aes_decrypt(ctx, input, output);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AES-ECB block encryption/decryption
|
||||
*/
|
||||
|
@ -211,12 +252,19 @@ int esp_aes_crypt_ecb( esp_aes_context *ctx,
|
|||
const unsigned char input[16],
|
||||
unsigned char output[16] )
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
esp_aes_setkey_hardware(ctx, mode);
|
||||
esp_aes_block(input, output);
|
||||
r = esp_aes_block(ctx, input, output);
|
||||
esp_aes_release_hardware();
|
||||
|
||||
return 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
@ -240,14 +288,19 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
|
|||
return ( ERR_ESP_AES_INVALID_INPUT_LENGTH );
|
||||
}
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, mode);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
while ( length > 0 ) {
|
||||
memcpy(temp, input_words, 16);
|
||||
esp_aes_block(input_words, output_words);
|
||||
esp_aes_block(ctx, input_words, output_words);
|
||||
|
||||
for ( i = 0; i < 4; i++ ) {
|
||||
output_words[i] = output_words[i] ^ iv_words[i];
|
||||
|
@ -266,7 +319,7 @@ int esp_aes_crypt_cbc( esp_aes_context *ctx,
|
|||
output_words[i] = input_words[i] ^ iv_words[i];
|
||||
}
|
||||
|
||||
esp_aes_block(output_words, output_words);
|
||||
esp_aes_block(ctx, output_words, output_words);
|
||||
memcpy( iv_words, output_words, 16 );
|
||||
|
||||
input_words += 4;
|
||||
|
@ -294,14 +347,19 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
|
|||
int c;
|
||||
size_t n = *iv_off;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(iv, iv );
|
||||
esp_aes_block(ctx, iv, iv);
|
||||
}
|
||||
|
||||
c = *input++;
|
||||
|
@ -313,7 +371,7 @@ int esp_aes_crypt_cfb128( esp_aes_context *ctx,
|
|||
} else {
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(iv, iv );
|
||||
esp_aes_block(ctx, iv, iv);
|
||||
}
|
||||
|
||||
iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ );
|
||||
|
@ -342,13 +400,18 @@ int esp_aes_crypt_cfb8( esp_aes_context *ctx,
|
|||
unsigned char c;
|
||||
unsigned char ov[17];
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
while ( length-- ) {
|
||||
memcpy( ov, iv, 16 );
|
||||
esp_aes_block(iv, iv);
|
||||
esp_aes_block(ctx, iv, iv);
|
||||
|
||||
if ( mode == ESP_AES_DECRYPT ) {
|
||||
ov[16] = *input;
|
||||
|
@ -382,13 +445,18 @@ int esp_aes_crypt_ctr( esp_aes_context *ctx,
|
|||
int c, i;
|
||||
size_t n = *nc_off;
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
ctx->key_in_hardware = 0;
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
while ( length-- ) {
|
||||
if ( n == 0 ) {
|
||||
esp_aes_block(nonce_counter, stream_block);
|
||||
esp_aes_block(ctx, nonce_counter, stream_block);
|
||||
|
||||
for ( i = 16; i > 0; i-- )
|
||||
if ( ++nonce_counter[i - 1] != 0 ) {
|
||||
|
@ -432,13 +500,17 @@ int esp_aes_crypt_ofb( esp_aes_context *ctx,
|
|||
return( MBEDTLS_ERR_AES_BAD_INPUT_DATA );
|
||||
}
|
||||
|
||||
if (!valid_key_length(ctx)) {
|
||||
return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH;
|
||||
}
|
||||
|
||||
esp_aes_acquire_hardware();
|
||||
|
||||
esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT);
|
||||
|
||||
while( length-- ) {
|
||||
if( n == 0 ) {
|
||||
esp_aes_block( iv, iv );
|
||||
esp_aes_block(ctx, iv, iv);
|
||||
}
|
||||
*output++ = *input++ ^ iv[n];
|
||||
|
||||
|
|
|
@ -228,6 +228,7 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
|||
{
|
||||
uint32_t *digest_state_words = NULL;
|
||||
uint32_t *reg_addr_buf = NULL;
|
||||
uint32_t word_len = sha_length(sha_type)/4;
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
SemaphoreHandle_t *engine_state = sha_get_engine_state(sha_type);
|
||||
|
@ -250,15 +251,25 @@ void esp_sha_read_digest_state(esp_sha_type sha_type, void *digest_state)
|
|||
if(sha_type == SHA2_384 || sha_type == SHA2_512) {
|
||||
/* for these ciphers using 64-bit states, swap each pair of words */
|
||||
DPORT_INTERRUPT_DISABLE(); // Disable interrupt only on current CPU.
|
||||
for(int i = 0; i < sha_length(sha_type)/4; i += 2) {
|
||||
for(int i = 0; i < word_len; i += 2) {
|
||||
digest_state_words[i+1] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i]);
|
||||
digest_state_words[i] = DPORT_SEQUENCE_REG_READ((uint32_t)®_addr_buf[i+1]);
|
||||
}
|
||||
DPORT_INTERRUPT_RESTORE(); // restore the previous interrupt level
|
||||
} else {
|
||||
esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], sha_length(sha_type)/4);
|
||||
esp_dport_access_read_buffer(digest_state_words, (uint32_t)®_addr_buf[0], word_len);
|
||||
}
|
||||
esp_sha_unlock_memory_block();
|
||||
|
||||
/* Fault injection check: verify SHA engine actually ran,
|
||||
state is not all zeroes.
|
||||
*/
|
||||
for (int i = 0; i < word_len; i++) {
|
||||
if (digest_state_words[i] != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
abort(); // SHA peripheral returned all zero state, probably due to fault injection
|
||||
}
|
||||
|
||||
void esp_sha_block(esp_sha_type sha_type, const void *data_block, bool is_first_block)
|
||||
|
|
|
@ -41,17 +41,13 @@ extern "C" {
|
|||
/**
|
||||
* \brief AES context structure
|
||||
*
|
||||
* \note buf is able to hold 32 extra bytes, which can be used:
|
||||
* - for alignment purposes if VIA padlock is used, and/or
|
||||
* - to simplify key expansion in the 256-bit case by
|
||||
* generating an extra round key
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t key_bytes;
|
||||
volatile uint8_t key_in_hardware; /* This variable is used for fault injection checks, so marked volatile to avoid optimisation */
|
||||
uint8_t key[32];
|
||||
} esp_aes_context;
|
||||
|
||||
|
||||
/**
|
||||
* \brief The AES XTS context-type definition.
|
||||
*/
|
||||
|
|
|
@ -59,16 +59,6 @@ static int net_prepare( void )
|
|||
return ( 0 );
|
||||
}
|
||||
|
||||
static int mbedtls_net_errno(int fd)
|
||||
{
|
||||
int sock_errno = 0;
|
||||
u32_t optlen = sizeof(sock_errno);
|
||||
|
||||
getsockopt(fd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
|
||||
|
||||
return sock_errno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a context
|
||||
*/
|
||||
|
@ -204,22 +194,19 @@ int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char
|
|||
*
|
||||
* Note: on a blocking socket this function always returns 0!
|
||||
*/
|
||||
static int net_would_block( const mbedtls_net_context *ctx, int *errout )
|
||||
static int net_would_block( const mbedtls_net_context *ctx )
|
||||
{
|
||||
int error = mbedtls_net_errno(ctx->fd);
|
||||
|
||||
if ( errout ) {
|
||||
*errout = error;
|
||||
}
|
||||
int error = errno;
|
||||
|
||||
/*
|
||||
* Never return 'WOULD BLOCK' on a non-blocking socket
|
||||
*/
|
||||
if ( ( fcntl( ctx->fd, F_GETFL, 0) & O_NONBLOCK ) != O_NONBLOCK ) {
|
||||
errno = error;
|
||||
return ( 0 );
|
||||
}
|
||||
|
||||
switch ( error ) {
|
||||
switch ( errno = error ) {
|
||||
#if defined EAGAIN
|
||||
case EAGAIN:
|
||||
#endif
|
||||
|
@ -267,7 +254,7 @@ int mbedtls_net_accept( mbedtls_net_context *bind_ctx,
|
|||
}
|
||||
|
||||
if ( ret < 0 ) {
|
||||
if ( net_would_block( bind_ctx, NULL ) != 0 ) {
|
||||
if ( net_would_block( bind_ctx ) != 0 ) {
|
||||
return ( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
}
|
||||
|
||||
|
@ -347,7 +334,6 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
|
|||
{
|
||||
int ret;
|
||||
int fd = ((mbedtls_net_context *) ctx)->fd;
|
||||
int error = 0;
|
||||
|
||||
if ( fd < 0 ) {
|
||||
return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
|
||||
|
@ -356,15 +342,15 @@ int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len )
|
|||
ret = (int) read( fd, buf, len );
|
||||
|
||||
if ( ret < 0 ) {
|
||||
if ( net_would_block( ctx, &error ) != 0 ) {
|
||||
if ( net_would_block( ctx ) != 0 ) {
|
||||
return ( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
}
|
||||
|
||||
if ( error == EPIPE || error == ECONNRESET ) {
|
||||
if ( errno == EPIPE || errno == ECONNRESET ) {
|
||||
return ( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
}
|
||||
|
||||
if ( error == EINTR ) {
|
||||
if ( errno == EINTR ) {
|
||||
return ( MBEDTLS_ERR_SSL_WANT_READ );
|
||||
}
|
||||
|
||||
|
@ -422,8 +408,6 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
|
|||
int ret;
|
||||
int fd = ((mbedtls_net_context *) ctx)->fd;
|
||||
|
||||
int error = 0;
|
||||
|
||||
if ( fd < 0 ) {
|
||||
return ( MBEDTLS_ERR_NET_INVALID_CONTEXT );
|
||||
}
|
||||
|
@ -431,15 +415,15 @@ int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len )
|
|||
ret = (int) write( fd, buf, len );
|
||||
|
||||
if ( ret < 0 ) {
|
||||
if ( net_would_block( ctx, &error ) != 0 ) {
|
||||
if ( net_would_block( ctx ) != 0 ) {
|
||||
return ( MBEDTLS_ERR_SSL_WANT_WRITE );
|
||||
}
|
||||
|
||||
if ( error == EPIPE || error == ECONNRESET ) {
|
||||
if ( errno == EPIPE || errno == ECONNRESET ) {
|
||||
return ( MBEDTLS_ERR_NET_CONN_RESET );
|
||||
}
|
||||
|
||||
if ( error == EINTR ) {
|
||||
if ( errno == EINTR ) {
|
||||
return ( MBEDTLS_ERR_SSL_WANT_WRITE );
|
||||
}
|
||||
|
||||
|
|
|
@ -1676,9 +1676,7 @@ static void _mdns_send_final_bye(bool include_ip)
|
|||
size_t srv_count = 0;
|
||||
mdns_srv_item_t * a = _mdns_server->services;
|
||||
while (a) {
|
||||
if (!a->service->instance) {
|
||||
srv_count++;
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
if (!srv_count) {
|
||||
|
@ -1688,9 +1686,7 @@ static void _mdns_send_final_bye(bool include_ip)
|
|||
size_t i = 0;
|
||||
a = _mdns_server->services;
|
||||
while (a) {
|
||||
if (!a->service->instance) {
|
||||
services[i++] = a;
|
||||
}
|
||||
a = a->next;
|
||||
}
|
||||
_mdns_send_bye(services, srv_count, include_ip);
|
||||
|
@ -1699,7 +1695,7 @@ static void _mdns_send_final_bye(bool include_ip)
|
|||
/**
|
||||
* @brief Stop the responder on all services without instance
|
||||
*/
|
||||
static void _mdns_send_bye_all_pcbs_no_instance(void)
|
||||
static void _mdns_send_bye_all_pcbs_no_instance(bool include_ip)
|
||||
{
|
||||
size_t srv_count = 0;
|
||||
mdns_srv_item_t * a = _mdns_server->services;
|
||||
|
@ -1721,7 +1717,7 @@ static void _mdns_send_bye_all_pcbs_no_instance(void)
|
|||
}
|
||||
a = a->next;
|
||||
}
|
||||
_mdns_send_bye(services, srv_count, false);
|
||||
_mdns_send_bye(services, srv_count, include_ip);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3734,14 +3730,14 @@ static void _mdns_execute_action(mdns_action_t * action)
|
|||
action->data.sys_event.event_id, action->data.sys_event.interface);
|
||||
break;
|
||||
case ACTION_HOSTNAME_SET:
|
||||
_mdns_send_final_bye(true);
|
||||
_mdns_send_bye_all_pcbs_no_instance(true);
|
||||
free((char*)_mdns_server->hostname);
|
||||
_mdns_server->hostname = action->data.hostname;
|
||||
_mdns_restart_all_pcbs();
|
||||
|
||||
break;
|
||||
case ACTION_INSTANCE_SET:
|
||||
_mdns_send_bye_all_pcbs_no_instance();
|
||||
_mdns_send_bye_all_pcbs_no_instance(false);
|
||||
free((char*)_mdns_server->instance);
|
||||
_mdns_server->instance = action->data.instance;
|
||||
_mdns_restart_all_pcbs_no_instance();
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit dc37d3a065f345a7358b8ff4553db0baceeb8ad6
|
||||
Subproject commit 117eef2dad54e0f9e25b3005fcfc18e7695ff29e
|
|
@ -287,7 +287,7 @@ gatt_svr_dsc_access(uint16_t conn_handle, uint16_t attr_handle, struct
|
|||
char *temp_outbuf = strdup(ctxt->dsc->arg);
|
||||
if (temp_outbuf == NULL) {
|
||||
ESP_LOGE(TAG, "Error duplicating user description of characteristic");
|
||||
return ESP_ERR_NO_MEM;
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
ssize_t temp_outlen = strlen(temp_outbuf);
|
||||
|
@ -308,6 +308,9 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
|||
ssize_t temp_outlen = 0;
|
||||
uint8_t *temp_outbuf = NULL;
|
||||
uint8_t *uuid = NULL;
|
||||
uint8_t *data_buf = NULL;
|
||||
uint16_t data_len = 0;
|
||||
uint16_t data_buf_len = 0;
|
||||
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
|
@ -328,7 +331,7 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
|||
uuid = (uint8_t *) calloc(BLE_UUID128_VAL_LENGTH, sizeof(uint8_t));
|
||||
if (!uuid) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for 128 bit UUID");
|
||||
return ESP_ERR_NO_MEM;
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
rc = ble_uuid_flat(ctxt->chr->uuid, uuid);
|
||||
|
@ -338,16 +341,32 @@ gatt_svr_chr_access(uint16_t conn_handle, uint16_t attr_handle,
|
|||
return rc;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, om_len = %d",
|
||||
ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, ctxt->om->om_len);
|
||||
/* Save the length of entire data */
|
||||
data_len = OS_MBUF_PKTLEN(ctxt->om);
|
||||
ESP_LOGD(TAG, "Write attempt for uuid = %s, attr_handle = %d, data_len = %d",
|
||||
ble_uuid_to_str(ctxt->chr->uuid, buf), attr_handle, data_len);
|
||||
|
||||
data_buf = calloc(1, data_len);
|
||||
if (data_buf == NULL) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for characteristic value");
|
||||
return BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, data_buf, data_len, &data_buf_len);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "Error getting data from memory buffers");
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
ret = protocomm_req_handle(protoble_internal->pc_ble,
|
||||
uuid128_to_handler(uuid),
|
||||
conn_handle,
|
||||
ctxt->om->om_data,
|
||||
ctxt->om->om_len,
|
||||
data_buf,
|
||||
data_buf_len,
|
||||
&temp_outbuf, &temp_outlen);
|
||||
/* Release the 16 bytes allocated for uuid*/
|
||||
free(uuid);
|
||||
free(data_buf);
|
||||
if (ret == ESP_OK) {
|
||||
|
||||
/* Save data address and length outbuf and outlen internally */
|
||||
|
|
|
@ -28,5 +28,5 @@ endif()
|
|||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
priv_requires ${soc_name}
|
||||
PRIV_REQUIRES ${soc_name}
|
||||
LDFRAGMENTS linker.lf)
|
||||
|
|
285
components/soc/esp32/include/hal/timer_ll.h
Normal file
285
components/soc/esp32/include/hal/timer_ll.h
Normal file
|
@ -0,0 +1,285 @@
|
|||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// The LL layer for Timer Group register operations.
|
||||
// Note that most of the register operations in this layer are non-atomic operations.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "hal/timer_types.h"
|
||||
#include "soc/timer_periph.h"
|
||||
|
||||
//Helper macro to get corresponding interrupt of a timer
|
||||
#define TIMER_LL_GET_INTR(TIMER_IDX) ((TIMER_IDX)==TIMER_0? TIMER_INTR_T0: TIMER_INTR_T1)
|
||||
|
||||
#define TIMER_LL_GET_HW(TIMER_GROUP) ((TIMER_GROUP)==0? &TIMERG0: &TIMERG1)
|
||||
|
||||
_Static_assert(TIMER_INTR_T0 == TIMG_T0_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
|
||||
_Static_assert(TIMER_INTR_T1 == TIMG_T1_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
|
||||
_Static_assert(TIMER_INTR_WDT == TIMG_WDT_INT_CLR, "Add mapping to LL interrupt handling, since it's no longer naturally compatible with the timer_intr_t");
|
||||
|
||||
/**
|
||||
* @brief Enable timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param intr_mask Interrupt enable mask
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_intr_enable(timg_dev_t *hw, timer_intr_t intr_mask)
|
||||
{
|
||||
hw->int_ena.val |= intr_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disable timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param intr_mask Interrupt disable mask
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_intr_disable(timg_dev_t *hw, timer_intr_t intr_mask)
|
||||
{
|
||||
hw->int_ena.val &= (~intr_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get timer interrupt status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @return Masked interrupt status
|
||||
*/
|
||||
static inline timer_intr_t timer_ll_intr_status_get(timg_dev_t *hw)
|
||||
{
|
||||
return hw->int_raw.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clear timer interrupt.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param intr_mask Interrupt mask to clear
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_intr_status_clear(timg_dev_t *hw, timer_intr_t intr_mask)
|
||||
{
|
||||
hw->int_clr_timers.val = intr_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get counter vaule from time-base counter
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param timer_val Pointer to accept the counter value
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_get_counter_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *timer_val)
|
||||
{
|
||||
hw->hw_timer[timer_num].update = 1;
|
||||
*timer_val = ((uint64_t) hw->hw_timer[timer_num].cnt_high << 32) | (hw->hw_timer[timer_num].cnt_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set counter status, enable or disable counter.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param counter_en Counter enable status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_counter_enable(timg_dev_t *hw, timer_idx_t timer_num, timer_start_t counter_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.enable = counter_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get auto reload mode.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param reload Pointer to accept the auto reload mode
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline bool timer_ll_get_auto_reload(timg_dev_t *hw, timer_idx_t timer_num)
|
||||
{
|
||||
return hw->hw_timer[timer_num].config.autoreload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the counter value to trigger the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_value Counter value to trigger the alarm
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t alarm_value)
|
||||
{
|
||||
hw->hw_timer[timer_num].alarm_high = (uint32_t) (alarm_value >> 32);
|
||||
hw->hw_timer[timer_num].alarm_low = (uint32_t) alarm_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the counter value to trigger the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_value Pointer to accept the counter value to trigger the alarm
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_get_alarm_value(timg_dev_t *hw, timer_idx_t timer_num, uint64_t *alarm_value)
|
||||
{
|
||||
*alarm_value = ((uint64_t) hw->hw_timer[timer_num].alarm_high << 32) | (hw->hw_timer[timer_num].alarm_low);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the alarm status, enable or disable the alarm.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_en true to enable, false to disable
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_set_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool alarm_en)
|
||||
{
|
||||
hw->hw_timer[timer_num].config.alarm_en = alarm_en;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the alarm status.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param timer_num The timer number
|
||||
* @param alarm_en Pointer to accept the alarm status
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
static inline void timer_ll_get_alarm_enable(timg_dev_t *hw, timer_idx_t timer_num, bool *alarm_en)
|
||||
{
|
||||
*alarm_en = hw->hw_timer[timer_num].config.alarm_en;
|
||||
}
|
||||
|
||||
/* WDT operations */
|
||||
|
||||
/**
|
||||
* Unlock/lock the WDT register in case of mis-operations.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
* @param protect true to lock, false to unlock before operations.
|
||||
*/
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_set_protect(timg_dev_t* hw, bool protect)
|
||||
{
|
||||
hw->wdt_wprotect=(protect? 0: TIMG_WDT_WKEY_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize WDT.
|
||||
*
|
||||
* @param hw Beginning address of the peripheral registers.
|
||||
*
|
||||
* @note Call ``timer_ll_wdt_set_protect first``
|
||||
*/
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_init(timg_dev_t* hw)
|
||||
{
|
||||
hw->wdt_config0.sys_reset_length=7; //3.2uS
|
||||
hw->wdt_config0.cpu_reset_length=7; //3.2uS
|
||||
//currently only level interrupt is supported
|
||||
hw->wdt_config0.level_int_en = 1;
|
||||
hw->wdt_config0.edge_int_en = 0;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_set_tick(timg_dev_t* hw, int tick_time_us)
|
||||
{
|
||||
hw->wdt_config1.clk_prescale=80*tick_time_us;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_feed(timg_dev_t* hw)
|
||||
{
|
||||
hw->wdt_feed = 1;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout(timg_dev_t* hw, int stage, uint32_t timeout_tick)
|
||||
{
|
||||
switch (stage) {
|
||||
case 0:
|
||||
hw->wdt_config2=timeout_tick;
|
||||
break;
|
||||
case 1:
|
||||
hw->wdt_config3=timeout_tick;
|
||||
break;
|
||||
case 2:
|
||||
hw->wdt_config4=timeout_tick;
|
||||
break;
|
||||
case 3:
|
||||
hw->wdt_config5=timeout_tick;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
_Static_assert(TIMER_WDT_OFF == TIMG_WDT_STG_SEL_OFF, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
|
||||
_Static_assert(TIMER_WDT_INT == TIMG_WDT_STG_SEL_INT, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
|
||||
_Static_assert(TIMER_WDT_RESET_CPU == TIMG_WDT_STG_SEL_RESET_CPU, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
|
||||
_Static_assert(TIMER_WDT_RESET_SYSTEM == TIMG_WDT_STG_SEL_RESET_SYSTEM, "Add mapping to LL watchdog timeout behavior, since it's no longer naturally compatible with the timer_wdt_behavior_t");
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_set_timeout_behavior(timg_dev_t* hw, int stage, timer_wdt_behavior_t behavior)
|
||||
{
|
||||
switch (stage) {
|
||||
case 0:
|
||||
hw->wdt_config0.stg0 = behavior;
|
||||
break;
|
||||
case 1:
|
||||
hw->wdt_config0.stg1 = behavior;
|
||||
break;
|
||||
case 2:
|
||||
hw->wdt_config0.stg2 = behavior;
|
||||
break;
|
||||
case 3:
|
||||
hw->wdt_config0.stg3 = behavior;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_set_enable(timg_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.en = enable;
|
||||
}
|
||||
|
||||
FORCE_INLINE_ATTR void timer_ll_wdt_flashboot_en(timg_dev_t* hw, bool enable)
|
||||
{
|
||||
hw->wdt_config0.flashboot_mod_en = enable;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -73,7 +73,7 @@ extern "C" {
|
|||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_reg_read(reg);
|
||||
|
@ -106,7 +106,7 @@ static inline uint32_t IRAM_ATTR DPORT_REG_READ(uint32_t reg)
|
|||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_sequence_reg_read(reg);
|
||||
|
@ -166,7 +166,7 @@ static inline uint32_t IRAM_ATTR DPORT_SEQUENCE_REG_READ(uint32_t reg)
|
|||
*/
|
||||
static inline uint32_t IRAM_ATTR DPORT_READ_PERI_REG(uint32_t reg)
|
||||
{
|
||||
#if defined(BOOTLOADER_BUILD) || defined(CONFIG_FREERTOS_UNICORE) || !defined(ESP_PLATFORM)
|
||||
#if defined(BOOTLOADER_BUILD) || !defined(CONFIG_ESP32_DPORT_WORKAROUND) || !defined(ESP_PLATFORM)
|
||||
return _DPORT_REG_READ(reg);
|
||||
#else
|
||||
return esp_dport_access_reg_read(reg);
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
|
||||
#define IS_DPORT_REG(_r) (((_r) >= DR_REG_DPORT_BASE) && (_r) <= DR_REG_DPORT_END)
|
||||
|
||||
#if !defined( BOOTLOADER_BUILD ) && !defined( CONFIG_FREERTOS_UNICORE ) && defined( ESP_PLATFORM )
|
||||
#if !defined( BOOTLOADER_BUILD ) && defined( CONFIG_ESP32_DPORT_WORKAROUND ) && defined( ESP_PLATFORM )
|
||||
#define ASSERT_IF_DPORT_REG(_r, OP) TRY_STATIC_ASSERT(!IS_DPORT_REG(_r), (Cannot use OP for DPORT registers use DPORT_##OP));
|
||||
#else
|
||||
#define ASSERT_IF_DPORT_REG(_r, OP)
|
||||
|
|
|
@ -88,14 +88,15 @@ esp_err_t spi_flash_hal_device_config(spi_flash_host_driver_t *driver);
|
|||
esp_err_t spi_flash_hal_common_command(spi_flash_host_driver_t *driver, spi_flash_trans_t *trans);
|
||||
|
||||
/**
|
||||
* Erase whole flash chip.
|
||||
* Erase whole flash chip by using the erase chip (C7h) command.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
*/
|
||||
void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver);
|
||||
|
||||
/**
|
||||
* Erase a specific sector by its start address.
|
||||
* Erase a specific sector by its start address through the sector erase (20h)
|
||||
* command.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
* @param start_address Start address of the sector to erase.
|
||||
|
@ -103,7 +104,8 @@ void spi_flash_hal_erase_chip(spi_flash_host_driver_t *driver);
|
|||
void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_address);
|
||||
|
||||
/**
|
||||
* Erase a specific block by its start address.
|
||||
* Erase a specific 64KB block by its start address through the 64KB block
|
||||
* erase (D8h) command.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
* @param start_address Start address of the block to erase.
|
||||
|
@ -111,7 +113,7 @@ void spi_flash_hal_erase_sector(spi_flash_host_driver_t *driver, uint32_t start_
|
|||
void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_address);
|
||||
|
||||
/**
|
||||
* Program a page of the flash.
|
||||
* Program a page of the flash using the page program (02h) command.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
* @param address Address of the page to program
|
||||
|
@ -121,7 +123,8 @@ void spi_flash_hal_erase_block(spi_flash_host_driver_t *driver, uint32_t start_a
|
|||
void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buffer, uint32_t address, uint32_t length);
|
||||
|
||||
/**
|
||||
* Read from the flash. The read command should be set by ``spi_flash_hal_configure_host_read_mode`` before.
|
||||
* Read from the flash. Call ``spi_flash_hal_configure_host_read_mode`` to
|
||||
* configure the read command before calling this function.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
* @param buffer Buffer to store the read data
|
||||
|
@ -133,7 +136,7 @@ void spi_flash_hal_program_page(spi_flash_host_driver_t *driver, const void *buf
|
|||
esp_err_t spi_flash_hal_read(spi_flash_host_driver_t *driver, void *buffer, uint32_t address, uint32_t read_len);
|
||||
|
||||
/**
|
||||
* Enable or disable the write protection of the flash chip.
|
||||
* @brief Send the write enable (06h) or write disable (04h) command to the flash chip.
|
||||
*
|
||||
* @param driver The driver context.
|
||||
* @param wp true to enable the write protection, otherwise false.
|
||||
|
|
67
components/soc/include/hal/timer_types.h
Normal file
67
components/soc/include/hal/timer_types.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <esp_bit_defs.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Select a hardware timer from timer groups
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_0 = 0, /*!<Select timer0 of GROUPx*/
|
||||
TIMER_1 = 1, /*!<Select timer1 of GROUPx*/
|
||||
TIMER_MAX,
|
||||
} timer_idx_t;
|
||||
|
||||
/**
|
||||
* @brief Decides whether timer is on or paused
|
||||
*/
|
||||
typedef enum {
|
||||
TIMER_PAUSE = 0, /*!<Pause timer counter*/
|
||||
TIMER_START = 1, /*!<Start timer counter*/
|
||||
} timer_start_t;
|
||||
|
||||
/**
|
||||
* @brief Interrupt types of the timer.
|
||||
*/
|
||||
//this is compatible with the value of esp32.
|
||||
typedef enum {
|
||||
TIMER_INTR_T0 = BIT(0), /*!< interrupt of timer 0 */
|
||||
TIMER_INTR_T1 = BIT(1), /*!< interrupt of timer 1 */
|
||||
TIMER_INTR_WDT = BIT(2), /*!< interrupt of watchdog */
|
||||
} timer_intr_t;
|
||||
FLAG_ATTR(timer_intr_t)
|
||||
|
||||
/**
|
||||
* @brief Behavior of the watchdog if a stage times out.
|
||||
*/
|
||||
//this is compatible with the value of esp32.
|
||||
typedef enum {
|
||||
TIMER_WDT_OFF = 0, ///< The stage is turned off
|
||||
TIMER_WDT_INT = 1, ///< The stage will trigger an interrupt
|
||||
TIMER_WDT_RESET_CPU = 2, ///< The stage will reset the CPU
|
||||
TIMER_WDT_RESET_SYSTEM = 3, ///< The stage will reset the whole system
|
||||
} timer_wdt_behavior_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
|
@ -265,23 +265,13 @@ esp_err_t IRAM_ATTR esp_flash_erase_chip(esp_flash_t *chip)
|
|||
{
|
||||
VERIFY_OP(erase_chip);
|
||||
CHECK_WRITE_ADDRESS(chip, 0, chip->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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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``.
|
||||
*
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
|
@ -492,4 +522,3 @@ 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:`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
|
||||
-----
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
const test_select_task_param_t *param = task_param;
|
||||
|
||||
int s = select(param->maxfds, param->rdfds, param->wrfds, param->errfds, param->tv);
|
||||
TEST_ASSERT_EQUAL(param->select_ret, s);
|
||||
|
||||
if (param->sem) {
|
||||
xSemaphoreGive(param->sem);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void inline start_select_task(test_select_task_param_t *param)
|
||||
{
|
||||
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();
|
||||
|
||||
{
|
||||
// Two tasks will wait for the same UART FD for reading and they will time-out
|
||||
|
||||
struct timeval tv = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 100000,
|
||||
};
|
||||
|
||||
fd_set rfds;
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(test_task_param->fd, &rfds);
|
||||
fd_set rdfds1;
|
||||
FD_ZERO(&rdfds1);
|
||||
FD_SET(uart_fd, &rdfds1);
|
||||
|
||||
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);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("concurent selects work", "[vfs]")
|
||||
{
|
||||
struct timeval tv = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = 100000,//irrelevant
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
test_task_param_t test_task_param = {
|
||||
.fd = uart_fd,
|
||||
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(test_task_param.sem);
|
||||
TEST_ASSERT_NOT_NULL(param.sem);
|
||||
|
||||
xTaskCreate(select_task, "select_task", 4*1024, (void *) &test_task_param, 5, NULL);
|
||||
fd_set rdfds2;
|
||||
FD_ZERO(&rdfds2);
|
||||
FD_SET(uart_fd, &rdfds2);
|
||||
FD_SET(socket_fd, &rdfds2);
|
||||
FD_SET(dummy_socket_fd, &rdfds2);
|
||||
|
||||
start_select_task(¶m);
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS); //make sure the task has started and waits in select()
|
||||
|
||||
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);
|
||||
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
|
||||
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS));
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(param.sem, 1000 / portTICK_PERIOD_MS));
|
||||
vSemaphoreDelete(param.sem);
|
||||
}
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(socket_fd, &rfds);
|
||||
{
|
||||
// One tasks waits for UART reading and one for writing. The former will be successful and latter will
|
||||
// time-out.
|
||||
|
||||
test_task_param.fd = dummy_socket_fd;
|
||||
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 wrfds1;
|
||||
FD_ZERO(&wrfds1);
|
||||
FD_SET(uart_fd, &wrfds1);
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(test_task_param.sem, 1000 / portTICK_PERIOD_MS));
|
||||
vSemaphoreDelete(test_task_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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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 unregister_select(uart_select_args_t *args)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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, _readfds_orig)) {
|
||||
FD_SET(uart_num, _readfds);
|
||||
esp_vfs_select_triggered_isr(_select_sem, task_woken);
|
||||
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, _writefds_orig)) {
|
||||
FD_SET(uart_num, _writefds);
|
||||
esp_vfs_select_triggered_isr(_select_sem, task_woken);
|
||||
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, _errorfds_orig)) {
|
||||
FD_SET(uart_num, _errorfds);
|
||||
esp_vfs_select_triggered_isr(_select_sem, task_woken);
|
||||
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);
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
if (_lock_try_acquire(&s_one_select_lock)) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
const int max_fds = MIN(nfds, UART_NUM);
|
||||
*end_select_args = NULL;
|
||||
|
||||
portENTER_CRITICAL(uart_get_selectlock());
|
||||
uart_select_args_t *args = malloc(sizeof(uart_select_args_t));
|
||||
|
||||
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();
|
||||
if (args == NULL) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
_select_sem = select_sem;
|
||||
|
||||
_readfds = readfds;
|
||||
_writefds = writefds;
|
||||
_errorfds = exceptfds;
|
||||
|
||||
*_readfds_orig = *readfds;
|
||||
*_writefds_orig = *writefds;
|
||||
*_errorfds_orig = *exceptfds;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
// s_one_select_lock is not released on successfull exit - will be
|
||||
// released in uart_end_select()
|
||||
|
||||
*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
|
||||
|
|
|
@ -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 ===== */
|
||||
|
|
|
@ -18,6 +18,59 @@
|
|||
#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,
|
||||
|
@ -99,3 +152,4 @@ pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
|
|||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -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;}))
|
||||
|
@ -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"
|
||||
|
|
4
docs/_static/theme_overrides.css
vendored
4
docs/_static/theme_overrides.css
vendored
|
@ -40,3 +40,7 @@ a:hover {
|
|||
.logo {
|
||||
width: 240px !important;
|
||||
}
|
||||
|
||||
a.internal::after{
|
||||
content: ' ';
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue