Merge branch 'master' into feature/modem_sleep

Conflicts:
	components/nvs_flash/src/nvs_api.cpp
This commit is contained in:
Xia Xiao Tian 2016-11-18 20:53:59 +08:00
commit 4dcf3709b0
100 changed files with 3426 additions and 850 deletions

5
.gitignore vendored
View file

@ -19,3 +19,8 @@ GPATH
examples/*/sdkconfig
examples/*/sdkconfig.old
examples/*/build
#Doc build artifacts
docs/_build/
docs/doxygen-warning-log.txt
docs/xml/

View file

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

View file

@ -17,7 +17,7 @@
#include <esp_log.h>
#include <bootloader_flash.h>
const static char *TAG = "esp_image";
static const char *TAG = "esp_image";
#define SIXTEEN_MB 0x1000000
#define ESP_ROM_CHECKSUM_INITIAL 0xEF

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -32,11 +32,11 @@ extern "C" {
#include "freertos/ringbuf.h"
#include <esp_types.h>
#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,6 +131,9 @@ 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*/
@ -115,8 +142,7 @@ typedef struct {
/**
* @brief Set 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 UART data bits
*
* @return
@ -128,7 +154,8 @@ esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit
/**
* @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
@ -139,20 +166,20 @@ esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bi
/**
* @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 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.
*
* @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
@ -163,20 +190,20 @@ esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit);
/**
* @brief Set UART parity.
*
* @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 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.
*
* @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
@ -188,20 +215,20 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
/**
* @brief Set UART baud 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 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.
*
* @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
@ -213,39 +240,35 @@ esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
/**
* @brief Set UART line inverse 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 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)
* 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.
*
* @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 Hardware flow control mode
*
* @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN)
*
* @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
*
* @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
@ -256,11 +279,9 @@ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flo
/**
* @brief Clear UART interrupt status
*
* @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 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)
* enable_mask should be chosen from the fields of register UART_INT_CLR_REG.
*
* @return
* - ESP_OK Success
@ -271,11 +292,9 @@ esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
/**
* @brief Set UART interrupt enable
*
* @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 enable_mask Bit mask of the enable bits.
*
* (enable_mask should be chosen from the fields of register UART_INT_ENA_REG)
* enable_mask should be chosen from the fields of register UART_INT_ENA_REG.
*
* @return
* - ESP_OK Success
@ -286,11 +305,9 @@ esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
/**
* @brief Clear UART interrupt enable 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 disable_mask Bit mask of the disable bits.
*
* (disable_mask should be chosen from the fields of register UART_INT_ENA_REG)
* disable_mask should be chosen from the fields of register UART_INT_ENA_REG.
*
* @return
* - ESP_OK Success
@ -302,7 +319,7 @@ 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)
*
* @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
@ -313,7 +330,7 @@ esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
/**
* @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
@ -324,7 +341,7 @@ esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
/**
* @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
@ -335,10 +352,8 @@ esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
/**
* @brief Enable 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
* @param enable 1: enable; 0: disable
*
* @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN
*
* @return
@ -349,19 +364,16 @@ 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.
*
* @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.
*
* @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.
*
* @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 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
*
* @return
@ -373,18 +385,13 @@ esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*
/**
* @brief Set UART pin number
*
* @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
* @note Internal signal can be output to multiple GPIO pads.
* Only one GPIO pad can connect with input signal.
*
* @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
@ -397,8 +404,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r
* @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 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
@ -410,8 +416,7 @@ esp_err_t uart_set_rts(uart_port_t uart_num, int level);
/**
* @brief UART set DTR level (before inverse)
*
* @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 level 1: DTR output low; 0: DTR output high
*
* @return
@ -423,8 +428,7 @@ esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
/**
* @brief UART parameter configure
*
* @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 uart_config UART parameter settings
*
* @return
@ -436,8 +440,7 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf
/**
* @brief UART interrupt configure
*
* @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 intr_conf UART interrupt settings
*
* @return
@ -453,18 +456,12 @@ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_
* 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 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
@ -476,7 +473,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
/**
* @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
@ -487,8 +484,7 @@ esp_err_t uart_driver_delete(uart_port_t uart_num);
/**
* @brief Wait UART TX FIFO empty
*
* @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 ticks_to_wait Timeout, count in RTOS ticks
*
* @return
@ -499,23 +495,20 @@ 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,
* @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
* @note This function should only be used when UART TX buffer is not enabled.
*
* @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,
@ -526,10 +519,8 @@ int uart_tx_chars(uart_port_t uart_no, const char* buffer, uint32_t len);
* 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 uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
* @param src data buffer address
*
* @param size data length to send
*
* @return
@ -549,15 +540,10 @@ int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
* 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 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: one bit's time@current_baudrate)
* @param brk_len break signal length (unit: time of one data bit at current_baudrate)
*
* @return
* - (-1) Parameter error
@ -569,15 +555,11 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si
/**
* @brief UART read bytes from UART buffer
*
* @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 buf pointer to the buffer.
*
* @param length data length
*
* @param ticks_to_wait sTimeout, count in RTOS ticks
*
*
* @return
* - (-1) Error
* - Others return a char data from uart fifo.
@ -587,7 +569,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp
/**
* @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
*

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#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<MAX_HOOKS; n++) {
if (tick_cb[n]!=NULL) {
tick_cb[n]();
}
}
}
void esp_vApplicationIdleHook()
{
bool doWait=true;
bool r;
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]!=NULL) {
r=idle_cb[n]();
if (!r) doWait=false;
}
}
if (doWait) {
//Wait for whatever interrupt comes next... this should save some power.
asm("waiti 0");
}
}
esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]==NULL) {
idle_cb[n]=new_idle_cb;
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (tick_cb[n]==NULL) {
tick_cb[n]=new_tick_cb;
return ESP_OK;
}
}
return ESP_ERR_NO_MEM;
}
void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (idle_cb[n]==old_idle_cb) idle_cb[n]=NULL;
}
}
void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
{
int n;
for (n=0; n<MAX_HOOKS; n++) {
if (tick_cb[n]==old_tick_cb) tick_cb[n]=NULL;
}
}

View file

@ -25,6 +25,7 @@
#include "soc/io_mux_reg.h"
#include "esp_gdbstub.h"
#include "driver/gpio.h"
//Length of buffer used to reserve GDB commands. Has to be at least able to fit the G command, which
//implies a minimum size of about 320 bytes.
@ -354,7 +355,7 @@ static int gdbReadCommand() {
void esp_gdbstub_panic_handler(XtExcFrame *frame) {
dumpHwToRegfile(frame);
//Make sure txd/rxd are enabled
PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U);
gpio_pullup_dis(1);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, FUNC_U0RXD_U0RXD);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_U0TXD);

View file

@ -26,6 +26,10 @@
// Forces data into DRAM instead of flash
#define DRAM_ATTR __attribute__((section(".dram1")))
// Forces a string into DRAM instrad of flash
// Use as ets_printf(DRAM_STR("Hello world!\n"));
#define DRAM_STR(str) (__extension__({static const DRAM_ATTR char __c[] = (str); (const char *)&__c;}))
// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst"
#define RTC_IRAM_ATTR __attribute__((section(".rtc.text")))

View file

@ -0,0 +1,83 @@
// 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.
#ifndef __ESP_FREERTOS_HOOKS_H__
#define __ESP_FREERTOS_HOOKS_H__
#include <stdbool.h>
#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

View file

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

View file

@ -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 <stdint.h>
#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

View file

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

View file

@ -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,7 +111,7 @@ 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
@ -133,7 +136,7 @@ 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
@ -146,7 +149,7 @@ 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
@ -161,8 +164,6 @@ 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
@ -175,12 +176,10 @@ 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
@ -193,8 +192,6 @@ 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
@ -207,8 +204,6 @@ 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
@ -220,8 +215,7 @@ esp_err_t esp_wifi_disconnect(void);
/**
* @brief Currently this API is just an stub API
*
* @param null
*
* @return
* - ESP_OK: succeed
* - others: fail
@ -231,7 +225,7 @@ 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
@ -249,8 +243,8 @@ 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
@ -260,12 +254,11 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
* - 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
@ -276,9 +269,9 @@ 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
@ -291,9 +284,9 @@ 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
@ -306,9 +299,9 @@ esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_re
/**
* @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
@ -319,18 +312,18 @@ 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
* - 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
* - 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
* - 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,8 +382,8 @@ 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
@ -401,12 +394,12 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
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
@ -417,12 +410,12 @@ esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
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
@ -435,7 +428,7 @@ 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
@ -448,7 +441,7 @@ 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
@ -462,11 +455,11 @@ 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
@ -475,14 +468,15 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country);
* - 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
* - 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
@ -497,8 +491,8 @@ esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
*
* 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
*/
@ -509,7 +503,7 @@ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
*
* 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
@ -520,7 +514,7 @@ 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
@ -531,7 +525,7 @@ 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
@ -548,8 +542,8 @@ 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
@ -566,8 +560,8 @@ 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
@ -582,7 +576,7 @@ 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
@ -599,7 +593,7 @@ 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
@ -612,7 +606,7 @@ 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
@ -625,7 +619,7 @@ 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
@ -637,15 +631,10 @@ 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
@ -657,23 +646,19 @@ esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_v
/**
* @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

View file

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

View file

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

View file

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

@ -1 +1 @@
Subproject commit 01f5c068e1ac3968add98439ee2f1748b9e391fa
Subproject commit a580f70a64872a7cc291b1f22455f6adbc2e35cf

64
components/esp32/phy.h Normal file
View file

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

224
components/esp32/phy_init.c Normal file
View file

@ -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 <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#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()
{
}

View file

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

View file

@ -22,10 +22,13 @@
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include <esp_types.h>
#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; x<portNUM_PROCESSORS; x++) {
ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
ets_printf(DRAM_STR("CPU %d: %s\n"), x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
}
#if CONFIG_TASK_WDT_PANIC
ets_printf("Aborting.\n");
ets_printf(DRAM_STR("Aborting.\n"));
abort();
#endif
portEXIT_CRITICAL(&taskwdt_spinlock);
}
@ -79,6 +95,8 @@ void esp_task_wdt_feed() {
wdt_task_t *wdttask=wdt_task_list;
bool found_task=false, do_feed_wdt=true;
TaskHandle_t handle=xTaskGetCurrentTaskHandle();
portENTER_CRITICAL(&taskwdt_spinlock);
//Walk the linked list of wdt tasks to find this one, as well as see if we need to feed
//the real watchdog timer.
for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
@ -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

View file

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

View file

@ -108,31 +108,20 @@ add_failure(SRunner *runner, int verbosity)
}
}
void
srunner_run_all(SRunner *runner, int verbosity)
static void run_test(SRunner *runner, int verbosity, TCase *tc, int i)
{
Suite *suite;
TCase *tc;
assert(runner != NULL);
suite = runner->suite;
tc = suite->tests;
while (tc != NULL) {
int i;
for (i = 0; i < tc->ntests; ++i) {
runner->nchecks++;
if (tc->setup != NULL) {
/* setup */
if (setjmp(env)) {
add_failure(runner, verbosity);
continue;
return;
}
tc->setup();
}
/* test */
if (setjmp(env)) {
add_failure(runner, verbosity);
continue;
return;
}
(tc->tests[i])();
@ -140,13 +129,25 @@ srunner_run_all(SRunner *runner, int verbosity)
if (tc->teardown != NULL) {
if (setjmp(env)) {
add_failure(runner, verbosity);
continue;
return;
}
tc->teardown();
}
}
void
srunner_run_all(SRunner *runner, int verbosity)
{
assert(runner != NULL);
assert(runner->suite != NULL);
TCase *tc = runner->suite->tests;
while (tc != NULL) {
for (int i = 0; i < tc->ntests; ++i) {
runner->nchecks++;
run_test(runner, verbosity, tc, i);
tc = tc->next_tcase;
}
}
if (verbosity) {
int passed = runner->nchecks - runner->nfailures;
double percentage = ((double) passed) / runner->nchecks;

View file

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

View file

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

View file

@ -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,16 +487,25 @@ 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();
}
} while (ringbufferFreeMem(rb) < needed_size && ticks_to_wait>=0);
// 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_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);

View file

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

View file

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

View file

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

View file

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

View file

@ -161,22 +161,26 @@ 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
#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
@ -186,15 +190,8 @@ wlanif_input(struct netif *netif, void *buffer, uint16 len)
}
p->payload = buffer;
p->eb = eb;
#else
p = pbuf_alloc(PBUF_IP, len, PBUF_POOL);
if (p == NULL) {
return;
}
memcpy(p->payload, buffer, len);
#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"));

View file

@ -4,3 +4,5 @@ COMPONENT_SRCDIRS := micro-ecc
COMPONENT_OBJS := micro-ecc/uECC.o
COMPONENT_ADD_INCLUDEDIRS := micro-ecc
COMPONENT_SUBMODULES := micro-ecc

View file

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

View file

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

View file

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

View file

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

View file

@ -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);
if (mSemaphore) {
xSemaphoreTake(mSemaphore, portMAX_DELAY);
}
}
~Lock()
{
assert(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()
{
if (mSemaphore) {
vSemaphoreDelete(mSemaphore);
}
mSemaphore = nullptr;
}

View file

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

View file

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

View file

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

View file

@ -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 <sstream>
#include <iostream>

View file

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

View file

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

View file

@ -28,12 +28,21 @@ config PARTITION_TABLE_CUSTOM_FILENAME
relative to the project root directory.
config PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET
hex "App offset in flash" if PARTITION_TABLE_CUSTOM
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
@ -45,6 +54,11 @@ config APP_OFFSET
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

View file

@ -117,6 +117,7 @@ class PartitionDefinition(object):
"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,
},
}

View file

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

1 # Name # Name, Type, SubType, Offset, Size Type SubType Offset Size
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000
4 phy_init, data, phy, 0xf000, 0x1000
5 factory factory, app, factory, 0x10000, 1M app factory 0x10000 1M
rfdata data rf 256K
wifidata data wifi 256K

View file

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

1 # Name # Name, Type, SubType, Offset, Size Type SubType Offset Size
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x4000
4 otadata, data, ota, 0xd000, 0x2000
5 phy_init, data, phy, 0xf000, 0x1000
6 factory factory, 0, 0, 0x10000, 1M 0 0 0x10000 1M
7 ota_0 ota_0, 0, ota_0, , 1M 0 ota_0 1M
8 ota_1 ota_1, 0, ota_1, , 1M 0 ota_1 1M
rfdata data rf 256K
wifidata data wifi 256K
otadata data ota 256K

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -3,7 +3,10 @@
Application Example
-------------------
`Instructions <http://esp-idf.readthedocs.io/en/latest/api/template.html>`_
Two examples are provided in ESP-IDF examples directory:
- `07_nvs_rw_value <https://github.com/espressif/esp-idf/tree/master/examples/07_nvs_rw_value>`_ demostrates how to read and write integer values
- `08_nvs_rw_blob <https://github.com/espressif/esp-idf/tree/master/examples/08_nvs_rw_blob>`_ demostrates how to read and write variable length binary values
API Reference
-------------

67
docs/api/spi_flash.rst Normal file
View file

@ -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 <https://github.com/espressif/esp-idf/blob/master/components/spi_flash/include/esp_spi_flash.h>`_
* `spi_flash/include/esp_partition.h <https://github.com/espressif/esp-idf/blob/master/components/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

72
docs/api/wdts.rst Normal file
View file

@ -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 <https://github.com/espressif/esp-idf/blob/master/components/esp32/include/esp_int_wdt.h>`_
* `esp32/include/esp_task_wdt.h <https://github.com/espressif/esp-idf/blob/master/components/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

View file

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

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This XSL transform converts Doxygen XML output for a header file into Sphinx/Breathe compatible list of APIs -->
<!-- Usage: xsltproc doxygen_xml_to_rst.xslt xml/esp__xxxx_8h.xml -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:text>Macros&#xA;</xsl:text>
<xsl:text>^^^^^^&#xA;&#xA;</xsl:text>
<xsl:for-each select="doxygen/compounddef/sectiondef/memberdef[@kind='define']">
<xsl:text>.. doxygendefine:: </xsl:text>
<xsl:value-of select="name"/>
<xsl:text>&#xA;</xsl:text>
</xsl:for-each>
<xsl:text>&#xA;</xsl:text>
<xsl:text>Type Definitions&#xA;</xsl:text>
<xsl:text>^^^^^^^^^^^^^^^^&#xA;&#xA;</xsl:text>
<xsl:for-each select="doxygen/compounddef/sectiondef/memberdef[@kind='typedef']">
<xsl:text>.. doxygentypedef:: </xsl:text>
<xsl:value-of select="name"/>
<xsl:text>&#xA;</xsl:text>
</xsl:for-each>
<xsl:text>&#xA;</xsl:text>
<xsl:text>Enumerations&#xA;</xsl:text>
<xsl:text>^^^^^^^^^^^^&#xA;&#xA;</xsl:text>
<xsl:for-each select="doxygen/compounddef/sectiondef/memberdef[@kind='enum']">
<xsl:text>.. doxygenenum:: </xsl:text>
<xsl:value-of select="name"/>
<xsl:text>&#xA;</xsl:text>
</xsl:for-each>
<xsl:text>&#xA;</xsl:text>
<!-- TODO: figure out why structures are listed as innerclass instances -->
<xsl:text>Structures&#xA;</xsl:text>
<xsl:text>^^^^^^^^^^&#xA;&#xA;</xsl:text>
<xsl:for-each select="doxygen/compounddef/innerclass">
<xsl:text>.. doxygenstruct:: </xsl:text>
<xsl:value-of select="."/>
<xsl:text>&#xA;</xsl:text>
</xsl:for-each>
<xsl:text>&#xA;</xsl:text>
<xsl:text>Functions&#xA;</xsl:text>
<xsl:text>^^^^^^^^^&#xA;&#xA;</xsl:text>
<xsl:for-each select="doxygen/compounddef/sectiondef/memberdef[@kind='function']">
<xsl:text>.. doxygenfunction:: </xsl:text>
<xsl:value-of select="name"/>
<xsl:text>&#xA;</xsl:text>
</xsl:for-each>
<xsl:text>&#xA;</xsl:text>
</xsl:template>
</xsl:stylesheet>

125
docs/general-notes.rst Normal file
View file

@ -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 <deep-sleep-stub>` 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 <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 <deep-sleep-stub>` 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 <deep-sleep-stub>` documentation.

View file

@ -28,6 +28,7 @@ Contents:
:caption: What Else?
:maxdepth: 1
General Notes <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 <api/wdts>
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 <api/esp_wifi>
Bluetooth <api/bt>
Watchdogs <api/wdts>
api/gpio
api/uart
api/ledc
SPI Flash and Partition APIs <api/spi_flash>
Logging <api/log>
Non-Volatile Storage <api/nvs_flash>
Virtual Filesystem <api/vfs>

View file

@ -40,10 +40,8 @@ Installing OpenOCD
The sources for the ESP32-enabled variant of OpenOCD are available from `Espressifs Github <https://github.com/espressif/openocd-esp32>`_.
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.

View file

@ -17,16 +17,6 @@ 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
-------------------------
@ -34,23 +24,23 @@ Here is the summary printed for the "Single factory app, no OTA" configuration::
# Espressif ESP32 Partition Table
# Name, Type, SubType, Offset, Size
nvs, data, nvs, 0x9000, 0x6000
phy_init, data, phy, 0xf000, 0x1000
factory, app, factory, 0x10000, 1M
rfdata, data, rf, 0x110000, 256K
wifidata,data, wifi, 0x150000, 256K
* 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
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,12 +55,12 @@ 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.
@ -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
---------------------------------

View file

@ -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,6 +30,7 @@ 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.)
@ -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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,3 @@
#
# Main Makefile. This is basically the same as a component makefile.
#

View file

@ -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 <string.h>
#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();
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 <string.h>
#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" \
"<html>\r\n" \
"<head>\r\n" \
"<title>OpenSSL demo</title></head><body>\r\n" \
"OpenSSL server demo!\r\n" \
"</body>\r\n" \
"</html>\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();
}

View file

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

View file

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

View file

@ -20,8 +20,13 @@ for example in ${IDF_PATH}/examples/*; do
mkdir ${EXAMPLE_NUM}
cp -r ${example} ${EXAMPLE_NUM}
pushd ${EXAMPLE_NUM}/`basename ${example}`
# 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 defconfig all || (RESULT=$?; make V=1)
(make clean defconfig && make all ) || (RESULT=$?; make V=1)
popd
EXAMPLE_NUM=$(( $EXAMPLE_NUM + 1 ))
done

View file

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

View file

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

View file

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