tags:
- build_docs
artifacts:
+ when: always
paths:
+ - docs/doxygen-warning-log.txt
+ - docs/sphinx-warning-log.txt
- docs/_build/html
expire_in: 1 mos
script:
- cd docs
- doxygen
- # If not building master branch, and there are Doxygen warnings, print them and bail out
- - test -n $IS_PRIVATE && test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false )
+ # If there are Doxygen warnings, print them and bail out
+ - test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false )
- make gh-linkcheck
- make html
+ # If there are Sphinx warnings, print them and bail out
+ # Ignore warnings (sphinx-known-warnings.txt) already reported in:
+ # https://github.com/sphinx-doc/sphinx/issues/2683
+ # https://github.com/sphinx-doc/sphinx/issues/4041
+ # If a new warning has to be added, then it should be documented as above
+ # Note: this check is not clever enough to ignore the same warning
+ # but reported for different line of documentation.
+ # If s warning stays the same and the line number has changed,
+ # then update 'sphinx-known-warnings.txt' to reflect the new lines numbers.
+ - DIFF_FORMAT="--changed-group-format=%<%> --unchanged-group-format="
+ - LOG_DIFF=$(diff $DIFF_FORMAT sphinx-known-warnings.txt sphinx-warning-log.txt)
+ - test -z "$LOG_DIFF" || ( echo "Sphinx pass had some new warnings:" && echo "$LOG_DIFF" && false )
test_nvs_on_host:
stage: test
[submodule "components/libsodium/libsodium"]
path = components/libsodium/libsodium
url = https://github.com/jedisct1/libsodium.git
+
+[submodule "components/spiffs/spiffs"]
+ path = components/spiffs/spiffs
+ url = https://github.com/pellepl/spiffs.git
cpu_freq = RTC_CPU_FREQ_240M;
}
- uart_tx_wait_idle(0);
rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
clk_cfg.cpu_freq = cpu_freq;
#include "alarm.h"
#include "thread.h"
#include "mutex.h"
+#include "fixed_queue.h"
typedef struct {
uint16_t opcode;
#include "bt_types.h"
#include "allocator.h"
-#include "fixed_queue.h"
#include "osi.h"
#include "future.h"
///// LEGACY DEFINITIONS /////
gatt_free_pending_ind(p_tcb);
gatt_free_pending_enc_queue(p_tcb);
gatt_free_pending_prepare_write_queue(p_tcb);
+#if (GATTS_INCLUDED == TRUE)
fixed_queue_free(p_tcb->sr_cmd.multi_rsp_q, osi_free_func);
p_tcb->sr_cmd.multi_rsp_q = NULL;
-
+#endif ///GATTS_INCLUDED == TRUE
for (i = 0; i < GATT_MAX_APPS; i ++) {
p_reg = &gatt_cb.cl_rcb[i];
if (p_reg->in_use && p_reg->app_cb.p_conn_cb) {
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
+#include "soc/adc_channel.h"
typedef enum {
ADC_ATTEN_0db = 0, /*!<The input voltage of ADC will be reduced to about 1/1 */
ADC1_CHANNEL_MAX,
} adc1_channel_t;
+typedef enum {
+ ADC2_CHANNEL_0 = 0, /*!< ADC2 channel 0 is GPIO4 */
+ ADC2_CHANNEL_1, /*!< ADC2 channel 1 is GPIO0 */
+ ADC2_CHANNEL_2, /*!< ADC2 channel 2 is GPIO2 */
+ ADC2_CHANNEL_3, /*!< ADC2 channel 3 is GPIO15 */
+ ADC2_CHANNEL_4, /*!< ADC2 channel 4 is GPIO13 */
+ ADC2_CHANNEL_5, /*!< ADC2 channel 5 is GPIO12 */
+ ADC2_CHANNEL_6, /*!< ADC2 channel 6 is GPIO14 */
+ ADC2_CHANNEL_7, /*!< ADC2 channel 7 is GPIO27 */
+ ADC2_CHANNEL_8, /*!< ADC2 channel 8 is GPIO25 */
+ ADC2_CHANNEL_9, /*!< ADC2 channel 9 is GPIO26 */
+ ADC2_CHANNEL_MAX,
+} adc2_channel_t;
+
/**
* @brief Configure ADC1 capture width.
*
#include <stdint.h>
#include "esp_err.h"
+#include "soc/dac_channel.h"
typedef enum {
DAC_CHANNEL_1 = 1, /*!< DAC channel 1 is GPIO25 */
#include <stdint.h>
#include "esp_err.h"
#include "driver/gpio.h"
+#include "soc/rtc_gpio_channel.h"
#ifdef __cplusplus
extern "C" {
#include "esp_intr.h"
#include "esp_err.h"
#include "esp_intr_alloc.h"
+#include "soc/touch_channel.h"
typedef enum {
TOUCH_PAD_NUM0 = 0, /*!< Touch pad channel 0 is GPIO4 */
typedef intr_handle_t touch_isr_handle_t;
-#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT (0x1000) /*!<The timer frequency is RTC_SLOW_CLK( can be 150k or 32k depending on the options), max value is 0xffff */
-#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (0xffff) /*!<The time frequency is 8Mhz, the max value is 0xffff */
-#define TOUCH_FSM_MODE_DEFAULT (TOUCH_FSM_MODE_TIMER)
-#define TOUCH_TRIGGER_MODE_DEFAULT (TOUCH_TRIGGER_BELOW)
-#define TOUCH_TRIGGER_SOURCE_DEFAULT (TOUCH_TRIGGER_SOURCE_SET1)
+#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT (0x1000) /*!<The timer frequency is RTC_SLOW_CLK (can be 150k or 32k depending on the options), max value is 0xffff */
+#define TOUCH_PAD_MEASURE_CYCLE_DEFAULT (0xffff) /*!<The timer frequency is 8Mhz, the max value is 0xffff */
+#define TOUCH_FSM_MODE_DEFAULT (TOUCH_FSM_MODE_TIMER) /*!<The touch FSM my be started by the software or timer */
+#define TOUCH_TRIGGER_MODE_DEFAULT (TOUCH_TRIGGER_BELOW) /*!<Interrupts can be triggered if sensor value gets below or above threshold */
+#define TOUCH_TRIGGER_SOURCE_DEFAULT (TOUCH_TRIGGER_SOURCE_SET1) /*!<The wakeup trigger source can be SET1 or both SET1 and SET2 */
#define TOUCH_PAD_BIT_MASK_MAX (0x3ff)
/**
* @brief Configure touch pad interrupt threshold.
* @param touch_num touch pad index
* @param threshold interrupt threshold,
- * @return - ESP_OK Success
- * - ESP_ERR_INVALID_ARG if argument wrong
- * - ESP_FAIL if touch pad not initialized
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG if argument wrong
+ * - ESP_FAIL if touch pad not initialized
*/
esp_err_t touch_pad_config(touch_pad_t touch_num, uint16_t threshold);
*
* @param touch_num touch pad index
* @param touch_value pointer to accept touch sensor value
- * @return - ESP_OK Success
- * - ESP_ERR_INVALID_ARG Touch pad error
- * - ESP_FAIL Touch pad not initialized
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Touch pad error
+ * - ESP_FAIL Touch pad not initialized
*/
esp_err_t touch_pad_read(touch_pad_t touch_num, uint16_t * touch_value);
*
* @param touch_num touch pad index
* @param touch_value pointer to accept touch sensor value
- * @return - ESP_OK Success
- * - ESP_ERR_INVALID_ARG Touch pad error
- * - ESP_FAIL Touch pad not initialized
+ * @return
+ * - ESP_OK Success
+ * - ESP_ERR_INVALID_ARG Touch pad error
+ * - ESP_FAIL Touch pad not initialized
*/
esp_err_t touch_pad_read_filtered(touch_pad_t touch_num, uint16_t *touch_value);
*
* If filter is not initialized, this API will initialize the filter with given period.
* If filter is already initialized, this API will update the filter period.
- * @note This filter uses FreeRTOS timer, which is dipatched from a task with
+ * @note This filter uses FreeRTOS timer, which is dispatched from a task with
* priority 1 by default on CPU 0. So if some application task with higher priority
* takes a lot of CPU0 time, then the quality of data obtained from this filter will be affected.
* You can adjust FreeRTOS timer task priority in menuconfig.
#include "freertos/queue.h"
#include "freertos/ringbuf.h"
#include <esp_types.h>
+#include "soc/uart_channel.h"
#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */
#define UART_INTR_MASK 0x1ff /*!< mask of all UART interrupts */
*/
esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
+/**
+ * @brief Set software flow control.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param enable switch on or off
+ * @param rx_thresh_xon low water mark
+ * @param rx_thresh_xoff high water mark
+ *
+ * @return
+ * - ESP_OK Success
+ * - ESP_FAIL Parameter error
+ */
+ esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff);
+
/**
* @brief Get hardware flow control mode
*
//Reg,Mux,Fun,IE,Up,Down,Rtc_number
const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
- {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, 11}, //0
+ {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_MUX_SEL_M, RTC_IO_TOUCH_PAD1_FUN_SEL_S, RTC_IO_TOUCH_PAD1_FUN_IE_M, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M, RTC_IO_TOUCH_PAD1_SLP_SEL_M, RTC_IO_TOUCH_PAD1_SLP_IE_M, RTC_IO_TOUCH_PAD1_HOLD_M, RTC_CNTL_TOUCH_PAD1_HOLD_FORCE_M, RTC_IO_TOUCH_PAD1_DRV_V, RTC_IO_TOUCH_PAD1_DRV_S, RTCIO_GPIO0_CHANNEL}, //0
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //1
- {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, RTC_IO_TOUCH_PAD2_HOLD_M, RTC_CNTL_TOUCH_PAD2_HOLD_FORCE_M, RTC_IO_TOUCH_PAD2_DRV_V, RTC_IO_TOUCH_PAD2_DRV_S, 12}, //2
+ {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_MUX_SEL_M, RTC_IO_TOUCH_PAD2_FUN_SEL_S, RTC_IO_TOUCH_PAD2_FUN_IE_M, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M, RTC_IO_TOUCH_PAD2_SLP_SEL_M, RTC_IO_TOUCH_PAD2_SLP_IE_M, RTC_IO_TOUCH_PAD2_HOLD_M, RTC_CNTL_TOUCH_PAD2_HOLD_FORCE_M, RTC_IO_TOUCH_PAD2_DRV_V, RTC_IO_TOUCH_PAD2_DRV_S, RTCIO_GPIO2_CHANNEL}, //2
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //3
- {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, RTC_IO_TOUCH_PAD0_HOLD_M, RTC_CNTL_TOUCH_PAD0_HOLD_FORCE_M, RTC_IO_TOUCH_PAD0_DRV_V, RTC_IO_TOUCH_PAD0_DRV_S, 10}, //4
+ {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_MUX_SEL_M, RTC_IO_TOUCH_PAD0_FUN_SEL_S, RTC_IO_TOUCH_PAD0_FUN_IE_M, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M, RTC_IO_TOUCH_PAD0_SLP_SEL_M, RTC_IO_TOUCH_PAD0_SLP_IE_M, RTC_IO_TOUCH_PAD0_HOLD_M, RTC_CNTL_TOUCH_PAD0_HOLD_FORCE_M, RTC_IO_TOUCH_PAD0_DRV_V, RTC_IO_TOUCH_PAD0_DRV_S, RTCIO_GPIO4_CHANNEL}, //4
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //5
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //6
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //7
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //9
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //10
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //11
- {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, RTC_IO_TOUCH_PAD5_HOLD_M, RTC_CNTL_TOUCH_PAD5_HOLD_FORCE_M, RTC_IO_TOUCH_PAD5_DRV_V, RTC_IO_TOUCH_PAD5_DRV_S, 15}, //12
- {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, RTC_IO_TOUCH_PAD4_HOLD_M, RTC_CNTL_TOUCH_PAD4_HOLD_FORCE_M, RTC_IO_TOUCH_PAD4_DRV_V, RTC_IO_TOUCH_PAD4_DRV_S, 14}, //13
- {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, RTC_IO_TOUCH_PAD6_HOLD_M, RTC_CNTL_TOUCH_PAD6_HOLD_FORCE_M, RTC_IO_TOUCH_PAD6_DRV_V, RTC_IO_TOUCH_PAD6_DRV_S, 16}, //14
- {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, RTC_IO_TOUCH_PAD3_HOLD_M, RTC_CNTL_TOUCH_PAD3_HOLD_FORCE_M, RTC_IO_TOUCH_PAD3_DRV_V, RTC_IO_TOUCH_PAD3_DRV_S, 13}, //15
+ {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_MUX_SEL_M, RTC_IO_TOUCH_PAD5_FUN_SEL_S, RTC_IO_TOUCH_PAD5_FUN_IE_M, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M, RTC_IO_TOUCH_PAD5_SLP_SEL_M, RTC_IO_TOUCH_PAD5_SLP_IE_M, RTC_IO_TOUCH_PAD5_HOLD_M, RTC_CNTL_TOUCH_PAD5_HOLD_FORCE_M, RTC_IO_TOUCH_PAD5_DRV_V, RTC_IO_TOUCH_PAD5_DRV_S, RTCIO_GPIO12_CHANNEL}, //12
+ {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_MUX_SEL_M, RTC_IO_TOUCH_PAD4_FUN_SEL_S, RTC_IO_TOUCH_PAD4_FUN_IE_M, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M, RTC_IO_TOUCH_PAD4_SLP_SEL_M, RTC_IO_TOUCH_PAD4_SLP_IE_M, RTC_IO_TOUCH_PAD4_HOLD_M, RTC_CNTL_TOUCH_PAD4_HOLD_FORCE_M, RTC_IO_TOUCH_PAD4_DRV_V, RTC_IO_TOUCH_PAD4_DRV_S, RTCIO_GPIO13_CHANNEL}, //13
+ {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_MUX_SEL_M, RTC_IO_TOUCH_PAD6_FUN_SEL_S, RTC_IO_TOUCH_PAD6_FUN_IE_M, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M, RTC_IO_TOUCH_PAD6_SLP_SEL_M, RTC_IO_TOUCH_PAD6_SLP_IE_M, RTC_IO_TOUCH_PAD6_HOLD_M, RTC_CNTL_TOUCH_PAD6_HOLD_FORCE_M, RTC_IO_TOUCH_PAD6_DRV_V, RTC_IO_TOUCH_PAD6_DRV_S, RTCIO_GPIO14_CHANNEL}, //14
+ {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_MUX_SEL_M, RTC_IO_TOUCH_PAD3_FUN_SEL_S, RTC_IO_TOUCH_PAD3_FUN_IE_M, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M, RTC_IO_TOUCH_PAD3_SLP_SEL_M, RTC_IO_TOUCH_PAD3_SLP_IE_M, RTC_IO_TOUCH_PAD3_HOLD_M, RTC_CNTL_TOUCH_PAD3_HOLD_FORCE_M, RTC_IO_TOUCH_PAD3_DRV_V, RTC_IO_TOUCH_PAD3_DRV_S, RTCIO_GPIO15_CHANNEL}, //15
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //16
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //17
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //18
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //22
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //23
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //24
- {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, RTC_IO_PDAC1_DRV_V, RTC_IO_PDAC1_DRV_S, 6}, //25
- {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, RTC_IO_PDAC2_DRV_V, RTC_IO_PDAC2_DRV_S, 7}, //26
- {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, RTC_IO_TOUCH_PAD7_DRV_V, RTC_IO_TOUCH_PAD7_DRV_S, 17}, //27
+ {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_MUX_SEL_M, RTC_IO_PDAC1_FUN_SEL_S, RTC_IO_PDAC1_FUN_IE_M, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M, RTC_IO_PDAC1_SLP_SEL_M, RTC_IO_PDAC1_SLP_IE_M, RTC_IO_PDAC1_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, RTC_IO_PDAC1_DRV_V, RTC_IO_PDAC1_DRV_S, RTCIO_GPIO25_CHANNEL}, //25
+ {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_MUX_SEL_M, RTC_IO_PDAC2_FUN_SEL_S, RTC_IO_PDAC2_FUN_IE_M, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M, RTC_IO_PDAC2_SLP_SEL_M, RTC_IO_PDAC2_SLP_IE_M, RTC_IO_PDAC2_HOLD_M, RTC_CNTL_PDAC1_HOLD_FORCE_M, RTC_IO_PDAC2_DRV_V, RTC_IO_PDAC2_DRV_S, RTCIO_GPIO26_CHANNEL}, //26
+ {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_MUX_SEL_M, RTC_IO_TOUCH_PAD7_FUN_SEL_S, RTC_IO_TOUCH_PAD7_FUN_IE_M, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M, RTC_IO_TOUCH_PAD7_SLP_SEL_M, RTC_IO_TOUCH_PAD7_SLP_IE_M, RTC_IO_TOUCH_PAD7_HOLD_M, RTC_CNTL_TOUCH_PAD7_HOLD_FORCE_M, RTC_IO_TOUCH_PAD7_DRV_V, RTC_IO_TOUCH_PAD7_DRV_S, RTCIO_GPIO27_CHANNEL}, //27
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //28
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //29
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //30
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1}, //31
- {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, RTC_IO_X32P_HOLD_M, RTC_CNTL_X32P_HOLD_FORCE_M, RTC_IO_X32P_DRV_V, RTC_IO_X32P_DRV_S, 9}, //32
- {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, RTC_IO_X32N_HOLD_M, RTC_CNTL_X32N_HOLD_FORCE_M, RTC_IO_X32N_DRV_V, RTC_IO_X32N_DRV_S, 8}, //33
- {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC1_HOLD_FORCE_M, 0, 0, 4}, //34
- {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC2_HOLD_FORCE_M, 0, 0, 5}, //35
- {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE1_HOLD_FORCE_M, 0, 0, 0}, //36
- {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE2_HOLD_FORCE_M, 0, 0, 1}, //37
- {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE3_HOLD_FORCE_M, 0, 0, 2}, //38
- {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE4_HOLD_FORCE_M, 0, 0, 3}, //39
+ {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_MUX_SEL_M, RTC_IO_X32P_FUN_SEL_S, RTC_IO_X32P_FUN_IE_M, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M, RTC_IO_X32P_SLP_SEL_M, RTC_IO_X32P_SLP_IE_M, RTC_IO_X32P_HOLD_M, RTC_CNTL_X32P_HOLD_FORCE_M, RTC_IO_X32P_DRV_V, RTC_IO_X32P_DRV_S, RTCIO_GPIO32_CHANNEL}, //32
+ {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL_M, RTC_IO_X32N_FUN_SEL_S, RTC_IO_X32N_FUN_IE_M, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M, RTC_IO_X32N_SLP_SEL_M, RTC_IO_X32N_SLP_IE_M, RTC_IO_X32N_HOLD_M, RTC_CNTL_X32N_HOLD_FORCE_M, RTC_IO_X32N_DRV_V, RTC_IO_X32N_DRV_S, RTCIO_GPIO33_CHANNEL}, //33
+ {RTC_IO_ADC_PAD_REG, RTC_IO_ADC1_MUX_SEL_M, RTC_IO_ADC1_FUN_SEL_S, RTC_IO_ADC1_FUN_IE_M, 0, 0, RTC_IO_ADC1_SLP_SEL_M, RTC_IO_ADC1_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC1_HOLD_FORCE_M, 0, 0, RTCIO_GPIO34_CHANNEL}, //34
+ {RTC_IO_ADC_PAD_REG, RTC_IO_ADC2_MUX_SEL_M, RTC_IO_ADC2_FUN_SEL_S, RTC_IO_ADC2_FUN_IE_M, 0, 0, RTC_IO_ADC2_SLP_SEL_M, RTC_IO_ADC2_SLP_IE_M, RTC_IO_ADC1_HOLD_M, RTC_CNTL_ADC2_HOLD_FORCE_M, 0, 0, RTCIO_GPIO35_CHANNEL}, //35
+ {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE1_MUX_SEL_M, RTC_IO_SENSE1_FUN_SEL_S, RTC_IO_SENSE1_FUN_IE_M, 0, 0, RTC_IO_SENSE1_SLP_SEL_M, RTC_IO_SENSE1_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE1_HOLD_FORCE_M, 0, 0, RTCIO_GPIO36_CHANNEL}, //36
+ {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE2_MUX_SEL_M, RTC_IO_SENSE2_FUN_SEL_S, RTC_IO_SENSE2_FUN_IE_M, 0, 0, RTC_IO_SENSE2_SLP_SEL_M, RTC_IO_SENSE2_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE2_HOLD_FORCE_M, 0, 0, RTCIO_GPIO37_CHANNEL}, //37
+ {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE3_MUX_SEL_M, RTC_IO_SENSE3_FUN_SEL_S, RTC_IO_SENSE3_FUN_IE_M, 0, 0, RTC_IO_SENSE3_SLP_SEL_M, RTC_IO_SENSE3_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE3_HOLD_FORCE_M, 0, 0, RTCIO_GPIO38_CHANNEL}, //38
+ {RTC_IO_SENSOR_PADS_REG, RTC_IO_SENSE4_MUX_SEL_M, RTC_IO_SENSE4_FUN_SEL_S, RTC_IO_SENSE4_FUN_IE_M, 0, 0, RTC_IO_SENSE4_SLP_SEL_M, RTC_IO_SENSE4_SLP_IE_M, RTC_IO_SENSE1_HOLD_M, RTC_CNTL_SENSE4_HOLD_FORCE_M, 0, 0, RTCIO_GPIO39_CHANNEL}, //39
};
/*---------------------------------------------------------------
{
switch (touch_num) {
case TOUCH_PAD_NUM0:
- *gpio_num = 4;
+ *gpio_num = TOUCH_PAD_NUM0_GPIO_NUM;
break;
case TOUCH_PAD_NUM1:
- *gpio_num = 0;
+ *gpio_num = TOUCH_PAD_NUM1_GPIO_NUM;
break;
case TOUCH_PAD_NUM2:
- *gpio_num = 2;
+ *gpio_num = TOUCH_PAD_NUM2_GPIO_NUM;
break;
case TOUCH_PAD_NUM3:
- *gpio_num = 15;
+ *gpio_num = TOUCH_PAD_NUM3_GPIO_NUM;
break;
case TOUCH_PAD_NUM4:
- *gpio_num = 13;
+ *gpio_num = TOUCH_PAD_NUM4_GPIO_NUM;
break;
case TOUCH_PAD_NUM5:
- *gpio_num = 12;
+ *gpio_num = TOUCH_PAD_NUM5_GPIO_NUM;
break;
case TOUCH_PAD_NUM6:
- *gpio_num = 14;
+ *gpio_num = TOUCH_PAD_NUM6_GPIO_NUM;
break;
case TOUCH_PAD_NUM7:
- *gpio_num = 27;
+ *gpio_num = TOUCH_PAD_NUM7_GPIO_NUM;
break;
case TOUCH_PAD_NUM8:
- *gpio_num = 32;
+ *gpio_num = TOUCH_PAD_NUM8_GPIO_NUM;
break;
case TOUCH_PAD_NUM9:
- *gpio_num = 33;
+ *gpio_num = TOUCH_PAD_NUM9_GPIO_NUM;
break;
default:
return ESP_ERR_INVALID_ARG;
switch (channel) {
case ADC1_CHANNEL_0:
- *gpio_num = 36;
+ *gpio_num = ADC1_CHANNEL_0_GPIO_NUM;
break;
case ADC1_CHANNEL_1:
- *gpio_num = 37;
+ *gpio_num = ADC1_CHANNEL_1_GPIO_NUM;
break;
case ADC1_CHANNEL_2:
- *gpio_num = 38;
+ *gpio_num = ADC1_CHANNEL_2_GPIO_NUM;
break;
case ADC1_CHANNEL_3:
- *gpio_num = 39;
+ *gpio_num = ADC1_CHANNEL_3_GPIO_NUM;
break;
case ADC1_CHANNEL_4:
- *gpio_num = 32;
+ *gpio_num = ADC1_CHANNEL_4_GPIO_NUM;
break;
case ADC1_CHANNEL_5:
- *gpio_num = 33;
+ *gpio_num = ADC1_CHANNEL_5_GPIO_NUM;
break;
case ADC1_CHANNEL_6:
- *gpio_num = 34;
+ *gpio_num = ADC1_CHANNEL_6_GPIO_NUM;
break;
case ADC1_CHANNEL_7:
- *gpio_num = 35;
+ *gpio_num = ADC1_CHANNEL_7_GPIO_NUM;
break;
default:
return ESP_ERR_INVALID_ARG;
switch (channel) {
case DAC_CHANNEL_1:
- *gpio_num = 25;
+ *gpio_num = DAC_CHANNEL_1_GPIO_NUM;
break;
case DAC_CHANNEL_2:
- *gpio_num = 26;
+ *gpio_num = DAC_CHANNEL_2_GPIO_NUM;
break;
default:
return ESP_ERR_INVALID_ARG;
#include "driver/uart.h"
#include "driver/gpio.h"
+#define XOFF (char)0x13
+#define XON (char)0x11
+
static const char* UART_TAG = "uart";
#define UART_CHECK(a, str, ret_val) \
if (!(a)) { \
return ESP_OK;
}
+esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff)
+{
+ UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+ UART_CHECK((rx_thresh_xon < UART_FIFO_LEN), "rx flow xon thresh error", ESP_FAIL);
+ UART_CHECK((rx_thresh_xoff < UART_FIFO_LEN), "rx flow xon thresh error", ESP_FAIL);
+ UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+ UART[uart_num]->flow_conf.sw_flow_con_en = enable? 1:0;
+ UART[uart_num]->flow_conf.xonoff_del = enable?1:0;
+ UART[uart_num]->swfc_conf.xon_threshold = rx_thresh_xon;
+ UART[uart_num]->swfc_conf.xoff_threshold = rx_thresh_xoff;
+ UART[uart_num]->swfc_conf.xon_char = XON;
+ UART[uart_num]->swfc_conf.xoff_char = XOFF;
+ UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+ return ESP_OK;
+}
+
//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set.
esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh)
{
#include "esp_attr.h"
#include "soc/dport_reg.h"
#include "sdkconfig.h"
+#include "esp_dport_access.h"
void esp_cache_err_int_init()
{
int IRAM_ATTR esp_cache_err_get_cpuid()
{
+ esp_dport_access_int_pause();
const uint32_t pro_mask =
DPORT_PRO_CPU_DISABLED_CACHE_IA_DRAM1 |
DPORT_PRO_CPU_DISABLED_CACHE_IA_DROM0 |
assert(res == pdTRUE);
}
-void esp_dport_access_int_pause(void)
+void IRAM_ATTR esp_dport_access_int_pause(void)
{
portENTER_CRITICAL_ISR(&g_dport_mux);
dport_core_state[0] = DPORT_CORE_STATE_IDLE;
portEXIT_CRITICAL_ISR(&g_dport_mux);
}
-void esp_dport_access_int_resume(void)
+void IRAM_ATTR esp_dport_access_int_resume(void)
{
portENTER_CRITICAL_ISR(&g_dport_mux);
dport_core_state[0] = DPORT_CORE_STATE_RUNNING;
const size_t workbuf_size = 4096;
void *workbuf = NULL;
- esp_partition_t *data_partition = (esp_partition_t *)esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, partition_label);
+ esp_partition_subtype_t subtype = partition_label ?
+ ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_FAT;
+ const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
+ subtype, partition_label);
if (data_partition == NULL) {
ESP_LOGE(TAG, "Failed to find FATFS partition (type='data', subtype='fat', partition_label='%s'). Check the partition table.", partition_label);
return ESP_ERR_NOT_FOUND;
#define configXT_BOARD 1 /* Board mode */
#define configXT_SIMULATOR 0
-#if CONFIG_ESP32_ENABLE_COREDUMP
#define configENABLE_TASK_SNAPSHOT 1
-#endif
#if CONFIG_SYSVIEW_ENABLE
#ifndef __ASSEMBLER__
#endif /* configUSE_TASK_NOTIFICATIONS */
#if ( configENABLE_TASK_SNAPSHOT == 1 )
-
- static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, TCB_t *pxTCB )
- {
- pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
- pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
- #if( portSTACK_GROWTH < 0 )
- {
- pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxEndOfStack;
- }
- #else
- {
- pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxStack;
- }
- #endif
- (*uxTask)++;
- }
+ static void prvTaskGetSnapshot( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, TCB_t *pxTCB )
+ {
+ if (pxTCB == NULL) {
+ return;
+ }
+ pxTaskSnapshotArray[ *uxTask ].pxTCB = pxTCB;
+ pxTaskSnapshotArray[ *uxTask ].pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
+ #if( portSTACK_GROWTH < 0 )
+ {
+ pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxEndOfStack;
+ }
+ #else
+ {
+ pxTaskSnapshotArray[ *uxTask ].pxEndOfStack = pxTCB->pxStack;
+ }
+ #endif
+ (*uxTask)++;
+ }
static void prvTaskGetSnapshotsFromList( TaskSnapshot_t *pxTaskSnapshotArray, UBaseType_t *uxTask, const UBaseType_t uxArraySize, List_t *pxList )
{
listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
do
{
- listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
-
if( *uxTask >= uxArraySize )
break;
- prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
+ listGET_OWNER_OF_NEXT_ENTRY( pxNextTCB, pxList );
+ prvTaskGetSnapshot( pxTaskSnapshotArray, uxTask, pxNextTCB );
} while( pxNextTCB != pxFirstTCB );
}
else
{
UBaseType_t uxTask = 0, i = 0;
-PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB[ portNUM_PROCESSORS ] = { NULL };
-
*pxTcbSz = sizeof(TCB_t);
/* Fill in an TaskStatus_t structure with information on each
task in the Blocked state. */
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxDelayedTaskList );
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, ( List_t * ) pxOverflowDelayedTaskList );
- for (i = 0; i < portNUM_PROCESSORS; i++) {
- if( uxTask >= uxArraySize )
- break;
- prvTaskGetSnapshot( pxTaskSnapshotArray, &uxTask, pxCurrentTCB[ i ] );
- prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( xPendingReadyList[ i ] ) );
- }
+ for (i = 0; i < portNUM_PROCESSORS; i++) {
+ if( uxTask >= uxArraySize )
+ break;
+ prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( xPendingReadyList[ i ] ) );
+ }
#if( INCLUDE_vTaskDelete == 1 )
{
--- /dev/null
+/*
+ Test FreeRTOS support for core dump.
+*/
+
+#include <stdio.h>
+#include "soc/cpu.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "unity.h"
+
+#define TEST_MAX_TASKS_NUM 32
+
+/* simple test to check that in normal conditions uxTaskGetSnapshotAll does not generate exception */
+TEST_CASE("Tasks snapshot", "[freertos]")
+{
+ TaskSnapshot_t tasks[TEST_MAX_TASKS_NUM];
+ UBaseType_t tcb_sz;
+ int other_core_id = xPortGetCoreID() == 0 ? 1 : 0;
+
+ // uxTaskGetSnapshotAll is supposed to be called when all tasks on both CPUs are
+ // inactive and can not alter FreeRTOS internal tasks lists, e.g. from panic handler
+ unsigned state = portENTER_CRITICAL_NESTED();
+#if CONFIG_FREERTOS_UNICORE == 0
+ esp_cpu_stall(other_core_id);
+#endif
+ UBaseType_t task_num = uxTaskGetSnapshotAll(tasks, TEST_MAX_TASKS_NUM, &tcb_sz);
+#if CONFIG_FREERTOS_UNICORE == 0
+ esp_cpu_unstall(other_core_id);
+#endif
+ portEXIT_CRITICAL_NESTED(state);
+
+ printf("Dumped %d tasks. TCB size %d\n", task_num, tcb_sz);
+ TEST_ASSERT_NOT_EQUAL(0, task_num);
+ TEST_ASSERT_NOT_EQUAL(0, tcb_sz);
+}
#include "tcpip_adapter.h"
#include "apps/dhcpserver.h"
+#include "apps/dhcpserver_options.h"
#if ESP_DHCP
#define DHCPS_STATE_IDLE 5
#define DHCPS_STATE_RELEASE 6
+typedef struct _list_node {
+ void *pnode;
+ struct _list_node *pnext;
+} list_node;
+
////////////////////////////////////////////////////////////////////////////////////
static const u32_t magic_cookie = 0x63538263;
* pinsert -- the insert node of the list
* Returns : none
*******************************************************************************/
-void node_insert_to_list(list_node **phead, list_node *pinsert)
+static void node_insert_to_list(list_node **phead, list_node *pinsert)
{
list_node *plist = NULL;
struct dhcps_pool *pdhcps_pool = NULL;
u8_t options[312];
}dhcps_msg;
-/** DHCP OPTIONS CODE **/
-typedef enum
-{
- /* RFC 1497 Vendor Extensions */
-
- PAD = 0,
- END = 255,
-
- SUBNET_MASK = 1,
- TIME_OFFSET = 2,
- ROUTER = 3,
- TIME_SERVER = 4,
- NAME_SERVER = 5,
- DOMAIN_NAME_SERVER = 6,
- LOG_SERVER = 7,
- COOKIE_SERVER = 8,
- LPR_SERVER = 9,
- IMPRESS_SERVER = 10,
- RESOURCE_LOCATION_SERVER = 11,
- HOST_NAME = 12,
- BOOT_FILE_SIZE = 13,
- MERIT_DUMP_FILE = 14,
- DOMAIN_NAME = 15,
- SWAP_SERVER = 16,
- ROOT_PATH = 17,
- EXTENSIONS_PATH = 18,
-
- /* IP Layer Parameters per Host */
-
- IP_FORWARDING = 19,
- NON_LOCAL_SOURCE_ROUTING = 20,
- POLICY_FILTER = 21,
- MAXIMUM_DATAGRAM_REASSEMBLY_SIZE = 22,
- DEFAULT_IP_TIME_TO_LIVE = 23,
- PATH_MTU_AGING_TIMEOUT = 24,
- PATH_MTU_PLATEAU_TABLE = 25,
-
- /* IP Layer Parameters per Interface */
-
- INTERFACE_MTU = 26,
- ALL_SUBNETS_ARE_LOCAL = 27,
- BROADCAST_ADDRESS = 28,
- PERFORM_MASK_DISCOVERY = 29,
- MASK_SUPPLIER = 30,
- PERFORM_ROUTER_DISCOVERY = 31,
- ROUTER_SOLICITATION_ADDRESS = 32,
- STATIC_ROUTE = 33,
-
- /* Link Layer Parameters per Interface */
-
- TRAILER_ENCAPSULATION = 34,
- ARP_CACHE_TIMEOUT = 35,
- ETHERNET_ENCAPSULATION = 36,
-
- /* TCP Parameters */
-
- TCP_DEFAULT_TTL = 37,
- TCP_KEEPALIVE_INTERVAL = 38,
- TCP_KEEPALIVE_GARBAGE = 39,
-
- /* Application and Service Parameters */
-
- NETWORK_INFORMATION_SERVICE_DOMAIN = 40,
- NETWORK_INFORMATION_SERVERS = 41,
- NETWORK_TIME_PROTOCOL_SERVERS = 42,
- VENDOR_SPECIFIC_INFORMATION = 43,
- NETBIOS_OVER_TCP_IP_NAME_SERVER = 44,
- NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER = 45,
- NETBIOS_OVER_TCP_IP_NODE_TYPE = 46,
- NETBIOS_OVER_TCP_IP_SCOPE = 47,
- X_WINDOW_SYSTEM_FONT_SERVER = 48,
- X_WINDOW_SYSTEM_DISPLAY_MANAGER = 49,
- NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN = 64,
- NETWORK_INFORMATION_SERVICE_PLUS_SERVERS = 65,
- MOBILE_IP_HOME_AGENT = 68,
- SMTP_SERVER = 69,
- POP3_SERVER = 70,
- NNTP_SERVER = 71,
- DEFAULT_WWW_SERVER = 72,
- DEFAULT_FINGER_SERVER = 73,
- DEFAULT_IRC_SERVER = 74,
- STREETTALK_SERVER = 75,
- STREETTALK_DIRECTORY_ASSISTANCE_SERVER = 76,
-
- /* DHCP Extensions */
-
- REQUESTED_IP_ADDRESS = 50,
- IP_ADDRESS_LEASE_TIME = 51,
- OPTION_OVERLOAD = 52,
- TFTP_SERVER_NAME = 66,
- BOOTFILE_NAME = 67,
- DHCP_MESSAGE_TYPE = 53,
- SERVER_IDENTIFIER = 54,
- PARAMETER_REQUEST_LIST = 55,
- MESSAGE = 56,
- MAXIMUM_DHCP_MESSAGE_SIZE = 57,
- RENEWAL_T1_TIME_VALUE = 58,
- REBINDING_T2_TIME_VALUE = 59,
- VENDOR_CLASS_IDENTIFIER = 60,
- CLIENT_IDENTIFIER = 61,
-
- USER_CLASS = 77,
- FQDN = 81,
- DHCP_AGENT_OPTIONS = 82,
- NDS_SERVERS = 85,
- NDS_TREE_NAME = 86,
- NDS_CONTEXT = 87,
- CLIENT_LAST_TRANSACTION_TIME = 91,
- ASSOCIATED_IP = 92,
- USER_AUTHENTICATION_PROTOCOL = 98,
- AUTO_CONFIGURE = 116,
- NAME_SERVICE_SEARCH = 117,
- SUBNET_SELECTION = 118,
- DOMAIN_SEARCH = 119,
- CLASSLESS_ROUTE = 121,
-} dhcp_msg_option;
-
/* Defined in esp_misc.h */
typedef struct {
bool enable;
u32_t lease_timer;
};
-typedef struct _list_node{
- void *pnode;
- struct _list_node *pnext;
-}list_node;
-
typedef u32_t dhcps_time_t;
typedef u8_t dhcps_offer_t;
--- /dev/null
+// Copyright 2017 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
+
+/** DHCP Options
+
+ This macros are not part of the public dhcpserver.h interface.
+ **/
+typedef enum
+{
+ /* RFC 1497 Vendor Extensions */
+
+ PAD = 0,
+ END = 255,
+
+ SUBNET_MASK = 1,
+ TIME_OFFSET = 2,
+ ROUTER = 3,
+ TIME_SERVER = 4,
+ NAME_SERVER = 5,
+ DOMAIN_NAME_SERVER = 6,
+ LOG_SERVER = 7,
+ COOKIE_SERVER = 8,
+ LPR_SERVER = 9,
+ IMPRESS_SERVER = 10,
+ RESOURCE_LOCATION_SERVER = 11,
+ HOST_NAME = 12,
+ BOOT_FILE_SIZE = 13,
+ MERIT_DUMP_FILE = 14,
+ DOMAIN_NAME = 15,
+ SWAP_SERVER = 16,
+ ROOT_PATH = 17,
+ EXTENSIONS_PATH = 18,
+
+ /* IP Layer Parameters per Host */
+
+ IP_FORWARDING = 19,
+ NON_LOCAL_SOURCE_ROUTING = 20,
+ POLICY_FILTER = 21,
+ MAXIMUM_DATAGRAM_REASSEMBLY_SIZE = 22,
+ DEFAULT_IP_TIME_TO_LIVE = 23,
+ PATH_MTU_AGING_TIMEOUT = 24,
+ PATH_MTU_PLATEAU_TABLE = 25,
+
+ /* IP Layer Parameters per Interface */
+
+ INTERFACE_MTU = 26,
+ ALL_SUBNETS_ARE_LOCAL = 27,
+ BROADCAST_ADDRESS = 28,
+ PERFORM_MASK_DISCOVERY = 29,
+ MASK_SUPPLIER = 30,
+ PERFORM_ROUTER_DISCOVERY = 31,
+ ROUTER_SOLICITATION_ADDRESS = 32,
+ STATIC_ROUTE = 33,
+
+ /* Link Layer Parameters per Interface */
+
+ TRAILER_ENCAPSULATION = 34,
+ ARP_CACHE_TIMEOUT = 35,
+ ETHERNET_ENCAPSULATION = 36,
+
+ /* TCP Parameters */
+
+ TCP_DEFAULT_TTL = 37,
+ TCP_KEEPALIVE_INTERVAL = 38,
+ TCP_KEEPALIVE_GARBAGE = 39,
+
+ /* Application and Service Parameters */
+
+ NETWORK_INFORMATION_SERVICE_DOMAIN = 40,
+ NETWORK_INFORMATION_SERVERS = 41,
+ NETWORK_TIME_PROTOCOL_SERVERS = 42,
+ VENDOR_SPECIFIC_INFORMATION = 43,
+ NETBIOS_OVER_TCP_IP_NAME_SERVER = 44,
+ NETBIOS_OVER_TCP_IP_DATAGRAM_DISTRIBUTION_SERVER = 45,
+ NETBIOS_OVER_TCP_IP_NODE_TYPE = 46,
+ NETBIOS_OVER_TCP_IP_SCOPE = 47,
+ X_WINDOW_SYSTEM_FONT_SERVER = 48,
+ X_WINDOW_SYSTEM_DISPLAY_MANAGER = 49,
+ NETWORK_INFORMATION_SERVICE_PLUS_DOMAIN = 64,
+ NETWORK_INFORMATION_SERVICE_PLUS_SERVERS = 65,
+ MOBILE_IP_HOME_AGENT = 68,
+ SMTP_SERVER = 69,
+ POP3_SERVER = 70,
+ NNTP_SERVER = 71,
+ DEFAULT_WWW_SERVER = 72,
+ DEFAULT_FINGER_SERVER = 73,
+ DEFAULT_IRC_SERVER = 74,
+ STREETTALK_SERVER = 75,
+ STREETTALK_DIRECTORY_ASSISTANCE_SERVER = 76,
+
+ /* DHCP Extensions */
+
+ REQUESTED_IP_ADDRESS = 50,
+ IP_ADDRESS_LEASE_TIME = 51,
+ OPTION_OVERLOAD = 52,
+ TFTP_SERVER_NAME = 66,
+ BOOTFILE_NAME = 67,
+ DHCP_MESSAGE_TYPE = 53,
+ SERVER_IDENTIFIER = 54,
+ PARAMETER_REQUEST_LIST = 55,
+ MESSAGE = 56,
+ MAXIMUM_DHCP_MESSAGE_SIZE = 57,
+ RENEWAL_T1_TIME_VALUE = 58,
+ REBINDING_T2_TIME_VALUE = 59,
+ VENDOR_CLASS_IDENTIFIER = 60,
+ CLIENT_IDENTIFIER = 61,
+
+ USER_CLASS = 77,
+ FQDN = 81,
+ DHCP_AGENT_OPTIONS = 82,
+ NDS_SERVERS = 85,
+ NDS_TREE_NAME = 86,
+ NDS_CONTEXT = 87,
+ CLIENT_LAST_TRANSACTION_TIME = 91,
+ ASSOCIATED_IP = 92,
+ USER_AUTHENTICATION_PROTOCOL = 98,
+ AUTO_CONFIGURE = 116,
+ NAME_SERVICE_SEARCH = 117,
+ SUBNET_SELECTION = 118,
+ DOMAIN_SEARCH = 119,
+ CLASSLESS_ROUTE = 121,
+} dhcp_msg_option;
return ESP_ERR_NVS_INVALID_LENGTH;
}
+ *length = dataSize;
return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize);
}
TEST_ESP_ERR(ESP_ERR_NVS_INVALID_LENGTH, nvs_get_str(handle_2, "key", buf, &buf_len_short));
CHECK(buf_len_short == buf_len);
+ size_t buf_len_long = buf_len + 1;
+ TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len_long));
+ CHECK(buf_len_long == buf_len);
+
TEST_ESP_OK(nvs_get_str(handle_2, "key", buf, &buf_len));
CHECK(0 == strcmp(buf, str));
--- /dev/null
+// Copyright 2010-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 _SOC_ADC_CHANNEL_H
+#define _SOC_ADC_CHANNEL_H
+
+#define ADC1_GPIO36_CHANNEL ADC1_CHANNEL_0
+#define ADC1_CHANNEL_0_GPIO_NUM 36
+
+#define ADC1_GPIO37_CHANNEL ADC1_CHANNEL_1
+#define ADC1_CHANNEL_1_GPIO_NUM 37
+
+#define ADC1_GPIO38_CHANNEL ADC1_CHANNEL_2
+#define ADC1_CHANNEL_2_GPIO_NUM 38
+
+#define ADC1_GPIO39_CHANNEL ADC1_CHANNEL_3
+#define ADC1_CHANNEL_3_GPIO_NUM 39
+
+#define ADC1_GPIO32_CHANNEL ADC1_CHANNEL_4
+#define ADC1_CHANNEL_4_GPIO_NUM 32
+
+#define ADC1_GPIO33_CHANNEL ADC1_CHANNEL_5
+#define ADC1_CHANNEL_5_GPIO_NUM 33
+
+#define ADC1_GPIO34_CHANNEL ADC1_CHANNEL_6
+#define ADC1_CHANNEL_6_GPIO_NUM 34
+
+#define ADC1_GPIO35_CHANNEL ADC1_CHANNEL_7
+#define ADC1_CHANNEL_7_GPIO_NUM 35
+
+#define ADC2_GPIO4_CHANNEL ADC2_CHANNEL_0
+#define ADC2_CHANNEL_0_GPIO_NUM 4
+
+#define ADC2_GPIO0_CHANNEL ADC2_CHANNEL_1
+#define ADC2_CHANNEL_1_GPIO_NUM 0
+
+#define ADC2_GPIO2_CHANNEL ADC2_CHANNEL_2
+#define ADC2_CHANNEL_2_GPIO_NUM 2
+
+#define ADC2_GPIO15_CHANNEL ADC2_CHANNEL_3
+#define ADC2_CHANNEL_3_GPIO_NUM 15
+
+#define ADC2_GPIO13_CHANNEL ADC2_CHANNEL_4
+#define ADC2_CHANNEL_4_GPIO_NUM 13
+
+#define ADC2_GPIO12_CHANNEL ADC2_CHANNEL_5
+#define ADC2_CHANNEL_5_GPIO_NUM 12
+
+#define ADC2_GPIO14_CHANNEL ADC2_CHANNEL_6
+#define ADC2_CHANNEL_6_GPIO_NUM 14
+
+#define ADC2_GPIO27_CHANNEL ADC2_CHANNEL_7
+#define ADC2_CHANNEL_7_GPIO_NUM 27
+
+#define ADC2_GPIO25_CHANNEL ADC2_CHANNEL_8
+#define ADC2_CHANNEL_8_GPIO_NUM 25
+
+#define ADC2_GPIO26_CHANNEL ADC2_CHANNEL_9
+#define ADC2_CHANNEL_9_GPIO_NUM 26
+
+#endif
--- /dev/null
+// Copyright 2010-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 _SOC_CLKOUT_CHANNEL_H
+#define _SOC_CLKOUT_CHANNEL_H
+
+//CLKOUT channels
+#define CLKOUT_GPIO0_DIRECT_CHANNEL CLKOUT_CHANNEL_1
+#define CLKOUT_CHANNEL_1_DIRECT_GPIO_NUM 0
+#define CLKOUT_GPIO3_DIRECT_CHANNEL CLKOUT_CHANNEL_2
+#define CLKOUT_CHANNEL_2_DIRECT_GPIO_NUM 3
+#define CLKOUT_GPIO1_DIRECT_CHANNEL CLKOUT_CHANNEL_3
+#define CLKOUT_CHANNEL_3_DIRECT_GPIO_NUM 1
+
+#endif
--- /dev/null
+// Copyright 2010-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 _SOC_DAC_CHANNEL_H
+#define _SOC_DAC_CHANNEL_H
+
+#define DAC_GPIO25_CHANNEL DAC_CHANNEL_1
+#define DAC_CHANNEL_1_GPIO_NUM 25
+
+#define DAC_GPIO26_CHANNEL DAC_CHANNEL_2
+#define DAC_CHANNEL_2_GPIO_NUM 26
+
+#endif
--- /dev/null
+// Copyright 2010-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 _SOC_RTC_GPIO_CHANNEL_H
+#define _SOC_RTC_GPIO_CHANNEL_H
+
+//RTC GPIO channels
+#define RTCIO_GPIO36_CHANNEL 0 //RTCIO_CHANNEL_0
+#define RTCIO_CHANNEL_0_GPIO_NUM 36
+
+#define RTCIO_GPIO37_CHANNEL 1 //RTCIO_CHANNEL_1
+#define RTCIO_CHANNEL_1_GPIO_NUM 37
+
+#define RTCIO_GPIO38_CHANNEL 2 //RTCIO_CHANNEL_2
+#define RTCIO_CHANNEL_2_GPIO_NUM 38
+
+#define RTCIO_GPIO39_CHANNEL 3 //RTCIO_CHANNEL_3
+#define RTCIO_CHANNEL_3_GPIO_NUM 39
+
+#define RTCIO_GPIO34_CHANNEL 4 //RTCIO_CHANNEL_4
+#define RTCIO_CHANNEL_4_GPIO_NUM 34
+
+#define RTCIO_GPIO35_CHANNEL 5 //RTCIO_CHANNEL_5
+#define RTCIO_CHANNEL_5_GPIO_NUM 35
+
+#define RTCIO_GPIO25_CHANNEL 6 //RTCIO_CHANNEL_6
+#define RTCIO_CHANNEL_6_GPIO_NUM 25
+
+#define RTCIO_GPIO26_CHANNEL 7 //RTCIO_CHANNEL_7
+#define RTCIO_CHANNEL_7_GPIO_NUM 26
+
+#define RTCIO_GPIO33_CHANNEL 8 //RTCIO_CHANNEL_8
+#define RTCIO_CHANNEL_8_GPIO_NUM 33
+
+#define RTCIO_GPIO32_CHANNEL 9 //RTCIO_CHANNEL_9
+#define RTCIO_CHANNEL_9_GPIO_NUM 32
+
+#define RTCIO_GPIO4_CHANNEL 10 //RTCIO_CHANNEL_10
+#define RTCIO_CHANNEL_10_GPIO_NUM 4
+
+#define RTCIO_GPIO0_CHANNEL 11 //RTCIO_CHANNEL_11
+#define RTCIO_CHANNEL_11_GPIO_NUM 0
+
+#define RTCIO_GPIO2_CHANNEL 12 //RTCIO_CHANNEL_12
+#define RTCIO_CHANNEL_12_GPIO_NUM 2
+
+#define RTCIO_GPIO15_CHANNEL 13 //RTCIO_CHANNEL_13
+#define RTCIO_CHANNEL_13_GPIO_NUM 15
+
+#define RTCIO_GPIO13_CHANNEL 14 //RTCIO_CHANNEL_14
+#define RTCIO_CHANNEL_14_GPIO_NUM 13
+
+#define RTCIO_GPIO12_CHANNEL 15 //RTCIO_CHANNEL_15
+#define RTCIO_CHANNEL_15_GPIO_NUM 12
+
+#define RTCIO_GPIO14_CHANNEL 16 //RTCIO_CHANNEL_16
+#define RTCIO_CHANNEL_16_GPIO_NUM 14
+
+#define RTCIO_GPIO27_CHANNEL 17 //RTCIO_CHANNEL_17
+#define RTCIO_CHANNEL_17_GPIO_NUM 27
+
+#endif
--- /dev/null
+// Copyright 2010-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 _SOC_TOUCH_CHANNEL_H
+#define _SOC_TOUCH_CHANNEL_H
+
+//Touch channels
+#define TOUCH_PAD_GPIO4_CHANNEL TOUCH_PAD_NUM0
+#define TOUCH_PAD_NUM0_GPIO_NUM 4
+
+#define TOUCH_PAD_GPIO0_CHANNEL TOUCH_PAD_NUM1
+#define TOUCH_PAD_NUM1_GPIO_NUM 0
+
+#define TOUCH_PAD_GPIO2_CHANNEL TOUCH_PAD_NUM2
+#define TOUCH_PAD_NUM2_GPIO_NUM 2
+
+#define TOUCH_PAD_GPIO15_CHANNEL TOUCH_PAD_NUM3
+#define TOUCH_PAD_NUM3_GPIO_NUM 15
+
+#define TOUCH_PAD_GPIO13_CHANNEL TOUCH_PAD_NUM4
+#define TOUCH_PAD_NUM4_GPIO_NUM 13
+
+#define TOUCH_PAD_GPIO12_CHANNEL TOUCH_PAD_NUM5
+#define TOUCH_PAD_NUM5_GPIO_NUM 12
+
+#define TOUCH_PAD_GPIO14_CHANNEL TOUCH_PAD_NUM6
+#define TOUCH_PAD_NUM6_GPIO_NUM 14
+
+#define TOUCH_PAD_GPIO27_CHANNEL TOUCH_PAD_NUM7
+#define TOUCH_PAD_NUM7_GPIO_NUM 27
+
+#define TOUCH_PAD_GPIO33_CHANNEL TOUCH_PAD_NUM8
+#define TOUCH_PAD_NUM8_GPIO_NUM 33
+
+#define TOUCH_PAD_GPIO32_CHANNEL TOUCH_PAD_NUM9
+#define TOUCH_PAD_NUM9_GPIO_NUM 32
+
+#endif
--- /dev/null
+// Copyright 2010-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 _SOC_UART_CHANNEL_H
+#define _SOC_UART_CHANNEL_H
+
+//UART channels
+#define UART_GPIO1_DIRECT_CHANNEL UART_NUM_0
+#define UART_NUM_0_TXD_DIRECT_GPIO_NUM 1
+#define UART_GPIO3_DIRECT_CHANNEL UART_NUM_0
+#define UART_NUM_0_RXD_DIRECT_GPIO_NUM 3
+#define UART_GPIO19_DIRECT_CHANNEL UART_NUM_0
+#define UART_NUM_0_CTS_DIRECT_GPIO_NUM 19
+#define UART_GPIO22_DIRECT_CHANNEL UART_NUM_0
+#define UART_NUM_0_RTS_DIRECT_GPIO_NUM 22
+
+#define UART_TXD_GPIO1_DIRECT_CHANNEL UART_GPIO1_DIRECT_CHANNEL
+#define UART_RXD_GPIO3_DIRECT_CHANNEL UART_GPIO3_DIRECT_CHANNEL
+#define UART_CTS_GPIO19_DIRECT_CHANNEL UART_GPIO19_DIRECT_CHANNEL
+#define UART_RTS_GPIO22_DIRECT_CHANNEL UART_GPIO22_DIRECT_CHANNEL
+
+#define UART_GPIO10_DIRECT_CHANNEL UART_NUM_1
+#define UART_NUM_1_TXD_DIRECT_GPIO_NUM 10
+#define UART_GPIO9_DIRECT_CHANNEL UART_NUM_1
+#define UART_NUM_1_RXD_DIRECT_GPIO_NUM 9
+#define UART_GPIO6_DIRECT_CHANNEL UART_NUM_1
+#define UART_NUM_1_CTS_DIRECT_GPIO_NUM 6
+#define UART_GPIO11_DIRECT_CHANNEL UART_NUM_1
+#define UART_NUM_1_RTS_DIRECT_GPIO_NUM 11
+
+#define UART_TXD_GPIO10_DIRECT_CHANNEL UART_GPIO10_DIRECT_CHANNEL
+#define UART_RXD_GPIO9_DIRECT_CHANNEL UART_GPIO9_DIRECT_CHANNEL
+#define UART_CTS_GPIO6_DIRECT_CHANNEL UART_GPIO6_DIRECT_CHANNEL
+#define UART_RTS_GPIO11_DIRECT_CHANNEL UART_GPIO11_DIRECT_CHANNEL
+
+#define UART_GPIO17_DIRECT_CHANNEL UART_NUM_2
+#define UART_NUM_2_TXD_DIRECT_GPIO_NUM 17
+#define UART_GPIO16_DIRECT_CHANNEL UART_NUM_2
+#define UART_NUM_2_RXD_DIRECT_GPIO_NUM 16
+#define UART_GPIO8_DIRECT_CHANNEL UART_NUM_2
+#define UART_NUM_2_CTS_DIRECT_GPIO_NUM 8
+#define UART_GPIO7_DIRECT_CHANNEL UART_NUM_2
+#define UART_NUM_2_RTS_DIRECT_GPIO_NUM 7
+
+#define UART_TXD_GPIO17_DIRECT_CHANNEL UART_GPIO17_DIRECT_CHANNEL
+#define UART_RXD_GPIO16_DIRECT_CHANNEL UART_GPIO16_DIRECT_CHANNEL
+#define UART_CTS_GPIO8_DIRECT_CHANNEL UART_GPIO8_DIRECT_CHANNEL
+#define UART_RTS_GPIO7_DIRECT_CHANNEL UART_GPIO7_DIRECT_CHANNEL
+
+#endif
SET_PERI_REG_BITS(ANA_CONFIG_REG, ANA_CONFIG_M, ANA_CONFIG_M, ANA_CONFIG_S);
CLEAR_PERI_REG_MASK(ANA_CONFIG_REG, I2C_APLL_M | I2C_BBPLL_M);
- /* Estimate XTAL frequency if requested */
+ /* Estimate XTAL frequency */
+ rtc_xtal_freq_t est_xtal_freq = rtc_clk_xtal_freq_estimate();
rtc_xtal_freq_t xtal_freq = cfg.xtal_freq;
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
if (clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
xtal_freq = rtc_clk_xtal_freq_get();
} else {
/* Not set yet, estimate XTAL frequency based on RTC_FAST_CLK */
- xtal_freq = rtc_clk_xtal_freq_estimate();
+ xtal_freq = est_xtal_freq;
if (xtal_freq == RTC_XTAL_FREQ_AUTO) {
SOC_LOGW(TAG, "Can't estimate XTAL frequency, assuming 26MHz");
xtal_freq = RTC_XTAL_FREQ_26M;
}
}
+ } else if (!clk_val_is_valid(READ_PERI_REG(RTC_XTAL_FREQ_REG))) {
+ /* Exact frequency was set in sdkconfig, but still warn if autodetected
+ * frequency is different. If autodetection failed, worst case we get a
+ * bit of garbage output.
+ */
+ SOC_LOGW(TAG, "Possibly invalid CONFIG_ESP32_XTAL_FREQ setting (%dMHz). Detected %d MHz.",
+ xtal_freq, est_xtal_freq);
}
+ uart_tx_wait_idle(0);
rtc_clk_xtal_freq_update(xtal_freq);
rtc_clk_apb_freq_update(xtal_freq * MHZ);
/* Set CPU frequency */
--- /dev/null
+menu "SPIFFS Configuration"
+
+config SPIFFS_MAX_PARTITIONS
+ int "Maximum Number of Partitions"
+ default 3
+ range 1 10
+ help
+ Define maximum number of partitions
+ that can be mounted.
+
+menu "SPIFFS Cache Configuration"
+config SPIFFS_CACHE
+ bool "Enable SPIFFS Cache"
+ default "y"
+ help
+ Enables/disable memory read
+ caching of nucleus file system
+ operations.
+
+config SPIFFS_CACHE_WR
+ bool "Enable SPIFFS Write Caching"
+ default "y"
+ depends on SPIFFS_CACHE
+ help
+ Enables memory write caching for
+ file descriptors in hydrogen.
+
+config SPIFFS_CACHE_STATS
+ bool "Enable SPIFFS Cache Statistics"
+ default "n"
+ depends on SPIFFS_CACHE
+ help
+ Enable/disable statistics on caching.
+ Debug/test purpose only.
+
+endmenu
+
+config SPIFFS_PAGE_CHECK
+ bool "Enable SPIFFS Page Check"
+ default "y"
+ help
+ Always check header of each
+ accessed page to ensure consistent state.
+ If enabled it will increase number
+ of reads, will increase flash.
+
+config SPIFFS_GC_MAX_RUNS
+ int "Set Maximum GC Runs"
+ default 10
+ range 1 255
+ help
+ Define maximum number of gc runs to
+ perform to reach desired free pages.
+
+config SPIFFS_GC_STATS
+ bool "Enable SPIFFS GC Statistics"
+ default "n"
+ help
+ Enable/disable statistics on gc.
+ Debug/test purpose only.
+
+config SPIFFS_OBJ_NAME_LEN
+ int "Set SPIFFS Maximum Name Length"
+ default 32
+ range 1 256
+ help
+ Object name maximum length. Note that this length
+ include the zero-termination character,
+ meaning maximum string of characters can at most be
+ SPIFFS_OBJ_NAME_LEN - 1.
+
+config SPIFFS_USE_MAGIC
+ bool "Enable SPIFFS Filesystem Magic"
+ default "y"
+ help
+ Enable this to have an identifiable spiffs filesystem.
+ This will look for a magic in all sectors
+ to determine if this is a valid spiffs system
+ or not on mount point.
+
+config SPIFFS_USE_MAGIC_LENGTH
+ bool "Enable SPIFFS Filesystem Length Magic"
+ default "y"
+ depends on SPIFFS_USE_MAGIC
+ help
+ If this option is enabled, the magic will also be dependent
+ on the length of the filesystem. For example, a filesystem
+ configured and formatted for 4 megabytes will not be accepted
+ for mounting with a configuration defining the filesystem as 2 megabytes.
+
+menu "Debug Configuration"
+
+config SPIFFS_DBG
+ bool "Enable general SPIFFS debug"
+ default "n"
+ help
+ Enabling this option will print
+ general debug mesages to the console
+
+config SPIFFS_API_DBG
+ bool "Enable SPIFFS API debug"
+ default "n"
+ help
+ Enabling this option will print
+ API debug mesages to the console
+
+config SPIFFS_GC_DBG
+ bool "Enable SPIFFS Garbage Cleaner debug"
+ default "n"
+ help
+ Enabling this option will print
+ GC debug mesages to the console
+
+config SPIFFS_CACHE_DBG
+ bool "Enable SPIFFS Cache debug"
+ default "n"
+ depends on SPIFFS_CACHE
+ help
+ Enabling this option will print
+ Cache debug mesages to the console
+
+config SPIFFS_CHECK_DBG
+ bool "Enable SPIFFS Filesystem Check debug"
+ default "n"
+ help
+ Enabling this option will print
+ Filesystem Check debug mesages
+ to the console
+
+config SPIFFS_TEST_VISUALISATION
+ bool "Enable SPIFFS Filesystem Visualization"
+ default "n"
+ help
+ Enable this option to enable SPIFFS_vis function
+ in the api.
+
+endmenu
+
+endmenu
--- /dev/null
+COMPONENT_ADD_INCLUDEDIRS := include
+COMPONENT_PRIV_INCLUDEDIRS := spiffs/src
+COMPONENT_SRCDIRS := . spiffs/src
--- /dev/null
+// Copyright 2015-2017 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 "esp_spiffs.h"
+#include "spiffs.h"
+#include "spiffs_nucleus.h"
+#include "esp_log.h"
+#include "esp_partition.h"
+#include "esp_spi_flash.h"
+#include "esp_image_format.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/errno.h>
+#include <sys/fcntl.h>
+#include <sys/lock.h>
+#include "esp_vfs.h"
+#include "esp_err.h"
+#include "rom/spi_flash.h"
+
+static const char * TAG = "SPIFFS";
+
+/**
+ * @brief SPIFFS definition structure
+ */
+typedef struct {
+ spiffs *fs; /*!< Handle to the underlying SPIFFS */
+ SemaphoreHandle_t lock; /*!< FS lock */
+ const esp_partition_t* partition; /*!< The partition on which SPIFFS is located */
+ char base_path[ESP_VFS_PATH_MAX+1]; /*!< Mount point */
+ bool by_label; /*!< Partition was mounted by label */
+ spiffs_config cfg; /*!< SPIFFS Mount configuration */
+ uint8_t *work; /*!< Work Buffer */
+ uint8_t *fds; /*!< File Descriptor Buffer */
+ uint32_t fds_sz; /*!< File Descriptor Buffer Length */
+ uint8_t *cache; /*!< Cache Buffer */
+ uint32_t cache_sz; /*!< Cache Buffer Length */
+} esp_spiffs_t;
+
+/**
+ * @brief SPIFFS DIR structure
+ */
+typedef struct {
+ DIR dir; /*!< VFS DIR struct */
+ spiffs_DIR d; /*!< SPIFFS DIR struct */
+ struct dirent e; /*!< Last open dirent */
+ long offset; /*!< Offset of the current dirent */
+ char path[SPIFFS_OBJ_NAME_LEN]; /*!< Requested directory name */
+} vfs_spiffs_dir_t;
+
+static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode);
+static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size);
+static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size);
+static int vfs_spiffs_close(void* ctx, int fd);
+static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode);
+static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st);
+static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st);
+static int vfs_spiffs_unlink(void* ctx, const char *path);
+static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2);
+static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst);
+static DIR* vfs_spiffs_opendir(void* ctx, const char* name);
+static int vfs_spiffs_closedir(void* ctx, DIR* pdir);
+static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir);
+static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir,
+ struct dirent* entry, struct dirent** out_dirent);
+static long vfs_spiffs_telldir(void* ctx, DIR* pdir);
+static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset);
+static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode);
+static int vfs_spiffs_rmdir(void* ctx, const char* name);
+
+static esp_spiffs_t * _efs[CONFIG_SPIFFS_MAX_PARTITIONS];
+
+void spiffs_api_lock(spiffs *fs)
+{
+ xSemaphoreTake(((esp_spiffs_t *)(fs->user_data))->lock, portMAX_DELAY);
+}
+
+void spiffs_api_unlock(spiffs *fs)
+{
+ xSemaphoreGive(((esp_spiffs_t *)(fs->user_data))->lock);
+}
+
+static s32_t spiffs_api_read(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *dst)
+{
+ esp_err_t err = esp_partition_read(((esp_spiffs_t *)(fs->user_data))->partition,
+ addr, dst, size);
+ if (err) {
+ ESP_LOGE(TAG, "failed to read addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static s32_t spiffs_api_write(spiffs *fs, uint32_t addr, uint32_t size, uint8_t *src)
+{
+ esp_err_t err = esp_partition_write(((esp_spiffs_t *)(fs->user_data))->partition,
+ addr, src, size);
+ if (err) {
+ ESP_LOGE(TAG, "failed to write addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static s32_t spiffs_api_erase(spiffs *fs, uint32_t addr, uint32_t size)
+{
+ esp_err_t err = esp_partition_erase_range(((esp_spiffs_t *)(fs->user_data))->partition,
+ addr, size);
+ if (err) {
+ ESP_LOGE(TAG, "failed to erase addr %08x, size %08x, err %d", addr, size, err);
+ return -1;
+ }
+ return 0;
+}
+
+static void spiffs_api_check(spiffs *fs, spiffs_check_type type,
+ spiffs_check_report report, uint32_t arg1, uint32_t arg2)
+{
+ static const char * spiffs_check_type_str[3] = {
+ "LOOKUP",
+ "INDEX",
+ "PAGE"
+ };
+
+ static const char * spiffs_check_report_str[7] = {
+ "PROGRESS",
+ "ERROR",
+ "FIX INDEX",
+ "FIX LOOKUP",
+ "DELETE ORPHANED INDEX",
+ "DELETE PAGE",
+ "DELETE BAD FILE"
+ };
+
+ if (report != SPIFFS_CHECK_PROGRESS) {
+ ESP_LOGE(TAG, "CHECK: type:%s, report:%s, %x:%x", spiffs_check_type_str[type],
+ spiffs_check_report_str[report], arg1, arg2);
+ } else {
+ ESP_LOGV(TAG, "CHECK PROGRESS: report:%s, %x:%x",
+ spiffs_check_report_str[report], arg1, arg2);
+ }
+}
+
+static void esp_spiffs_free(esp_spiffs_t ** efs)
+{
+ esp_spiffs_t * e = *efs;
+ if (*efs == NULL) {
+ return;
+ }
+ *efs = NULL;
+
+ if (e->fs) {
+ SPIFFS_unmount(e->fs);
+ free(e->fs);
+ }
+ vSemaphoreDelete(e->lock);
+ free(e->fds);
+ free(e->cache);
+ free(e->work);
+ free(e);
+}
+
+static esp_err_t esp_spiffs_by_label(const char* label, int * index){
+ int i;
+ esp_spiffs_t * p;
+ for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) {
+ p = _efs[i];
+ if (p) {
+ if (!label && !p->by_label) {
+ *index = i;
+ return ESP_OK;
+ }
+ if (label && p->by_label && strncmp(label, p->partition->label, 17) == 0) {
+ *index = i;
+ return ESP_OK;
+ }
+ }
+ }
+ return ESP_ERR_NOT_FOUND;
+}
+
+static esp_err_t esp_spiffs_get_empty(int * index){
+ int i;
+ for (i = 0; i < CONFIG_SPIFFS_MAX_PARTITIONS; i++) {
+ if (_efs[i] == NULL) {
+ *index = i;
+ return ESP_OK;
+ }
+ }
+ return ESP_ERR_NOT_FOUND;
+}
+
+static esp_err_t esp_spiffs_init(const esp_vfs_spiffs_conf_t* conf)
+{
+ int index;
+ //find if such partition is already mounted
+ if (esp_spiffs_by_label(conf->partition_label, &index) == ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ if (esp_spiffs_get_empty(&index) != ESP_OK) {
+ ESP_LOGE(TAG, "max mounted partitions reached");
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ esp_partition_subtype_t subtype = conf->partition_label ?
+ ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_SPIFFS;
+ const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
+ subtype, conf->partition_label);
+ if (!partition) {
+ ESP_LOGE(TAG, "spiffs partition could not be found");
+ return ESP_ERR_NOT_FOUND;
+ }
+
+ if (partition->encrypted) {
+ ESP_LOGE(TAG, "spiffs can not run on encrypted partition");
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ esp_spiffs_t * efs = malloc(sizeof(esp_spiffs_t));
+ if (efs == NULL) {
+ ESP_LOGE(TAG, "esp_spiffs could not be malloced");
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs, 0, sizeof(esp_spiffs_t));
+
+ efs->cfg.hal_erase_f = spiffs_api_erase;
+ efs->cfg.hal_read_f = spiffs_api_read;
+ efs->cfg.hal_write_f = spiffs_api_write;
+ efs->cfg.log_block_size = g_rom_flashchip.sector_size;
+ efs->cfg.log_page_size = g_rom_flashchip.page_size;
+ efs->cfg.phys_addr = 0;
+ efs->cfg.phys_erase_block = g_rom_flashchip.sector_size;
+ efs->cfg.phys_size = partition->size;
+
+ efs->by_label = conf->partition_label != NULL;
+
+ efs->lock = xSemaphoreCreateMutex();
+ if (efs->lock == NULL) {
+ ESP_LOGE(TAG, "mutex lock could not be created");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+
+ efs->fds_sz = conf->max_files * sizeof(spiffs_fd);
+ efs->fds = malloc(efs->fds_sz);
+ if (efs->fds == NULL) {
+ ESP_LOGE(TAG, "fd buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->fds, 0, efs->fds_sz);
+
+#if SPIFFS_CACHE
+ efs->cache_sz = sizeof(spiffs_cache) + conf->max_files * (sizeof(spiffs_cache_page)
+ + efs->cfg.log_page_size);
+ efs->cache = malloc(efs->cache_sz);
+ if (efs->cache == NULL) {
+ ESP_LOGE(TAG, "cache buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->cache, 0, efs->cache_sz);
+#endif
+
+ const uint32_t work_sz = efs->cfg.log_page_size * 2;
+ efs->work = malloc(work_sz);
+ if (efs->work == NULL) {
+ ESP_LOGE(TAG, "work buffer could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->work, 0, work_sz);
+
+ efs->fs = malloc(sizeof(spiffs));
+ if (efs->fs == NULL) {
+ ESP_LOGE(TAG, "spiffs could not be malloced");
+ esp_spiffs_free(&efs);
+ return ESP_ERR_NO_MEM;
+ }
+ memset(efs->fs, 0, sizeof(spiffs));
+
+ efs->fs->user_data = (void *)efs;
+ efs->partition = partition;
+
+ s32_t res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
+ efs->cache, efs->cache_sz, spiffs_api_check);
+
+ if (conf->format_if_mount_failed && res != SPIFFS_OK) {
+ ESP_LOGW(TAG, "mount failed, %i. formatting...", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ res = SPIFFS_format(efs->fs);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ esp_spiffs_free(&efs);
+ return ESP_FAIL;
+ }
+ res = SPIFFS_mount(efs->fs, &efs->cfg, efs->work, efs->fds, efs->fds_sz,
+ efs->cache, efs->cache_sz, spiffs_api_check);
+ }
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ esp_spiffs_free(&efs);
+ return ESP_FAIL;
+ }
+ _efs[index] = efs;
+ return ESP_OK;
+}
+
+bool esp_spiffs_mounted(const char* partition_label)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return false;
+ }
+ return (SPIFFS_mounted(_efs[index]->fs));
+}
+
+esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ SPIFFS_info(_efs[index]->fs, total_bytes, used_bytes);
+ return ESP_OK;
+}
+
+esp_err_t esp_spiffs_format(const char* partition_label)
+{
+ bool mount_on_success = false;
+ int index;
+ esp_err_t err = esp_spiffs_by_label(partition_label, &index);
+ if (err != ESP_OK) {
+ esp_vfs_spiffs_conf_t conf = {
+ .format_if_mount_failed = true,
+ .partition_label = partition_label,
+ .max_files = 1
+ };
+ err = esp_spiffs_init(&conf);
+ if (err != ESP_OK) {
+ return err;
+ }
+ err = esp_spiffs_by_label(partition_label, &index);
+ if (err != ESP_OK) {
+ return err;
+ }
+ esp_spiffs_free(&_efs[index]);
+ return ESP_OK;
+ } else if (SPIFFS_mounted(_efs[index]->fs)) {
+ SPIFFS_unmount(_efs[index]->fs);
+ mount_on_success = true;
+ }
+ s32_t res = SPIFFS_format(_efs[index]->fs);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "format failed, %i", SPIFFS_errno(_efs[index]->fs));
+ SPIFFS_clearerr(_efs[index]->fs);
+ return ESP_FAIL;
+ }
+
+ if (mount_on_success) {
+ res = SPIFFS_mount(_efs[index]->fs, &_efs[index]->cfg, _efs[index]->work,
+ _efs[index]->fds, _efs[index]->fds_sz, _efs[index]->cache,
+ _efs[index]->cache_sz, spiffs_api_check);
+ if (res != SPIFFS_OK) {
+ ESP_LOGE(TAG, "mount failed, %i", SPIFFS_errno(_efs[index]->fs));
+ SPIFFS_clearerr(_efs[index]->fs);
+ return ESP_FAIL;
+ }
+ }
+ return ESP_OK;
+}
+
+esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf)
+{
+ assert(conf->base_path);
+ const esp_vfs_t vfs = {
+ .flags = ESP_VFS_FLAG_CONTEXT_PTR,
+ .write_p = &vfs_spiffs_write,
+ .lseek_p = &vfs_spiffs_lseek,
+ .read_p = &vfs_spiffs_read,
+ .open_p = &vfs_spiffs_open,
+ .close_p = &vfs_spiffs_close,
+ .fstat_p = &vfs_spiffs_fstat,
+ .stat_p = &vfs_spiffs_stat,
+ .link_p = &vfs_spiffs_link,
+ .unlink_p = &vfs_spiffs_unlink,
+ .rename_p = &vfs_spiffs_rename,
+ .opendir_p = &vfs_spiffs_opendir,
+ .closedir_p = &vfs_spiffs_closedir,
+ .readdir_p = &vfs_spiffs_readdir,
+ .readdir_r_p = &vfs_spiffs_readdir_r,
+ .seekdir_p = &vfs_spiffs_seekdir,
+ .telldir_p = &vfs_spiffs_telldir,
+ .mkdir_p = &vfs_spiffs_mkdir,
+ .rmdir_p = &vfs_spiffs_rmdir
+ };
+
+ esp_err_t err = esp_spiffs_init(conf);
+ if (err != ESP_OK) {
+ return err;
+ }
+
+ int index;
+ if (esp_spiffs_by_label(conf->partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+
+ strlcat(_efs[index]->base_path, conf->base_path, ESP_VFS_PATH_MAX + 1);
+ err = esp_vfs_register(conf->base_path, &vfs, _efs[index]);
+ if (err != ESP_OK) {
+ esp_spiffs_free(&_efs[index]);
+ return err;
+ }
+
+ return ESP_OK;
+}
+
+esp_err_t esp_vfs_spiffs_unregister(const char* partition_label)
+{
+ int index;
+ if (esp_spiffs_by_label(partition_label, &index) != ESP_OK) {
+ return ESP_ERR_INVALID_STATE;
+ }
+ esp_err_t err = esp_vfs_unregister(_efs[index]->base_path);
+ if (err != ESP_OK) {
+ return err;
+ }
+ esp_spiffs_free(&_efs[index]);
+ return ESP_OK;
+}
+
+static int spiffs_res_to_errno(s32_t fr)
+{
+ switch(fr) {
+ case SPIFFS_OK :
+ return 0;
+ case SPIFFS_ERR_NOT_MOUNTED :
+ return ENODEV;
+ case SPIFFS_ERR_NOT_A_FS :
+ return ENODEV;
+ case SPIFFS_ERR_FULL :
+ return ENOSPC;
+ case SPIFFS_ERR_BAD_DESCRIPTOR :
+ return EBADF;
+ case SPIFFS_ERR_MOUNTED :
+ return EEXIST;
+ case SPIFFS_ERR_FILE_EXISTS :
+ return EEXIST;
+ case SPIFFS_ERR_NOT_FOUND :
+ return ENOENT;
+ case SPIFFS_ERR_NOT_A_FILE :
+ return ENOENT;
+ case SPIFFS_ERR_DELETED :
+ return ENOENT;
+ case SPIFFS_ERR_FILE_DELETED :
+ return ENOENT;
+ case SPIFFS_ERR_NAME_TOO_LONG :
+ return ENAMETOOLONG;
+ case SPIFFS_ERR_RO_NOT_IMPL :
+ return EROFS;
+ case SPIFFS_ERR_RO_ABORTED_OPERATION :
+ return EROFS;
+ default :
+ return EIO;
+ }
+ return ENOTSUP;
+}
+
+static int spiffs_mode_conv(int m)
+{
+ int res = 0;
+ int acc_mode = m & O_ACCMODE;
+ if (acc_mode == O_RDONLY) {
+ res |= SPIFFS_O_RDONLY;
+ } else if (acc_mode == O_WRONLY) {
+ res |= SPIFFS_O_WRONLY;
+ } else if (acc_mode == O_RDWR) {
+ res |= SPIFFS_O_RDWR;
+ }
+ if ((m & O_CREAT) && (m & O_EXCL)) {
+ res |= SPIFFS_O_CREAT | SPIFFS_O_EXCL;
+ } else if ((m & O_CREAT) && (m & O_TRUNC)) {
+ res |= SPIFFS_O_CREAT | SPIFFS_O_TRUNC;
+ } else if (m & O_APPEND) {
+ res |= SPIFFS_O_APPEND;
+ }
+ return res;
+}
+
+static int vfs_spiffs_open(void* ctx, const char * path, int flags, int mode)
+{
+ assert(path);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int fd = SPIFFS_open(efs->fs, path, spiffs_mode_conv(flags), mode);
+ if (fd < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return fd;
+}
+
+static ssize_t vfs_spiffs_write(void* ctx, int fd, const void * data, size_t size)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ ssize_t res = SPIFFS_write(efs->fs, fd, (void *)data, size);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static ssize_t vfs_spiffs_read(void* ctx, int fd, void * dst, size_t size)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ ssize_t res = SPIFFS_read(efs->fs, fd, dst, size);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static int vfs_spiffs_close(void* ctx, int fd)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int res = SPIFFS_close(efs->fs, fd);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static off_t vfs_spiffs_lseek(void* ctx, int fd, off_t offset, int mode)
+{
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_lseek(efs->fs, fd, offset, mode);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+
+}
+
+static int vfs_spiffs_fstat(void* ctx, int fd, struct stat * st)
+{
+ assert(st);
+ spiffs_stat s;
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_fstat(efs->fs, fd, &s);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ st->st_size = s.size;
+ st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO | S_IFREG;
+ return res;
+}
+
+static int vfs_spiffs_stat(void* ctx, const char * path, struct stat * st)
+{
+ assert(path);
+ assert(st);
+ spiffs_stat s;
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ off_t res = SPIFFS_stat(efs->fs, path, &s);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+
+ st->st_size = s.size;
+ st->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+ st->st_mode |= (s.type == SPIFFS_TYPE_DIR)?S_IFDIR:S_IFREG;
+ return res;
+}
+
+static int vfs_spiffs_rename(void* ctx, const char *src, const char *dst)
+{
+ assert(src);
+ assert(dst);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int res = SPIFFS_rename(efs->fs, src, dst);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static int vfs_spiffs_unlink(void* ctx, const char *path)
+{
+ assert(path);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ int res = SPIFFS_remove(efs->fs, path);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static DIR* vfs_spiffs_opendir(void* ctx, const char* name)
+{
+ assert(name);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = calloc(1, sizeof(vfs_spiffs_dir_t));
+ if (!dir) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ if (!SPIFFS_opendir(efs->fs, name, &dir->d)) {
+ free(dir);
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return NULL;
+ }
+ dir->offset = 0;
+ strlcpy(dir->path, name, SPIFFS_OBJ_NAME_LEN);
+ return (DIR*) dir;
+}
+
+static int vfs_spiffs_closedir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ int res = SPIFFS_closedir(&dir->d);
+ free(dir);
+ if (res < 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return -1;
+ }
+ return res;
+}
+
+static struct dirent* vfs_spiffs_readdir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ struct dirent* out_dirent;
+ int err = vfs_spiffs_readdir_r(ctx, pdir, &dir->e, &out_dirent);
+ if (err != 0) {
+ errno = err;
+ return NULL;
+ }
+ return out_dirent;
+}
+
+static int vfs_spiffs_readdir_r(void* ctx, DIR* pdir, struct dirent* entry,
+ struct dirent** out_dirent)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ struct spiffs_dirent out;
+ if (SPIFFS_readdir(&dir->d, &out) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ if (!errno) {
+ *out_dirent = NULL;
+ }
+ return errno;
+ }
+ const char * item_name = (const char *)out.name;
+ size_t plen = strlen(dir->path);
+ if (plen > 1) {
+ if (strncasecmp(dir->path, (const char *)out.name, plen) || out.name[plen] != '/' || !out.name[plen+1]) {
+ return vfs_spiffs_readdir_r(ctx, pdir, entry, out_dirent);
+ }
+ item_name += plen + 1;
+ } else if (item_name[0] == '/') {
+ item_name++;
+ }
+ entry->d_ino = 0;
+ entry->d_type = out.type;
+ snprintf(entry->d_name, SPIFFS_OBJ_NAME_LEN, "%s", item_name);
+ dir->offset++;
+ *out_dirent = entry;
+ return 0;
+}
+
+static long vfs_spiffs_telldir(void* ctx, DIR* pdir)
+{
+ assert(pdir);
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ return dir->offset;
+}
+
+static void vfs_spiffs_seekdir(void* ctx, DIR* pdir, long offset)
+{
+ assert(pdir);
+ esp_spiffs_t * efs = (esp_spiffs_t *)ctx;
+ vfs_spiffs_dir_t * dir = (vfs_spiffs_dir_t *)pdir;
+ struct spiffs_dirent tmp;
+ if (offset < dir->offset) {
+ //rewind dir
+ SPIFFS_closedir(&dir->d);
+ if (!SPIFFS_opendir(efs->fs, NULL, &dir->d)) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return;
+ }
+ dir->offset = 0;
+ }
+ while (dir->offset < offset) {
+ if (SPIFFS_readdir(&dir->d, &tmp) == 0) {
+ errno = spiffs_res_to_errno(SPIFFS_errno(efs->fs));
+ SPIFFS_clearerr(efs->fs);
+ return;
+ }
+ size_t plen = strlen(dir->path);
+ if (plen > 1) {
+ if (strncasecmp(dir->path, (const char *)tmp.name, plen) || tmp.name[plen] != '/' || !tmp.name[plen+1]) {
+ continue;
+ }
+ }
+ dir->offset++;
+ }
+}
+
+static int vfs_spiffs_mkdir(void* ctx, const char* name, mode_t mode)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int vfs_spiffs_rmdir(void* ctx, const char* name)
+{
+ errno = ENOTSUP;
+ return -1;
+}
+
+static int vfs_spiffs_link(void* ctx, const char* n1, const char* n2)
+{
+ errno = ENOTSUP;
+ return -1;
+}
--- /dev/null
+// Copyright 2015-2017 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_SPIFFS_H_
+#define _ESP_SPIFFS_H_
+
+#include <stdbool.h>
+#include "esp_err.h"
+
+/**
+ * @brief Configuration structure for esp_vfs_spiffs_register
+ */
+typedef struct {
+ const char* base_path; /*!< File path prefix associated with the filesystem. */
+ const char* partition_label; /*!< Optional, label of SPIFFS partition to use. If set to NULL, first partition with subtype=spiffs will be used. */
+ size_t max_files; /*!< Maximum files that could be open at the same time. */
+ bool format_if_mount_failed; /*!< If true, it will format the file system if it fails to mount. */
+} esp_vfs_spiffs_conf_t;
+
+/**
+ * Register and mount SPIFFS to VFS with given path prefix.
+ *
+ * @param conf Pointer to esp_vfs_spiffs_conf_t configuration structure
+ *
+ * @return
+ * - ESP_OK if success
+ * - ESP_ERR_NO_MEM if objects could not be allocated
+ * - ESP_ERR_INVALID_STATE if already mounted or partition is encrypted
+ * - ESP_ERR_NOT_FOUND if partition for SPIFFS was not found
+ * - ESP_FAIL if mount or format fails
+ */
+esp_err_t esp_vfs_spiffs_register(const esp_vfs_spiffs_conf_t * conf);
+
+/**
+ * Unregister and unmount SPIFFS from VFS
+ *
+ * @param partition_label Optional, label of the partition to unregister.
+ * If not specified, first partition with subtype=spiffs is used.
+ *
+ * @return
+ * - ESP_OK if successful
+ * - ESP_ERR_INVALID_STATE already unregistered
+ */
+esp_err_t esp_vfs_spiffs_unregister(const char* partition_label);
+
+/**
+ * Check if SPIFFS is mounted
+ *
+ * @param partition_label Optional, label of the partition to check.
+ * If not specified, first partition with subtype=spiffs is used.
+ *
+ * @return
+ * - true if mounted
+ * - false if not mounted
+ */
+bool esp_spiffs_mounted(const char* partition_label);
+
+/**
+ * Format the SPIFFS partition
+ *
+ * @param partition_label Optional, label of the partition to format.
+ * If not specified, first partition with subtype=spiffs is used.
+ * @return
+ * - ESP_OK if successful
+ * - ESP_FAIL on error
+ */
+esp_err_t esp_spiffs_format(const char* partition_label);
+
+/**
+ * Get information for SPIFFS
+ *
+ * @param partition_label Optional, label of the partition to get info for.
+ * If not specified, first partition with subtype=spiffs is used.
+ * @param[out] total_bytes Size of the file system
+ * @param[out] used_bytes Current used bytes in the file system
+ *
+ * @return
+ * - ESP_OK if success
+ * - ESP_ERR_INVALID_STATE if not mounted
+ */
+esp_err_t esp_spiffs_info(const char* partition_label, size_t *total_bytes, size_t *used_bytes);
+
+#endif /* _ESP_SPIFFS_H_ */
--- /dev/null
+/*
+ * spiffs_config.h
+ *
+ * Created on: Jul 3, 2013
+ * Author: petera
+ */
+
+#ifndef SPIFFS_CONFIG_H_
+#define SPIFFS_CONFIG_H_
+
+// ----------- 8< ------------
+// Following includes are for the linux test build of spiffs
+// These may/should/must be removed/altered/replaced in your target
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sdkconfig.h>
+#include <esp_log.h>
+
+// compile time switches
+#define SPIFFS_TAG "SPIFFS"
+
+// Set generic spiffs debug output call.
+#if CONGIG_SPIFFS_DBG
+#define SPIFFS_DBG(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#else
+#define SPIFFS_DBG(...)
+#endif
+#if CONGIG_SPIFFS_API_DBG
+#define SPIFFS_API_DBG(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#else
+#define SPIFFS_API_DBG(...)
+#endif
+#if CONGIG_SPIFFS_DBG
+#define SPIFFS_GC_DBG(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#else
+#define SPIFFS_GC_DBG(...)
+#endif
+#if CONGIG_SPIFFS_CACHE_DBG
+#define SPIFFS_CACHE_DBG(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#else
+#define SPIFFS_CACHE_DBG(...)
+#endif
+#if CONGIG_SPIFFS_CHECK_DBG
+#define SPIFFS_CHECK_DBG(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#else
+#define SPIFFS_CHECK_DBG(...)
+#endif
+
+// needed types
+typedef signed int s32_t;
+typedef unsigned int u32_t;
+typedef signed short s16_t;
+typedef unsigned short u16_t;
+typedef signed char s8_t;
+typedef unsigned char u8_t;
+
+struct spiffs_t;
+extern void spiffs_api_lock(struct spiffs_t *fs);
+extern void spiffs_api_unlock(struct spiffs_t *fs);
+
+// Defines spiffs debug print formatters
+// some general signed number
+#define _SPIPRIi "%d"
+// address
+#define _SPIPRIad "%08x"
+// block
+#define _SPIPRIbl "%04x"
+// page
+#define _SPIPRIpg "%04x"
+// span index
+#define _SPIPRIsp "%04x"
+// file descriptor
+#define _SPIPRIfd "%d"
+// file object id
+#define _SPIPRIid "%04x"
+// file flags
+#define _SPIPRIfl "%02x"
+
+
+// Enable/disable API functions to determine exact number of bytes
+// for filedescriptor and cache buffers. Once decided for a configuration,
+// this can be disabled to reduce flash.
+#define SPIFFS_BUFFER_HELP 0
+
+// Enables/disable memory read caching of nucleus file system operations.
+// If enabled, memory area must be provided for cache in SPIFFS_mount.
+#ifdef CONFIG_SPIFFS_CACHE
+#define SPIFFS_CACHE (1)
+#else
+#define SPIFFS_CACHE (0)
+#endif
+#if SPIFFS_CACHE
+// Enables memory write caching for file descriptors in hydrogen
+#ifdef CONFIG_SPIFFS_CACHE_WR
+#define SPIFFS_CACHE_WR (1)
+#else
+#define SPIFFS_CACHE_WR (0)
+#endif
+
+// Enable/disable statistics on caching. Debug/test purpose only.
+#ifdef CONFIG_SPIFFS_CACHE_STATS
+#define SPIFFS_CACHE_STATS (1)
+#else
+#define SPIFFS_CACHE_STATS (0)
+#endif
+#endif
+
+// Always check header of each accessed page to ensure consistent state.
+// If enabled it will increase number of reads, will increase flash.
+#ifdef CONFIG_SPIFFS_PAGE_CHECK
+#define SPIFFS_PAGE_CHECK (1)
+#else
+#define SPIFFS_PAGE_CHECK (0)
+#endif
+
+// Define maximum number of gc runs to perform to reach desired free pages.
+#define SPIFFS_GC_MAX_RUNS CONFIG_SPIFFS_GC_MAX_RUNS
+
+// Enable/disable statistics on gc. Debug/test purpose only.
+#ifdef CONFIG_SPIFFS_GC_STATS
+#define SPIFFS_GC_STATS (1)
+#else
+#define SPIFFS_GC_STATS (0)
+#endif
+
+// Garbage collecting examines all pages in a block which and sums up
+// to a block score. Deleted pages normally gives positive score and
+// used pages normally gives a negative score (as these must be moved).
+// To have a fair wear-leveling, the erase age is also included in score,
+// whose factor normally is the most positive.
+// The larger the score, the more likely it is that the block will
+// picked for garbage collection.
+
+// Garbage collecting heuristics - weight used for deleted pages.
+#define SPIFFS_GC_HEUR_W_DELET (5)
+// Garbage collecting heuristics - weight used for used pages.
+#define SPIFFS_GC_HEUR_W_USED (-1)
+// Garbage collecting heuristics - weight used for time between
+// last erased and erase of this block.
+#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
+
+// Object name maximum length. Note that this length include the
+// zero-termination character, meaning maximum string of characters
+// can at most be SPIFFS_OBJ_NAME_LEN - 1.
+#define SPIFFS_OBJ_NAME_LEN (CONFIG_SPIFFS_OBJ_NAME_LEN)
+
+// Maximum length of the metadata associated with an object.
+// Setting to non-zero value enables metadata-related API but also
+// changes the on-disk format, so the change is not backward-compatible.
+//
+// Do note: the meta length must never exceed
+// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
+//
+// This is derived from following:
+// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
+// spiffs_object_ix_header fields + at least some LUT entries)
+#define SPIFFS_OBJ_META_LEN (0)
+
+// Size of buffer allocated on stack used when copying data.
+// Lower value generates more read/writes. No meaning having it bigger
+// than logical page size.
+#define SPIFFS_COPY_BUFFER_STACK (256)
+
+// Enable this to have an identifiable spiffs filesystem. This will look for
+// a magic in all sectors to determine if this is a valid spiffs system or
+// not on mount point. If not, SPIFFS_format must be called prior to mounting
+// again.
+#ifdef CONFIG_SPIFFS_USE_MAGIC
+#define SPIFFS_USE_MAGIC (1)
+#else
+#define SPIFFS_USE_MAGIC (0)
+#endif
+
+#if SPIFFS_USE_MAGIC
+// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
+// enabled, the magic will also be dependent on the length of the filesystem.
+// For example, a filesystem configured and formatted for 4 megabytes will not
+// be accepted for mounting with a configuration defining the filesystem as 2
+// megabytes.
+#ifdef CONFIG_SPIFFS_USE_MAGIC_LENGTH
+#define SPIFFS_USE_MAGIC_LENGTH (1)
+#else
+#define SPIFFS_USE_MAGIC_LENGTH (0)
+#endif
+#endif
+
+// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
+// These should be defined on a multithreaded system
+
+// define this to enter a mutex if you're running on a multithreaded system
+#define SPIFFS_LOCK(fs) spiffs_api_lock(fs)
+// define this to exit a mutex if you're running on a multithreaded system
+#define SPIFFS_UNLOCK(fs) spiffs_api_unlock(fs)
+
+// Enable if only one spiffs instance with constant configuration will exist
+// on the target. This will reduce calculations, flash and memory accesses.
+// Parts of configuration must be defined below instead of at time of mount.
+#define SPIFFS_SINGLETON 0
+
+// Enable this if your target needs aligned data for index tables
+#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 0
+
+// Enable this if you want the HAL callbacks to be called with the spiffs struct
+#define SPIFFS_HAL_CALLBACK_EXTRA 1
+
+// Enable this if you want to add an integer offset to all file handles
+// (spiffs_file). This is useful if running multiple instances of spiffs on
+// same target, in order to recognise to what spiffs instance a file handle
+// belongs.
+// NB: This adds config field fh_ix_offset in the configuration struct when
+// mounting, which must be defined.
+#define SPIFFS_FILEHDL_OFFSET 0
+
+// Enable this to compile a read only version of spiffs.
+// This will reduce binary size of spiffs. All code comprising modification
+// of the file system will not be compiled. Some config will be ignored.
+// HAL functions for erasing and writing to spi-flash may be null. Cache
+// can be disabled for even further binary size reduction (and ram savings).
+// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
+// If the file system cannot be mounted due to aborted erase operation and
+// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
+// returned.
+// Might be useful for e.g. bootloaders and such.
+#define SPIFFS_READ_ONLY 0
+
+// Enable this to add a temporal file cache using the fd buffer.
+// The effects of the cache is that SPIFFS_open will find the file faster in
+// certain cases. It will make it a lot easier for spiffs to find files
+// opened frequently, reducing number of readings from the spi flash for
+// finding those files.
+// This will grow each fd by 6 bytes. If your files are opened in patterns
+// with a degree of temporal locality, the system is optimized.
+// Examples can be letting spiffs serve web content, where one file is the css.
+// The css is accessed for each html file that is opened, meaning it is
+// accessed almost every second time a file is opened. Another example could be
+// a log file that is often opened, written, and closed.
+// The size of the cache is number of given file descriptors, as it piggybacks
+// on the fd update mechanism. The cache lives in the closed file descriptors.
+// When closed, the fd know the whereabouts of the file. Instead of forgetting
+// this, the temporal cache will keep handling updates to that file even if the
+// fd is closed. If the file is opened again, the location of the file is found
+// directly. If all available descriptors become opened, all cache memory is
+// lost.
+#define SPIFFS_TEMPORAL_FD_CACHE 1
+
+// Temporal file cache hit score. Each time a file is opened, all cached files
+// will lose one point. If the opened file is found in cache, that entry will
+// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
+// value for the specific access patterns of the application. However, it must
+// be between 1 (no gain for hitting a cached entry often) and 255.
+#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 4
+
+// Enable to be able to map object indices to memory.
+// This allows for faster and more deterministic reading if cases of reading
+// large files and when changing file offset by seeking around a lot.
+// When mapping a file's index, the file system will be scanned for index pages
+// and the info will be put in memory provided by user. When reading, the
+// memory map can be looked up instead of searching for index pages on the
+// medium. This way, user can trade memory against performance.
+// Whole, parts of, or future parts not being written yet can be mapped. The
+// memory array will be owned by spiffs and updated accordingly during garbage
+// collecting or when modifying the indices. The latter is invoked by when the
+// file is modified in some way. The index buffer is tied to the file
+// descriptor.
+#define SPIFFS_IX_MAP 1
+
+// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
+// in the api. This function will visualize all filesystem using given printf
+// function.
+#ifdef CONFIG_SPIFFS_TEST_VISUALISATION
+#define SPIFFS_TEST_VISUALISATION 1
+#else
+#define SPIFFS_TEST_VISUALISATION 0
+#endif
+#if SPIFFS_TEST_VISUALISATION
+#ifndef spiffs_printf
+#define spiffs_printf(...) ESP_LOGD(SPIFFS_TAG, __VA_ARGS__)
+#endif
+// spiffs_printf argument for a free page
+#define SPIFFS_TEST_VIS_FREE_STR "_"
+// spiffs_printf argument for a deleted page
+#define SPIFFS_TEST_VIS_DELE_STR "/"
+// spiffs_printf argument for an index page for given object id
+#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
+// spiffs_printf argument for a data page for given object id
+#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
+#endif
+
+// Types depending on configuration such as the amount of flash bytes
+// given to spiffs file system in total (spiffs_file_system_size),
+// the logical block size (log_block_size), and the logical page size
+// (log_page_size)
+
+// Block index type. Make sure the size of this type can hold
+// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
+typedef u16_t spiffs_block_ix;
+// Page index type. Make sure the size of this type can hold
+// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
+typedef u16_t spiffs_page_ix;
+// Object id type - most significant bit is reserved for index flag. Make sure the
+// size of this type can hold the highest object id on a full system,
+// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
+typedef u16_t spiffs_obj_id;
+// Object span index type. Make sure the size of this type can
+// hold the largest possible span index on the system -
+// i.e. (spiffs_file_system_size / log_page_size) - 1
+typedef u16_t spiffs_span_ix;
+
+#endif /* SPIFFS_CONFIG_H_ */
--- /dev/null
+Subproject commit 794f0478d2aa9c978c3844da6e97f14239a1e061
--- /dev/null
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
--- /dev/null
+// Copyright 2015-2017 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/unistd.h>
+#include "unity.h"
+#include "test_utils.h"
+#include "esp_log.h"
+#include "esp_system.h"
+#include "esp_vfs.h"
+#include "esp_spiffs.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+#include "esp_partition.h"
+
+const char* spiffs_test_hello_str = "Hello, World!\n";
+const char* spiffs_test_partition_label = "flash_test";
+
+void test_spiffs_create_file_with_text(const char* name, const char* text)
+{
+ FILE* f = fopen(name, "wb");
+ TEST_ASSERT_NOT_NULL(f);
+ TEST_ASSERT_TRUE(fputs(text, f) != EOF);
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_overwrite_append(const char* filename)
+{
+ /* Create new file with 'aaaa' */
+ test_spiffs_create_file_with_text(filename, "aaaa");
+
+ /* Append 'bbbb' to file */
+ FILE *f_a = fopen(filename, "a");
+ TEST_ASSERT_NOT_NULL(f_a);
+ TEST_ASSERT_NOT_EQUAL(EOF, fputs("bbbb", f_a));
+ TEST_ASSERT_EQUAL(0, fclose(f_a));
+
+ /* Read back 8 bytes from file, verify it's 'aaaabbbb' */
+ char buf[10] = { 0 };
+ FILE *f_r = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f_r);
+ TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r));
+ TEST_ASSERT_EQUAL_STRING_LEN("aaaabbbb", buf, 8);
+
+ /* Be sure we're at end of file */
+ TEST_ASSERT_EQUAL(0, fread(buf, 1, 8, f_r));
+
+ TEST_ASSERT_EQUAL(0, fclose(f_r));
+
+ /* Overwrite file with 'cccc' */
+ test_spiffs_create_file_with_text(filename, "cccc");
+
+ /* Verify file now only contains 'cccc' */
+ f_r = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f_r);
+ bzero(buf, sizeof(buf));
+ TEST_ASSERT_EQUAL(4, fread(buf, 1, 8, f_r)); // trying to read 8 bytes, only expecting 4
+ TEST_ASSERT_EQUAL_STRING_LEN("cccc", buf, 4);
+ TEST_ASSERT_EQUAL(0, fclose(f_r));
+}
+
+void test_spiffs_read_file(const char* filename)
+{
+ FILE* f = fopen(filename, "r");
+ TEST_ASSERT_NOT_NULL(f);
+ char buf[32] = { 0 };
+ int cb = fread(buf, 1, sizeof(buf), f);
+ TEST_ASSERT_EQUAL(strlen(spiffs_test_hello_str), cb);
+ TEST_ASSERT_EQUAL(0, strcmp(spiffs_test_hello_str, buf));
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_open_max_files(const char* filename_prefix, size_t files_count)
+{
+ FILE** files = calloc(files_count, sizeof(FILE*));
+ for (size_t i = 0; i < files_count; ++i) {
+ char name[32];
+ snprintf(name, sizeof(name), "%s_%d.txt", filename_prefix, i);
+ files[i] = fopen(name, "w");
+ TEST_ASSERT_NOT_NULL(files[i]);
+ }
+ /* close everything and clean up */
+ for (size_t i = 0; i < files_count; ++i) {
+ fclose(files[i]);
+ }
+ free(files);
+}
+
+void test_spiffs_lseek(const char* filename)
+{
+ FILE* f = fopen(filename, "wb+");
+ TEST_ASSERT_NOT_NULL(f);
+ TEST_ASSERT_EQUAL(11, fprintf(f, "0123456789\n"));
+ TEST_ASSERT_EQUAL(0, fseek(f, -2, SEEK_CUR));
+ TEST_ASSERT_EQUAL('9', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 3, SEEK_SET));
+ TEST_ASSERT_EQUAL('3', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, -3, SEEK_END));
+ TEST_ASSERT_EQUAL('8', fgetc(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(11, ftell(f));
+ TEST_ASSERT_EQUAL(4, fprintf(f, "abc\n"));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(15, ftell(f));
+ TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_SET));
+ char buf[20];
+ TEST_ASSERT_EQUAL(15, fread(buf, 1, sizeof(buf), f));
+ const char ref_buf[] = "0123456789\nabc\n";
+ TEST_ASSERT_EQUAL_INT8_ARRAY(ref_buf, buf, sizeof(ref_buf) - 1);
+
+ TEST_ASSERT_EQUAL(0, fclose(f));
+}
+
+void test_spiffs_stat(const char* filename)
+{
+ test_spiffs_create_file_with_text(filename, "foo\n");
+ struct stat st;
+ TEST_ASSERT_EQUAL(0, stat(filename, &st));
+ TEST_ASSERT(st.st_mode & S_IFREG);
+ TEST_ASSERT_FALSE(st.st_mode & S_IFDIR);
+}
+
+void test_spiffs_unlink(const char* filename)
+{
+ test_spiffs_create_file_with_text(filename, "unlink\n");
+
+ TEST_ASSERT_EQUAL(0, unlink(filename));
+
+ TEST_ASSERT_NULL(fopen(filename, "r"));
+}
+
+void test_spiffs_rename(const char* filename_prefix)
+{
+ char name_dst[64];
+ char name_src[64];
+ snprintf(name_dst, sizeof(name_dst), "%s_dst.txt", filename_prefix);
+ snprintf(name_src, sizeof(name_src), "%s_src.txt", filename_prefix);
+
+ unlink(name_dst);
+ unlink(name_src);
+
+ FILE* f = fopen(name_src, "w+");
+ TEST_ASSERT_NOT_NULL(f);
+ char* str = "0123456789";
+ for (int i = 0; i < 400; ++i) {
+ TEST_ASSERT_NOT_EQUAL(EOF, fputs(str, f));
+ }
+ TEST_ASSERT_EQUAL(0, fclose(f));
+ TEST_ASSERT_EQUAL(0, rename(name_src, name_dst));
+ TEST_ASSERT_NULL(fopen(name_src, "r"));
+ FILE* fdst = fopen(name_dst, "r");
+ TEST_ASSERT_NOT_NULL(fdst);
+ TEST_ASSERT_EQUAL(0, fseek(fdst, 0, SEEK_END));
+ TEST_ASSERT_EQUAL(4000, ftell(fdst));
+ TEST_ASSERT_EQUAL(0, fclose(fdst));
+}
+
+void test_spiffs_can_opendir(const char* path)
+{
+ char name_dir_file[64];
+ const char * file_name = "test_opd.txt";
+ snprintf(name_dir_file, sizeof(name_dir_file), "%s/%s", path, file_name);
+ unlink(name_dir_file);
+ test_spiffs_create_file_with_text(name_dir_file, "test_opendir\n");
+ DIR* dir = opendir(path);
+ TEST_ASSERT_NOT_NULL(dir);
+ bool found = false;
+ while (true) {
+ struct dirent* de = readdir(dir);
+ if (!de) {
+ break;
+ }
+ if (strcasecmp(de->d_name, file_name) == 0) {
+ found = true;
+ break;
+ }
+ }
+ TEST_ASSERT_TRUE(found);
+ TEST_ASSERT_EQUAL(0, closedir(dir));
+ unlink(name_dir_file);
+}
+
+void test_spiffs_opendir_readdir_rewinddir(const char* dir_prefix)
+{
+ char name_dir_inner_file[64];
+ char name_dir_inner[64];
+ char name_dir_file3[64];
+ char name_dir_file2[64];
+ char name_dir_file1[64];
+
+ snprintf(name_dir_inner_file, sizeof(name_dir_inner_file), "%s/inner/3.txt", dir_prefix);
+ snprintf(name_dir_inner, sizeof(name_dir_inner), "%s/inner", dir_prefix);
+ snprintf(name_dir_file3, sizeof(name_dir_file2), "%s/boo.bin", dir_prefix);
+ snprintf(name_dir_file2, sizeof(name_dir_file2), "%s/2.txt", dir_prefix);
+ snprintf(name_dir_file1, sizeof(name_dir_file1), "%s/1.txt", dir_prefix);
+
+ unlink(name_dir_inner_file);
+ rmdir(name_dir_inner);
+ unlink(name_dir_file1);
+ unlink(name_dir_file2);
+ unlink(name_dir_file3);
+ rmdir(dir_prefix);
+
+ test_spiffs_create_file_with_text(name_dir_file1, "1\n");
+ test_spiffs_create_file_with_text(name_dir_file2, "2\n");
+ test_spiffs_create_file_with_text(name_dir_file3, "\01\02\03");
+ test_spiffs_create_file_with_text(name_dir_inner_file, "3\n");
+
+ DIR* dir = opendir(dir_prefix);
+ TEST_ASSERT_NOT_NULL(dir);
+ int count = 0;
+ const char* names[4];
+ while(count < 4) {
+ struct dirent* de = readdir(dir);
+ if (!de) {
+ break;
+ }
+ printf("found '%s'\n", de->d_name);
+ if (strcasecmp(de->d_name, "1.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "1.txt";
+ ++count;
+ } else if (strcasecmp(de->d_name, "2.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "2.txt";
+ ++count;
+ } else if (strcasecmp(de->d_name, "inner/3.txt") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "inner/3.txt";
+ ++count;
+ } else if (strcasecmp(de->d_name, "boo.bin") == 0) {
+ TEST_ASSERT_TRUE(de->d_type == DT_REG);
+ names[count] = "boo.bin";
+ ++count;
+ } else {
+ TEST_FAIL_MESSAGE("unexpected directory entry");
+ }
+ }
+ TEST_ASSERT_EQUAL(count, 4);
+
+ rewinddir(dir);
+ struct dirent* de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[0]));
+ seekdir(dir, 3);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[3]));
+ seekdir(dir, 1);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[1]));
+ seekdir(dir, 2);
+ de = readdir(dir);
+ TEST_ASSERT_NOT_NULL(de);
+ TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[2]));
+
+ TEST_ASSERT_EQUAL(0, closedir(dir));
+}
+
+
+typedef struct {
+ const char* filename;
+ bool write;
+ size_t word_count;
+ int seed;
+ SemaphoreHandle_t done;
+ int result;
+} read_write_test_arg_t;
+
+#define READ_WRITE_TEST_ARG_INIT(name, seed_) \
+ { \
+ .filename = name, \
+ .seed = seed_, \
+ .word_count = 4096, \
+ .write = true, \
+ .done = xSemaphoreCreateBinary() \
+ }
+
+static void read_write_task(void* param)
+{
+ read_write_test_arg_t* args = (read_write_test_arg_t*) param;
+ FILE* f = fopen(args->filename, args->write ? "wb" : "rb");
+ if (f == NULL) {
+ args->result = ESP_ERR_NOT_FOUND;
+ goto done;
+ }
+
+ srand(args->seed);
+ for (size_t i = 0; i < args->word_count; ++i) {
+ uint32_t val = rand();
+ if (args->write) {
+ int cnt = fwrite(&val, sizeof(val), 1, f);
+ if (cnt != 1) {
+ ets_printf("E(w): i=%d, cnt=%d val=%d\n\n", i, cnt, val);
+ args->result = ESP_FAIL;
+ goto close;
+ }
+ } else {
+ uint32_t rval;
+ int cnt = fread(&rval, sizeof(rval), 1, f);
+ if (cnt != 1) {
+ ets_printf("E(r): i=%d, cnt=%d rval=%d\n\n", i, cnt, rval);
+ args->result = ESP_FAIL;
+ goto close;
+ }
+ }
+ }
+ args->result = ESP_OK;
+
+close:
+ fclose(f);
+
+done:
+ xSemaphoreGive(args->done);
+ vTaskDelay(1);
+ vTaskDelete(NULL);
+}
+
+void test_spiffs_concurrent(const char* filename_prefix)
+{
+ char names[4][64];
+ for (size_t i = 0; i < 4; ++i) {
+ snprintf(names[i], sizeof(names[i]), "%s%d", filename_prefix, i + 1);
+ unlink(names[i]);
+ }
+
+ read_write_test_arg_t args1 = READ_WRITE_TEST_ARG_INIT(names[0], 1);
+ read_write_test_arg_t args2 = READ_WRITE_TEST_ARG_INIT(names[1], 2);
+
+ printf("writing f1 and f2\n");
+
+ xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, 0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, 1);
+
+ xSemaphoreTake(args1.done, portMAX_DELAY);
+ printf("f1 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args1.result);
+ xSemaphoreTake(args2.done, portMAX_DELAY);
+ printf("f2 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args2.result);
+
+ args1.write = false;
+ args2.write = false;
+ read_write_test_arg_t args3 = READ_WRITE_TEST_ARG_INIT(names[2], 3);
+ read_write_test_arg_t args4 = READ_WRITE_TEST_ARG_INIT(names[3], 4);
+
+ printf("reading f1 and f2, writing f3 and f4\n");
+
+ xTaskCreatePinnedToCore(&read_write_task, "rw3", 2048, &args3, 3, NULL, 1);
+ xTaskCreatePinnedToCore(&read_write_task, "rw4", 2048, &args4, 3, NULL, 0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw1", 2048, &args1, 3, NULL, 0);
+ xTaskCreatePinnedToCore(&read_write_task, "rw2", 2048, &args2, 3, NULL, 1);
+
+ xSemaphoreTake(args1.done, portMAX_DELAY);
+ printf("f1 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args1.result);
+ xSemaphoreTake(args2.done, portMAX_DELAY);
+ printf("f2 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args2.result);
+ xSemaphoreTake(args3.done, portMAX_DELAY);
+ printf("f3 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args3.result);
+ xSemaphoreTake(args4.done, portMAX_DELAY);
+ printf("f4 done\n");
+ TEST_ASSERT_EQUAL(ESP_OK, args4.result);
+
+ vSemaphoreDelete(args1.done);
+ vSemaphoreDelete(args2.done);
+ vSemaphoreDelete(args3.done);
+ vSemaphoreDelete(args4.done);
+}
+
+
+static void test_setup()
+{
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = spiffs_test_partition_label,
+ .max_files = 5,
+ .format_if_mount_failed = true
+ };
+
+ TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
+}
+
+static void test_teardown()
+{
+ TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label));
+}
+
+TEST_CASE("can format partition", "[spiffs]")
+{
+ const esp_partition_t* part = get_test_data_partition();
+ TEST_ASSERT_NOT_NULL(part);
+ TEST_ESP_OK(esp_partition_erase_range(part, 0, part->size));
+ test_setup();
+ size_t total = 0, used = 0;
+ TEST_ESP_OK(esp_spiffs_info(spiffs_test_partition_label, &total, &used));
+ printf("total: %d, used: %d\n", total, used);
+ TEST_ASSERT_EQUAL(0, used);
+ test_teardown();
+}
+
+TEST_CASE("can create and write file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_create_file_with_text("/spiffs/hello.txt", spiffs_test_hello_str);
+ test_teardown();
+}
+
+TEST_CASE("can read file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_create_file_with_text("/spiffs/hello.txt", spiffs_test_hello_str);
+ test_spiffs_read_file("/spiffs/hello.txt");
+ test_teardown();
+}
+
+TEST_CASE("can open maximum number of files", "[spiffs]")
+{
+ size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr */
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = spiffs_test_partition_label,
+ .format_if_mount_failed = true,
+ .max_files = max_files
+ };
+ TEST_ESP_OK(esp_vfs_spiffs_register(&conf));
+ test_spiffs_open_max_files("/spiffs/f", max_files);
+ TEST_ESP_OK(esp_vfs_spiffs_unregister(spiffs_test_partition_label));
+}
+
+TEST_CASE("overwrite and append file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_overwrite_append("/spiffs/hello.txt");
+ test_teardown();
+}
+
+TEST_CASE("can lseek", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_lseek("/spiffs/seek.txt");
+ test_teardown();
+}
+
+
+TEST_CASE("stat returns correct values", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_stat("/spiffs/stat.txt");
+ test_teardown();
+}
+
+TEST_CASE("unlink removes a file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_unlink("/spiffs/unlink.txt");
+ test_teardown();
+}
+
+TEST_CASE("rename moves a file", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_rename("/spiffs/move");
+ test_teardown();
+}
+
+TEST_CASE("can opendir root directory of FS", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_can_opendir("/spiffs");
+ test_teardown();
+}
+
+TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_opendir_readdir_rewinddir("/spiffs/dir");
+ test_teardown();
+}
+
+TEST_CASE("multiple tasks can use same volume", "[spiffs]")
+{
+ test_setup();
+ test_spiffs_concurrent("/spiffs/f");
+ test_teardown();
+}
#include "netif/ethernetif.h"
#include "apps/dhcpserver.h"
+#include "apps/dhcpserver_options.h"
#include "esp_event.h"
#include "esp_log.h"
../components/driver/include/driver/touch_pad.h \
../components/driver/include/driver/uart.h \
../components/esp_adc_cal/include/esp_adc_cal.h \
+ ../components/soc/esp32/include/soc/adc_channel.h \
+ ../components/soc/esp32/include/soc/dac_channel.h \
+ ../components/soc/esp32/include/soc/touch_channel.h \
+ ../components/soc/esp32/include/soc/uart_channel.h \
+ ../components/soc/esp32/include/soc/rtc_gpio_channel.h \
##
## Protocols - API Reference
##
../components/spi_flash/include/esp_spi_flash.h \
../components/spi_flash/include/esp_partition.h \
../components/bootloader_support/include/esp_flash_encrypt.h \
+ ## SPIFFS
+ ../components/spiffs/include/esp_spiffs.h \
## SD/MMC Card Host
## NOTE: for three lines below header_file.inc is not used
../components/sdmmc/include/sdmmc_cmd.h \
System Behaviour Analysis with SEGGER SystemView
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-Another useful IDF feature built on top of application tracing library is the system level tracing which produces traces compatible with SEGGER SystemView tool (see `SystemView <https://www.segger.com/systemview.html>`_). SEGGER SystemView is a real-time recording and visualization tool that allows to analyze runtime behavior of an application.
+Another useful IDF feature built on top of application tracing library is the system level tracing which produces traces compatible with SEGGER SystemView tool (see `SystemView <https://www.segger.com/products/development-tools/systemview/>`_). SEGGER SystemView is a real-time recording and visualization tool that allows to analyze runtime behavior of an application.
.. note::
By default, the build process will print a warning if an undefined variable is referenced (like ``$(DOES_NOT_EXIST)``). This can be useful to find errors in variable names.
-If you don't want this behaviour, it can be disabled by disabling :ref:`CONFIG_MAKE_WARN_UNDEFINED_VARIABLES`.
+If you don't want this behaviour, it can be disabled in menuconfig's top level menu under `SDK tool configuration`.
Note that this option doesn't trigger a warning if ``ifdef`` or ``ifndef`` are used in Makefiles.
.. include:: /_build/inc/adc.inc
+GPIO Lookup Macros
+^^^^^^^^^^^^^^^^^^
+Some useful macros can be used to specified the GPIO number of a ADC channel, or vice versa.
+e.g.
+
+1. ``ADC1_CHANNEL_0_GPIO_NUM`` is the GPIO number of ADC1 channel 0 (36);
+2. ``ADC1_GPIO32_CHANNEL`` is the ADC1 channel number of GPIO 32 (ADC1 channel 4).
+
+.. include:: /_build/inc/adc_channel.inc
ADC Calibration
===============
API Reference
-------------
-.. include:: /_build/inc/esp_adc_cal.inc
\ No newline at end of file
+.. include:: /_build/inc/esp_adc_cal.inc
.. include:: /_build/inc/dac.inc
+GPIO Lookup Macros
+^^^^^^^^^^^^^^^^^^
+Some useful macros can be used to specified the GPIO number of a DAC channel, or vice versa.
+e.g.
+
+1. ``DAC_CHANNEL_1_GPIO_NUM`` is the GPIO number of channel 1 (25);
+2. ``DAC_GPIO26_CHANNEL`` is the channel number of GPIO 26 (channel 2).
+
+.. include:: /_build/inc/dac_channel.inc
SPI Master <spi_master>
SPI Slave <spi_slave>
Timer <timer>
- Touch pad <touch_pad>
+ Touch Sensor <touch_pad>
UART <uart>
Example code for this API section is provided in :example:`peripherals` directory of ESP-IDF examples.
``trans_conf.rx_length`` respectively. ** Note that a half duplex transaction with both a read and
write phase is not supported when using DMA. ** If such transaction is needed, you have to use one
of the alternative solutions:
+
1. use full-duplex mode instead.
2. disable the DMA by set the last parameter to 0 in bus initialization function just as belows:
``ret=spi_bus_initialize(VSPI_HOST, &buscfg, 0);``
Normally, data to be transferred to or from a device will be read from or written to a chunk of memory
indicated by the ``rx_buffer`` and ``tx_buffer`` members of the transaction structure.
When DMA is enabled for transfers, these buffers are highly recommended to meet the requirements as belows:
+
1. allocated in DMA-capable memory using ``pvPortMallocCaps(size, MALLOC_CAP_DMA)``;
2. 32-bit aligned (start from the boundary and have length of multiples of 4 bytes).
+
If these requirements are not satisfied, efficiency of the transaction will suffer due to the allocation and
memcpy of temporary buffers.
Touch Sensor
============
-Overview
---------
+Introduction
+------------
A touch-sensor system is built on a substrate which carries electrodes and relevant connections under a protective flat surface. When a user touches the surface, the capacitance variation is triggered and a binary signal is generated to indicate whether the touch is valid.
-ESP32 can provide up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations, so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer.
+ESP32 can provide up to 10 capacitive touch pads / GPIOs. The sensing pads can be arranged in different combinations (e.g. matrix, slider), so that a larger area or more points can be detected. The touch pad sensing process is under the control of a hardware-implemented finite-state machine (FSM) which is initiated by software or a dedicated hardware timer.
+
+Design, operation and control registers of touch sensor are discussed in `ESP32 Technical Reference Manual <https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf>`_ (PDF). Please refer to it for additional details how this subsystem works.
+
+
+Functionality Overview
+----------------------
+
+Description of API is broken down into groups of functions to provide quick overview of features like:
+
+- Initialization of touch pad driver
+- Configuration of touch pad GPIO pins
+- Taking measurements
+- Adjusting parameters of measurements
+- Filtering measurements
+- Touch detection methods
+- Setting up interrupts to report touch detection
+- Waking up from sleep mode on interrupt
+
+For detailed description of particular function please go to section :ref:`touch_pad-api-reference`. Practical implementation of this API is covered in section :ref:`touch_pad-api-examples`.
+
+
+Initialization
+^^^^^^^^^^^^^^
+
+Touch pad driver should be initialized before use by calling function :cpp:func:`touch_pad_init`. This function sets several ``.._DEFAULT`` driver parameters listed in :ref:`touch_pad-api-reference` under "Macros". It also clears information what pads have been touched before (if any) and disables interrupts.
+
+If not required anymore, driver can be disabled by calling :cpp:func:`touch_pad_deinit`.
+
+
+Configuration
+^^^^^^^^^^^^^
+
+Enabling of touch sensor functionality for particular GPIO is done with :cpp:func:`touch_pad_config`.
+
+The function :cpp:func:`touch_pad_set_fsm_mode` is used to select whether touch pad measurement (operated by FSM) is started automatically by hardware timer, or by software. If software mode is selected, then use :cpp:func:`touch_pad_sw_start` to start of the FSM.
+
+
+Touch State Measurements
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following two functions come handy to read raw or filtered measurements from the sensor:
+
+* :cpp:func:`touch_pad_read`
+* :cpp:func:`touch_pad_read_filtered`
+
+They may be used to characterize particular touch pad design by checking the range of sensor readings when a pad is touched or released. This information can be then used to establish the touch threshold.
+
+.. note::
+
+ Start and configure filter before using :cpp:func:`touch_pad_read_filtered` by calling specific filter functions described down below.
+
+To see how to use both read functions check :example:`peripherals/touch_pad_read` application example.
+
+
+Optimization of Measurements
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Touch sensor has several configurable parameters to match characteristics of particular touch pad design. For instance, to sense smaller capacity changes, it is possible to narrow the reference voltage range within which the touch pads are charged / discharged. The high and low reference voltages are set using function :cpp:func:`touch_pad_set_voltage`. A positive side effect, besides ability to discern smaller capacity changes, will be reduction of power consumption for low power applications. A likely negative effect will be increase of measurement noise. If dynamic rage of obtained readings is still satisfactory, then further reduction of power consumption may be done by lowering the measurement time with :cpp:func:`touch_pad_set_meas_time`.
+
+The following summarizes available measurement parameters and corresponding 'set' functions:
+
+* Touch pad charge / discharge parameters:
+
+ * voltage range: :cpp:func:`touch_pad_set_voltage`
+ * speed (slope): :cpp:func:`touch_pad_set_cnt_mode`
+
+* Measure time: :cpp:func:`touch_pad_set_meas_time`
+
+Relationship between voltage range (high / low reference voltages), speed (slope) and measure time is shown on figure below.
+
+.. figure:: ../../_static/touch_pad-measurement-parameters.jpg
+ :align: center
+ :alt: Touch Pad - relationship between measurement parameters
+ :figclass: align-center
+
+ Touch Pad - relationship between measurement parameters
+
+The last chart "Output" represents the touch sensor reading, i.e. the count of pulses collected within measure time.
+
+All functions are provided in pairs to 'set' specific parameter and to 'get' the current parameter's value, e.g. :cpp:func:`touch_pad_set_voltage` and :cpp:func:`touch_pad_get_voltage`.
+
+.. _touch_pad-api-filtering-of-measurements:
+
+Filtering of Measurements
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If measurements are noisy, you may filter them with provided API. The filter should be started before first use by calling :cpp:func:`touch_pad_filter_start`.
+
+The filter type is IIR (Infinite Impulse Response) and it has configurable period that can be set with function :cpp:func:`touch_pad_set_filter_period`.
+
+You can stop the filter with :cpp:func:`touch_pad_filter_stop`. If not required anymore, the filter may be deleted by invoking :cpp:func:`touch_pad_filter_delete`.
+
+
+Touch Detection
+^^^^^^^^^^^^^^^
+
+Touch detection is implemented in ESP32's hardware basing on user configured threshold and raw measurements executed by FSM. Use function :cpp:func:`touch_pad_get_status` to check what pads have been touched and :cpp:func:`touch_pad_clear_status` to clear the touch status information.
+
+Hardware touch detection may be also wired to interrupts and this is described in next section.
+
+If measurements are noisy and capacity changes small, then hardware touch detection may be not reliable. To resolve this issue, instead of using hardware detection / provided interrupts, implement measurement filtering and perform touch detection in your own application. See :example:`peripherals/touch_pad_interrupt` for sample implementation of both methods of touch detection.
+
+
+Touch Triggered Interrupts
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Before enabling an interrupt on touch detection, user should establish touch detection threshold. Use functions described above to read and display sensor measurements when pad is touched and released. Apply a filter when measurements are noisy and relative changes are small. Depending on your application and environmental conditions, test the influence of temperature and power supply voltage changes on measured values.
+
+Once detection threshold is established, it may be set on initialization with :cpp:func:`touch_pad_config` or at the runtime with :cpp:func:`touch_pad_set_thresh`.
+
+In next step configure how interrupts are triggered. They may be triggered below or above threshold and this is set with function :cpp:func:`touch_pad_set_trigger_mode`.
+
+Finally configure and manage interrupt calls using the following functions:
+
+* :cpp:func:`touch_pad_isr_register` / :cpp:func:`touch_pad_isr_deregister`
+* :cpp:func:`touch_pad_intr_enable` / :cpp:func:`touch_pad_intr_disable`
+
+When interrupts are operational, you can obtain information what particular pad triggered interrupt by invoking :cpp:func:`touch_pad_get_status` and clear pad status with :cpp:func:`touch_pad_clear_status`.
+
+.. note::
+
+ Interrupts on touch detection operate on raw / unfiltered measurements checked against user established threshold and are implemented in hardware. Enabling software filtering API (see :ref:`touch_pad-api-filtering-of-measurements`) does not affect this process.
+
+
+Wakeup from Sleep Mode
+^^^^^^^^^^^^^^^^^^^^^^
+
+If touch pad interrupts are used to wakeup the chip from a sleep mode, then user can select certain configuration of pads (SET1 or both SET1 and SET2), that should be touched to trigger the interrupt and cause subsequent wakeup. To do so, use function :cpp:func:`touch_pad_set_trigger_source`.
+
+Configuration of required bit patterns of pads may be managed for each 'SET' with:
+
+* :cpp:func:`touch_pad_set_group_mask` / :cpp:func:`touch_pad_get_group_mask`
+* :cpp:func:`touch_pad_clear_group_mask`
+
+
+.. _touch_pad-api-examples:
Application Examples
--------------------
- Touch sensor read example: :example:`peripherals/touch_pad_read`.
- Touch sensor interrupt example: :example:`peripherals/touch_pad_interrupt`.
+
+.. _touch_pad-api-reference:
+
API Reference
-------------
.. include:: /_build/inc/touch_pad.inc
+GPIO Lookup Macros
+^^^^^^^^^^^^^^^^^^
+Some useful macros can be used to specified the GPIO number of a touchpad channel, or vice versa.
+e.g.
+
+1. ``TOUCH_PAD_NUM5_GPIO_NUM`` is the GPIO number of channel 5 (12);
+2. ``TOUCH_PAD_GPIO4_CHANNEL`` is the channel number of GPIO 4 (channel 0).
+
+.. include:: /_build/inc/touch_channel.inc
+
.. include:: /_build/inc/uart.inc
+GPIO Lookup Macros
+^^^^^^^^^^^^^^^^^^
+Some useful macros can be used to specified the **direct** GPIO (UART module connected to pads through direct IO mux without the GPIO mux) number of a UART channel, or vice versa.
+The pin name can be omitted if specify the channel of a GPIO num.
+e.g.
+
+1. ``UART_NUM_2_TXD_DIRECT_GPIO_NUM`` is the GPIO number of UART channel 2 TXD pin (17);
+2. ``UART_GPIO19_DIRECT_CHANNEL`` is the UART channel number of GPIO 19 (channel 0);
+3. ``UART_CTS_GPIO19_DIRECT_CHANNEL`` is the UART channel number of GPIO 19, and GPIO 19 must be a CTS pin (channel 0).
+
+
+.. include:: /_build/inc/uart_channel.inc
+
Virtual Filesystem <vfs>
FAT Filesystem <fatfs>
Wear Levelling <wear-levelling>
+ SPIFFS Filesystem <spiffs>
Example code for this API section is provided in :example:`storage` directory of ESP-IDF examples.
--- /dev/null
+SPIFFS Filesystem\r
+=================\r
+\r
+Overview\r
+--------\r
+\r
+SPIFFS is a file system intended for SPI NOR flash devices on embedded targets.\r
+It supports wear leveling, file system consistency checks and more.\r
+\r
+Notes\r
+-----\r
+\r
+ - Presently, spiffs does not support directories. It produces a flat structure. If SPIFFS is mounted under ``/spiffs`` creating a file with path ``/spiffs/tmp/myfile.txt`` will create a file called ``/tmp/myfile.txt`` in SPIFFS, instead of ``myfile.txt`` under directory ``/spiffs/tmp``. \r
+ - It is not a realtime stack. One write operation might last much longer than another.\r
+ - Presently, it does not detect or handle bad blocks.\r
+\r
+Tools\r
+-----\r
+\r
+Host-Side tools for creating SPIFS partition images exist and one such tool is `mkspiffs <https://github.com/igrr/mkspiffs>`_.\r
+You can use it to create image from a given folder and then flash that image with ``esptool.py``\r
+\r
+To do that you need to obtain some parameters:\r
+\r
+- Block Size: 4096 (standard for SPI Flash)\r
+- Page Size: 256 (standard for SPI Flash)\r
+- Image Size: Size of the partition in bytes (can be obtained from partition table)\r
+- Partition Offset: Starting address of the partition (can be obtained from partition table)\r
+\r
+To pack a folder into 1 Megabyte image::\r
+\r
+ mkspiffs -c [src_folder] -b 4096 -p 256 -s 0x100000 spiffs.bin\r
+\r
+To flash the image to ESP32 at offset 0x110000::\r
+\r
+ python esptool.py --chip esp32 --port [port] --baud [baud] write_flash -z 0x110000 spiffs.bin\r
+\r
+See also\r
+--------\r
+\r
+- :doc:`Partition Table documentation <../../api-guides/partition-tables>`\r
+\r
+Application Example\r
+-------------------\r
+\r
+An example for using SPIFFS is provided in :example:`storage/spiffs` directory. This example initializes and mounts SPIFFS partition, and writes and reads data from it using POSIX and C library APIs. See README.md file in the example directory for more information.\r
+\r
+High level API Reference\r
+------------------------\r
+\r
+* :component_file:`spiffs/include/esp_spiffs.h`\r
+\r
+.. include:: /_build/inc/esp_spiffs.inc\r
* `ESP-WROVER-KIT V2 schematic`_ (PDF)
* `ESP32 Datasheet <https://www.espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf>`_ (PDF)
-* `ESP-WROOM-32 Datasheet <http://www.espressif.com/sites/default/files/documentation/esp_wroom_32_datasheet_en.pdf>`_ (PDF)
+* `ESP-WROOM-32 Datasheet <https://www.espressif.com/sites/default/files/documentation/esp-wroom-32_datasheet_en.pdf>`_ (PDF)
* `ESP32-WROVER Datasheet <https://espressif.com/sites/default/files/documentation/esp32-wrover_datasheet_en.pdf>`_ (PDF)
* :doc:`../api-guides/jtag-debugging/index`
* :doc:`../hw-reference/modules-and-boards`
\r
If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``.\r
\r
+.. note::\r
+\r
+ Most ESP32 development boards have a 40MHz crystal installed. However, some boards use a 26MHz crystal. If your board uses a 26MHz crystal, or you get garbage output from serial port after code upload, adjust the :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` option in menuconfig.\r
\r
.. _get-started-build-flash:\r
\r
import os
import re
import sys
+import platform
# File layout:
#
self.m = register_special_symbol(TRISTATE, "m", "m")
self.y = register_special_symbol(TRISTATE, "y", "y")
# DEFCONFIG_LIST uses this
- register_special_symbol(STRING, "UNAME_RELEASE", os.uname()[2])
+ # changed os.uname to platform.uname for compatibility with Windows
+ register_special_symbol(STRING, "UNAME_RELEASE", platform.uname()[2])
# The symbol with "option defconfig_list" set, containing a list of
# default .config files
--- /dev/null
+_build/inc/esp_a2dp_api.inc:26: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
+ union esp_a2d_mcc_t::@1 esp_a2d_mcc_t::cie
+ ---------------------^
+_build/inc/esp_bt_defs.inc:11: WARNING: Invalid definition: Expected identifier in nested name. [error at 21]
+ union esp_bt_uuid_t::@0 esp_bt_uuid_t::uuid
+ ---------------------^
+/builds/idf/esp-idf/docs/api-reference/storage/sdmmc.rst:24: WARNING: cpp:typeOrConcept targets a member (sdmmc_host_t::slot).
+/builds/idf/esp-idf/docs/api-reference/storage/sdmmc.rst:24: WARNING: cpp:typeOrConcept targets a member (sdmmc_host_t::slot).
+/builds/idf/esp-idf/docs/api-reference/storage/sdmmc.rst:24: WARNING: cpp:typeOrConcept targets a member (sdmmc_host_t::slot).
break;
}
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
- gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char.attr_handle;
+ gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n",
- param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
+ param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;
case ESP_GATTS_DELETE_EVT:
break;
NULL, NULL);
break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
- gl_profile_tab[PROFILE_B_APP_ID].descr_handle = param->add_char.attr_handle;
+ gl_profile_tab[PROFILE_B_APP_ID].descr_handle = param->add_char_descr.attr_handle;
ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n",
- param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
+ param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
break;
case ESP_GATTS_DELETE_EVT:
break;
vTaskDelay(1000 / portTICK_PERIOD_MS);
continue;
}
- ESP_LOGI(TAG, "... allocated socket\r\n");
+ ESP_LOGI(TAG, "... allocated socket");
if(connect(s, res->ai_addr, res->ai_addrlen) != 0) {
ESP_LOGE(TAG, "... socket connect failed errno=%d", errno);
}
ESP_LOGI(TAG, "... socket send success");
+ struct timeval receiving_timeout;
+ receiving_timeout.tv_sec = 5;
+ receiving_timeout.tv_usec = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &receiving_timeout,
+ sizeof(receiving_timeout)) < 0) {
+ ESP_LOGE(TAG, "... failed to set socket receiving timeout");
+ close(s);
+ vTaskDelay(4000 / portTICK_PERIOD_MS);
+ continue;
+ }
+ ESP_LOGI(TAG, "... set socket receiving timeout success");
+
/* Read HTTP response */
do {
bzero(recv_buf, sizeof(recv_buf));
If not done already, consider checking simpler example *storage/nvs_rw_value*, that has been used as a starting point for preparing this one.
-Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html).
+Detailed functional description of NVS and API is provided in [documentation](https://esp-idf.readthedocs.io/en/latest/api-reference/nvs_flash.html).
See the README.md file in the upper level 'examples' directory for more information about examples.
Check another example *storage/nvs_rw_blob*, that shows how to read and write variable length binary data (blob).
-Detailed functional description of NVS and API is provided in [documentation](http://esp-idf.readthedocs.io/en/latest/api/nvs_flash.html).
+Detailed functional description of NVS and API is provided in [documentation](https://esp-idf.readthedocs.io/en/latest/api-reference/nvs_flash.html).
See the README.md file in the upper level 'examples' directory for more information about examples.
--- /dev/null
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := spiffs
+
+include $(IDF_PATH)/make/project.mk
+
--- /dev/null
+# SPIFFS example
+
+This example demonstrates how to use SPIFFS with ESP32. Example does the following steps:
+
+1. Use an "all-in-one" `esp_vfs_spiffs_register` function to:
+ - initialize SPIFFS,
+ - mount SPIFFS filesystem using SPIFFS library (and format, if the filesystem can not be mounted),
+ - register SPIFFS filesystem in VFS, enabling C standard library and POSIX functions to be used.
+2. Create a file using `fopen` and write to it using `fprintf`.
+3. Rename the file. Before renaming, check if destination file already exists using `stat` function, and remove it using `unlink` function.
+4. Open renamed file for reading, read back the line, and print it to the terminal.
+
+## Example output
+
+Here is an example console output. In this case `format_if_mount_failed` parameter was set to `true` in the source code. SPIFFS was unformatted, so the initial mount has failed. SPIFFS was then formatted, and mounted again.
+
+```
+I (195) example: Initializing SPIFFS
+E (195) SPIFFS: mount failed, -10025. formatting...
+I (4525) example: Opening file
+I (4635) example: File written
+I (4685) example: Renaming file
+I (4735) example: Reading file
+I (4735) example: Read from file: 'Hello World!'
+I (4735) example: SPIFFS unmounted
+```
+
--- /dev/null
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
--- /dev/null
+/* SPIFFS filesystem 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 <stdio.h>
+#include <string.h>
+#include <sys/unistd.h>
+#include <sys/stat.h>
+#include "esp_err.h"
+#include "esp_log.h"
+#include "esp_spiffs.h"
+
+static const char *TAG = "example";
+
+void app_main(void)
+{
+ ESP_LOGI(TAG, "Initializing SPIFFS");
+
+ esp_vfs_spiffs_conf_t conf = {
+ .base_path = "/spiffs",
+ .partition_label = NULL,
+ .max_files = 5,
+ .format_if_mount_failed = true
+ };
+
+ // Use settings defined above to initialize and mount SPIFFS filesystem.
+ // Note: esp_vfs_spiffs_register is an all-in-one convenience function.
+ esp_err_t ret = esp_vfs_spiffs_register(&conf);
+
+ if (ret != ESP_OK) {
+ if (ret == ESP_FAIL) {
+ ESP_LOGE(TAG, "Failed to mount or format filesystem");
+ } else if (ret == ESP_ERR_NOT_FOUND) {
+ ESP_LOGE(TAG, "Failed to find SPIFFS partition");
+ } else {
+ ESP_LOGE(TAG, "Failed to initialize SPIFFS (%d)", ret);
+ }
+ return;
+ }
+
+ size_t total = 0, used = 0;
+ ret = esp_spiffs_info(NULL, &total, &used);
+ if (ret != ESP_OK) {
+ ESP_LOGE(TAG, "Failed to get SPIFFS partition information");
+ } else {
+ ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
+ }
+
+ // Use POSIX and C standard library functions to work with files.
+ // First create a file.
+ ESP_LOGI(TAG, "Opening file");
+ FILE* f = fopen("/spiffs/hello.txt", "w");
+ if (f == NULL) {
+ ESP_LOGE(TAG, "Failed to open file for writing");
+ return;
+ }
+ fprintf(f, "Hello World!\n");
+ fclose(f);
+ ESP_LOGI(TAG, "File written");
+
+ // Check if destination file exists before renaming
+ struct stat st;
+ if (stat("/spiffs/foo.txt", &st) == 0) {
+ // Delete it if it exists
+ unlink("/spiffs/foo.txt");
+ }
+
+ // Rename original file
+ ESP_LOGI(TAG, "Renaming file");
+ if (rename("/spiffs/hello.txt", "/spiffs/foo.txt") != 0) {
+ ESP_LOGE(TAG, "Rename failed");
+ return;
+ }
+
+ // Open renamed file for reading
+ ESP_LOGI(TAG, "Reading file");
+ f = fopen("/spiffs/foo.txt", "r");
+ if (f == NULL) {
+ ESP_LOGE(TAG, "Failed to open file for reading");
+ return;
+ }
+ char line[64];
+ fgets(line, sizeof(line), f);
+ fclose(f);
+ // strip newline
+ char* pos = strchr(line, '\n');
+ if (pos) {
+ *pos = '\0';
+ }
+ ESP_LOGI(TAG, "Read from file: '%s'", line);
+
+ // All done, unmount partition and disable SPIFFS
+ esp_vfs_spiffs_unregister(NULL);
+ ESP_LOGI(TAG, "SPIFFS unmounted");
+}
--- /dev/null
+# Name, Type, SubType, Offset, Size, Flags
+# 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,
+storage, data, spiffs, , 0xF0000,
--- /dev/null
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
+CONFIG_APP_OFFSET=0x10000
else
summary := @echo
details := @true
-endif
# disable echoing of commands, directory names
MAKEFLAGS += --silent
+endif # $(V)==1
ifdef CONFIG_MAKE_WARN_UNDEFINED_VARIABLES
MAKEFLAGS += --warn-undefined-variables
components/libsodium/libsodium @GENERAL_MIRROR_SERVER@/idf/libsodium.git ALLOW_TO_SYNC_FROM_PUBLIC
components/micro-ecc/micro-ecc @GENERAL_MIRROR_SERVER@/idf/micro-ecc.git ALLOW_TO_SYNC_FROM_PUBLIC
components/nghttp/nghttp2 @GENERAL_MIRROR_SERVER@/idf/nghttp2.git ALLOW_TO_SYNC_FROM_PUBLIC
+components/spiffs/spiffs @GENERAL_MIRROR_SERVER@/idf/spiffs.git ALLOW_TO_SYNC_FROM_PUBLIC
third-party/mruby @GENERAL_MIRROR_SERVER@/idf/mruby.git ALLOW_TO_SYNC_FROM_PUBLIC
third-party/neverbleed @GENERAL_MIRROR_SERVER@/idf/neverbleed.git ALLOW_TO_SYNC_FROM_PUBLIC
# (done this way so tests can run in 2MB of flash.)
ota_0, 0, ota_0, , 64K
ota_1, 0, ota_1, , 64K
-# flash_test partition used for SPI flash tests and WL FAT partition
-# 528K is the minimal size needed to create a FAT partition
-# (128 sectors for FAT + 4 sectors for WL)
+# flash_test partition used for SPI flash tests, WL FAT tests, and SPIFFS tests
flash_test, data, fat, , 528K