]> granicus.if.org Git - esp-idf/commitdiff
Merge branch 'feature/gcov_over_apptrace' into 'master'
authorIvan Grokhotkov <ivan@espressif.com>
Tue, 12 Sep 2017 10:54:26 +0000 (18:54 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Tue, 12 Sep 2017 10:54:26 +0000 (18:54 +0800)
esp32: Adds gcov over JTAG feature

See merge request !1117

69 files changed:
.gitlab-ci.yml
.gitmodules
components/bootloader/subproject/main/bootloader_start.c
components/bt/bluedroid/hci/hci_layer.c
components/bt/bluedroid/hci/include/hci_layer.h
components/bt/bluedroid/stack/gatt/gatt_utils.c
components/driver/include/driver/adc.h
components/driver/include/driver/dac.h
components/driver/include/driver/rtc_io.h
components/driver/include/driver/touch_pad.h
components/driver/include/driver/uart.h
components/driver/rtc_module.c
components/driver/uart.c
components/esp32/cache_err_int.c
components/esp32/dport_access.c
components/fatfs/src/vfs_fat_spiflash.c
components/freertos/include/freertos/FreeRTOSConfig.h
components/freertos/tasks.c
components/freertos/test/test_tasks_snapshot.c [new file with mode: 0644]
components/lwip/apps/dhcpserver.c
components/lwip/include/lwip/apps/dhcpserver.h
components/lwip/include/lwip/apps/dhcpserver_options.h [new file with mode: 0644]
components/nvs_flash/src/nvs_api.cpp
components/nvs_flash/test_nvs_host/test_nvs.cpp
components/soc/esp32/include/soc/adc_channel.h [new file with mode: 0644]
components/soc/esp32/include/soc/clkout_channel.h [new file with mode: 0644]
components/soc/esp32/include/soc/dac_channel.h [new file with mode: 0644]
components/soc/esp32/include/soc/rtc_gpio_channel.h [new file with mode: 0644]
components/soc/esp32/include/soc/touch_channel.h [new file with mode: 0644]
components/soc/esp32/include/soc/uart_channel.h [new file with mode: 0644]
components/soc/esp32/rtc_clk.c
components/spiffs/Kconfig [new file with mode: 0644]
components/spiffs/component.mk [new file with mode: 0644]
components/spiffs/esp_spiffs.c [new file with mode: 0644]
components/spiffs/include/esp_spiffs.h [new file with mode: 0644]
components/spiffs/include/spiffs_config.h [new file with mode: 0755]
components/spiffs/spiffs [new submodule]
components/spiffs/test/component.mk [new file with mode: 0644]
components/spiffs/test/test_spiffs.c [new file with mode: 0644]
components/tcpip_adapter/tcpip_adapter_lwip.c
docs/Doxyfile
docs/_static/touch_pad-measurement-parameters.jpg [new file with mode: 0644]
docs/api-guides/app_trace.rst
docs/api-guides/build-system.rst
docs/api-reference/peripherals/adc.rst
docs/api-reference/peripherals/dac.rst
docs/api-reference/peripherals/index.rst
docs/api-reference/peripherals/spi_master.rst
docs/api-reference/peripherals/touch_pad.rst
docs/api-reference/peripherals/uart.rst
docs/api-reference/storage/index.rst
docs/api-reference/storage/spiffs.rst [new file with mode: 0644]
docs/get-started/get-started-wrover-kit-v2.rst
docs/get-started/index.rst
docs/kconfiglib.py
docs/sphinx-known-warnings.txt [new file with mode: 0644]
examples/bluetooth/gatt_server/main/gatts_demo.c
examples/protocols/http_request/main/http_request_example_main.c
examples/storage/nvs_rw_blob/README.md
examples/storage/nvs_rw_value/README.md
examples/storage/spiffs/Makefile [new file with mode: 0644]
examples/storage/spiffs/README.md [new file with mode: 0644]
examples/storage/spiffs/main/component.mk [new file with mode: 0644]
examples/storage/spiffs/main/spiffs_example_main.c [new file with mode: 0644]
examples/storage/spiffs/partitions_example.csv [new file with mode: 0644]
examples/storage/spiffs/sdkconfig.defaults [new file with mode: 0644]
make/common.mk
tools/ci/mirror-list.txt
tools/unit-test-app/partition_table_unit_test_app.csv

index a480e580b300da5cef2e02a29ba843aa8bb69283..4989fa7ebbb357834507ff3ddebb60f538a52ac2 100644 (file)
@@ -175,16 +175,31 @@ build_docs:
   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
index c54435224f6bb54fce57e90834bea1ebbdac0337..e118821b73c51d2c51d68a9abd720c2ccea37389 100644 (file)
@@ -29,3 +29,7 @@
 [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
index 65e55fac9e5b0fde97ed15e99223a34dd6820cd0..012348ddf2e5b6f7df8b312f47390e08c3fdb4e8 100644 (file)
@@ -753,7 +753,6 @@ static void clock_configure(void)
         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;
index 5b5205dd9a5d0faab461005ccc04c998482f4972..1c5117c7f25046582b9dab1c0d33a1987e38f0ae 100644 (file)
@@ -32,6 +32,7 @@
 #include "alarm.h"
 #include "thread.h"
 #include "mutex.h"
+#include "fixed_queue.h"
 
 typedef struct {
     uint16_t opcode;
index 76f93638ad375e9490c61c9ae1eef83432c9dcc9..5e9b8c695b50c2da918ff28f691d3e5922236a63 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "bt_types.h"
 #include "allocator.h"
-#include "fixed_queue.h"
 #include "osi.h"
 #include "future.h"
 ///// LEGACY DEFINITIONS /////
index 30b618001b214c66411b0964d234e6fe2fceb246..0266a212d5ad85aa4bb9e0eed06d79f25e2ca5c3 100644 (file)
@@ -2216,9 +2216,10 @@ void gatt_cleanup_upon_disc(BD_ADDR bda, UINT16 reason, tBT_TRANSPORT transport)
         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) {
index 444f145eb3b572076d1319a37d1188a87edb0685..08d32288211e0a78e24fb7161df5473ee3eb2213 100644 (file)
@@ -22,6 +22,7 @@ extern "C" {
 #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 */
@@ -49,6 +50,20 @@ typedef enum {
     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.
  *
index 842894d0e967c4eb854113ca5558582c09f5dd7a..a5563bb821f594509e25e1ed705d1d96b790ae63 100644 (file)
@@ -21,6 +21,7 @@ extern "C" {
 
 #include <stdint.h>
 #include "esp_err.h"
+#include "soc/dac_channel.h"
 
 typedef enum {
     DAC_CHANNEL_1 = 1,  /*!< DAC channel 1 is GPIO25 */
index 5abff188055ab1a3528bba8b8c73e8f695555793..831a07fdb3b6f4795e41940bf5b3faa63cbb85ac 100644 (file)
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include "esp_err.h"
 #include "driver/gpio.h"
+#include "soc/rtc_gpio_channel.h"
 
 #ifdef __cplusplus
 extern "C" {
index 548edbcf524a68ec7811d18ab7e5c711b9109ef1..ce67a7dc72fe97a62f59571857f3d5ca026e7698 100644 (file)
@@ -20,6 +20,7 @@ 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 */
@@ -101,11 +102,11 @@ typedef enum {
 
 typedef intr_handle_t touch_isr_handle_t;
 
-#define TOUCH_PAD_SLEEP_CYCLE_DEFAULT   (0x1000)  /*!<The timer frequency is RTC_SLOW_CLKcan 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)
 
 /**
@@ -128,9 +129,10 @@ esp_err_t touch_pad_deinit();
  * @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);
 
@@ -143,9 +145,10 @@ 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);
 
@@ -156,9 +159,10 @@ 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);
 
@@ -460,7 +464,7 @@ esp_err_t touch_pad_get_filter_period(uint32_t* p_period_ms);
  *
  *      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.
index 9bd35e4359035869e09aa9b462810fb2f76fd2e2..de1b619f93059b9164fd4ae078bf786e2b4324f8 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #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 */
@@ -268,6 +269,20 @@ esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
  */
 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
  *
index aecb0e92f672c17e73ae2eb53aed95c0986bab08..0804721e4d95ba933b7ac91c1176d70d07c5c483 100644 (file)
@@ -74,11 +74,11 @@ static touch_pad_filter_t *s_touch_pad_filter = NULL;
 
 //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
@@ -86,10 +86,10 @@ const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
     {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
@@ -99,21 +99,21 @@ const rtc_gpio_desc_t rtc_gpio_desc[GPIO_PIN_COUNT] = {
     {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
 };
 
 /*---------------------------------------------------------------
@@ -377,34 +377,34 @@ static esp_err_t touch_pad_get_io_num(touch_pad_t touch_num, gpio_num_t *gpio_nu
 {
     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;
@@ -879,28 +879,28 @@ static esp_err_t adc1_pad_get_io_num(adc1_channel_t channel, gpio_num_t *gpio_nu
 
     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;
@@ -1041,10 +1041,10 @@ static esp_err_t dac_pad_get_io_num(dac_channel_t channel, gpio_num_t *gpio_num)
 
     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;
index 5371a447c8feb40371b9f2276b0ad05b250a5d64..fffae17344cd24f88bca85de4551ea482bf3fd31 100644 (file)
@@ -29,6 +29,9 @@
 #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)) { \
@@ -199,6 +202,22 @@ esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask)
     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)
 {
index d8fa649a00788c737004a3b38213db8f9e822f35..a6de81ce65b36fa6192435469ceac75de02851d9 100644 (file)
@@ -29,6 +29,7 @@
 #include "esp_attr.h"
 #include "soc/dport_reg.h"
 #include "sdkconfig.h"
+#include "esp_dport_access.h"
 
 void esp_cache_err_int_init()
 {
@@ -72,6 +73,7 @@ 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 |
index 8cafeb456230bec104cfbf4e67325bc1781866cc..af6c92e1abc59f8b2db4734d8fe84f6b482cfdde 100644 (file)
@@ -184,7 +184,7 @@ void esp_dport_access_int_init(void)
     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;
@@ -194,7 +194,7 @@ void esp_dport_access_int_pause(void)
     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;
index b9f80354a14fcad755de8f93240ccba525005914..2e90468d2b0dcac62c81fe73ed0f0be5abcedd6c 100644 (file)
@@ -32,7 +32,10 @@ esp_err_t esp_vfs_fat_spiflash_mount(const char* base_path,
     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;
index 81e8a7734719987e673e41a0f93d2f487c54d230..3ccd3fda695f3032a24f44185caad6ae005545f4 100644 (file)
@@ -269,9 +269,7 @@ extern void vPortCleanUpTCB ( void *pxTCB );
 #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__
index 0433deb2af4da5707c0a0d0c5e602ebc09389d2c..9126f862e0e2ba42091812a829f9029a1586f899 100644 (file)
@@ -4991,22 +4991,24 @@ TickType_t uxReturn;
 #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 )
        {
@@ -5017,12 +5019,11 @@ TickType_t uxReturn;
                        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
@@ -5035,8 +5036,6 @@ TickType_t uxReturn;
        {
                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
@@ -5052,12 +5051,11 @@ PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB[ portNUM_PROCESSORS ] = { NULL };
                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 )
                {
diff --git a/components/freertos/test/test_tasks_snapshot.c b/components/freertos/test/test_tasks_snapshot.c
new file mode 100644 (file)
index 0000000..c9364cc
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ 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);
+}
index 44ddd33681285378db0180bb96d950a3a95e8cd0..c5ce7a8adebaa0c66684c8960bcb244fd3c8e526 100644 (file)
@@ -23,6 +23,7 @@
 #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;
@@ -135,7 +141,7 @@ void *dhcps_option_info(u8_t op_id, u32_t opt_len)
  *                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;
index 9e361833d3de0dda5c73d67006f5eae8be2b7967..a0024ab5f05354fb72368d50b13566411d3cfb8f 100644 (file)
@@ -36,123 +36,6 @@ typedef struct dhcps_msg {
         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;
@@ -176,11 +59,6 @@ struct dhcps_pool{
        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;
 
diff --git a/components/lwip/include/lwip/apps/dhcpserver_options.h b/components/lwip/include/lwip/apps/dhcpserver_options.h
new file mode 100644 (file)
index 0000000..38d46f6
--- /dev/null
@@ -0,0 +1,134 @@
+// 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;
index 57759ecd83798fda1280f998e70c9076cdad0408..0f06def07ea0cd18e58cfb4831c1af590f86f6d9 100644 (file)
@@ -402,6 +402,7 @@ static esp_err_t nvs_get_str_or_blob(nvs_handle handle, nvs::ItemType type, cons
         return ESP_ERR_NVS_INVALID_LENGTH;
     }
 
+    *length = dataSize;
     return entry.mStoragePtr->readItem(entry.mNsIndex, type, key, out_value, dataSize);
 }
 
index 5a35c11f4a12ad094a6e8c90f5248baab449b5c8..f419256cf334b9b8c7db3cd0f025c96e7cd53bce 100644 (file)
@@ -530,6 +530,10 @@ TEST_CASE("nvs api tests", "[nvs]")
     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));
diff --git a/components/soc/esp32/include/soc/adc_channel.h b/components/soc/esp32/include/soc/adc_channel.h
new file mode 100644 (file)
index 0000000..e8835d3
--- /dev/null
@@ -0,0 +1,72 @@
+// 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
diff --git a/components/soc/esp32/include/soc/clkout_channel.h b/components/soc/esp32/include/soc/clkout_channel.h
new file mode 100644 (file)
index 0000000..5161e3f
--- /dev/null
@@ -0,0 +1,26 @@
+// 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
diff --git a/components/soc/esp32/include/soc/dac_channel.h b/components/soc/esp32/include/soc/dac_channel.h
new file mode 100644 (file)
index 0000000..241a067
--- /dev/null
@@ -0,0 +1,24 @@
+// 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
diff --git a/components/soc/esp32/include/soc/rtc_gpio_channel.h b/components/soc/esp32/include/soc/rtc_gpio_channel.h
new file mode 100644 (file)
index 0000000..c5107a0
--- /dev/null
@@ -0,0 +1,73 @@
+// 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
diff --git a/components/soc/esp32/include/soc/touch_channel.h b/components/soc/esp32/include/soc/touch_channel.h
new file mode 100644 (file)
index 0000000..a9aa838
--- /dev/null
@@ -0,0 +1,49 @@
+// 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
diff --git a/components/soc/esp32/include/soc/uart_channel.h b/components/soc/esp32/include/soc/uart_channel.h
new file mode 100644 (file)
index 0000000..5b8dc56
--- /dev/null
@@ -0,0 +1,61 @@
+// 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
index aee0a39ff1ec605882d7b4e1281adf9ab0615b75..39ea41f40d5f09467f66457c44231b1e51386806 100644 (file)
@@ -541,7 +541,8 @@ void rtc_clk_init(rtc_clk_config_t cfg)
     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))) {
@@ -549,13 +550,21 @@ void rtc_clk_init(rtc_clk_config_t cfg)
             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 */
diff --git a/components/spiffs/Kconfig b/components/spiffs/Kconfig
new file mode 100644 (file)
index 0000000..d82ceec
--- /dev/null
@@ -0,0 +1,139 @@
+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
diff --git a/components/spiffs/component.mk b/components/spiffs/component.mk
new file mode 100644 (file)
index 0000000..624b219
--- /dev/null
@@ -0,0 +1,3 @@
+COMPONENT_ADD_INCLUDEDIRS := include
+COMPONENT_PRIV_INCLUDEDIRS := spiffs/src
+COMPONENT_SRCDIRS := . spiffs/src
diff --git a/components/spiffs/esp_spiffs.c b/components/spiffs/esp_spiffs.c
new file mode 100644 (file)
index 0000000..f731f5b
--- /dev/null
@@ -0,0 +1,766 @@
+// 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;
+}
diff --git a/components/spiffs/include/esp_spiffs.h b/components/spiffs/include/esp_spiffs.h
new file mode 100644 (file)
index 0000000..9a1f12c
--- /dev/null
@@ -0,0 +1,94 @@
+// 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_ */
diff --git a/components/spiffs/include/spiffs_config.h b/components/spiffs/include/spiffs_config.h
new file mode 100755 (executable)
index 0000000..e0c9d7f
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * 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_ */
diff --git a/components/spiffs/spiffs b/components/spiffs/spiffs
new file mode 160000 (submodule)
index 0000000..794f047
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 794f0478d2aa9c978c3844da6e97f14239a1e061
diff --git a/components/spiffs/test/component.mk b/components/spiffs/test/component.mk
new file mode 100644 (file)
index 0000000..ce464a2
--- /dev/null
@@ -0,0 +1 @@
+COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
diff --git a/components/spiffs/test/test_spiffs.c b/components/spiffs/test/test_spiffs.c
new file mode 100644 (file)
index 0000000..d60e4a5
--- /dev/null
@@ -0,0 +1,506 @@
+// 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();
+}
index 25676266ac420ce82898d2245dba5e6930d01476..f9d7afe6bca8060e242e65dfe85213b45cfec480 100644 (file)
@@ -33,6 +33,7 @@
 #include "netif/ethernetif.h"
 
 #include "apps/dhcpserver.h"
+#include "apps/dhcpserver_options.h"
 
 #include "esp_event.h"
 #include "esp_log.h"
index 9dccdf56e23c660282fc3508d3800bb8e29bafa1..628db925acff9e267c01fddc10ecabbdae5f2890 100644 (file)
@@ -75,6 +75,11 @@ INPUT = \
     ../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
     ##
@@ -86,6 +91,8 @@ INPUT = \
     ../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 \
diff --git a/docs/_static/touch_pad-measurement-parameters.jpg b/docs/_static/touch_pad-measurement-parameters.jpg
new file mode 100644 (file)
index 0000000..581410b
Binary files /dev/null and b/docs/_static/touch_pad-measurement-parameters.jpg differ
index 68fa4e94c262a11a6f8567d83c8b74e4d97d585b..8ef36d73f1a37ec29968cfcbd035634282545992 100644 (file)
@@ -311,7 +311,7 @@ Optional arguments:
 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::
 
index 34e35de3de71ae08aa4dc47cf0c979681fb58281..54660741e60dbc822e741dd398dd3c0c252da713 100644 (file)
@@ -358,7 +358,7 @@ Warning On Undefined Variables
 
 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.
 
index bc9d3a754343f39b4ed41f40f93d742b52b66ffe..11cc0f48b0c170f5b5c75d4f5eb25b16ea1791ad 100644 (file)
@@ -44,6 +44,15 @@ API Reference
 
 .. 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
 ===============
@@ -99,4 +108,4 @@ Routing ADC reference voltage to GPIO::
 API Reference
 -------------
 
-.. include:: /_build/inc/esp_adc_cal.inc
\ No newline at end of file
+.. include:: /_build/inc/esp_adc_cal.inc
index 7d860f3bf25dc3d21b9da5726892dc8d69e10112..053ba342f55c71bde80bf20172a2f1d727664b04 100644 (file)
@@ -30,3 +30,12 @@ API Reference
 
 .. 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
index 51a46febd439d126fd81f666199c136879bffa1b..001b1173d3e5e7c5da296c5ab6909fbec9a1a8a8 100644 (file)
@@ -18,7 +18,7 @@ Peripherals API
    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.
index 89833e83d73763fef94e428248ed0682a13d2df6..e4b0347f85008b8bfa9bb05c697f77dbd2e3bd12 100644 (file)
@@ -66,6 +66,7 @@ In half duplex, the length of write phase and read phase are decided by ``trans_
 ``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);``  
@@ -109,8 +110,10 @@ Transaction data
 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.
 
index a4ee4950e5f9b28c75a03e0b446f66e6d05fb655..f56a13fe32240615cd5637498044b0edb9833686 100644 (file)
 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
 --------------------
@@ -14,8 +150,21 @@ 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
+
index 921b5eb6339f81868b3ab894ddcc0e266055a698..77c2c8dab7108ca0db85b38509004c32ef8e4941 100644 (file)
@@ -18,4 +18,17 @@ API Reference
 
 .. 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
+
 
index 9c4394bd5a25534cadb471b7f63b17d4a4184c57..9c9215b09f7c221cbc6ec2d457a46b49e88217f4 100644 (file)
@@ -10,6 +10,7 @@ Storage API
    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.
diff --git a/docs/api-reference/storage/spiffs.rst b/docs/api-reference/storage/spiffs.rst
new file mode 100644 (file)
index 0000000..d463024
--- /dev/null
@@ -0,0 +1,53 @@
+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
index f0623ef3fbe03f80eb6402de11089edcbfb1b3a3..271b4052140d23259b17af5342561ed6abd82e97 100644 (file)
@@ -174,7 +174,7 @@ Related Documents
 
 * `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`
index 3a65d6cd7a77a40bfb52997ddac7f3c23a0634cc..31cda9cf3df9010f9d7252f50eb39cc247ae32bf 100644 (file)
@@ -205,6 +205,9 @@ Here are couple of tips on navigation and use of ``menuconfig``:
 \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
index 9bc89f37ea21c2359c1abd1f1f83ffb41cc69e9d..566098d69039b52d40dd653416f2edd88b0a5b14 100644 (file)
@@ -69,6 +69,7 @@ might add it in a safe way as a client API instead."""
 import os
 import re
 import sys
+import platform
 
 # File layout:
 #
@@ -165,7 +166,8 @@ class Config(object):
         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
diff --git a/docs/sphinx-known-warnings.txt b/docs/sphinx-known-warnings.txt
new file mode 100644 (file)
index 0000000..3981c7b
--- /dev/null
@@ -0,0 +1,9 @@
+_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).
index edbe74394726c29e812d5beac6bcde0724ff0d3a..8c30fd326e269e6330cee2711634946e4f25bad2 100644 (file)
@@ -455,9 +455,9 @@ static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
         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;
@@ -608,9 +608,9 @@ static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_i
                                      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;
index be3bb9e364b47f076f2d0ede52f0349d3dcec8b0..c51205e8219acda4d64398251dc9fa3932fab8ce 100644 (file)
@@ -132,7 +132,7 @@ static void http_get_task(void *pvParameters)
             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);
@@ -153,6 +153,18 @@ static void http_get_task(void *pvParameters)
         }
         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));
index 94b8549b36062bbebcb86a6685280bda6573b325..b39c289038f6048886a10fca9a400a6a65c9a001 100644 (file)
@@ -9,6 +9,6 @@ Example also shows how to implement diagnostics if read / write operation was su
 
 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.
index 797e8d422a128326fc14a40976bfb5f2707f7103..eec9f3163e51785d7bc94295baa7b3e583e83f5a 100644 (file)
@@ -8,6 +8,6 @@ Example also shows how to check if read / write operation was successful, or cer
 
 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.
diff --git a/examples/storage/spiffs/Makefile b/examples/storage/spiffs/Makefile
new file mode 100644 (file)
index 0000000..4523423
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# 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
+
diff --git a/examples/storage/spiffs/README.md b/examples/storage/spiffs/README.md
new file mode 100644 (file)
index 0000000..8c048fa
--- /dev/null
@@ -0,0 +1,27 @@
+# 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
+```
+
diff --git a/examples/storage/spiffs/main/component.mk b/examples/storage/spiffs/main/component.mk
new file mode 100644 (file)
index 0000000..a98f634
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
diff --git a/examples/storage/spiffs/main/spiffs_example_main.c b/examples/storage/spiffs/main/spiffs_example_main.c
new file mode 100644 (file)
index 0000000..d2ead73
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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");
+}
diff --git a/examples/storage/spiffs/partitions_example.csv b/examples/storage/spiffs/partitions_example.csv
new file mode 100644 (file)
index 0000000..6d9ee2e
--- /dev/null
@@ -0,0 +1,6 @@
+# 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, 
diff --git a/examples/storage/spiffs/sdkconfig.defaults b/examples/storage/spiffs/sdkconfig.defaults
new file mode 100644 (file)
index 0000000..f30f322
--- /dev/null
@@ -0,0 +1,5 @@
+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
index ea39421cb0dbfa1576ffb63ab9f7212a15492f0d..ccee32278c1acc60bac3c47620bd2263aa7414e5 100644 (file)
@@ -27,10 +27,10 @@ details := @echo
 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
index 549359f60e175bd2d5365d994f450aa3d14ff9bc..d3972aa5d5a4ac3e6e3882e2e55ec844da6542f3 100644 (file)
@@ -6,5 +6,6 @@ components/esptool_py/esptool                       @GENERAL_MIRROR_SERVER@/idf/
 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
index ea43d0791cbd9873f69a7395088548d8e105e9c6..46173719b5826c8dfd84ae31b359928d2710895d 100644 (file)
@@ -10,7 +10,5 @@ factory,    0,    0,       0x10000, 0x140000
 # (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