diff --git a/.gitignore b/.gitignore index 5ec57a167f..2870b4a805 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,8 @@ GPATH examples/*/sdkconfig examples/*/sdkconfig.old examples/*/build + +#Doc build artifacts +docs/_build/ +docs/doxygen-warning-log.txt +docs/xml/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e09b55c44..1352bd6c93 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -118,6 +118,9 @@ build_docs: - build_docs script: - cd docs + - doxygen + # If not building master branch, and there are Doxygen warnings, print them and bail out + - test "${CI_BUILD_REF_NAME}" = "master" || test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false ) - make html artifacts: paths: diff --git a/components/bootloader_support/src/esp_image_format.c b/components/bootloader_support/src/esp_image_format.c index 42a3e4ffe2..ca75f6ae45 100644 --- a/components/bootloader_support/src/esp_image_format.c +++ b/components/bootloader_support/src/esp_image_format.c @@ -17,7 +17,7 @@ #include #include -const static char *TAG = "esp_image"; +static const char *TAG = "esp_image"; #define SIXTEEN_MB 0x1000000 #define ESP_ROM_CHECKSUM_INITIAL 0xEF diff --git a/components/bootloader_support/src/secure_boot_signatures.c b/components/bootloader_support/src/secure_boot_signatures.c index 6d47651b2f..f7e435e86d 100644 --- a/components/bootloader_support/src/secure_boot_signatures.c +++ b/components/bootloader_support/src/secure_boot_signatures.c @@ -45,10 +45,13 @@ esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length) sha_context sha; uint8_t digest[32]; ptrdiff_t keylen; - const uint8_t *data, *digest_data; - uint32_t digest_len; + const uint8_t *data; const signature_block_t *sigblock; bool is_valid; +#ifdef BOOTLOADER_BUILD + const uint8_t *digest_data; + uint32_t digest_len; +#endif ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length); diff --git a/components/bt/component.mk b/components/bt/component.mk index 91620ddc14..d6bde0c5b6 100644 --- a/components/bt/component.mk +++ b/components/bt/component.mk @@ -15,5 +15,4 @@ COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \ ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) $(COMPONENT_LIBRARY): $(ALL_LIB_FILES) -# automatically trigger a git submodule update if BT library is missing -$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib)) +COMPONENT_SUBMODULES += lib diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index f476334b12..d7e0496c55 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -32,13 +32,10 @@ void bt_controller_init(void); /** @brief vhci_host_callback * used for vhci call host function to notify what host need to do - * - * notify_host_send_available: notify host can send packet to controller - * notify_host_recv: notify host that controller has packet send to host */ typedef struct vhci_host_callback { - void (*notify_host_send_available)(void); - int (*notify_host_recv)(uint8_t *data, uint16_t len); + void (*notify_host_send_available)(void); /*!< callback used to notify that the host can send packet to controller */ + int (*notify_host_recv)(uint8_t *data, uint16_t len); /*!< callback used to notify that the controller has a packet to send to the host*/ } vhci_host_callback_t; /** @brief API_vhci_host_check_send_available diff --git a/components/driver/gpio.c b/components/driver/gpio.c index b445d3df03..ddbcb352c0 100644 --- a/components/driver/gpio.c +++ b/components/driver/gpio.c @@ -69,6 +69,74 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = { GPIO_PIN_REG_39 }; +const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]={ + {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M}, + {PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M}, + {PERIPHS_IO_MUX_U0RXD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M}, + {PERIPHS_IO_MUX_GPIO5_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_CLK_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA0_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA1_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA2_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_DATA3_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_SD_CMD_U, FUN_PU, FUN_PD}, + {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M}, + {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M}, + {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M}, + {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M}, + {PERIPHS_IO_MUX_GPIO16_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO17_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO18_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO19_U, FUN_PU, FUN_PD}, + {0,0,0}, + {PERIPHS_IO_MUX_GPIO21_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO22_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO23_U, FUN_PU, FUN_PD}, + {0,0,0}, + {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M}, + {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M}, + {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {0,0,0}, + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M}, + {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M}, + {PERIPHS_IO_MUX_GPIO34_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO35_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO36_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO37_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO38_U, FUN_PU, FUN_PD}, + {PERIPHS_IO_MUX_GPIO39_U, FUN_PU, FUN_PD} +}; + + +esp_err_t gpio_pullup_en(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + return ESP_OK; +} + +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + return ESP_OK; +} + +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + return ESP_OK; +} + +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) { + GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); + return ESP_OK; +} + esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type) { GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); @@ -152,20 +220,20 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull) esp_err_t ret = ESP_OK; switch(pull) { case GPIO_PULLUP_ONLY: - PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); break; case GPIO_PULLDOWN_ONLY: - PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); break; case GPIO_PULLUP_PULLDOWN: - PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); break; case GPIO_FLOATING: - PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]); - PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); + REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd); break; default: ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull); @@ -253,15 +321,15 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig) } if(pGPIOConfig->pull_up_en) { pu_en = 1; - PIN_PULLUP_EN(io_reg); + REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); } else { - PIN_PULLUP_DIS(io_reg); + REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); } if(pGPIOConfig->pull_down_en) { pd_en = 1; - PIN_PULLDWN_EN(io_reg); + REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); } else { - PIN_PULLDWN_DIS(io_reg); + REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd); } ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type); gpio_set_intr_type(io_num, pGPIOConfig->intr_type); diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 73efeaa342..de34ac4e35 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -117,6 +117,32 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT]; #define GPIO_IS_VALID_GPIO(gpio_num) ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0)) //to decide whether it is a valid GPIO number #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode +/** + * @brief Pullup/pulldown information for a single GPIO pad + */ +typedef struct { + uint32_t reg; /*!< Register to modify to enable or disable pullups or pulldowns */ + uint32_t pu; /*!< Bit to set or clear in the above register to enable or disable the pullup, respectively */ + uint32_t pd; /*!< Bit to set or clear in the above register to enable or disable the pulldown, respectively */ +} gpio_pu_pd_desc_t; + + +/** + * Per-GPIO pullup/pulldown information + * On the ESP32, some GPIOs need their pullups and pulldowns enabled and disabled in the RTC + * peripheral instead of in the GPIO peripheral. This array documents for every GPIO what bit + * to set or clear. + * + * This array is non-static, so if you need a very quick way of toggling the pull-up/downs, you can just + * do e.g. REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); inline. + * + * ToDo: Functions using the contents of this array will do a read/modify/write on GPIO as well as RTC + * registers. We may need to look into muxes/locks for other code that accesses these RTC registers when we + * write drivers for the RTC stuff. + */ +extern const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]; + + typedef enum { GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ @@ -185,6 +211,9 @@ typedef enum { GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */ } gpio_pulldown_t; +/** + * @brief Configuration parameters of GPIO pad for gpio_config function + */ typedef struct { uint64_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ gpio_mode_t mode; /*!< GPIO mode: set input/output mode */ @@ -220,7 +249,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig); /** * @brief GPIO set interrupt trigger type * - * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param intr_type Interrupt type, select from gpio_int_type_t * * @return @@ -233,7 +262,7 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** * @brief Enable GPIO module interrupt signal * - * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * * @return * - ESP_OK Success @@ -245,7 +274,7 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); /** * @brief Disable GPIO module interrupt signal * - * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * * @return * - ESP_OK success @@ -257,7 +286,7 @@ esp_err_t gpio_intr_disable(gpio_num_t gpio_num); /** * @brief GPIO set output level * - * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param level Output level. 0: low ; 1: high * * @return @@ -270,7 +299,7 @@ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level); /** * @brief GPIO get input level * - * @param gpio_num GPIO number. If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16); * * @return * - 0 the GPIO input level is 0 @@ -284,7 +313,7 @@ int gpio_get_level(gpio_num_t gpio_num); * * Configure GPIO direction,such as output_only,input_only,output_and_input * - * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param mode GPIO direction * * @return @@ -299,7 +328,7 @@ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); * * User this Function,configure GPIO pull mode,such as pull-up,pull-down * - * @param gpio_num GPIO number. If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16); * @param pull GPIO pull up/down mode. * * @return @@ -314,7 +343,7 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); * * @param gpio_num GPIO number. * - * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL\GPIO_INTR_HIGH_LEVEL can be used. + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used. * * @return * - ESP_OK Success @@ -354,6 +383,53 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); */ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg); + + +/** + * @brief Enable pull-up on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pullup_en(gpio_num_t gpio_num); + +/** + * @brief Disable pull-up on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pullup_dis(gpio_num_t gpio_num); + +/** + * @brief Enable pull-down on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pulldown_en(gpio_num_t gpio_num); + +/** + * @brief Disable pull-down on GPIO. + * + * @param gpio_num GPIO number + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + */ +esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num); + + /** * *************** ATTENTION ********************/ /** diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 3ab0ebff1e..e07787b2b1 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -78,6 +78,9 @@ typedef enum { LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */ } ledc_timer_bit_t; +/** + * @brief Configuration parameters of LEDC channel for ledc_channel_config function + */ typedef struct { int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/ ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ @@ -87,6 +90,9 @@ typedef struct { uint32_t duty; /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */ } ledc_channel_config_t; +/** + * @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function + */ typedef struct { ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ ledc_timer_bit_t bit_num; /*!< LEDC channel duty depth*/ @@ -150,6 +156,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * * @param channel LEDC channel(0-7), select from ledc_channel_t * + * @param idle_level Set output idle level after LEDC stops. + * * @return * - ESP_OK Success * - ESP_ERR_INVALID_ARG Parameter error diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 7dccf1666c..905c288260 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -32,11 +32,11 @@ extern "C" { #include "freertos/ringbuf.h" #include -#define UART_FIFO_LEN (128) /*< Length of the hardware FIFO buffers */ -#define UART_INTR_MASK 0x1ff -#define UART_LINE_INV_MASK (0x3f << 19) -#define UART_BITRATE_MAX 5000000 -#define UART_PIN_NO_CHANGE (-1) +#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */ +#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */ +#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */ +#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */ +#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */ #define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/ #define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/ @@ -44,6 +44,9 @@ extern "C" { #define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/ #define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/ +/** + * @brief UART word length constants + */ typedef enum { UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/ UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/ @@ -52,6 +55,9 @@ typedef enum { UART_DATA_BITS_MAX = 0X4, } uart_word_length_t; +/** + * @brief UART stop bits number + */ typedef enum { UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/ UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/ @@ -59,6 +65,9 @@ typedef enum { UART_STOP_BITS_MAX = 0x4, } uart_stop_bits_t; +/** + * @brief UART peripheral number + */ typedef enum { UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/ UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/ @@ -66,12 +75,18 @@ typedef enum { UART_NUM_MAX, } uart_port_t; +/** + * @brief UART parity constants + */ typedef enum { UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/ - UART_PARITY_EVEN = 0x10, /*!< Enable UART even parity*/ - UART_PARITY_ODD = 0x11 /*!< Enable UART odd parity*/ + UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/ + UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/ } uart_parity_t; +/** + * @brief UART hardware flow control modes + */ typedef enum { UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/ UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/ @@ -80,6 +95,9 @@ typedef enum { UART_HW_FLOWCTRL_MAX = 0x4, } uart_hw_flowcontrol_t; +/** + * @brief UART configuration parameters for uart_param_config function + */ typedef struct { int baud_rate; /*!< UART baudrate*/ uart_word_length_t data_bits; /*!< UART byte size*/ @@ -89,6 +107,9 @@ typedef struct { uint8_t rx_flow_ctrl_thresh ; /*!< UART HW RTS threshold*/ } uart_config_t; +/** + * @brief UART interrupt configuration parameters for uart_intr_config function + */ typedef struct { uint32_t intr_enable_mask; /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/ uint8_t rx_timeout_thresh; /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/ @@ -96,6 +117,9 @@ typedef struct { uint8_t rxfifo_full_thresh; /*!< UART RX full interrupt threshold.*/ } uart_intr_config_t; +/** + * @brief UART event types used in the ringbuffer + */ typedef enum { UART_DATA, /*!< UART data event*/ UART_BREAK, /*!< UART break event*/ @@ -107,17 +131,19 @@ typedef enum { UART_EVENT_MAX, /*!< UART event max index*/ } uart_event_type_t; +/** + * @brief Event structure used in UART event queue + */ typedef struct { uart_event_type_t type; /*!< UART event type */ size_t size; /*!< UART data size for UART_DATA event*/ } uart_event_t; /** - * @brief Set UART data bits. + * @brief Set UART data bits. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param data_bit UART data bits + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param data_bit UART data bits * * @return * - ESP_OK Success @@ -126,9 +152,10 @@ typedef struct { esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit); /** - * @brief Get UART data bits. + * @brief Get UART data bits. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param data_bit Pointer to accept value of UART data bits. * * @return * - ESP_FAIL Parameter error @@ -137,22 +164,22 @@ esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit); /** - * @brief Set UART stop bits. + * @brief Set UART stop bits. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param bit_num UART stop bits + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param bit_num UART stop bits * * @return * - ESP_OK Success * - ESP_FAIL Fail */ -esp_err_t uart_set_stop_bits(uart_port_t uart_no, uart_stop_bits_t bit_num); +esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t bit_num); /** - * @brief Set UART stop bits. + * @brief Set UART stop bits. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param stop_bit Pointer to accept value of UART stop bits. * * @return * - ESP_FAIL Parameter error @@ -161,22 +188,22 @@ esp_err_t uart_set_stop_bits(uart_port_t uart_no, uart_stop_bits_t bit_num); esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit); /** - * @brief Set UART parity. + * @brief Set UART parity. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param parity_mode the enum of uart parity configuration + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param parity_mode the enum of uart parity configuration * * @return * - ESP_FAIL Parameter error * - ESP_OK Success */ -esp_err_t uart_set_parity(uart_port_t uart_no, uart_parity_t parity_mode); +esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode); /** - * @brief Get UART parity mode. + * @brief Get UART parity mode. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param parity_mode Pointer to accept value of UART parity mode. * * @return * - ESP_FAIL Parameter error @@ -186,22 +213,22 @@ esp_err_t uart_set_parity(uart_port_t uart_no, uart_parity_t parity_mode); esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode); /** - * @brief Set UART baud rate. + * @brief Set UART baud rate. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param baud_rate UART baud-rate. + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param baud_rate UART baud-rate. * * @return * - ESP_FAIL Parameter error * - ESP_OK Success */ -esp_err_t uart_set_baudrate(uart_port_t uart_no, uint32_t baud_rate); +esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate); /** - * @brief Get UART bit-rate. + * @brief Get UART bit-rate. * - * @param uart_no: UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param baudrate Pointer to accept value of UART baud rate * * @return * - ESP_FAIL Parameter error @@ -211,41 +238,37 @@ esp_err_t uart_set_baudrate(uart_port_t uart_no, uint32_t baud_rate); esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate); /** - * @brief Set UART line inverse mode + * @brief Set UART line inverse mode * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param inverse_mask Choose the wires that need to be inversed. - * - * (inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR-OPERATION) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param inverse_mask Choose the wires that need to be inversed. + * Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation. * * @return * - ESP_OK Success * - ESP_FAIL Parameter error */ -esp_err_t uart_set_line_inverse(uart_port_t uart_no, uint32_t inverse_mask); +esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask); /** - * @brief Set hardware flow control. + * @brief Set hardware flow control. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param flow_ctrl Hardware flow control mode - * - * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN) - * - * Only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param flow_ctrl Hardware flow control mode + * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN). + * Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set. * * @return * - ESP_OK Success * - ESP_FAIL Parameter error */ -esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_no, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh); +esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh); /** - * @brief Get hardware flow control mode + * @brief Get hardware flow control mode * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param flow_ctrl Option for different flow control mode. * * @return * - ESP_FAIL Parameter error @@ -254,13 +277,11 @@ esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_no, uart_hw_flowcontrol_t flow_ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl); /** - * @brief Clear UART interrupt status + * @brief Clear UART interrupt status * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param clr_mask Bit mask of the status that to be cleared. - * - * (enable_mask should be chosen from the fields of register UART_INT_CLR_REG) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param clr_mask Bit mask of the status that to be cleared. + * enable_mask should be chosen from the fields of register UART_INT_CLR_REG. * * @return * - ESP_OK Success @@ -269,13 +290,11 @@ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flo esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask); /** - * @brief Set UART interrupt enable + * @brief Set UART interrupt enable * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param enable_mask Bit mask of the enable bits. - * - * (enable_mask should be chosen from the fields of register UART_INT_ENA_REG) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param enable_mask Bit mask of the enable bits. + * enable_mask should be chosen from the fields of register UART_INT_ENA_REG. * * @return * - ESP_OK Success @@ -284,13 +303,11 @@ esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask); esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask); /** - * @brief Clear UART interrupt enable bits + * @brief Clear UART interrupt enable bits * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param disable_mask Bit mask of the disable bits. - * - * (disable_mask should be chosen from the fields of register UART_INT_ENA_REG) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param disable_mask Bit mask of the disable bits. + * disable_mask should be chosen from the fields of register UART_INT_ENA_REG. * * @return * - ESP_OK Success @@ -300,9 +317,9 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask); /** - * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * * @return * - ESP_OK Success @@ -311,9 +328,9 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask); esp_err_t uart_enable_rx_intr(uart_port_t uart_num); /** - * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * * @return * - ESP_OK Success @@ -322,9 +339,9 @@ esp_err_t uart_enable_rx_intr(uart_port_t uart_num); esp_err_t uart_disable_rx_intr(uart_port_t uart_num); /** - * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * * @return * - ESP_OK Success @@ -333,13 +350,11 @@ esp_err_t uart_disable_rx_intr(uart_port_t uart_num); esp_err_t uart_disable_tx_intr(uart_port_t uart_num); /** - * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) + * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param enable 1: enable; 0: disable - * - * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param enable 1: enable; 0: disable + * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN * * @return * - ESP_OK Success @@ -348,21 +363,18 @@ esp_err_t uart_disable_tx_intr(uart_port_t uart_num); esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); /** -* @brief register UART interrupt handler(ISR). -* @note - * UART ISR handler will be attached to the same CPU core that this function is running on. - * Users should know that which CPU is running and then pick a INUM that is not used by system. - * We can find the information of INUM and interrupt level in soc.h. + * @brief register UART interrupt handler(ISR). * + * @note UART ISR handler will be attached to the same CPU core that this function is running on. + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now. * - * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details - * - * @param fn Interrupt handler function. - * @attention - * The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now. - * @param arg parameter for handler function + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details + * @param fn Interrupt handler function. + * @param arg parameter for handler function * * @return * - ESP_OK Success @@ -371,21 +383,16 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg); /** - * @brief Set UART pin number + * @brief Set UART pin number * - * @note - * Internal signal can be output to multiple GPIO pads - * Only one GPIO pad can connect with input signal + * @note Internal signal can be output to multiple GPIO pads. + * Only one GPIO pad can connect with input signal. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. - * - * @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. - * - * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. - * - * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param tx_io_num UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * @param rx_io_num UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. + * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin. * * @return * - ESP_OK Success @@ -394,12 +401,11 @@ esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (* esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num); /** - * @brief UART set RTS level (before inverse) + * @brief UART set RTS level (before inverse) * UART rx hardware flow control should not be set. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param level 1: RTS output low(active); 0: RTS output high(block) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param level 1: RTS output low(active); 0: RTS output high(block) * * @return * - ESP_OK Success @@ -408,11 +414,10 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r esp_err_t uart_set_rts(uart_port_t uart_num, int level); /** - * @brief UART set DTR level (before inverse) + * @brief UART set DTR level (before inverse) * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param level 1: DTR output low; 0: DTR output high + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param level 1: DTR output low; 0: DTR output high * * @return * - ESP_OK Success @@ -421,11 +426,10 @@ esp_err_t uart_set_rts(uart_port_t uart_num, int level); esp_err_t uart_set_dtr(uart_port_t uart_num, int level); /** -* @brief UART parameter configure +* @brief UART parameter configure * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param uart_config UART parameter settings + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_config UART parameter settings * * @return * - ESP_OK Success @@ -434,11 +438,10 @@ esp_err_t uart_set_dtr(uart_port_t uart_num, int level); esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config); /** -* @brief UART interrupt configure +* @brief UART interrupt configure * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param intr_conf UART interrupt settings + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param intr_conf UART interrupt settings * * @return * - ESP_OK Success @@ -447,25 +450,19 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf); /** - * @brief Install UART driver. + * @brief Install UART driver. * - * UART ISR handler will be attached to the same CPU core that this function is running on. - * Users should know that which CPU is running and then pick a INUM that is not used by system. - * We can find the information of INUM and interrupt level in soc.h. + * UART ISR handler will be attached to the same CPU core that this function is running on. + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param rx_buffer_size UART RX ring buffer size - * - * @param tx_buffer_size UART TX ring buffer size. - * - * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out.. - * - * @param queue_size UART event queue size/depth. - * - * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details - * - * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue. + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param rx_buffer_size UART RX ring buffer size + * @param tx_buffer_size UART TX ring buffer size. + * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out.. + * @param queue_size UART event queue size/depth. + * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details + * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue. * * @return * - ESP_OK Success @@ -474,9 +471,9 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue); /** - * @brief Uninstall UART driver. + * @brief Uninstall UART driver. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * * @return * - ESP_OK Success @@ -485,11 +482,10 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b esp_err_t uart_driver_delete(uart_port_t uart_num); /** - * @brief Wait UART TX FIFO empty + * @brief Wait UART TX FIFO empty * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param ticks_to_wait Timeout, count in RTOS ticks + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param ticks_to_wait Timeout, count in RTOS ticks * * @return * - ESP_OK Success @@ -499,38 +495,33 @@ esp_err_t uart_driver_delete(uart_port_t uart_num); esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait); /** - * @brief Send data to the UART port from a given buffer and length, - * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full. - * @note - * This function should only be used when UART TX buffer is not enabled. + * @brief Send data to the UART port from a given buffer and length. + * + * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full. + * @note This function should only be used when UART TX buffer is not enabled. * - * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param buffer data buffer address - * - * @param len data length to send + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param buffer data buffer address + * @param len data length to send * * @return * - (-1) Parameter error * - OTHERS(>=0) The number of data that pushed to the TX FIFO */ -int uart_tx_chars(uart_port_t uart_no, const char* buffer, uint32_t len); +int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len); /** - * @brief Send data to the UART port from a given buffer and length, + * @brief Send data to the UART port from a given buffer and length, * - * If parameter tx_buffer_size is set to zero: - * This function will not return until all the data have been sent out, or at least pushed into TX FIFO. + * If parameter tx_buffer_size is set to zero: + * This function will not return until all the data have been sent out, or at least pushed into TX FIFO. * - * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, - * then, UART ISR will move data from ring buffer to TX FIFO gradually. + * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, + * then, UART ISR will move data from ring buffer to TX FIFO gradually. * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param src data buffer address - * - * @param size data length to send + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param src data buffer address + * @param size data length to send * * @return * - (-1) Parameter error @@ -539,25 +530,20 @@ int uart_tx_chars(uart_port_t uart_no, const char* buffer, uint32_t len); int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size); /** - * @brief Send data to the UART port from a given buffer and length, + * @brief Send data to the UART port from a given buffer and length, * - * If parameter tx_buffer_size is set to zero: - * This function will not return until all the data and the break signal have been sent out. - * After all data send out, send a break signal. + * If parameter tx_buffer_size is set to zero: + * This function will not return until all the data and the break signal have been sent out. + * After all data send out, send a break signal. * - * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, - * then, UART ISR will move data from ring buffer to TX FIFO gradually. - * After all data send out, send a break signal. + * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer, + * then, UART ISR will move data from ring buffer to TX FIFO gradually. + * After all data send out, send a break signal. * - * - * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param src data buffer address - * - * @param size data length to send - * - * @param brk_len break signal length (unit: one bit's time@current_baudrate) + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param src data buffer address + * @param size data length to send + * @param brk_len break signal length (unit: time of one data bit at current_baudrate) * * @return * - (-1) Parameter error @@ -567,16 +553,12 @@ int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size); int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len); /** -* @brief UART read bytes from UART buffer - * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @param buf pointer to the buffer. - * - * @param length data length - * - * @param ticks_to_wait sTimeout, count in RTOS ticks + * @brief UART read bytes from UART buffer * + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param buf pointer to the buffer. + * @param length data length + * @param ticks_to_wait sTimeout, count in RTOS ticks * * @return * - (-1) Error @@ -585,9 +567,9 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait); /** - * @brief UART ring buffer flush + * @brief UART ring buffer flush * - * @param uart_no UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 * * @return * - ESP_OK Success @@ -686,13 +668,14 @@ esp_err_t uart_flush(uart_port_t uart_num); * { * int uart_num = (int)pvParameters; * uart_event_t event; - * uint8_t dtmp[1000]; + * size_t size = 1024; + * uint8_t* dtmp = (uint8_t*)malloc(size); * for(;;) { * //Waiting for UART event. * if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { * ESP_LOGI(TAG, "uart[%d] event:", uart_num); * switch(event.type) { - * memset(dtmp, 0, sizeof(dtmp)); + * memset(dtmp, 0, size); * //Event of UART receving data * case UART_DATA: * ESP_LOGI(TAG,"data, len: %d", event.size); @@ -727,6 +710,8 @@ esp_err_t uart_flush(uart_port_t uart_num); * } * } * } + * free(dtmp); + * dtmp = NULL; * vTaskDelete(NULL); * } * @@ -744,13 +729,13 @@ esp_err_t uart_flush(uart_port_t uart_num); * //Set UART parameters * uart_param_config(uart_num, &uart_config); * //Set UART pins,(-1: default pin, no change.) - * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13); + * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); * //Set UART log level * esp_log_level_set(TAG, ESP_LOG_INFO); * //Install UART driver, and get the queue. - * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue, RINGBUF_TYPE_BYTEBUF); + * uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue); * //Create a task to handler UART event from ISR - * xTaskCreate(uart_task, "uTask", 2048*8, (void*)uart_num, 10, NULL); + * xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL); * } * @endcode * diff --git a/components/driver/uart.c b/components/driver/uart.c index d9e3fd64ca..02610e7b49 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -23,11 +23,9 @@ #include "freertos/task.h" #include "freertos/ringbuf.h" #include "soc/dport_reg.h" -#include "rom/ets_sys.h" #include "soc/uart_struct.h" #include "driver/uart.h" #include "driver/gpio.h" -#include "soc/uart_struct.h" static const char* UART_TAG = "UART"; #define UART_CHECK(a, str, ret) if (!(a)) { \ @@ -458,17 +456,20 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) uart_reg->int_clr.txfifo_empty = 1; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); if(p_uart->tx_waiting_brk) { - return; + continue; } //TX semaphore will only be used when tx_buf_size is zero. if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { p_uart->tx_waiting_fifo = false; - xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, NULL); + xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } } else { - //We don't use TX ring buffer, because the size if zero. + //We don't use TX ring buffer, because the size is zero. if(p_uart->tx_buf_size == 0) { - return; + continue; } int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt; bool en_tx_flg = false; @@ -492,6 +493,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) } //We have saved the data description from the 1st item, return buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } }else if(p_uart->tx_ptr == NULL) { //Update the TX item pointer, we will need this to return item to buffer. p_uart->tx_ptr = (uint8_t*) p_uart->tx_head; @@ -501,7 +505,7 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) } else { //Can not get data from ring buffer, return; - return; + break; } } if(p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) { @@ -516,6 +520,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) if(p_uart->tx_len_cur == 0) { //Return item to ring buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } p_uart->tx_head = NULL; p_uart->tx_ptr = NULL; //Sending item done, now we need to send break if there is a record. @@ -529,7 +536,6 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) uart_reg->int_ena.tx_brk_done = 1; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); p_uart->tx_waiting_brk = 1; - return; } else { //enable TX empty interrupt en_tx_flg = true; @@ -576,6 +582,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) } else { uart_event.type = UART_DATA; } + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } } else { UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); uart_reg->int_ena.rxfifo_full = 0; @@ -594,10 +603,10 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) } else if(uart_intr_status & UART_BRK_DET_INT_ST_M) { uart_reg->int_clr.brk_det = 1; uart_event.type = UART_BREAK; - } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) { + } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M ) { uart_reg->int_clr.parity_err = 1; uart_event.type = UART_FRAME_ERR; - } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M) { + } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) { uart_reg->int_clr.frm_err = 1; uart_event.type = UART_PARITY_ERR; } else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) { @@ -614,6 +623,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) p_uart->tx_waiting_brk = 0; } else { xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } } } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) { UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); @@ -626,6 +638,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) uart_reg->int_clr.tx_done = 1; UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } } else { uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/ @@ -634,6 +649,9 @@ static void IRAM_ATTR uart_rx_intr_handler_default(void *param) if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) { xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken); + if(HPTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR() ; + } } uart_intr_status = uart_reg->int_st.val; } @@ -946,7 +964,8 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b | UART_RXFIFO_TOUT_INT_ENA_M | UART_FRM_ERR_INT_ENA_M | UART_RXFIFO_OVF_INT_ENA_M - | UART_BRK_DET_INT_ENA_M, + | UART_BRK_DET_INT_ENA_M + | UART_PARITY_ERR_INT_ENA_M, .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT, .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT, .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 1f04cf4bb7..206ea669e1 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -364,4 +364,43 @@ config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL depends on DOCUMENTATION_FOR_RTC_CNTL endchoice + +config ESP32_PHY_AUTO_INIT + bool "Initialize PHY in startup code" + default y + help + If enabled, PHY will be initialized in startup code, before + app_main function runs. + If this is undesired, disable this option and call esp_phy_init + from the application before enabling WiFi or BT. + + If this option is enabled, startup code will also initialize + NVS prior to initializing PHY. + + If unsure, choose 'y'. + +config ESP32_PHY_INIT_DATA_IN_PARTITION + bool "Use a partition to store PHY init data" + default n + help + If enabled, PHY init data will be loaded from a partition. + When using a custom partition table, make sure that PHY data + partition is included (type: 'data', subtype: 'phy'). + With default partition tables, this is done automatically. + If PHY init data is stored in a partition, it has to be flashed there, + otherwise runtime error will occur. + + If this option is not enabled, PHY init data will be embedded + into the application binary. + + If unsure, choose 'n'. + +config ESP32_PHY_MAX_TX_POWER + int "Max TX power (dBm)" + range 0 20 + default 20 + help + Set maximum transmit power. Actual transmit power for high + data rates may be lower than this setting. + endmenu diff --git a/components/esp32/Makefile.projbuild b/components/esp32/Makefile.projbuild new file mode 100644 index 0000000000..01f8d03c5a --- /dev/null +++ b/components/esp32/Makefile.projbuild @@ -0,0 +1,32 @@ +ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION + +PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o +PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin + +# Command to flash PHY init data partition +PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) +ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN) + +ESP32_COMPONENT_PATH := $(COMPONENT_PATH) + +$(PHY_INIT_DATA_OBJ): $(ESP32_COMPONENT_PATH)/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h + $(summary) CC $(notdir $@) + printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP32_COMPONENT_PATH) -I $(ESP32_COMPONENT_PATH)/include -c -o $@ -xc - + +$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ) + $(summary) BIN $(notdir $@) + $(OBJCOPY) -O binary $< $@ + +phy_init_data: $(PHY_INIT_DATA_BIN) + +phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin + @echo "Flashing PHY init data..." + $(PHY_INIT_DATA_FLASH_CMD) + +phy_init_data-clean: + rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ) + +all: phy_init_data +flash: phy_init_data + +endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION diff --git a/components/esp32/component.mk b/components/esp32/component.mk index 040c686e5e..8059d157c5 100644 --- a/components/esp32/component.mk +++ b/components/esp32/component.mk @@ -17,9 +17,7 @@ COMPONENT_ADD_LDFLAGS := -lesp32 \ ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) -# automatically trigger a git submodule update -# if any libraries are missing -$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib)) +COMPONENT_SUBMODULES += lib # this is a hack to make sure the app is re-linked if the binary # libraries change or are updated. If they change, the main esp32 diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index a96fdee950..1eb0a5355e 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -50,6 +50,7 @@ #include "esp_brownout.h" #include "esp_int_wdt.h" #include "esp_task_wdt.h" +#include "esp_phy_init.h" #include "trax.h" void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); @@ -62,6 +63,7 @@ static bool app_cpu_started = false; #endif //!CONFIG_FREERTOS_UNICORE static void do_global_ctors(void); +static void do_phy_init(); static void main_task(void* args); extern void app_main(void); @@ -187,6 +189,11 @@ void start_cpu0_default(void) esp_ipc_init(); spi_flash_init(); +#if CONFIG_ESP32_PHY_AUTO_INIT + nvs_flash_init(); + do_phy_init(); +#endif + xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); @@ -224,3 +231,36 @@ static void main_task(void* args) vTaskDelete(NULL); } +static void do_phy_init() +{ + esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; + if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { + calibration_mode = PHY_RF_CAL_NONE; + } + const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); + if (init_data == NULL) { + ESP_LOGE(TAG, "failed to obtain PHY init data"); + abort(); + } + esp_phy_calibration_data_t* cal_data = + (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); + if (cal_data == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); + abort(); + } + esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); + if (err != ESP_OK) { + ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + calibration_mode = PHY_RF_CAL_FULL; + } + + esp_phy_init(init_data, calibration_mode, cal_data); + + if (calibration_mode != PHY_RF_CAL_NONE) { + err = esp_phy_store_cal_data_to_nvs(cal_data); + } else { + err = ESP_OK; + } + esp_phy_release_init_data(init_data); + free(cal_data); // PHY maintains a copy of calibration data, so we can free this +} diff --git a/components/esp32/freertos_hooks.c b/components/esp32/freertos_hooks.c new file mode 100644 index 0000000000..d59a20363d --- /dev/null +++ b/components/esp32/freertos_hooks.c @@ -0,0 +1,96 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + + +#include +#include +#include +#include "esp_attr.h" +#include "esp_freertos_hooks.h" + +//We use just a static array here because it's not expected many components will need +//an idle or tick hook. +#define MAX_HOOKS 8 + +static esp_freertos_idle_cb_t idle_cb[MAX_HOOKS]={0}; +static esp_freertos_tick_cb_t tick_cb[MAX_HOOKS]={0}; + +void IRAM_ATTR esp_vApplicationTickHook() +{ + int n; + for (n=0; n +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + Definitions for the tickhook and idlehook callbacks +*/ +typedef bool (*esp_freertos_idle_cb_t)(); +typedef void (*esp_freertos_tick_cb_t)(); + +/** + * @brief Register a callback to be called on the freertos idle hook + * The callback should return true if it's okay for the core to + * sleep until an interrupt (or FreeRTOS tick) happens and false + * if it should be called again as fast as possible. + * + * @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL + * A FUNCTION THAT MIGHT BLOCK. + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be called + * + * @return ESP_OK : Callback registered + * @return ESP_ERR_NO_MEM : No more space to register hook + */ +esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb); + +/** + * @brief Register a callback to be called on the freertos tick hook + * + * @param esp_freertos_tick_cb_t new_tick_cb : Callback to be called + * + * @return ESP_OK : Callback registered + * @return ESP_ERR_NO_MEM : No more space to register hook + */ +esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t tick_cb); + + +/** + * @brief Unregister an idle callback registered earlier + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered + * + * @return void + */ +void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb); + + +/** + * @brief Unregister a tick callback registered earlier + * + * @param esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered + * + * @return void + */ +void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb); + +#ifdef __cplusplus +} +#endif + + +#endif \ No newline at end of file diff --git a/components/esp32/include/esp_int_wdt.h b/components/esp32/include/esp_int_wdt.h index 4387400396..b32d0219fb 100644 --- a/components/esp32/include/esp_int_wdt.h +++ b/components/esp32/include/esp_int_wdt.h @@ -41,9 +41,6 @@ This uses the TIMERG1 WDT. * @brief Initialize the interrupt watchdog. This is called in the init code if * the interrupt watchdog is enabled in menuconfig. * - * @param null - * - * @return null */ void esp_int_wdt_init(); diff --git a/components/esp32/include/esp_phy_init.h b/components/esp32/include/esp_phy_init.h new file mode 100644 index 0000000000..7bc0536103 --- /dev/null +++ b/components/esp32/include/esp_phy_init.h @@ -0,0 +1,249 @@ +// Copyright 2015-2016 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 +#include +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file PHY init parameters and API + */ + + +/** + * @brief Structure holding PHY init parameters + */ +typedef struct { + uint8_t param_ver_id; /*!< init_data structure version */ + uint8_t crystal_select; /*!< 0: 40MHz, 1: 26 MHz, 2: 24 MHz, 3: auto */ + uint8_t wifi_rx_gain_swp_step_1; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_2; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_3; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_4; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_5; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_6; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_7; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_8; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_9; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_10; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_11; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_12; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_13; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_14; /*!< do not change */ + uint8_t wifi_rx_gain_swp_step_15; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_1; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_2; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_3; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_4; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_5; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_6; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_7; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_8; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_9; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_10; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_11; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_12; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_13; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_14; /*!< do not change */ + uint8_t bt_rx_gain_swp_step_15; /*!< do not change */ + uint8_t gain_cmp_1; /*!< do not change */ + uint8_t gain_cmp_6; /*!< do not change */ + uint8_t gain_cmp_11; /*!< do not change */ + uint8_t gain_cmp_ext2_1; /*!< do not change */ + uint8_t gain_cmp_ext2_6; /*!< do not change */ + uint8_t gain_cmp_ext2_11; /*!< do not change */ + uint8_t gain_cmp_ext3_1; /*!< do not change */ + uint8_t gain_cmp_ext3_6; /*!< do not change */ + uint8_t gain_cmp_ext3_11; /*!< do not change */ + uint8_t gain_cmp_bt_ofs_1; /*!< do not change */ + uint8_t gain_cmp_bt_ofs_6; /*!< do not change */ + uint8_t gain_cmp_bt_ofs_11; /*!< do not change */ + uint8_t target_power_qdb_0; /*!< 78 means target power is 78/4=19.5dbm */ + uint8_t target_power_qdb_1; /*!< 76 means target power is 76/4=19dbm */ + uint8_t target_power_qdb_2; /*!< 74 means target power is 74/4=18.5dbm */ + uint8_t target_power_qdb_3; /*!< 68 means target power is 68/4=17dbm */ + uint8_t target_power_qdb_4; /*!< 64 means target power is 64/4=16dbm */ + uint8_t target_power_qdb_5; /*!< 52 means target power is 52/4=13dbm */ + uint8_t target_power_index_mcs0; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (1m,2m,5.5m,11m,6m,9m) */ + uint8_t target_power_index_mcs1; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (12m) */ + uint8_t target_power_index_mcs2; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (18m) */ + uint8_t target_power_index_mcs3; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (24m) */ + uint8_t target_power_index_mcs4; /*!< target power index is 2, means target power is target_power_qdb_2 18.5dbm; (36m) */ + uint8_t target_power_index_mcs5; /*!< target power index is 3, means target power is target_power_qdb_3 17dbm; (48m) */ + uint8_t target_power_index_mcs6; /*!< target power index is 4, means target power is target_power_qdb_4 16dbm; (54m) */ + uint8_t target_power_index_mcs7; /*!< target power index is 5, means target power is target_power_qdb_5 13dbm */ + uint8_t pwr_ind_11b_en; /*!< 0: 11b power is same as mcs0 and 6m, 1: 11b power different with OFDM */ + uint8_t pwr_ind_11b_0; /*!< 1m, 2m power index [0~5] */ + uint8_t pwr_ind_11b_1; /*!< 5.5m, 11m power index [0~5] */ + uint8_t chan_backoff_en; /*!< 0: channel backoff disable, 1:channel backoff enable */ + uint8_t chan1_power_backoff_qdb; /*!< 4 means backoff is 1db */ + uint8_t chan2_power_backoff_qdb; /*!< see chan1_power_backoff_qdb */ + uint8_t chan3_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan4_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan5_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan6_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan7_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan8_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan9_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan10_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan11_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan12_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan13_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan14_power_backoff_qdb; /*!< chan1_power_backoff_qdb */ + uint8_t chan1_rate_backoff_index; /*!< if bit i is set, backoff data rate is target_power_qdb_i */ + uint8_t chan2_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan3_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan4_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan5_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan6_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan7_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan8_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan9_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan10_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan11_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan12_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan13_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t chan14_rate_backoff_index; /*!< see chan1_rate_backoff_index */ + uint8_t spur_freq_cfg_msb_1; /*!< first spur: */ + uint8_t spur_freq_cfg_1; /*!< spur_freq_cfg = (spur_freq_cfg_msb_1 <<8) | spur_freq_cfg_1 */ + uint8_t spur_freq_cfg_div_1; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_1 */ + uint8_t spur_freq_en_h_1; /*!< the seventh bit for total enable */ + uint8_t spur_freq_en_l_1; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */ + uint8_t spur_freq_cfg_msb_2; /*!< second spur: */ + uint8_t spur_freq_cfg_2; /*!< spur_freq_cfg = (spur_freq_cfg_msb_2 <<8) | spur_freq_cfg_2 */ + uint8_t spur_freq_cfg_div_2; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_2 */ + uint8_t spur_freq_en_h_2; /*!< the seventh bit for total enable */ + uint8_t spur_freq_en_l_2; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */ + uint8_t spur_freq_cfg_msb_3; /*!< third spur: */ + uint8_t spur_freq_cfg_3; /*!< spur_freq_cfg = (spur_freq_cfg_msb_3 <<8) | spur_freq_cfg_3 */ + uint8_t spur_freq_cfg_div_3; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_3 */ + uint8_t spur_freq_en_h_3; /*!< the seventh bit for total enable */ + uint8_t spur_freq_en_l_3; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority, */ + uint8_t reserved[23]; /*!< reserved for future expansion */ +} esp_phy_init_data_t; + +/** + * @brief Opaque PHY calibration data + */ +typedef struct { + uint8_t opaque[1904]; /*!< calibration data */ +} esp_phy_calibration_data_t; + +typedef enum { + PHY_RF_CAL_PARTIAL = 0x00000000, /*!< Do part of RF calibration. This should be used after power-on reset. */ + PHY_RF_CAL_NONE = 0x00000001, /*!< Don't do any RF calibration. This mode is only suggested to be used after deep sleep reset. */ + PHY_RF_CAL_FULL = 0x00000002 /*!< Do full RF calibration. Produces best results, but also consumes a lot of time and current. Suggested to be used once. */ +} esp_phy_calibration_mode_t; + +/** + * @brief Get PHY init data + * + * If "Use a partition to store PHY init data" option is set in menuconfig, + * This function will load PHY init data from a partition. Otherwise, + * PHY init data will be compiled into the application itself, and this function + * will return a pointer to PHY init data located in read-only memory (DROM). + * + * If "Use a partition to store PHY init data" option is enabled, this function + * may return NULL if the data loaded from flash is not valid. + * + * @note Call esp_phy_release_init_data to release the pointer obtained using + * this function after the call to esp_wifi_init. + * + * @return pointer to PHY init data structure + */ +const esp_phy_init_data_t* esp_phy_get_init_data(); + +/** + * @brief Release PHY init data + * @param data pointer to PHY init data structure obtained from + * esp_phy_get_init_data function + */ +void esp_phy_release_init_data(const esp_phy_init_data_t* data); + +/** + * @brief Function called by esp_phy_init to load PHY calibration data + * + * This is a convenience function which can be used to load PHY calibration + * data from NVS. Data can be stored to NVS using esp_phy_store_cal_data_to_nvs + * function. + * + * If calibration data is not present in the NVS, or + * data is not valid (was obtained for a chip with a different MAC address, + * or obtained for a different version of software), this function will + * return an error. + * + * If "Initialize PHY in startup code" option is set in menuconfig, this + * function will be used to load calibration data. To provide a different + * mechanism for loading calibration data, disable + * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init + * function from the application. For an example usage of esp_phy_init and + * this function, see do_phy_init function in cpu_start.c + * + * @param out_cal_data pointer to calibration data structure to be filled with + * loaded data. + * @return ESP_OK on success + */ +esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data); + +/** + * @brief Function called by esp_phy_init to store PHY calibration data + * + * This is a convenience function which can be used to store PHY calibration + * data to the NVS. Calibration data is returned by esp_phy_init function. + * Data saved using this function to the NVS can later be loaded using + * esp_phy_store_cal_data_to_nvs function. + * + * If "Initialize PHY in startup code" option is set in menuconfig, this + * function will be used to store calibration data. To provide a different + * mechanism for storing calibration data, disable + * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init + * function from the application. + * + * @param cal_data pointer to calibration data which has to be saved. + * @return ESP_OK on success + */ +esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data); + +/** + * @brief Initialize PHY module + * + * PHY module should be initialized in order to use WiFi or BT. + * If "Initialize PHY in startup code" option is set in menuconfig, + * this function will be called automatically before app_main is called, + * using parameters obtained from esp_phy_get_init_data. + * + * Applications which don't need to enable PHY on every start up should + * disable this menuconfig option and call esp_phy_init before calling + * esp_wifi_init or bt_controller_init. See do_phy_init function in + * cpu_start.c for an example of using this function. + * + * @param init_data PHY parameters. Default set of parameters can + * be obtained by calling esp_phy_get_default_init_data + * function. + * @param mode Calibration mode (Full, partial, or no calibration) + * @param[inout] calibration_data + * @return ESP_OK on success. + */ +esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data); + + +#ifdef __cplusplus +} +#endif + diff --git a/components/esp32/include/esp_task_wdt.h b/components/esp32/include/esp_task_wdt.h index bbc4995674..eb77377009 100644 --- a/components/esp32/include/esp_task_wdt.h +++ b/components/esp32/include/esp_task_wdt.h @@ -42,9 +42,6 @@ This uses the TIMERG0 WDT. * @brief Initialize the task watchdog. This is called in the init code, if the * task watchdog is enabled in menuconfig. * - * @param null - * - * @return null */ void esp_task_wdt_init(); @@ -52,9 +49,6 @@ void esp_task_wdt_init(); * @brief Feed the watchdog. After the first feeding session, the watchdog will expect the calling * task to keep feeding the watchdog until task_wdt_delete() is called. * - * @param null - * - * @return null */ void esp_task_wdt_feed(); @@ -63,9 +57,6 @@ void esp_task_wdt_feed(); /** * @brief Delete the watchdog for the current task. * - * @param null - * - * @return null */ void esp_task_wdt_delete(); diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 88ea0d9a65..65a91929dd 100644 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -88,6 +88,9 @@ extern "C" { #define ESP_ERR_WIFI_PASSWORD (ESP_ERR_WIFI_BASE + 10) /*!< Passord is invalid */ #define ESP_ERR_WIFI_TIMEOUT (ESP_ERR_WIFI_BASE + 11) /*!< Timeout error */ +/** + * @brief WiFi stack configuration parameters passed to esp_wifi_init call. + */ typedef struct { system_event_handler_t event_handler; /**< WiFi event handler */ } wifi_init_config_t; @@ -108,12 +111,12 @@ typedef struct { * will post station connected event to this queue. If the queue is not initialized, WiFi * will not post any events * - * @param wifi_init_config_t *config : provide WiFi init configuration + * @param config provide WiFi init configuration * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NO_MEM : out of memory - * - others : refer to error code esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NO_MEM: out of memory + * - others: refer to error code esp_err.h */ esp_err_t esp_wifi_init(wifi_init_config_t *config); @@ -123,7 +126,7 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config); * * @attention 1. This API should be called if you want to remove WiFi driver from the system * - * @return ESP_OK : succeed + * @return ESP_OK: succeed */ esp_err_t esp_wifi_deinit(void); @@ -133,25 +136,25 @@ esp_err_t esp_wifi_deinit(void); * Set the WiFi operating mode as station, soft-AP or station+soft-AP, * The default mode is soft-AP mode. * - * @param wifi_mode_t mode : WiFi operating modes: + * @param mode WiFi operating mode * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - others: refer to error code in esp_err.h */ esp_err_t esp_wifi_set_mode(wifi_mode_t mode); /** * @brief Get current operating mode of WiFi * - * @param wifi_mode_t *mode : store current WiFi mode + * @param[out] mode store current WiFi mode * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); @@ -161,29 +164,25 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode); * If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP * If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station * - * @param null - * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_NO_MEM : out of memory - * - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong - * - ESP_ERR_WIFI_FAIL : other WiFi internal errors + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_NO_MEM: out of memory + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_FAIL: other WiFi internal errors */ esp_err_t esp_wifi_start(void); /** * @brief Stop WiFi - If mode is WIFI_MODE_STA, it stop station and free station control block + * If mode is WIFI_MODE_STA, it stop station and free station control block * If mode is WIFI_MODE_AP, it stop soft-AP and free soft-AP control block * If mode is WIFI_MODE_APSTA, it stop station/soft-AP and free station/soft-AP control block * - * @param null - * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_stop(void); @@ -193,52 +192,47 @@ esp_err_t esp_wifi_stop(void); * @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode * @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect. * - * @param null - * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong - * - ESP_ERR_WIFI_SSID : SSID of AP which station connects is invalid + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong + * - ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid */ esp_err_t esp_wifi_connect(void); /** * @brief Disconnect the ESP32 WiFi station from the AP. * - * @param null - * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_FAIL : other WiFi internal errors + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_FAIL: other WiFi internal errors */ esp_err_t esp_wifi_disconnect(void); /** * @brief Currently this API is just an stub API * - * @param null - * + * @return - * - ESP_OK : succeed - * - others : fail + * - ESP_OK: succeed + * - others: fail */ esp_err_t esp_wifi_clear_fast_connect(void); /** * @brief deauthenticate all stations or associated id equals to aid * - * @param uint16_t aid : when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid + * @param aid when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_MODE : WiFi mode is wrong + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong */ esp_err_t esp_wifi_deauth_sta(uint16_t aid); @@ -249,88 +243,87 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid); * will be freed in esp_wifi_get_ap_list, so generally, call esp_wifi_get_ap_list to cause * the memory to be freed once the scan is done * - * @param struct scan_config *config : configuration of scanning - * @param bool block : if block is true, this API will block the caller until the scan is done, otherwise + * @param config configuration of scanning + * @param block if block is true, this API will block the caller until the scan is done, otherwise * it will return immediately * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_TIMEOUT : blocking scan is timeout - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout + * - others: refer to error code in esp_err.h */ -esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block); +esp_err_t esp_wifi_scan_start(wifi_scan_config_t *config, bool block); /** * @brief Stop the scan in process * - * @param null * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start */ esp_err_t esp_wifi_scan_stop(void); /** * @brief Get number of APs found in last scan * - * @param uint16_t *number : store number of APIs found in last scan + * @param[out] number store number of APIs found in last scan * - * @attention This API can only be called when the scan is completed, otherwise it may get wrong value + * @attention This API can only be called when the scan is completed, otherwise it may get wrong value. * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number); /** * @brief Get AP list found in last scan * - * @param uint16_t *number : as input param, it stores max AP number ap_records can hold, as output param, it store - the actual AP number this API returns - * @param wifi_ap_record_t *ap_records: wifi_ap_record_t array to hold the found APs + * @param[inout] number As input param, it stores max AP number ap_records can hold. + * As output param, it receives the actual AP number this API returns. + * @param ap_records wifi_ap_record_t array to hold the found APs * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_NO_MEM : out of memory + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_NO_MEM: out of memory */ esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records); /** - * @brief Get information of AP associated with ESP32 station + * @brief Get information of AP which the ESP32 station is associated with * - * @param wifi_ap_record_t *ap_info: the wifi_ap_record_t to hold station assocated AP + * @param ap_info the wifi_ap_record_t to hold AP information * * @return - * - ESP_OK : succeed - * - others : fail + * - ESP_OK: succeed + * - others: fail */ esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info); /** * @brief Set current power save type * - * @param wifi_ps_type_t type : power save type + * @param type power save type * - * @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet + * @return ESP_ERR_WIFI_NOT_SUPPORT: not supported yet */ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type); /** * @brief Get current power save type * - * @param wifi_ps_type_t *type : store current power save type + * @param[out] type: store current power save type * - * @return ESP_ERR_WIFI_NOT_SUPPORT : not support yet + * @return ESP_ERR_WIFI_NOT_SUPPORT: not supported yet */ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); @@ -340,47 +333,47 @@ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type); * * @attention Currently we only support 802.11b or 802.11bg or 802.11bgn mode * - * @param wifi_interface_t ifx : interfaces - * @param uint8_t protocol : WiFi protocol bitmap + * @param ifx interfaces + * @param protocol_bitmap WiFi protocol bitmap * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF : invalid interface - * - others : refer to erro code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - others: refer to error codes in esp_err.h */ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap); /** - * @brief Get the current protocol bitmap of specified ifx + * @brief Get the current protocol bitmap of the specified interface * - * @param wifi_interface_t ifx : interfaces - * @param uint8_t protocol : store current WiFi protocol bitmap of interface ifx + * @param ifx interface + * @param[out] protocol_bitmap store current WiFi protocol bitmap of interface ifx * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_ARG : invalid argument - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_ARG: invalid argument + * - others: refer to error codes in esp_err.h */ esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap); /** * @brief Set the bandwidth of ESP32 specified interface * - * @attention 1. API return false if try to configure a interface that is not enable + * @attention 1. API return false if try to configure an interface that is not enabled * @attention 2. WIFI_BW_HT40 is supported only when the interface support 11N * - * @param wifi_interface_t ifx : interface to be configured - * @param wifi_bandwidth_t bw : bandwidth + * @param ifx interface to be configured + * @param bw bandwidth * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_ARG : invalid argument - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_ARG: invalid argument + * - others: refer to error codes in esp_err.h */ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); @@ -389,45 +382,45 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw); * * @attention 1. API return false if try to get a interface that is not enable * - * @param wifi_interface_t ifx : interface to be configured - * @param wifi_bandwidth_t *bw : store bandwidth of interface ifx + * @param ifx interface to be configured + * @param[out] bw store bandwidth of interface ifx * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw); /** - * @brief Set primary/second channel of ESP32 + * @brief Set primary/secondary channel of ESP32 * * @attention 1. This is a special API for sniffer * - * @param uint8_t primary : for HT20, primary is the channel number, for HT40, primary is the primary channel - * @param wifi_second_chan_t second : for HT20, second is ignored, for HT40, second is the second channel + * @param primary for HT20, primary is the channel number, for HT40, primary is the primary channel + * @param second for HT20, second is ignored, for HT40, second is the second channel * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second); /** - * @brief Get the primary/second channel of ESP32 + * @brief Get the primary/secondary channel of ESP32 * * @attention 1. API return false if try to get a interface that is not enable * - * @param uint8_t *primary : store current primary channel - * @param wifi_second_chan_t *second : store current second channel + * @param primary store current primary channel + * @param[out] second store current second channel * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); @@ -435,25 +428,25 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second); * @brief Set country code * The default value is WIFI_COUNTRY_CN * - * @param wifi_country_t country : country type + * @param country country type * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - others: refer to error code in esp_err.h */ esp_err_t esp_wifi_set_country(wifi_country_t country); /** * @brief Get country code * - * @param wifi_country_t country : store current country + * @param country store current country * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_country(wifi_country_t *country); @@ -462,43 +455,44 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country); * * @attention 1. This API can only be called when the interface is disabled * @attention 2. ESP32 soft-AP and station have different MAC addresses, do not set them to be the same. - * - The bit0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address + * @attention 3. The bit 0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address * can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX". * - * @param wifi_interface_t ifx : interface - * @param uint8 mac[6]: the MAC address. + * @param ifx interface + * @param mac the MAC address * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_MAC : invalid mac address - * - ESP_ERR_WIFI_MODE : WiFi mode is wrong - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_MAC: invalid mac address + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong + * - others: refer to error codes in esp_err.h */ esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]); /** * @brief Get mac of specified interface * - * @param uint8_t mac[6] : store mac of this interface ifx + * @param ifx interface + * @param[out] mac store mac of the interface ifx * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface */ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]); /** * @brief The RX callback function in the promiscuous mode. * - * Each time a packet is received, the callback function will be called. + * Each time a packet is received, the callback function will be called. * - * @param void *buf : the data received - * @param uint16_t len : data length + * @param buf the data received + * @param len data length * * @return none */ @@ -507,36 +501,36 @@ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len); /** * @brief Register the RX callback function in the promiscuous mode. * - * Each time a packet is received, the registered callback function will be called. + * Each time a packet is received, the registered callback function will be called. * - * @param wifi_promiscuous_cb_t cb : callback + * @param cb callback * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb); /** * @brief Enable the promiscuous mode. * - * @param bool promiscuous : false - disable / true - enable + * @param en false - disable, true - enable * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_promiscuous(bool en); /** * @brief Get the promiscuous mode. * - * @param bool *enable : store the current status of promiscuous mode + * @param[out] en store the current status of promiscuous mode * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_promiscuous(bool *en); @@ -548,32 +542,32 @@ esp_err_t esp_wifi_get_promiscuous(bool *en); * @attention 3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as * the channel of the ESP32 station. * - * @param wifi_interface_t ifx : interface - * @param wifi_config_t *conf : station or soft-AP configuration + * @param ifx interface + * @param conf station or soft-AP configuration * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_IF : invalid interface - * - ESP_ERR_WIFI_MODE : invalid mode - * - ESP_ERR_WIFI_PASSWORD : invalid password - * - ESP_ERR_WIFI_NVS : WiFi internal NVS error - * - others : refer to the erro code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface + * - ESP_ERR_WIFI_MODE: invalid mode + * - ESP_ERR_WIFI_PASSWORD: invalid password + * - ESP_ERR_WIFI_NVS: WiFi internal NVS error + * - others: refer to the erro code in esp_err.h */ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf); /** * @brief Get configuration of specified interface * - * @param wifi_interface_t ifx : interface - * @param wifi_config_t *conf : station or soft-AP configuration + * @param ifx interface + * @param[out] conf station or soft-AP configuration * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_IF : invalid interface + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_IF: invalid interface */ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf); @@ -582,14 +576,14 @@ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf); * * @attention SSC only API * - * @param wifi_sta_list_t *sta: station list + * @param[out] sta station list * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_MODE : WiFi mode is wrong - * - ESP_ERR_WIFI_CONN : WiFi internal error, the station/soft-AP control block is invalid + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_MODE: WiFi mode is wrong + * - ESP_ERR_WIFI_CONN: WiFi internal error, the station/soft-AP control block is invalid */ esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta); @@ -599,12 +593,12 @@ esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta); * * @attention 1. The default value is WIFI_STORAGE_FLASH * - * @param wifi_storage_t storage : storage type + * @param storage : storage type * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_set_storage(wifi_storage_t storage); @@ -612,72 +606,63 @@ esp_err_t esp_wifi_set_storage(wifi_storage_t storage); * @brief Set auto connect * The default value is true * - * @param bool en : true - enable auto connect / false - disable auto connect + * @param en : true - enable auto connect / false - disable auto connect * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_MODE : WiFi internal error, the station/soft-AP control block is invalid - * - others : refer to error code in esp_err.h + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_MODE: WiFi internal error, the station/soft-AP control block is invalid + * - others: refer to error code in esp_err.h */ esp_err_t esp_wifi_set_auto_connect(bool en); /** * @brief Get the auto connect flag * - * @param bool *en : store current auto connect configuration + * @param[out] en store current auto connect configuration * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument */ esp_err_t esp_wifi_get_auto_connect(bool *en); /** * @brief Set vendor specific element * - * @param bool enable : enable or not - * @param wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON - * 1 - WIFI_VND_IE_TYPE_PROBE_REQ - * 2 - WIFI_VND_IE_TYPE_PROBE_RESP - * 3 - WIFI_VND_IE_TYPE_ASSOC_REQ - * 4 - WIFI_VND_IE_TYPE_ASSOC_RESP - * @param wifi_vendor_ie_id_t idx : 0 - WIFI_VND_IE_ID_0 - 1 - WIFI_VND_IE_ID_1 - * @param uint8_t *vnd_ie : pointer to a vendor specific element + * @param enable enable or not + * @param type information element type + * @param idx information element index + * @param vnd_ie pointer to a vendor specific element * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init - * - ESP_ERR_WIFI_ARG : invalid argument - * - ESP_ERR_WIFI_NO_MEM : out of memory + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + * - ESP_ERR_WIFI_ARG: invalid argument + * - ESP_ERR_WIFI_NO_MEM: out of memory */ esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, uint8_t *vnd_ie); /** * @brief Define function pointer for vendor specific element callback - * @param void *ctx : reserved - * @param wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON - * 1 - WIFI_VND_IE_TYPE_PROBE_REQ - * 2 - WIFI_VND_IE_TYPE_PROBE_RESP - * 3 - WIFI_VND_IE_TYPE_ASSOC_REQ - * 4 - WIFI_VND_IE_TYPE_ASSOC_RESP - * @param const uint8_t sa[6] : source address - * @param const uint8_t *vnd_ie : pointer to a vendor specific element - * @param int rssi : received signal strength indication + * @param ctx reserved + * @param type information element type + * @param sa source address + * @param vnd_ie pointer to a vendor specific element + * @param rssi received signal strength indication */ typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const uint8_t *vnd_ie, int rssi); /** * @brief Set vendor specific element callback * - * @param esp_vendor_ie_cb_t cb : callback function - * @param void *ctx : reserved + * @param cb callback function + * @param ctx reserved * * @return - * - ESP_OK : succeed - * - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init */ esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx); diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index 0c43c08740..1be0fdee14 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -1028,6 +1028,7 @@ #define DPORT_WIFI_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) /* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: */ +#define DPORT_MAC_RST (BIT(2)) #define DPORT_WIFI_RST 0xFFFFFFFF #define DPORT_WIFI_RST_M ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S)) #define DPORT_WIFI_RST_V 0xFFFFFFFF diff --git a/components/esp32/include/soc/io_mux_reg.h b/components/esp32/include/soc/io_mux_reg.h index 208a60703a..de8fe7ec99 100644 --- a/components/esp32/include/soc/io_mux_reg.h +++ b/components/esp32/include/soc/io_mux_reg.h @@ -34,10 +34,41 @@ #define PIN_INPUT_ENABLE(PIN_NAME) SET_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_INPUT_DISABLE(PIN_NAME) CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE) #define PIN_SET_DRV(PIN_NAME, drv) REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv)); -#define PIN_PULLUP_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLUP_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PU) -#define PIN_PULLDWN_DIS(PIN_NAME) REG_CLR_BIT(PIN_NAME, FUN_PD) -#define PIN_PULLDWN_EN(PIN_NAME) REG_SET_BIT(PIN_NAME, FUN_PD) + +/* + * @attention + * The PIN_PULL[UP|DWN]_[EN|DIS]() functions used to exist as macros in previous SDK versions. + * Unfortunately, however, they do not work for some GPIOs on the ESP32 chip, which needs pullups + * and -downs turned on and off through RTC registers. The functions still exist for compatibility + * with older code, but are marked as deprecated in order to generate a warning. + * Please replace them in this fashion: (make sure to include driver/gpio.h as well) + * PIN_PULLUP_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_en(x) + * PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pullup_dis(x) + * PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_en(x) + * PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[x]) -> gpio_pulldown_dis(x) + * +*/ +static inline void __attribute__ ((deprecated)) PIN_PULLUP_DIS(uint32_t PIN_NAME) +{ + REG_CLR_BIT(PIN_NAME, FUN_PU); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLUP_EN(uint32_t PIN_NAME) +{ + REG_SET_BIT(PIN_NAME, FUN_PU); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLDWN_DIS(uint32_t PIN_NAME) +{ + REG_CLR_BIT(PIN_NAME, FUN_PD); +} + +static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME) +{ + REG_SET_BIT(PIN_NAME, FUN_PD); +} + + #define PIN_FUNC_SELECT(PIN_NAME, FUNC) REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC) #define PIN_FUNC_GPIO 2 diff --git a/components/esp32/int_wdt.c b/components/esp32/int_wdt.c index 11de8f20d2..fe3ddab370 100644 --- a/components/esp32/int_wdt.c +++ b/components/esp32/int_wdt.c @@ -25,6 +25,7 @@ #include "esp_err.h" #include "esp_intr.h" #include "esp_attr.h" +#include "esp_freertos_hooks.h" #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" @@ -36,6 +37,38 @@ #define WDT_INT_NUM 24 +//Take care: the tick hook can also be called before esp_int_wdt_init() is called. +#if CONFIG_INT_WDT_CHECK_CPU1 +//Not static; the ISR assembly checks this. +bool int_wdt_app_cpu_ticked=false; + +static void IRAM_ATTR tick_hook(void) { + if (xPortGetCoreID()!=0) { + int_wdt_app_cpu_ticked=true; + } 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_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt + TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset + TIMERG1.wdt_feed=1; + TIMERG1.wdt_wprotect=0; + int_wdt_app_cpu_ticked=false; + } + } +} +#else +static void IRAM_ATTR tick_hook(void) { + if (xPortGetCoreID()!=0) return; + TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt + TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset + TIMERG1.wdt_feed=1; + TIMERG1.wdt_wprotect=0; +} +#endif + + void esp_int_wdt_init() { TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG1.wdt_config0.sys_reset_length=7; //3.2uS @@ -53,6 +86,7 @@ void esp_int_wdt_init() { TIMERG1.wdt_wprotect=0; TIMERG1.int_clr_timers.wdt=1; TIMERG1.int_ena.wdt=1; + esp_register_freertos_tick_hook(tick_hook); ESP_INTR_DISABLE(WDT_INT_NUM); intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM); //We do not register a handler for the interrupt because it is interrupt level 4 which @@ -62,35 +96,5 @@ void esp_int_wdt_init() { } -//Take care: the tick hook can also be called before esp_int_wdt_init() is called. -#if CONFIG_INT_WDT_CHECK_CPU1 -//Not static; the ISR assembly checks this. -bool int_wdt_app_cpu_ticked=false; - -void IRAM_ATTR vApplicationTickHook(void) { - if (xPortGetCoreID()!=0) { - int_wdt_app_cpu_ticked=true; - } 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_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; - int_wdt_app_cpu_ticked=false; - } - } -} -#else -void IRAM_ATTR vApplicationTickHook(void) { - if (xPortGetCoreID()!=0) return; - TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; - TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2; //Set timeout before interrupt - TIMERG1.wdt_config3=CONFIG_INT_WDT_TIMEOUT_MS*4; //Set timeout before reset - TIMERG1.wdt_feed=1; - TIMERG1.wdt_wprotect=0; -} -#endif #endif \ No newline at end of file diff --git a/components/esp32/lib b/components/esp32/lib index 01f5c068e1..a580f70a64 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 01f5c068e1ac3968add98439ee2f1748b9e391fa +Subproject commit a580f70a64872a7cc291b1f22455f6adbc2e35cf diff --git a/components/esp32/phy.h b/components/esp32/phy.h new file mode 100644 index 0000000000..81990f2e36 --- /dev/null +++ b/components/esp32/phy.h @@ -0,0 +1,64 @@ +// Copyright 2015-2016 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 +#include "esp_phy_init.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file phy.h + * @brief Declarations for functions provided by libphy.a + */ + +/** + * @brief Initialize function pointer table in PHY library. + * @note This function should be called before register_chipv7_phy. + */ +void phy_get_romfunc_addr(void); + +/** + * @brief Initialize PHY module and do RF calibration + * @param[in] init_data Initialization parameters to be used by the PHY + * @param[inout] cal_data As input, calibration data previously obtained. As output, will contain new calibration data. + * @param[in] cal_mode RF calibration mode + * @return reserved for future use + */ +int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibration_data_t *cal_data, esp_phy_calibration_mode_t cal_mode); + +/** + * @brief Get the format version of calibration data used by PHY library. + * @return Format version number, OR'ed with BIT(16) if PHY is in WIFI only mode. + */ +uint32_t phy_get_rf_cal_version(); + +/** + * @brief Set RF/BB for only WIFI mode or coexist(WIFI & BT) mode + * @param[in] true is for only WIFI mode, false is for coexist mode. default is 0. + * @return NULL + */ +void phy_set_wifi_mode_only(bool wifi_only); + +/** + * @brief Set BT the highest priority in coexist mode. + * @return NULL + */ +void coex_bt_high_prio(void); + +#ifdef __cplusplus +} +#endif + diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c new file mode 100644 index 0000000000..32d8f64edf --- /dev/null +++ b/components/esp32/phy_init.c @@ -0,0 +1,224 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include "rom/ets_sys.h" +#include "soc/dport_reg.h" + +#include "esp_err.h" +#include "esp_phy_init.h" +#include "esp_system.h" +#include "phy.h" +#include "esp_log.h" +#include "nvs.h" +#include "sdkconfig.h" +#include "phy_init_data.h" + +static const char* TAG = "phy_init"; + + +esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) +{ + assert(init_data); + assert(calibration_data); + // Initialize PHY pointer table + phy_get_romfunc_addr(); + REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); + REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); + // Enable WiFi peripheral clock + SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); + ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", + init_data, calibration_data, mode); + phy_set_wifi_mode_only(0); + register_chipv7_phy(init_data, calibration_data, mode); + coex_bt_high_prio(); + return ESP_OK; +} + +// PHY init data handling functions +#if CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION +#include "esp_partition.h" + +const esp_phy_init_data_t* esp_phy_get_init_data() +{ + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); + if (partition == NULL) { + ESP_LOGE(TAG, "PHY data partition not found"); + return NULL; + } + ESP_LOGD(TAG, "loading PHY init data from partition at offset 0x%x", partition->address); + size_t init_data_store_length = sizeof(phy_init_magic_pre) + + sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post); + uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length); + if (init_data_store == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for PHY init data"); + return NULL; + } + esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err); + return NULL; + } + if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 || + memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post), + PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) { + ESP_LOGE(TAG, "failed to validate PHY data partition"); + return NULL; + } + ESP_LOGE(TAG, "PHY data partition validated"); + return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre)); +} + +void esp_phy_release_init_data(const esp_phy_init_data_t* init_data) +{ + free((uint8_t*) init_data - sizeof(phy_init_magic_pre)); +} + +#else // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION + +// phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data + +const esp_phy_init_data_t* esp_phy_get_init_data() +{ + ESP_LOGD(TAG, "loading PHY init data from application binary"); + return &phy_init_data; +} + +void esp_phy_release_init_data(const esp_phy_init_data_t* init_data) +{ + // no-op +} +#endif // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION + + +// PHY calibration data handling functions +static const char* PHY_NAMESPACE = "phy"; +static const char* PHY_CAL_VERSION_KEY = "cal_version"; +static const char* PHY_CAL_MAC_KEY = "cal_mac"; +static const char* PHY_CAL_DATA_KEY = "cal_data"; + +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, + esp_phy_calibration_data_t* out_cal_data); + +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, + const esp_phy_calibration_data_t* cal_data); + +esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) +{ + nvs_handle handle; + esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + return err; + } + else { + err = load_cal_data_from_nvs_handle(handle, out_cal_data); + nvs_close(handle); + return err; + } +} + +esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data) +{ + nvs_handle handle; + esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err); + return err; + } + else { + err = store_cal_data_to_nvs_handle(handle, cal_data); + nvs_close(handle); + return err; + } +} + +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, + esp_phy_calibration_data_t* out_cal_data) +{ + esp_err_t err; + uint32_t cal_data_version; + err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err); + return err; + } + uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); + ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); + if (cal_data_version != cal_format_version) { + ESP_LOGD(TAG, "%s: expected calibration data format %d, found %d", + __func__, cal_format_version, cal_data_version); + return ESP_FAIL; + } + uint8_t cal_data_mac[6]; + size_t length = sizeof(cal_data_mac); + err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length); + if (err != ESP_OK) { + ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err); + return err; + } + if (length != sizeof(cal_data_mac)) { + ESP_LOGD(TAG, "%s: invalid length of cal_mac (%d)", __func__, length); + return ESP_ERR_INVALID_SIZE; + } + uint8_t sta_mac[6]; + system_efuse_read_mac(sta_mac); + if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) { + ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \ + MACSTR ", found " MACSTR, + __func__, MAC2STR(sta_mac), MAC2STR(cal_data_mac)); + return ESP_FAIL; + } + length = sizeof(*out_cal_data); + err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err); + return err; + } + if (length != sizeof(*out_cal_data)) { + ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length); + return ESP_ERR_INVALID_SIZE; + } + return ESP_OK; +} + +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, + const esp_phy_calibration_data_t* cal_data) +{ + esp_err_t err; + uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); + ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); + err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version); + if (err != ESP_OK) { + return err; + } + uint8_t sta_mac[6]; + system_efuse_read_mac(sta_mac); + err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac)); + if (err != ESP_OK) { + return err; + } + err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data)); + return err; +} + +void register_chipv7_phy_stub() +{ +} diff --git a/components/esp32/phy_init_data.h b/components/esp32/phy_init_data.h new file mode 100644 index 0000000000..206598f97c --- /dev/null +++ b/components/esp32/phy_init_data.h @@ -0,0 +1,139 @@ +// Copyright 2016 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 +#include "esp_phy_init.h" +#include "sdkconfig.h" + +// constrain a value between 'low' and 'high', inclusive +#define LIMIT(val, low, high) ((val < low) ? low : (val > high) ? high : val) + +#define PHY_INIT_MAGIC "PHYINIT" + +static const char phy_init_magic_pre[] = PHY_INIT_MAGIC; + +/** + * @brief Structure containing default recommended PHY initialization parameters. + */ +static const esp_phy_init_data_t phy_init_data= { + .param_ver_id = 0, + .crystal_select = 3, + .wifi_rx_gain_swp_step_1 = 0x05, + .wifi_rx_gain_swp_step_2 = 0x04, + .wifi_rx_gain_swp_step_3 = 0x06, + .wifi_rx_gain_swp_step_4 = 0x05, + .wifi_rx_gain_swp_step_5 = 0x01, + .wifi_rx_gain_swp_step_6 = 0x06, + .wifi_rx_gain_swp_step_7 = 0x05, + .wifi_rx_gain_swp_step_8 = 0x04, + .wifi_rx_gain_swp_step_9 = 0x06, + .wifi_rx_gain_swp_step_10 = 0x04, + .wifi_rx_gain_swp_step_11 = 0x05, + .wifi_rx_gain_swp_step_12 = 0x00, + .wifi_rx_gain_swp_step_13 = 0x00, + .wifi_rx_gain_swp_step_14 = 0x00, + .wifi_rx_gain_swp_step_15 = 0x00, + .bt_rx_gain_swp_step_1 = 0x05, + .bt_rx_gain_swp_step_2 = 0x04, + .bt_rx_gain_swp_step_3 = 0x06, + .bt_rx_gain_swp_step_4 = 0x05, + .bt_rx_gain_swp_step_5 = 0x01, + .bt_rx_gain_swp_step_6 = 0x06, + .bt_rx_gain_swp_step_7 = 0x05, + .bt_rx_gain_swp_step_8 = 0x00, + .bt_rx_gain_swp_step_9 = 0x00, + .bt_rx_gain_swp_step_10 = 0x00, + .bt_rx_gain_swp_step_11 = 0x00, + .bt_rx_gain_swp_step_12 = 0x00, + .bt_rx_gain_swp_step_13 = 0x00, + .bt_rx_gain_swp_step_14 = 0x00, + .bt_rx_gain_swp_step_15 = 0x00, + .gain_cmp_1 = 0x0a, + .gain_cmp_6 = 0x0a, + .gain_cmp_11 = 0x0c, + .gain_cmp_ext2_1 = 0xf0, + .gain_cmp_ext2_6 = 0xf0, + .gain_cmp_ext2_11 = 0xf0, + .gain_cmp_ext3_1 = 0xe0, + .gain_cmp_ext3_6 = 0xe0, + .gain_cmp_ext3_11 = 0xe0, + .gain_cmp_bt_ofs_1 = 0x18, + .gain_cmp_bt_ofs_6 = 0x18, + .gain_cmp_bt_ofs_11 = 0x18, + .target_power_qdb_0 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 78), + .target_power_qdb_1 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 76), + .target_power_qdb_2 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 74), + .target_power_qdb_3 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 68), + .target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 64), + .target_power_qdb_5 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52), + .target_power_index_mcs0 = 0, + .target_power_index_mcs1 = 0, + .target_power_index_mcs2 = 1, + .target_power_index_mcs3 = 1, + .target_power_index_mcs4 = 2, + .target_power_index_mcs5 = 3, + .target_power_index_mcs6 = 4, + .target_power_index_mcs7 = 5, + .pwr_ind_11b_en = 0, + .pwr_ind_11b_0 = 0, + .pwr_ind_11b_1 = 0, + .chan_backoff_en = 0, + .chan1_power_backoff_qdb = 0, + .chan2_power_backoff_qdb = 0, + .chan3_power_backoff_qdb = 0, + .chan4_power_backoff_qdb = 0, + .chan5_power_backoff_qdb = 0, + .chan6_power_backoff_qdb = 0, + .chan7_power_backoff_qdb = 0, + .chan8_power_backoff_qdb = 0, + .chan9_power_backoff_qdb = 0, + .chan10_power_backoff_qdb = 0, + .chan11_power_backoff_qdb = 0, + .chan12_power_backoff_qdb = 0, + .chan13_power_backoff_qdb = 0, + .chan14_power_backoff_qdb = 0, + .chan1_rate_backoff_index = 0, + .chan2_rate_backoff_index = 0, + .chan3_rate_backoff_index = 0, + .chan4_rate_backoff_index = 0, + .chan5_rate_backoff_index = 0, + .chan6_rate_backoff_index = 0, + .chan7_rate_backoff_index = 0, + .chan8_rate_backoff_index = 0, + .chan9_rate_backoff_index = 0, + .chan10_rate_backoff_index = 0, + .chan11_rate_backoff_index = 0, + .chan12_rate_backoff_index = 0, + .chan13_rate_backoff_index = 0, + .chan14_rate_backoff_index = 0, + .spur_freq_cfg_msb_1 = 0, + .spur_freq_cfg_1 = 0, + .spur_freq_cfg_div_1 = 0, + .spur_freq_en_h_1 = 0, + .spur_freq_en_l_1 = 0, + .spur_freq_cfg_msb_2 = 0, + .spur_freq_cfg_2 = 0, + .spur_freq_cfg_div_2 = 0, + .spur_freq_en_h_2 = 0, + .spur_freq_en_l_2 = 0, + .spur_freq_cfg_msb_3 = 0, + .spur_freq_cfg_3 = 0, + .spur_freq_cfg_div_3 = 0, + .spur_freq_en_h_3 = 0, + .spur_freq_en_l_3 = 0, + .reserved = {0} +}; + +static const char phy_init_magic_post[] = PHY_INIT_MAGIC; + diff --git a/components/esp32/task_wdt.c b/components/esp32/task_wdt.c index 3428b2a54c..1fcd5ea392 100644 --- a/components/esp32/task_wdt.c +++ b/components/esp32/task_wdt.c @@ -22,10 +22,13 @@ #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" #include #include "esp_err.h" #include "esp_intr.h" #include "esp_attr.h" +#include "esp_freertos_hooks.h" #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" #include "esp_log.h" @@ -44,6 +47,8 @@ struct wdt_task_t { }; static wdt_task_t *wdt_task_list=NULL; +static portMUX_TYPE taskwdt_spinlock = portMUX_INITIALIZER_UNLOCKED; + static void IRAM_ATTR task_wdt_isr(void *arg) { wdt_task_t *wdttask; @@ -54,24 +59,35 @@ static void IRAM_ATTR task_wdt_isr(void *arg) { TIMERG0.wdt_wprotect=0; //Ack interrupt TIMERG0.int_clr_timers.wdt=1; + //We are taking a spinlock while doing I/O (ets_printf) 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 + //than the badness caused by a spinlock here. + portENTER_CRITICAL(&taskwdt_spinlock); + if (!wdt_task_list) { + //No task on list. Maybe none registered yet. + portEXIT_CRITICAL(&taskwdt_spinlock); + return; + } //Watchdog got triggered because at least one task did not report in. - ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n"); + ets_printf(DRAM_STR("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n")); for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) { if (!wdttask->fed_watchdog) { - cpu=xTaskGetAffinity(wdttask->task_handle)==0?"CPU 0":"CPU 1"; - if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu="CPU 0/1"; - printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu); + cpu=xTaskGetAffinity(wdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1"); + if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1"); + ets_printf(DRAM_STR(" - %s (%s)\n"), pcTaskGetTaskName(wdttask->task_handle), cpu); } } - ets_printf("Tasks currently running:\n"); + ets_printf(DRAM_STR("Tasks currently running:\n")); for (int x=0; xnext) { @@ -113,14 +131,18 @@ void esp_task_wdt_feed() { //Reset fed_watchdog status for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false; } + portEXIT_CRITICAL(&taskwdt_spinlock); } void esp_task_wdt_delete() { TaskHandle_t handle=xTaskGetCurrentTaskHandle(); wdt_task_t *wdttask=wdt_task_list; + portENTER_CRITICAL(&taskwdt_spinlock); + //Wdt task list can't be empty if (!wdt_task_list) { ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?"); + portEXIT_CRITICAL(&taskwdt_spinlock); return; } if (handle==wdt_task_list) { @@ -129,17 +151,39 @@ void esp_task_wdt_delete() { free(wdttask); } else { //Find current task in list + if (wdt_task_list->task_handle==handle) { + //Task is the very first one. + wdt_task_t *freeme=wdt_task_list; + wdt_task_list=wdt_task_list->next; + free(freeme); + portEXIT_CRITICAL(&taskwdt_spinlock); + return; + } while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next; if (!wdttask->next) { ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!"); + portEXIT_CRITICAL(&taskwdt_spinlock); return; } wdt_task_t *freeme=wdttask->next; wdttask->next=wdttask->next->next; free(freeme); } + portEXIT_CRITICAL(&taskwdt_spinlock); } + +#if CONFIG_TASK_WDT_CHECK_IDLE_TASK +static bool idle_hook(void) { +#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 + if (xPortGetCoreID()!=0) return true; +#endif + esp_task_wdt_feed(); + return true; +} +#endif + + void esp_task_wdt_init() { TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS @@ -153,6 +197,9 @@ void esp_task_wdt_init() { TIMERG0.wdt_config0.en=1; TIMERG0.wdt_feed=1; TIMERG0.wdt_wprotect=0; +#if CONFIG_TASK_WDT_CHECK_IDLE_TASK + esp_register_freertos_idle_hook(idle_hook); +#endif ESP_INTR_DISABLE(ETS_T0_WDT_INUM); intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM); xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL); @@ -161,13 +208,5 @@ void esp_task_wdt_init() { ESP_INTR_ENABLE(ETS_T0_WDT_INUM); } -#if CONFIG_TASK_WDT_CHECK_IDLE_TASK -void vApplicationIdleHook(void) { -#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1 - if (xPortGetCoreID()!=0) return; -#endif - esp_task_wdt_feed(); -} -#endif #endif diff --git a/components/esptool_py/Makefile.projbuild b/components/esptool_py/Makefile.projbuild index aa3bb2bfa9..acbada7244 100644 --- a/components/esptool_py/Makefile.projbuild +++ b/components/esptool_py/Makefile.projbuild @@ -54,4 +54,6 @@ app-flash: $(APP_BIN) $(ESPTOOLPY_SRC) @echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..." $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN) -$(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool)) +# Submodules normally added in component.mk, but can be added +# at the project level as long as qualified path +COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool diff --git a/components/expat/port/minicheck.c b/components/expat/port/minicheck.c index 5a1f5ed0e2..95a4939bdb 100644 --- a/components/expat/port/minicheck.c +++ b/components/expat/port/minicheck.c @@ -108,44 +108,45 @@ add_failure(SRunner *runner, int verbosity) } } +static void run_test(SRunner *runner, int verbosity, TCase *tc, int i) +{ + if (tc->setup != NULL) { + /* setup */ + if (setjmp(env)) { + add_failure(runner, verbosity); + return; + } + tc->setup(); + } + /* test */ + if (setjmp(env)) { + add_failure(runner, verbosity); + return; + } + (tc->tests[i])(); + + /* teardown */ + if (tc->teardown != NULL) { + if (setjmp(env)) { + add_failure(runner, verbosity); + return; + } + tc->teardown(); + } +} + void srunner_run_all(SRunner *runner, int verbosity) { - Suite *suite; - TCase *tc; assert(runner != NULL); - suite = runner->suite; - tc = suite->tests; + assert(runner->suite != NULL); + TCase *tc = runner->suite->tests; while (tc != NULL) { - int i; - for (i = 0; i < tc->ntests; ++i) { + for (int i = 0; i < tc->ntests; ++i) { runner->nchecks++; - - if (tc->setup != NULL) { - /* setup */ - if (setjmp(env)) { - add_failure(runner, verbosity); - continue; - } - tc->setup(); - } - /* test */ - if (setjmp(env)) { - add_failure(runner, verbosity); - continue; - } - (tc->tests[i])(); - - /* teardown */ - if (tc->teardown != NULL) { - if (setjmp(env)) { - add_failure(runner, verbosity); - continue; - } - tc->teardown(); - } + run_test(runner, verbosity, tc, i); + tc = tc->next_tcase; } - tc = tc->next_tcase; } if (verbosity) { int passed = runner->nchecks - runner->nfailures; diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 91e824b2dc..b9db00e50b 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -141,6 +141,35 @@ config FREERTOS_ISR_STACKSIZE The interrupt handlers have their own stack. The size of the stack can be defined here. Each processor has its own stack, so the total size occupied will be twice this. +config FREERTOS_LEGACY_HOOKS + bool "Use FreeRTOS legacy hooks" + default n + help + FreeRTOS offers a number of hooks/callback functions that are called when a timer + tick happens, the idle thread runs etc. esp-idf replaces these by runtime registerable + hooks using the esp_register_freertos_xxx_hook system, but for legacy reasons the old + hooks can also still be enabled. Please enable this only if you have code that for some + reason can't be migrated to the esp_register_freertos_xxx_hook system. + +if FREERTOS_LEGACY_HOOKS + +config FREERTOS_LEGACY_IDLE_HOOK + bool "Enable legacy idle hook" + default n + help + If enabled, FreeRTOS will call a function called vApplicationIdleHook when the idle thread + on a CPU is running. Please make sure your code defines such a function. + +config FREERTOS_LEGACY_TICK_HOOK + bool "Enable legacy tick hook" + default n + help + If enabled, FreeRTOS will call a function called vApplicationTickHook when a FreeRTOS + tick is executed. Please make sure your code defines such a function. + +endif #FREERTOS_LEGACY_HOOKS + + menuconfig FREERTOS_DEBUG_INTERNALS bool "Debug FreeRTOS internals" default n diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index 47566ab3b3..13ce73e0a8 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -152,9 +152,9 @@ *----------------------------------------------------------*/ #define configUSE_PREEMPTION 1 -#define configUSE_IDLE_HOOK ( CONFIG_TASK_WDT_CHECK_IDLE_TASK ) +#define configUSE_IDLE_HOOK ( CONFIG_FREERTOS_LEGACY_IDLE_HOOK ) -#define configUSE_TICK_HOOK ( CONFIG_INT_WDT ) +#define configUSE_TICK_HOOK ( CONFIG_FREERTOS_LEGACY_TICK_HOOK ) #define configTICK_RATE_HZ ( CONFIG_FREERTOS_HZ ) diff --git a/components/freertos/ringbuf.c b/components/freertos/ringbuf.c index a4205d88dc..67323e3276 100644 --- a/components/freertos/ringbuf.c +++ b/components/freertos/ringbuf.c @@ -471,7 +471,8 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, ringbuf_t *rb=(ringbuf_t *)ringbuf; size_t needed_size=dataSize+sizeof(buf_entry_hdr_t); BaseType_t done=pdFALSE; - portTickType ticks_end=xTaskGetTickCount() + ticks_to_wait; + TickType_t ticks_end = xTaskGetTickCount() + ticks_to_wait; + TickType_t ticks_remaining = ticks_to_wait; configASSERT(rb); @@ -486,17 +487,26 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, if (ringbufferFreeMem(rb) < needed_size) { //Data does not fit yet. Wait until the free_space_sem is given, then re-evaluate. - BaseType_t r = xSemaphoreTake(rb->free_space_sem, ticks_to_wait); + BaseType_t r = xSemaphoreTake(rb->free_space_sem, ticks_remaining); if (r == pdFALSE) { //Timeout. return pdFALSE; } - //Adjust ticks_to_wait; we may have waited less than that and in the case the free memory still is not enough, + //Adjust ticks_remaining; we may have waited less than that and in the case the free memory still is not enough, //we will need to wait some more. - ticks_to_wait = ticks_end - xTaskGetTickCount(); + if (ticks_to_wait != portMAX_DELAY) { + ticks_remaining = ticks_end - xTaskGetTickCount(); + } + + // ticks_remaining will always be less than or equal to the original ticks_to_wait, + // unless the timeout is reached - in which case it unsigned underflows to a much + // higher value. + // + // (Check is written this non-intuitive way to allow for the case where xTaskGetTickCount() + // has overflowed but the ticks_end value has not overflowed.) } - } while (ringbufferFreeMem(rb) < needed_size && ticks_to_wait>=0); - + } while (ringbufferFreeMem(rb) < needed_size && ticks_remaining > 0 && ticks_remaining <= ticks_to_wait); + //Lock the mux in order to make sure no one else is messing with the ringbuffer and do the copy. portENTER_CRITICAL(&rb->mux); //Another thread may have been able to sneak its write first. Check again now we locked the ringbuff, and retry diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index b79d3a98ba..26103ee236 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -476,6 +476,7 @@ to its original value when it is released. */ #if configUSE_TICK_HOOK > 0 extern void vApplicationTickHook( void ); #endif +extern void esp_vApplicationTickHook( void ); #if portFIRST_TASK_HOOK extern void vPortFirstTaskHook(TaskFunction_t taskfn); @@ -2360,22 +2361,21 @@ BaseType_t xSwitchRequired = pdFALSE; We can't really calculate what we need, that's done on core 0... just assume we need a switch. ToDo: Make this more intelligent? -- JD */ - //We do need the tick hook to satisfy the int watchdog. - #if ( configUSE_TICK_HOOK == 1 ) { /* Guard against the tick hook being called when the pended tick count is being unwound (when the scheduler is being unlocked). */ if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U ) { + #if ( configUSE_TICK_HOOK == 1 ) vApplicationTickHook(); + #endif /* configUSE_TICK_HOOK */ + esp_vApplicationTickHook(); } else { mtCOVERAGE_TEST_MARKER(); } } - #endif /* configUSE_TICK_HOOK */ - return pdTRUE; } @@ -2506,20 +2506,21 @@ BaseType_t xSwitchRequired = pdFALSE; } #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */ - #if ( configUSE_TICK_HOOK == 1 ) { /* Guard against the tick hook being called when the pended tick count is being unwound (when the scheduler is being unlocked). */ if( uxPendedTicks == ( UBaseType_t ) 0U ) { + #if ( configUSE_TICK_HOOK == 1 ) vApplicationTickHook(); + #endif /* configUSE_TICK_HOOK */ + esp_vApplicationTickHook(); } else { mtCOVERAGE_TEST_MARKER(); } } - #endif /* configUSE_TICK_HOOK */ taskEXIT_CRITICAL_ISR(&xTaskQueueMutex); } else @@ -2533,6 +2534,7 @@ BaseType_t xSwitchRequired = pdFALSE; vApplicationTickHook(); } #endif + esp_vApplicationTickHook(); } #if ( configUSE_PREEMPTION == 1 ) @@ -2702,7 +2704,7 @@ void vTaskSwitchContext( void ) taskENTER_CRITICAL_ISR(&xTaskQueueMutex); unsigned portBASE_TYPE foundNonExecutingWaiter = pdFALSE, ableToSchedule = pdFALSE, resetListHead; - unsigned portBASE_TYPE uxDynamicTopReady = uxTopReadyPriority; + portBASE_TYPE uxDynamicTopReady = uxTopReadyPriority; unsigned portBASE_TYPE holdTop=pdFALSE; /* @@ -2715,8 +2717,6 @@ void vTaskSwitchContext( void ) while ( ableToSchedule == pdFALSE && uxDynamicTopReady >= 0 ) { - configASSERT( uxTopReadyPriority>=0 ); - configASSERT( uxDynamicTopReady>=0 ); resetListHead = pdFALSE; // Nothing to do for empty lists if (!listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxDynamicTopReady ] ) )) { @@ -3270,6 +3270,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) vApplicationIdleHook(); } #endif /* configUSE_IDLE_HOOK */ + { + /* Call the esp-idf hook system */ + extern void esp_vApplicationIdleHook( void ); + esp_vApplicationIdleHook(); + } + /* This conditional compilation should use inequality to 0, not equality to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 801fa0b51c..bf7bff15b4 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -1,5 +1,21 @@ menu "LWIP" +config L2_TO_L3_COPY + bool "Enable copy between Layer2 and Layer3 packets" + default 0 + help + If this feature is enabled, all traffic from layer2(WIFI Driver) will be + copied to a new buffer before sending it to layer3(LWIP stack), freeing + the layer2 buffer. + Please be notified that the total layer2 receiving buffer is fixed and + ESP32 currently supports 25 layer2 receiving buffer, when layer2 buffer + runs out of memory, then the incoming packets will be dropped in hardware. + The layer3 buffer is allocated from the heap, so the total layer3 receiving + buffer depends on the available heap size, when heap runs out of memory, + no copy will be sent to layer3 and packet will be dropped in layer2. + Please make sure you fully understand the impact of this feature before + enabling it. + config LWIP_MAX_SOCKETS int "Max number of open sockets" range 1 16 diff --git a/components/lwip/include/lwip/lwip/opt.h b/components/lwip/include/lwip/lwip/opt.h index 51d340e00b..c42f3cd735 100755 --- a/components/lwip/include/lwip/lwip/opt.h +++ b/components/lwip/include/lwip/lwip/opt.h @@ -3008,6 +3008,13 @@ #define LWIP_PERF 0 #endif +/** + * ESP_L2_TO_L3_COPY: enable memcpy when receiving packet from L2 + */ +#ifndef ESP_L2_TO_L3_COPY +#define ESP_L2_TO_L3_COPY 0 +#endif + #ifndef ESP_THREAD_SAFE_DEBUG #define ESP_THREAD_SAFE_DEBUG 0 #endif diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index d06e756850..26bdc3a4e9 100755 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -525,6 +525,7 @@ extern unsigned long os_random(void); #define ESP_RANDOM_TCP_PORT 1 #define ESP_IP4_ATON 1 #define ESP_LIGHT_SLEEP 1 +#define ESP_L2_TO_L3_COPY CONFIG_L2_TO_L3_COPY #define TCP_WND_DEFAULT (4*TCP_MSS) #define TCP_SND_BUF_DEFAULT (2*TCP_MSS) diff --git a/components/lwip/port/netif/wlanif.c b/components/lwip/port/netif/wlanif.c index ffad69cd46..3fd2a3192a 100755 --- a/components/lwip/port/netif/wlanif.c +++ b/components/lwip/port/netif/wlanif.c @@ -161,40 +161,37 @@ low_level_output(struct netif *netif, struct pbuf *p) * @param netif the lwip network interface structure for this ethernetif */ void -#if ESP_LWIP wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb) -#else -wlanif_input(struct netif *netif, void *buffer, uint16 len) -#endif { struct pbuf *p; -#if ESP_LWIP - if(buffer== NULL) + if(!buffer || !netif) goto _exit; - if(netif == NULL) - goto _exit; -#endif -#if ESP_LWIP - p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); - if (p == NULL){ -#if ESP_PERF - g_rx_alloc_pbuf_fail_cnt++; -#endif - return; - } - p->payload = buffer; - p->eb = eb; -#else - p = pbuf_alloc(PBUF_IP, len, PBUF_POOL); +#if (ESP_L2_TO_L3_COPY == 1) + //p = pbuf_alloc(PBUF_IP, len, PBUF_POOL); + p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM); if (p == NULL) { + #if ESP_PERF + g_rx_alloc_pbuf_fail_cnt++; + #endif + esp_wifi_internal_free_rx_buffer(eb); return; } memcpy(p->payload, buffer, len); + esp_wifi_internal_free_rx_buffer(eb); +#else + p = pbuf_alloc(PBUF_RAW, len, PBUF_REF); + if (p == NULL){ + #if ESP_PERF + g_rx_alloc_pbuf_fail_cnt++; + #endif + return; + } + p->payload = buffer; + p->eb = eb; #endif - /* full packet send to tcpip_thread to process */ if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); diff --git a/components/micro-ecc/component.mk b/components/micro-ecc/component.mk index df73f7a3b2..8c569df597 100644 --- a/components/micro-ecc/component.mk +++ b/components/micro-ecc/component.mk @@ -4,3 +4,5 @@ COMPONENT_SRCDIRS := micro-ecc COMPONENT_OBJS := micro-ecc/uECC.o COMPONENT_ADD_INCLUDEDIRS := micro-ecc + +COMPONENT_SUBMODULES := micro-ecc diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 8418959793..5f7a93a7b0 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -77,8 +77,9 @@ typedef enum { */ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle); +/**@{*/ /** - * @brief nvs_set_X - set value for given key + * @brief set value for given key * * This family of functions set value for the key, given its name. Note that * actual storage will not be updated until nvs_commit function is called. @@ -89,7 +90,6 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha * implementation, but is guaranteed to be at least * 16 characters. Shouldn't be empty. * @param[in] value The value to set. - * @param[in] length For nvs_set_blob: length of binary value to set, in bytes. * * @return * - ESP_OK if value was set successfully @@ -112,10 +112,39 @@ esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value); esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value); esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value); esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value); -esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length); +/**@}*/ /** - * @brief nvs_get_X - get value for given key + * @brief set variable length binary value for given key + * + * This family of functions set value for the key, given its name. Note that + * actual storage will not be updated until nvs_commit function is called. + * + * @param[in] handle Handle obtained from nvs_open function. + * Handles that were opened read only cannot be used. + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 16 characters. Shouldn't be empty. + * @param[in] value The value to set. + * @param[in] length length of binary value to set, in bytes. + * + * @return + * - ESP_OK if value was set successfully + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the + * underlying storage to save the value + * - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash + * write operation has failed. The value was written however, and + * update will be finished after re-initialization of nvs, provided that + * flash operation doesn't fail again. + */ +esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length); + +/**@{*/ +/** + * @brief get value for given key * * These functions retrieve value for the key, given its name. If key does not * exist, or the requested variable type doesn't match the type which was used @@ -125,7 +154,55 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * * All functions expect out_value to be a pointer to an already allocated variable * of the given type. - * Additionally, nvs_get_str and nvs_get_blob support WinAPI-style length queries. + * + * \code{c} + * // Example of using nvs_get_i32: + * int32_t max_buffer_size = 4096; // default value + * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); + * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); + * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still + * // have its default value. + * + * \endcode + * + * @param[in] handle Handle obtained from nvs_open function. + * @param[in] key Key name. Maximal length is determined by the underlying + * implementation, but is guaranteed to be at least + * 16 characters. Shouldn't be empty. + * @param out_value Pointer to the output value. + * May be NULL for nvs_get_str and nvs_get_blob, in this + * case required length will be returned in length argument. + * + * @return + * - ESP_OK if the value was retrieved successfully + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints + * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data + */ +esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value); +esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value); +esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value); +esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value); +esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value); +esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value); +esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value); +esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); +/**@}*/ + +/** + * @brief get value for given key + * + * These functions retrieve value for the key, given its name. If key does not + * exist, or the requested variable type doesn't match the type which was used + * when setting a value, an error is returned. + * + * In case of any error, out_value is not modified. + * + * All functions expect out_value to be a pointer to an already allocated variable + * of the given type. + * + * nvs_get_str and nvs_get_blob functions support WinAPI-style length queries. * To get the size necessary to store the value, call nvs_get_str or nvs_get_blob * with zero out_value and non-zero pointer to length. Variable pointed to * by length argument will be set to the required length. For nvs_get_str, @@ -136,13 +213,6 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * nvs_get/set_blob used for arbitrary data structures. * * \code{c} - * // Example of using nvs_get_i32: - * int32_t max_buffer_size = 4096; // default value - * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); - * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); - * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still - * // have its default value. - * * // Example (without error checking) of using nvs_get_str to get a string into dynamic array: * size_t required_size; * nvs_get_str(my_handle, "server_name", NULL, &required_size); @@ -163,8 +233,7 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * @param out_value Pointer to the output value. * May be NULL for nvs_get_str and nvs_get_blob, in this * case required length will be returned in length argument. - * @param[inout] length For nvs_get_str and nvs_get_blob, non-zero pointer - * to the variable holding the length of out_value. + * @param[inout] length A non-zero pointer to the variable holding the length of out_value. * In case out_value a zero, will be set to the length * required to hold the value. In case out_value is not * zero, will be set to the actual length of the value @@ -177,16 +246,10 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints * - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data */ -esp_err_t nvs_get_i8 (nvs_handle handle, const char* key, int8_t* out_value); -esp_err_t nvs_get_u8 (nvs_handle handle, const char* key, uint8_t* out_value); -esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value); -esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value); -esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value); -esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value); -esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value); -esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value); +/**@{*/ esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length); esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length); +/**@}*/ /** * @brief Erase key-value pair with given key name. diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index 1cade0e956..0162a8f8ac 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -18,27 +18,13 @@ extern "C" { #endif -/** Initialise NVS flash storage with default flash sector layout - - Temporarily, this region is hardcoded as a 12KB (0x3000 byte) - region starting at 24KB (0x6000 byte) offset in flash. - - @return ESP_OK if flash was successfully initialised. -*/ +/** + * @brief Initialize NVS flash storage with layout given in the partition table. + * + * @return ESP_OK if storage was successfully initialized. + */ esp_err_t nvs_flash_init(void); -/** Initialise NVS flash storage with custom flash sector layout - - @param baseSector Flash sector (units of 4096 bytes) offset to start NVS. - @param sectorCount Length (in flash sectors) of NVS region. - - @return ESP_OK if flash was successfully initialised. - - @note Use this parameter if you're not using the options in menuconfig for - configuring flash layout & partition table. -*/ -esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount); - #ifdef __cplusplus } diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index f6c6c588aa..7c9ec89a6f 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -16,6 +16,7 @@ #include "nvs_storage.hpp" #include "intrusive_list.h" #include "nvs_platform.hpp" +#include "esp_partition.h" #include "sdkconfig.h" #ifdef ESP_PLATFORM @@ -61,20 +62,32 @@ extern "C" void nvs_dump() s_nvs_storage.debugDump(); } -extern "C" esp_err_t nvs_flash_init(void) -{ - return nvs_flash_init_custom(9, 3); -} - extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount) { - Lock::init(); - Lock lock; - ESP_LOGD(TAG, "init start=%d count=%d", baseSector, sectorCount); + ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount); s_nvs_handles.clear(); return s_nvs_storage.init(baseSector, sectorCount); } +#ifdef ESP_PLATFORM +extern "C" esp_err_t nvs_flash_init(void) +{ + Lock::init(); + Lock lock; + if (s_nvs_storage.isValid()) { + return ESP_OK; + } + const esp_partition_t* partition = esp_partition_find_first( + ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL); + if (partition == NULL) { + return ESP_ERR_NOT_FOUND; + } + + return nvs_flash_init_custom(partition->address / SPI_FLASH_SEC_SIZE, + partition->size / SPI_FLASH_SEC_SIZE); +} +#endif + static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry) { auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool { diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index d2ca225352..80ccb1f6d0 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -114,7 +114,30 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) assert(mFirstUsedEntry != INVALID_ENTRY); const uint16_t count = size / ENTRY_SIZE; - auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), data, size); + const uint8_t* buf = data; + +#ifdef ESP_PLATFORM + /* On the ESP32, data can come from DROM, which is not accessible by spi_flash_write + * function. To work around this, we copy the data to heap if it came from DROM. + * Hopefully this won't happen very often in practice. For data from DRAM, we should + * still be able to write it to flash directly. + * TODO: figure out how to make this platform-specific check nicer (probably by introducing + * a platform-specific flash layer). + */ + if ((uint32_t) data < 0x3ff00000) { + buf = (uint8_t*) malloc(size); + if (!buf) { + return ESP_ERR_NO_MEM; + } + memcpy((void*)buf, data, size); + } +#endif //ESP_PLATFORM + auto rc = spi_flash_write(getEntryAddress(mNextFreeEntry), buf, size); +#ifdef ESP_PLATFORM + if (buf != data) { + free((void*)buf); + } +#endif //ESP_PLATFORM if (rc != ESP_OK) { mState = PageState::INVALID; return rc; diff --git a/components/nvs_flash/src/nvs_platform.hpp b/components/nvs_flash/src/nvs_platform.hpp index 374dbca6cc..0973c4875c 100644 --- a/components/nvs_flash/src/nvs_platform.hpp +++ b/components/nvs_flash/src/nvs_platform.hpp @@ -16,9 +16,6 @@ #ifdef ESP_PLATFORM -#define NVS_DEBUGV(...) ets_printf(__VA_ARGS__) - -#include "rom/ets_sys.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -30,19 +27,23 @@ class Lock public: Lock() { - assert(mSemaphore); - xSemaphoreTake(mSemaphore, portMAX_DELAY); + if (mSemaphore) { + xSemaphoreTake(mSemaphore, portMAX_DELAY); + } } ~Lock() { - assert(mSemaphore); - xSemaphoreGive(mSemaphore); + if (mSemaphore) { + xSemaphoreGive(mSemaphore); + } } static esp_err_t init() { - assert(mSemaphore == nullptr); + if (mSemaphore) { + return ESP_OK; + } mSemaphore = xSemaphoreCreateMutex(); if (!mSemaphore) { return ESP_ERR_NO_MEM; @@ -52,7 +53,9 @@ public: static void uninit() { - vSemaphoreDelete(mSemaphore); + if (mSemaphore) { + vSemaphoreDelete(mSemaphore); + } mSemaphore = nullptr; } diff --git a/components/nvs_flash/src/nvs_storage.cpp b/components/nvs_flash/src/nvs_storage.cpp index cacfbd4022..f8da28fa24 100644 --- a/components/nvs_flash/src/nvs_storage.cpp +++ b/components/nvs_flash/src/nvs_storage.cpp @@ -69,6 +69,11 @@ esp_err_t Storage::init(uint32_t baseSector, uint32_t sectorCount) return ESP_OK; } +bool Storage::isValid() const +{ + return mState == StorageState::ACTIVE; +} + esp_err_t Storage::findItem(uint8_t nsIndex, ItemType datatype, const char* key, Page* &page, Item& item) { for (auto it = std::begin(mPageManager); it != std::end(mPageManager); ++it) { diff --git a/components/nvs_flash/src/nvs_storage.hpp b/components/nvs_flash/src/nvs_storage.hpp index f8cee9f2a9..ecf2651ae5 100644 --- a/components/nvs_flash/src/nvs_storage.hpp +++ b/components/nvs_flash/src/nvs_storage.hpp @@ -47,6 +47,8 @@ public: esp_err_t init(uint32_t baseSector, uint32_t sectorCount); + bool isValid() const; + esp_err_t createOrOpenNamespace(const char* nsName, bool canCreate, uint8_t& nsIndex); esp_err_t writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize); diff --git a/components/nvs_flash/src/nvs_test_api.h b/components/nvs_flash/src/nvs_test_api.h new file mode 100644 index 0000000000..97940092d5 --- /dev/null +++ b/components/nvs_flash/src/nvs_test_api.h @@ -0,0 +1,47 @@ +// Copyright 2015-2016 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 "nvs_flash.h" + +/** + * @brief Initialize NVS flash storage with custom flash sector layout + * + * @note This API is intended to be used in unit tests. + * + * @param baseSector Flash sector (units of 4096 bytes) offset to start NVS + * @param sectorCount Length (in flash sectors) of NVS region. + NVS partition must be at least 3 sectors long. + * @return ESP_OK if flash was successfully initialized + */ +esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount); + + +/** + * @brief Dump contents of NVS storage to stdout + * + * This function may be used for debugging purposes to inspect the state + * of NVS pages. For each page, list of entries is also dumped. + */ +void nvs_dump(void); + + +#ifdef __cplusplus +} +#endif diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index 81bf7fd216..282d4de48e 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -13,7 +13,7 @@ // limitations under the License. #include "catch.hpp" #include "nvs.hpp" -#include "nvs_flash.h" +#include "nvs_test_api.h" #include "spi_flash_emulation.h" #include #include diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 887fe2e82b..b4c0754637 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -55,16 +55,17 @@ #else #ifdef SSL_PRINT_LOG #undef SSL_PRINT_LOG - #define SSL_PRINT_LOG(...) #endif + #define SSL_PRINT_LOG(...) + #ifdef SSL_ERROR_LOG #undef SSL_ERROR_LOG - #define SSL_ERROR_LOG(...) #endif + #define SSL_ERROR_LOG(...) #ifdef SSL_LOCAL_LOG #undef SSL_LOCAL_LOG - #define SSL_LOCAL_LOG(...) #endif + #define SSL_LOCAL_LOG(...) #endif #if SSL_DEBUG_LOCATION_ENABLE diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 92e72bfdb8..a5986dc3ee 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -90,10 +90,6 @@ int ssl_pm_new(SSL *ssl) if (!ssl_pm) SSL_ERR(ret, failed1, "ssl_mem_zalloc\n"); - if (ssl->ctx->read_buffer_len < 2048 || - ssl->ctx->read_buffer_len > 8192) - return -1; - max_content_len = ssl->ctx->read_buffer_len; mbedtls_net_init(&ssl_pm->fd); @@ -215,6 +211,31 @@ static int ssl_pm_reload_crt(SSL *ssl) return 0; } +/* + * Perform the mbedtls SSL handshake instead of mbedtls_ssl_handshake. + * We can add debug here. + */ +LOCAL int mbedtls_handshake( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if (ssl == NULL || ssl->conf == NULL) + return MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + + while (ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER) + { + ret = mbedtls_ssl_handshake_step(ssl); + + SSL_DEBUG(1, "ssl ret %d state %d heap %d\n", + ret, ssl->state, system_get_free_heap_size()); + + if (ret != 0) + break; + } + + return ret; +} + int ssl_pm_handshake(SSL *ssl) { int ret, mbed_ret; @@ -224,13 +245,19 @@ int ssl_pm_handshake(SSL *ssl) if (mbed_ret) return 0; + SSL_DEBUG(1, "ssl_speed_up_enter "); ssl_speed_up_enter(); - while((mbed_ret = mbedtls_ssl_handshake(&ssl_pm->ssl)) != 0) { + SSL_DEBUG(1, "OK\n"); + + while((mbed_ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) { if (mbed_ret != MBEDTLS_ERR_SSL_WANT_READ && mbed_ret != MBEDTLS_ERR_SSL_WANT_WRITE) { break; } } + + SSL_DEBUG(1, "ssl_speed_up_exit "); ssl_speed_up_exit(); + SSL_DEBUG(1, "OK\n"); if (!mbed_ret) { struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; @@ -492,6 +519,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) return 0; failed2: + mbedtls_x509_crt_free(x509_pm->x509_crt); ssl_mem_free(x509_pm->x509_crt); x509_pm->x509_crt = NULL; failed1: @@ -567,6 +595,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) return 0; failed2: + mbedtls_pk_free(pkey_pm->pkey); ssl_mem_free(pkey_pm->pkey); pkey_pm->pkey = NULL; failed1: diff --git a/components/partition_table/Kconfig.projbuild b/components/partition_table/Kconfig.projbuild index fa2685d7a1..1f019a6e3f 100644 --- a/components/partition_table/Kconfig.projbuild +++ b/components/partition_table/Kconfig.projbuild @@ -1,49 +1,63 @@ menu "Partition Table" choice - prompt "Partition Table" - default PARTITION_TABLE_SINGLE_APP - help - The partition table to flash to the ESP32. The partition table - determines where apps, data and other resources are expected to - be found. + prompt "Partition Table" + default PARTITION_TABLE_SINGLE_APP + help + The partition table to flash to the ESP32. The partition table + determines where apps, data and other resources are expected to + be found. - The predefined partition table CSV descriptions can be found - in the components/partition_table directory. Otherwise it's - possible to create a new custom partition CSV for your application. + The predefined partition table CSV descriptions can be found + in the components/partition_table directory. Otherwise it's + possible to create a new custom partition CSV for your application. config PARTITION_TABLE_SINGLE_APP - bool "Single factory app, no OTA" + bool "Single factory app, no OTA" config PARTITION_TABLE_TWO_OTA - bool "Factory app, two OTA definitions" + bool "Factory app, two OTA definitions" config PARTITION_TABLE_CUSTOM - bool "Custom partition table CSV" + bool "Custom partition table CSV" endchoice config PARTITION_TABLE_CUSTOM_FILENAME - string "Custom partition CSV file" if PARTITION_TABLE_CUSTOM - default partitions.csv - help - Name of the custom partition CSV filename. This path is evaluated - relative to the project root directory. + string "Custom partition CSV file" if PARTITION_TABLE_CUSTOM + default partitions.csv + help + Name of the custom partition CSV filename. This path is evaluated + relative to the project root directory. config PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET - hex "App offset in flash" if PARTITION_TABLE_CUSTOM - default 0x10000 - help - If using a custom partition table, specify the offset in the flash - where 'make flash' should write the built app. + hex "Factory app partition offset" if PARTITION_TABLE_CUSTOM + default 0x10000 + help + If using a custom partition table, specify the offset in the flash + where 'make flash' should write the built app. + +config PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET + hex "PHY data partition offset" if PARTITION_TABLE_CUSTOM + depends on ESP32_PHY_INIT_DATA_IN_PARTITION + default 0xf000 + help + If using a custom partition table, specify the offset in the flash + where 'make flash' should write the initial PHY data file. + config PARTITION_TABLE_FILENAME - string - default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP - default partitions_two_ota.csv if PARTITION_TABLE_TWO_OTA - default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM + string + default partitions_singleapp.csv if PARTITION_TABLE_SINGLE_APP + default partitions_two_ota.csv if PARTITION_TABLE_TWO_OTA + default PARTITION_TABLE_CUSTOM_FILENAME if PARTITION_TABLE_CUSTOM config APP_OFFSET - hex - default PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET if PARTITION_TABLE_CUSTOM - default 0x10000 # this is the factory app offset used by the default tables + hex + default PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET if PARTITION_TABLE_CUSTOM + default 0x10000 # this is the factory app offset used by the default tables + +config PHY_DATA_OFFSET + hex + default PARTITION_TABLE_CUSTOM_PHY_DATA_OFFSET if PARTITION_TABLE_CUSTOM + default 0xf000 # this is the factory app offset used by the default tables endmenu diff --git a/components/partition_table/gen_esp32part.py b/components/partition_table/gen_esp32part.py index cb6a5f24a1..5ead13adc7 100755 --- a/components/partition_table/gen_esp32part.py +++ b/components/partition_table/gen_esp32part.py @@ -116,7 +116,8 @@ class PartitionDefinition(object): "app" : APP_TYPE, "data" : DATA_TYPE, } - + + # Keep this map in sync with esp_partition_subtype_t enum in esp_partition.h SUBTYPES = { APP_TYPE : { "factory" : 0x00, @@ -124,8 +125,11 @@ class PartitionDefinition(object): }, DATA_TYPE : { "ota" : 0x00, - "rf" : 0x01, - "wifi" : 0x02, + "phy" : 0x01, + "nvs" : 0x02, + "esphttpd" : 0x80, + "fat" : 0x81, + "spiffs" : 0x82, }, } diff --git a/components/partition_table/partitions_singleapp.csv b/components/partition_table/partitions_singleapp.csv index 940b8a76c4..e1647008ee 100644 --- a/components/partition_table/partitions_singleapp.csv +++ b/components/partition_table/partitions_singleapp.csv @@ -1,4 +1,5 @@ # Name, Type, SubType, Offset, Size +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x6000 +phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M -rfdata, data, rf, , 256K -wifidata, data, wifi, , 256K diff --git a/components/partition_table/partitions_two_ota.csv b/components/partition_table/partitions_two_ota.csv index 8e064e14b2..afb43967a3 100644 --- a/components/partition_table/partitions_two_ota.csv +++ b/components/partition_table/partitions_two_ota.csv @@ -1,7 +1,8 @@ # Name, Type, SubType, Offset, Size +# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild +nvs, data, nvs, 0x9000, 0x4000 +otadata, data, ota, 0xd000, 0x2000 +phy_init, data, phy, 0xf000, 0x1000 factory, 0, 0, 0x10000, 1M ota_0, 0, ota_0, , 1M ota_1, 0, ota_1, , 1M -rfdata, data, rf, , 256K -wifidata, data, wifi, , 256K -otadata, data, ota, , 256K diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index 134e1fe65b..3358c550f2 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -135,6 +135,12 @@ esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t si if (size % 4 != 0) { return ESP_ERR_INVALID_SIZE; } + if ((uint32_t) src < 0x3ff00000) { + // if source address is in DROM, we won't be able to read it + // from within SPIWrite + // TODO: consider buffering source data using heap and writing it anyway? + return ESP_ERR_INVALID_ARG; + } // Out of bound writes are checked in ROM code, but we can give better // error code here if (dest_addr + size > g_rom_flashchip.chip_size) { diff --git a/components/spi_flash/include/esp_partition.h b/components/spi_flash/include/esp_partition.h index ae0185dcd7..13b803e10f 100644 --- a/components/spi_flash/include/esp_partition.h +++ b/components/spi_flash/include/esp_partition.h @@ -25,57 +25,78 @@ extern "C" { #endif +/** + * @file esp_partition.h + * @brief Partition APIs + */ + + +/** + * @brief Partition type + * @note Keep this enum in sync with PartitionDefinition class gen_esp32part.py + */ typedef enum { - ESP_PARTITION_TYPE_APP = 0x00, - ESP_PARTITION_TYPE_DATA = 0x01, - ESP_PARTITION_TYPE_FILESYSTEM = 0x02, + ESP_PARTITION_TYPE_APP = 0x00, //!< Application partition type + ESP_PARTITION_TYPE_DATA = 0x01, //!< Data partition type } esp_partition_type_t; +/** + * @brief Partition subtype + * @note Keep this enum in sync with PartitionDefinition class gen_esp32part.py + */ typedef enum { - ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, - ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, - ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, - ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, - ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, - ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, - ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, - ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, - ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, - ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, - ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, - ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, - ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10, - ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11, - ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12, - ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13, - ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14, - ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15, - ESP_PARTITION_SUBTYPE_APP_OTA_MAX = 15, - ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, + ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, //!< Factory application partition + ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, //!< Base for OTA partition subtypes + ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, //!< OTA partition 0 + ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, //!< OTA partition 1 + ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, //!< OTA partition 2 + ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, //!< OTA partition 3 + ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, //!< OTA partition 4 + ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, //!< OTA partition 5 + ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, //!< OTA partition 6 + ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, //!< OTA partition 7 + ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, //!< OTA partition 8 + ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, //!< OTA partition 9 + ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10,//!< OTA partition 10 + ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11,//!< OTA partition 11 + ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12,//!< OTA partition 12 + ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13,//!< OTA partition 13 + ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14,//!< OTA partition 14 + ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15,//!< OTA partition 15 + ESP_PARTITION_SUBTYPE_APP_OTA_MAX = 15, //!< Max subtype of OTA partition + ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, //!< Test application partition - ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, - ESP_PARTITION_SUBTYPE_DATA_RF = 0x01, - ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, + ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, //!< OTA selection partition + ESP_PARTITION_SUBTYPE_DATA_PHY = 0x01, //!< PHY init data partition + ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, //!< NVS partition - ESP_PARTITION_SUBTYPE_FILESYSTEM_ESPHTTPD = 0x00, - ESP_PARTITION_SUBTYPE_FILESYSTEM_FAT = 0x01, - ESP_PARTITION_SUBTYPE_FILESYSTEM_SPIFFS = 0x02, + ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition + ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition + ESP_PARTITION_SUBTYPE_DATA_SPIFFS = 0x82, //!< SPIFFS partition - ESP_PARTITION_SUBTYPE_ANY = 0xff, + ESP_PARTITION_SUBTYPE_ANY = 0xff, //!< Used to search for partitions with any subtype } esp_partition_subtype_t; +/** + * @brief Convenience macro to get esp_partition_subtype_t value for the i-th OTA partition + */ #define ESP_PARTITION_SUBTYPE_OTA(i) ((esp_partition_subtype_t)(ESP_PARTITION_SUBTYPE_APP_OTA_MIN + ((i) & 0xf))) - +/** + * @brief Opaque partition iterator type + */ typedef struct esp_partition_iterator_opaque_* esp_partition_iterator_t; +/** + * @brief partition information structure + */ typedef struct { - esp_partition_type_t type; - esp_partition_subtype_t subtype; - uint32_t address; - uint32_t size; - char label[17]; - bool encrypted; + esp_partition_type_t type; /*!< partition type (app/data) */ + esp_partition_subtype_t subtype; /*!< partition subtype */ + uint32_t address; /*!< starting address of the partition in flash */ + uint32_t size; /*!< size of the partition, in bytes */ + char label[17]; /*!< partition label, zero-terminated ASCII string */ + bool encrypted; /*!< flag is set to true if partition is encrypted */ } esp_partition_t; /** diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index 840bbc4971..f940c0ad50 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -62,13 +62,13 @@ esp_err_t spi_flash_erase_sector(size_t sector); /** * @brief Erase a range of flash sectors * - * @param uint32_t start_address : Address where erase operation has to start. + * @param start_address Address where erase operation has to start. * Must be 4kB-aligned - * @param uint32_t size : Size of erased range, in bytes. Must be divisible by 4kB. + * @param size Size of erased range, in bytes. Must be divisible by 4kB. * * @return esp_err_t */ -esp_err_t spi_flash_erase_range(size_t start_addr, size_t size); +esp_err_t spi_flash_erase_range(size_t start_address, size_t size); /** @@ -76,6 +76,8 @@ esp_err_t spi_flash_erase_range(size_t start_addr, size_t size); * * @note Address in flash, dest, has to be 4-byte aligned. * This is a temporary limitation which will be removed. + * @note If source address is in DROM, this function will return + * ESP_ERR_INVALID_ARG. * * @param dest destination address in Flash * @param src pointer to the source buffer diff --git a/components/tcpip_adapter/include/tcpip_adapter.h b/components/tcpip_adapter/include/tcpip_adapter.h index e847016884..45d6ade305 100644 --- a/components/tcpip_adapter/include/tcpip_adapter.h +++ b/components/tcpip_adapter/include/tcpip_adapter.h @@ -372,6 +372,19 @@ wifi_interface_t tcpip_adapter_get_wifi_if(void *dev); */ esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapter_sta_list_t *tcpip_sta_list); +#define TCPIP_HOSTNAME_MAX_SIZE 31 +/** + * @brief Set the hostname to the interface + * + * @param[in] tcpip_if: the interface which we will set the hostname + * @param[in] hostname: the host name for set the interfce + * + * @return ESP_OK:success + * ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY:interface status error + * ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS:parameter error + */ +esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname); + #ifdef __cplusplus } #endif diff --git a/components/tcpip_adapter/tcpip_adapter_lwip.c b/components/tcpip_adapter/tcpip_adapter_lwip.c index 9b6e9d94fa..3edc90509e 100644 --- a/components/tcpip_adapter/tcpip_adapter_lwip.c +++ b/components/tcpip_adapter/tcpip_adapter_lwip.c @@ -607,4 +607,32 @@ esp_err_t tcpip_adapter_get_sta_list(wifi_sta_list_t *wifi_sta_list, tcpip_adapt return ESP_OK; } +esp_err_t tcpip_adapter_set_hostname(tcpip_adapter_if_t tcpip_if, const char *hostname) +{ + struct netif *p_netif; + static char hostinfo[TCPIP_HOSTNAME_MAX_SIZE + 1]; + + if (tcpip_if >= TCPIP_ADAPTER_IF_MAX || hostname == NULL) { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + } + + if (strlen(hostname) >= TCPIP_HOSTNAME_MAX_SIZE) { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + } + + p_netif = esp_netif[tcpip_if]; + if (p_netif != NULL) { + if (netif_is_up(p_netif)) { + return ESP_ERR_TCPIP_ADAPTER_IF_NOT_READY; + } else { + memset(hostinfo, 0, sizeof(hostinfo)); + memcpy(hostinfo, hostname, strlen(hostname)); + p_netif->hostname = hostinfo; + return ESP_OK; + } + } else { + return ESP_ERR_TCPIP_ADAPTER_INVALID_PARAMS; + } +} + #endif diff --git a/components/vfs/include/esp_vfs.h b/components/vfs/include/esp_vfs.h index 2d9e52c5af..7dd273fb00 100644 --- a/components/vfs/include/esp_vfs.h +++ b/components/vfs/include/esp_vfs.h @@ -57,15 +57,15 @@ extern "C" { * flags member to ESP_VFS_FLAG_CONTEXT_PTR and provide the context pointer * to esp_vfs_register function. * If the implementation doesn't use this extra argument, populate the - * members without _p suffix and set flags memeber to ESP_VFS_FLAG_DEFAULT. + * members without _p suffix and set flags member to ESP_VFS_FLAG_DEFAULT. * * If the FS driver doesn't provide some of the functions, set corresponding * members to NULL. */ typedef struct { - int fd_offset; - int flags; + int fd_offset; /*!< file descriptor offset, determined by the FS driver */ + int flags; /*!< ESP_VFS_FLAG_CONTEXT_PTR or ESP_VFS_FLAG_DEFAULT */ union { size_t (*write_p)(void* p, int fd, const void * data, size_t size); size_t (*write)(int fd, const void * data, size_t size); @@ -135,7 +135,7 @@ esp_err_t esp_vfs_register(const char* base_path, const esp_vfs_t* vfs, void* ct * These functions are to be used in newlib syscall table. They will be called by * newlib when it needs to use any of the syscalls. */ - +/**@{*/ ssize_t esp_vfs_write(struct _reent *r, int fd, const void * data, size_t size); off_t esp_vfs_lseek(struct _reent *r, int fd, off_t size, int mode); ssize_t esp_vfs_read(struct _reent *r, int fd, void * dst, size_t size); @@ -146,7 +146,7 @@ int esp_vfs_stat(struct _reent *r, const char * path, struct stat * st); int esp_vfs_link(struct _reent *r, const char* n1, const char* n2); int esp_vfs_unlink(struct _reent *r, const char *path); int esp_vfs_rename(struct _reent *r, const char *src, const char *dst); - +/**@}*/ #ifdef __cplusplus diff --git a/docs/Doxyfile b/docs/Doxyfile index 6ff4c45860..1f53a85931 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,6 +1,14 @@ PROJECT_NAME = "ESP32 Programming Guide" -INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver ../components/bt/include ../components/nvs_flash/include ../components/log/include ../components/vfs/include +INPUT = ../components/esp32/include/esp_wifi.h \ + ../components/driver/include/driver \ + ../components/bt/include \ + ../components/nvs_flash/include \ + ../components/log/include \ + ../components/vfs/include \ + ../components/spi_flash/include \ + ../components/esp32/include/esp_int_wdt.h \ + ../components/esp32/include/esp_task_wdt.h WARN_NO_PARAMDOC = YES @@ -14,9 +22,8 @@ XML_OUTPUT = xml GENERATE_HTML = NO HAVE_DOT = NO GENERATE_LATEX = NO -GENERATE_MAN = NO +GENERATE_MAN = YES GENERATE_RTF = NO -QUIET = YES WARN_LOGFILE = "doxygen-warning-log.txt" diff --git a/docs/api/nvs_flash.rst b/docs/api/nvs_flash.rst index 0768fa5597..5d36343552 100644 --- a/docs/api/nvs_flash.rst +++ b/docs/api/nvs_flash.rst @@ -3,7 +3,10 @@ Application Example ------------------- -`Instructions `_ +Two examples are provided in ESP-IDF examples directory: + +- `07_nvs_rw_value `_ demostrates how to read and write integer values +- `08_nvs_rw_blob `_ demostrates how to read and write variable length binary values API Reference ------------- diff --git a/docs/api/spi_flash.rst b/docs/api/spi_flash.rst new file mode 100644 index 0000000000..5903c0902d --- /dev/null +++ b/docs/api/spi_flash.rst @@ -0,0 +1,67 @@ +.. include:: ../../components/spi_flash/README.rst + +Application Example +------------------- + +`Instructions`_ + +.. _Instructions: template.html + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `spi_flash/include/esp_spi_flash.h `_ + * `spi_flash/include/esp_partition.h `_ + +Macros +^^^^^^ + +.. doxygendefine:: ESP_ERR_FLASH_BASE +.. doxygendefine:: ESP_ERR_FLASH_OP_FAIL +.. doxygendefine:: ESP_ERR_FLASH_OP_TIMEOUT +.. doxygendefine:: SPI_FLASH_SEC_SIZE +.. doxygendefine:: ESP_PARTITION_SUBTYPE_OTA + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: spi_flash_mmap_handle_t +.. doxygentypedef:: esp_partition_iterator_t + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: spi_flash_mmap_memory_t +.. doxygenenum:: esp_partition_type_t +.. doxygenenum:: esp_partition_subtype_t + +Structures +^^^^^^^^^^ + +.. doxygenstruct:: esp_partition_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: spi_flash_init +.. doxygenfunction:: spi_flash_get_chip_size +.. doxygenfunction:: spi_flash_erase_sector +.. doxygenfunction:: spi_flash_erase_range +.. doxygenfunction:: spi_flash_write +.. doxygenfunction:: spi_flash_read +.. doxygenfunction:: spi_flash_mmap +.. doxygenfunction:: spi_flash_munmap +.. doxygenfunction:: spi_flash_mmap_dump +.. doxygenfunction:: esp_partition_find +.. doxygenfunction:: esp_partition_find_first +.. doxygenfunction:: esp_partition_get +.. doxygenfunction:: esp_partition_next +.. doxygenfunction:: esp_partition_iterator_release +.. doxygenfunction:: esp_partition_read +.. doxygenfunction:: esp_partition_write +.. doxygenfunction:: esp_partition_erase_range +.. doxygenfunction:: esp_partition_mmap + diff --git a/docs/api/wdts.rst b/docs/api/wdts.rst new file mode 100644 index 0000000000..1b476f2f79 --- /dev/null +++ b/docs/api/wdts.rst @@ -0,0 +1,72 @@ +Watchdogs +========= + +Overview +-------- + +Esp-idf has support for two types of watchdogs: a task watchdog as well as an interrupt watchdog. Both can be +enabled using ``make menuconfig`` and selecting the appropriate options. + +Interrupt watchdog +^^^^^^^^^^^^^^^^^^ + +The interrupt watchdog makes sure the FreeRTOS task switching interrupt isn't blocked for a long time. This +is bad because no other tasks, including potentially important ones like the WiFi task and the idle task, +can't get any CPU runtime. A blocked task switching interrupt can happen because a program runs into an +infinite loop with interrupts disabled or hangs in an interrupt. + +The default action of the interrupt watchdog is to invoke the panic handler. causing a register dump and an opportunity +for the programmer to find out, using either OpenOCD or gdbstub, what bit of code is stuck with interrupts +disabled. Depending on the configuration of the panic handler, it can also blindly reset the CPU, which may be +preferred in a production environment. + +The interrupt watchdog is built around the hardware watchdog in timer group 1. If this watchdog for some reason +cannot execute the NMI handler that invokes the panic handler (e.g. because IRAM is overwritten by garbage), +it will hard-reset the SOC. + +Task watchdog +^^^^^^^^^^^^^ + +Any tasks can elect to be watched by the task watchdog. If such a task does not feed the watchdog within the time +specified by the task watchdog timeout (which is configurable using ``make menuconfig``), the watchdog will +print out a warning with information about which processes are running on the ESP32 CPUs and which processes +failed to feed the watchdog. + +By default, the task watchdog watches the idle tasks. The usual cause of idle tasks not feeding the watchdog +is a higher-priority process looping without yielding to the lower-priority processes, and can be an indicator +of badly-written code that spinloops on a peripheral or a task that is stuck in an infinite loop. + +Other task can elect to be watched by the task watchdog by calling ``esp_task_wdt_feed()``. Calling this routine +for the first time will register the task to the task watchdog; calling it subsequent times will feed +the watchdog. If a task does not want to be watched anymore (e.g. because it is finished and will call +``vTaskDelete()`` on itself), it needs to call ``esp_task_wdt_delete()``. + +The task watchdog is built around the hardware watchdog in timer group 0. If this watchdog for some reason +cannot execute the interrupt handler that prints the task data (e.g. because IRAM is overwritten by garbage +or interrupts are disabled entirely) it will hard-reset the SOC. + +JTAG and watchdogs +^^^^^^^^^^^^^^^^^^ + +While debugging using OpenOCD, if the CPUs are halted the watchdogs will keep running, eventually resetting the +CPU. This makes it very hard to debug code; that is why the OpenOCD config will disable both watchdogs on startup. +This does mean that you will not get any warnings or panics from either the task or interrupt watchdog when the ESP32 +is connected to OpenOCD via JTAG. + +API Reference +------------- + +Header Files +^^^^^^^^^^^^ + + * `esp32/include/esp_int_wdt.h `_ + * `esp32/include/esp_task_wdt.h `_ + + +Functions +--------- + +.. doxygenfunction:: esp_int_wdt_init +.. doxygenfunction:: esp_task_wdt_init +.. doxygenfunction:: esp_task_wdt_feed +.. doxygenfunction:: esp_task_wdt_delete diff --git a/docs/build_system.rst b/docs/build_system.rst index 8168cb76ef..aa14cdda56 100644 --- a/docs/build_system.rst +++ b/docs/build_system.rst @@ -186,6 +186,14 @@ The following variables can be set inside ``component.mk`` to control build sett generates an include file which you then want to include in another component. Most components do not need to set this variable. +The following variable only works for components that are part of esp-idf itself: + +- ``COMPONENT_SUBMODULES``: Optional list of git submodule paths + (relative to COMPONENT_PATH) used by the component. These will be + checked (and initialised if necessary) by the build process. This + variable is ignored if the component is outside the IDF_PATH + directory. + Optional Component-Specific Variables ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/doxygen_xml_to_rst.xslt b/docs/doxygen_xml_to_rst.xslt new file mode 100644 index 0000000000..c4570a9df6 --- /dev/null +++ b/docs/doxygen_xml_to_rst.xslt @@ -0,0 +1,56 @@ + + + + + + + + + Macros + ^^^^^^ + + .. doxygendefine:: + + + + + + Type Definitions + ^^^^^^^^^^^^^^^^ + + .. doxygentypedef:: + + + + + + Enumerations + ^^^^^^^^^^^^ + + .. doxygenenum:: + + + + + + + Structures + ^^^^^^^^^^ + + .. doxygenstruct:: + + + + + + Functions + ^^^^^^^^^ + + .. doxygenfunction:: + + + + + + + diff --git a/docs/general-notes.rst b/docs/general-notes.rst new file mode 100644 index 0000000000..a683467007 --- /dev/null +++ b/docs/general-notes.rst @@ -0,0 +1,125 @@ +General Notes About ESP-IDF Programming +======================================= + +Application startup flow +------------------------ + +This note explains various steps which happen before ``app_main`` function of an ESP-IDF application is called. + +The high level view of startup process is as follows: + +1. First-stage bootloader in ROM loads second-stage bootloader image to RAM (IRAM & DRAM) from flash offset 0x1000. +2. Second-stage bootloader loads partition table and main app image from flash. Main app incorporates both RAM segments and read-only segments mapped via flash cache. +3. Main app image executes. At this point the second CPU and RTOS scheduler can be started. + +This process is explained in detail in the following sections. + +First stage bootloader +^^^^^^^^^^^^^^^^^^^^^^ + +After SoC reset, PRO CPU will start running immediately, executing reset vector code, while APP CPU will be held in reset. During startup process, PRO CPU does all the initialization. APP CPU reset is de-asserted in the ``call_start_cpu0`` function of application startup code. Reset vector code is located at address 0x40000400 in the mask ROM of the ESP32 chip and can not be modified. + +Startup code called from the reset vector determines the boot mode by checking ``GPIO_STRAP_REG`` register for bootstrap pin states. Depending on the reset reason, the following takes place: + +1. Reset from deep sleep: if the value in ``RTC_CNTL_STORE6_REG`` is non-zero, and CRC value of RTC memory in ``RTC_CNTL_STORE7_REG`` is valid, use ``RTC_CNTL_STORE6_REG`` as an entry point address and jump immediately to it. If ``RTC_CNTL_STORE6_REG`` is zero, or ``RTC_CNTL_STORE7_REG`` contains invalid CRC, or once the code called via ``RTC_CNTL_STORE6_REG`` returns, proceed with boot as if it was a power-on reset. **Note**: to run customized code at this point, a deep sleep stub mechanism is provided. Please see :doc:`deep sleep ` documentation for this. + +2. For power-on reset, software SOC reset, and watchdog SOC reset: check the ``GPIO_STRAP_REG`` register if UART or SDIO download mode is requested. If this is the case, configure UART or SDIO, and wait for code to be downloaded. Otherwise, proceed with boot as if it was due to software CPU reset. + +3. For software CPU reset and watchdog CPU reset: configure SPI flash based on EFUSE values, and attempt to load the code from flash. This step is described in more detail in the next paragraphs. If loading code from flash fails, unpack BASIC interpreter into the RAM and start it. Note that RTC watchdog is still enabled when this happens, so unless any input is received by the interpreter, watchdog will reset the SOC in a few hundred milliseconds, repeating the whole process. If the interpreter receives any input from the UART, it disables the watchdog. + +Application binary image is loaded from flash starting at address 0x1000. First 4kB sector of flash is used to store secure boot IV and signature of the application image. Please check secure boot documentation for details about this. + +.. TODO: describe application binary image format, describe optional flash configuration commands. + +Second stage bootloader +^^^^^^^^^^^^^^^^^^^^^^^ + +In ESP-IDF, the binary image which resides at offset 0x1000 in flash is the second stage bootloader. Second stage bootloader source code is available in components/bootloader directory of ESP-IDF. Note that this arrangement is not the only one possible with the ESP32 chip. It is possible to write a fully featured application which would work when flashed to offset 0x1000, but this is out of scope of this document. Second stage bootloader is used in ESP-IDF to add flexibility to flash layout (using partition tables), and allow for various flows associated with flash encryption, secure boot, and over-the-air updates (OTA) to take place. + +When the first stage bootloader is finished checking and loading the second stage bootloader, it jumps to the second stage bootloader entry point found in the binary image header. + +Second stage bootloader reads the partition table found at offset 0x8000. See :doc:`partition tables ` documentation for more information. The bootloader finds factory and OTA partitions, and decides which one to boot based on data found in *OTA info* partition. + +For the selected partition, second stage bootloader copies data and code sections which are mapped into IRAM and DRAM to their load addresses. For sections which have load addresses in DROM and IROM regions, flash MMU is configured to provide the correct mapping. Note that the second stage bootloader configures flash MMU for both PRO and APP CPUs, but it only enables flash MMU for PRO CPU. Reason for this is that second stage bootloader code is loaded into the memory region used by APP CPU cache. The duty of enabling cache for APP CPU is passed on to the application. Once code is loaded and flash MMU is set up, second stage bootloader jumps to the application entry point found in the binary image header. + +Currently it is not possible to add application-defined hooks to the bootloader to customize application partition selection logic. This may be required to load different application image depending on a state of a GPIO, for example. Such customization features will be added to ESP-IDF in the future. For now, bootloader can be customized by copying bootloader component into application directory and making necessary changes there. ESP-IDF build system will compile the component in application directory instead of ESP-IDF components directory in this case. + +Application startup +^^^^^^^^^^^^^^^^^^^ + +ESP-IDF application entry point is ``call_start_cpu0`` function found in ``components/esp32/cpu_start.c``. Two main things this function does are to enable heap allocator and to make APP CPU jump to its entry point, ``call_start_cpu1``. The code on PRO CPU sets the entry point for APP CPU, de-asserts APP CPU reset, and waits for a global flag to be set by the code running on APP CPU, indicating that it has started. Once this is done, PRO CPU jumps to ``start_cpu0`` function, and APP CPU jumps to ``start_cpu1`` function. + +Both ``start_cpu0`` and ``start_cpu1`` are weak functions, meaning that they can be overridden in the application, if some application-specific change to initialization sequence is needed. Default implementation of ``start_cpu0`` enables or initializes components depending on choices made in ``menuconfig``. Please see source code of this function in ``components/esp32/cpu_start.c`` for an up to date list of steps performed. Note that any C++ global constructors present in the application will be called at this stage. Once all essential components are initialized, *main task* is created and FreeRTOS scheduler is started. + +While PRO CPU does initialization in ``start_cpu0`` function, APP CPU spins in ``start_cpu1`` function, waiting for the scheduler to be started on the PRO CPU. Once the scheduler is started on the PRO CPU, code on the APP CPU starts the scheduler as well. + +Main task is the task which runs ``app_main`` function. Main task stack size and priority can be configured in ``menuconfig``. Application can use this task for initial application-specific setup, for example to launch other tasks. Application can also use main task for event loops and other general purpose activities. If ``app_main`` function returns, main task is deleted. + + +Application memory layout +------------------------- + +ESP32 chip has flexible memory mapping features. This section describes how ESP-IDF uses these features by default. + +Application code in ESP-IDF can be placed into one of the following memory regions. + +IRAM (instruction RAM) +^^^^^^^^^^^^^^^^^^^^^^ + +ESP-IDF allocates part of `Internal SRAM0` region (defined in the Technical Reference Manual) for instruction RAM. Except for the first 64 kB block which is used for PRO and APP CPU caches, the rest of this memory range (i.e. from ``0x40080000`` to ``0x400A0000``) is used to store parts of application which need to run from RAM. + +A few components of ESP-IDF and parts of WiFi stack are placed into this region using the linker script. + +If some application code needs to be placed into IRAM, it can be done using ``IRAM_ATTR`` define:: + + #include "esp_attr.h" + + void IRAM_ATTR gpio_isr_handler(void* arg) + { + // ... + } + +Here are the cases when parts of application may or should be placed into IRAM. + +- ISR handlers must always be placed into IRAM. Furthermore, ISR handlers may only call functions placed into IRAM or functions present in ROM. *Note 1:* all FreeRTOS APIs are currently placed into IRAM, so are safe to call from ISR handlers. *Note 1:* all constant data used by ISR handlers and functions called from ISR handlers (including, but not limited to, ``const char`` arrays), must be placed into DRAM using ``DRAM_ATTR``. + +- Some timing critical code may be placed into IRAM to reduce the penalty associated with loading the code from flash. ESP32 reads code and data from flash via a 32 kB cache. In some cases, placing a function into IRAM may reduce delays caused by a cache miss. + +IROM (code executed from Flash) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If a function is not explicitly placed into IRAM or RTC memory, it is placed into flash. The mechanism by which Flash MMU is used to allow code execution from flash is described in the Technical Reference Manual. ESP-IDF places the code which should be executed from flash starting from the beginning of ``0x400D0000 — 0x40400000`` region. Upon startup, second stage bootloader initializes Flash MMU to map the location in flash where code is located into the beginning of this region. Access to this region is transparently cached using two 32kB blocks in ``0x40070000`` — ``0x40080000`` range. + +Note that the code outside ``0x40000000 — 0x40400000`` region may not be reachable with Window ABI ``CALLx`` instructions, so special care is required if ``0x40400000 — 0x40800000`` or ``0x40800000 — 0x40C00000`` regions are used by the application. ESP-IDF doesn't use these regions by default. + +RTC fast memory +^^^^^^^^^^^^^^^ + +The code which has to run after wake-up from deep sleep mode has to be placed into RTC memory. Please check detailed description in :doc:`deep sleep ` documentation. + +DRAM (data RAM) +^^^^^^^^^^^^^^^ + +Non-constant static data and zero-initialized data is placed by the linker into 200 kB ``0x3FFB0000 — 0x3FFF0000`` region. Note that this region is reduced by 64kB (by shifting start address to ``0x3FFC0000``) if Bluetooth stack is used. Length of this region is also reduced by 16 kB or 32kB if trace memory is used. All space which is left in this region after placing static data there is used for the runtime heap. + +Constant data may also be placed into DRAM, for example if it is used in an ISR handler (see notes in IRAM section above). To do that, ``DRAM_ATTR`` define can be used:: + + DRAM_ATTR const char[] format_string = "%p %x"; + char buffer[64]; + sprintf(buffer, format_string, ptr, val); + +Needless to say, it is not advised to use ``printf`` and other output functions in ISR handlers. For debugging purposes, use ``ESP_EARLY_LOGx`` macros when logging from ISR handlers. Make sure that both ``TAG`` and format string are placed into ``DRAM`` in that case. + +DROM (data stored in Flash) +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +By default, constant data is placed by the linker into a 4 MB region (``0x3F400000 — 0x3F800000``) which is used to access external flash memory via Flash MMU and cache. Exceptions to this are literal constants which are embedded by the compiler into application code. + +RTC slow memory +^^^^^^^^^^^^^^^ + +Global and static variables used by code which runs from RTC memory (i.e. deep sleep stub code) must be placed into RTC slow memory. Please check detailed description in :doc:`deep sleep ` documentation. + + + + diff --git a/docs/index.rst b/docs/index.rst index 1ca6e28eec..8bc7a72f29 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -28,6 +28,7 @@ Contents: :caption: What Else? :maxdepth: 1 + General Notes partition-tables build_system openocd @@ -42,9 +43,9 @@ Contents: 1.2. Application startup flow - TBA 1.3. Flash encryption and secure boot: how they work and APIs - TBA 1.4. Lower Power Coprocessor - TBA - 1.5. Watchdogs + 1.5. Watchdogs 1.6. ... - 2. Memeory - TBA + 2. Memory - TBA 2.1. Memory layout of the application (IRAM/IROM, limitations of each) - TBA 2.2. Flash layout and partitions - TBA 2.3. Flash access APIs - TBA @@ -92,11 +93,12 @@ Contents: Wi-Fi Bluetooth + Watchdogs api/gpio api/uart api/ledc - + SPI Flash and Partition APIs Logging Non-Volatile Storage Virtual Filesystem diff --git a/docs/openocd.rst b/docs/openocd.rst index 2dcb55f0c5..642e3067e1 100644 --- a/docs/openocd.rst +++ b/docs/openocd.rst @@ -40,10 +40,8 @@ Installing OpenOCD The sources for the ESP32-enabled variant of OpenOCD are available from `Espressifs Github `_. To download the source, use the following commands:: - git clone https://github.com/espressif/openocd-esp32.git + git clone --recursive https://github.com/espressif/openocd-esp32.git cd openocd-esp32 - git submodule init - git submodule update For compilation of OpenOCD, please refer to the README, README.OSX and README.Windows file in the openocd-esp32 directory. You can skip the ``make install`` step if you want. diff --git a/docs/partition-tables.rst b/docs/partition-tables.rst index 5f5911bd52..c9709029d8 100644 --- a/docs/partition-tables.rst +++ b/docs/partition-tables.rst @@ -17,40 +17,30 @@ The simplest way to use the partition table is to `make menuconfig` and choose o In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. -Known Issues ------------- - -The below design document outlines the goals for the partition table system. At the moment, only some features are used: - -- data partition types "rf" & "wifi" are unused and can be entirely omitted to save space. -- NVS (non-volatile-storage) uses a hardcoded 12KB (0x3000 byte) region at offset 0x6000. - -Once a full user API is in place for partition access, these limitations will be resolved and you'll be able to use the partition mechanism fully for storing data in flash. - Built-in Partition Tables ------------------------- Here is the summary printed for the "Single factory app, no OTA" configuration:: # Espressif ESP32 Partition Table - # Name, Type, SubType, Offset, Size - factory, app, factory, 0x10000, 1M - rfdata, data, rf, 0x110000, 256K - wifidata,data, wifi, 0x150000, 256K + # Name, Type, SubType, Offset, Size + nvs, data, nvs, 0x9000, 0x6000 + phy_init, data, phy, 0xf000, 0x1000 + factory, app, factory, 0x10000, 1M * At a 0x10000 (64KB) offset in the flash is the app labelled "factory". The bootloader will run this app by default. -* There are also two data regions defined in the partition table for storing RF & Wifi calibration data. +* There are also two data regions defined in the partition table for storing NVS library partition and PHY init data. Here is the summary printed for the "Factory app, two OTA definitions" configuration:: # Espressif ESP32 Partition Table - # Name, Type, SubType, Offset, Size - factory, app, factory, 0x10000, 1M - ota_0, app, ota_0, 0x110000, 1M - ota_1, app, ota_1, 0x210000, 1M - rfdata, data, rf, 0x310000, 256K - wifidata,data, wifi, 0x350000, 256K - otadata, data, ota, 0x390000, 256K + # Name, Type, SubType, Offset, Size + nvs, data, nvs, 0x9000, 0x4000 + otadata, data, ota, 0xd000, 0x2000 + phy_init, data, phy, 0xf000, 0x1000 + factory, 0, 0, 0x10000, 1M + ota_0, 0, ota_0, , 1M + ota_1, 0, ota_1, , 1M * There are now three app partition definitions. * The type of all three are set as "app", but the subtype varies between the factory app at 0x10000 and the next two "OTA" apps. @@ -65,13 +55,13 @@ If you choose "Custom partition table CSV" in menuconfig then you can also enter The CSV format is the same format as printed in the summaries shown above. However, not all fields are required in the CSV. For example, here is the "input" CSV for the OTA partition table:: # Name, Type, SubType, Offset, Size + nvs, data, nvs, 0x9000, 0x4000 + otadata, data, ota, 0xd000, 0x2000 + phy_init, data, phy, 0xf000, 0x1000 factory, app, factory, 0x10000, 1M ota_0, app, ota_0, , 1M ota_1, app, ota_1, , 1M - rfdata, data, rf, , 256K - wifidata, data, wifi, , 256K - otadata, data, ota, , 256K - + * Whitespace between fields is ignored, and so is any line starting with # (comments). * Each non-comment line in the CSV file is a partition definition. * Only the offset for the first partition is supplied. The gen_esp32part.py tool fills in each remaining offset to start after the preceding partition. @@ -93,7 +83,7 @@ Subtype When type is "app", the subtype field can be specified as factory (0), ota_0 (0x10) ... ota_15 (0x1F) and test (0x20). Or it can be any number 0-255 (0x00-0xFF). The bootloader will execute the factory app unless there it sees a partition of type data/ota, in which case it reads this partition to determine which OTA image to boot -When type is "data", the subtype field can be specified as ota (0), rf (1), wifi (2). Or it can be a number 0x00-0xFF. The bootloader ignores all data subtypes except for ota. Other "data" subtypes are reserved for Espressif use. To create custom data partition subtypes then use a custom type value, and choose any subtype 0x00-0xFF. +When type is "data", the subtype field can be specified as ota (0), phy (1), nvs (2). Or it can be a number 0x00-0xFF. The bootloader ignores all data subtypes except for ota. Subtypes 0-0x7f are reserved for Espressif use. To create custom data partition subtypes use "data" type, and choose any unused subtype in 0x80-0xFF range. If you are porting a filesystem to the ESP-IDF, consider opening a PR to add the new subtype to esp_partition.h file. Offset & Size ~~~~~~~~~~~~~ @@ -104,6 +94,8 @@ App partitions have to be at offsets aligned to 0x10000 (64K). If you leave the Sizes and offsets can be specified as decimal numbers, hex numbers with the prefix 0x, or size multipliers M or K (1024 and 1024*1024 bytes). +NVS data partition has to be at least 0x3000 bytes long, and OTA data parition has to be 0x2000 bytes long. If you are using NVS in your application to store a lot of data, consider using a custom partition table with larger NVS partition. + Generating Binary Partition Table --------------------------------- diff --git a/docs/security/secure-boot.rst b/docs/security/secure-boot.rst index bdc1b71699..b352b3964c 100644 --- a/docs/security/secure-boot.rst +++ b/docs/security/secure-boot.rst @@ -14,7 +14,7 @@ Background - Efuses are used to store the secure bootloader key (in efuse block 2), and also a single Efuse bit (ABS_DONE_0) is burned (written to 1) to permanently enable secure boot on the chip. For more details about efuse, see the (forthcoming) chapter in the Technical Reference Manual. -- To understand the secure boot process, first familiarise yourself with the standard `esp-idf boot process`. +- To understand the secure boot process, first familiarise yourself with the standard :doc:`ESP-IDF boot process <../general-notes>`. - Both stages of the boot process (initial software bootloader load, and subsequent partition & app loading) are verified by the secure boot process, in a "chain of trust" relationship. @@ -30,10 +30,11 @@ This is a high level overview of the secure boot process. Step by step instructi 2. The software bootloader image is built by esp-idf with secure boot support enabled and the public key (signature verification) portion of the secure boot signing key compiled in. This software bootloader image is flashed at offset 0x1000. 3. On first boot, the software bootloader follows the following process to enable secure boot: - - Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents. - - The secure digest is flashed at offset 0x0 in the flash. - - Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.) - - Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.) + + - Hardware secure boot support generates a device secure bootloader key (generated via hardware RNG, then stored read/write protected in efuse), and a secure digest. The digest is derived from the key, an IV, and the bootloader image contents. + - The secure digest is flashed at offset 0x0 in the flash. + - Depending on Secure Boot Configuration, efuses are burned to disable JTAG and the ROM BASIC interpreter (it is strongly recommended these options are turned on.) + - Bootloader permanently enables secure boot by burning the ABS_DONE_0 efuse. The software bootloader then becomes protected (the chip will only boot a bootloader image if the digest matches.) 4. On subsequent boots the ROM bootloader sees that the secure boot efuse is burned, reads the saved digest at 0x0 and uses hardware secure boot support to compare it with a newly calculated digest. If the digest does not match then booting will not continue. The digest and comparison are performed entirely by hardware, and the calculated digest is not readable by software. For technical details see `Hardware Secure Boot Support`. @@ -175,5 +176,4 @@ Deterministic ECDSA as specified by `RFC6979`. - Image signature is 68 bytes - a 4 byte version word (currently zero), followed by a 64 bytes of signature data. These 68 bytes are appended to an app image or partition table data. -.. _esp-idf boot process: ../boot-process.rst .. _RFC6979: https://tools.ietf.org/html/rfc6979 diff --git a/examples/01_hello_world/main/component.mk b/examples/01_hello_world/main/component.mk index 4d3b30caf3..0b9d7585e7 100644 --- a/examples/01_hello_world/main/component.mk +++ b/examples/01_hello_world/main/component.mk @@ -1,5 +1,5 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/02_blink/main/component.mk b/examples/02_blink/main/component.mk index b4fa72791c..a98f634eae 100644 --- a/examples/02_blink/main/component.mk +++ b/examples/02_blink/main/component.mk @@ -1,4 +1,4 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/03_http_request/main/component.mk b/examples/03_http_request/main/component.mk index b4fa72791c..a98f634eae 100644 --- a/examples/03_http_request/main/component.mk +++ b/examples/03_http_request/main/component.mk @@ -1,4 +1,4 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/04_https_request/main/component.mk b/examples/04_https_request/main/component.mk index f4502c25db..818e2a1822 100644 --- a/examples/04_https_request/main/component.mk +++ b/examples/04_https_request/main/component.mk @@ -1,5 +1,5 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/05_ble_adv/main/component.mk b/examples/05_ble_adv/main/component.mk index b4fa72791c..a98f634eae 100644 --- a/examples/05_ble_adv/main/component.mk +++ b/examples/05_ble_adv/main/component.mk @@ -1,4 +1,4 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/06_sntp/main/component.mk b/examples/06_sntp/main/component.mk index b4fa72791c..a98f634eae 100644 --- a/examples/06_sntp/main/component.mk +++ b/examples/06_sntp/main/component.mk @@ -1,4 +1,4 @@ # -# Main Makefile. This is basically the same as a component makefile. +# "main" pseudo-component makefile. # # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/07_nvs_rw_value/main/component.mk b/examples/07_nvs_rw_value/main/component.mk index d33485c26c..0b9d7585e7 100644 --- a/examples/07_nvs_rw_value/main/component.mk +++ b/examples/07_nvs_rw_value/main/component.mk @@ -1,2 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -include $(IDF_PATH)/make/component_common.mk diff --git a/examples/08_nvs_rw_blob/main/component.mk b/examples/08_nvs_rw_blob/main/component.mk index d33485c26c..0b9d7585e7 100644 --- a/examples/08_nvs_rw_blob/main/component.mk +++ b/examples/08_nvs_rw_blob/main/component.mk @@ -1,2 +1,5 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) -include $(IDF_PATH)/make/component_common.mk diff --git a/examples/09_openssl_client/Makefile b/examples/09_openssl_client/Makefile new file mode 100644 index 0000000000..7e2f4fe7f8 --- /dev/null +++ b/examples/09_openssl_client/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := openssl_client + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/09_openssl_client/README.md b/examples/09_openssl_client/README.md new file mode 100644 index 0000000000..2a6ac19881 --- /dev/null +++ b/examples/09_openssl_client/README.md @@ -0,0 +1,16 @@ +# Openssl Example + +The Example contains of OpenSSL client demo. + +First you should config the project by "make menuconfig": + Example Configuration -> + 1. Target Domain : the domain that you want to connect to, and default is "www.baidu.com". + 2. Target port number : the port number of the target domain, and default is 443. + 3. WIFI SSID : your own WIFI, which is connected to the Internet, and default is "myssid". + 4. WIFI Password : WIFI password, and default is "mypassword" + +If you want to test the OpenSSL client demo: + 1. compile the code and load the firmware + 2. open the UART TTY, then you can see it print the context of target domain + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/09_openssl_client/main/Kconfig.projbuild b/examples/09_openssl_client/main/Kconfig.projbuild new file mode 100644 index 0000000000..1767923ad1 --- /dev/null +++ b/examples/09_openssl_client/main/Kconfig.projbuild @@ -0,0 +1,28 @@ +menu "Example Configuration" + +config TARGET_DOMAIN + string "Target Domain" + default "www.baidu.com" + help + Target domain for the example to connect to. + +config TARGET_PORT_NUMBER + int "Target port number" + range 0 65535 + default 433 + help + Target port number for the example to connect to. + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu \ No newline at end of file diff --git a/examples/09_openssl_client/main/component.mk b/examples/09_openssl_client/main/component.mk new file mode 100644 index 0000000000..44bd2b5273 --- /dev/null +++ b/examples/09_openssl_client/main/component.mk @@ -0,0 +1,3 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# diff --git a/examples/09_openssl_client/main/openssl_client.c b/examples/09_openssl_client/main/openssl_client.c new file mode 100644 index 0000000000..c6b0e449ac --- /dev/null +++ b/examples/09_openssl_client/main/openssl_client.c @@ -0,0 +1,225 @@ +/* OpenSSL client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "openssl_client.h" + +#include + +#include "openssl/ssl.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" + +#include "nvs_flash.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" + +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const static int CONNECTED_BIT = BIT0; + +const static char *TAG = "Openssl_demo"; + +void openssl_demo_thread(void *p) +{ + int ret; + SSL_CTX *ctx; + SSL *ssl; + int socket; + struct sockaddr_in sock_addr; + struct hostent *hp; + struct ip4_addr *ip4_addr; + + int recv_bytes = 0; + char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + + const char send_data[] = OPENSSL_DEMO_REQUEST; + const int send_bytes = sizeof(send_data); + + ESP_LOGI(TAG, "OpenSSL demo thread start OK"); + + ESP_LOGI(TAG, "get target IP address"); + hp = gethostbyname(OPENSSL_DEMO_TARGET_NAME); + if (!hp) { + ESP_LOGI(TAG, "failed"); + goto failed1; + } + ESP_LOGI(TAG, "OK"); + + ip4_addr = (struct ip4_addr *)hp->h_addr; + ESP_LOGI(TAG, IPSTR, IP2STR(ip4_addr)); + + ESP_LOGI(TAG, "create SSL context ......"); + ctx = SSL_CTX_new(TLSv1_1_client_method()); + if (!ctx) { + ESP_LOGI(TAG, "failed"); + goto failed1; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "create socket ......"); + socket = socket(AF_INET, SOCK_STREAM, 0); + if (socket < 0) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "bind socket ......"); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = 0; + sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "socket connect to remote %s ......", OPENSSL_DEMO_TARGET_NAME); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = ip4_addr->addr; + sock_addr.sin_port = htons(OPENSSL_DEMO_TARGET_TCP_PORT); + ret = connect(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "create SSL ......"); + ssl = SSL_new(ctx); + if (!ssl) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + SSL_set_fd(ssl, socket); + + ESP_LOGI(TAG, "SSL connected to %s port %d ......", + OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + ret = SSL_connect(ssl); + if (!ret) { + ESP_LOGI(TAG, "failed " ); + goto failed4; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "send https request to %s port %d ......", + OPENSSL_DEMO_TARGET_NAME, OPENSSL_DEMO_TARGET_TCP_PORT); + ret = SSL_write(ssl, send_data, send_bytes); + if (ret <= 0) { + ESP_LOGI(TAG, "failed"); + goto failed5; + } + ESP_LOGI(TAG, "OK"); + + do { + ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + if (ret <= 0) { + break; + } + recv_bytes += ret; + ESP_LOGI(TAG, "%s", recv_buf); + } while (1); + + ESP_LOGI(TAG, "totaly read %d bytes data from %s ......", recv_bytes, OPENSSL_DEMO_TARGET_NAME); + +failed5: + SSL_shutdown(ssl); +failed4: + SSL_free(ssl); + ssl = NULL; +failed3: + close(socket); + socket = -1; +failed2: + SSL_CTX_free(ctx); + ctx = NULL; +failed1: + vTaskDelete(NULL); + return ; +} + +static void openssl_client_init(void) +{ + int ret; + xTaskHandle openssl_handle; + + ret = xTaskCreate(openssl_demo_thread, + OPENSSL_DEMO_THREAD_NAME, + OPENSSL_DEMO_THREAD_STACK_WORDS, + NULL, + OPENSSL_DEMO_THREAD_PRORIOTY, + &openssl_handle); + + if (ret != pdPASS) { + ESP_LOGI(TAG, "create thread %s failed", OPENSSL_DEMO_THREAD_NAME); + } +} + +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + openssl_client_init(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +static void wifi_conn_init(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]\n", EXAMPLE_WIFI_SSID, EXAMPLE_WIFI_PASS); + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +void app_main(void) +{ + nvs_flash_init(); + wifi_conn_init(); +} diff --git a/examples/09_openssl_client/main/openssl_client.h b/examples/09_openssl_client/main/openssl_client.h new file mode 100644 index 0000000000..f5ab887ad4 --- /dev/null +++ b/examples/09_openssl_client/main/openssl_client.h @@ -0,0 +1,43 @@ +/* OpenSSL client Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#ifndef _OPENSSL_DEMO_H_ +#define _OPENSSL_DEMO_H_ + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +/* The examples use domain of "www.baidu.com" and port number of 433 that + you can set via 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define OPENSSL_DEMO_TARGET_NAME "www.baidu.com" + and ie #define OPENSSL_DEMO_TARGET_TCP_PORT 433 +*/ +#define OPENSSL_DEMO_TARGET_NAME CONFIG_TARGET_DOMAIN +#define OPENSSL_DEMO_TARGET_TCP_PORT CONFIG_TARGET_PORT_NUMBER + +#define OPENSSL_DEMO_REQUEST "{\"path\": \"/v1/ping/\", \"method\": \"GET\"}\r\n" + +#define OPENSSL_DEMO_THREAD_NAME "OpenSSL_demo" +#define OPENSSL_DEMO_THREAD_STACK_WORDS 10240 +#define OPENSSL_DEMO_THREAD_PRORIOTY 8 + +#define OPENSSL_DEMO_RECV_BUF_LEN 1024 + +#define OPENSSL_DEMO_LOCAL_TCP_PORT 443 + +#endif + diff --git a/examples/10_openssl_server/Makefile b/examples/10_openssl_server/Makefile new file mode 100644 index 0000000000..f65f11a562 --- /dev/null +++ b/examples/10_openssl_server/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := openssl_server + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/10_openssl_server/README.md b/examples/10_openssl_server/README.md new file mode 100644 index 0000000000..333cb3d6a6 --- /dev/null +++ b/examples/10_openssl_server/README.md @@ -0,0 +1,21 @@ +# Openssl Example + +The Example contains of OpenSSL server demo. + +First you should configure the project by "make menuconfig": + Example Configuration -> + 1. WIFI SSID: WIFI network to which your PC is also connected to. + 1. WIFI Password: WIFI password + +IF you want to test the OpenSSL server demo: + 1. compile the code and load the firmware + 2. input the context of "https://192.168.17.128" into your web browser, the IP of your module may not be 192.168.17.128, you should input your module's IP + 3. You may see that it shows the website is not able to be trusted, but you should select that "go on to visit it" + 4. You should wait for a moment until your see the "OpenSSL server demo!" in your web browser + +Note: + The private key and certification at the example are not trusted by web browser, because they are not created by CA official, just by ourselves. + You can alse create your own private key and ceritification by "openssl at ubuntu or others". + We have the document of "ESP8266_SDKSSL_User_Manual_EN_v1.4.pdf" at "http://www.espressif.com/en/support/download/documents". By it you can gernerate the private key and certification with the fomate of ".pem" + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/10_openssl_server/main/Kconfig.projbuild b/examples/10_openssl_server/main/Kconfig.projbuild new file mode 100644 index 0000000000..7a9cb97a0e --- /dev/null +++ b/examples/10_openssl_server/main/Kconfig.projbuild @@ -0,0 +1,15 @@ +menu "Example Configuration" + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "mypassword" + help + WiFi password (WPA or WPA2) for the example to use. + +endmenu \ No newline at end of file diff --git a/examples/10_openssl_server/main/cacert.pem b/examples/10_openssl_server/main/cacert.pem new file mode 100644 index 0000000000..e09c3989cd --- /dev/null +++ b/examples/10_openssl_server/main/cacert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIJAPMMNobNczaUMA0GCSqGSIb3DQEBBAUAMHQxEzARBgNV +BAMTCk15IFRlc3QgQ0ExCzAJBgNVBAgTAkhaMQswCQYDVQQGEwJDTjEcMBoGCSqG +SIb3DQEJARYNdGVzdEBjZXJ0LmNvbTElMCMGA1UEChMcUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNjExMTUwNTA0MThaFw0xOTExMTUwNTA0MThaMHQx +EzARBgNVBAMTCk15IFRlc3QgQ0ExCzAJBgNVBAgTAkhaMQswCQYDVQQGEwJDTjEc +MBoGCSqGSIb3DQEJARYNdGVzdEBjZXJ0LmNvbTElMCMGA1UEChMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALDjSPDlomepHCzbw4MUrquQAU0xTV4/Npb27k9I5TRVTjIoOs/5hNI2LPFW +e4CREx09ZrT8K3NFOBoSy7bhPAsjGaFxCYYWc9tiX1m5gq3ToVRSmbZ65fE3kvnI +8E/d5VyzA0OMmWbfaolBSTMoWgqRynEaT+z1Eh2yDTzVFy9eov1DdQFUqGDqbH5b +QYvTY5Fyem7UcKWAe2yS0j3H4dVtVBKNY7qV3Px08yGAs5fQFgUwhyB5+qwhvkeL +JdgapGaSTwLgoQKWHbe/lA3NiBIB9hznFUGKo3hmniAvYZbrQcn3tc0l/J4I39v2 +Pm29FAyjWvQyBkGktz2q4elOZYkCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQQFAAOCAQEAJCJ+97oae/FcOLbPpjCpUQnWqYydgSChgalkZNvr4fVp +TnuNg471l0Y2oTJLoWn2YcbPSFVOEeKkU47mpjMzucHHp0zGaW9SdzhZalWwmbgK +q2ijecIbuFHFNedYTk/03K7eaAcjVhD8e0oOJImeLOL6DAFivA1LUnSgXsdGPDtD +zhISsCPTu+cL1j0yP6HBvLeAyb8kaCWJ05RtiVLRANNHQn/keHajJYpMwnEEbJdG +cqN3whfJoGVbZ6isEf2RQJ0pYRnP7uGLW3wGkLWxfdto8uER8HVDx7fZpevLIqGd +1OoSEi3cIJXWBAjx0TLzzhtb6aeIxBJWQqHThtkKdg== +-----END CERTIFICATE----- diff --git a/examples/10_openssl_server/main/component.mk b/examples/10_openssl_server/main/component.mk new file mode 100644 index 0000000000..80af01cb53 --- /dev/null +++ b/examples/10_openssl_server/main/component.mk @@ -0,0 +1,6 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# + +COMPONENT_EMBED_TXTFILES := cacert.pem +COMPONENT_EMBED_TXTFILES += prvtkey.pem diff --git a/examples/10_openssl_server/main/openssl_server.c b/examples/10_openssl_server/main/openssl_server.c new file mode 100644 index 0000000000..53b6050d57 --- /dev/null +++ b/examples/10_openssl_server/main/openssl_server.c @@ -0,0 +1,248 @@ +/* OpenSSL server Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include "openssl_server.h" + +#include + +#include "openssl/ssl.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "esp_log.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" + +#include "nvs_flash.h" + +#include "lwip/sockets.h" +#include "lwip/netdb.h" + +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const static int CONNECTED_BIT = BIT0; + +const static char *TAG = "Openssl_demo"; + +#define OPENSSL_DEMO_SERVER_ACK "HTTP/1.1 200 OK\r\n" \ + "Content-Type: text/html\r\n" \ + "Content-Length: 98\r\n" \ + "\r\n" \ + "\r\n" \ + "OpenSSL demo\r\n" \ + "OpenSSL server demo!\r\n" \ + "\r\n" \ + "\r\n" + +static void openssl_demo_thread(void *p) +{ + int ret; + + SSL_CTX *ctx; + SSL *ssl; + + int socket, new_socket; + socklen_t addr_len; + struct sockaddr_in sock_addr; + + char recv_buf[OPENSSL_DEMO_RECV_BUF_LEN]; + + const char send_data[] = OPENSSL_DEMO_SERVER_ACK; + const int send_bytes = sizeof(send_data); + + extern const unsigned char cacert_pem_start[] asm("_binary_cacert_pem_start"); + extern const unsigned char cacert_pem_end[] asm("_binary_cacert_pem_end"); + const unsigned int cacert_pem_bytes = cacert_pem_end - cacert_pem_start; + + extern const unsigned char prvtkey_pem_start[] asm("_binary_prvtkey_pem_start"); + extern const unsigned char prvtkey_pem_end[] asm("_binary_prvtkey_pem_end"); + const unsigned int prvtkey_pem_bytes = prvtkey_pem_end - prvtkey_pem_start; + + ESP_LOGI(TAG, "SSL server context create ......"); + ctx = SSL_CTX_new(SSLv3_server_method()); + if (!ctx) { + ESP_LOGI(TAG, "failed"); + goto failed1; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server context set own certification......"); + ret = SSL_CTX_use_certificate_ASN1(ctx, cacert_pem_bytes, cacert_pem_start); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server context set private key......"); + ret = SSL_CTX_use_PrivateKey_ASN1(0, ctx, prvtkey_pem_start, prvtkey_pem_bytes); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server create socket ......"); + socket = socket(AF_INET, SOCK_STREAM, 0); + if (socket < 0) { + ESP_LOGI(TAG, "failed"); + goto failed2; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket bind ......"); + memset(&sock_addr, 0, sizeof(sock_addr)); + sock_addr.sin_family = AF_INET; + sock_addr.sin_addr.s_addr = 0; + sock_addr.sin_port = htons(OPENSSL_DEMO_LOCAL_TCP_PORT); + ret = bind(socket, (struct sockaddr*)&sock_addr, sizeof(sock_addr)); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket listen ......"); + ret = listen(socket, 32); + if (ret) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + +reconnect: + ESP_LOGI(TAG, "SSL server create ......"); + ssl = SSL_new(ctx); + if (!ssl) { + ESP_LOGI(TAG, "failed"); + goto failed3; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server socket accept client ......"); + new_socket = accept(socket, (struct sockaddr *)&sock_addr, &addr_len); + if (new_socket < 0) { + ESP_LOGI(TAG, "failed" ); + goto failed4; + } + ESP_LOGI(TAG, "OK"); + + SSL_set_fd(ssl, new_socket); + + ESP_LOGI(TAG, "SSL server accept client ......"); + ret = SSL_accept(ssl); + if (!ret) { + ESP_LOGI(TAG, "failed"); + goto failed5; + } + ESP_LOGI(TAG, "OK"); + + ESP_LOGI(TAG, "SSL server read message ......"); + do { + memset(recv_buf, 0, OPENSSL_DEMO_RECV_BUF_LEN); + ret = SSL_read(ssl, recv_buf, OPENSSL_DEMO_RECV_BUF_LEN - 1); + if (ret <= 0) { + break; + } + if (strstr(recv_buf, "GET / HTTP/1.1")) { + SSL_write(ssl, send_data, send_bytes); + break; + } + } while (1); + + ESP_LOGI(TAG, "result %d", ret); + + SSL_shutdown(ssl); +failed5: + close(new_socket); + new_socket = -1; +failed4: + SSL_free(ssl); + ssl = NULL; + goto reconnect; +failed3: + close(socket); + socket = -1; +failed2: + SSL_CTX_free(ctx); + ctx = NULL; +failed1: + vTaskDelete(NULL); + return ; +} + +static void openssl_client_init(void) +{ + int ret; + xTaskHandle openssl_handle; + + ret = xTaskCreate(openssl_demo_thread, + OPENSSL_DEMO_THREAD_NAME, + OPENSSL_DEMO_THREAD_STACK_WORDS, + NULL, + OPENSSL_DEMO_THREAD_PRORIOTY, + &openssl_handle); + + if (ret != pdPASS) { + ESP_LOGI(TAG, "create thread %s failed", OPENSSL_DEMO_THREAD_NAME); + } +} + +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + openssl_client_init(); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} + +static void wifi_conn_init(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_LOGI(TAG, "start the WIFI SSID:[%s] password:[%s]\n", EXAMPLE_WIFI_SSID, EXAMPLE_WIFI_PASS); + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +void app_main(void) +{ + nvs_flash_init(); + wifi_conn_init(); +} diff --git a/examples/10_openssl_server/main/openssl_server.h b/examples/10_openssl_server/main/openssl_server.h new file mode 100644 index 0000000000..5f49de35f2 --- /dev/null +++ b/examples/10_openssl_server/main/openssl_server.h @@ -0,0 +1,31 @@ +/* OpenSSL server Example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#ifndef _OPENSSL_DEMO_H_ +#define _OPENSSL_DEMO_H_ + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +#define OPENSSL_DEMO_THREAD_NAME "OpenSSL_demo" +#define OPENSSL_DEMO_THREAD_STACK_WORDS 10240 +#define OPENSSL_DEMO_THREAD_PRORIOTY 8 + +#define OPENSSL_DEMO_RECV_BUF_LEN 1024 + +#define OPENSSL_DEMO_LOCAL_TCP_PORT 443 + +#endif + diff --git a/examples/10_openssl_server/main/prvtkey.pem b/examples/10_openssl_server/main/prvtkey.pem new file mode 100644 index 0000000000..4ead61f6ff --- /dev/null +++ b/examples/10_openssl_server/main/prvtkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAsONI8OWiZ6kcLNvDgxSuq5ABTTFNXj82lvbuT0jlNFVOMig6 +z/mE0jYs8VZ7gJETHT1mtPwrc0U4GhLLtuE8CyMZoXEJhhZz22JfWbmCrdOhVFKZ +tnrl8TeS+cjwT93lXLMDQ4yZZt9qiUFJMyhaCpHKcRpP7PUSHbINPNUXL16i/UN1 +AVSoYOpsfltBi9NjkXJ6btRwpYB7bJLSPcfh1W1UEo1jupXc/HTzIYCzl9AWBTCH +IHn6rCG+R4sl2BqkZpJPAuChApYdt7+UDc2IEgH2HOcVQYqjeGaeIC9hlutByfe1 +zSX8ngjf2/Y+bb0UDKNa9DIGQaS3Parh6U5liQIDAQABAoIBAB9K9jp3xXVlO3DM +KBhmbkg3n6NSV4eW00d9w8cO9E1/0eeZql3knJS7tNO1IwApqiIAHM1j1yP7WONz +88oUqpSlzwD6iF7KVhC3pHqxEOdDi0Tpn/viXg+Ab2X1IF5guRTfLnKiyviiCazi +edqtBtDb3d6Icx9Oc7gBKcpbQFDGt++wSOb5L+xhRm9B5B4l/6byikiPeKqIK5tC +SoP9Zr1mvpNoGm1P4LvEunFJcRBqVI010VNwfO9P98oVyzJu9/FZZrQxXoY9JdXF +OM6nbl+hMDM3TkEOda9NvBhImozEAvuc97CaaXyR3XivxMqNqNIb4+syUPa2PCS3 +ZztI5qECgYEA1gbVG6ifpvpbBkDPi3Im8fM3F7FLLrQc48FdFjdMvDhHD9lVKucD +Uaa8PF9dbbvlu2cwMyfBOKSuWaXxRxRsiqiPmTunS1MvPzQcSrGwUrL2AogGucn6 ++NrLQf5P4H5IpkDQ9ih3zwjO6xKFK1WeYnYpHM8qUBtl6q0YFyVBPu0CgYEA05Pn +StWA4D7VSbNnVi6lvFyEOUsTrK3v419598TFiq4eXLq6aV8/CQYzKsSzoG+aOZhX +Li+0uyT5cNzUcXYhTsW1hA/pNhMfxMrYiB1x14zlLp2WRGg4vd/+SxX6d9Yd3acX +7QzPKgdDicXs9QN8ozJOICKvNbUI53AJdATVEY0CgYEAwvpGeoQLrdq1weSZLrg3 +soOX1QW3MDz1dKdbXjnStkWut0mOxR7fbysuoPFf8/ARQcCnsHKvHCMqkpESVWbN +2yPkbfxiU8Tcbf/TJljqAOz4ISY6ula/RKZONTixHBrvpEW4GAiV3Q5xMsYUe33s +ZFaw7YXtTj0ng7tdDvjpj6ECgYEApHdUU9ejVq2BHslWiqe4LbO9FMxHfvO2hgix +xugupp6y+2Irhb2EQn+PRq+g8hXOzPaezkhHNTKItDL08T3iplkJwJ6dqmszRsZn +i2dYFzZu8M2PAZ4CfZahFbz/9id7D9HTx3EtmH4NAgvZJpyPRkzUbiaIDDettDpj +Hsyi1AECgYAPLvjBzQj4kPF8Zo9pQEUcz4pmupRVfv3aRfjnahDK4qZHEePDRj+J +W7pzayrs1dyN9QLB8pTc424z7f8MB3llCICN+ohs8CR/eW0NEobE9ldDOeoCr1Vh +NhNSbrN1iZ8U4oLkRTMaDKkVngGffvjGi/q0tOU7hJdZOqNlk2Iahg== +-----END RSA PRIVATE KEY----- diff --git a/make/build_examples.sh b/make/build_examples.sh index a522666a98..8345dab502 100755 --- a/make/build_examples.sh +++ b/make/build_examples.sh @@ -20,8 +20,13 @@ for example in ${IDF_PATH}/examples/*; do mkdir ${EXAMPLE_NUM} cp -r ${example} ${EXAMPLE_NUM} pushd ${EXAMPLE_NUM}/`basename ${example}` - # build non-verbose first, only build verbose if there's an error - make defconfig all || (RESULT=$?; make V=1) + + # be stricter in the CI build than the default IDF settings + export EXTRA_CFLAGS="-Werror -Werror=deprecated-declarations" + export EXTRA_CXXFLAGS=${EXTRA_CFLAGS} + + # build non-verbose first, only build verbose if there's an error + (make clean defconfig && make all ) || (RESULT=$?; make V=1) popd EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 )) done diff --git a/make/common.mk b/make/common.mk index 6e4fa75ab5..4d40f7abc3 100644 --- a/make/common.mk +++ b/make/common.mk @@ -26,31 +26,6 @@ details := @true MAKEFLAGS += --silent endif -# Pseudo-target to check a git submodule has been properly initialised -# -# $(eval $(call SubmoduleCheck,FILENAMES,SUBMODULE_PATH)) to create a target that -# automatically runs 'git submodule update --init SUBMODULE_PATH' if any of -# the files in FILENAMES are missing, and fails if this is not possible. -# -# Will also print a WARNING if the submodule at SUBMODULE_PATH appears -# to require an update. -define SubmoduleCheck -$(1): - @echo "WARNING: Missing submodule $(2) for $$@..." - [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) - [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule --init' in esp-idf root directory."; exit 1) - @echo "Attempting 'git submodule update --init' in esp-idf root directory..." - cd ${IDF_PATH} && git submodule update --init $(2) - -# Parse 'git submodule status' output for out-of-date submodule. -# Status output prefixes status line with '+' if the submodule commit doesn't match -ifneq ("$(shell cd ${IDF_PATH} && git submodule status $(2) | grep '^+')","") -$$(info WARNING: git submodule $2 may be out of date. Run 'git submodule update' to update.) -endif -endef - - - # General make utilities # convenience variable for printing an 80 asterisk wide separator line diff --git a/make/component_wrapper.mk b/make/component_wrapper.mk index 55a135158a..3018c18b55 100644 --- a/make/component_wrapper.mk +++ b/make/component_wrapper.mk @@ -103,8 +103,8 @@ endef # component_project_vars.mk target for the component. This is used to # take component.mk variables COMPONENT_ADD_INCLUDEDIRS, -# COMPONENT_ADD_LDFLAGS and COMPONENT_DEPENDS and inject those into -# the project make pass. +# COMPONENT_ADD_LDFLAGS, COMPONENT_DEPENDS and COMPONENT_SUBMODULES +# and inject those into the project make pass. # # The target here has no dependencies, as the parent target in # project.mk evaluates dependencies before calling down to here. See @@ -119,6 +119,7 @@ component_project_vars.mk:: @echo '# Automatically generated build file. Do not edit.' > $@ @echo 'COMPONENT_INCLUDES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_ADD_INCLUDEDIRS)))' >> $@ @echo 'COMPONENT_LDFLAGS += $(call MakeVariablePath,$(COMPONENT_ADD_LDFLAGS))' >> $@ + @echo 'COMPONENT_SUBMODULES += $(call MakeVariablePath,$(addprefix $(COMPONENT_PATH)/,$(COMPONENT_SUBMODULES)))' >> $@ @echo '$(COMPONENT_NAME)-build: $(addsuffix -build,$(COMPONENT_DEPENDS))' >> $@ @@ -179,7 +180,7 @@ $(foreach srcdir,$(COMPONENT_SRCDIRS), $(eval $(call GenerateCompileTargets,$(sr ## Support for embedding binary files into the ELF as symbols -OBJCOPY_EMBED_ARGS := --input binary --output elf32-xtensa-le --binary-architecture xtensa --rename-section .data=.rodata.embedded +OBJCOPY_EMBED_ARGS := --input-target binary --output-target elf32-xtensa-le --binary-architecture xtensa --rename-section .data=.rodata.embedded # Generate pattern for embedding text or binary files into the app # $(1) is name of file (as relative path inside component) @@ -188,18 +189,29 @@ OBJCOPY_EMBED_ARGS := --input binary --output elf32-xtensa-le --binary-architect # txt files are null-terminated before being embedded (otherwise # identical behaviour.) # -# Files are temporarily copied to the build directory before objcopy, -# because objcopy generates the symbol name from the full command line -# path to the input file. define GenerateEmbedTarget -$(1).$(2).o: $(call resolvepath,$(1),$(COMPONENT_PATH)) | $$(dir $(1)) + +# copy the input file into the build dir (using a subdirectory +# in case the file already exists elsewhere in the build dir) +embed_bin/$$(notdir $(1)): $(call resolvepath,$(1),$(COMPONENT_PATH)) | embed_bin + cp $$< $$@ + +embed_txt/$$(notdir $(1)): $(call resolvepath,$(1),$(COMPONENT_PATH)) | embed_txt + cp $$< $$@ + echo -ne '\0' >> $$@ # null-terminate text files + +# messing about with the embed_X subdirectory then using 'cd' for objcopy is because the +# full path passed to OBJCOPY makes it into the name of the symbols in the .o file +$(1).$(2).o: embed_$(2)/$$(notdir $(1)) | $$(dir $(1)) $(summary) EMBED $$@ - $$(if $$(filter-out $$(notdir $$(abspath $$<)),$$(abspath $$(notdir $$<))), cp $$< $$(notdir $$<) ) # copy input file to build dir, unless already in build dir - $$(if $$(subst bin,,$(2)),echo -ne '\0' >> $$(notdir $$<) ) # trailing NUL byte on text output - $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) $$@ - rm $$(notdir $$<) + cd embed_$(2); $(OBJCOPY) $(OBJCOPY_EMBED_ARGS) $$(notdir $$<) ../$$@ + +CLEAN_FILES += embed_$(2)/$$(notdir $(1)) endef +embed_txt embed_bin: + mkdir -p $@ + # generate targets to embed binary & text files $(foreach binfile,$(COMPONENT_EMBED_FILES), $(eval $(call GenerateEmbedTarget,$(binfile),bin))) diff --git a/make/project.mk b/make/project.mk index 08c7dd89a9..870db55f97 100644 --- a/make/project.mk +++ b/make/project.mk @@ -10,7 +10,7 @@ # where this file is located. # -.PHONY: build-components menuconfig defconfig all build clean all_binaries +.PHONY: build-components menuconfig defconfig all build clean all_binaries check-submodules all: all_binaries # see below for recipe of 'all' target # @@ -94,13 +94,16 @@ COMPONENT_PATHS += $(abspath $(SRCDIRS)) # A component is buildable if it has a component.mk makefile in it COMPONENT_PATHS_BUILDABLE := $(foreach cp,$(COMPONENT_PATHS),$(if $(wildcard $(cp)/component.mk),$(cp))) -# Initialise a project-wide list of include dirs (COMPONENT_INCLUDES), -# and LDFLAGS args (COMPONENT_LDFLAGS) supplied by each component. +# Initialise project-wide variables which can be added to by +# each component. # # These variables are built up via the component_project_vars.mk # generated makefiles (one per component). +# +# See docs/build-system.rst for more details. COMPONENT_INCLUDES := COMPONENT_LDFLAGS := +COMPONENT_SUBMODULES := # COMPONENT_PROJECT_VARS is the list of component_project_vars.mk generated makefiles # for each component. @@ -158,14 +161,16 @@ LDFLAGS ?= -nostdlib \ # CPPFLAGS used by C preprocessor # If any flags are defined in application Makefile, add them at the end. -CPPFLAGS := -DESP_PLATFORM $(CPPFLAGS) +CPPFLAGS := -DESP_PLATFORM $(CPPFLAGS) $(EXTRA_CPPFLAGS) # Warnings-related flags relevant both for C and C++ -COMMON_WARNING_FLAGS = -Wall -Werror \ +COMMON_WARNING_FLAGS = -Wall -Werror=all \ -Wno-error=unused-function \ -Wno-error=unused-but-set-variable \ -Wno-error=unused-variable \ - -Wno-error=deprecated-declarations + -Wno-error=deprecated-declarations \ + -Wextra \ + -Wno-unused-parameter -Wno-sign-compare # Flags which control code generation and dependency generation, both for C and C++ COMMON_FLAGS = \ @@ -192,8 +197,9 @@ CFLAGS := $(strip \ -std=gnu99 \ $(OPTIMIZATION_FLAGS) \ $(COMMON_FLAGS) \ - $(COMMON_WARNING_FLAGS) \ - $(CFLAGS)) + $(COMMON_WARNING_FLAGS) -Wno-old-style-declaration \ + $(CFLAGS) \ + $(EXTRA_CFLAGS)) # List of flags to pass to C++ compiler # If any flags are defined in application Makefile, add them at the end. @@ -204,7 +210,8 @@ CXXFLAGS := $(strip \ $(OPTIMIZATION_FLAGS) \ $(COMMON_FLAGS) \ $(COMMON_WARNING_FLAGS) \ - $(CXXFLAGS)) + $(CXXFLAGS) \ + $(EXTRA_CXXFLAGS)) export CFLAGS CPPFLAGS CXXFLAGS @@ -285,7 +292,7 @@ endef define GenerateComponentTargets .PHONY: $(2)-build $(2)-clean -$(2)-build: +$(2)-build: check-submodules $(call ComponentMake,$(1),$(2)) build $(2)-clean: @@ -328,4 +335,30 @@ app-clean: $(addsuffix -clean,$(notdir $(COMPONENT_PATHS_BUILDABLE))) config-clean: app-clean clean: config-clean +# phony target to check if any git submodule listed in COMPONENT_SUBMODULES are missing +# or out of date, and exit if so. Components can add paths to this variable. +# +# This only works for components inside IDF_PATH +check-submodules: +# Generate a target to check this submodule +# $(1) - submodule directory, relative to IDF_PATH +define GenerateSubmoduleCheckTarget +check-submodules: $(IDF_PATH)/$(1)/.git +$(IDF_PATH)/$(1)/.git: + @echo "WARNING: Missing submodule $(1)..." + [ -d ${IDF_PATH}/.git ] || ( echo "ERROR: esp-idf must be cloned from git to work."; exit 1) + [ -x $(which git) ] || ( echo "ERROR: Need to run 'git submodule init $(1)' in esp-idf root directory."; exit 1) + @echo "Attempting 'git submodule update --init $(1)' in esp-idf root directory..." + cd ${IDF_PATH} && git submodule update --init $(1) + +# Parse 'git submodule status' output for out-of-date submodule. +# Status output prefixes status line with '+' if the submodule commit doesn't match +ifneq ("$(shell cd ${IDF_PATH} && git submodule status $(1) | grep '^+')","") +$$(info WARNING: git submodule $(1) may be out of date. Run 'git submodule update' to update.) +endif +endef + +# filter/subst in expression ensures all submodule paths begin with $(IDF_PATH), and then strips that prefix +# so the argument is suitable for use with 'git submodule' commands +$(foreach submodule,$(subst $(IDF_PATH)/,,$(filter $(IDF_PATH)/%,$(COMPONENT_SUBMODULES))),$(eval $(call GenerateSubmoduleCheckTarget,$(submodule))))