Ver Fonte

Merge branch 'master' into feature/wpa2_enterprise

Conflicts:
	components/esp32/component.mk
	components/wpa_supplicant/component.mk
Xia Xiaotian há 9 anos atrás
pai
commit
1ca82de638
100 ficheiros alterados com 6169 adições e 1720 exclusões
  1. 5 0
      .gitignore
  2. 6 5
      .gitlab-ci.yml
  3. 3 0
      .gitmodules
  4. 2 1
      CONTRIBUTING.rst
  5. 94 7
      components/bootloader/Kconfig.projbuild
  6. 83 18
      components/bootloader/Makefile.projbuild
  7. 6 3
      components/bootloader/src/Makefile
  8. 0 8
      components/bootloader/src/main/bootloader_config.h
  9. 179 160
      components/bootloader/src/main/bootloader_start.c
  10. 4 7
      components/bootloader/src/main/component.mk
  11. 78 82
      components/bootloader/src/main/flash_encrypt.c
  12. 0 127
      components/bootloader/src/main/secure_boot.c
  13. 9 0
      components/bootloader_support/README.rst
  14. 35 0
      components/bootloader_support/component.mk
  15. 132 0
      components/bootloader_support/include/esp_image_format.h
  16. 75 0
      components/bootloader_support/include/esp_secure_boot.h
  17. 69 0
      components/bootloader_support/include_priv/bootloader_flash.h
  18. 122 0
      components/bootloader_support/src/bootloader_flash.c
  19. 161 0
      components/bootloader_support/src/esp_image_format.c
  20. 222 0
      components/bootloader_support/src/secure_boot.c
  21. 110 0
      components/bootloader_support/src/secure_boot_signatures.c
  22. 2 7
      components/bt/component.mk
  23. 2 5
      components/bt/include/bt.h
  24. 0 6
      components/driver/component.mk
  25. 113 103
      components/driver/gpio.c
  26. 85 8
      components/driver/include/driver/gpio.h
  27. 8 0
      components/driver/include/driver/ledc.h
  28. 748 0
      components/driver/include/driver/uart.h
  29. 56 167
      components/driver/ledc.c
  30. 1027 0
      components/driver/uart.c
  31. 39 0
      components/esp32/Kconfig
  32. 32 0
      components/esp32/Makefile.projbuild
  33. 5 17
      components/esp32/component.mk
  34. 40 0
      components/esp32/cpu_start.c
  35. 1 6
      components/esp32/crosscore_int.c
  36. 20 0
      components/esp32/event_default_handlers.c
  37. 96 0
      components/esp32/freertos_hooks.c
  38. 2 1
      components/esp32/gdbstub.c
  39. 4 0
      components/esp32/include/esp_attr.h
  40. 2 0
      components/esp32/include/esp_err.h
  41. 9 0
      components/esp32/include/esp_event.h
  42. 1 49
      components/esp32/include/esp_flash_data_types.h
  43. 83 0
      components/esp32/include/esp_freertos_hooks.h
  44. 0 3
      components/esp32/include/esp_int_wdt.h
  45. 249 0
      components/esp32/include/esp_phy_init.h
  46. 0 9
      components/esp32/include/esp_task_wdt.h
  47. 209 224
      components/esp32/include/esp_wifi.h
  48. 111 0
      components/esp32/include/esp_wps.h
  49. 1 1
      components/esp32/include/rom/secure_boot.h
  50. 1 0
      components/esp32/include/soc/dport_reg.h
  51. 26 0
      components/esp32/include/soc/efuse_reg.h
  52. 37 0
      components/esp32/include/soc/hwcrypto_reg.h
  53. 35 4
      components/esp32/include/soc/io_mux_reg.h
  54. 1 0
      components/esp32/include/soc/soc.h
  55. 3 1
      components/esp32/include/soc/uart_reg.h
  56. 32 28
      components/esp32/int_wdt.c
  57. 1 1
      components/esp32/lib
  58. 64 0
      components/esp32/phy.h
  59. 224 0
      components/esp32/phy_init.c
  60. 139 0
      components/esp32/phy_init_data.h
  61. 54 15
      components/esp32/task_wdt.c
  62. 29 7
      components/esptool_py/Makefile.projbuild
  63. 1 1
      components/esptool_py/esptool
  64. 0 6
      components/expat/component.mk
  65. 32 31
      components/expat/port/minicheck.c
  66. 29 0
      components/freertos/Kconfig
  67. 0 1
      components/freertos/component.mk
  68. 2 8
      components/freertos/include/freertos/FreeRTOSConfig.h
  69. 45 5
      components/freertos/include/freertos/ringbuf.h
  70. 8 4
      components/freertos/include/freertos/xtensa_api.h
  71. 0 5
      components/freertos/readme_smp.txt
  72. 272 88
      components/freertos/ringbuf.c
  73. 15 9
      components/freertos/tasks.c
  74. 9 2
      components/freertos/xtensa_intr.c
  75. 21 2
      components/freertos/xtensa_intr_asm.S
  76. 26 0
      components/freertos/xtensa_vectors.S
  77. 0 6
      components/json/component.mk
  78. 4 2
      components/log/component.mk
  79. 4 0
      components/log/include/esp_log.h
  80. 16 0
      components/lwip/Kconfig
  81. 0 1
      components/lwip/component.mk
  82. 7 0
      components/lwip/include/lwip/lwip/opt.h
  83. 1 0
      components/lwip/include/lwip/port/lwipopts.h
  84. 18 21
      components/lwip/port/netif/wlanif.c
  85. 36 1
      components/mbedtls/Kconfig
  86. 0 1
      components/mbedtls/component.mk
  87. 7 1
      components/mbedtls/library/bignum.c
  88. 410 396
      components/mbedtls/port/esp_bignum.c
  89. 1 2
      components/mbedtls/port/include/aes_alt.h
  90. 78 0
      components/mbedtls/port/include/mbedtls/bignum.h
  91. 6 4
      components/mbedtls/port/include/mbedtls/esp_config.h
  92. 13 4
      components/mbedtls/port/include/sha1_alt.h
  93. 14 6
      components/mbedtls/port/include/sha256_alt.h
  94. 14 7
      components/mbedtls/port/include/sha512_alt.h
  95. 8 0
      components/micro-ecc/component.mk
  96. 1 0
      components/micro-ecc/micro-ecc
  97. 1 2
      components/newlib/component.mk
  98. 0 2
      components/nghttp/component.mk
  99. 0 1
      components/nvs_flash/component.mk
  100. 84 21
      components/nvs_flash/include/nvs.h

+ 5 - 0
.gitignore

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

+ 6 - 5
.gitlab-ci.yml

@@ -63,10 +63,7 @@ build_ssc:
   <<: *build_template
   artifacts:
     paths:
-      - ./SSC/build/*.bin
-      - ./SSC/build/*.elf
-      - ./SSC/build/*.map
-      - ./SSC/build/bootloader/*.bin
+      - ./SSC/ssc_bin
     expire_in: 6 mos
 
   script:
@@ -118,6 +115,9 @@ build_docs:
     - build_docs
   script:
     - cd docs
+    - doxygen
+    # If not building master branch, and there are Doxygen warnings, print them and bail out
+    - test "${CI_BUILD_REF_NAME}" = "master" || test $(cat doxygen-warning-log.txt | wc -l) -eq 0 || ( echo "Doxygen pass had some warnings:" && cat doxygen-warning-log.txt && false )
     - make html
   artifacts:
     paths:
@@ -159,6 +159,7 @@ test_report:
     when: always
     paths:
       - $REPORT_PATH
+      - $LOG_PATH
     expire_in: 12 mos
   script:
     # clone test bench
@@ -229,7 +230,7 @@ deploy_docs:
   variables:
     # LOCAL_ENV_CONFIG_PATH: define in template and jobs can overwrite if required
     LOCAL_ENV_CONFIG_PATH: /home/gitlab-runner/LocalConfig/ESP32_IDF
-    BIN_PATH: "$CI_PROJECT_DIR/SSC/build/"
+    BIN_PATH: "$CI_PROJECT_DIR/SSC/ssc_bin/SSC"
     APP_NAME: "ssc"
     LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF"
     # append test level folder to TEST_CASE_FILE_PATH in before_script of test job

+ 3 - 0
.gitmodules

@@ -7,3 +7,6 @@
 [submodule "components/bt/lib"]
 	path = components/bt/lib
 	url = https://github.com/espressif/esp32-bt-lib.git
+[submodule "components/micro-ecc/micro-ecc"]
+	path = components/micro-ecc/micro-ecc
+	url = https://github.com/kmackay/micro-ecc.git

+ 2 - 1
CONTRIBUTING.rst

@@ -39,6 +39,7 @@ If this process passes, it will be merged onto the public github repository.
 Legal Part
 ----------
 
-Before a contribution can be accepted, you will need to sign our `Contributor Agreement <http://esp-idf.readthedocs.io/en/latest/contributing.html>`_. You will be prompted for this automatically as part of the Pull Request process.
+Before a contribution can be accepted, you will need to sign our :doc:`contributor-agreement`. You will be prompted for this automatically as part of the Pull Request process.
+
 
 

+ 94 - 7
components/bootloader/Kconfig.projbuild

@@ -20,12 +20,99 @@ config LOG_BOOTLOADER_LEVEL_VERBOSE
 endchoice
 
 config LOG_BOOTLOADER_LEVEL
-	int
-	default 0 if LOG_BOOTLOADER_LEVEL_NONE
-	default 1 if LOG_BOOTLOADER_LEVEL_ERROR
-	default 2 if LOG_BOOTLOADER_LEVEL_WARN
-	default 3 if LOG_BOOTLOADER_LEVEL_INFO
-	default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
-	default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
+    int
+    default 0 if LOG_BOOTLOADER_LEVEL_NONE
+    default 1 if LOG_BOOTLOADER_LEVEL_ERROR
+    default 2 if LOG_BOOTLOADER_LEVEL_WARN
+    default 3 if LOG_BOOTLOADER_LEVEL_INFO
+    default 4 if LOG_BOOTLOADER_LEVEL_DEBUG
+    default 5 if LOG_BOOTLOADER_LEVEL_VERBOSE
 
 endmenu
+
+
+
+menu "Secure boot configuration"
+
+choice SECURE_BOOTLOADER
+    bool "Secure bootloader"
+    default SECURE_BOOTLOADER_DISABLED
+    help
+        Build a bootloader with the secure boot flag enabled.
+
+        Secure bootloader can be one-time-flash (chip will only ever
+        boot that particular bootloader), or a digest key can be used
+        to allow the secure bootloader to be re-flashed with
+        modifications. Secure boot also permanently disables JTAG.
+
+        See docs/security/secure-boot.rst for details.
+
+config SECURE_BOOTLOADER_DISABLED
+       bool "Disabled"
+
+config SECURE_BOOTLOADER_ONE_TIME_FLASH
+       bool "One-time flash"
+       help
+           On first boot, the bootloader will generate a key which is not readable externally or by software. A digest is generated from the bootloader image itself. This digest will be verified on each subsequent boot.
+
+           Enabling this option means that the bootloader cannot be changed after the first time it is booted.
+
+config SECURE_BOOTLOADER_REFLASHABLE
+    bool "Reflashable"
+    help
+        Generate a reusable secure bootloader key, derived (via SHA-256) from the secure boot signing key.
+
+		This allows the secure bootloader to be re-flashed by anyone with access to the secure boot signing key.
+
+        This option is less secure than one-time flash, because a leak of the digest key from one device allows reflashing of any device that uses it.
+
+endchoice
+
+config SECURE_BOOT_SIGNING_KEY
+     string "Secure boot signing key"
+	 depends on SECURE_BOOTLOADER_ENABLED
+	 default secure_boot_signing_key.pem
+     help
+        Path to the key file used to sign partition tables and app images for secure boot.
+
+        Key file is an ECDSA private key (NIST256p curve) in PEM format.
+
+        Path is evaluated relative to the project directory.
+
+        You can generate a new signing key by running the following command:
+        espsecure.py generate_signing_key secure_boot_signing_key.pem
+
+        See docs/security/secure-boot.rst for details.
+
+config SECURE_BOOT_DISABLE_JTAG
+       bool "First boot: Permanently disable JTAG"
+       depends on SECURE_BOOTLOADER_ENABLED
+       default Y
+       help
+          Bootloader permanently disable JTAG (across entire chip) when enabling secure boot. This happens on first boot of the bootloader.
+
+          It is recommended this option remains set for production environments.
+
+config SECURE_BOOT_DISABLE_ROM_BASIC
+       bool "First boot: Permanently disable ROM BASIC fallback"
+       depends on SECURE_BOOTLOADER_ENABLED
+       default Y
+       help
+          Bootloader permanently disables ROM BASIC (on UART console) as a fallback if the bootloader image becomes invalid. This happens on first boot.
+
+          It is recommended this option remains set in production environments.
+
+config SECURE_BOOT_TEST_MODE
+       bool "Test mode: don't actually enable secure boot"
+       depends on SECURE_BOOTLOADER_ENABLED
+       default N
+       help
+          If this option is set, all permanent secure boot changes (via Efuse) are disabled.
+
+          This option is for testing purposes only - it effectively completely disables secure boot protection.
+
+config SECURE_BOOTLOADER_ENABLED
+    bool
+    default SECURE_BOOTLOADER_ONE_TIME_FLASH || SECURE_BOOTLOADER_REFLASHABLE
+
+endmenu

+ 83 - 18
components/bootloader/Makefile.projbuild

@@ -13,45 +13,110 @@ ifndef IS_BOOTLOADER_BUILD
 BOOTLOADER_COMPONENT_PATH := $(COMPONENT_PATH)
 BOOTLOADER_BUILD_DIR=$(abspath $(BUILD_DIR_BASE)/bootloader)
 BOOTLOADER_BIN=$(BOOTLOADER_BUILD_DIR)/bootloader.bin
-BOOTLOADER_SDKCONFIG=$(BOOTLOADER_BUILD_DIR)/sdkconfig
+
+# signing key path is resolved relative to the project directory
+SECURE_BOOT_SIGNING_KEY=$(abspath $(call dequote,$(CONFIG_SECURE_BOOT_SIGNING_KEY)))
+export SECURE_BOOT_SIGNING_KEY  # used by bootloader_support component
 
 # Custom recursive make for bootloader sub-project
 BOOTLOADER_MAKE=+$(MAKE) -C $(BOOTLOADER_COMPONENT_PATH)/src \
-	V=$(V) SDKCONFIG=$(BOOTLOADER_SDKCONFIG) \
-	BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR) \
+	V=$(V) BUILD_DIR_BASE=$(BOOTLOADER_BUILD_DIR)
 
 .PHONY: bootloader-clean bootloader-flash bootloader $(BOOTLOADER_BIN)
 
-$(BOOTLOADER_BIN): | $(BOOTLOADER_BUILD_DIR)/sdkconfig
-	$(Q) $(BOOTLOADER_MAKE) $@
-
-bootloader-clean:
-	$(Q) $(BOOTLOADER_MAKE) app-clean config-clean
-	$(Q) rm -f $(BOOTLOADER_SDKCONFIG) $(BOOTLOADER_SDKCONFIG).old
+$(BOOTLOADER_BIN): $(SDKCONFIG_MAKEFILE)
+	$(BOOTLOADER_MAKE) $@
 
 clean: bootloader-clean
 
+ifdef CONFIG_SECURE_BOOTLOADER_DISABLED
+# If secure boot disabled, bootloader flashing is integrated
+# with 'make flash' and no warnings are printed.
+
 bootloader: $(BOOTLOADER_BIN)
+	@echo $(SEPARATOR)
 	@echo "Bootloader built. Default flash command is:"
 	@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^"
 
-all_binaries: $(BOOTLOADER_BIN)
-
 ESPTOOL_ALL_FLASH_ARGS += 0x1000 $(BOOTLOADER_BIN)
 
-# bootloader-flash calls flash in the bootloader dummy project
 bootloader-flash: $(BOOTLOADER_BIN)
 	$(ESPTOOLPY_WRITE_FLASH) 0x1000 $^
 
-# synchronise the project level config to the bootloader's
-# config
-$(BOOTLOADER_SDKCONFIG): $(PROJECT_PATH)/sdkconfig | $(BOOTLOADER_BUILD_DIR)
-	$(Q) cp $< $@
+else ifdef CONFIG_SECURE_BOOTLOADER_ONE_TIME_FLASH
+
+#### TEMPORARILY DISABLE THIS OPTION
+ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
+bootloader:
+	@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device"
+	@echo "If you flash this bootloader, you will be left with an non-updateable bootloader that is missing features."
+	@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
+	exit 1
+else
+
+# One time flashing requires user to run esptool.py command themselves,
+# and warning is printed about inability to reflash.
+
+bootloader: $(BOOTLOADER_BIN)
+	@echo $(SEPARATOR)
+	@echo "Bootloader built. One-time flash command is:"
+	@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
+	@echo $(SEPARATOR)
+	@echo "* IMPORTANT: After first boot, BOOTLOADER CANNOT BE RE-FLASHED on same device"
+
+endif # IDF_INSECURE_SECURE_BOOT
+else ifdef CONFIG_SECURE_BOOTLOADER_REFLASHABLE
+# Reflashable secure bootloader
+# generates a digest binary (bootloader + digest)
+
+#### TEMPORARILY DISABLE THIS OPTION
+ifneq ("$(IDF_INSECURE_SECURE_BOOT)","1")
+bootloader:
+	@echo "Secure boot features are not yet mature, so the current secure bootloader will not properly secure the device."
+	@echo "If using this feature, expect to reflash the bootloader at least one more time."
+	@echo "If you really want to do this, set the environment variable IDF_INSECURE_SECURE_BOOT=1 and rerun make."
+	exit 1
+else
+
+BOOTLOADER_DIGEST_BIN := $(BOOTLOADER_BUILD_DIR)/bootloader-reflash-digest.bin
+SECURE_BOOTLOADER_KEY := $(BOOTLOADER_BUILD_DIR)/secure-bootloader-key.bin
+
+$(SECURE_BOOTLOADER_KEY): $(SECURE_BOOT_SIGNING_KEY)
+	$(Q) $(ESPSECUREPY) digest_private_key -k $< $@
+
+bootloader: $(BOOTLOADER_DIGEST_BIN)
+	@echo $(SEPARATOR)
+	@echo "Bootloader built and secure digest generated. First time flash command is:"
+	@echo "$(ESPEFUSEPY) burn_key secure_boot $(SECURE_BOOTLOADER_KEY)"
+	@echo "$(ESPTOOLPY_WRITE_FLASH) 0x1000 $(BOOTLOADER_BIN)"
+	@echo $(SEPARATOR)
+	@echo "To reflash the bootloader after initial flash:"
+	@echo "$(ESPTOOLPY_WRITE_FLASH) 0x0 $(BOOTLOADER_DIGEST_BIN)"
+	@echo $(SEPARATOR)
+	@echo "* After first boot, only re-flashes of this kind (with same key) will be accepted."
+	@echo "* Not recommended to re-use the same secure boot keyfile on multiple production devices."
+
+$(BOOTLOADER_DIGEST_BIN): $(BOOTLOADER_BIN) $(SECURE_BOOTLOADER_KEY)
+	@echo "DIGEST $(notdir $@)"
+	$(Q) $(ESPSECUREPY) digest_secure_bootloader -k $(SECURE_BOOTLOADER_KEY) -o $@ $<
+
+endif # IDF_INSECURE_SECURE_BOOT
+else
+bootloader:
+	@echo "Invalid bootloader target: bad sdkconfig?"
+	@exit 1
+endif
+
+all_binaries: $(BOOTLOADER_BIN)
+
+bootloader-clean:
+	$(BOOTLOADER_MAKE) app-clean
+	rm -f $(SECURE_BOOTLOADER_KEY) $(BOOTLOADER_DIGEST_BIN)
 
 $(BOOTLOADER_BUILD_DIR):
-	$(Q) mkdir -p $@
+	mkdir -p $@
 
 else
-CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include 
+CFLAGS += -D BOOTLOADER_BUILD=1 -I $(IDF_PATH)/components/esp32/include
 
 endif

+ 6 - 3
components/bootloader/src/Makefile

@@ -4,7 +4,10 @@
 #
 
 PROJECT_NAME := bootloader
-COMPONENTS := esptool_py bootloader log spi_flash
+
+#We cannot include the esp32 component directly but we need its includes.
+#This is fixed by adding CFLAGS from Makefile.projbuild
+COMPONENTS := esptool_py bootloader bootloader_support log spi_flash micro-ecc
 
 # The bootloader pseudo-component is also included in this build, for its Kconfig.projbuild to be included.
 #
@@ -12,7 +15,7 @@ COMPONENTS := esptool_py bootloader log spi_flash
 IS_BOOTLOADER_BUILD := 1
 export IS_BOOTLOADER_BUILD
 
-#We cannot include the esp32 component directly but we need its includes. 
-#This is fixed by adding CFLAGS from Makefile.projbuild
+# include the top-level "project" include directory, for sdkconfig.h
+CFLAGS += -I$(BUILD_DIR_BASE)/../include
 
 include $(IDF_PATH)/make/project.mk

+ 0 - 8
components/bootloader/src/main/bootloader_config.h

@@ -25,8 +25,6 @@ extern "C"
 
 #define BOOT_VERSION "V0.1"
 #define SPI_SEC_SIZE 0x1000
-#define MEM_CACHE(offset)   (uint8_t *)(0x3f400000 + (offset))
-#define CACHE_READ_32(offset)   ((uint32_t *)(0x3f400000 + (offset)))
 #define IROM_LOW    0x400D0000
 #define IROM_HIGH   0x40400000
 #define DROM_LOW    0x3F400000
@@ -36,7 +34,6 @@ extern "C"
 #define RTC_DATA_LOW  0x50000000
 #define RTC_DATA_HIGH 0x50002000
 
-
 #define PART_TYPE_APP 0x00
 #define PART_SUBTYPE_FACTORY  0x00
 #define PART_SUBTYPE_OTA_FLAG 0x10
@@ -62,12 +59,7 @@ typedef struct {
     uint32_t selected_subtype;
 } bootloader_state_t;
 
-void boot_cache_redirect( uint32_t pos, size_t size );
-uint32_t get_bin_len(uint32_t pos);
-
 bool flash_encrypt(bootloader_state_t *bs);
-bool secure_boot(void);
-
 
 #ifdef __cplusplus
 }

+ 179 - 160
components/bootloader/src/main/bootloader_start.c

@@ -33,6 +33,9 @@
 #include "soc/timer_group_reg.h"
 
 #include "sdkconfig.h"
+#include "esp_image_format.h"
+#include "esp_secure_boot.h"
+#include "bootloader_flash.h"
 
 #include "bootloader_config.h"
 
@@ -49,7 +52,7 @@ flash cache is down and the app CPU is in reset. We do have a stack, so we can d
 extern void Cache_Flush(int);
 
 void bootloader_main();
-void unpack_load_app(const esp_partition_pos_t *app_node);
+static void unpack_load_app(const esp_partition_pos_t *app_node);
 void print_flash_info(const esp_image_header_t* pfhdr);
 void set_cache_and_start_app(uint32_t drom_addr,
     uint32_t drom_load_addr,
@@ -94,53 +97,6 @@ void IRAM_ATTR call_start_cpu0()
     bootloader_main();
 }
 
-/**
- *  @function :     get_bin_len
- *  @description:   get bin's length 
- *
- *  @inputs:        pos     bin locate address in flash
- *  @return:        uint32  length of bin,if bin MAGIC error return 0
- */
-
-uint32_t get_bin_len(uint32_t pos)
-{   
-    uint32_t len = 8 + 16;
-    uint8_t i;
-    ESP_LOGD(TAG, "pos %d %x",pos,*(uint8_t *)pos);
-    if(0xE9 != *(uint8_t *)pos) {
-        return 0;
-    }
-    for (i = 0; i < *(uint8_t *)(pos + 1); i++) {
-        len += *(uint32_t *)(pos + len + 4) + 8;
-    }
-    if (len % 16 != 0) {
-        len = (len / 16 + 1) * 16;
-    } else {
-        len += 16;
-    }
-    ESP_LOGD(TAG, "bin length = %d", len);
-    return len;
-}
-
-/** 
- *  @function :     boot_cache_redirect
- *  @description:   Configure several pages in flash map so that `size` bytes 
- *                  starting at `pos` are mapped to 0x3f400000.
- *                  This sets up mapping only for PRO CPU.
- *
- *  @inputs:        pos     address in flash
- *                  size    size of the area to map, in bytes
- */
-void boot_cache_redirect( uint32_t pos, size_t size )
-{
-    uint32_t pos_aligned = pos & 0xffff0000;
-    uint32_t count = (size + 0xffff) / 0x10000;
-    Cache_Read_Disable( 0 );
-    Cache_Flush( 0 );
-    ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", pos_aligned, count );
-    cache_flash_mmu_set( 0, 0, 0x3f400000, pos_aligned, 64, count );
-    Cache_Read_Enable( 0 );
-}
 
 /**
  *  @function :     load_partition_table
@@ -148,85 +104,103 @@ void boot_cache_redirect( uint32_t pos, size_t size )
  *                  OTA info sector, factory app sector, and test app sector.
  *
  *  @inputs:        bs     bootloader state structure used to save the data
- *                  addr   address of partition table in flash
  *  @return:        return true, if the partition table is loaded (and MD5 checksum is valid)
  *
  */
-bool load_partition_table(bootloader_state_t* bs, uint32_t addr)
+bool load_partition_table(bootloader_state_t* bs)
 {
-    esp_partition_info_t partition;
-    uint32_t end = addr + 0x1000;
-    int index = 0;
+    const esp_partition_info_t *partitions;
+    const int ESP_PARTITION_TABLE_DATA_LEN = 0xC00; /* length of actual data (signature is appended to this) */
+    const int MAX_PARTITIONS = ESP_PARTITION_TABLE_DATA_LEN / sizeof(esp_partition_info_t);
     char *partition_usage;
 
     ESP_LOGI(TAG, "Partition Table:");
     ESP_LOGI(TAG, "## Label            Usage          Type ST Offset   Length");
 
-    while (addr < end) {
-        ESP_LOGD(TAG, "load partition table entry from %x(%08x)", addr, MEM_CACHE(addr));
-        memcpy(&partition, MEM_CACHE(addr), sizeof(partition));
-        ESP_LOGD(TAG, "type=%x subtype=%x", partition.type, partition.subtype);
+#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+    if(esp_secure_boot_enabled()) {
+        ESP_LOGI(TAG, "Verifying partition table signature...");
+        esp_err_t err = esp_secure_boot_verify_signature(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "Failed to verify partition table signature.");
+            return false;
+        }
+        ESP_LOGD(TAG, "Partition table signature verified");
+    }
+#endif
+
+    partitions = bootloader_mmap(ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+    if (!partitions) {
+            ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_ADDR, ESP_PARTITION_TABLE_DATA_LEN);
+            return false;
+    }
+    ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_ADDR, (intptr_t)partitions);
+
+    for(int i = 0; i < MAX_PARTITIONS; i++) {
+        const esp_partition_info_t *partition = &partitions[i];
+        ESP_LOGD(TAG, "load partition table entry 0x%x", (intptr_t)partition);
+        ESP_LOGD(TAG, "type=%x subtype=%x", partition->type, partition->subtype);
         partition_usage = "unknown";
 
-        if (partition.magic == ESP_PARTITION_MAGIC) { /* valid partition definition */
-            switch(partition.type) {
-            case PART_TYPE_APP: /* app partition */
-                switch(partition.subtype) {
-                case PART_SUBTYPE_FACTORY: /* factory binary */
-                    bs->factory = partition.pos;
-                    partition_usage = "factory app";
-                    break;
-                case PART_SUBTYPE_TEST: /* test binary */
-                    bs->test = partition.pos;
-                    partition_usage = "test app";
-                    break;
-                default:
-                    /* OTA binary */
-                    if ((partition.subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
-                        bs->ota[partition.subtype & PART_SUBTYPE_OTA_MASK] = partition.pos;
-                        ++bs->app_count;
-                        partition_usage = "OTA app";
-                    }
-                    else {
-                        partition_usage = "Unknown app";
-                    }
-                    break;
+        if (partition->magic != ESP_PARTITION_MAGIC) {
+            /* invalid partition definition indicates end-of-table */
+            break;
+        }
+
+        /* valid partition table */
+        switch(partition->type) {
+        case PART_TYPE_APP: /* app partition */
+            switch(partition->subtype) {
+            case PART_SUBTYPE_FACTORY: /* factory binary */
+                bs->factory = partition->pos;
+                partition_usage = "factory app";
+                break;
+            case PART_SUBTYPE_TEST: /* test binary */
+                bs->test = partition->pos;
+                partition_usage = "test app";
+                break;
+            default:
+                /* OTA binary */
+                if ((partition->subtype & ~PART_SUBTYPE_OTA_MASK) == PART_SUBTYPE_OTA_FLAG) {
+                    bs->ota[partition->subtype & PART_SUBTYPE_OTA_MASK] = partition->pos;
+                    ++bs->app_count;
+                    partition_usage = "OTA app";
                 }
-                break; /* PART_TYPE_APP */
-            case PART_TYPE_DATA: /* data partition */
-                switch(partition.subtype) {
-                case PART_SUBTYPE_DATA_OTA: /* ota data */
-                    bs->ota_info = partition.pos;
-                    partition_usage = "OTA data";
-                    break;
-                case PART_SUBTYPE_DATA_RF:
-                    partition_usage = "RF data";
-                    break;
-                case PART_SUBTYPE_DATA_WIFI:
-                    partition_usage = "WiFi data";
-                    break;
-                default:
-                    partition_usage = "Unknown data";
-                    break;
+                else {
+                    partition_usage = "Unknown app";
                 }
-                break; /* PARTITION_USAGE_DATA */
-            default: /* other partition type */
                 break;
             }
-        }
-        /* invalid partition magic number */
-        else {
-            break; /* todo: validate md5 */
+            break; /* PART_TYPE_APP */
+        case PART_TYPE_DATA: /* data partition */
+            switch(partition->subtype) {
+            case PART_SUBTYPE_DATA_OTA: /* ota data */
+                bs->ota_info = partition->pos;
+                partition_usage = "OTA data";
+                break;
+            case PART_SUBTYPE_DATA_RF:
+                partition_usage = "RF data";
+                break;
+            case PART_SUBTYPE_DATA_WIFI:
+                partition_usage = "WiFi data";
+                break;
+            default:
+                partition_usage = "Unknown data";
+                break;
+            }
+            break; /* PARTITION_USAGE_DATA */
+        default: /* other partition type */
+            break;
         }
 
         /* print partition type info */
-        ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", index, partition.label, partition_usage,
-                 partition.type, partition.subtype,
-                 partition.pos.offset, partition.pos.size);
-        index++;
-        addr += sizeof(partition);
+        ESP_LOGI(TAG, "%2d %-16s %-16s %02x %02x %08x %08x", i, partition->label, partition_usage,
+                 partition->type, partition->subtype,
+                 partition->pos.offset, partition->pos.size);
     }
 
+    bootloader_munmap(partitions);
+
     ESP_LOGI(TAG,"End of partition table");
     return true;
 }
@@ -254,8 +228,10 @@ void bootloader_main()
 
     esp_image_header_t fhdr;
     bootloader_state_t bs;
-    SpiFlashOpResult spiRet1,spiRet2;    
+    SpiFlashOpResult spiRet1,spiRet2;
     esp_ota_select_entry_t sa,sb;
+    const esp_ota_select_entry_t *ota_select_map;
+
     memset(&bs, 0, sizeof(bs));
 
     ESP_LOGI(TAG, "compile time " __TIME__ );
@@ -263,16 +239,17 @@ void bootloader_main()
     REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN );
     REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
     SPIUnlock();
-    /*register first sector in drom0 page 0 */
-    boot_cache_redirect( 0, 0x5000 );
 
-    memcpy((unsigned int *) &fhdr, MEM_CACHE(0x1000), sizeof(esp_image_header_t) );
+    if(esp_image_load_header(0x1000, &fhdr) != ESP_OK) {
+        ESP_LOGE(TAG, "failed to load bootloader header!");
+        return;
+    }
 
     print_flash_info(&fhdr);
 
     update_flash_config(&fhdr);
 
-    if (!load_partition_table(&bs, ESP_PARTITION_TABLE_ADDR)) {
+    if (!load_partition_table(&bs)) {
         ESP_LOGE(TAG, "load partition table error!");
         return;
     }
@@ -281,9 +258,19 @@ void bootloader_main()
 
     if (bs.ota_info.offset != 0) {              // check if partition table has OTA info partition
         //ESP_LOGE("OTA info sector handling is not implemented");
-        boot_cache_redirect(bs.ota_info.offset, bs.ota_info.size );
-        memcpy(&sa,MEM_CACHE(bs.ota_info.offset & 0x0000ffff),sizeof(sa));
-        memcpy(&sb,MEM_CACHE((bs.ota_info.offset + 0x1000)&0x0000ffff) ,sizeof(sb));
+        if (bs.ota_info.size < 2 * sizeof(esp_ota_select_entry_t)) {
+            ESP_LOGE(TAG, "ERROR: ota_info partition size %d is too small (minimum %d bytes)", bs.ota_info.size, sizeof(esp_ota_select_entry_t));
+            return;
+        }
+        ota_select_map = bootloader_mmap(bs.ota_info.offset, bs.ota_info.size);
+        if (!ota_select_map) {
+            ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", bs.ota_info.offset, bs.ota_info.size);
+            return;
+        }
+        sa = ota_select_map[0];
+        sb = ota_select_map[1];
+        bootloader_munmap(ota_select_map);
+
         if(sa.ota_seq == 0xFFFFFFFF && sb.ota_seq == 0xFFFFFFFF) {
             // init status flash
             load_part_pos = bs.ota[0];
@@ -329,35 +316,61 @@ void bootloader_main()
     }
 
     ESP_LOGI(TAG, "Loading app partition at offset %08x", load_part_pos);
-    if(fhdr.secure_boot_flag == 0x01) {
-        /* protect the 2nd_boot  */    
-        if(false == secure_boot()){
-            ESP_LOGE(TAG, "secure boot failed");
-            return;
-        }
+
+#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+    /* Generate secure digest from this bootloader to protect future
+       modifications */
+    esp_err_t err = esp_secure_boot_permanently_enable();
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Bootloader digest generation failed (%d). SECURE BOOT IS NOT ENABLED.", err);
+        /* Allow booting to continue, as the failure is probably
+           due to user-configured EFUSEs for testing...
+        */
     }
+#endif
 
     if(fhdr.encrypt_flag == 0x01) {
-        /* encrypt flash */            
+        /* encrypt flash */
         if (false == flash_encrypt(&bs)) {
            ESP_LOGE(TAG, "flash encrypt failed");
            return;
         }
     }
 
-    // copy sections to RAM, set up caches, and start application
+    // copy loaded segments to RAM, set up caches for mapped segments, and start application
     unpack_load_app(&load_part_pos);
 }
 
 
-void unpack_load_app(const esp_partition_pos_t* partition)
+static void unpack_load_app(const esp_partition_pos_t* partition)
 {
-    boot_cache_redirect(partition->offset, partition->size);
-
-    uint32_t pos = 0;
+    esp_err_t err;
     esp_image_header_t image_header;
-    memcpy(&image_header, MEM_CACHE(pos), sizeof(image_header));
-    pos += sizeof(image_header);
+    uint32_t image_length;
+
+    /* TODO: verify the app image as part of OTA boot decision, so can have fallbacks */
+    err = esp_image_basic_verify(partition->offset, &image_length);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to verify app image @ 0x%x (%d)", partition->offset, err);
+        return;
+    }
+
+#ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+    if (esp_secure_boot_enabled()) {
+        ESP_LOGI(TAG, "Verifying app signature @ 0x%x (length 0x%x)", partition->offset, image_length);
+        err = esp_secure_boot_verify_signature(partition->offset, image_length);
+        if (err != ESP_OK) {
+            ESP_LOGE(TAG, "App image @ 0x%x failed signature verification (%d)", partition->offset, err);
+            return;
+        }
+        ESP_LOGD(TAG, "App signature is valid");
+    }
+#endif
+
+    if (esp_image_load_header(partition->offset, &image_header) != ESP_OK) {
+        ESP_LOGE(TAG, "Failed to load app image header @ 0x%x", partition->offset);
+        return;
+    }
 
     uint32_t drom_addr = 0;
     uint32_t drom_load_addr = 0;
@@ -366,24 +379,27 @@ void unpack_load_app(const esp_partition_pos_t* partition)
     uint32_t irom_load_addr = 0;
     uint32_t irom_size = 0;
 
-    /* Reload the RTC memory sections whenever a non-deepsleep reset
+    /* Reload the RTC memory segments whenever a non-deepsleep reset
        is occurring */
     bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
 
     ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
-             image_header.blocks,
+             image_header.segment_count,
              image_header.spi_mode,
              image_header.spi_size,
              (unsigned)image_header.entry_addr);
 
-    for (uint32_t section_index = 0;
-            section_index < image_header.blocks;
-            ++section_index) {
-        esp_image_section_header_t section_header = {0};
-        memcpy(&section_header, MEM_CACHE(pos), sizeof(section_header));
-        pos += sizeof(section_header);
+    for (int segment = 0; segment < image_header.segment_count; segment++) {
+        esp_image_segment_header_t segment_header;
+        uint32_t data_offs;
+        if(esp_image_load_segment_header(segment, partition->offset,
+                                         &image_header, &segment_header,
+                                         &data_offs) != ESP_OK) {
+            ESP_LOGE(TAG, "failed to load segment header #%d", segment);
+            return;
+        }
 
-        const uint32_t address = section_header.load_addr;
+        const uint32_t address = segment_header.load_addr;
         bool load = true;
         bool map = false;
         if (address == 0x00000000) {        // padding, ignore block
@@ -395,47 +411,50 @@ void unpack_load_app(const esp_partition_pos_t* partition)
         }
 
         if (address >= DROM_LOW && address < DROM_HIGH) {
-            ESP_LOGD(TAG, "found drom section, map from %08x to %08x", pos,
-                      section_header.load_addr);
-            drom_addr = partition->offset + pos - sizeof(section_header);
-            drom_load_addr = section_header.load_addr;
-            drom_size = section_header.data_len + sizeof(section_header);
+            ESP_LOGD(TAG, "found drom segment, map from %08x to %08x", data_offs,
+                      segment_header.load_addr);
+            drom_addr = data_offs;
+            drom_load_addr = segment_header.load_addr;
+            drom_size = segment_header.data_len + sizeof(segment_header);
             load = false;
             map = true;
         }
 
         if (address >= IROM_LOW && address < IROM_HIGH) {
-            ESP_LOGD(TAG, "found irom section, map from %08x to %08x", pos,
-                      section_header.load_addr);
-            irom_addr = partition->offset + pos - sizeof(section_header);
-            irom_load_addr = section_header.load_addr;
-            irom_size = section_header.data_len + sizeof(section_header);
+            ESP_LOGD(TAG, "found irom segment, map from %08x to %08x", data_offs,
+                      segment_header.load_addr);
+            irom_addr = data_offs;
+            irom_load_addr = segment_header.load_addr;
+            irom_size = segment_header.data_len + sizeof(segment_header);
             load = false;
             map = true;
         }
 
         if (!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
-            ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos);
+            ESP_LOGD(TAG, "Skipping RTC code segment at %08x\n", data_offs);
             load = false;
         }
 
         if (!load_rtc_memory && address >= RTC_DATA_LOW && address < RTC_DATA_HIGH) {
-            ESP_LOGD(TAG, "Skipping RTC data section at %08x\n", pos);
+            ESP_LOGD(TAG, "Skipping RTC data segment at %08x\n", data_offs);
             load = false;
         }
 
-        ESP_LOGI(TAG, "section %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", section_index, pos,
-                 section_header.load_addr, section_header.data_len, section_header.data_len, (load)?"load":(map)?"map":"");
+        ESP_LOGI(TAG, "segment %d: paddr=0x%08x vaddr=0x%08x size=0x%05x (%6d) %s", segment, data_offs - sizeof(esp_image_segment_header_t),
+                 segment_header.load_addr, segment_header.data_len, segment_header.data_len, (load)?"load":(map)?"map":"");
 
-        if (!load) {
-            pos += section_header.data_len;
-            continue;
+        if (load) {
+            const void *data = bootloader_mmap(data_offs, segment_header.data_len);
+            if(!data) {
+                ESP_LOGE(TAG, "bootloader_mmap(0x%xc, 0x%x) failed",
+                         data_offs, segment_header.data_len);
+                return;
+            }
+            memcpy((void *)segment_header.load_addr, data, segment_header.data_len);
+            bootloader_munmap(data);
         }
-
-        memcpy((void*) section_header.load_addr, MEM_CACHE(pos), section_header.data_len);
-        pos += section_header.data_len;
     }
-    
+
     set_cache_and_start_app(drom_addr,
         drom_load_addr,
         drom_size,
@@ -520,7 +539,7 @@ void print_flash_info(const esp_image_header_t* phdr)
 #if (BOOT_LOG_LEVEL >= BOOT_LOG_LEVEL_NOTICE)
 
     ESP_LOGD(TAG, "magic %02x", phdr->magic );
-    ESP_LOGD(TAG, "blocks %02x", phdr->blocks );
+    ESP_LOGD(TAG, "segments %02x", phdr->segment_count );
     ESP_LOGD(TAG, "spi_mode %02x", phdr->spi_mode );
     ESP_LOGD(TAG, "spi_speed %02x", phdr->spi_speed );
     ESP_LOGD(TAG, "spi_size %02x", phdr->spi_size );

+ 4 - 7
components/bootloader/src/main/component.mk

@@ -1,12 +1,9 @@
 #
-# Main Makefile. This is basically the same as a component makefile.
+# Main bootloader Makefile.
 #
-# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, 
-# this will take the sources in the src/ directory, compile them and link them into 
-# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
-# please read the esp-idf build system document if you need to do this.
+# This is basically the same as a component makefile, but in the case of the bootloader
+# we pull in bootloader-specific linker arguments.
 #
 
-COMPONENT_ADD_LDFLAGS := -L $(abspath .) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld 
+COMPONENT_ADD_LDFLAGS := -L $(COMPONENT_PATH) -lmain -T esp32.bootloader.ld -T $(IDF_PATH)/components/esp32/ld/esp32.rom.ld
 
-include $(IDF_PATH)/make/component_common.mk

+ 78 - 82
components/bootloader/src/main/flash_encrypt.c

@@ -17,6 +17,7 @@
 #include "esp_types.h"
 #include "esp_attr.h"
 #include "esp_log.h"
+#include "esp_err.h"
 
 #include "rom/cache.h"
 #include "rom/ets_sys.h"
@@ -30,6 +31,7 @@
 #include "sdkconfig.h"
 
 #include "bootloader_config.h"
+#include "esp_image_format.h"
 
 static const char* TAG = "flash_encrypt";
 
@@ -90,103 +92,97 @@ bool flash_encrypt_write(uint32_t pos, uint32_t len)
    Cache_Read_Enable(0); 
    return true;
 }
+
+
 /**
  *  @function :     flash_encrypt
  *  @description:   encrypt 2nd boot ,partition table ,factory bin ��test bin (if use)��ota bin
  *                  ��OTA info sector.
  *
  *  @inputs:        bs     bootloader state structure used to save the data
- *                 
+ *
  *  @return:        return true, if the encrypt flash success
- *                  
+ *
  */
 bool flash_encrypt(bootloader_state_t *bs)
 {
-   uint32_t bin_len = 0;
-   uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
-   uint8_t count = bitcount(flash_crypt_cnt);
-   int i = 0;
-   ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
-
-   if ((count % 2) == 0) {    
-       boot_cache_redirect( 0, 64*1024);
-        /* encrypt iv and abstruct */ 
-       if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
-           ESP_LOGE(TAG, "encrypt iv and abstract error");
-           return false;
-       }
+    esp_err_t err;
+    uint32_t image_len = 0;
+    uint32_t flash_crypt_cnt = REG_GET_FIELD(EFUSE_BLK0_RDATA0_REG, EFUSE_FLASH_CRYPT_CNT);
+    uint8_t count = bitcount(flash_crypt_cnt);
+    ESP_LOGD(TAG, "flash encrypt cnt %x, bitcount %d", flash_crypt_cnt, count);
+
+    if ((count % 2) == 0) {
+        /* encrypt iv and abstract */
+        if (false == flash_encrypt_write(0, SPI_SEC_SIZE)) {
+            ESP_LOGE(TAG, "encrypt iv and abstract error");
+            return false;
+        }
+
+        /* encrypt bootloader image */
+        err = esp_image_basic_verify(0x1000, &image_len);
+        if(err == ESP_OK && image_len != 0) {
+            if (false == flash_encrypt_write(0x1000, image_len)) {
+                ESP_LOGE(TAG, "encrypt 2nd boot error");
+                return false;
+            }
+        } else {
+            ESP_LOGE(TAG, "2nd boot len error");
+            return false;
+        }
 
-        /* encrypt write boot bin*/
-       bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
-       if(bin_len != 0) {
-           if (false == flash_encrypt_write(0x1000, bin_len)) {
-               ESP_LOGE(TAG, "encrypt 2nd boot error");
-               return false;
-           }
-       } else {
-           ESP_LOGE(TAG, "2nd boot len error");
-           return false;
-       }
         /* encrypt partition table */
-       if (false ==  flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
-           ESP_LOGE(TAG, "encrypt partition table error");
-           return false;
-       }
+        if (false ==  flash_encrypt_write(ESP_PARTITION_TABLE_ADDR, SPI_SEC_SIZE)) {
+            ESP_LOGE(TAG, "encrypt partition table error");
+            return false;
+        }
 
         /* encrypt write factory bin  */
-       if(bs->factory.offset != 0x00) {
-           ESP_LOGD(TAG, "have factory bin");
-           boot_cache_redirect(bs->factory.offset, bs->factory.size);
-           bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->factory.offset&0xffff));
-           if(bin_len != 0) {           
-               if (false ==  flash_encrypt_write(bs->factory.offset, bin_len)) {
-                   ESP_LOGE(TAG, "encrypt factory bin error");
-                   return false;
-               }
-           }
-       }
+        if(bs->factory.offset != 0 && bs->factory.size != 0) {
+            ESP_LOGD(TAG, "have factory bin");
+            if (false ==  flash_encrypt_write(bs->factory.offset, bs->factory.size)) {
+                ESP_LOGE(TAG, "encrypt factory bin error");
+                return false;
+            }
+        }
+
         /* encrypt write test bin  */
-       if(bs->test.offset != 0x00) {
-           ESP_LOGD(TAG, "have test bin");
-           boot_cache_redirect(bs->test.offset, bs->test.size);
-           bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->test.offset&0xffff));
-           if(bin_len != 0) {
-               if (false ==  flash_encrypt_write(bs->test.offset, bin_len)) {
-                   ESP_LOGE(TAG, "encrypt test bin error");
-                   return false;
-               }
-           }
-       }
+        if(bs->test.offset != 0 && bs->test.size != 0) {
+            ESP_LOGD(TAG, "have test bin");
+            if (false ==  flash_encrypt_write(bs->test.offset, bs->test.size)) {
+                ESP_LOGE(TAG, "encrypt test bin error");
+                return false;
+            }
+        }
+
         /* encrypt write ota bin  */
-       for (i = 0;i<16;i++) {
-           if(bs->ota[i].offset != 0x00) {
-               ESP_LOGD(TAG, "have ota[%d] bin",i);
-               boot_cache_redirect(bs->ota[i].offset, bs->ota[i].size);
-               bin_len = get_bin_len((uint32_t)MEM_CACHE(bs->ota[i].offset&0xffff));
-               if(bin_len != 0) {    
-                   if (false == flash_encrypt_write(bs->ota[i].offset, bin_len)) {
-                       ESP_LOGE(TAG, "encrypt ota bin error");
-                       return false;
-                   }
-               }
-           }
-       }
+        for (int i = 0; i < 16; i++) {
+            if(bs->ota[i].offset != 0 && bs->ota[i].size != 0) {
+                ESP_LOGD(TAG, "have ota[%d] bin",i);
+                if (false == flash_encrypt_write(bs->ota[i].offset, bs->ota[i].size)) {
+                    ESP_LOGE(TAG, "encrypt ota bin error");
+                    return false;
+                }
+            }
+        }
+
         /* encrypt write ota info bin  */
-       if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
-           ESP_LOGE(TAG, "encrypt ota info error");
-           return false;
-       }  
-       REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);   
-       REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */     
-       REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */     
-       while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */
-       ESP_LOGW(TAG, "burn  flash_crypt_cnt");   
-       REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */   
-       REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */     
-       while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */  
-       return true;
-   } else {   
-       ESP_LOGI(TAG, "flash already encrypted.");
-       return true;
-   }
+        if (false == flash_encrypt_write(bs->ota_info.offset, 2*SPI_SEC_SIZE)) {
+            ESP_LOGE(TAG, "encrypt ota info error");
+            return false;
+        }
+
+        REG_SET_FIELD(EFUSE_BLK0_WDATA0_REG, EFUSE_FLASH_CRYPT_CNT, 0x04);
+        REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */
+        REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */
+        while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */
+        ESP_LOGW(TAG, "burn  flash_crypt_cnt");
+        REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */
+        REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */
+        while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */
+        return true;
+    } else {
+        ESP_LOGI(TAG, "flash already encrypted.");
+        return true;
+    }
 }

+ 0 - 127
components/bootloader/src/main/secure_boot.c

@@ -1,127 +0,0 @@
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <string.h>
-
-#include "esp_attr.h"
-#include "esp_types.h"
-#include "esp_log.h"
-
-#include "rom/cache.h"
-#include "rom/ets_sys.h"
-#include "rom/spi_flash.h"
-#include "rom/secure_boot.h"
-
-#include "soc/dport_reg.h"
-#include "soc/io_mux_reg.h"
-#include "soc/efuse_reg.h"
-#include "soc/rtc_cntl_reg.h"
-
-#include "sdkconfig.h"
-
-#include "bootloader_config.h"
-
-static const char* TAG = "secure_boot";
-
-/**
- *  @function :     secure_boot_generate
- *  @description:   generate boot abstract & iv
- *
- *  @inputs:        bool
- */
-bool secure_boot_generate(uint32_t bin_len){
-	SpiFlashOpResult spiRet;
-	uint16_t i;
-	uint32_t buf[32];
-	if (bin_len % 128 != 0) {  
-		bin_len = (bin_len / 128 + 1) * 128; 
-	} 
-	ets_secure_boot_start();
-	ets_secure_boot_rd_iv(buf);
-	ets_secure_boot_hash(NULL);
-	Cache_Read_Disable(0);
-	/* iv stored in sec 0 */ 
-	spiRet = SPIEraseSector(0);
-	if (spiRet != SPI_FLASH_RESULT_OK)
-	{   
-		ESP_LOGE(TAG, SPI_ERROR_LOG);
-		return false;
-	}
-	/* write iv to flash, 0x0000, 128 bytes (1024 bits) */
-	spiRet = SPIWrite(0, buf, 128);
-	if (spiRet != SPI_FLASH_RESULT_OK) 
-	{
-		ESP_LOGE(TAG, SPI_ERROR_LOG);
-		return false;
-	}
-	ESP_LOGD(TAG, "write iv to flash.");
-	Cache_Read_Enable(0);
-	/* read 4K code image from flash, for test */
-	for (i = 0; i < bin_len; i+=128) {
-		ets_secure_boot_hash((uint32_t *)(0x3f400000 + 0x1000 + i));
-	}
-
-	ets_secure_boot_obtain();
-	ets_secure_boot_rd_abstract(buf);
-	ets_secure_boot_finish();
-	Cache_Read_Disable(0);
-	/* write abstract to flash, 0x0080, 64 bytes (512 bits) */
-	spiRet = SPIWrite(0x80, buf, 64);
-	if (spiRet != SPI_FLASH_RESULT_OK) {
-		ESP_LOGE(TAG, SPI_ERROR_LOG);
-		return false;
-	}
-	ESP_LOGD(TAG, "write abstract to flash.");
-	Cache_Read_Enable(0);
-	return true;
-}
-
-
-/**
- *  @function :     secure_boot
- *  @description:   protect boot code in flash
- *
- *  @inputs:        bool
- */
-bool secure_boot(void){ 
-	uint32_t bin_len = 0;
-	if (REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0)
-	{     
-		ESP_LOGD(TAG, "already secure boot !");
-		return true;
-	} else {  
-		boot_cache_redirect( 0, 64*1024);
-		bin_len = get_bin_len((uint32_t)MEM_CACHE(0x1000));
-		if (bin_len == 0) {
-			ESP_LOGE(TAG, "boot len is error");
-			return false;
-		}
-		if (false == secure_boot_generate(bin_len)){
-			ESP_LOGE(TAG, "secure boot generate failed");
-			return false;
-		}  
-	}  
-
-	REG_SET_BIT(EFUSE_BLK0_WDATA6_REG, EFUSE_RD_ABS_DONE_0); 
-	REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */     
-	REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */    
-	while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */   
-	ESP_LOGW(TAG, "burn abstract_done_0");   
-	REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */   
-	REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */     
-	while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */       
-	ESP_LOGI(TAG, "read EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG)); 
-	return true;
-
-}

+ 9 - 0
components/bootloader_support/README.rst

@@ -0,0 +1,9 @@
+Bootloader Support Component
+============================
+
+Overview
+--------
+
+"Bootloader support" contains APIs which are used by the bootloader but are also needed for the main app.
+
+Code in this component needs to be aware of being executed in a bootloader environment (no RTOS available, BOOTLOADER_BUILD macro set) or in an esp-idf app environment (RTOS running, need locking support.)

+ 35 - 0
components/bootloader_support/component.mk

@@ -0,0 +1,35 @@
+COMPONENT_ADD_INCLUDEDIRS := include
+COMPONENT_PRIV_INCLUDEDIRS := include_priv
+
+ifdef IS_BOOTLOADER_BUILD
+# share "private" headers with the bootloader component
+# eventual goal: all functionality that needs this lives in bootloader_support
+COMPONENT_ADD_INCLUDEDIRS += include_priv
+endif
+
+COMPONENT_SRCDIRS := src
+
+#
+# Secure boot signing key support
+#
+ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+
+# this path is created relative to the component build directory
+SECURE_BOOT_VERIFICATION_KEY := $(abspath signature_verification_key.bin)
+
+$(SECURE_BOOT_SIGNING_KEY):
+	@echo "Need to generate secure boot signing key."
+	@echo "One way is to run this command:"
+	@echo "$(ESPSECUREPY) generate_signing_key $@"
+	@echo "Keep key file safe after generating."
+	@echo "(See secure boot documentation for risks & alternatives.)"
+	@exit 1
+
+$(SECURE_BOOT_VERIFICATION_KEY): $(SECURE_BOOT_SIGNING_KEY)
+	$(ESPSECUREPY) extract_public_key --keyfile $< $@
+
+COMPONENT_EXTRA_CLEAN += $(SECURE_BOOT_VERIFICATION_KEY)
+
+COMPONENT_EMBED_FILES := $(SECURE_BOOT_VERIFICATION_KEY)
+
+endif

+ 132 - 0
components/bootloader_support/include/esp_image_format.h

@@ -0,0 +1,132 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __ESP32_IMAGE_FORMAT_H
+#define __ESP32_IMAGE_FORMAT_H
+
+#include <stdbool.h>
+#include <esp_err.h>
+
+#define ESP_ERR_IMAGE_BASE       0x2000
+#define ESP_ERR_IMAGE_FLASH_FAIL (ESP_ERR_IMAGE_BASE + 1)
+#define ESP_ERR_IMAGE_INVALID    (ESP_ERR_IMAGE_BASE + 2)
+
+/* Support for app/bootloader image parsing
+   Can be compiled as part of app or bootloader code.
+*/
+
+/* SPI flash mode, used in esp_image_header_t */
+typedef enum {
+    ESP_IMAGE_SPI_MODE_QIO,
+    ESP_IMAGE_SPI_MODE_QOUT,
+    ESP_IMAGE_SPI_MODE_DIO,
+    ESP_IMAGE_SPI_MODE_DOUT,
+    ESP_IMAGE_SPI_MODE_FAST_READ,
+    ESP_IMAGE_SPI_MODE_SLOW_READ
+} esp_image_spi_mode_t;
+
+/* SPI flash clock frequency */
+enum {
+    ESP_IMAGE_SPI_SPEED_40M,
+    ESP_IMAGE_SPI_SPEED_26M,
+    ESP_IMAGE_SPI_SPEED_20M,
+    ESP_IMAGE_SPI_SPEED_80M = 0xF
+} esp_image_spi_freq_t;
+
+/* Supported SPI flash sizes */
+typedef enum {
+    ESP_IMAGE_FLASH_SIZE_1MB = 0,
+    ESP_IMAGE_FLASH_SIZE_2MB,
+    ESP_IMAGE_FLASH_SIZE_4MB,
+    ESP_IMAGE_FLASH_SIZE_8MB,
+    ESP_IMAGE_FLASH_SIZE_16MB,
+    ESP_IMAGE_FLASH_SIZE_MAX
+} esp_image_flash_size_t;
+
+#define ESP_IMAGE_HEADER_MAGIC 0xE9
+
+/* Main header of binary image */
+typedef struct {
+    uint8_t magic;
+    uint8_t segment_count;
+    uint8_t spi_mode;      /* flash read mode (esp_image_spi_mode_t as uint8_t) */
+    uint8_t spi_speed: 4;  /* flash frequency (esp_image_spi_freq_t as uint8_t) */
+    uint8_t spi_size: 4;   /* flash chip size (esp_image_flash_size_t as uint8_t) */
+    uint32_t entry_addr;
+    uint8_t encrypt_flag;    /* encrypt flag */
+    uint8_t extra_header[15]; /* ESP32 additional header, unused by second bootloader */
+}  esp_image_header_t;
+
+/* Header of binary image segment */
+typedef struct {
+    uint32_t load_addr;
+    uint32_t data_len;
+} esp_image_segment_header_t;
+
+
+/**
+ * @brief Read an ESP image header from flash.
+ *
+ * @param src_addr Address in flash to load image header. Must be 4 byte aligned.
+ * @param[out] image_header Pointer to an esp_image_header_t struture to be filled with data. If the function fails, contents are undefined.
+ *
+ * @return ESP_OK if image header was loaded, ESP_ERR_IMAGE_FLASH_FAIL
+ * if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header
+ * appears invalid.
+ */
+esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header);
+
+/**
+ * @brief Read the segment header and data offset of a segment in the image.
+ *
+ * @param index Index of the segment to load information for.
+ * @param src_addr Base address in flash of the image.
+ * @param[in] image_header Pointer to the flash image header, already loaded by @ref esp_image_load_header().
+ * @param[out] segment_header Pointer to a segment header structure to be filled with data. If the function fails, contents are undefined.
+ * @param[out] segment_data_offset Pointer to the data offset of the segment.
+ *
+ * @return ESP_OK if segment_header & segment_data_offset were loaded successfully, ESP_ERR_IMAGE_FLASH_FAIL if a SPI flash error occurs, ESP_ERR_IMAGE_INVALID if the image header appears invalid, ESP_ERR_INVALID_ARG if the index is invalid.
+ */
+esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset);
+
+
+/**
+ * @brief Return length of an image in flash. Non-cryptographically validates image integrity in the process.
+ *
+ * If the image has a secure boot signature appended, the signature is not checked and this length is not included in the result.
+ *
+ * Image validation checks:
+ * - Magic byte
+ * - No single segment longer than 16MB
+ * - Total image no longer than 16MB
+ * - 8 bit image checksum is valid
+ *
+ * @param src_addr Offset of the start of the image in flash. Must be 4 byte aligned.
+ * @param[out] length Length of the image, set to a value if the image is valid. Can be null.
+ *
+ * @return ESP_OK if image is valid, ESP_FAIL or ESP_ERR_IMAGE_INVALID on errors.
+ *
+ */
+esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *length);
+
+
+typedef struct {
+    uint32_t drom_addr;
+    uint32_t drom_load_addr;
+    uint32_t drom_size;
+    uint32_t irom_addr;
+    uint32_t irom_load_addr;
+    uint32_t irom_size;
+} esp_image_flash_mapping_t;
+
+#endif

+ 75 - 0
components/bootloader_support/include/esp_secure_boot.h

@@ -0,0 +1,75 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __ESP32_SECUREBOOT_H
+#define __ESP32_SECUREBOOT_H
+
+#include <stdbool.h>
+#include <esp_err.h>
+#include "soc/efuse_reg.h"
+
+/* Support functions for secure boot features.
+
+   Can be compiled as part of app or bootloader code.
+*/
+
+/** @brief Is secure boot currently enabled in hardware?
+ *
+ * Secure boot is enabled if the ABS_DONE_0 efuse is blown. This means
+ * that the ROM bootloader code will only boot a verified secure
+ * bootloader digest from now on.
+ *
+ * @return true if secure boot is enabled.
+ */
+static inline bool esp_secure_boot_enabled(void) {
+    return REG_READ(EFUSE_BLK0_RDATA6_REG) & EFUSE_RD_ABS_DONE_0;
+}
+
+
+/** @brief Enable secure boot if it is not already enabled.
+ *
+ * @important If this function succeeds, secure boot is permanently
+ * enabled on the chip via efuse.
+ *
+ * @important This function is intended to be called from bootloader code only.
+ *
+ * If secure boot is not yet enabled for bootloader, this will
+ * generate the secure boot digest and enable secure boot by blowing
+ * the EFUSE_RD_ABS_DONE_0 efuse.
+ *
+ * This function does not verify secure boot of the bootloader (the
+ * ROM bootloader does this.)
+ *
+ * Will fail if efuses have been part-burned in a way that indicates
+ * secure boot should not or could not be correctly enabled.
+ *
+ *
+ * @return ESP_ERR_INVALID_STATE if efuse state doesn't allow
+ * secure boot to be enabled cleanly. ESP_OK if secure boot
+ * is enabled on this chip from now on.
+ */
+esp_err_t esp_secure_boot_permanently_enable(void);
+
+/** @brief Verify the secure boot signature (determinstic ECDSA w/ SHA256) appended to some binary data in flash.
+ *
+ * Public key is compiled into the calling program. See docs/security/secure-boot.rst for details.
+ *
+ * @param src_addr Starting offset of the data in flash.
+ * @param length Length of data in bytes. Signature is appended -after- length bytes.
+ *
+ * @return ESP_OK if signature is valid, ESP_ERR_INVALID_STATE if
+ * signature fails, ESP_FAIL for other failures (ie can't read flash).
+ */
+esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length);
+
+#endif

+ 69 - 0
components/bootloader_support/include_priv/bootloader_flash.h

@@ -0,0 +1,69 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __BOOTLOADER_FLASH_H
+#define __BOOTLOADER_FLASH_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <esp_err.h>
+
+/* Provide a Flash API for bootloader_support code,
+   that can be used from bootloader or app code.
+
+   This header is available to source code in the bootloader &
+   bootloader_support components only.
+*/
+
+/**
+ * @brief Map a region of flash to data memory
+ *
+ * @important In bootloader code, only one region can be bootloader_mmaped at once. The previous region must be bootloader_munmapped before another region is mapped.
+ *
+ * @important In app code, these functions are not thread safe.
+ *
+ * Call bootloader_munmap once for each successful call to bootloader_mmap.
+ *
+ * In esp-idf app, this function maps directly to spi_flash_mmap.
+ *
+ * @param offset - Starting flash offset to map to memory.
+ * @param length - Length of data to map.
+ *
+ * @return Pointer to mapped data memory (at src_addr), or NULL
+ * if an allocation error occured.
+ */
+const void *bootloader_mmap(uint32_t src_addr, uint32_t size);
+
+
+/**
+ * @brief Unmap a previously mapped region of flash
+ *
+ * Call bootloader_munmap once for each successful call to bootloader_mmap.
+ */
+void bootloader_munmap(const void *mapping);
+
+/**
+ * @brief  Read data from Flash.
+ *
+ * @note Both src and dest have to be 4-byte aligned.
+ *
+ * @param  src   source address of the data in Flash.
+ * @param  dest  pointer to the destination buffer
+ * @param  size  length of data
+ *
+ * @return esp_err_t
+ */
+esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size);
+
+#endif

+ 122 - 0
components/bootloader_support/src/bootloader_flash.c

@@ -0,0 +1,122 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <stddef.h>
+
+#include <bootloader_flash.h>
+#include <esp_log.h>
+#include <esp_spi_flash.h> /* including in bootloader for error values */
+
+#ifndef BOOTLOADER_BUILD
+/* Normal app version maps to esp_spi_flash.h operations...
+ */
+static const char *TAG = "bootloader_mmap";
+
+static spi_flash_mmap_memory_t map;
+
+const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
+{
+    if (map) {
+        ESP_LOGE(TAG, "tried to bootloader_mmap twice");
+        return NULL; /* existing mapping in use... */
+    }
+    const void *result = NULL;
+    esp_err_t err = spi_flash_mmap(src_addr, size, SPI_FLASH_MMAP_DATA, &result, &map);
+    if (err != ESP_OK) {
+        result = NULL;
+    }
+    return result;
+}
+
+void bootloader_munmap(const void *mapping)
+{
+    if(mapping && map) {
+        spi_flash_munmap(map);
+    }
+    map = 0;
+}
+
+esp_err_t bootloader_flash_read(size_t src, void *dest, size_t size)
+{
+    return spi_flash_read(src, dest, size);
+}
+
+#else
+/* Bootloader version, uses ROM functions only */
+#include <rom/spi_flash.h>
+#include <rom/cache.h>
+
+static const char *TAG = "bootloader_flash";
+
+static bool mapped;
+
+const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
+{
+    if (mapped) {
+        ESP_LOGE(TAG, "tried to bootloader_mmap twice");
+        return NULL; /* can't map twice */
+    }
+
+    uint32_t src_addr_aligned = src_addr & 0xffff0000;
+    uint32_t count = (size + (src_addr - src_addr_aligned) + 0xffff) / 0x10000;
+    Cache_Read_Disable(0);
+    Cache_Flush(0);
+    ESP_LOGD(TAG, "mmu set paddr=%08x count=%d", src_addr_aligned, count );
+    cache_flash_mmu_set( 0, 0, 0x3f400000, src_addr_aligned, 64, count );
+    Cache_Read_Enable( 0 );
+
+    mapped = true;
+
+    return (void *)(0x3f400000 + (src_addr - src_addr_aligned));
+}
+
+void bootloader_munmap(const void *mapping)
+{
+    if (mapped)  {
+        /* Full MMU reset */
+        Cache_Read_Disable(0);
+        Cache_Flush(0);
+        mmu_init(0);
+        mapped = false;
+    }
+}
+
+esp_err_t bootloader_flash_read(size_t src_addr, void *dest, size_t size)
+{
+    if(src_addr & 3) {
+        ESP_LOGE(TAG, "bootloader_flash_read src_addr 0x%x not 4-byte aligned", src_addr);
+        return ESP_FAIL;
+    }
+    if((intptr_t)dest & 3) {
+        ESP_LOGE(TAG, "bootloader_flash_read dest 0x%x not 4-byte aligned", (intptr_t)dest);
+        return ESP_FAIL;
+    }
+
+    Cache_Read_Disable(0);
+    Cache_Flush(0);
+    SpiFlashOpResult r = SPIRead(src_addr, dest, size);
+    Cache_Read_Enable(0);
+
+    switch(r) {
+    case SPI_FLASH_RESULT_OK:
+        return ESP_OK;
+    case SPI_FLASH_RESULT_ERR:
+        return ESP_ERR_FLASH_OP_FAIL;
+    case SPI_FLASH_RESULT_TIMEOUT:
+        return ESP_ERR_FLASH_OP_TIMEOUT;
+    default:
+        return ESP_FAIL;
+    }
+}
+
+#endif

+ 161 - 0
components/bootloader_support/src/esp_image_format.c

@@ -0,0 +1,161 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+
+#include <esp_image_format.h>
+#include <esp_log.h>
+#include <bootloader_flash.h>
+
+static const char *TAG = "esp_image";
+
+#define SIXTEEN_MB 0x1000000
+#define ESP_ROM_CHECKSUM_INITIAL 0xEF
+
+esp_err_t esp_image_load_header(uint32_t src_addr, esp_image_header_t *image_header)
+{
+    esp_err_t err;
+    ESP_LOGD(TAG, "reading image header @ 0x%x", src_addr);
+
+    err = bootloader_flash_read(src_addr, image_header, sizeof(esp_image_header_t));
+
+    if (err == ESP_OK) {
+        if (image_header->magic != ESP_IMAGE_HEADER_MAGIC) {
+            ESP_LOGE(TAG, "image at 0x%x has invalid magic byte", src_addr);
+            err = ESP_ERR_IMAGE_INVALID;
+        }
+        if (image_header->spi_mode > ESP_IMAGE_SPI_MODE_SLOW_READ) {
+            ESP_LOGW(TAG, "image at 0x%x has invalid SPI mode %d", src_addr, image_header->spi_mode);
+        }
+        if (image_header->spi_speed > ESP_IMAGE_SPI_SPEED_80M) {
+            ESP_LOGW(TAG, "image at 0x%x has invalid SPI speed %d", src_addr, image_header->spi_speed);
+        }
+        if (image_header->spi_size > ESP_IMAGE_FLASH_SIZE_MAX) {
+            ESP_LOGW(TAG, "image at 0x%x has invalid SPI size %d", src_addr, image_header->spi_size);
+        }
+    }
+
+    if (err != ESP_OK) {
+        bzero(image_header, sizeof(esp_image_header_t));
+    }
+    return err;
+}
+
+esp_err_t esp_image_load_segment_header(uint8_t index, uint32_t src_addr, const esp_image_header_t *image_header, esp_image_segment_header_t *segment_header, uint32_t *segment_data_offset)
+{
+    esp_err_t err = ESP_OK;
+    uint32_t next_addr = src_addr + sizeof(esp_image_header_t);
+
+    if(index >= image_header->segment_count) {
+        ESP_LOGE(TAG, "index %d higher than segment count %d", index, image_header->segment_count);
+        return ESP_ERR_INVALID_ARG;
+    }
+
+    for(int i = 0; i <= index && err == ESP_OK; i++) {
+        ESP_LOGV(TAG, "loading segment header %d at offset 0x%x", i, next_addr);
+        err = bootloader_flash_read(next_addr, segment_header, sizeof(esp_image_segment_header_t));
+        if (err == ESP_OK) {
+            if ((segment_header->data_len & 3) != 0
+                || segment_header->data_len >= SIXTEEN_MB) {
+                ESP_LOGE(TAG, "invalid segment length 0x%x", segment_header->data_len);
+                err = ESP_ERR_IMAGE_INVALID;
+            }
+            next_addr += sizeof(esp_image_segment_header_t);
+            ESP_LOGV(TAG, "segment data length 0x%x data starts 0x%x", segment_header->data_len, next_addr);
+            *segment_data_offset = next_addr;
+            next_addr += segment_header->data_len;
+        }
+    }
+
+    if (err != ESP_OK) {
+        *segment_data_offset = 0;
+        bzero(segment_header, sizeof(esp_image_segment_header_t));
+    }
+
+    return err;
+}
+
+esp_err_t esp_image_basic_verify(uint32_t src_addr, uint32_t *p_length)
+{
+    esp_err_t err;
+    uint8_t buf[16];
+    uint8_t checksum = ESP_ROM_CHECKSUM_INITIAL;
+    esp_image_header_t image_header;
+    esp_image_segment_header_t segment_header = { 0 };
+    uint32_t segment_data_offs = 0;
+    const uint8_t *segment_data;
+    uint32_t end_addr;
+    uint32_t length;
+
+    if (p_length != NULL) {
+        *p_length = 0;
+    }
+
+    err = esp_image_load_header(src_addr, &image_header);
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    ESP_LOGD(TAG, "reading %d image segments", image_header.segment_count);
+
+    /* Checksum each segment's data */
+    for (int i = 0; i < image_header.segment_count; i++) {
+        err = esp_image_load_segment_header(i, src_addr, &image_header,
+                                      &segment_header, &segment_data_offs);
+        if (err != ESP_OK) {
+            return err;
+        }
+
+        segment_data = bootloader_mmap(segment_data_offs, segment_header.data_len);
+        if (segment_data == NULL) {
+            ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", segment_data_offs, segment_header.data_len);
+            return ESP_FAIL;
+        }
+        for(int i = 0; i < segment_header.data_len; i++) {
+            checksum ^= segment_data[i];
+        }
+        bootloader_munmap(segment_data);
+    }
+
+    /* End of image, verify checksum */
+    end_addr = segment_data_offs + segment_header.data_len;
+
+    if (end_addr < src_addr) {
+        ESP_LOGE(TAG, "image offset has wrapped");
+        return ESP_ERR_IMAGE_INVALID;
+    }
+
+    length = end_addr - src_addr;
+    if (length >= SIXTEEN_MB) {
+        ESP_LOGE(TAG, "invalid total length 0x%x", length);
+        return ESP_ERR_IMAGE_INVALID;
+    }
+
+    /* image padded to next full 16 byte block, with checksum byte at very end */
+    ESP_LOGV(TAG, "unpadded image length 0x%x", length);
+    length += 16; /* always pad by at least 1 byte */
+    length = length - (length % 16);
+    ESP_LOGV(TAG, "padded image length 0x%x", length);
+    ESP_LOGD(TAG, "reading checksum block at 0x%x", src_addr + length - 16);
+    bootloader_flash_read(src_addr + length - 16, buf, 16);
+    if (checksum != buf[15]) {
+        ESP_LOGE(TAG, "checksum failed. Calculated 0x%x read 0x%x",
+                 checksum, buf[15]);
+        return ESP_ERR_IMAGE_INVALID;
+    }
+
+    if (p_length != NULL) {
+        *p_length = length;
+    }
+    return ESP_OK;
+}

+ 222 - 0
components/bootloader_support/src/secure_boot.c

@@ -0,0 +1,222 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string.h>
+
+#include "esp_attr.h"
+#include "esp_types.h"
+#include "esp_log.h"
+
+#include "rom/cache.h"
+#include "rom/ets_sys.h"
+#include "rom/spi_flash.h"
+#include "rom/secure_boot.h"
+
+#include "soc/dport_reg.h"
+#include "soc/io_mux_reg.h"
+#include "soc/efuse_reg.h"
+#include "soc/rtc_cntl_reg.h"
+
+#include "sdkconfig.h"
+
+#include "bootloader_flash.h"
+#include "esp_image_format.h"
+#include "esp_secure_boot.h"
+
+static const char* TAG = "secure_boot";
+
+#define HASH_BLOCK_SIZE 128
+#define IV_LEN HASH_BLOCK_SIZE
+#define DIGEST_LEN 64
+
+/**
+ *  @function :     secure_boot_generate
+ *  @description:   generate boot digest (aka "abstract") & iv
+ *
+ *  @inputs:        image_len - length of image to calculate digest for
+ */
+static bool secure_boot_generate(uint32_t image_len){
+    SpiFlashOpResult spiRet;
+    /* buffer is uint32_t not uint8_t to meet ROM SPI API signature */
+    uint32_t buf[IV_LEN / sizeof(uint32_t)];
+    const void *image;
+
+    /* hardware secure boot engine only takes full blocks, so round up the
+       image length. The additional data should all be 0xFF.
+    */
+    if (image_len % HASH_BLOCK_SIZE != 0) {
+        image_len = (image_len / HASH_BLOCK_SIZE + 1) * HASH_BLOCK_SIZE;
+    }
+    ets_secure_boot_start();
+    ets_secure_boot_rd_iv(buf);
+    ets_secure_boot_hash(NULL);
+    Cache_Read_Disable(0);
+    /* iv stored in sec 0 */
+    spiRet = SPIEraseSector(0);
+    if (spiRet != SPI_FLASH_RESULT_OK)
+    {
+        ESP_LOGE(TAG, "SPI erase failed %d", spiRet);
+        return false;
+    }
+    Cache_Read_Enable(0);
+
+    /* write iv to flash, 0x0000, 128 bytes (1024 bits) */
+    ESP_LOGD(TAG, "write iv to flash.");
+    spiRet = SPIWrite(0, buf, IV_LEN);
+    if (spiRet != SPI_FLASH_RESULT_OK)
+    {
+        ESP_LOGE(TAG, "SPI write failed %d", spiRet);
+        return false;
+    }
+    bzero(buf, sizeof(buf));
+
+    /* generate digest from image contents */
+    image = bootloader_mmap(0x1000, image_len);
+    if (!image) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x1000, 0x%x) failed", image_len);
+        return false;
+    }
+    for (int i = 0; i < image_len; i+= HASH_BLOCK_SIZE) {
+        ets_secure_boot_hash(image + i/sizeof(void *));
+    }
+    bootloader_munmap(image);
+
+    ets_secure_boot_obtain();
+    ets_secure_boot_rd_abstract(buf);
+    ets_secure_boot_finish();
+
+    ESP_LOGD(TAG, "write digest to flash.");
+    spiRet = SPIWrite(0x80, buf, DIGEST_LEN);
+    if (spiRet != SPI_FLASH_RESULT_OK) {
+        ESP_LOGE(TAG, "SPI write failed %d", spiRet);
+        return false;
+    }
+    ESP_LOGD(TAG, "write digest to flash.");
+    Cache_Read_Enable(0);
+    return true;
+}
+
+/* Burn values written to the efuse write registers */
+static inline void burn_efuses()
+{
+#ifdef CONFIG_SECURE_BOOT_TEST_MODE
+    ESP_LOGE(TAG, "SECURE BOOT TEST MODE. Not really burning any efuses!");
+#else
+    REG_WRITE(EFUSE_CONF_REG, 0x5A5A);  /* efuse_pgm_op_ena, force no rd/wr disable */
+    REG_WRITE(EFUSE_CMD_REG,  0x02);    /* efuse_pgm_cmd */
+    while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_pagm_cmd=0 */
+    REG_WRITE(EFUSE_CONF_REG, 0x5AA5);  /* efuse_read_op_ena, release force */
+    REG_WRITE(EFUSE_CMD_REG,  0x01);    /* efuse_read_cmd */
+    while (REG_READ(EFUSE_CMD_REG));    /* wait for efuse_read_cmd=0 */
+#endif
+}
+
+esp_err_t esp_secure_boot_permanently_enable(void) {
+    esp_err_t err;
+    uint32_t image_len = 0;
+    if (esp_secure_boot_enabled())
+    {
+        ESP_LOGI(TAG, "bootloader secure boot is already enabled, continuing..");
+        return ESP_OK;
+    }
+
+    err = esp_image_basic_verify(0x1000, &image_len);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "bootloader image appears invalid! error %d", err);
+        return err;
+    }
+
+    uint32_t dis_reg = REG_READ(EFUSE_BLK0_RDATA0_REG);
+    bool efuse_key_read_protected = dis_reg & EFUSE_RD_DIS_BLK2;
+    bool efuse_key_write_protected = dis_reg & EFUSE_WR_DIS_BLK2;
+    if (efuse_key_read_protected == false
+        && efuse_key_write_protected == false
+        && REG_READ(EFUSE_BLK2_RDATA0_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA1_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA2_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA3_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA4_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA5_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA6_REG) == 0
+        && REG_READ(EFUSE_BLK2_RDATA7_REG) == 0) {
+        ESP_LOGI(TAG, "Generating new secure boot key...");
+        /* reuse the secure boot IV generation function to generate
+           the key, as this generator uses the hardware RNG. */
+        uint32_t buf[32];
+        ets_secure_boot_start();
+        ets_secure_boot_rd_iv(buf);
+        ets_secure_boot_finish();
+        for (int i = 0; i < 8; i++) {
+            ESP_LOGV(TAG, "EFUSE_BLK2_WDATA%d_REG = 0x%08x", i, buf[i]);
+            REG_WRITE(EFUSE_BLK2_WDATA0_REG + 4*i, buf[i]);
+        }
+        bzero(buf, sizeof(buf));
+        burn_efuses();
+        ESP_LOGI(TAG, "Read & write protecting new key...");
+        REG_WRITE(EFUSE_BLK0_WDATA0_REG, EFUSE_WR_DIS_BLK2 | EFUSE_RD_DIS_BLK2);
+        burn_efuses();
+        efuse_key_read_protected = true;
+        efuse_key_write_protected = true;
+
+    } else {
+        ESP_LOGW(TAG, "Using pre-loaded secure boot key in EFUSE block 2");
+    }
+
+    ESP_LOGI(TAG, "Generating secure boot digest...");
+    if (false == secure_boot_generate(image_len)){
+        ESP_LOGE(TAG, "secure boot generation failed");
+        return ESP_FAIL;
+    }
+    ESP_LOGI(TAG, "Digest generation complete.");
+
+    if (!efuse_key_read_protected) {
+        ESP_LOGE(TAG, "Pre-loaded key is not read protected. Refusing to blow secure boot efuse.");
+        return ESP_ERR_INVALID_STATE;
+    }
+    if (!efuse_key_write_protected) {
+        ESP_LOGE(TAG, "Pre-loaded key is not write protected. Refusing to blow secure boot efuse.");
+        return ESP_ERR_INVALID_STATE;
+    }
+
+    ESP_LOGI(TAG, "blowing secure boot efuse...");
+    ESP_LOGD(TAG, "before updating, EFUSE_BLK0_RDATA6 %x", REG_READ(EFUSE_BLK0_RDATA6_REG));
+
+    uint32_t new_wdata6 = EFUSE_RD_ABS_DONE_0;
+
+    #ifdef CONFIG_SECURE_BOOT_DISABLE_JTAG
+    ESP_LOGI(TAG, "disabling JTAG...");
+    new_wdata6 |= EFUSE_RD_DISABLE_JTAG;
+    #endif
+
+    #ifdef CONFIG_SECURE_BOOT_DISABLE_UART_BOOTLOADER
+    ESP_LOGI(TAG, "disabling UART bootloader...");
+    new_wdata6 |= EFUSE_RD_CONSOLE_DEBUG_DISABLE_S;
+    #endif
+
+    REG_WRITE(EFUSE_BLK0_WDATA6_REG, new_wdata6);
+    burn_efuses();
+    uint32_t after = REG_READ(EFUSE_BLK0_RDATA6_REG);
+    ESP_LOGD(TAG, "after updating, EFUSE_BLK0_RDATA6 %x", after);
+    if (after & EFUSE_RD_ABS_DONE_0) {
+        ESP_LOGI(TAG, "secure boot is now enabled for bootloader image");
+        return ESP_OK;
+    } else {
+#ifdef CONFIG_SECURE_BOOT_TEST_MODE
+        ESP_LOGE(TAG, "secure boot not enabled due to test mode");
+#else
+        ESP_LOGE(TAG, "secure boot not enabled for bootloader image, EFUSE_RD_ABS_DONE_0 is probably write protected!");
+#endif
+        return ESP_ERR_INVALID_STATE;
+    }
+}

+ 110 - 0
components/bootloader_support/src/secure_boot_signatures.c

@@ -0,0 +1,110 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include "sdkconfig.h"
+
+#include "bootloader_flash.h"
+#include "esp_log.h"
+#include "esp_image_format.h"
+#include "esp_secure_boot.h"
+
+#include "uECC.h"
+
+#ifdef BOOTLOADER_BUILD
+#include "rom/sha.h"
+typedef SHA_CTX sha_context;
+#else
+#include "hwcrypto/sha.h"
+typedef esp_sha_context sha_context;
+#endif
+
+typedef struct {
+    uint32_t version;
+    uint8_t signature[64];
+} signature_block_t;
+
+static const char* TAG = "secure_boot";
+
+extern const uint8_t signature_verification_key_start[] asm("_binary_signature_verification_key_bin_start");
+extern const uint8_t signature_verification_key_end[] asm("_binary_signature_verification_key_bin_end");
+
+#define SIGNATURE_VERIFICATION_KEYLEN 64
+
+esp_err_t esp_secure_boot_verify_signature(uint32_t src_addr, uint32_t length)
+{
+    sha_context sha;
+    uint8_t digest[32];
+    ptrdiff_t keylen;
+    const uint8_t *data;
+    const signature_block_t *sigblock;
+    bool is_valid;
+#ifdef BOOTLOADER_BUILD
+    const uint8_t *digest_data;
+    uint32_t digest_len;
+#endif
+
+    ESP_LOGD(TAG, "verifying signature src_addr 0x%x length 0x%x", src_addr, length);
+
+    data = bootloader_mmap(src_addr, length + sizeof(signature_block_t));
+    if(data == NULL) {
+        ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", src_addr, length+sizeof(signature_block_t));
+        return ESP_FAIL;
+    }
+
+    sigblock = (const signature_block_t *)(data + length);
+
+    if (sigblock->version != 0) {
+        ESP_LOGE(TAG, "src 0x%x has invalid signature version field 0x%08x", src_addr, sigblock->version);
+        goto unmap_and_fail;
+    }
+
+#ifdef BOOTLOADER_BUILD
+    /* Use ROM SHA functions directly */
+    ets_sha_enable();
+    ets_sha_init(&sha);
+    digest_len = length * 8;
+    digest_data = data;
+    while (digest_len > 0) {
+        uint32_t chunk_len = (digest_len > 64) ? 64 : digest_len;
+        ets_sha_update(&sha, SHA2_256, digest_data, chunk_len);
+        digest_len -= chunk_len;
+        digest_data += chunk_len / 8;
+    }
+    ets_sha_finish(&sha, SHA2_256, digest);
+    ets_sha_disable();
+#else
+    /* Use thread-safe esp-idf SHA layer */
+    esp_sha256_init(&sha);
+    esp_sha256_start(&sha, false);
+    esp_sha256_update(&sha, data, length);
+    esp_sha256_finish(&sha, digest);
+    esp_sha256_free(&sha);
+#endif
+
+    keylen = signature_verification_key_end - signature_verification_key_start;
+    if(keylen != SIGNATURE_VERIFICATION_KEYLEN) {
+        ESP_LOGE(TAG, "Embedded public verification key has wrong length %d", keylen);
+        goto unmap_and_fail;
+    }
+
+    is_valid = uECC_verify(signature_verification_key_start,
+                           digest, sizeof(digest), sigblock->signature,
+                           uECC_secp256r1());
+
+    bootloader_munmap(data);
+    return is_valid ? ESP_OK : ESP_ERR_IMAGE_INVALID;
+
+ unmap_and_fail:
+    bootloader_munmap(data);
+    return ESP_FAIL;
+}

+ 2 - 7
components/bt/component.mk

@@ -2,22 +2,17 @@
 # Component Makefile
 #
 
-#COMPONENT_ADD_INCLUDEDIRS := 
-
 COMPONENT_ADD_INCLUDEDIRS := include
 
 CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
 
 LIBS := btdm_app
 
-COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \
+COMPONENT_ADD_LDFLAGS := -lbt -L $(COMPONENT_PATH)/lib \
                            $(addprefix -l,$(LIBS)) \
                           $(LINKER_SCRIPTS)
 
-include $(IDF_PATH)/make/component_common.mk
-
 ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
 $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
 
-# automatically trigger a git submodule update if BT library is missing
-$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib))
+COMPONENT_SUBMODULES += lib

+ 2 - 5
components/bt/include/bt.h

@@ -32,13 +32,10 @@ void bt_controller_init(void);
 
 /** @brief vhci_host_callback
  *  used for vhci call host function to notify what host need to do
- *  
- *  notify_host_send_available: notify host can send packet to controller
- *  notify_host_recv: notify host that controller has packet send to host
  */
 typedef struct vhci_host_callback {
-    void (*notify_host_send_available)(void);
-    int (*notify_host_recv)(uint8_t *data, uint16_t len);
+    void (*notify_host_send_available)(void);               /*!< callback used to notify that the host can send packet to controller */
+    int (*notify_host_recv)(uint8_t *data, uint16_t len);   /*!< callback used to notify that the controller has a packet to send to the host*/
 } vhci_host_callback_t;
 
 /** @brief API_vhci_host_check_send_available

+ 0 - 6
components/driver/component.mk

@@ -1,14 +1,8 @@
 #
 # Component Makefile
 #
-# This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default, 
-# this will take the sources in this directory, compile them and link them into 
-# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
-# please read the SDK documents if you need to do this.
-#
 
 COMPONENT_ADD_INCLUDEDIRS := include
 
 COMPONENT_PRIV_INCLUDEDIRS := include/driver
 
-include $(IDF_PATH)/make/component_common.mk

+ 113 - 103
components/driver/gpio.c

@@ -18,34 +18,13 @@
 #include "freertos/xtensa_api.h"
 #include "driver/gpio.h"
 #include "soc/soc.h"
+#include "esp_log.h"
 
-//TODO: move debug options to menuconfig
-#define GPIO_DBG_ENABLE     (0)
-#define GPIO_WARNING_ENABLE (0)
-#define GPIO_ERROR_ENABLE   (0)
-#define GPIO_INFO_ENABLE    (0)
-//DBG INFOR 
-#if GPIO_INFO_ENABLE
-#define GPIO_INFO ets_printf
-#else
-#define GPIO_INFO(...)
-#endif
-#if GPIO_WARNING_ENABLE
-#define GPIO_WARNING(format,...) do{\
-        ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else 
-#define GPIO_WARNING(...)
-#endif
-#if GPIO_ERROR_ENABLE
-#define GPIO_ERROR(format,...) do{\
-        ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else 
-#define GPIO_ERROR(...)
-#endif 
+static const char* GPIO_TAG = "GPIO";
+#define GPIO_CHECK(a, str, ret_val) if (!(a)) {                                         \
+        ESP_LOGE(GPIO_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str);    \
+        return (ret_val);                                                               \
+        }
 
 const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
     GPIO_PIN_REG_0,
@@ -90,33 +69,85 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
     GPIO_PIN_REG_39
 };
 
-static int is_valid_gpio(int gpio_num)
-{
-    if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
-        GPIO_ERROR("GPIO io_num=%d does not exist\n",gpio_num);
-        return 0;
-    }
-    return 1;
+const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT]={
+    {RTC_IO_TOUCH_PAD1_REG, RTC_IO_TOUCH_PAD1_RUE_M, RTC_IO_TOUCH_PAD1_RDE_M},
+    {PERIPHS_IO_MUX_U0TXD_U, FUN_PU, FUN_PD},
+    {RTC_IO_TOUCH_PAD2_REG, RTC_IO_TOUCH_PAD2_RUE_M, RTC_IO_TOUCH_PAD2_RDE_M},
+    {PERIPHS_IO_MUX_U0RXD_U, FUN_PU, FUN_PD},
+    {RTC_IO_TOUCH_PAD0_REG, RTC_IO_TOUCH_PAD0_RUE_M, RTC_IO_TOUCH_PAD0_RDE_M},
+    {PERIPHS_IO_MUX_GPIO5_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_CLK_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_DATA0_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_DATA1_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_DATA2_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_DATA3_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_SD_CMD_U, FUN_PU, FUN_PD},
+    {RTC_IO_TOUCH_PAD5_REG, RTC_IO_TOUCH_PAD5_RUE_M, RTC_IO_TOUCH_PAD5_RDE_M},
+    {RTC_IO_TOUCH_PAD4_REG, RTC_IO_TOUCH_PAD4_RUE_M, RTC_IO_TOUCH_PAD4_RDE_M},
+    {RTC_IO_TOUCH_PAD6_REG, RTC_IO_TOUCH_PAD6_RUE_M, RTC_IO_TOUCH_PAD6_RDE_M},
+    {RTC_IO_TOUCH_PAD3_REG, RTC_IO_TOUCH_PAD3_RUE_M, RTC_IO_TOUCH_PAD3_RDE_M},
+    {PERIPHS_IO_MUX_GPIO16_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO17_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO18_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO19_U, FUN_PU, FUN_PD},
+    {0,0,0},
+    {PERIPHS_IO_MUX_GPIO21_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO22_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO23_U, FUN_PU, FUN_PD},
+    {0,0,0},
+    {RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_RUE_M, RTC_IO_PDAC1_RDE_M},
+    {RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_RUE_M, RTC_IO_PDAC2_RDE_M},
+    {RTC_IO_TOUCH_PAD7_REG, RTC_IO_TOUCH_PAD7_RUE_M, RTC_IO_TOUCH_PAD7_RDE_M},
+    {0,0,0},
+    {0,0,0},
+    {0,0,0},
+    {0,0,0},
+    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE_M, RTC_IO_X32P_RDE_M},
+    {RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_RUE_M, RTC_IO_X32N_RDE_M},
+    {PERIPHS_IO_MUX_GPIO34_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO35_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO36_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO37_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO38_U, FUN_PU, FUN_PD},
+    {PERIPHS_IO_MUX_GPIO39_U, FUN_PU, FUN_PD}
+};
+
+
+esp_err_t gpio_pullup_en(gpio_num_t gpio_num) {
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+    return ESP_OK;
+}
+
+esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) {
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+    return ESP_OK;
+}
+
+esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) {
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
+    return ESP_OK;
+}
+
+esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num) {
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
+    return ESP_OK;
 }
 
 esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(intr_type >= GPIO_INTR_MAX) {
-        GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type);
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    GPIO_CHECK(intr_type < GPIO_INTR_MAX, "GPIO interrupt type error", ESP_ERR_INVALID_ARG);
     GPIO.pin[gpio_num].int_type = intr_type;
     return ESP_OK;
 }
 
 esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     if(xPortGetCoreID() == 0) {
         GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA;     //enable pro cpu intr
     } else {
@@ -127,18 +158,14 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 
 esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     GPIO.pin[gpio_num].int_ena = 0;                             //disable GPIO intr
     return ESP_OK;
 }
 
 static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     if(gpio_num < 32) {
         GPIO.enable_w1tc = (0x1 << gpio_num);
     } else {
@@ -149,13 +176,7 @@ static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
 
 static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
 {
-    if(gpio_num >= 34) {
-        GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO output gpio_num error", ESP_ERR_INVALID_ARG);
     if(gpio_num < 32) {
         GPIO.enable_w1ts = (0x1 << gpio_num);
     } else {
@@ -166,9 +187,7 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
 
 esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
 {
-    if(!GPIO_IS_VALID_GPIO(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     if(level) {
         if(gpio_num < 32) {
             GPIO.out_w1ts = (1 << gpio_num);
@@ -196,29 +215,28 @@ int gpio_get_level(gpio_num_t gpio_num)
 
 esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
+    GPIO_CHECK(pull <= GPIO_FLOATING, "GPIO pull mode error", ESP_ERR_INVALID_ARG);
     esp_err_t ret = ESP_OK;
     switch(pull) {
         case GPIO_PULLUP_ONLY:
-            PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
-            PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]);
+            REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+            REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
             break;
         case GPIO_PULLDOWN_ONLY:
-            PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
-            PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]);
+            REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+            REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
             break;
         case GPIO_PULLUP_PULLDOWN:
-            PIN_PULLUP_EN(GPIO_PIN_MUX_REG[gpio_num]);
-            PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[gpio_num]);
+            REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+            REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
             break;
         case GPIO_FLOATING:
-            PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[gpio_num]);
-            PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[gpio_num]);
+            REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu);
+            REG_CLR_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pd);
             break;
         default:
-            GPIO_ERROR("Unknown pull up/down mode,gpio_num=%u,pull=%u\n",gpio_num,pull);
+            ESP_LOGE(GPIO_TAG, "Unknown pull up/down mode,gpio_num=%u,pull=%u",gpio_num,pull);
             ret = ESP_ERR_INVALID_ARG;
             break;
     }
@@ -227,11 +245,9 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
 
 esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
-        GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
+        ESP_LOGE(GPIO_TAG, "io_num=%d can only be input",gpio_num);
         return ESP_ERR_INVALID_ARG;
     }
     esp_err_t ret = ESP_OK;
@@ -266,54 +282,56 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
     uint64_t gpio_pin_mask = (pGPIOConfig->pin_bit_mask);
     uint32_t io_reg = 0;
     uint32_t io_num = 0;
-    uint64_t bit_valid = 0;
+    uint8_t input_en = 0;
+    uint8_t output_en = 0;
+    uint8_t od_en = 0;
+    uint8_t pu_en = 0;
+    uint8_t pd_en = 0;
     if(pGPIOConfig->pin_bit_mask == 0 || pGPIOConfig->pin_bit_mask >= (((uint64_t) 1) << GPIO_PIN_COUNT)) {
-        GPIO_ERROR("GPIO_PIN mask error \n");
+        ESP_LOGE(GPIO_TAG, "GPIO_PIN mask error ");
         return ESP_ERR_INVALID_ARG;
     }
     if((pGPIOConfig->mode) & (GPIO_MODE_DEF_OUTPUT)) {
         //GPIO 34/35/36/37/38/39 can only be used as input mode;
         if((gpio_pin_mask & ( GPIO_SEL_34 | GPIO_SEL_35 | GPIO_SEL_36 | GPIO_SEL_37 | GPIO_SEL_38 | GPIO_SEL_39))) {
-            GPIO_ERROR("GPIO34-39 can only be used as input mode\n");
+            ESP_LOGE(GPIO_TAG, "GPIO34-39 can only be used as input mode");
             return ESP_ERR_INVALID_ARG;
         }
     }
     do {
         io_reg = GPIO_PIN_MUX_REG[io_num];
         if(((gpio_pin_mask >> io_num) & BIT(0)) && io_reg) {
-            GPIO_INFO("Gpio%02d |Mode:",io_num);
             if((pGPIOConfig->mode) & GPIO_MODE_DEF_INPUT) {
-                GPIO_INFO("INPUT ");
+                input_en = 1;
                 PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[io_num]);
             } else {
                 PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[io_num]);
             }
             if((pGPIOConfig->mode) & GPIO_MODE_DEF_OD) {
-                GPIO_INFO("OD ");
+                od_en = 1;
                 GPIO.pin[io_num].pad_driver = 1; /*0x01 Open-drain */
             } else {
                 GPIO.pin[io_num].pad_driver = 0; /*0x00 Normal gpio output */
             }
             if((pGPIOConfig->mode) & GPIO_MODE_DEF_OUTPUT) {
-                GPIO_INFO("OUTPUT ");
+                output_en = 1;
                 gpio_output_enable(io_num);
             } else {
                 gpio_output_disable(io_num);
             }
-            GPIO_INFO("|");
             if(pGPIOConfig->pull_up_en) {
-                GPIO_INFO("PU ");
-                PIN_PULLUP_EN(io_reg);
+                pu_en = 1;
+                REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
             } else {
-                PIN_PULLUP_DIS(io_reg);
+                REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
             }
             if(pGPIOConfig->pull_down_en) {
-                GPIO_INFO("PD ");
-                PIN_PULLDWN_EN(io_reg);
+                pd_en = 1;
+                REG_SET_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
             } else {
-                PIN_PULLDWN_DIS(io_reg);
+                REG_CLR_BIT(gpio_pu_pd_desc[io_num].reg, gpio_pu_pd_desc[io_num].pd);
             }
-            GPIO_INFO("Intr:%d |\n",pGPIOConfig->intr_type);
+            ESP_LOGI(GPIO_TAG, "GPIO[%d]| InputEn: %d| OutputEn: %d| OpenDrain: %d| Pullup: %d| Pulldown: %d| Intr:%d ", io_num, input_en, output_en, od_en, pu_en, pd_en, pGPIOConfig->intr_type);
             gpio_set_intr_type(io_num, pGPIOConfig->intr_type);
             if(pGPIOConfig->intr_type) {
                 gpio_intr_enable(io_num);
@@ -321,8 +339,6 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
                 gpio_intr_disable(io_num);
             }
             PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
-        } else if(bit_valid && (io_reg == 0)) {
-            GPIO_WARNING("io_num=%d does not exist\n",io_num);
         }
         io_num++;
     } while(io_num < GPIO_PIN_COUNT);
@@ -331,9 +347,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
 
 esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
 {
-    if(fn == NULL) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(fn, "GPIO ISR null", ESP_ERR_INVALID_ARG);
     ESP_INTR_DISABLE(gpio_intr_num);
     intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
     xt_set_interrupt_handler(gpio_intr_num, fn, arg);
@@ -344,15 +358,13 @@ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * ar
 /*only level interrupt can be used for wake-up function*/
 esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     esp_err_t ret = ESP_OK;
     if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
         GPIO.pin[gpio_num].int_type = intr_type;
         GPIO.pin[gpio_num].wakeup_enable = 0x1;
     } else {
-        GPIO_ERROR("GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u\n",gpio_num);
+        ESP_LOGE(GPIO_TAG, "GPIO wakeup only support Level mode,but edge mode set. gpio_num:%u",gpio_num);
         ret = ESP_ERR_INVALID_ARG;
     }
     return ret;
@@ -360,9 +372,7 @@ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 
 esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
 {
-    if(!is_valid_gpio(gpio_num)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    GPIO_CHECK(GPIO_IS_VALID_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG);
     GPIO.pin[gpio_num].wakeup_enable = 0;
     return ESP_OK;
 }

+ 85 - 8
components/driver/include/driver/gpio.h

@@ -20,6 +20,7 @@
 #include "soc/gpio_struct.h"
 #include "soc/rtc_io_reg.h"
 #include "soc/io_mux_reg.h"
+#include "soc/gpio_sig_map.h"
 #include "rom/gpio.h"
 #include "esp_attr.h"
 
@@ -116,6 +117,32 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT];
 #define GPIO_IS_VALID_GPIO(gpio_num)      ((gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0))   //to decide whether it is a valid GPIO number
 #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)      ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34))         //to decide whether it can be a valid GPIO number of output mode
 
+/**
+ * @brief Pullup/pulldown information for a single GPIO pad
+ */
+typedef struct {
+    uint32_t reg;       /*!< Register to modify to enable or disable pullups or pulldowns */
+    uint32_t pu;        /*!< Bit to set or clear in the above register to enable or disable the pullup, respectively */
+    uint32_t pd;        /*!< Bit to set or clear in the above register to enable or disable the pulldown, respectively */
+} gpio_pu_pd_desc_t;
+
+
+/**
+ * Per-GPIO pullup/pulldown information
+ * On the ESP32, some GPIOs need their pullups and pulldowns enabled and disabled in the RTC 
+ * peripheral instead of in the GPIO peripheral. This array documents for every GPIO what bit
+ * to set or clear.
+ * 
+ * This array is non-static, so if you need a very quick way of toggling the pull-up/downs, you can just
+ * do e.g. REG_SET_BIT(gpio_pu_pd_desc[gpio_num].reg, gpio_pu_pd_desc[gpio_num].pu); inline.
+ * 
+ * ToDo: Functions using the contents of this array will do a read/modify/write on GPIO as well as RTC
+ * registers. We may need to look into muxes/locks for other code that accesses these RTC registers when we
+ * write drivers for the RTC stuff.
+ */
+extern const gpio_pu_pd_desc_t gpio_pu_pd_desc[GPIO_PIN_COUNT];
+
+
 typedef enum {
     GPIO_NUM_0 = 0,     /*!< GPIO0, input and output */
     GPIO_NUM_1 = 1,     /*!< GPIO1, input and output */
@@ -184,6 +211,9 @@ typedef enum {
     GPIO_PULLDOWN_ENABLE = 0x1,    /*!< Enable GPIO pull-down resistor  */
 } gpio_pulldown_t;
 
+/**
+ * @brief Configuration parameters of GPIO pad for gpio_config function
+ */
 typedef struct {
     uint64_t pin_bit_mask;          /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */
     gpio_mode_t mode;               /*!< GPIO mode: set input/output mode                     */
@@ -219,7 +249,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig);
 /**
  * @brief  GPIO set interrupt trigger type
  *
- * @param  gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to set the trigger type of e.g. of GPIO16, gpio_num should be GPIO_NUM_16 (16);
  * @param  intr_type Interrupt type, select from gpio_int_type_t
  *
  * @return
@@ -232,7 +262,7 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type);
 /**
  * @brief  Enable GPIO module interrupt signal
  *
- * @param  gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to enable an interrupt on e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  *
  * @return
  *     - ESP_OK Success
@@ -244,7 +274,7 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num);
 /**
  * @brief  Disable GPIO module interrupt signal
  *
- * @param  gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to disable the interrupt of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  *
  * @return
  *     - ESP_OK success
@@ -256,7 +286,7 @@ esp_err_t gpio_intr_disable(gpio_num_t gpio_num);
 /**
  * @brief  GPIO set output level
  *
- * @param  gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to set the output level of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  * @param  level Output level. 0: low ; 1: high
  *
  * @return
@@ -269,7 +299,7 @@ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level);
 /**
  * @brief  GPIO get input level
  *
- * @param  gpio_num GPIO number. If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to get the logic level of e.g. pin GPIO16, gpio_num should be GPIO_NUM_16 (16);
  *
  * @return
  *     - 0 the GPIO input level is 0
@@ -283,7 +313,7 @@ int gpio_get_level(gpio_num_t gpio_num);
  *
  * Configure GPIO direction,such as output_only,input_only,output_and_input
  *
- * @param  gpio_num  Configure GPIO pins number, it should be GPIO number. If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num  Configure GPIO pins number, it should be GPIO number. If you want to set direction of e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  * @param  mode GPIO direction
  *
  * @return
@@ -298,7 +328,7 @@ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode);
  *
  * User this Function,configure GPIO pull mode,such as pull-up,pull-down
  *
- * @param  gpio_num GPIO number. If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16);
+ * @param  gpio_num GPIO number. If you want to set pull up or down mode for e.g. GPIO16, gpio_num should be GPIO_NUM_16 (16);
  * @param  pull GPIO pull up/down mode.
  *
  * @return
@@ -313,7 +343,7 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull);
   *
   * @param gpio_num GPIO number.
   *
-  * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL\GPIO_INTR_HIGH_LEVEL can be used.
+  * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOW_LEVEL or GPIO_INTR_HIGH_LEVEL can be used.
   *
   * @return
   *     - ESP_OK Success
@@ -353,6 +383,53 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num);
  */
 esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg);
 
+
+
+/**
+  * @brief Enable pull-up on GPIO.
+  *
+  * @param gpio_num GPIO number
+  *
+  * @return
+  *     - ESP_OK Success
+  *     - ESP_ERR_INVALID_ARG Parameter error
+  */
+esp_err_t gpio_pullup_en(gpio_num_t gpio_num);
+
+/**
+  * @brief Disable pull-up on GPIO.
+  *
+  * @param gpio_num GPIO number
+  *
+  * @return
+  *     - ESP_OK Success
+  *     - ESP_ERR_INVALID_ARG Parameter error
+  */
+esp_err_t gpio_pullup_dis(gpio_num_t gpio_num);
+
+/**
+  * @brief Enable pull-down on GPIO.
+  *
+  * @param gpio_num GPIO number
+  *
+  * @return
+  *     - ESP_OK Success
+  *     - ESP_ERR_INVALID_ARG Parameter error
+  */
+esp_err_t gpio_pulldown_en(gpio_num_t gpio_num);
+
+/**
+  * @brief Disable pull-down on GPIO.
+  *
+  * @param gpio_num GPIO number
+  *
+  * @return
+  *     - ESP_OK Success
+  *     - ESP_ERR_INVALID_ARG Parameter error
+  */
+esp_err_t gpio_pulldown_dis(gpio_num_t gpio_num);
+
+
 /**
  * ***************        ATTENTION       ********************/
 /**

+ 8 - 0
components/driver/include/driver/ledc.h

@@ -78,6 +78,9 @@ typedef enum {
     LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */
 } ledc_timer_bit_t;
 
+/**
+ * @brief Configuration parameters of LEDC channel for ledc_channel_config function
+ */
 typedef struct {
     int gpio_num;                   /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/
     ledc_mode_t speed_mode;         /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/
@@ -87,6 +90,9 @@ typedef struct {
     uint32_t duty;                  /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
 } ledc_channel_config_t;
 
+/**
+ * @brief Configuration parameters of LEDC Timer timer for ledc_timer_config function
+ */
 typedef struct {
     ledc_mode_t speed_mode;         /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/
     ledc_timer_bit_t bit_num;       /*!< LEDC channel duty depth*/
@@ -150,6 +156,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
  *
  * @param  channel LEDC channel(0-7), select from ledc_channel_t
  *
+ * @param  idle_level Set output idle level after LEDC stops.
+ *
  * @return
  *     - ESP_OK Success
  *     - ESP_ERR_INVALID_ARG Parameter error

+ 748 - 0
components/driver/include/driver/uart.h

@@ -0,0 +1,748 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef _DRIVER_UART_H_
+#define _DRIVER_UART_H_
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "soc/uart_reg.h"
+#include "soc/uart_struct.h"
+#include "esp_err.h"
+#include "driver/periph_ctrl.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/ringbuf.h"
+#include <esp_types.h>
+
+#define UART_FIFO_LEN           (128)        /*!< Length of the hardware FIFO buffers */
+#define UART_INTR_MASK          0x1ff        /*!< mask of all UART interrupts */
+#define UART_LINE_INV_MASK      (0x3f << 19) /*!< TBD */
+#define UART_BITRATE_MAX        5000000      /*!< Max bit rate supported by UART */
+#define UART_PIN_NO_CHANGE      (-1)         /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */
+
+#define UART_INVERSE_DISABLE  (0x0)            /*!< Disable UART signal inverse*/
+#define UART_INVERSE_RXD   (UART_RXD_INV_M)    /*!< UART RXD input inverse*/
+#define UART_INVERSE_CTS   (UART_CTS_INV_M)    /*!< UART CTS input inverse*/
+#define UART_INVERSE_TXD   (UART_TXD_INV_M)    /*!< UART TXD output inverse*/
+#define UART_INVERSE_RTS   (UART_RTS_INV_M)    /*!< UART RTS output inverse*/
+
+/**
+ * @brief UART word length constants
+ */
+typedef enum {
+    UART_DATA_5_BITS = 0x0,    /*!< word length: 5bits*/
+    UART_DATA_6_BITS = 0x1,    /*!< word length: 6bits*/
+    UART_DATA_7_BITS = 0x2,    /*!< word length: 7bits*/
+    UART_DATA_8_BITS = 0x3,    /*!< word length: 8bits*/
+    UART_DATA_BITS_MAX = 0X4,
+} uart_word_length_t;
+
+/**
+ * @brief UART stop bits number
+ */
+typedef enum {
+    UART_STOP_BITS_1   = 0x1,  /*!< stop bit: 1bit*/
+    UART_STOP_BITS_1_5 = 0x2,  /*!< stop bit: 1.5bits*/
+    UART_STOP_BITS_2   = 0x3,  /*!< stop bit: 2bits*/
+    UART_STOP_BITS_MAX = 0x4,
+} uart_stop_bits_t;
+
+/**
+ * @brief UART peripheral number
+ */
+typedef enum {
+    UART_NUM_0 = 0x0,  /*!< UART base address 0x3ff40000*/
+    UART_NUM_1 = 0x1,  /*!< UART base address 0x3ff50000*/
+    UART_NUM_2 = 0x2,  /*!< UART base address 0x3ff6E000*/
+    UART_NUM_MAX,
+} uart_port_t;
+
+/**
+ * @brief UART parity constants
+ */
+typedef enum {
+    UART_PARITY_DISABLE = 0x0,   /*!< Disable UART parity*/
+    UART_PARITY_EVEN = 0x2,     /*!< Enable UART even parity*/
+    UART_PARITY_ODD  = 0x3      /*!< Enable UART odd parity*/
+} uart_parity_t;
+
+/**
+ * @brief UART hardware flow control modes
+ */
+typedef enum {
+    UART_HW_FLOWCTRL_DISABLE = 0x0,   /*!< disable hardware flow control*/
+    UART_HW_FLOWCTRL_RTS     = 0x1,   /*!< enable RX hardware flow control (rts)*/
+    UART_HW_FLOWCTRL_CTS     = 0x2,   /*!< enable TX hardware flow control (cts)*/
+    UART_HW_FLOWCTRL_CTS_RTS = 0x3,   /*!< enable hardware flow control*/
+    UART_HW_FLOWCTRL_MAX     = 0x4,
+} uart_hw_flowcontrol_t;
+
+/**
+ * @brief UART configuration parameters for uart_param_config function
+ */
+typedef struct {
+    int baud_rate;                      /*!< UART baudrate*/
+    uart_word_length_t data_bits;       /*!< UART byte size*/
+    uart_parity_t parity;               /*!< UART parity mode*/
+    uart_stop_bits_t stop_bits;         /*!< UART stop bits*/
+    uart_hw_flowcontrol_t flow_ctrl;    /*!< UART HW flow control mode(cts/rts)*/
+    uint8_t rx_flow_ctrl_thresh ;       /*!< UART HW RTS threshold*/
+} uart_config_t;
+
+/**
+ * @brief UART interrupt configuration parameters for uart_intr_config function
+ */
+typedef struct {
+    uint32_t intr_enable_mask;          /*!< UART interrupt enable mask, choose from UART_XXXX_INT_ENA_M under UART_INT_ENA_REG(i), connect with bit-or operator*/
+    uint8_t  rx_timeout_thresh;         /*!< UART timeout interrupt threshold(unit: time of sending one byte)*/
+    uint8_t  txfifo_empty_intr_thresh;  /*!< UART TX empty interrupt threshold.*/
+    uint8_t  rxfifo_full_thresh;        /*!< UART RX full interrupt threshold.*/
+} uart_intr_config_t;
+
+/**
+ * @brief UART event types used in the ringbuffer
+ */
+typedef enum {
+    UART_DATA,              /*!< UART data event*/
+    UART_BREAK,             /*!< UART break event*/
+    UART_BUFFER_FULL,       /*!< UART RX buffer full event*/
+    UART_FIFO_OVF,          /*!< UART FIFO overflow event*/
+    UART_FRAME_ERR,         /*!< UART RX frame error event*/
+    UART_PARITY_ERR,        /*!< UART RX parity event*/
+    UART_DATA_BREAK,        /*!< UART TX data and break event*/
+    UART_EVENT_MAX,         /*!< UART event max index*/
+} uart_event_type_t;
+
+/**
+ * @brief Event structure used in UART event queue
+ */
+typedef struct {
+    uart_event_type_t type; /*!< UART event type */
+    size_t size;            /*!< UART data size for UART_DATA event*/
+} uart_event_t;
+
+/**
+ * @brief Set UART data bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param data_bit UART data bits
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit);
+
+/**
+ * @brief Get UART data bits.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param data_bit Pointer to accept value of UART data bits.
+ *
+ * @return
+ *     - ESP_FAIL  Parameter error
+ *     - ESP_OK    Success, result will be put in (*data_bit)
+ */
+esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit);
+
+/**
+ * @brief Set UART stop bits.
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param bit_num  UART stop bits
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Fail
+ */
+esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t bit_num);
+
+/**
+ * @brief Set UART stop bits.
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param stop_bit  Pointer to accept value of UART stop bits.
+ *
+ * @return
+ *     - ESP_FAIL Parameter error
+ *     - ESP_OK   Success, result will be put in (*stop_bit)
+ */
+esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit);
+
+/**
+ * @brief Set UART parity.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param parity_mode the enum of uart parity configuration
+ *
+ * @return
+ *     - ESP_FAIL  Parameter error
+ *     - ESP_OK    Success
+ */
+esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode);
+
+/**
+ * @brief Get UART parity mode.
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param parity_mode Pointer to accept value of UART parity mode.
+ *
+ * @return
+ *     - ESP_FAIL  Parameter error
+ *     - ESP_OK    Success, result will be put in (*parity_mode)
+ *
+ */
+esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode);
+
+/**
+ * @brief Set UART baud rate.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param baud_rate UART baud-rate.
+ *
+ * @return
+ *     - ESP_FAIL Parameter error
+ *     - ESP_OK   Success
+ */
+esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate);
+
+/**
+ * @brief Get UART bit-rate.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param baudrate Pointer to accept value of UART baud rate
+ *
+ * @return
+ *     - ESP_FAIL Parameter error
+ *     - ESP_OK   Success, result will be put in (*baudrate)
+ *
+ */
+esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate);
+
+/**
+ * @brief Set UART line inverse mode
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param inverse_mask Choose the wires that need to be inversed.
+ *        Inverse_mask should be chosen from UART_INVERSE_RXD/UART_INVERSE_TXD/UART_INVERSE_RTS/UART_INVERSE_CTS, combine with OR operation.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask);
+
+/**
+ * @brief Set hardware flow control.
+ *
+ * @param uart_num   UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param flow_ctrl Hardware flow control mode
+ * @param rx_thresh Threshold of Hardware RX flow control(0 ~ UART_FIFO_LEN).
+ *          Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh);
+
+/**
+ * @brief Get hardware flow control mode
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param flow_ctrl Option for different flow control mode.
+ *
+ * @return
+ *     - ESP_FAIL Parameter error
+ *     - ESP_OK   Success, result will be put in (*flow_ctrl)
+ */
+esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl);
+
+/**
+ * @brief Clear UART interrupt status
+ *
+ * @param uart_num   UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param clr_mask  Bit mask of the status that to be cleared.
+ *                  enable_mask should be chosen from the fields of register UART_INT_CLR_REG.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask);
+
+/**
+ * @brief Set UART interrupt enable
+ *
+ * @param uart_num      UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param enable_mask  Bit mask of the enable bits.
+ *                     enable_mask should be chosen from the fields of register UART_INT_ENA_REG.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask);
+
+/**
+ * @brief Clear UART interrupt enable bits
+ *
+ * @param uart_num       UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param disable_mask  Bit mask of the disable bits.
+ *                      disable_mask should be chosen from the fields of register UART_INT_ENA_REG.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask);
+
+
+/**
+ * @brief Enable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_rx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Disable UART RX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_rx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Disable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_disable_tx_intr(uart_port_t uart_num);
+
+/**
+ * @brief Enable UART TX interrupt(RX_FULL & RX_TIMEOUT INTERRUPT)
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param enable  1: enable; 0: disable
+ * @param thresh  Threshold of TX interrupt, 0 ~ UART_FIFO_LEN
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh);
+
+/**
+ * @brief register UART interrupt handler(ISR).
+ *
+ * @note UART ISR handler will be attached to the same CPU core that this function is running on.
+ * Users should know that which CPU is running and then pick a INUM that is not used by system.
+ * We can find the information of INUM and interrupt level in soc.h.
+ *
+ * @attention The ISR handler function MUST be defined with attribution of "IRAM_ATTR" for now.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
+ * @param fn  Interrupt handler function.
+ * @param arg parameter for handler function
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg);
+
+/**
+ * @brief Set UART pin number
+ *
+ * @note Internal signal can be output to multiple GPIO pads.
+ * Only one GPIO pad can connect with input signal.
+ *
+ * @param uart_num    UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param tx_io_num  UART TX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param rx_io_num  UART RX pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param rts_io_num UART RTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ * @param cts_io_num UART CTS pin GPIO number, if set to UART_PIN_NO_CHANGE, use the current pin.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num);
+
+/**
+ * @brief UART set RTS level (before inverse)
+ *          UART rx hardware flow control should not be set.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param level   1: RTS output low(active); 0: RTS output high(block)
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_rts(uart_port_t uart_num, int level);
+
+/**
+ * @brief UART set DTR level (before inverse)
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param level    1: DTR output low; 0: DTR output high
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_set_dtr(uart_port_t uart_num, int level);
+
+/**
+* @brief UART parameter configure
+ *
+ * @param uart_num     UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param uart_config UART parameter settings
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
+
+/**
+* @brief UART interrupt configure
+ *
+ * @param uart_num     UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param intr_conf UART interrupt settings
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf);
+
+/**
+ * @brief Install UART driver.
+ *
+ * UART ISR handler will be attached to the same CPU core that this function is running on.
+ * Users should know that which CPU is running and then pick a INUM that is not used by system.
+ * We can find the information of INUM and interrupt level in soc.h.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param rx_buffer_size UART RX ring buffer size
+ * @param tx_buffer_size UART TX ring buffer size.
+ *        If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out..
+ * @param queue_size UART event queue size/depth.
+ * @param uart_intr_num UART interrupt number,check the info in soc.h, and please refer to core-isa.h for more details
+ * @param uart_queue UART event queue handle, if set NULL, driver will not use an event queue.
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue);
+
+/**
+ * @brief Uninstall UART driver.
+ *
+ * @param uart_num  UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_driver_delete(uart_port_t uart_num);
+
+/**
+ * @brief Wait UART TX FIFO empty
+ *
+ * @param uart_num       UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param ticks_to_wait Timeout, count in RTOS ticks
+ *
+ * @return
+ *     - ESP_OK   Success
+ *     - ESP_FAIL Parameter error
+ *     - ESP_ERR_TIMEOUT  Timeout
+ */
+esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length.
+ * 
+ * This function will not wait for the space in TX FIFO, just fill the TX FIFO and return when the FIFO is full.
+ * @note This function should only be used when UART TX buffer is not enabled.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param buffer data buffer address
+ * @param len    data length to send
+ *
+ * @return
+ *     - (-1)  Parameter error
+ *     - OTHERS(>=0)  The number of data that pushed to the TX FIFO
+ */
+int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length,
+ *
+ * If parameter tx_buffer_size is set to zero:
+ * This function will not return until all the data have been sent out, or at least pushed into TX FIFO.
+ *
+ * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
+ * then, UART ISR will move data from ring buffer to TX FIFO gradually.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param src   data buffer address
+ * @param size  data length to send
+ *
+ * @return
+ *     - (-1) Parameter error
+ *     - OTHERS(>=0)  The number of data that pushed to the TX FIFO
+ */
+int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size);
+
+/**
+ * @brief Send data to the UART port from a given buffer and length,
+ *
+ * If parameter tx_buffer_size is set to zero:
+ * This function will not return until all the data and the break signal have been sent out.
+ * After all data send out, send a break signal.
+ *
+ * Otherwise, if tx_buffer_size > 0, this function will return after copying all the data to tx ringbuffer,
+ * then, UART ISR will move data from ring buffer to TX FIFO gradually.
+ * After all data send out, send a break signal.
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param src   data buffer address
+ * @param size  data length to send
+ * @param brk_len break signal length (unit: time of one data bit at current_baudrate)
+ *
+ * @return
+ *     - (-1) Parameter error
+ *     - OTHERS(>=0) The number of data that pushed to the TX FIFO
+ */
+
+int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len);
+
+/**
+ * @brief UART read bytes from UART buffer
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ * @param buf     pointer to the buffer.
+ * @param length  data length
+ * @param ticks_to_wait sTimeout, count in RTOS ticks
+ *
+ * @return
+ *     - (-1) Error
+ *     - Others return a char data from uart fifo.
+ */
+int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait);
+
+/**
+ * @brief UART ring buffer flush
+ *
+ * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2
+ *
+ * @return
+ *     - ESP_OK Success
+ *     - ESP_FAIL Parameter error
+ */
+esp_err_t uart_flush(uart_port_t uart_num);
+
+/***************************EXAMPLE**********************************
+ *
+ *
+ * ----------------EXAMPLE OF UART SETTING ---------------------
+ * @code{c}
+ * //1. Setup UART
+ * #include "freertos/queue.h"
+ * #define UART_INTR_NUM 17                                //choose one interrupt number from soc.h
+ * //a. Set UART parameter
+ * int uart_num = 0;                                       //uart port number
+ * uart_config_t uart_config = {
+ *    .baud_rate = UART_BITRATE_115200,                    //baudrate
+ *    .data_bits = UART_DATA_8_BITS,                       //data bit mode
+ *    .parity = UART_PARITY_DISABLE,                       //parity mode
+ *    .stop_bits = UART_STOP_BITS_1,                       //stop bit mode
+ *    .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,               //hardware flow control(cts/rts)
+ *    .rx_flow_ctrl_thresh = 120,                          //flow control threshold
+ * };
+ * uart_param_config(uart_num, &uart_config);
+ * //b1. Setup UART driver(with UART queue)
+ * QueueHandle_t uart_queue;
+ * //parameters here are just an example, tx buffer size is 2048
+ * uart_driver_install(uart_num, 1024 * 2, 1024 * 2, 10, UART_INTR_NUM, &uart_queue);
+ * //b2. Setup UART driver(without UART queue)
+ * //parameters here are just an example, tx buffer size is 0
+ * uart_driver_install(uart_num, 1024 * 2, 0, 10, UART_INTR_NUM, NULL);
+ *@endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //2. Set UART pin
+ * //set UART pin, not needed if use default pins.
+ * uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 15, 13);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //3. Read data from UART.
+ * uint8_t data[128];
+ * int length = 0;
+ * length = uart_read_bytes(uart_num, data, sizeof(data), 100);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //4. Write data to UART.
+ * char* test_str = "This is a test string.\n"
+ * uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //5. Write data to UART, end with a break signal.
+ * uart_write_bytes_with_break(0, "test break\n",strlen("test break\n"), 100);
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //6. an example of echo test with hardware flow control on UART1
+ * void uart_loop_back_test()
+ * {
+ *     int uart_num = 1;
+ *     uart_config_t uart_config = {
+ *         .baud_rate = 115200,
+ *         .data_bits = UART_DATA_8_BITS,
+ *         .parity = UART_PARITY_DISABLE,
+ *         .stop_bits = UART_STOP_BITS_1,
+ *         .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
+ *         .rx_flow_ctrl_thresh = 122,
+ *     };
+ *     //Configure UART1 parameters
+ *     uart_param_config(uart_num, &uart_config);
+ *     //Set UART1 pins(TX: IO16, RX: IO17, RTS: IO18, CTS: IO19)
+ *     uart_set_pin(uart_num, 16, 17, 18, 19);
+ *     //Install UART driver( We don't need an event queue here)
+ *     uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, NULL, RINGBUF_TYPE_BYTEBUF);
+ *     uint8_t data[1000];
+ *     while(1) {
+ *         //Read data from UART
+ *         int len = uart_read_bytes(uart_num, data, sizeof(data), 10);
+ *         //Write data back to UART
+ *         uart_write_bytes(uart_num, (const char*)data, len);
+ *     }
+ * }
+ * @endcode
+ *-----------------------------------------------------------------------------*
+ * @code{c}
+ * //7. An example of using UART event queue on UART0.
+ * #include "freertos/queue.h"
+ * //A queue to handle UART event.
+ * QueueHandle_t uart0_queue;
+ * static const char *TAG = "uart_example";
+ * void uart_task(void *pvParameters)
+ * {
+ *     int uart_num = (int)pvParameters;
+ *     uart_event_t event;
+ *     size_t size = 1024;
+ *     uint8_t* dtmp = (uint8_t*)malloc(size);
+ *     for(;;) {
+ *         //Waiting for UART event.
+ *         if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
+ *             ESP_LOGI(TAG, "uart[%d] event:", uart_num);
+ *             switch(event.type) {
+ *                 memset(dtmp, 0, size);
+ *                 //Event of UART receving data
+ *                 case UART_DATA:
+ *                     ESP_LOGI(TAG,"data, len: %d", event.size);
+ *                     int len = uart_read_bytes(uart_num, dtmp, event.size, 10);
+ *                     ESP_LOGI(TAG, "uart read: %d", len);
+                       uart_write_bytes(uart_num, (const char*)dtmp, len);
+ *                     break;
+ *                 //Event of HW FIFO overflow detected
+ *                 case UART_FIFO_OVF:
+ *                     ESP_LOGI(TAG, "hw fifo overflow\n");
+ *                     break;
+ *                 //Event of UART ring buffer full
+ *                 case UART_BUFFER_FULL:
+ *                     ESP_LOGI(TAG, "ring buffer full\n");
+ *                     break;
+ *                 //Event of UART RX break detected
+ *                 case UART_BREAK:
+ *                     ESP_LOGI(TAG, "uart rx break\n");
+ *                     break;
+ *                 //Event of UART parity check error
+ *                 case UART_PARITY_ERR:
+ *                     ESP_LOGI(TAG, "uart parity error\n");
+ *                     break;
+ *                 //Event of UART frame error
+ *                 case UART_FRAME_ERR:
+ *                     ESP_LOGI(TAG, "uart frame error\n");
+ *                     break;
+ *                 //Others
+ *                 default:
+ *                     ESP_LOGI(TAG, "uart event type: %d\n", event.type);
+ *                     break;
+ *             }
+ *        }
+ *     }
+ *     free(dtmp);
+ *     dtmp = NULL;
+ *     vTaskDelete(NULL);
+ * }
+ *
+ * void uart_queue_test()
+ * {
+ *     int uart_num = 0;
+ *     uart_config_t uart_config = {
+ *        .baud_rate = 115200,
+ *        .data_bits = UART_DATA_8_BITS,
+ *        .parity = UART_PARITY_DISABLE,
+ *        .stop_bits = UART_STOP_BITS_1,
+ *        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+ *        .rx_flow_ctrl_thresh = 122,
+ *     };
+ *     //Set UART parameters
+ *     uart_param_config(uart_num, &uart_config);
+ *     //Set UART pins,(-1: default pin, no change.)
+ *     uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
+ *     //Set UART log level
+ *     esp_log_level_set(TAG, ESP_LOG_INFO);
+ *     //Install UART driver, and get the queue.
+ *     uart_driver_install(uart_num, 1024 * 2, 1024*4, 10, 17, &uart0_queue);
+ *     //Create a task to handler UART event from ISR
+ *     xTaskCreate(uart_task, "uTask", 1024, (void*)uart_num, 10, NULL);
+ * }
+ * @endcode
+ *
+ ***************************END OF EXAMPLE**********************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_DRIVER_UART_H_*/

+ 56 - 167
components/driver/ledc.c

@@ -18,86 +18,19 @@
 #include "freertos/xtensa_api.h"
 #include "soc/gpio_sig_map.h"
 #include "driver/ledc.h"
+#include "esp_log.h"
 
-//TODO: to use APIs in esp_log.h.
-#define LEDC_DBG_WARING_ENABLE (0)
-#define LEDC_DBG_ERROR_ENABLE  (0)
-#define LEDC_INFO_ENABLE       (0)
-#define LEDC_DBG_ENABLE        (0)
-
-//DBG INFOR
-#if LEDC_DBG_ENABLE
-#define LEDC_DBG(format,...) do{\
-        ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else
-#define LEDC_DBG(...)
-#endif
-
-#if LEDC_INFO_ENABLE
-#define LEDC_INFO(format,...) do{\
-        ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else
-#define LEDC_INFO(...)
-#endif
-
-#if LEDC_DBG_WARING_ENABLE
-#define LEDC_WARING(format,...) do{\
-        ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else
-#define LEDC_WARING(...)
-#endif
-#if LEDC_DBG_ERROR_ENABLE
-#define LEDC_ERROR(format,...) do{\
-        ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
-        ets_printf(format,##__VA_ARGS__);\
-}while(0)
-#else
-#define LEDC_ERROR(...)
-#endif
-
+static const char* LEDC_TAG = "LEDC";
 static portMUX_TYPE ledc_spinlock = portMUX_INITIALIZER_UNLOCKED;
-
-static bool ledc_is_valid_channel(uint32_t channel)
-{
-    if(channel > LEDC_CHANNEL_7) {
-        LEDC_ERROR("LEDC CHANNEL ERR: %d\n",channel);
-        return false;
-    }
-    return true;
-}
-
-static bool ledc_is_valid_mode(uint32_t mode)
-{
-    if(mode >= LEDC_SPEED_MODE_MAX) {
-        LEDC_ERROR("LEDC MODE ERR: %d\n",mode);
-        return false;
-    }
-    return true;
-}
-
-static bool ledc_is_valid_timer(int timer)
-{
-    if(timer > LEDC_TIMER_3) {
-        LEDC_ERROR("LEDC TIMER ERR: %d\n", timer);
-        return false;
-    }
-    return true;
-}
+#define LEDC_CHECK(a, str, ret_val) if (!(a)) {                                         \
+        ESP_LOGE(LEDC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str);    \
+        return (ret_val);                                                               \
+        }
 
 esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_timer(timer_sel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.div_num = div_num;
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.tick_sel = clk_src;
@@ -125,12 +58,8 @@ static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num,
 
 esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_timer(timer_idx)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_idx <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
     portEXIT_CRITICAL(&ledc_spinlock);
@@ -139,12 +68,8 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint
 
 esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_timer(timer_sel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 1;
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.rst = 0;
@@ -154,12 +79,8 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel)
 
 esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_timer(timer_sel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
     portEXIT_CRITICAL(&ledc_spinlock);
@@ -168,12 +89,8 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel)
 
 esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_timer(timer_sel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_sel <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
     portEXIT_CRITICAL(&ledc_spinlock);
@@ -182,9 +99,7 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel)
 
 static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel, ledc_intr_type_t type)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
     uint32_t value;
     uint32_t intr_type = type;
     portENTER_CRITICAL(&ledc_spinlock);
@@ -200,9 +115,7 @@ static esp_err_t ledc_enable_intr_type(ledc_mode_t speed_mode, uint32_t channel,
 
 esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
 {
-    if(fn == NULL) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(fn, "ledc isr null", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     ESP_INTR_DISABLE(ledc_intr_num);
     intr_matrix_set(xPortGetCoreID(), ETS_LEDC_INTR_SOURCE, ledc_intr_num);
@@ -218,16 +131,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
     int bit_num = timer_conf->bit_num;
     int timer_num = timer_conf->timer_num;
     int speed_mode = timer_conf->speed_mode;
-
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
     if(freq_hz == 0 || bit_num == 0 || bit_num > LEDC_TIMER_15_BIT) {
-        LEDC_ERROR("freq_hz=%u bit_num=%u\n", freq_hz, bit_num);
+        ESP_LOGE(LEDC_TAG, "freq_hz=%u bit_num=%u", freq_hz, bit_num);
         return ESP_ERR_INVALID_ARG;
     }
     if(timer_num > LEDC_TIMER_3) {
-        LEDC_ERROR("Time Select %u\n", timer_num);
+        ESP_LOGE(LEDC_TAG, "Time Select %u", timer_num);
         return ESP_ERR_INVALID_ARG;
     }
     esp_err_t ret = ESP_OK;
@@ -239,7 +149,7 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
         /*Selet the reference tick*/
         div_param = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
         if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) {
-            LEDC_ERROR("div param err,div_param=%u\n", div_param);
+            ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", (uint32_t)div_param);
             ret = ESP_FAIL;
         }
         timer_clk_src = LEDC_REF_TICK;
@@ -254,6 +164,21 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
     return ret;
 }
 
+esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
+{
+    LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
+    gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
+    if(speed_mode == LEDC_HIGH_SPEED_MODE) {
+        gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
+    } else {
+
+    }
+    return ESP_OK;
+}
+
 esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
 {
     uint32_t speed_mode = ledc_conf->speed_mode;
@@ -262,21 +187,10 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
     uint32_t timer_select = ledc_conf->timer_sel;
     uint32_t intr_type = ledc_conf->intr_type;
     uint32_t duty = ledc_conf->duty;
-
-    if(!ledc_is_valid_channel(ledc_channel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!GPIO_IS_VALID_OUTPUT_GPIO(gpio_num)) {
-        LEDC_ERROR("GPIO number error: IO%d\n ", gpio_num);
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(timer_select > LEDC_TIMER_3) {
-        LEDC_ERROR("Time Select %u\n", timer_select);
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(ledc_channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "ledc GPIO output number error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(timer_select <= LEDC_TIMER_3, "ledc timer error", ESP_ERR_INVALID_ARG);
     esp_err_t ret = ESP_OK;
     /*set channel parameters*/
     /*   channel parameters decide how the waveform looks like in one period*/
@@ -288,7 +202,7 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
     ledc_bind_channel_timer(speed_mode, ledc_channel, timer_select);
     /*set interrupt type*/
     ledc_enable_intr_type(speed_mode, ledc_channel, intr_type);
-    LEDC_INFO("LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u\n",
+    ESP_LOGI(LEDC_TAG, "LEDC_PWM CHANNEL %1u|GPIO %02u|Duty %04u|Time %01u",
         ledc_channel, gpio_num, duty, timer_select
     );
     /*set LEDC signal in gpio matrix*/
@@ -300,12 +214,8 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
 
 esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_channel(channel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 1;
     LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 1;
@@ -315,12 +225,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
 
 esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_channel(channel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     LEDC.channel_group[speed_mode].channel[channel].conf0.idle_lv = idle_level & 0x1;
     LEDC.channel_group[speed_mode].channel[channel].conf0.sig_out_en = 0;
@@ -331,18 +237,11 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl
 esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t fade_direction,
     uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_channel(channel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(fade_direction > LEDC_DUTY_DIR_INCREASE) {
-        LEDC_ERROR("Duty direction err\n");
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(fade_direction <= LEDC_DUTY_DIR_INCREASE, "ledc fade direction error", ESP_ERR_INVALID_ARG);
     if(step_num > LEDC_DUTY_NUM_HSCH0_V || duty_cyle_num > LEDC_DUTY_CYCLE_HSCH0_V || duty_scale > LEDC_DUTY_SCALE_HSCH0_V) {
-        LEDC_ERROR("step_num=%u duty_cyle_num=%u duty_scale=%u\n", step_num, duty_cyle_num, duty_scale);
+        ESP_LOGE(LEDC_TAG, "step_num=%u duty_cyle_num=%u duty_scale=%u", step_num, duty_cyle_num, duty_scale);
         return ESP_ERR_INVALID_ARG;
     }
     ledc_duty_config(speed_mode,
@@ -359,12 +258,8 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty,
 
 esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
-    if(!ledc_is_valid_channel(channel)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
+    LEDC_CHECK(channel <= LEDC_CHANNEL_7, "ledc channel error", ESP_ERR_INVALID_ARG);
     ledc_duty_config(speed_mode,
                      channel,         //uint32_t chan_num,
                      0,               //uint32_t hpoint_val,
@@ -379,18 +274,14 @@ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t
 
 int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return -1;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (-1));
     uint32_t duty = (LEDC.channel_group[speed_mode].channel[channel].duty_rd.duty_read >> 4);
     return duty;
 }
 
 esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return ESP_ERR_INVALID_ARG;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", ESP_ERR_INVALID_ARG);
     portENTER_CRITICAL(&ledc_spinlock);
     esp_err_t ret = ESP_OK;
     uint32_t div_num = 0;
@@ -403,7 +294,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
         div_num = ((uint64_t) LEDC_REF_CLK_HZ << 8) / freq_hz / precision;
     }
     if(div_num <= 256 || div_num > LEDC_DIV_NUM_HSTIMER0) {
-        LEDC_ERROR("div param err,div_param=%u\n", div_num);
+        ESP_LOGE(LEDC_TAG, "div param err,div_param=%u", div_num);
         ret = ESP_FAIL;
     }
     LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num;
@@ -413,9 +304,7 @@ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t
 
 uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
 {
-    if(!ledc_is_valid_mode(speed_mode)) {
-        return 0;
-    }
+    LEDC_CHECK(speed_mode < LEDC_SPEED_MODE_MAX, "ledc mode error", (0));
     portENTER_CRITICAL(&ledc_spinlock);
     uint32_t freq = 0;
     uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;

+ 1027 - 0
components/driver/uart.c

@@ -0,0 +1,1027 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#include <string.h>
+#include "esp_types.h"
+#include "esp_attr.h"
+#include "esp_intr.h"
+#include "esp_log.h"
+#include "malloc.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/task.h"
+#include "freertos/ringbuf.h"
+#include "soc/dport_reg.h"
+#include "soc/uart_struct.h"
+#include "driver/uart.h"
+#include "driver/gpio.h"
+
+static const char* UART_TAG = "UART";
+#define UART_CHECK(a, str, ret) if (!(a)) {                                             \
+        ESP_LOGE(UART_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str);    \
+        return (ret);                                                                   \
+        }
+#define UART_EMPTY_THRESH_DEFAULT  (10)
+#define UART_FULL_THRESH_DEFAULT  (120)
+#define UART_TOUT_THRESH_DEFAULT   (10)
+#define UART_ENTER_CRITICAL_ISR(mux)    portENTER_CRITICAL_ISR(mux)
+#define UART_EXIT_CRITICAL_ISR(mux)     portEXIT_CRITICAL_ISR(mux)
+#define UART_ENTER_CRITICAL(mux)    portENTER_CRITICAL(mux)
+#define UART_EXIT_CRITICAL(mux)     portEXIT_CRITICAL(mux)
+
+typedef struct {
+    uart_event_type_t type;        /*!< UART TX data type */
+    struct {
+        int brk_len;
+        size_t size;
+        uint8_t data[0];
+    } tx_data;
+} uart_tx_data_t;
+
+typedef struct {
+    uart_port_t uart_num;               /*!< UART port number*/
+    int queue_size;                     /*!< UART event queue size*/
+    QueueHandle_t xQueueUart;           /*!< UART queue handler*/
+    int intr_num;                       /*!< UART interrupt number*/
+    //rx parameters
+    SemaphoreHandle_t rx_mux;           /*!< UART RX data mutex*/
+    int rx_buf_size;                    /*!< RX ring buffer size */
+    RingbufHandle_t rx_ring_buf;        /*!< RX ring buffer handler*/
+    bool rx_buffer_full_flg;            /*!< RX ring buffer full flag. */
+    int rx_cur_remain;                  /*!< Data number that waiting to be read out in ring buffer item*/
+    uint8_t* rx_ptr;                    /*!< pointer to the current data in ring buffer*/
+    uint8_t* rx_head_ptr;               /*!< pointer to the head of RX item*/
+    uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/
+    uint8_t rx_stash_len;               /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */
+    //tx parameters
+    SemaphoreHandle_t tx_fifo_sem;      /*!< UART TX FIFO semaphore*/
+    SemaphoreHandle_t tx_mux;           /*!< UART TX mutex*/
+    SemaphoreHandle_t tx_done_sem;      /*!< UART TX done semaphore*/
+    SemaphoreHandle_t tx_brk_sem;       /*!< UART TX send break done semaphore*/
+    int tx_buf_size;                    /*!< TX ring buffer size */
+    RingbufHandle_t tx_ring_buf;        /*!< TX ring buffer handler*/
+    bool tx_waiting_fifo;               /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/
+    uint8_t* tx_ptr;                    /*!< TX data pointer to push to FIFO in TX buffer mode*/
+    uart_tx_data_t* tx_head;            /*!< TX data pointer to head of the current buffer in TX ring buffer*/
+    uint32_t tx_len_tot;                /*!< Total length of current item in ring buffer*/
+    uint32_t tx_len_cur;
+    uint8_t tx_brk_flg;                 /*!< Flag to indicate to send a break signal in the end of the item sending procedure */
+    uint8_t tx_brk_len;                 /*!< TX break signal cycle length/number */
+    uint8_t tx_waiting_brk;             /*!< Flag to indicate that TX FIFO is ready to send break signal after FIFO is empty, do not push data into TX FIFO right now.*/
+} uart_obj_t;
+
+
+
+static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};
+static uart_dev_t* UART[UART_NUM_MAX] = {&UART0, &UART1, &UART2};
+static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = {portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED, portMUX_INITIALIZER_UNLOCKED};
+
+esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.bit_num = data_bit;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    *(data_bit) = UART[uart_num]->conf0.bit_num;
+    return ESP_OK;
+}
+
+esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.stop_bit_num = stop_bit;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    (*stop_bit) = UART[uart_num]->conf0.stop_bit_num;
+    return ESP_OK;
+}
+
+esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.parity = parity_mode & 0x1;
+    UART[uart_num]->conf0.parity_en = (parity_mode >> 1) & 0x1;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    int val = UART[uart_num]->conf0.val;
+    if(val & UART_PARITY_EN_M) {
+        if(val & UART_PARITY_M) {
+            (*parity_mode) = UART_PARITY_ODD;
+        } else {
+            (*parity_mode) = UART_PARITY_EVEN;
+        }
+    } else {
+        (*parity_mode) = UART_PARITY_DISABLE;
+    }
+    return ESP_OK;
+}
+
+esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((baud_rate < UART_BITRATE_MAX), "baud_rate error", ESP_FAIL);
+    uint32_t clk_div = (((UART_CLK_FREQ) << 4) / baud_rate);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->clk_div.div_int = clk_div >> 4;
+    UART[uart_num]->clk_div.div_frag = clk_div & 0xf;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    uint32_t clk_div = (UART[uart_num]->clk_div.div_int << 4) | UART[uart_num]->clk_div.div_frag;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    (*baudrate) = ((UART_CLK_FREQ) << 4) / clk_div;
+    return ESP_OK;
+}
+
+esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((((inverse_mask & UART_LINE_INV_MASK) == 0) && (inverse_mask != 0)), "inverse_mask error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    CLEAR_PERI_REG_MASK(UART_CONF0_REG(uart_num), UART_LINE_INV_MASK);
+    SET_PERI_REG_MASK(UART_CONF0_REG(uart_num), inverse_mask);
+    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)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((rx_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL);
+    UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    if(flow_ctrl & UART_HW_FLOWCTRL_RTS) {
+        UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh;
+        UART[uart_num]->conf1.rx_flow_en = 1;
+    } else {
+        UART[uart_num]->conf1.rx_flow_en = 0;
+    }
+    if(flow_ctrl & UART_HW_FLOWCTRL_CTS) {
+        UART[uart_num]->conf0.tx_flow_en = 1;
+    } else {
+        UART[uart_num]->conf0.tx_flow_en = 0;
+    }
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE;
+    if(UART[uart_num]->conf1.rx_flow_en) {
+        val |= UART_HW_FLOWCTRL_RTS;
+    }
+    if(UART[uart_num]->conf0.tx_flow_en) {
+        val |= UART_HW_FLOWCTRL_CTS;
+    }
+    (*flow_ctrl) = val;
+    return ESP_OK;
+}
+
+static esp_err_t uart_reset_fifo(uart_port_t uart_num)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.rxfifo_rst = 1;
+    UART[uart_num]->conf0.rxfifo_rst = 0;
+    UART[uart_num]->conf0.txfifo_rst = 1;
+    UART[uart_num]->conf0.txfifo_rst = 0;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    //intr_clr register is write-only
+    UART[uart_num]->int_clr.val = clr_mask;
+    return ESP_OK;
+}
+
+esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask);
+    SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask);
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask);
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_enable_rx_intr(uart_port_t uart_num)
+{
+    uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+    return ESP_OK;
+}
+
+esp_err_t uart_disable_rx_intr(uart_port_t uart_num)
+{
+    uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA);
+    return ESP_OK;
+}
+
+esp_err_t uart_disable_tx_intr(uart_port_t uart_num)
+{
+    uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA);
+    return ESP_OK;
+}
+
+esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->int_clr.txfifo_empty = 1;
+    UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V;
+    UART[uart_num]->int_ena.txfifo_empty = enable & 0x1;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    ESP_INTR_ENABLE(p_uart_obj[uart_num]->intr_num);
+    return ESP_OK;
+}
+
+esp_err_t uart_isr_register(uart_port_t uart_num, uint8_t uart_intr_num, void (*fn)(void*), void * arg)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    ESP_INTR_DISABLE(uart_intr_num);
+    switch(uart_num) {
+        case UART_NUM_1:
+            intr_matrix_set(xPortGetCoreID(), ETS_UART1_INTR_SOURCE, uart_intr_num);
+            break;
+        case UART_NUM_2:
+            intr_matrix_set(xPortGetCoreID(), ETS_UART2_INTR_SOURCE, uart_intr_num);
+            break;
+        case UART_NUM_0:
+            default:
+            intr_matrix_set(xPortGetCoreID(), ETS_UART0_INTR_SOURCE, uart_intr_num);
+            break;
+    }
+    xt_set_interrupt_handler(uart_intr_num, fn, arg);
+    ESP_INTR_ENABLE(uart_intr_num);
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+//internal signal can be output to multiple GPIO pads
+//only one GPIO pad can connect with input signal
+esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((tx_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(tx_io_num))), "tx_io_num error", ESP_FAIL);
+    UART_CHECK((rx_io_num < 0 || (GPIO_IS_VALID_GPIO(rx_io_num))), "rx_io_num error", ESP_FAIL);
+    UART_CHECK((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), "rts_io_num error", ESP_FAIL);
+    UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL);
+
+    int tx_sig, rx_sig, rts_sig, cts_sig;
+    switch(uart_num) {
+        case UART_NUM_0:
+            tx_sig = U0TXD_OUT_IDX;
+            rx_sig = U0RXD_IN_IDX;
+            rts_sig = U0RTS_OUT_IDX;
+            cts_sig = U0CTS_IN_IDX;
+            break;
+        case UART_NUM_1:
+            tx_sig = U1TXD_OUT_IDX;
+            rx_sig = U1RXD_IN_IDX;
+            rts_sig = U1RTS_OUT_IDX;
+            cts_sig = U1CTS_IN_IDX;
+            break;
+        case UART_NUM_2:
+            tx_sig = U2TXD_OUT_IDX;
+            rx_sig = U2RXD_IN_IDX;
+            rts_sig = U2RTS_OUT_IDX;
+            cts_sig = U2CTS_IN_IDX;
+            break;
+        case UART_NUM_MAX:
+            default:
+            tx_sig = U0TXD_OUT_IDX;
+            rx_sig = U0RXD_IN_IDX;
+            rts_sig = U0RTS_OUT_IDX;
+            cts_sig = U0CTS_IN_IDX;
+            break;
+    }
+    if(tx_io_num >= 0) {
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO);
+        gpio_set_direction(tx_io_num, GPIO_MODE_OUTPUT);
+        gpio_matrix_out(tx_io_num, tx_sig, 0, 0);
+    }
+
+    if(rx_io_num >= 0) {
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO);
+        gpio_set_direction(rx_io_num, GPIO_MODE_INPUT);
+        gpio_matrix_in(rx_io_num, rx_sig, 0);
+    }
+    if(rts_io_num >= 0) {
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO);
+        gpio_set_direction(rts_io_num, GPIO_MODE_OUTPUT);
+        gpio_matrix_out(rts_io_num, rts_sig, 0, 0);
+    }
+    if(cts_io_num >= 0) {
+        PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO);
+        gpio_set_direction(cts_io_num, GPIO_MODE_INPUT);
+        gpio_matrix_in(cts_io_num, cts_sig, 0);
+    }
+    return ESP_OK;
+}
+
+esp_err_t uart_set_rts(uart_port_t uart_num, int level)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using sw control", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.sw_rts = level & 0x1;
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_set_dtr(uart_port_t uart_num, int level)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->conf0.sw_dtr = level & 0x1;
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((uart_config), "param null", ESP_FAIL);
+    if(uart_num == UART_NUM_0) {
+        periph_module_enable(PERIPH_UART0_MODULE);
+    } else if(uart_num == UART_NUM_1) {
+        periph_module_enable(PERIPH_UART1_MODULE);
+    } else if(uart_num == UART_NUM_2) {
+        periph_module_enable(PERIPH_UART2_MODULE);
+    }
+    uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh);
+    uart_set_baudrate(uart_num, uart_config->baud_rate);
+    UART[uart_num]->conf0.val = (
+        (uart_config->parity << UART_PARITY_S)
+            | (uart_config->stop_bits << UART_STOP_BIT_NUM_S)
+            | (uart_config->data_bits << UART_BIT_NUM_S)
+            | ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0)
+            | UART_TICK_REF_ALWAYS_ON_M);
+    return ESP_OK;
+}
+
+esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((intr_conf), "param null", ESP_FAIL);
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->int_clr.val = UART_INTR_MASK;
+    if(intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) {
+        UART[uart_num]->conf1.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V);
+        UART[uart_num]->conf1.rx_tout_en = 1;
+    } else {
+        UART[uart_num]->conf1.rx_tout_en = 0;
+    }
+    if(intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) {
+        UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh;
+    }
+    if(intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) {
+        UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh;
+    }
+    UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_FAIL;
+}
+
+//internal isr handler for default driver code.
+static void IRAM_ATTR uart_rx_intr_handler_default(void *param)
+{
+    uart_obj_t *p_uart = (uart_obj_t*) param;
+    uint8_t uart_num = p_uart->uart_num;
+    uart_dev_t* uart_reg = UART[uart_num];
+    uint8_t buf_idx = 0;
+    uint32_t uart_intr_status = UART[uart_num]->int_st.val;
+    int rx_fifo_len = 0;
+    uart_event_t uart_event;
+    portBASE_TYPE HPTaskAwoken = 0;
+
+    while(uart_intr_status != 0x0) {
+        buf_idx = 0;
+        uart_event.type = UART_EVENT_MAX;
+        if(uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) {
+            UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_reg->int_ena.txfifo_empty = 0;
+            uart_reg->int_clr.txfifo_empty = 1;
+            UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            if(p_uart->tx_waiting_brk) {
+                continue;
+            }
+            //TX semaphore will only be used when tx_buf_size is zero.
+            if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) {
+                p_uart->tx_waiting_fifo = false;
+                xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken);
+                if(HPTaskAwoken == pdTRUE) {
+                    portYIELD_FROM_ISR() ;
+                }
+            }
+            else {
+                //We don't use TX ring buffer, because the size is zero.
+                if(p_uart->tx_buf_size == 0) {
+                    continue;
+                }
+                int tx_fifo_rem = UART_FIFO_LEN - UART[uart_num]->status.txfifo_cnt;
+                bool en_tx_flg = false;
+                //We need to put a loop here, in case all the buffer items are very short.
+                //That would cause a watch_dog reset because empty interrupt happens so often.
+                //Although this is a loop in ISR, this loop will execute at most 128 turns.
+                while(tx_fifo_rem) {
+                    if(p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) {
+                        size_t size;
+                        p_uart->tx_head = (uart_tx_data_t*) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size);
+                        if(p_uart->tx_head) {
+                            //The first item is the data description
+                            //Get the first item to get the data information
+                            if(p_uart->tx_len_tot == 0) {
+                                p_uart->tx_ptr = NULL;
+                                p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
+                                if(p_uart->tx_head->type == UART_DATA_BREAK) {
+                                    p_uart->tx_len_tot = p_uart->tx_head->tx_data.size;
+                                    p_uart->tx_brk_flg = 1;
+                                    p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len;
+                                }
+                                //We have saved the data description from the 1st item, return buffer.
+                                vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
+                                if(HPTaskAwoken == pdTRUE) {
+                                    portYIELD_FROM_ISR() ;
+                                }
+                            }else if(p_uart->tx_ptr == NULL) {
+                                //Update the TX item pointer, we will need this to return item to buffer.
+                                p_uart->tx_ptr =  (uint8_t*) p_uart->tx_head;
+                                en_tx_flg = true;
+                                p_uart->tx_len_cur = size;
+                            }
+                        }
+                        else {
+                            //Can not get data from ring buffer, return;
+                            break;
+                        }
+                    }
+                    if(p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) {
+                        //To fill the TX FIFO.
+                        int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur;
+                        for(buf_idx = 0; buf_idx < send_len; buf_idx++) {
+                            WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), *(p_uart->tx_ptr++) & 0xff);
+                        }
+                        p_uart->tx_len_tot -= send_len;
+                        p_uart->tx_len_cur -= send_len;
+                        tx_fifo_rem -= send_len;
+                        if(p_uart->tx_len_cur == 0) {
+                            //Return item to ring buffer.
+                            vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken);
+                            if(HPTaskAwoken == pdTRUE) {
+                                portYIELD_FROM_ISR() ;
+                            }
+                            p_uart->tx_head = NULL;
+                            p_uart->tx_ptr = NULL;
+                            //Sending item done, now we need to send break if there is a record.
+                            //Set TX break signal after FIFO is empty
+                            if(p_uart->tx_brk_flg == 1 && p_uart->tx_len_tot == 0) {
+                                UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                                uart_reg->int_ena.tx_brk_done = 0;
+                                uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len;
+                                uart_reg->conf0.txd_brk = 1;
+                                uart_reg->int_clr.tx_brk_done = 1;
+                                uart_reg->int_ena.tx_brk_done = 1;
+                                UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                                p_uart->tx_waiting_brk = 1;
+                            } else {
+                                //enable TX empty interrupt
+                                en_tx_flg = true;
+                            }
+                        } else {
+                            //enable TX empty interrupt
+                            en_tx_flg = true;
+                        }
+                    }
+                }
+                if(en_tx_flg) {
+                    UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                    uart_reg->int_clr.txfifo_empty = 1;
+                    uart_reg->int_ena.txfifo_empty = 1;
+                    UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                }
+            }
+        }
+        else if((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M)) {
+            if(p_uart->rx_buffer_full_flg == false) {
+                //Get the buffer from the FIFO
+                rx_fifo_len = uart_reg->status.rxfifo_cnt;
+                p_uart->rx_stash_len = rx_fifo_len;
+                //We have to read out all data in RX FIFO to clear the interrupt signal
+                while(buf_idx < rx_fifo_len) {
+                    p_uart->rx_data_buf[buf_idx++] = uart_reg->fifo.rw_byte;
+                }
+                //After Copying the Data From FIFO ,Clear intr_status
+                UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                uart_reg->int_clr.rxfifo_tout = 1;
+                uart_reg->int_clr.rxfifo_full = 1;
+                UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                uart_event.type = UART_DATA;
+                uart_event.size = rx_fifo_len;
+                //If we fail to push data to ring buffer, we will have to stash the data, and send next time.
+                //Mainly for applications that uses flow control or small ring buffer.
+                if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) {
+                    UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                    uart_reg->int_ena.rxfifo_full = 0;
+                    uart_reg->int_ena.rxfifo_tout = 0;
+                    UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                    p_uart->rx_buffer_full_flg = true;
+                    uart_event.type = UART_BUFFER_FULL;
+                } else {
+                    uart_event.type = UART_DATA;
+                }
+                if(HPTaskAwoken == pdTRUE) {
+                    portYIELD_FROM_ISR() ;
+                }
+            } else {
+                UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                uart_reg->int_ena.rxfifo_full = 0;
+                uart_reg->int_ena.rxfifo_tout = 0;
+                uart_reg->int_clr.val = UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M;
+                UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+                uart_event.type = UART_BUFFER_FULL;
+            }
+        } else if(uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) {
+            UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_reg->conf0.rxfifo_rst = 1;
+            uart_reg->conf0.rxfifo_rst = 0;
+            uart_reg->int_clr.rxfifo_ovf = 1;
+            UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_event.type = UART_FIFO_OVF;
+        } else if(uart_intr_status & UART_BRK_DET_INT_ST_M) {
+            uart_reg->int_clr.brk_det = 1;
+            uart_event.type = UART_BREAK;
+        } else if(uart_intr_status & UART_PARITY_ERR_INT_ST_M ) {
+            uart_reg->int_clr.parity_err = 1;
+            uart_event.type = UART_FRAME_ERR;
+        } else if(uart_intr_status & UART_FRM_ERR_INT_ST_M) {
+            uart_reg->int_clr.frm_err = 1;
+            uart_event.type = UART_PARITY_ERR;
+        } else if(uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) {
+            UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_reg->conf0.txd_brk = 0;
+            uart_reg->int_ena.tx_brk_done = 0;
+            uart_reg->int_clr.tx_brk_done = 1;
+            if(p_uart->tx_brk_flg == 1) {
+                uart_reg->int_ena.txfifo_empty = 1;
+            }
+            UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            if(p_uart->tx_brk_flg == 1) {
+                p_uart->tx_brk_flg = 0;
+                p_uart->tx_waiting_brk = 0;
+            } else {
+                xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken);
+                if(HPTaskAwoken == pdTRUE) {
+                    portYIELD_FROM_ISR() ;
+                }
+            }
+        } else if(uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) {
+            UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_reg->int_ena.tx_brk_idle_done = 0;
+            uart_reg->int_clr.tx_brk_idle_done = 1;
+            UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+        } else if(uart_intr_status & UART_TX_DONE_INT_ST_M) {
+            UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            uart_reg->int_ena.tx_done = 0;
+            uart_reg->int_clr.tx_done = 1;
+            UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]);
+            xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken);
+            if(HPTaskAwoken == pdTRUE) {
+                portYIELD_FROM_ISR() ;
+            }
+        }
+        else {
+            uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/
+            uart_event.type = UART_EVENT_MAX;
+        }
+
+        if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) {
+            xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken);
+            if(HPTaskAwoken == pdTRUE) {
+                portYIELD_FROM_ISR() ;
+            }
+        }
+        uart_intr_status = uart_reg->int_st.val;
+    }
+}
+
+/**************************************************************/
+esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
+    BaseType_t res;
+    portTickType ticks_end = xTaskGetTickCount() + ticks_to_wait;
+    //Take tx_mux
+    res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait);
+    if(res == pdFALSE) {
+        return ESP_ERR_TIMEOUT;
+    }
+    ticks_to_wait = ticks_end - xTaskGetTickCount();
+    xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0);
+    ticks_to_wait = ticks_end - xTaskGetTickCount();
+    if(UART[uart_num]->status.txfifo_cnt == 0) {
+        xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+        return ESP_OK;
+    }
+    uart_enable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
+    //take 2nd tx_done_sem, wait given from ISR
+    res = xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, (portTickType)ticks_to_wait);
+    if(res == pdFALSE) {
+        uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M);
+        xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+        return ESP_ERR_TIMEOUT;
+    }
+    xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+    return ESP_OK;
+}
+
+static esp_err_t uart_set_break(uart_port_t uart_num, int break_num)
+{
+    UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+    UART[uart_num]->idle_conf.tx_brk_num = break_num;
+    UART[uart_num]->conf0.txd_brk = 1;
+    UART[uart_num]->int_clr.tx_brk_done = 1;
+    UART[uart_num]->int_ena.tx_brk_done = 1;
+    UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+    return ESP_OK;
+}
+
+//Fill UART tx_fifo and return a number,
+//This function by itself is not thread-safe, always call from within a muxed section.
+static int uart_fill_fifo(uart_port_t uart_num, const char* buffer, uint32_t len)
+{
+    uint8_t i = 0;
+    uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt;
+    uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt);
+    uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len);
+    for(i = 0; i < copy_cnt; i++) {
+        WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), buffer[i]);
+    }
+    return copy_cnt;
+}
+
+int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+    UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+    UART_CHECK(buffer, "buffer null", (-1));
+    if(len == 0) {
+        return 0;
+    }
+    xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);
+    int tx_len = uart_fill_fifo(uart_num, (const char*) buffer, len);
+    xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+    return tx_len;
+}
+
+static int uart_tx_all(uart_port_t uart_num, const char* src, size_t size, bool brk_en, int brk_len)
+{
+    if(size == 0) {
+        return 0;
+    }
+    size_t original_size = size;
+
+    //lock for uart_tx
+    xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY);
+    if(p_uart_obj[uart_num]->tx_buf_size > 0) {
+        int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf);
+        int offset = 0;
+        uart_tx_data_t evt;
+        evt.tx_data.size = size;
+        evt.tx_data.brk_len = brk_len;
+        if(brk_en) {
+            evt.type = UART_DATA_BREAK;
+        } else {
+            evt.type = UART_DATA;
+        }
+        xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) &evt, sizeof(uart_tx_data_t), portMAX_DELAY);
+        while(size > 0) {
+            int send_size = size > max_size / 2 ? max_size / 2 : size;
+            xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) (src + offset), send_size, portMAX_DELAY);
+            size -= send_size;
+            offset += send_size;
+        }
+        xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+        uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);
+    } else {
+        while(size) {
+            //semaphore for tx_fifo available
+            if(pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) {
+                size_t sent = uart_fill_fifo(uart_num, (char*) src, size);
+                if(sent < size) {
+                    p_uart_obj[uart_num]->tx_waiting_fifo = true;
+                    uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);
+                }
+                size -= sent;
+                src += sent;
+            }
+        }
+        if(brk_en) {
+            uart_set_break(uart_num, brk_len);
+            xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (portTickType)portMAX_DELAY);
+        }
+        xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
+    }
+    xSemaphoreGive(p_uart_obj[uart_num]->tx_mux);
+    return original_size;
+}
+
+int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+    UART_CHECK((p_uart_obj[uart_num] != NULL), "uart driver error", (-1));
+    UART_CHECK(src, "buffer null", (-1));
+    return uart_tx_all(uart_num, src, size, 0, 0);
+}
+
+int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+    UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+    UART_CHECK((size > 0), "uart size error", (-1));
+    UART_CHECK((src), "uart data null", (-1));
+    UART_CHECK((brk_len > 0 && brk_len < 256), "break_num error", (-1));
+    return uart_tx_all(uart_num, src, size, 1, brk_len);
+}
+
+int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1));
+    UART_CHECK((buf), "uart_num error", (-1));
+    UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1));
+    uint8_t* data = NULL;
+    size_t size;
+    size_t copy_len = 0;
+    int len_tmp;
+    if(xSemaphoreTake(p_uart_obj[uart_num]->rx_mux,(portTickType)ticks_to_wait) != pdTRUE) {
+        return -1;
+    }
+    while(length) {
+        if(p_uart_obj[uart_num]->rx_cur_remain == 0) {
+            data = (uint8_t*) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait);
+            if(data) {
+                p_uart_obj[uart_num]->rx_head_ptr = data;
+                p_uart_obj[uart_num]->rx_ptr = data;
+                p_uart_obj[uart_num]->rx_cur_remain = size;
+            } else {
+                xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
+                return copy_len;
+            }
+        }
+        if(p_uart_obj[uart_num]->rx_cur_remain > length) {
+            len_tmp = length;
+        } else {
+            len_tmp = p_uart_obj[uart_num]->rx_cur_remain;
+        }
+        memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp);
+        p_uart_obj[uart_num]->rx_ptr += len_tmp;
+        p_uart_obj[uart_num]->rx_cur_remain -= len_tmp;
+        copy_len += len_tmp;
+        length -= len_tmp;
+        if(p_uart_obj[uart_num]->rx_cur_remain == 0) {
+            vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr);
+            p_uart_obj[uart_num]->rx_head_ptr = NULL;
+            p_uart_obj[uart_num]->rx_ptr = NULL;
+            if(p_uart_obj[uart_num]->rx_buffer_full_flg) {
+                BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1);
+                if(res == pdTRUE) {
+                    p_uart_obj[uart_num]->rx_buffer_full_flg = false;
+                    uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num);
+                }
+            }
+        }
+    }
+    xSemaphoreGive(p_uart_obj[uart_num]->rx_mux);
+    return copy_len;
+}
+
+esp_err_t uart_flush(uart_port_t uart_num)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL);
+    uart_obj_t* p_uart = p_uart_obj[uart_num];
+    uint8_t* data;
+    size_t size;
+
+    //rx sem protect the ring buffer read related functions
+    xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY);
+    ESP_INTR_DISABLE(p_uart->intr_num);
+    while(true) {
+        if(p_uart->rx_head_ptr) {
+            vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr);
+            p_uart->rx_ptr = NULL;
+            p_uart->rx_cur_remain = 0;
+            p_uart->rx_head_ptr = NULL;
+        }
+        data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0);
+        if(data == NULL) {
+            break;
+        }
+        vRingbufferReturnItem(p_uart->rx_ring_buf, data);
+    }
+    p_uart->rx_ptr = NULL;
+    p_uart->rx_cur_remain = 0;
+    p_uart->rx_head_ptr = NULL;
+    ESP_INTR_ENABLE(p_uart->intr_num);
+    xSemaphoreGive(p_uart->rx_mux);
+
+    if(p_uart->tx_buf_size > 0) {
+        xSemaphoreTake(p_uart->tx_mux, (portTickType)portMAX_DELAY);
+        ESP_INTR_DISABLE(p_uart->intr_num);
+        UART_ENTER_CRITICAL(&uart_spinlock[uart_num]);
+        UART[uart_num]->int_ena.txfifo_empty = 0;
+        UART[uart_num]->int_clr.txfifo_empty = 1;
+        UART_EXIT_CRITICAL(&uart_spinlock[uart_num]);
+        do {
+            data = (uint8_t*) xRingbufferReceive(p_uart->tx_ring_buf, &size, (portTickType) 0);
+            if(data == NULL) {
+                break;
+            }
+            vRingbufferReturnItem(p_uart->rx_ring_buf, data);
+        } while(1);
+        p_uart->tx_brk_flg = 0;
+        p_uart->tx_brk_len = 0;
+        p_uart->tx_head = NULL;
+        p_uart->tx_len_cur = 0;
+        p_uart->tx_len_tot = 0;
+        p_uart->tx_ptr = NULL;
+        p_uart->tx_waiting_brk = 0;
+        p_uart->tx_waiting_fifo = false;
+        ESP_INTR_ENABLE(p_uart->intr_num);
+        xSemaphoreGive(p_uart->tx_mux);
+    }
+    uart_reset_fifo(uart_num);
+    return ESP_OK;
+}
+
+esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, int uart_intr_num, void* uart_queue)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    UART_CHECK((rx_buffer_size > 0), "uart rx buffer length error", ESP_FAIL);
+    if(p_uart_obj[uart_num] == NULL) {
+        ESP_INTR_DISABLE(uart_intr_num);
+        p_uart_obj[uart_num] = (uart_obj_t*) malloc(sizeof(uart_obj_t));
+        if(p_uart_obj[uart_num] == NULL) {
+            ESP_LOGE(UART_TAG, "UART driver malloc error");
+            return ESP_FAIL;
+        }
+        p_uart_obj[uart_num]->uart_num = uart_num;
+        p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary();
+        xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem);
+        p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary();
+        p_uart_obj[uart_num]->tx_brk_sem = xSemaphoreCreateBinary();
+        p_uart_obj[uart_num]->tx_mux = xSemaphoreCreateMutex();
+        p_uart_obj[uart_num]->rx_mux = xSemaphoreCreateMutex();
+        p_uart_obj[uart_num]->intr_num = uart_intr_num;
+        p_uart_obj[uart_num]->queue_size = queue_size;
+        p_uart_obj[uart_num]->tx_ptr = NULL;
+        p_uart_obj[uart_num]->tx_head = NULL;
+        p_uart_obj[uart_num]->tx_len_tot = 0;
+        p_uart_obj[uart_num]->tx_brk_flg = 0;
+        p_uart_obj[uart_num]->tx_brk_len = 0;
+        p_uart_obj[uart_num]->tx_waiting_brk = 0;
+
+        if(uart_queue) {
+            p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t));
+            *((QueueHandle_t*) uart_queue) = p_uart_obj[uart_num]->xQueueUart;
+            ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart));
+        } else {
+            p_uart_obj[uart_num]->xQueueUart = NULL;
+        }
+        p_uart_obj[uart_num]->rx_buffer_full_flg = false;
+        p_uart_obj[uart_num]->tx_waiting_fifo = false;
+        p_uart_obj[uart_num]->rx_ptr = NULL;
+        p_uart_obj[uart_num]->rx_cur_remain = 0;
+        p_uart_obj[uart_num]->rx_head_ptr = NULL;
+        p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF);
+        if(tx_buffer_size > 0) {
+            p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT);
+            p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size;
+        } else {
+            p_uart_obj[uart_num]->tx_ring_buf = NULL;
+            p_uart_obj[uart_num]->tx_buf_size = 0;
+        }
+    } else {
+        ESP_LOGE(UART_TAG, "UART driver already installed");
+        return ESP_FAIL;
+    }
+    uart_isr_register(uart_num, uart_intr_num, uart_rx_intr_handler_default, p_uart_obj[uart_num]);
+    uart_intr_config_t uart_intr = {
+        .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M
+                            | UART_RXFIFO_TOUT_INT_ENA_M
+                            | UART_FRM_ERR_INT_ENA_M
+                            | UART_RXFIFO_OVF_INT_ENA_M
+                            | UART_BRK_DET_INT_ENA_M
+                            | UART_PARITY_ERR_INT_ENA_M,
+        .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT,
+        .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT,
+        .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT
+    };
+    uart_intr_config(uart_num, &uart_intr);
+    ESP_INTR_ENABLE(uart_intr_num);
+    return ESP_OK;
+}
+
+//Make sure no other tasks are still using UART before you call this function
+esp_err_t uart_driver_delete(uart_port_t uart_num)
+{
+    UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL);
+    if(p_uart_obj[uart_num] == NULL) {
+        ESP_LOGI(UART_TAG, "ALREADY NULL");
+        return ESP_OK;
+    }
+    ESP_INTR_DISABLE(p_uart_obj[uart_num]->intr_num);
+    uart_disable_rx_intr(uart_num);
+    uart_disable_tx_intr(uart_num);
+    uart_isr_register(uart_num, p_uart_obj[uart_num]->intr_num, NULL, NULL);
+
+    if(p_uart_obj[uart_num]->tx_fifo_sem) {
+        vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem);
+        p_uart_obj[uart_num]->tx_fifo_sem = NULL;
+    }
+    if(p_uart_obj[uart_num]->tx_done_sem) {
+        vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem);
+        p_uart_obj[uart_num]->tx_done_sem = NULL;
+    }
+    if(p_uart_obj[uart_num]->tx_brk_sem) {
+        vSemaphoreDelete(p_uart_obj[uart_num]->tx_brk_sem);
+        p_uart_obj[uart_num]->tx_brk_sem = NULL;
+    }
+    if(p_uart_obj[uart_num]->tx_mux) {
+        vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux);
+        p_uart_obj[uart_num]->tx_mux = NULL;
+    }
+    if(p_uart_obj[uart_num]->rx_mux) {
+        vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux);
+        p_uart_obj[uart_num]->rx_mux = NULL;
+    }
+    if(p_uart_obj[uart_num]->xQueueUart) {
+        vQueueDelete(p_uart_obj[uart_num]->xQueueUart);
+        p_uart_obj[uart_num]->xQueueUart = NULL;
+    }
+    if(p_uart_obj[uart_num]->rx_ring_buf) {
+        vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf);
+        p_uart_obj[uart_num]->rx_ring_buf = NULL;
+    }
+    if(p_uart_obj[uart_num]->tx_ring_buf) {
+        vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf);
+        p_uart_obj[uart_num]->tx_ring_buf = NULL;
+    }
+
+    free(p_uart_obj[uart_num]);
+    p_uart_obj[uart_num] = NULL;
+    return ESP_OK;
+}

+ 39 - 0
components/esp32/Kconfig

@@ -364,4 +364,43 @@ config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
 	depends on DOCUMENTATION_FOR_RTC_CNTL
 endchoice
 
+
+config ESP32_PHY_AUTO_INIT
+	bool "Initialize PHY in startup code"
+	default y
+	help
+		If enabled, PHY will be initialized in startup code, before
+		app_main function runs.
+		If this is undesired, disable this option and call esp_phy_init
+		from the application before enabling WiFi or BT.
+		
+		If this option is enabled, startup code will also initialize 
+		NVS prior to initializing PHY.
+		
+		If unsure, choose 'y'. 
+
+config ESP32_PHY_INIT_DATA_IN_PARTITION
+	bool "Use a partition to store PHY init data"
+	default n
+	help
+		If enabled, PHY init data will be loaded from a partition.
+		When using a custom partition table, make sure that PHY data
+		partition is included (type: 'data', subtype: 'phy'). 
+		With default partition tables, this is done automatically. 
+		If PHY init data is stored in a partition, it has to be flashed there,
+		otherwise runtime error will occur.
+		
+		If this option is not enabled, PHY init data will be embedded
+		into the application binary.
+		
+		If unsure, choose 'n'.
+
+config ESP32_PHY_MAX_TX_POWER
+	int "Max TX power (dBm)"
+	range 0 20
+	default 20
+	help
+		Set maximum transmit power. Actual transmit power for high
+		data rates may be lower than this setting.
+
 endmenu

+ 32 - 0
components/esp32/Makefile.projbuild

@@ -0,0 +1,32 @@
+ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
+
+PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o
+PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin
+
+# Command to flash PHY init data partition
+PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN)
+ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_PHY_DATA_OFFSET) $(PHY_INIT_DATA_BIN)
+
+ESP32_COMPONENT_PATH := $(COMPONENT_PATH)
+
+$(PHY_INIT_DATA_OBJ): $(ESP32_COMPONENT_PATH)/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h
+	$(summary) CC $(notdir $@)
+	printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP32_COMPONENT_PATH) -I $(ESP32_COMPONENT_PATH)/include -c -o $@ -xc -
+
+$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ)
+	$(summary) BIN $(notdir $@)
+	$(OBJCOPY) -O binary $< $@
+
+phy_init_data: $(PHY_INIT_DATA_BIN)
+
+phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin
+	@echo "Flashing PHY init data..."
+	$(PHY_INIT_DATA_FLASH_CMD)
+
+phy_init_data-clean:
+	rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ)
+
+all: phy_init_data
+flash: phy_init_data
+
+endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION

+ 5 - 17
components/esp32/component.mk

@@ -1,33 +1,23 @@
 #
 # Component Makefile
 #
-# This Makefile should, at the very least, just include $(IDF_PATH)/make/component_common.mk. By default, 
-# this will take the sources in this directory, compile them and link them into 
-# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
-# please read the esp-idf build system document if you need to do this.
-#
--include include/config/auto.conf
 
 COMPONENT_SRCDIRS := . hwcrypto
 
-LIBS := core net80211 phy rtc pp wpa smartconfig coexist wpa2
+LIBS := core net80211 phy rtc pp wpa smartconfig coexist wps wpa2
 
 LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
 
 COMPONENT_ADD_LDFLAGS := -lesp32 \
-                           $(abspath libhal.a) \
-                           -L$(abspath lib) \
+                           $(COMPONENT_PATH)/libhal.a \
+                           -L$(COMPONENT_PATH)/lib \
                            $(addprefix -l,$(LIBS)) \
-                          -L $(abspath ld) \
+                          -L $(COMPONENT_PATH)/ld \
                           $(LINKER_SCRIPTS)
 
-include $(IDF_PATH)/make/component_common.mk
-
 ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
 
-# automatically trigger a git submodule update
-# if any libraries are missing
-$(eval $(call SubmoduleCheck,$(ALL_LIB_FILES),$(COMPONENT_PATH)/lib))
+COMPONENT_SUBMODULES += lib
 
 # this is a hack to make sure the app is re-linked if the binary
 # libraries change or are updated. If they change, the main esp32
@@ -44,8 +34,6 @@ $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
 # saves us from having to add the target to a Makefile.projbuild
 $(COMPONENT_LIBRARY): esp32_out.ld
 
-# .. is BUILD_DIR_BASE here, as component makefiles
-# are evaluated with CWD=component build dir
 esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
 	$(CC) -I ../include -C -P -x c -E $< -o $@
 

+ 40 - 0
components/esp32/cpu_start.c

@@ -50,6 +50,7 @@
 #include "esp_brownout.h"
 #include "esp_int_wdt.h"
 #include "esp_task_wdt.h"
+#include "esp_phy_init.h"
 #include "trax.h"
 
 void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
@@ -62,6 +63,7 @@ static bool app_cpu_started = false;
 #endif //!CONFIG_FREERTOS_UNICORE
 
 static void do_global_ctors(void);
+static void do_phy_init();
 static void main_task(void* args);
 extern void app_main(void);
 
@@ -187,6 +189,11 @@ void start_cpu0_default(void)
     esp_ipc_init();
     spi_flash_init();
 
+#if CONFIG_ESP32_PHY_AUTO_INIT
+    nvs_flash_init();
+    do_phy_init();
+#endif
+
     xTaskCreatePinnedToCore(&main_task, "main",
             ESP_TASK_MAIN_STACK, NULL,
             ESP_TASK_MAIN_PRIO, NULL, 0);
@@ -224,3 +231,36 @@ static void main_task(void* args)
     vTaskDelete(NULL);
 }
 
+static void do_phy_init()
+{
+    esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL;
+    if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) {
+        calibration_mode = PHY_RF_CAL_NONE;
+    }
+    const esp_phy_init_data_t* init_data = esp_phy_get_init_data();
+    if (init_data == NULL) {
+        ESP_LOGE(TAG, "failed to obtain PHY init data");
+        abort();
+    }
+    esp_phy_calibration_data_t* cal_data =
+            (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1);
+    if (cal_data == NULL) {
+        ESP_LOGE(TAG, "failed to allocate memory for RF calibration data");
+        abort();
+    }
+    esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data);
+    if (err != ESP_OK) {
+        ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration");
+        calibration_mode = PHY_RF_CAL_FULL;
+    }
+
+    esp_phy_init(init_data, calibration_mode, cal_data);
+
+    if (calibration_mode != PHY_RF_CAL_NONE) {
+        err = esp_phy_store_cal_data_to_nvs(cal_data);
+    } else {
+        err = ESP_OK;
+    }
+    esp_phy_release_init_data(init_data);
+    free(cal_data); // PHY maintains a copy of calibration data, so we can free this
+}

+ 1 - 6
components/esp32/crosscore_int.c

@@ -45,14 +45,9 @@ the ISR will cause it to switch _away_ from it. portYIELD_FROM_ISR will probably
 */
 static void esp_crosscore_isr(void *arg) {
     uint32_t myReasonVal;
-#if 0
     //A pointer to the correct reason array item is passed to this ISR.
     volatile uint32_t *myReason=arg;
-#else
-    //The previous line does not work yet, the interrupt code needs work to understand two separate interrupt and argument
-    //tables... this is a valid but slightly less optimal replacement.
-    volatile uint32_t *myReason=&reason[xPortGetCoreID()];
-#endif
+
     //Clear the interrupt first.
     if (xPortGetCoreID()==0) {
         WRITE_PERI_REG(DPORT_CPU_INTR_FROM_CPU_0_REG, 0);

+ 20 - 0
components/esp32/event_default_handlers.c

@@ -68,6 +68,10 @@ static system_event_handle_t g_system_event_handle_table[] = {
     {SYSTEM_EVENT_STA_DISCONNECTED,    system_event_sta_disconnected_handle_default},
     {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
     {SYSTEM_EVENT_STA_GOT_IP,          system_event_sta_got_ip_default},
+    {SYSTEM_EVENT_STA_WPS_ER_SUCCESS,  NULL},
+    {SYSTEM_EVENT_STA_WPS_ER_FAILED,   NULL},
+    {SYSTEM_EVENT_STA_WPS_ER_TIMEOUT,  NULL},
+    {SYSTEM_EVENT_STA_WPS_ER_PIN,      NULL},
     {SYSTEM_EVENT_AP_START,            system_event_ap_start_handle_default},
     {SYSTEM_EVENT_AP_STOP,             system_event_ap_stop_handle_default},
     {SYSTEM_EVENT_AP_STACONNECTED,     NULL},
@@ -220,6 +224,22 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
             IP2STR(&got_ip->ip_info.gw));
         break;
     }
+    case SYSTEM_EVENT_STA_WPS_ER_SUCCESS: {
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_SUCCESS");
+        break;
+    }
+    case SYSTEM_EVENT_STA_WPS_ER_FAILED: {
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_FAILED");
+        break;
+    }
+    case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT: {
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_TIMEOUT");
+        break;
+    }
+    case SYSTEM_EVENT_STA_WPS_ER_PIN: {
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_WPS_ER_PIN");
+        break;
+    }
     case SYSTEM_EVENT_AP_START: {
         ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
         break;

+ 96 - 0
components/esp32/freertos_hooks.c

@@ -0,0 +1,96 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include "esp_attr.h"
+#include "esp_freertos_hooks.h"
+
+//We use just a static array here because it's not expected many components will need
+//an idle or tick hook.
+#define MAX_HOOKS 8
+
+static esp_freertos_idle_cb_t idle_cb[MAX_HOOKS]={0};
+static esp_freertos_tick_cb_t tick_cb[MAX_HOOKS]={0};
+
+void IRAM_ATTR esp_vApplicationTickHook() 
+{
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (tick_cb[n]!=NULL) {
+            tick_cb[n]();
+        }
+    }
+}
+
+void esp_vApplicationIdleHook() 
+{
+    bool doWait=true;
+    bool r;
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (idle_cb[n]!=NULL) {
+            r=idle_cb[n]();
+            if (!r) doWait=false;
+        }
+    }
+    if (doWait) {
+        //Wait for whatever interrupt comes next... this should save some power.
+        asm("waiti 0");
+    }
+}
+
+
+esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb) 
+{
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (idle_cb[n]==NULL) {
+            idle_cb[n]=new_idle_cb;
+            return ESP_OK;
+        }
+    }
+    return ESP_ERR_NO_MEM;
+}
+
+esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t new_tick_cb) 
+{
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (tick_cb[n]==NULL) {
+            tick_cb[n]=new_tick_cb;
+            return ESP_OK;
+        }
+    }
+    return ESP_ERR_NO_MEM;
+}
+
+void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb)
+{
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (idle_cb[n]==old_idle_cb) idle_cb[n]=NULL;
+    }
+}
+
+void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb)
+{
+    int n;
+    for (n=0; n<MAX_HOOKS; n++) {
+        if (tick_cb[n]==old_tick_cb) tick_cb[n]=NULL;
+    }
+}
+

+ 2 - 1
components/esp32/gdbstub.c

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

+ 4 - 0
components/esp32/include/esp_attr.h

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

+ 2 - 0
components/esp32/include/esp_err.h

@@ -34,6 +34,8 @@ typedef int32_t esp_err_t;
 #define ESP_ERR_INVALID_SIZE    0x104
 #define ESP_ERR_NOT_FOUND       0x105
 #define ESP_ERR_NOT_SUPPORTED   0x106
+#define ESP_ERR_TIMEOUT         0x107
+
 
 #define ESP_ERR_WIFI_BASE       0x3000 /*!< Starting number of WiFi error codes */
 

+ 9 - 0
components/esp32/include/esp_event.h

@@ -35,6 +35,10 @@ typedef enum {
     SYSTEM_EVENT_STA_DISCONNECTED,         /**< ESP32 station disconnected from AP */
     SYSTEM_EVENT_STA_AUTHMODE_CHANGE,      /**< the auth mode of AP connected by ESP32 station changed */
     SYSTEM_EVENT_STA_GOT_IP,               /**< ESP32 station got IP from connected AP */
+    SYSTEM_EVENT_STA_WPS_ER_SUCCESS,       /**< ESP32 station wps succeeds in enrollee mode */
+    SYSTEM_EVENT_STA_WPS_ER_FAILED,        /**< ESP32 station wps fails in enrollee mode */
+    SYSTEM_EVENT_STA_WPS_ER_TIMEOUT,       /**< ESP32 station wps timeout in enrollee mode */
+    SYSTEM_EVENT_STA_WPS_ER_PIN,           /**< ESP32 station wps pin code in enrollee mode */
     SYSTEM_EVENT_AP_START,                 /**< ESP32 soft-AP start */
     SYSTEM_EVENT_AP_STOP,                  /**< ESP32 soft-AP stop */
     SYSTEM_EVENT_AP_STACONNECTED,          /**< a station connected to ESP32 soft-AP */
@@ -73,6 +77,10 @@ typedef struct {
     tcpip_adapter_ip_info_t ip_info;
 } system_event_sta_got_ip_t;
 
+typedef struct {
+    uint8_t pin_code[8];         /**< PIN code of station in enrollee mode */
+}system_event_sta_wps_er_pin_t;
+
 typedef struct {
     uint8_t mac[6];           /**< MAC address of the station connected to ESP32 soft-AP */
     uint8_t aid;              /**< the aid that ESP32 soft-AP gives to the station connected to  */
@@ -94,6 +102,7 @@ typedef union {
     system_event_sta_scan_done_t               scan_done;          /**< ESP32 station scan (APs) done */
     system_event_sta_authmode_change_t         auth_change;        /**< the auth mode of AP ESP32 station connected to changed */
     system_event_sta_got_ip_t                  got_ip;             /**< ESP32 station got IP */
+    system_event_sta_wps_er_pin_t              sta_er_pin;         /**< ESP32 station WPS enrollee mode PIN code received */
     system_event_ap_staconnected_t             sta_connected;      /**< a station connected to ESP32 soft-AP */
     system_event_ap_stadisconnected_t          sta_disconnected;   /**< a station disconnected to ESP32 soft-AP */
     system_event_ap_probe_req_rx_t             ap_probereqrecved;  /**< ESP32 soft-AP receive probe request packet */

+ 1 - 49
components/esp32/include/esp_flash_data_types.h

@@ -21,57 +21,9 @@ extern "C"
 {
 #endif
 
-#define ESP_PARTITION_TABLE_ADDR 0x4000
+#define ESP_PARTITION_TABLE_ADDR 0x8000
 #define ESP_PARTITION_MAGIC 0x50AA
 
-/* SPI flash mode, used in esp_image_header_t */
-typedef enum {
-    ESP_IMAGE_SPI_MODE_QIO,
-    ESP_IMAGE_SPI_MODE_QOUT,
-    ESP_IMAGE_SPI_MODE_DIO,
-    ESP_IMAGE_SPI_MODE_DOUT,
-    ESP_IMAGE_SPI_MODE_FAST_READ,
-    ESP_IMAGE_SPI_MODE_SLOW_READ
-} esp_image_spi_mode_t;
-
-/* SPI flash clock frequency */
-enum {
-    ESP_IMAGE_SPI_SPEED_40M,
-    ESP_IMAGE_SPI_SPEED_26M,
-    ESP_IMAGE_SPI_SPEED_20M,
-    ESP_IMAGE_SPI_SPEED_80M = 0xF
-} esp_image_spi_freq_t;
-
-/* Supported SPI flash sizes */
-typedef enum {
-    ESP_IMAGE_FLASH_SIZE_1MB = 0,
-    ESP_IMAGE_FLASH_SIZE_2MB,
-    ESP_IMAGE_FLASH_SIZE_4MB,
-    ESP_IMAGE_FLASH_SIZE_8MB,
-    ESP_IMAGE_FLASH_SIZE_16MB,
-    ESP_IMAGE_FLASH_SIZE_MAX
-} esp_image_flash_size_t;
-
-/* Main header of binary image */
-typedef struct {
-    uint8_t magic;
-    uint8_t blocks;
-    uint8_t spi_mode;      /* flash read mode (esp_image_spi_mode_t as uint8_t) */
-    uint8_t spi_speed: 4;  /* flash frequency (esp_image_spi_freq_t as uint8_t) */
-    uint8_t spi_size: 4;   /* flash chip size (esp_image_flash_size_t as uint8_t) */
-    uint32_t entry_addr;
-    uint8_t encrypt_flag;    /* encrypt flag */
-    uint8_t secure_boot_flag; /* secure boot flag */
-    uint8_t extra_header[14]; /* ESP32 additional header, unused by second bootloader */
-}  esp_image_header_t;
-
-/* Header of binary image segment */
-typedef struct {
-    uint32_t load_addr;
-    uint32_t data_len;
-} esp_image_section_header_t;
-
-
 /* OTA selection structure (two copies in the OTA data partition.)
    Size of 32 bytes is friendly to flash encryption */
 typedef struct {

+ 83 - 0
components/esp32/include/esp_freertos_hooks.h

@@ -0,0 +1,83 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_FREERTOS_HOOKS_H__
+#define __ESP_FREERTOS_HOOKS_H__
+
+#include <stdbool.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ Definitions for the tickhook and idlehook callbacks
+*/
+typedef bool (*esp_freertos_idle_cb_t)();
+typedef void (*esp_freertos_tick_cb_t)();
+
+/**
+  * @brief  Register a callback to be called on the freertos idle hook
+  *         The callback should return true if it's okay for the core to
+  *         sleep until an interrupt (or FreeRTOS tick) happens and false
+  *         if it should be called again as fast as possible.
+  *
+  * @warning Idle callbacks MUST NOT, UNDER ANY CIRCUMSTANCES, CALL 
+  *          A FUNCTION THAT MIGHT BLOCK.
+  *
+  * @param  esp_freertos_idle_cb_t new_idle_cb : Callback to be called
+  *
+  * @return ESP_OK : Callback registered
+  * @return ESP_ERR_NO_MEM : No more space to register hook
+  */
+esp_err_t esp_register_freertos_idle_hook(esp_freertos_idle_cb_t new_idle_cb);
+
+/**
+  * @brief  Register a callback to be called on the freertos tick hook
+  *
+  * @param  esp_freertos_tick_cb_t new_tick_cb : Callback to be called
+  *
+  * @return ESP_OK : Callback registered
+  * @return ESP_ERR_NO_MEM : No more space to register hook
+  */
+esp_err_t esp_register_freertos_tick_hook(esp_freertos_tick_cb_t tick_cb);
+
+
+/**
+  * @brief  Unregister an idle callback registered earlier
+  *
+  * @param  esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
+  *
+  * @return void
+  */
+void esp_deregister_freertos_idle_hook(esp_freertos_idle_cb_t old_idle_cb);
+
+
+/**
+  * @brief  Unregister a tick callback registered earlier
+  *
+  * @param  esp_freertos_idle_cb_t new_idle_cb : Callback to be unregistered
+  *
+  * @return void
+  */
+void esp_deregister_freertos_tick_hook(esp_freertos_tick_cb_t old_tick_cb);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif

+ 0 - 3
components/esp32/include/esp_int_wdt.h

@@ -41,9 +41,6 @@ This uses the TIMERG1 WDT.
   * @brief  Initialize the interrupt watchdog. This is called in the init code if
   *         the interrupt watchdog is enabled in menuconfig.
   *
-  * @param  null
-  *
-  * @return null
   */
 void esp_int_wdt_init();
 

+ 249 - 0
components/esp32/include/esp_phy_init.h

@@ -0,0 +1,249 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+#include <stdint.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file PHY init parameters and API
+ */
+
+
+/**
+ * @brief Structure holding PHY init parameters
+ */
+typedef struct {
+	uint8_t param_ver_id;                   /*!< init_data structure version */
+	uint8_t crystal_select;                 /*!< 0: 40MHz, 1: 26 MHz, 2: 24 MHz, 3: auto */
+	uint8_t wifi_rx_gain_swp_step_1;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_2;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_3;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_4;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_5;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_6;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_7;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_8;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_9;        /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_10;       /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_11;       /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_12;       /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_13;       /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_14;       /*!< do not change */
+	uint8_t wifi_rx_gain_swp_step_15;       /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_1;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_2;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_3;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_4;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_5;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_6;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_7;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_8;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_9;          /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_10;         /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_11;         /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_12;         /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_13;         /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_14;         /*!< do not change */
+	uint8_t bt_rx_gain_swp_step_15;         /*!< do not change */
+	uint8_t gain_cmp_1;                     /*!< do not change */
+	uint8_t gain_cmp_6;                     /*!< do not change */
+	uint8_t gain_cmp_11;                    /*!< do not change */
+	uint8_t gain_cmp_ext2_1;                /*!< do not change */
+	uint8_t gain_cmp_ext2_6;                /*!< do not change */
+	uint8_t gain_cmp_ext2_11;               /*!< do not change */
+	uint8_t gain_cmp_ext3_1;                /*!< do not change */
+	uint8_t gain_cmp_ext3_6;                /*!< do not change */
+	uint8_t gain_cmp_ext3_11;               /*!< do not change */
+	uint8_t gain_cmp_bt_ofs_1;              /*!< do not change */
+	uint8_t gain_cmp_bt_ofs_6;              /*!< do not change */
+	uint8_t gain_cmp_bt_ofs_11;             /*!< do not change */
+	uint8_t target_power_qdb_0;             /*!< 78 means target power is 78/4=19.5dbm */
+	uint8_t target_power_qdb_1;             /*!< 76 means target power is 76/4=19dbm */
+	uint8_t target_power_qdb_2;             /*!< 74 means target power is 74/4=18.5dbm */
+	uint8_t target_power_qdb_3;             /*!< 68 means target power is 68/4=17dbm */
+	uint8_t target_power_qdb_4;             /*!< 64 means target power is 64/4=16dbm */
+	uint8_t target_power_qdb_5;             /*!< 52 means target power is 52/4=13dbm */
+	uint8_t target_power_index_mcs0;        /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm;  (1m,2m,5.5m,11m,6m,9m) */
+	uint8_t target_power_index_mcs1;        /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm;  (12m) */
+	uint8_t target_power_index_mcs2;        /*!< target power index is 1, means target power is target_power_qdb_1 19dbm;    (18m) */
+	uint8_t target_power_index_mcs3;        /*!< target power index is 1, means target power is target_power_qdb_1 19dbm;    (24m) */
+	uint8_t target_power_index_mcs4;        /*!< target power index is 2, means target power is target_power_qdb_2 18.5dbm;  (36m) */
+	uint8_t target_power_index_mcs5;        /*!< target power index is 3, means target power is target_power_qdb_3 17dbm;    (48m) */
+	uint8_t target_power_index_mcs6;        /*!< target power index is 4, means target power is target_power_qdb_4 16dbm;    (54m) */
+	uint8_t target_power_index_mcs7;        /*!< target power index is 5, means target power is target_power_qdb_5 13dbm */
+	uint8_t pwr_ind_11b_en;                 /*!< 0: 11b power is same as mcs0 and 6m, 1: 11b power different with OFDM */
+	uint8_t pwr_ind_11b_0;                  /*!< 1m, 2m power index [0~5] */
+	uint8_t pwr_ind_11b_1;                  /*!< 5.5m, 11m power index [0~5] */
+	uint8_t chan_backoff_en;                /*!< 0: channel backoff disable, 1:channel backoff enable */
+	uint8_t chan1_power_backoff_qdb;        /*!< 4 means backoff is 1db */
+	uint8_t chan2_power_backoff_qdb;        /*!< see chan1_power_backoff_qdb */
+	uint8_t chan3_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan4_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan5_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan6_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan7_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan8_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan9_power_backoff_qdb;        /*!< chan1_power_backoff_qdb */
+	uint8_t chan10_power_backoff_qdb;       /*!< chan1_power_backoff_qdb */
+	uint8_t chan11_power_backoff_qdb;       /*!< chan1_power_backoff_qdb */
+	uint8_t chan12_power_backoff_qdb;       /*!< chan1_power_backoff_qdb */
+	uint8_t chan13_power_backoff_qdb;       /*!< chan1_power_backoff_qdb */
+	uint8_t chan14_power_backoff_qdb;       /*!< chan1_power_backoff_qdb */
+	uint8_t chan1_rate_backoff_index;       /*!< if bit i is set, backoff data rate is target_power_qdb_i */
+	uint8_t chan2_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan3_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan4_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan5_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan6_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan7_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan8_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan9_rate_backoff_index;       /*!< see chan1_rate_backoff_index */
+	uint8_t chan10_rate_backoff_index;      /*!< see chan1_rate_backoff_index */
+	uint8_t chan11_rate_backoff_index;      /*!< see chan1_rate_backoff_index */
+	uint8_t chan12_rate_backoff_index;      /*!< see chan1_rate_backoff_index */
+	uint8_t chan13_rate_backoff_index;      /*!< see chan1_rate_backoff_index */
+	uint8_t chan14_rate_backoff_index;      /*!< see chan1_rate_backoff_index */
+	uint8_t spur_freq_cfg_msb_1;            /*!< first spur: */
+	uint8_t spur_freq_cfg_1;                /*!< spur_freq_cfg = (spur_freq_cfg_msb_1 <<8) | spur_freq_cfg_1 */
+	uint8_t spur_freq_cfg_div_1;            /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_1 */
+	uint8_t spur_freq_en_h_1;               /*!< the seventh bit for total enable */
+	uint8_t spur_freq_en_l_1;               /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
+	uint8_t spur_freq_cfg_msb_2;            /*!< second spur: */
+	uint8_t spur_freq_cfg_2;                /*!< spur_freq_cfg = (spur_freq_cfg_msb_2 <<8) | spur_freq_cfg_2 */
+	uint8_t spur_freq_cfg_div_2;            /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_2 */
+	uint8_t spur_freq_en_h_2;               /*!< the seventh bit for total enable */
+	uint8_t spur_freq_en_l_2;               /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
+	uint8_t spur_freq_cfg_msb_3;            /*!< third spur: */
+	uint8_t spur_freq_cfg_3;                /*!< spur_freq_cfg = (spur_freq_cfg_msb_3 <<8) | spur_freq_cfg_3 */
+	uint8_t spur_freq_cfg_div_3;            /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_3 */
+	uint8_t spur_freq_en_h_3;               /*!< the seventh bit for total enable */
+	uint8_t spur_freq_en_l_3;               /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority, */
+	uint8_t reserved[23];                   /*!< reserved for future expansion */
+} esp_phy_init_data_t;
+
+/**
+ * @brief Opaque PHY calibration data
+ */
+typedef struct {
+    uint8_t opaque[1904];                   /*!< calibration data */
+} esp_phy_calibration_data_t;
+
+typedef enum {
+    PHY_RF_CAL_PARTIAL = 0x00000000,        /*!< Do part of RF calibration. This should be used after power-on reset. */
+    PHY_RF_CAL_NONE    = 0x00000001,        /*!< Don't do any RF calibration. This mode is only suggested to be used after deep sleep reset. */
+    PHY_RF_CAL_FULL    = 0x00000002         /*!< Do full RF calibration. Produces best results, but also consumes a lot of time and current. Suggested to be used once. */
+} esp_phy_calibration_mode_t;
+
+/**
+ * @brief Get PHY init data
+ *
+ * If "Use a partition to store PHY init data" option is set in menuconfig,
+ * This function will load PHY init data from a partition. Otherwise,
+ * PHY init data will be compiled into the application itself, and this function
+ * will return a pointer to PHY init data located in read-only memory (DROM).
+ *
+ * If "Use a partition to store PHY init data" option is enabled, this function
+ * may return NULL if the data loaded from flash is not valid.
+ *
+ * @note Call esp_phy_release_init_data to release the pointer obtained using
+ * this function after the call to esp_wifi_init.
+ *
+ * @return pointer to PHY init data structure
+ */
+const esp_phy_init_data_t* esp_phy_get_init_data();
+
+/**
+ * @brief Release PHY init data
+ * @param data  pointer to PHY init data structure obtained from
+ *              esp_phy_get_init_data function
+ */
+void esp_phy_release_init_data(const esp_phy_init_data_t* data);
+
+/**
+ * @brief Function called by esp_phy_init to load PHY calibration data
+ *
+ * This is a convenience function which can be used to load PHY calibration
+ * data from NVS. Data can be stored to NVS using esp_phy_store_cal_data_to_nvs
+ * function.
+ *
+ * If calibration data is not present in the NVS, or
+ * data is not valid (was obtained for a chip with a different MAC address,
+ * or obtained for a different version of software), this function will
+ * return an error.
+ *
+ * If "Initialize PHY in startup code" option is set in menuconfig, this
+ * function will be used to load calibration data. To provide a different
+ * mechanism for loading calibration data, disable
+ * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init
+ * function from the application. For an example usage of esp_phy_init and
+ * this function, see do_phy_init function in cpu_start.c
+ *
+ * @param out_cal_data pointer to calibration data structure to be filled with
+ *                     loaded data.
+ * @return ESP_OK on success
+ */
+esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data);
+
+/**
+ * @brief Function called by esp_phy_init to store PHY calibration data
+ *
+ * This is a convenience function which can be used to store PHY calibration
+ * data to the NVS. Calibration data is returned by esp_phy_init function.
+ * Data saved using this function to the NVS can later be loaded using
+ * esp_phy_store_cal_data_to_nvs function.
+ *
+ * If "Initialize PHY in startup code" option is set in menuconfig, this
+ * function will be used to store calibration data. To provide a different
+ * mechanism for storing calibration data, disable
+ * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init
+ * function from the application.
+ *
+ * @param cal_data pointer to calibration data which has to be saved.
+ * @return ESP_OK on success
+ */
+esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data);
+
+/**
+ * @brief Initialize PHY module
+ *
+ * PHY module should be initialized in order to use WiFi or BT.
+ * If "Initialize PHY in startup code" option is set in menuconfig,
+ * this function will be called automatically before app_main is called,
+ * using parameters obtained from esp_phy_get_init_data.
+ *
+ * Applications which don't need to enable PHY on every start up should
+ * disable this menuconfig option and call esp_phy_init before calling
+ * esp_wifi_init or bt_controller_init. See do_phy_init function in
+ * cpu_start.c for an example of using this function.
+ *
+ * @param init_data  PHY parameters. Default set of parameters can
+ *                   be obtained by calling esp_phy_get_default_init_data
+ *                   function.
+ * @param mode  Calibration mode (Full, partial, or no calibration)
+ * @param[inout] calibration_data
+ * @return ESP_OK on success.
+ */
+esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
+        esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+

+ 0 - 9
components/esp32/include/esp_task_wdt.h

@@ -42,9 +42,6 @@ This uses the TIMERG0 WDT.
   * @brief  Initialize the task watchdog. This is called in the init code, if the
   *         task watchdog is enabled in menuconfig.
   *
-  * @param  null
-  *
-  * @return null
   */
 void esp_task_wdt_init();
 
@@ -52,9 +49,6 @@ void esp_task_wdt_init();
   * @brief  Feed the watchdog. After the first feeding session, the watchdog will expect the calling
   *         task to keep feeding the watchdog until task_wdt_delete() is called.
   *
-  * @param  null
-  *
-  * @return null
   */
 
 void esp_task_wdt_feed();
@@ -63,9 +57,6 @@ void esp_task_wdt_feed();
 /**
   * @brief  Delete the watchdog for the current task.
   *
-  * @param  null
-  *
-  * @return null
   */
 void esp_task_wdt_delete();
 

+ 209 - 224
components/esp32/include/esp_wifi.h

@@ -88,6 +88,9 @@ extern "C" {
 #define ESP_ERR_WIFI_PASSWORD    (ESP_ERR_WIFI_BASE + 10)  /*!< Passord is invalid */
 #define ESP_ERR_WIFI_TIMEOUT     (ESP_ERR_WIFI_BASE + 11)  /*!< Timeout error */
 
+/**
+ * @brief WiFi stack configuration parameters passed to esp_wifi_init call.
+ */
 typedef struct {
     system_event_handler_t event_handler;  /**< WiFi event handler */
 } wifi_init_config_t;
@@ -108,12 +111,12 @@ typedef struct {
   *               will post station connected event to this queue. If the queue is not initialized, WiFi
   *               will not post any events
   *
-  * @param  wifi_init_config_t *config : provide WiFi init configuration
+  * @param  config provide WiFi init configuration
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NO_MEM : out of memory
-  *    - others : refer to error code esp_err.h 
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NO_MEM: out of memory
+  *    - others: refer to error code esp_err.h 
   */
 esp_err_t esp_wifi_init(wifi_init_config_t *config);
 
@@ -123,7 +126,7 @@ esp_err_t esp_wifi_init(wifi_init_config_t *config);
   *
   * @attention 1. This API should be called if you want to remove WiFi driver from the system
   *
-  * @return ESP_OK : succeed
+  * @return ESP_OK: succeed
   */
 esp_err_t esp_wifi_deinit(void);
 
@@ -133,25 +136,25 @@ esp_err_t esp_wifi_deinit(void);
   *            Set the WiFi operating mode as station, soft-AP or station+soft-AP,
   *            The default mode is soft-AP mode.
   *
-  * @param     wifi_mode_t mode : WiFi operating modes:
+  * @param     mode  WiFi operating mode
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - others: refer to error code in esp_err.h
   */
 esp_err_t esp_wifi_set_mode(wifi_mode_t mode);
 
 /**
   * @brief  Get current operating mode of WiFi
   *
-  * @param  wifi_mode_t *mode : store current WiFi mode
+  * @param[out]  mode  store current WiFi mode
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
 
@@ -161,29 +164,25 @@ esp_err_t esp_wifi_get_mode(wifi_mode_t *mode);
   *         If mode is WIFI_MODE_AP, it create soft-AP control block and start soft-AP
   *         If mode is WIFI_MODE_APSTA, it create soft-AP and station control block and start soft-AP and station
   *
-  * @param  null
-  *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_NO_MEM : out of memory
-  *    - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong
-  *    - ESP_ERR_WIFI_FAIL : other WiFi internal errors
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_NO_MEM: out of memory
+  *    - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
+  *    - ESP_ERR_WIFI_FAIL: other WiFi internal errors
   */
 esp_err_t esp_wifi_start(void);
 
 /**
   * @brief  Stop WiFi
-            If mode is WIFI_MODE_STA, it stop station and free station control block
+  *         If mode is WIFI_MODE_STA, it stop station and free station control block
   *         If mode is WIFI_MODE_AP, it stop soft-AP and free soft-AP control block
   *         If mode is WIFI_MODE_APSTA, it stop station/soft-AP and free station/soft-AP control block
   *
-  * @param  null
-  *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
   */
 esp_err_t esp_wifi_stop(void);
 
@@ -193,52 +192,47 @@ esp_err_t esp_wifi_stop(void);
   * @attention 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
   * @attention 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
   *
-  * @param     null
-  *
   * @return 
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_CONN : WiFi internal error, station or soft-AP control block wrong
-  *    - ESP_ERR_WIFI_SSID : SSID of AP which station connects is invalid
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_CONN: WiFi internal error, station or soft-AP control block wrong
+  *    - ESP_ERR_WIFI_SSID: SSID of AP which station connects is invalid
   */
 esp_err_t esp_wifi_connect(void);
 
 /**
   * @brief     Disconnect the ESP32 WiFi station from the AP.
   *
-  * @param     null
-  *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_FAIL : other WiFi internal errors
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_FAIL: other WiFi internal errors
   */
 esp_err_t esp_wifi_disconnect(void);
 
 /**
   * @brief     Currently this API is just an stub API
   *
-  * @param     null
-  *
+
   * @return
-  *    - ESP_OK : succeed
-  *    - others : fail
+  *    - ESP_OK: succeed
+  *    - others: fail
   */
 esp_err_t esp_wifi_clear_fast_connect(void);
 
 /**
   * @brief     deauthenticate all stations or associated id equals to aid
   *
-  * @param     uint16_t aid : when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid
+  * @param     aid  when aid is 0, deauthenticate all stations, otherwise deauthenticate station whose associated id is aid
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_MODE : WiFi mode is wrong
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_MODE: WiFi mode is wrong
   */
 esp_err_t esp_wifi_deauth_sta(uint16_t aid);
 
@@ -249,88 +243,87 @@ esp_err_t esp_wifi_deauth_sta(uint16_t aid);
   *            will be freed in esp_wifi_get_ap_list, so generally, call esp_wifi_get_ap_list to cause
   *            the memory to be freed once the scan is done
   *
-  * @param     struct scan_config *config : configuration of scanning
-  * @param     bool block : if block is true, this API will block the caller until the scan is done, otherwise
+  * @param     config  configuration of scanning
+  * @param     block if block is true, this API will block the caller until the scan is done, otherwise
   *                         it will return immediately
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_TIMEOUT : blocking scan is timeout
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_TIMEOUT: blocking scan is timeout
+  *    - others: refer to error code in esp_err.h
   */
-esp_err_t esp_wifi_scan_start(wifi_scan_config_t *conf, bool block);
+esp_err_t esp_wifi_scan_start(wifi_scan_config_t *config, bool block);
 
 /**
   * @brief     Stop the scan in process
   *
-  * @param     null
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
   */
 esp_err_t esp_wifi_scan_stop(void);
 
 /**
   * @brief     Get number of APs found in last scan
   *
-  * @param     uint16_t *number : store number of APIs found in last scan
+  * @param[out] number  store number of APIs found in last scan
   *
-  * @attention This API can only be called when the scan is completed, otherwise it may get wrong value
+  * @attention This API can only be called when the scan is completed, otherwise it may get wrong value.
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_scan_get_ap_num(uint16_t *number);
 
 /**
   * @brief     Get AP list found in last scan
   *
-  * @param     uint16_t *number : as input param, it stores max AP number ap_records can hold, as output param, it store
-                                  the actual AP number this API returns
-  * @param     wifi_ap_record_t *ap_records: wifi_ap_record_t array to hold the found APs
+  * @param[inout]  number As input param, it stores max AP number ap_records can hold. 
+  *                As output param, it receives the actual AP number this API returns.
+  * @param         ap_records  wifi_ap_record_t array to hold the found APs
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_NOT_START : WiFi is not started by esp_wifi_start
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_NO_MEM : out of memory
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_NOT_START: WiFi is not started by esp_wifi_start
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_NO_MEM: out of memory
   */
 esp_err_t esp_wifi_scan_get_ap_records(uint16_t *number, wifi_ap_record_t *ap_records);
 
 
 /**
-  * @brief     Get information of AP associated with ESP32 station
+  * @brief     Get information of AP which the ESP32 station is associated with
   *
-  * @param     wifi_ap_record_t *ap_info: the wifi_ap_record_t to hold station assocated AP
+  * @param     ap_info  the wifi_ap_record_t to hold AP information
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - others : fail
+  *    - ESP_OK: succeed
+  *    - others: fail
   */
 esp_err_t esp_wifi_sta_get_ap_info(wifi_ap_record_t *ap_info);
 
 /**
   * @brief     Set current power save type
   *
-  * @param     wifi_ps_type_t type : power save type
+  * @param     type  power save type
   *
-  * @return    ESP_ERR_WIFI_NOT_SUPPORT : not support yet
+  * @return    ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
   */
 esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
 
 /**
   * @brief     Get current power save type
   *
-  * @param     wifi_ps_type_t *type : store current power save type
+  * @param[out]  type: store current power save type
   *
-  * @return    ESP_ERR_WIFI_NOT_SUPPORT : not support yet
+  * @return    ESP_ERR_WIFI_NOT_SUPPORT: not supported yet
   */
 esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
 
@@ -340,47 +333,47 @@ esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
   *
   * @attention Currently we only support 802.11b or 802.11bg or 802.11bgn mode
   *
-  * @param     wifi_interface_t ifx : interfaces
-  * @param     uint8_t protocol : WiFi protocol bitmap
+  * @param     ifx  interfaces
+  * @param     protocol_bitmap  WiFi protocol bitmap
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - others : refer to erro code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - others: refer to error codes in esp_err.h
   */
 esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
 
 /**
-  * @brief     Get the current protocol bitmap of specified ifx
+  * @brief     Get the current protocol bitmap of the specified interface
   *
-  * @param     wifi_interface_t ifx : interfaces
-  * @param     uint8_t protocol : store current WiFi protocol bitmap of interface ifx
+  * @param     ifx  interface
+  * @param[out] protocol_bitmap  store current WiFi protocol bitmap of interface ifx
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - others: refer to error codes in esp_err.h
   */
 esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
 
 /**
   * @brief     Set the bandwidth of ESP32 specified interface
   *
-  * @attention 1. API return false if try to configure a interface that is not enable
+  * @attention 1. API return false if try to configure an interface that is not enabled
   * @attention 2. WIFI_BW_HT40 is supported only when the interface support 11N
   *
-  * @param     wifi_interface_t ifx : interface to be configured
-  * @param     wifi_bandwidth_t bw : bandwidth
+  * @param     ifx  interface to be configured
+  * @param     bw  bandwidth
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - others: refer to error codes in esp_err.h
   */
 esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
 
@@ -389,45 +382,45 @@ esp_err_t esp_wifi_set_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t bw);
   *
   * @attention 1. API return false if try to get a interface that is not enable
   *
-  * @param     wifi_interface_t ifx : interface to be configured
-  * @param     wifi_bandwidth_t *bw : store bandwidth  of interface ifx
+  * @param     ifx interface to be configured
+  * @param[out] bw  store bandwidth of interface ifx
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_bandwidth(wifi_interface_t ifx, wifi_bandwidth_t *bw);
 
 /**
-  * @brief     Set primary/second channel of ESP32
+  * @brief     Set primary/secondary channel of ESP32
   *
   * @attention 1. This is a special API for sniffer
   *
-  * @param     uint8_t primary : for HT20, primary is the channel number, for HT40, primary is the primary channel
-  * @param     wifi_second_chan_t second : for HT20, second is ignored, for HT40, second is the second channel
+  * @param     primary  for HT20, primary is the channel number, for HT40, primary is the primary channel
+  * @param     second   for HT20, second is ignored, for HT40, second is the second channel
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_set_channel(uint8_t primary, wifi_second_chan_t second);
 
 /**
-  * @brief     Get the primary/second channel of ESP32
+  * @brief     Get the primary/secondary channel of ESP32
   *
   * @attention 1. API return false if try to get a interface that is not enable
   *
-  * @param     uint8_t *primary : store current primary channel
-  * @param     wifi_second_chan_t *second : store current second channel
+  * @param     primary   store current primary channel
+  * @param[out]  second  store current second channel
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
 
@@ -435,25 +428,25 @@ esp_err_t esp_wifi_get_channel(uint8_t *primary, wifi_second_chan_t *second);
   * @brief     Set country code
   *            The default value is WIFI_COUNTRY_CN
   *
-  * @param     wifi_country_t country : country type
+  * @param     country  country type
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - others: refer to error code in esp_err.h
   */
 esp_err_t esp_wifi_set_country(wifi_country_t country);
 
 /**
   * @brief     Get country code
   *
-  * @param     wifi_country_t country : store current country
+  * @param     country  store current country
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_country(wifi_country_t *country);
 
@@ -462,43 +455,44 @@ esp_err_t esp_wifi_get_country(wifi_country_t *country);
   *
   * @attention 1. This API can only be called when the interface is disabled
   * @attention 2. ESP32 soft-AP and station have different MAC addresses, do not set them to be the same.
-  *    - The bit0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address
+  * @attention 3. The bit 0 of the first byte of ESP32 MAC address can not be 1. For example, the MAC address
   *      can set to be "1a:XX:XX:XX:XX:XX", but can not be "15:XX:XX:XX:XX:XX".
   *
-  * @param     wifi_interface_t ifx : interface
-  * @param     uint8 mac[6]: the MAC address.
+  * @param     ifx  interface
+  * @param     mac  the MAC address
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_MAC : invalid mac address
-  *    - ESP_ERR_WIFI_MODE : WiFi mode is wrong
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_MAC: invalid mac address
+  *    - ESP_ERR_WIFI_MODE: WiFi mode is wrong
+  *    - others: refer to error codes in esp_err.h
   */
 esp_err_t esp_wifi_set_mac(wifi_interface_t ifx, uint8_t mac[6]);
 
 /**
   * @brief     Get mac of specified interface
   *
-  * @param     uint8_t mac[6] : store mac of this interface ifx
+  * @param      ifx  interface
+  * @param[out] mac  store mac of the interface ifx
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_IF : invalid interface
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF: invalid interface
   */
 esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
 
 /**
   * @brief The RX callback function in the promiscuous mode.
   *
-  *        Each time a packet is received, the callback function will be called.
+  * Each time a packet is received, the callback function will be called.
   *
-  * @param void *buf : the data received
-  * @param uint16_t len : data length
+  * @param buf  the data received
+  * @param len  data length
   *
   * @return    none
   */
@@ -507,36 +501,36 @@ typedef void (* wifi_promiscuous_cb_t)(void *buf, uint16_t len);
 /**
   * @brief Register the RX callback function in the promiscuous mode.
   *
-  *        Each time a packet is received, the registered callback function will be called.
+  * Each time a packet is received, the registered callback function will be called.
   *
-  * @param wifi_promiscuous_cb_t cb : callback
+  * @param cb  callback
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
   */
 esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
 
 /**
   * @brief     Enable the promiscuous mode.
   *
-  * @param     bool promiscuous : false - disable / true - enable
+  * @param     en  false - disable, true - enable
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
   */
 esp_err_t esp_wifi_set_promiscuous(bool en);
 
 /**
   * @brief     Get the promiscuous mode.
   *
-  * @param     bool *enable : store the current status of promiscuous mode
+  * @param[out] en  store the current status of promiscuous mode
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT  : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_promiscuous(bool *en);
 
@@ -548,32 +542,32 @@ esp_err_t esp_wifi_get_promiscuous(bool *en);
   * @attention 3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as
   *               the channel of the ESP32 station.
   *
-  * @param     wifi_interface_t ifx : interface
-  * @param     wifi_config_t *conf : station or soft-AP configuration
+  * @param     ifx  interface
+  * @param     conf  station or soft-AP configuration
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_IF : invalid interface
-  *    - ESP_ERR_WIFI_MODE : invalid mode
-  *    - ESP_ERR_WIFI_PASSWORD : invalid password
-  *    - ESP_ERR_WIFI_NVS : WiFi internal NVS error
-  *    - others : refer to the erro code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF: invalid interface
+  *    - ESP_ERR_WIFI_MODE: invalid mode
+  *    - ESP_ERR_WIFI_PASSWORD: invalid password
+  *    - ESP_ERR_WIFI_NVS: WiFi internal NVS error
+  *    - others: refer to the erro code in esp_err.h
   */
 esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
 
 /**
   * @brief     Get configuration of specified interface
   *
-  * @param     wifi_interface_t ifx : interface
-  * @param     wifi_config_t *conf : station or soft-AP configuration
+  * @param     ifx  interface
+  * @param[out]  conf  station or soft-AP configuration
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_IF : invalid interface
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_IF: invalid interface
   */
 esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
 
@@ -582,14 +576,14 @@ esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
   *
   * @attention SSC only API
   *
-  * @param     wifi_sta_list_t *sta:  station list
+  * @param[out] sta  station list
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_MODE : WiFi mode is wrong
-  *    - ESP_ERR_WIFI_CONN : WiFi internal error, the station/soft-AP control block is invalid
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_MODE: WiFi mode is wrong
+  *    - ESP_ERR_WIFI_CONN: WiFi internal error, the station/soft-AP control block is invalid
   */
 esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
 
@@ -599,12 +593,12 @@ esp_err_t esp_wifi_ap_get_sta_list(wifi_sta_list_t *sta);
   *
   * @attention 1. The default value is WIFI_STORAGE_FLASH
   *
-  * @param     wifi_storage_t storage : storage type
+  * @param     storage : storage type
   *
   * @return
-  *   - ESP_OK : succeed
-  *   - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *   - ESP_ERR_WIFI_ARG : invalid argument
+  *   - ESP_OK: succeed
+  *   - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *   - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_set_storage(wifi_storage_t storage);
 
@@ -612,72 +606,63 @@ esp_err_t esp_wifi_set_storage(wifi_storage_t storage);
   * @brief     Set auto connect
   *            The default value is true
   *
-  * @param     bool en : true - enable auto connect / false - disable auto connect
+  * @param     en : true - enable auto connect / false - disable auto connect
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_MODE : WiFi internal error, the station/soft-AP control block is invalid
-  *    - others : refer to error code in esp_err.h
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_MODE: WiFi internal error, the station/soft-AP control block is invalid
+  *    - others: refer to error code in esp_err.h
   */
 esp_err_t esp_wifi_set_auto_connect(bool en);
 
 /**
   * @brief     Get the auto connect flag
   *
-  * @param     bool *en : store current auto connect configuration
+  * @param[out] en  store current auto connect configuration
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
   */
 esp_err_t esp_wifi_get_auto_connect(bool *en);
 
 /**
   * @brief     Set vendor specific element
   *
-  * @param     bool enable : enable or not
-  * @param     wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON
-  *                           1 - WIFI_VND_IE_TYPE_PROBE_REQ
-  *                           2 - WIFI_VND_IE_TYPE_PROBE_RESP
-  *                           3 - WIFI_VND_IE_TYPE_ASSOC_REQ
-  *                           4 - WIFI_VND_IE_TYPE_ASSOC_RESP
-  * @param     wifi_vendor_ie_id_t idx : 0 - WIFI_VND_IE_ID_0
-                                    1 - WIFI_VND_IE_ID_1
-  * @param     uint8_t *vnd_ie : pointer to a vendor specific element
+  * @param     enable  enable or not
+  * @param     type  information element type
+  * @param     idx  information element index
+  * @param     vnd_ie  pointer to a vendor specific element
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
-  *    - ESP_ERR_WIFI_ARG : invalid argument
-  *    - ESP_ERR_WIFI_NO_MEM : out of memory
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
+  *    - ESP_ERR_WIFI_ARG: invalid argument
+  *    - ESP_ERR_WIFI_NO_MEM: out of memory
   */
 esp_err_t esp_wifi_set_vendor_ie(bool enable, wifi_vendor_ie_type_t type, wifi_vendor_ie_id_t idx, uint8_t *vnd_ie);
 
 /**
   * @brief     Define function pointer for vendor specific element callback
-  * @param     void *ctx : reserved
-  * @param     wifi_vendor_ie_type_t type : 0 - WIFI_VND_IE_TYPE_BEACON
-  *                           1 - WIFI_VND_IE_TYPE_PROBE_REQ
-  *                           2 - WIFI_VND_IE_TYPE_PROBE_RESP
-  *                           3 - WIFI_VND_IE_TYPE_ASSOC_REQ
-  *                           4 - WIFI_VND_IE_TYPE_ASSOC_RESP
-  * @param     const uint8_t sa[6] : source address
-  * @param     const uint8_t *vnd_ie : pointer to a vendor specific element
-  * @param     int rssi : received signal strength indication
+  * @param     ctx  reserved
+  * @param     type  information element type 
+  * @param     sa  source address
+  * @param     vnd_ie  pointer to a vendor specific element
+  * @param     rssi  received signal strength indication
   */
 typedef void (*esp_vendor_ie_cb_t) (void *ctx, wifi_vendor_ie_type_t type, const uint8_t sa[6], const uint8_t *vnd_ie, int rssi);
 
 /**
   * @brief     Set vendor specific element callback
   *
-  * @param     esp_vendor_ie_cb_t cb : callback function
-  * @param     void *ctx : reserved
+  * @param     cb   callback function
+  * @param     ctx  reserved
   *
   * @return
-  *    - ESP_OK : succeed
-  *    - ESP_ERR_WIFI_NOT_INIT : WiFi is not initialized by eps_wifi_init
+  *    - ESP_OK: succeed
+  *    - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init
   */
 esp_err_t esp_wifi_set_vendor_ie_cb(esp_vendor_ie_cb_t cb, void *ctx);
 

+ 111 - 0
components/esp32/include/esp_wps.h

@@ -0,0 +1,111 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef __ESP_WPS_H__
+#define __ESP_WPS_H__
+
+#include <stdbool.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup WiFi_APIs WiFi Related APIs
+  * @brief WiFi APIs
+  */
+
+/** @addtogroup WiFi_APIs
+  * @{
+  */
+
+/** \defgroup WPS_APIs  WPS APIs
+  * @brief ESP32 WPS APIs
+  *
+  * WPS can only be used when ESP32 station is enabled.
+  *
+  */
+
+/** @addtogroup WPS_APIs
+  * @{
+  */
+
+#define ESP_ERR_WIFI_REGISTRAR   (ESP_ERR_WIFI_BASE + 51)  /*!< WPS registrar is not supported */
+#define ESP_ERR_WIFI_WPS_TYPE    (ESP_ERR_WIFI_BASE + 52)  /*!< WPS type error */
+#define ESP_ERR_WIFI_WPS_SM      (ESP_ERR_WIFI_BASE + 53)  /*!< WPS state machine is not initialized */
+
+typedef enum wps_type {
+    WPS_TYPE_DISABLE = 0,
+    WPS_TYPE_PBC,
+    WPS_TYPE_PIN,
+    WPS_TYPE_MAX,
+} wps_type_t;
+
+/**
+  * @brief     Enable Wi-Fi WPS function.
+  *
+  * @attention WPS can only be used when ESP32 station is enabled.
+  *
+  * @param     wps_type_t wps_type : WPS type, so far only WPS_TYPE_PBC and WPS_TYPE_PIN is supported
+  *
+  * @return    
+  *          - ESP_OK : succeed
+  *          - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
+  *          - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
+  *          - ESP_ERR_WIFI_FAIL : wps initialization fails
+  */
+esp_err_t esp_wifi_wps_enable(wps_type_t wps_type);
+
+/**
+  * @brief  Disable Wi-Fi WPS function and release resource it taken.
+  *
+  * @param  null
+  *
+  * @return    
+  *          - ESP_OK : succeed
+  *          - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
+  */
+esp_err_t esp_wifi_wps_disable(void);
+
+/**
+  * @brief     WPS starts to work.
+  *
+  * @attention WPS can only be used when ESP32 station is enabled.
+  *
+  * @param     timeout_ms : maximum blocking time before API return.
+  *          - 0 : non-blocking
+  *          - 1~120000 : blocking time (not supported in IDF v1.0)
+  *
+  * @return    
+  *          - ESP_OK : succeed
+  *          - ESP_ERR_WIFI_WPS_TYPE : wps type is invalid
+  *          - ESP_ERR_WIFI_WPS_MODE : wifi is not in station mode or sniffer mode is on
+  *          - ESP_ERR_WIFI_WPS_SM : wps state machine is not initialized
+  *          - ESP_ERR_WIFI_FAIL : wps initialization fails
+  */
+esp_err_t esp_wifi_wps_start(int timeout_ms);
+
+/**
+  * @}
+  */
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_WPS_H__ */

+ 1 - 1
components/esp32/include/rom/secure_boot.h

@@ -25,7 +25,7 @@ void ets_secure_boot_start(void);
 
 void ets_secure_boot_finish(void);
 
-void ets_secure_boot_hash(uint32_t *buf);
+void ets_secure_boot_hash(const uint32_t *buf);
 
 void ets_secure_boot_obtain(void);
 

+ 1 - 0
components/esp32/include/soc/dport_reg.h

@@ -1028,6 +1028,7 @@
 #define DPORT_WIFI_RST_EN_REG          (DR_REG_DPORT_BASE + 0x0D0)
 /* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
 /*description: */
+#define DPORT_MAC_RST (BIT(2))
 #define DPORT_WIFI_RST  0xFFFFFFFF
 #define DPORT_WIFI_RST_M  ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S))
 #define DPORT_WIFI_RST_V  0xFFFFFFFF

+ 26 - 0
components/esp32/include/soc/efuse_reg.h

@@ -29,6 +29,16 @@
 #define EFUSE_RD_EFUSE_RD_DIS_M  ((EFUSE_RD_EFUSE_RD_DIS_V)<<(EFUSE_RD_EFUSE_RD_DIS_S))
 #define EFUSE_RD_EFUSE_RD_DIS_V  0xF
 #define EFUSE_RD_EFUSE_RD_DIS_S  16
+
+/* Read disable bits for efuse blocks 1-3 */
+#define EFUSE_RD_DIS_BLK1 (1<<16)
+#define EFUSE_RD_DIS_BLK2 (1<<17)
+#define EFUSE_RD_DIS_BLK3 (1<<18)
+/* Read disable FLASH_CRYPT_CONFIG, CODING_SCHEME & KEY_STATUS
+   in efuse block 0
+*/
+#define EFUSE_RD_DIS_BLK0_PARTIAL (1<<19)
+
 /* EFUSE_RD_EFUSE_WR_DIS : RO ;bitpos:[15:0] ;default: 16'b0 ; */
 /*description: read for efuse_wr_disable*/
 #define EFUSE_RD_EFUSE_WR_DIS  0x0000FFFF
@@ -36,6 +46,22 @@
 #define EFUSE_RD_EFUSE_WR_DIS_V  0xFFFF
 #define EFUSE_RD_EFUSE_WR_DIS_S  0
 
+/* Write disable bits */
+#define EFUSE_WR_DIS_RD_DIS (1<<0) /*< disable writing read disable reg */
+#define EFUSE_WR_DIS_WR_DIS (1<<1) /*< disable writing write disable reg */
+#define EFUSE_WR_DIS_FLASH_CRYPT_CNT (1<<2)
+#define EFUSE_WR_DIS_MAC_SPI_CONFIG_HD (1<<3) /*< disable writing MAC & SPI config hd efuses */
+#define EFUSE_WR_DIS_XPD_SDIO (1<<5) /*< disable writing SDIO config efuses */
+#define EFUSE_WR_DIS_SPI_PAD_CONFIG (1<<6) /*< disable writing SPI_PAD_CONFIG efuses */
+#define EFUSE_WR_DIS_BLK1 (1<<7) /*< disable writing BLK1 efuses */
+#define EFUSE_WR_DIS_BLK2 (1<<8) /*< disable writing BLK2 efuses */
+#define EFUSE_WR_DIS_BLK3 (1<<9) /*< disable writing BLK3 efuses */
+#define EFUSE_WR_DIS_FLASH_CRYPT_CODING_SCHEME (1<<10) /*< disable writing FLASH_CRYPT_CONFIG and CODING_SCHEME efuses */
+#define EFUSE_WR_DIS_ABS_DONE_0 (1<<12) /*< disable writing ABS_DONE_0 efuse */
+#define EFUSE_WR_DIS_ABS_DONE_1 (1<<13) /*< disable writing ABS_DONE_1 efuse */
+#define EFUSE_WR_DIS_JTAG_DISABLE (1<<14) /*< disable writing JTAG_DISABLE efuse */
+#define EFUSE_WR_DIS_CONSOLE_DL_DISABLE (1<<15) /*< disable writing CONSOLE_DEBUG_DISABLE, DISABLE_DL_ENCRYPT, DISABLE_DL_DECRYPT and DISABLE_DL_CACHE efuses */
+
 #define EFUSE_BLK0_RDATA1_REG          (DR_REG_EFUSE_BASE + 0x004)
 /* EFUSE_RD_WIFI_MAC_CRC_LOW : RO ;bitpos:[31:0] ;default: 32'b0 ; */
 /*description: read for low 32bit WIFI_MAC_Address*/

+ 37 - 0
components/esp32/include/soc/hwcrypto_reg.h

@@ -0,0 +1,37 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __HWCRYPTO_REG_H__
+#define __HWCRYPTO_REG_H__
+
+#include "soc.h"
+
+/* registers for RSA acceleration via Multiple Precision Integer ops */
+#define RSA_MEM_M_BLOCK_BASE          ((DR_REG_RSA_BASE)+0x000)
+/* RB & Z use the same memory block, depending on phase of operation */
+#define RSA_MEM_RB_BLOCK_BASE         ((DR_REG_RSA_BASE)+0x200)
+#define RSA_MEM_Z_BLOCK_BASE          ((DR_REG_RSA_BASE)+0x200)
+#define RSA_MEM_Y_BLOCK_BASE          ((DR_REG_RSA_BASE)+0x400)
+#define RSA_MEM_X_BLOCK_BASE          ((DR_REG_RSA_BASE)+0x600)
+
+#define RSA_M_DASH_REG                (DR_REG_RSA_BASE + 0x800)
+#define RSA_MODEXP_MODE_REG           (DR_REG_RSA_BASE + 0x804)
+#define RSA_START_MODEXP_REG          (DR_REG_RSA_BASE + 0x808)
+#define RSA_MULT_MODE_REG             (DR_REG_RSA_BASE + 0x80c)
+#define RSA_MULT_START_REG            (DR_REG_RSA_BASE + 0x810)
+
+#define RSA_INTERRUPT_REG             (DR_REG_RSA_BASE + 0X814)
+
+#define RSA_CLEAN_ADDR                (DR_REG_RSA_BASE + 0X818)
+
+#endif

+ 35 - 4
components/esp32/include/soc/io_mux_reg.h

@@ -34,10 +34,41 @@
 #define PIN_INPUT_ENABLE(PIN_NAME)               SET_PERI_REG_MASK(PIN_NAME,FUN_IE)
 #define PIN_INPUT_DISABLE(PIN_NAME)              CLEAR_PERI_REG_MASK(PIN_NAME,FUN_IE)
 #define PIN_SET_DRV(PIN_NAME, drv)            REG_SET_FIELD(PIN_NAME, FUN_DRV, (drv));
-#define PIN_PULLUP_DIS(PIN_NAME)                 REG_CLR_BIT(PIN_NAME, FUN_PU)
-#define PIN_PULLUP_EN(PIN_NAME)                  REG_SET_BIT(PIN_NAME, FUN_PU)
-#define PIN_PULLDWN_DIS(PIN_NAME)             REG_CLR_BIT(PIN_NAME, FUN_PD)
-#define PIN_PULLDWN_EN(PIN_NAME)              REG_SET_BIT(PIN_NAME, FUN_PD)
+
+/*
+ * @attention
+ *     The PIN_PULL[UP|DWN]_[EN|DIS]() functions used to exist as macros in previous SDK versions. 
+ *     Unfortunately, however, they do not work for some GPIOs on the ESP32 chip, which needs pullups 
+ *     and -downs turned on and off through RTC registers. The functions still exist for compatibility 
+ *     with older code, but are marked as deprecated in order to generate a warning.
+ *     Please replace them in this fashion: (make sure to include driver/gpio.h as well)
+ *     PIN_PULLUP_EN(GPIO_PIN_MUX_REG[x])   ->  gpio_pullup_en(x)
+ *     PIN_PULLUP_DIS(GPIO_PIN_MUX_REG[x])  ->  gpio_pullup_dis(x)
+ *     PIN_PULLDWN_EN(GPIO_PIN_MUX_REG[x])  ->  gpio_pulldown_en(x)
+ *     PIN_PULLDWN_DIS(GPIO_PIN_MUX_REG[x]) ->  gpio_pulldown_dis(x)
+ *
+*/
+static inline void __attribute__ ((deprecated)) PIN_PULLUP_DIS(uint32_t PIN_NAME) 
+{
+    REG_CLR_BIT(PIN_NAME, FUN_PU);
+}
+
+static inline void __attribute__ ((deprecated)) PIN_PULLUP_EN(uint32_t PIN_NAME)
+{
+    REG_SET_BIT(PIN_NAME, FUN_PU);
+}
+
+static inline void __attribute__ ((deprecated)) PIN_PULLDWN_DIS(uint32_t PIN_NAME)
+{
+    REG_CLR_BIT(PIN_NAME, FUN_PD);
+}
+
+static inline void __attribute__ ((deprecated)) PIN_PULLDWN_EN(uint32_t PIN_NAME)
+{
+    REG_SET_BIT(PIN_NAME, FUN_PD);
+}
+
+
 #define PIN_FUNC_SELECT(PIN_NAME, FUNC)      REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
 
 #define PIN_FUNC_GPIO                               2

+ 1 - 0
components/esp32/include/soc/soc.h

@@ -141,6 +141,7 @@
 //}}
 
 #define DR_REG_DPORT_BASE                       0x3ff00000
+#define DR_REG_RSA_BASE                         0x3ff02000
 #define DR_REG_UART_BASE                        0x3ff40000
 #define DR_REG_SPI1_BASE                        0x3ff42000
 #define DR_REG_SPI0_BASE                        0x3ff43000

+ 3 - 1
components/esp32/include/soc/uart_reg.h

@@ -18,8 +18,10 @@
 #include "soc.h"
 
 #define REG_UART_BASE( i )  (DR_REG_UART_BASE + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) )
-
+#define REG_UART_AHB_BASE(i)  (0x60000000 + (i) * 0x10000 + ( i > 1 ? 0xe000 : 0 ) )
+#define UART_FIFO_AHB_REG(i)  (REG_UART_AHB_BASE(i) + 0x0)
 #define UART_FIFO_REG(i)          (REG_UART_BASE(i) + 0x0)
+
 /* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
 /*description: This register stores one byte data  read by rx fifo.*/
 #define UART_RXFIFO_RD_BYTE  0x000000FF

+ 32 - 28
components/esp32/int_wdt.c

@@ -25,6 +25,7 @@
 #include "esp_err.h"
 #include "esp_intr.h"
 #include "esp_attr.h"
+#include "esp_freertos_hooks.h"
 #include "soc/timer_group_struct.h"
 #include "soc/timer_group_reg.h"
 
@@ -36,38 +37,12 @@
 #define WDT_INT_NUM 24
 
 
-void esp_int_wdt_init() {
-    TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
-    TIMERG1.wdt_config0.sys_reset_length=7;                 //3.2uS
-    TIMERG1.wdt_config0.cpu_reset_length=7;                 //3.2uS
-    TIMERG1.wdt_config0.level_int_en=1;
-    TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT;          //1st stage timeout: interrupt
-    TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
-    TIMERG1.wdt_config1.clk_prescale=80*500;                //Prescaler: wdt counts in ticks of 0.5mS
-    //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
-    //it to their actual value.
-    TIMERG1.wdt_config2=10000;
-    TIMERG1.wdt_config3=10000;
-    TIMERG1.wdt_config0.en=1;
-    TIMERG1.wdt_feed=1;
-    TIMERG1.wdt_wprotect=0;
-    TIMERG1.int_clr_timers.wdt=1;
-    TIMERG1.int_ena.wdt=1;
-    ESP_INTR_DISABLE(WDT_INT_NUM);
-    intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
-    //We do not register a handler for the interrupt because it is interrupt level 4 which
-    //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
-    //this interrupt.
-    ESP_INTR_ENABLE(WDT_INT_NUM);
-}
-
-
 //Take care: the tick hook can also be called before esp_int_wdt_init() is called.
 #if CONFIG_INT_WDT_CHECK_CPU1
 //Not static; the ISR assembly checks this.
 bool int_wdt_app_cpu_ticked=false;
 
-void IRAM_ATTR vApplicationTickHook(void) {
+static void IRAM_ATTR tick_hook(void) {
     if (xPortGetCoreID()!=0) {
         int_wdt_app_cpu_ticked=true;
     } else {
@@ -83,7 +58,7 @@ void IRAM_ATTR vApplicationTickHook(void) {
     }
 }
 #else
-void IRAM_ATTR vApplicationTickHook(void) {
+static void IRAM_ATTR tick_hook(void) {
     if (xPortGetCoreID()!=0) return;
     TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
     TIMERG1.wdt_config2=CONFIG_INT_WDT_TIMEOUT_MS*2;        //Set timeout before interrupt
@@ -93,4 +68,33 @@ void IRAM_ATTR vApplicationTickHook(void) {
 }
 #endif
 
+
+void esp_int_wdt_init() {
+    TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
+    TIMERG1.wdt_config0.sys_reset_length=7;                 //3.2uS
+    TIMERG1.wdt_config0.cpu_reset_length=7;                 //3.2uS
+    TIMERG1.wdt_config0.level_int_en=1;
+    TIMERG1.wdt_config0.stg0=TIMG_WDT_STG_SEL_INT;          //1st stage timeout: interrupt
+    TIMERG1.wdt_config0.stg1=TIMG_WDT_STG_SEL_RESET_SYSTEM; //2nd stage timeout: reset system
+    TIMERG1.wdt_config1.clk_prescale=80*500;                //Prescaler: wdt counts in ticks of 0.5mS
+    //The timer configs initially are set to 5 seconds, to make sure the CPU can start up. The tick hook sets
+    //it to their actual value.
+    TIMERG1.wdt_config2=10000;
+    TIMERG1.wdt_config3=10000;
+    TIMERG1.wdt_config0.en=1;
+    TIMERG1.wdt_feed=1;
+    TIMERG1.wdt_wprotect=0;
+    TIMERG1.int_clr_timers.wdt=1;
+    TIMERG1.int_ena.wdt=1;
+    esp_register_freertos_tick_hook(tick_hook);
+    ESP_INTR_DISABLE(WDT_INT_NUM);
+    intr_matrix_set(xPortGetCoreID(), ETS_TG1_WDT_LEVEL_INTR_SOURCE, WDT_INT_NUM);
+    //We do not register a handler for the interrupt because it is interrupt level 4 which
+    //is not servicable from C. Instead, xtensa_vectors.S has a call to the panic handler for
+    //this interrupt.
+    ESP_INTR_ENABLE(WDT_INT_NUM);
+}
+
+
+
 #endif

+ 1 - 1
components/esp32/lib

@@ -1 +1 @@
-Subproject commit 76f91098061b0052fe1bb67e85001014f39b84a0
+Subproject commit ea9c156e8a67d27623eab6f98ce5a55a00c8fb19

+ 64 - 0
components/esp32/phy.h

@@ -0,0 +1,64 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+#include "esp_phy_init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file phy.h
+ * @brief Declarations for functions provided by libphy.a
+ */
+
+/**
+ * @brief Initialize function pointer table in PHY library.
+ * @note This function should be called before register_chipv7_phy.
+ */
+void phy_get_romfunc_addr(void);
+
+/**
+ * @brief Initialize PHY module and do RF calibration
+ * @param[in] init_data Initialization parameters to be used by the PHY
+ * @param[inout] cal_data As input, calibration data previously obtained. As output, will contain new calibration data.
+ * @param[in] cal_mode  RF calibration mode
+ * @return reserved for future use
+ */
+int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibration_data_t *cal_data, esp_phy_calibration_mode_t cal_mode);
+
+/**
+ * @brief Get the format version of calibration data used by PHY library.
+ * @return Format version number, OR'ed with BIT(16) if PHY is in WIFI only mode.
+ */
+uint32_t phy_get_rf_cal_version();
+
+/**
+ * @brief Set RF/BB for only WIFI mode or coexist(WIFI & BT) mode
+ * @param[in] true is for only WIFI mode, false is for coexist mode. default is 0.
+ * @return NULL
+ */
+void phy_set_wifi_mode_only(bool wifi_only);
+
+/**
+ * @brief Set BT the highest priority in coexist mode.
+ * @return NULL
+ */
+void coex_bt_high_prio(void);
+
+#ifdef __cplusplus
+}
+#endif
+

+ 224 - 0
components/esp32/phy_init.c

@@ -0,0 +1,224 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include "rom/ets_sys.h"
+#include "soc/dport_reg.h"
+
+#include "esp_err.h"
+#include "esp_phy_init.h"
+#include "esp_system.h"
+#include "phy.h"
+#include "esp_log.h"
+#include "nvs.h"
+#include "sdkconfig.h"
+#include "phy_init_data.h"
+
+static const char* TAG = "phy_init";
+
+
+esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
+        esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data)
+{
+    assert(init_data);
+    assert(calibration_data);
+    // Initialize PHY pointer table
+    phy_get_romfunc_addr();
+    REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
+    REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
+    // Enable WiFi peripheral clock
+    SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
+    ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
+            init_data, calibration_data, mode);
+    phy_set_wifi_mode_only(0);
+    register_chipv7_phy(init_data, calibration_data, mode);
+    coex_bt_high_prio();
+    return ESP_OK;
+}
+
+// PHY init data handling functions
+#if CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
+#include "esp_partition.h"
+
+const esp_phy_init_data_t* esp_phy_get_init_data()
+{
+    const esp_partition_t* partition = esp_partition_find_first(
+            ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL);
+    if (partition == NULL) {
+        ESP_LOGE(TAG, "PHY data partition not found");
+        return NULL;
+    }
+    ESP_LOGD(TAG, "loading PHY init data from partition at offset 0x%x", partition->address);
+    size_t init_data_store_length = sizeof(phy_init_magic_pre) +
+            sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post);
+    uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length);
+    if (init_data_store == NULL) {
+        ESP_LOGE(TAG, "failed to allocate memory for PHY init data");
+        return NULL;
+    }
+    esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err);
+        return NULL;
+    }
+    if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 ||
+        memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post),
+                PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) {
+        ESP_LOGE(TAG, "failed to validate PHY data partition");
+        return NULL;
+    }
+    ESP_LOGE(TAG, "PHY data partition validated");
+    return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre));
+}
+
+void esp_phy_release_init_data(const esp_phy_init_data_t* init_data)
+{
+    free((uint8_t*) init_data - sizeof(phy_init_magic_pre));
+}
+
+#else // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
+
+// phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data
+
+const esp_phy_init_data_t* esp_phy_get_init_data()
+{
+    ESP_LOGD(TAG, "loading PHY init data from application binary");
+    return &phy_init_data;
+}
+
+void esp_phy_release_init_data(const esp_phy_init_data_t* init_data)
+{
+    // no-op
+}
+#endif // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
+
+
+// PHY calibration data handling functions
+static const char* PHY_NAMESPACE = "phy";
+static const char* PHY_CAL_VERSION_KEY = "cal_version";
+static const char* PHY_CAL_MAC_KEY = "cal_mac";
+static const char* PHY_CAL_DATA_KEY = "cal_data";
+
+static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle,
+        esp_phy_calibration_data_t* out_cal_data);
+
+static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
+        const esp_phy_calibration_data_t* cal_data);
+
+esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data)
+{
+    nvs_handle handle;
+    esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle);
+    if (err != ESP_OK) {
+        ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
+        return err;
+    }
+    else {
+        err = load_cal_data_from_nvs_handle(handle, out_cal_data);
+        nvs_close(handle);
+        return err;
+    }
+}
+
+esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data)
+{
+    nvs_handle handle;
+    esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle);
+    if (err != ESP_OK) {
+        ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
+        return err;
+    }
+    else {
+        err = store_cal_data_to_nvs_handle(handle, cal_data);
+        nvs_close(handle);
+        return err;
+    }
+}
+
+static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle,
+        esp_phy_calibration_data_t* out_cal_data)
+{
+    esp_err_t err;
+    uint32_t cal_data_version;
+    err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version);
+    if (err != ESP_OK) {
+        ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err);
+        return err;
+    }
+    uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
+    ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
+    if (cal_data_version != cal_format_version) {
+        ESP_LOGD(TAG, "%s: expected calibration data format %d, found %d",
+                __func__, cal_format_version, cal_data_version);
+        return ESP_FAIL;
+    }
+    uint8_t cal_data_mac[6];
+    size_t length = sizeof(cal_data_mac);
+    err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length);
+    if (err != ESP_OK) {
+        ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err);
+        return err;
+    }
+    if (length != sizeof(cal_data_mac)) {
+        ESP_LOGD(TAG, "%s: invalid length of cal_mac (%d)", __func__, length);
+        return ESP_ERR_INVALID_SIZE;
+    }
+    uint8_t sta_mac[6];
+    system_efuse_read_mac(sta_mac);
+    if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) {
+        ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \
+                MACSTR ", found " MACSTR,
+                __func__, MAC2STR(sta_mac), MAC2STR(cal_data_mac));
+        return ESP_FAIL;
+    }
+    length = sizeof(*out_cal_data);
+    err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err);
+        return err;
+    }
+    if (length != sizeof(*out_cal_data)) {
+        ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length);
+        return ESP_ERR_INVALID_SIZE;
+    }
+    return ESP_OK;
+}
+
+static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle,
+        const esp_phy_calibration_data_t* cal_data)
+{
+    esp_err_t err;
+    uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16));
+    ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version);
+    err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version);
+    if (err != ESP_OK) {
+        return err;
+    }
+    uint8_t sta_mac[6];
+    system_efuse_read_mac(sta_mac);
+    err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac));
+    if (err != ESP_OK) {
+        return err;
+    }
+    err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data));
+    return err;
+}
+
+void register_chipv7_phy_stub()
+{
+}

+ 139 - 0
components/esp32/phy_init_data.h

@@ -0,0 +1,139 @@
+// Copyright 2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+#include "esp_phy_init.h"
+#include "sdkconfig.h"
+
+// constrain a value between 'low' and 'high', inclusive
+#define LIMIT(val, low, high) ((val < low) ? low : (val > high) ? high : val)
+
+#define PHY_INIT_MAGIC "PHYINIT"
+
+static const char phy_init_magic_pre[] = PHY_INIT_MAGIC;
+
+/**
+ * @brief Structure containing default recommended PHY initialization parameters.
+ */
+static const esp_phy_init_data_t phy_init_data= {
+        .param_ver_id = 0,
+        .crystal_select = 3,
+        .wifi_rx_gain_swp_step_1 = 0x05,
+        .wifi_rx_gain_swp_step_2 = 0x04,
+        .wifi_rx_gain_swp_step_3 = 0x06,
+        .wifi_rx_gain_swp_step_4 = 0x05,
+        .wifi_rx_gain_swp_step_5 = 0x01,
+        .wifi_rx_gain_swp_step_6 = 0x06,
+        .wifi_rx_gain_swp_step_7 = 0x05,
+        .wifi_rx_gain_swp_step_8 = 0x04,
+        .wifi_rx_gain_swp_step_9 = 0x06,
+        .wifi_rx_gain_swp_step_10 = 0x04,
+        .wifi_rx_gain_swp_step_11 = 0x05,
+        .wifi_rx_gain_swp_step_12 = 0x00,
+        .wifi_rx_gain_swp_step_13 = 0x00,
+        .wifi_rx_gain_swp_step_14 = 0x00,
+        .wifi_rx_gain_swp_step_15 = 0x00,
+        .bt_rx_gain_swp_step_1 = 0x05,
+        .bt_rx_gain_swp_step_2 = 0x04,
+        .bt_rx_gain_swp_step_3 = 0x06,
+        .bt_rx_gain_swp_step_4 = 0x05,
+        .bt_rx_gain_swp_step_5 = 0x01,
+        .bt_rx_gain_swp_step_6 = 0x06,
+        .bt_rx_gain_swp_step_7 = 0x05,
+        .bt_rx_gain_swp_step_8 = 0x00,
+        .bt_rx_gain_swp_step_9 = 0x00,
+        .bt_rx_gain_swp_step_10 = 0x00,
+        .bt_rx_gain_swp_step_11 = 0x00,
+        .bt_rx_gain_swp_step_12 = 0x00,
+        .bt_rx_gain_swp_step_13 = 0x00,
+        .bt_rx_gain_swp_step_14 = 0x00,
+        .bt_rx_gain_swp_step_15 = 0x00,
+        .gain_cmp_1 = 0x0a,
+        .gain_cmp_6 = 0x0a,
+        .gain_cmp_11 = 0x0c,
+        .gain_cmp_ext2_1 = 0xf0,
+        .gain_cmp_ext2_6 = 0xf0,
+        .gain_cmp_ext2_11 = 0xf0,
+        .gain_cmp_ext3_1 = 0xe0,
+        .gain_cmp_ext3_6 = 0xe0,
+        .gain_cmp_ext3_11 = 0xe0,
+        .gain_cmp_bt_ofs_1 = 0x18,
+        .gain_cmp_bt_ofs_6 = 0x18,
+        .gain_cmp_bt_ofs_11 = 0x18,
+        .target_power_qdb_0 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 78),
+        .target_power_qdb_1 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 76),
+        .target_power_qdb_2 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 74),
+        .target_power_qdb_3 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 68),
+        .target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 64),
+        .target_power_qdb_5 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52),
+        .target_power_index_mcs0 = 0,
+        .target_power_index_mcs1 = 0,
+        .target_power_index_mcs2 = 1,
+        .target_power_index_mcs3 = 1,
+        .target_power_index_mcs4 = 2,
+        .target_power_index_mcs5 = 3,
+        .target_power_index_mcs6 = 4,
+        .target_power_index_mcs7 = 5,
+        .pwr_ind_11b_en = 0,
+        .pwr_ind_11b_0 = 0,
+        .pwr_ind_11b_1 = 0,
+        .chan_backoff_en = 0,
+        .chan1_power_backoff_qdb = 0,
+        .chan2_power_backoff_qdb = 0,
+        .chan3_power_backoff_qdb = 0,
+        .chan4_power_backoff_qdb = 0,
+        .chan5_power_backoff_qdb = 0,
+        .chan6_power_backoff_qdb = 0,
+        .chan7_power_backoff_qdb = 0,
+        .chan8_power_backoff_qdb = 0,
+        .chan9_power_backoff_qdb = 0,
+        .chan10_power_backoff_qdb = 0,
+        .chan11_power_backoff_qdb = 0,
+        .chan12_power_backoff_qdb = 0,
+        .chan13_power_backoff_qdb = 0,
+        .chan14_power_backoff_qdb = 0,
+        .chan1_rate_backoff_index = 0,
+        .chan2_rate_backoff_index = 0,
+        .chan3_rate_backoff_index = 0,
+        .chan4_rate_backoff_index = 0,
+        .chan5_rate_backoff_index = 0,
+        .chan6_rate_backoff_index = 0,
+        .chan7_rate_backoff_index = 0,
+        .chan8_rate_backoff_index = 0,
+        .chan9_rate_backoff_index = 0,
+        .chan10_rate_backoff_index = 0,
+        .chan11_rate_backoff_index = 0,
+        .chan12_rate_backoff_index = 0,
+        .chan13_rate_backoff_index = 0,
+        .chan14_rate_backoff_index = 0,
+        .spur_freq_cfg_msb_1 = 0,
+        .spur_freq_cfg_1 = 0,
+        .spur_freq_cfg_div_1 = 0,
+        .spur_freq_en_h_1 = 0,
+        .spur_freq_en_l_1 = 0,
+        .spur_freq_cfg_msb_2 = 0,
+        .spur_freq_cfg_2 = 0,
+        .spur_freq_cfg_div_2 = 0,
+        .spur_freq_en_h_2 = 0,
+        .spur_freq_en_l_2 = 0,
+        .spur_freq_cfg_msb_3 = 0,
+        .spur_freq_cfg_3 = 0,
+        .spur_freq_cfg_div_3 = 0,
+        .spur_freq_en_h_3 = 0,
+        .spur_freq_en_l_3 = 0,
+        .reserved = {0}
+};
+
+static const char phy_init_magic_post[] = PHY_INIT_MAGIC;
+

+ 54 - 15
components/esp32/task_wdt.c

@@ -22,10 +22,13 @@
 #include "sdkconfig.h"
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
 #include <esp_types.h>
 #include "esp_err.h"
 #include "esp_intr.h"
 #include "esp_attr.h"
+#include "esp_freertos_hooks.h"
 #include "soc/timer_group_struct.h"
 #include "soc/timer_group_reg.h"
 #include "esp_log.h"
@@ -44,6 +47,8 @@ struct wdt_task_t {
 };
 
 static wdt_task_t *wdt_task_list=NULL;
+static portMUX_TYPE taskwdt_spinlock = portMUX_INITIALIZER_UNLOCKED;
+
 
 static void IRAM_ATTR task_wdt_isr(void *arg) {
     wdt_task_t *wdttask;
@@ -54,24 +59,35 @@ static void IRAM_ATTR task_wdt_isr(void *arg) {
     TIMERG0.wdt_wprotect=0;
     //Ack interrupt
     TIMERG0.int_clr_timers.wdt=1;
+    //We are taking a spinlock while doing I/O (ets_printf) here. Normally, that is a pretty
+    //bad thing, possibly (temporarily) hanging up the 2nd core and stopping FreeRTOS. In this case,
+    //something bad already happened and reporting this is considered more important
+    //than the badness caused by a spinlock here.
+    portENTER_CRITICAL(&taskwdt_spinlock);
+    if (!wdt_task_list) {
+        //No task on list. Maybe none registered yet.
+        portEXIT_CRITICAL(&taskwdt_spinlock);
+        return;
+    }
     //Watchdog got triggered because at least one task did not report in.
-    ets_printf("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n");
+    ets_printf(DRAM_STR("Task watchdog got triggered. The following tasks did not feed the watchdog in time:\n"));
     for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
         if (!wdttask->fed_watchdog) {
-            cpu=xTaskGetAffinity(wdttask->task_handle)==0?"CPU 0":"CPU 1";
-            if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu="CPU 0/1";
-            printf(" - %s (%s)\n", pcTaskGetTaskName(wdttask->task_handle), cpu);
+            cpu=xTaskGetAffinity(wdttask->task_handle)==0?DRAM_STR("CPU 0"):DRAM_STR("CPU 1");
+            if (xTaskGetAffinity(wdttask->task_handle)==tskNO_AFFINITY) cpu=DRAM_STR("CPU 0/1");
+            ets_printf(DRAM_STR(" - %s (%s)\n"), pcTaskGetTaskName(wdttask->task_handle), cpu);
         }
     }
-    ets_printf("Tasks currently running:\n");
+    ets_printf(DRAM_STR("Tasks currently running:\n"));
     for (int x=0; x<portNUM_PROCESSORS; x++) {
-        ets_printf("CPU %d: %s\n", x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
+        ets_printf(DRAM_STR("CPU %d: %s\n"), x, pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(x)));
     }
 
 #if CONFIG_TASK_WDT_PANIC
-    ets_printf("Aborting.\n");
+    ets_printf(DRAM_STR("Aborting.\n"));
     abort();
 #endif
+    portEXIT_CRITICAL(&taskwdt_spinlock);
 }
 
 
@@ -79,6 +95,8 @@ void esp_task_wdt_feed() {
     wdt_task_t *wdttask=wdt_task_list;
     bool found_task=false, do_feed_wdt=true;
     TaskHandle_t handle=xTaskGetCurrentTaskHandle();
+    portENTER_CRITICAL(&taskwdt_spinlock);
+
     //Walk the linked list of wdt tasks to find this one, as well as see if we need to feed
     //the real watchdog timer.
     for (wdttask=wdt_task_list; wdttask!=NULL; wdttask=wdttask->next) {
@@ -113,14 +131,18 @@ void esp_task_wdt_feed() {
         //Reset fed_watchdog status
         for (wdttask=wdt_task_list; wdttask->next!=NULL; wdttask=wdttask->next) wdttask->fed_watchdog=false;
     }
+    portEXIT_CRITICAL(&taskwdt_spinlock);
 }
 
 void esp_task_wdt_delete() {
     TaskHandle_t handle=xTaskGetCurrentTaskHandle();
     wdt_task_t *wdttask=wdt_task_list;
+    portENTER_CRITICAL(&taskwdt_spinlock);
+
     //Wdt task list can't be empty
     if (!wdt_task_list) {
         ESP_LOGE(TAG, "task_wdt_delete: No tasks in list?");
+        portEXIT_CRITICAL(&taskwdt_spinlock);
         return;
     }
     if (handle==wdt_task_list) {
@@ -129,17 +151,39 @@ void esp_task_wdt_delete() {
         free(wdttask);
     } else {
         //Find current task in list
+        if (wdt_task_list->task_handle==handle) {
+            //Task is the very first one.
+            wdt_task_t *freeme=wdt_task_list;
+            wdt_task_list=wdt_task_list->next;
+            free(freeme);
+            portEXIT_CRITICAL(&taskwdt_spinlock);
+            return;
+        }
         while (wdttask->next!=NULL && wdttask->next->task_handle!=handle) wdttask=wdttask->next;
         if (!wdttask->next) {
             ESP_LOGE(TAG, "task_wdt_delete: Task never called task_wdt_feed!");
+            portEXIT_CRITICAL(&taskwdt_spinlock);
             return;
         }
         wdt_task_t *freeme=wdttask->next;
         wdttask->next=wdttask->next->next;
         free(freeme);
     }
+    portEXIT_CRITICAL(&taskwdt_spinlock);
 }
 
+
+#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
+static bool idle_hook(void) {
+#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
+    if (xPortGetCoreID()!=0) return true;
+#endif
+    esp_task_wdt_feed();
+    return true;
+}
+#endif
+
+
 void esp_task_wdt_init() {
     TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
     TIMERG0.wdt_config0.sys_reset_length=7;                 //3.2uS
@@ -153,6 +197,9 @@ void esp_task_wdt_init() {
     TIMERG0.wdt_config0.en=1;
     TIMERG0.wdt_feed=1;
     TIMERG0.wdt_wprotect=0;
+#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
+    esp_register_freertos_idle_hook(idle_hook);
+#endif
     ESP_INTR_DISABLE(ETS_T0_WDT_INUM);
     intr_matrix_set(xPortGetCoreID(), ETS_TG0_WDT_LEVEL_INTR_SOURCE, ETS_T0_WDT_INUM);
     xt_set_interrupt_handler(ETS_T0_WDT_INUM, task_wdt_isr, NULL);
@@ -161,13 +208,5 @@ void esp_task_wdt_init() {
     ESP_INTR_ENABLE(ETS_T0_WDT_INUM);
 }
 
-#if CONFIG_TASK_WDT_CHECK_IDLE_TASK
-void vApplicationIdleHook(void) {
-#if !CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1
-    if (xPortGetCoreID()!=0) return;
-#endif
-    esp_task_wdt_feed();
-}
-#endif
 
 #endif

+ 29 - 7
components/esptool_py/Makefile.projbuild

@@ -11,27 +11,49 @@ PYTHON ?= $(call dequote,$(CONFIG_PYTHON))
 # two commands that can be used from other components
 # to invoke esptool.py (with or without serial port args)
 #
-# NB: esptool.py lives in the sdk/bin directory not the component directory
 ESPTOOLPY_SRC := $(COMPONENT_PATH)/esptool/esptool.py
 ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
 
+# Supporting esptool command line tools
+ESPEFUSEPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espefuse.py
+ESPSECUREPY := $(PYTHON) $(COMPONENT_PATH)/esptool/espsecure.py
+export ESPSECUREPY  # is used in bootloader_support component
+
 ESPTOOL_FLASH_OPTIONS := --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ) --flash_size $(ESPFLASHSIZE)
 
-# the no-stub argument is temporary until esptool.py fully supports compressed uploads
+ESPTOOL_ELF2IMAGE_OPTIONS :=
+
 ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) $(ESPTOOL_FLASH_OPTIONS)
 
 ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
 
-$(APP_BIN): $(APP_ELF) $(ESPTOOLPY_SRC)
-	$(Q) $(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) -o $@ $<
+ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+ifndef IS_BOOTLOADER_BUILD
+# for secure boot, add a signing step to get from unsiged app to signed app
+APP_BIN_UNSIGNED := $(APP_BIN:.bin=-unsigned.bin)
+
+$(APP_BIN): $(APP_BIN_UNSIGNED)
+	$(ESPSECUREPY) sign_data --keyfile $(SECURE_BOOT_SIGNING_KEY) -o $@ $^  # signed in-place
+endif
+endif
+# non-secure boot (or bootloader), both these files are the same
+APP_BIN_UNSIGNED ?= $(APP_BIN)
+
+$(APP_BIN_UNSIGNED): $(APP_ELF) $(ESPTOOLPY_SRC)
+	$(ESPTOOLPY) elf2image $(ESPTOOL_FLASH_OPTIONS) $(ESPTOOL_ELF2IMAGE_OPTIONS) -o $@ $<
 
 flash: all_binaries $(ESPTOOLPY_SRC)
 	@echo "Flashing binaries to serial port $(ESPPORT) (app at offset $(CONFIG_APP_OFFSET))..."
-	$(Q) $(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
+ifdef CONFIG_SECURE_BOOTLOADER_ENABLED
+	@echo "(Secure boot enabled, so bootloader not flashed automatically. See 'make bootloader' output)"
+endif
+	$(ESPTOOLPY_WRITE_FLASH) $(ESPTOOL_ALL_FLASH_ARGS)
 
 app-flash: $(APP_BIN) $(ESPTOOLPY_SRC)
 	@echo "Flashing app to serial port $(ESPPORT), offset $(CONFIG_APP_OFFSET)..."
-	$(Q) $(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
+	$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_APP_OFFSET) $(APP_BIN)
 
-$(eval $(call SubmoduleCheck,$(ESPTOOLPY_SRC),$(COMPONENT_PATH)/esptool))
+# Submodules normally added in component.mk, but can be added
+# at the project level as long as qualified path
+COMPONENT_SUBMODULES += $(COMPONENT_PATH)/esptool

+ 1 - 1
components/esptool_py/esptool

@@ -1 +1 @@
-Subproject commit 5c6962e894e0a118c9a4b5760876433493449260
+Subproject commit b1e00025fa6cbc63062b205259ee70d91bfe4989

+ 0 - 6
components/expat/component.mk

@@ -1,15 +1,9 @@
 #
 # Component Makefile
 #
-# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
-# this will take the sources in this directory, compile them and link them into 
-# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
-# please read the SDK documents if you need to do this.
-#
 COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
 
 COMPONENT_SRCDIRS := library port
 
 CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
 
-include $(IDF_PATH)/make/component_common.mk

+ 32 - 31
components/expat/port/minicheck.c

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

+ 29 - 0
components/freertos/Kconfig

@@ -141,6 +141,35 @@ config FREERTOS_ISR_STACKSIZE
         The interrupt handlers have their own stack. The size of the stack can be defined here. 
         Each processor has its own stack, so the total size occupied will be twice this.
 
+config FREERTOS_LEGACY_HOOKS
+    bool "Use FreeRTOS legacy hooks"
+    default n
+    help
+        FreeRTOS offers a number of hooks/callback functions that are called when a timer
+        tick happens, the idle thread runs etc. esp-idf replaces these by runtime registerable
+        hooks using the esp_register_freertos_xxx_hook system, but for legacy reasons the old
+        hooks can also still be enabled. Please enable this only if you have code that for some
+        reason can't be migrated to the esp_register_freertos_xxx_hook system.
+
+if FREERTOS_LEGACY_HOOKS
+
+config FREERTOS_LEGACY_IDLE_HOOK
+    bool "Enable legacy idle hook"
+    default n
+    help
+        If enabled, FreeRTOS will call a function called vApplicationIdleHook when the idle thread
+        on a CPU is running. Please make sure your code defines such a function.
+
+config FREERTOS_LEGACY_TICK_HOOK
+    bool "Enable legacy tick hook"
+    default n
+    help
+        If enabled, FreeRTOS will call a function called vApplicationTickHook when a FreeRTOS
+        tick is executed. Please make sure your code defines such a function.
+
+endif #FREERTOS_LEGACY_HOOKS
+
+
 menuconfig FREERTOS_DEBUG_INTERNALS
     bool "Debug FreeRTOS internals"
     default n

+ 0 - 1
components/freertos/component.mk

@@ -6,4 +6,3 @@ COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) -Wl,--undefined=uxTopUsedPriority
 COMPONENT_ADD_INCLUDEDIRS := include
 COMPONENT_PRIV_INCLUDEDIRS := include/freertos
 
-include $(IDF_PATH)/make/component_common.mk

+ 2 - 8
components/freertos/include/freertos/FreeRTOSConfig.h

@@ -152,9 +152,9 @@
  *----------------------------------------------------------*/
 
 #define configUSE_PREEMPTION			1
-#define configUSE_IDLE_HOOK				( CONFIG_TASK_WDT_CHECK_IDLE_TASK )
+#define configUSE_IDLE_HOOK				( CONFIG_FREERTOS_LEGACY_IDLE_HOOK )
 
-#define configUSE_TICK_HOOK				( CONFIG_INT_WDT )
+#define configUSE_TICK_HOOK				( CONFIG_FREERTOS_LEGACY_TICK_HOOK )
 
 #define configTICK_RATE_HZ				( CONFIG_FREERTOS_HZ )
 
@@ -265,12 +265,6 @@
 #define INCLUDE_eTaskGetState               1
 #define configUSE_QUEUE_SETS                1
 
-#if (!defined XT_INTEXC_HOOKS)
-#define configXT_INTEXC_HOOKS               1   /* Exception hooks used by certain tests */
-#if configUSE_TRACE_FACILITY_2
-#define configASSERT_2						1	/* Specific to Xtensa port */
-#endif
-#endif
 
 #define configXT_BOARD                      1   /* Board mode */
 #define configXT_SIMULATOR					0

+ 45 - 5
components/freertos/include/freertos/ringbuf.h

@@ -18,22 +18,34 @@ to this bit of memory will block.
 
 The requirement for items to be contiguous is slightly problematic when the only way to place
 the next item would involve a wraparound from the end to the beginning of the ringbuffer. This can
-be solved in two ways:
-- allow_split_items = pdTRUE: The insertion code will split the item in two items; one which fits
+be solved (or not) in a few ways:
+- type = RINGBUF_TYPE_ALLOWSPLIT: The insertion code will split the item in two items; one which fits
 in the space left at the end of the ringbuffer, one that contains the remaining data which is placed
 in the beginning. Two xRingbufferReceive calls will be needed to retrieve the data.
-- allow_split_items = pdFALSE: The insertion code will leave the room at the end of the ringbuffer
+- type = RINGBUF_TYPE_NOSPLIT: The insertion code will leave the room at the end of the ringbuffer
 unused and instead will put the entire item at the start of the ringbuffer, as soon as there is 
 enough free space.
+- type = RINGBUF_TYPE_BYTEBUF: This is your conventional byte-based ringbuffer. It does have no
+overhead, but it has no item contiguousness either: a read will just give you the entire written
+buffer space, or the space up to the end of the buffer, and writes can be broken up in any way 
+possible. Note that this type cannot do a 2nd read before returning the memory of the 1st.
 
 The maximum size of an item will be affected by this decision. When split items are allowed, it's
 acceptable to push items of (buffer_size)-16 bytes into the buffer. When it's not allowed, the
-maximum size is (buffer_size/2)-8 bytes.
+maximum size is (buffer_size/2)-8 bytes. The bytebuf can fill the entire buffer with data, it has
+no overhead.
 */
 
 //An opaque handle for a ringbuff object.
 typedef void * RingbufHandle_t;
 
+//The various types of buffer
+typedef enum {
+	RINGBUF_TYPE_NOSPLIT = 0,
+	RINGBUF_TYPE_ALLOWSPLIT,
+	RINGBUF_TYPE_BYTEBUF
+} ringbuf_type_t;
+
 
 /**
  * @brief  Create a ring buffer
@@ -45,7 +57,7 @@ typedef void * RingbufHandle_t;
  *
  * @return A RingbufHandle_t handle to the created ringbuffer, or NULL in case of error.
  */
-RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items);
+RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type);
 
 
 /**
@@ -120,6 +132,34 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
 void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
 
 
+/**
+ * @brief  Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
+ * to return
+ *
+ * @param  ringbuf - Ring buffer to retrieve the item from
+ * @param  item_size - Pointer to a variable to which the size of the retrieved item will be written.
+ * @param  xTicksToWait - Ticks to wait for items in the ringbuffer.
+ *
+ * @return Pointer to the retrieved item on success; *item_size filled with the length of the 
+ *         item. NULL on timeout, *item_size is untouched in that case.
+ */
+void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size);
+
+
+/**
+ * @brief  Retrieve bytes from a ByteBuf type of ring buffer, specifying the maximum amount of bytes
+ * to return. Call this from an ISR.
+ *
+ * @param  ringbuf - Ring buffer to retrieve the item from
+ * @param  item_size - Pointer to a variable to which the size of the retrieved item will be written.
+ *
+ * @return Pointer to the retrieved item on success; *item_size filled with the length of the 
+ *         item. NULL when the ringbuffer is empty, *item_size is untouched in that case.
+ */
+void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size);
+
+
+
 /**
  * @brief  Return a previously-retrieved item to the ringbuffer
  *

+ 8 - 4
components/freertos/include/freertos/xtensa_api.h

@@ -42,7 +42,8 @@ typedef void (*xt_exc_handler)(XtExcFrame *);
 
 /*
 -------------------------------------------------------------------------------
-  Call this function to set a handler for the specified exception.
+  Call this function to set a handler for the specified exception. The handler
+  will be installed on the core that calls this function.
 
     n        - Exception number (type)
     f        - Handler function address, NULL to uninstall handler.
@@ -61,7 +62,8 @@ extern xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f);
 
 /*
 -------------------------------------------------------------------------------
-  Call this function to set a handler for the specified interrupt.
+  Call this function to set a handler for the specified interrupt. The handler
+  will be installed on the core that calls this function.
  
     n        - Interrupt number.
     f        - Handler function address, NULL to uninstall handler.
@@ -73,7 +75,8 @@ extern xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg);
 
 /*
 -------------------------------------------------------------------------------
-  Call this function to enable the specified interrupts.
+  Call this function to enable the specified interrupts on the core that runs
+  this code.
 
     mask     - Bit mask of interrupts to be enabled.
 -------------------------------------------------------------------------------
@@ -83,7 +86,8 @@ extern void xt_ints_on(unsigned int mask);
 
 /*
 -------------------------------------------------------------------------------
-  Call this function to disable the specified interrupts.
+  Call this function to disable the specified interrupts on the core that runs
+  this code.
 
     mask     - Bit mask of interrupts to be disabled.
 -------------------------------------------------------------------------------

+ 0 - 5
components/freertos/readme_smp.txt

@@ -19,11 +19,6 @@ it would on a single-core system: the other core still will keep on
 executing all it's own. Use a mux, queue or semaphore to protect your
 structures instead.
 
-- While each core has individual interrupts, the handlers are shared. This 
-means that when you set a handler for an interrupt, it will get triggered if 
-the interrupt is triggered on both CPU0 as well as on CPU1. This is something
-we may change in future FreeRTOS-esp32 releases.
-
 - This FreeRTOS version has the task local storage backported from the 8.2.x
 versions. It, however, has an addition: you can also set a callback when you 
 set the pointer. This callback will be called by the idle task, with the 

+ 272 - 88
components/freertos/ringbuf.c

@@ -18,6 +18,7 @@
 #include "freertos/queue.h"
 #include "freertos/xtensa_api.h"
 #include "freertos/ringbuf.h"
+#include "esp_attr.h"
 #include <stdint.h>
 #include <string.h>
 #include <stdlib.h>
@@ -25,6 +26,7 @@
 
 typedef enum {
     flag_allowsplit = 1,
+    flag_bytebuf = 2,
 } rbflag_t;
 
 typedef enum {
@@ -33,8 +35,10 @@ typedef enum {
 } itemflag_t;
 
 
+typedef struct ringbuf_t ringbuf_t;
+
 //The ringbuffer structure
-typedef struct {
+struct  ringbuf_t {
     SemaphoreHandle_t free_space_sem;           //Binary semaphore, wakes up writing threads when there's more free space
     SemaphoreHandle_t items_buffered_sem;       //Binary semaphore, indicates there are new packets in the circular buffer. See remark.
     size_t size;                                //Size of the data storage
@@ -44,7 +48,12 @@ typedef struct {
     uint8_t *data;                              //Data storage
     portMUX_TYPE mux;                           //Spinlock for actual data/ptr/struct modification
     rbflag_t flags;
-} ringbuf_t;
+    size_t maxItemSize;
+   //The following keep function pointers to hold different implementations for ringbuffer management.
+    BaseType_t (*copyItemToRingbufImpl)(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size);
+    uint8_t *(*getItemFromRingbufImpl)(ringbuf_t *rb, size_t *length, int wanted_length);
+    void (*returnItemToRingbufImpl)(ringbuf_t *rb, void *item);
+};
 
 
 
@@ -73,14 +82,81 @@ static int ringbufferFreeMem(ringbuf_t *rb)
     return free_size-1;
 }
 
-//Copies a single item to the ring buffer. Assumes there is space in the ringbuffer and
+
+//Copies a single item to the ring buffer; refuses to split items. Assumes there is space in the ringbuffer and
+//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
+//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
+//later or fail.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static BaseType_t copyItemToRingbufNoSplit(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) 
+{
+    size_t rbuffer_size;
+    rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value
+    configASSERT(((int)rb->write_ptr&3)==0); //write_ptr needs to be 32-bit aligned
+    configASSERT(rb->write_ptr-(rb->data+rb->size) >= sizeof(buf_entry_hdr_t)); //need to have at least the size 
+                                            //of a header to the end of the ringbuff
+    size_t rem_len=(rb->data + rb->size) - rb->write_ptr; //length remaining until end of ringbuffer
+    
+    //See if we have enough contiguous space to write the buffer.
+    if (rem_len < rbuffer_size + sizeof(buf_entry_hdr_t)) {
+        //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
+        //ringbuffer... but we're not allowed to split the buffer. We need to fill the 
+        //rest of the ringbuffer with a dummy item so we can place the data at the _start_ of
+        //the ringbuffer..
+        //First, find out if we actually have enough space at the start of the ringbuffer to
+        //make this work (Again, we need 4 bytes extra because otherwise read_ptr==free_ptr)
+        if (rb->free_ptr-rb->data < rbuffer_size+sizeof(buf_entry_hdr_t)+4) {
+            //Will not fit.
+            return pdFALSE;
+        }
+        //If the read buffer hasn't wrapped around yet, there's no way this will work either.
+        if (rb->free_ptr > rb->write_ptr) {
+            //No luck.
+            return pdFALSE;
+        }
+
+        //Okay, it will fit. Mark the rest of the ringbuffer space with a dummy packet.
+        buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+        hdr->flags=iflag_dummydata;
+        //Reset the write pointer to the start of the ringbuffer so the code later on can
+        //happily write the data.
+        rb->write_ptr=rb->data;
+    } else {
+        //No special handling needed. Checking if it's gonna fit probably still is a good idea.
+        if (ringbufferFreeMem(rb) < sizeof(buf_entry_hdr_t)+rbuffer_size) {
+            //Buffer is not going to fit, period.
+            return pdFALSE;
+        }
+    }
+
+    //If we are here, the buffer is guaranteed to fit in the space starting at the write pointer.
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+    hdr->len=buffer_size;
+    hdr->flags=0;
+    rb->write_ptr+=sizeof(buf_entry_hdr_t);
+    memcpy(rb->write_ptr, buffer, buffer_size);
+    rb->write_ptr+=rbuffer_size;
+
+    //The buffer will wrap around if we don't have room for a header anymore.
+    if ((rb->data+rb->size)-rb->write_ptr < sizeof(buf_entry_hdr_t)) {
+        //'Forward' the write buffer until we are at the start of the ringbuffer.
+        //The read pointer will always be at the start of a full header, which cannot 
+        //exist at the point of the current write pointer, so there's no chance of overtaking
+        //that.
+        rb->write_ptr=rb->data;
+    }
+    return pdTRUE;
+}
+
+//Copies a single item to the ring buffer; allows split items. Assumes there is space in the ringbuffer and
 //the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
 //success, pdFALSE if it can't make the item fit and the calling routine needs to retry
 //later or fail.
 //This function by itself is not threadsafe, always call from within a muxed section.
-static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) 
+static BaseType_t copyItemToRingbufAllowSplit(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) 
 {
-    size_t rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value
+    size_t rbuffer_size;
+    rbuffer_size=(buffer_size+3)&~3; //Payload length, rounded to next 32-bit value
     configASSERT(((int)rb->write_ptr&3)==0); //write_ptr needs to be 32-bit aligned
     configASSERT(rb->write_ptr-(rb->data+rb->size) >= sizeof(buf_entry_hdr_t)); //need to have at least the size 
                                             //of a header to the end of the ringbuff
@@ -92,61 +168,36 @@ static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffe
         //that depending on how the ringbuffer is configured.
         //The code here is also expected to check if the buffer, mangled in whatever way is implemented,
         //will still fit, and return pdFALSE if that is not the case.
-        if (rb->flags & flag_allowsplit) {
-            //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
-            //ringbuffer... we need to split the write in two.
-            //First, see if this will fit at all.
-            if (ringbufferFreeMem(rb) < (sizeof(buf_entry_hdr_t)*2)+rbuffer_size) {
-                //Will not fit.
-                return pdFALSE;
-            }
-            //Because the code at the end of the function makes sure we always have 
-            //room for a header, this should never assert.
-            configASSERT(rem_len>=sizeof(buf_entry_hdr_t));
-            //Okay, it should fit. Write everything.
-            //First, place bit of buffer that does fit. Write header first...
-            buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
-            hdr->flags=0;
-            hdr->len=rem_len-sizeof(buf_entry_hdr_t);
-            rb->write_ptr+=sizeof(buf_entry_hdr_t);
-            rem_len-=sizeof(buf_entry_hdr_t);
-            if (rem_len!=0) {
-                //..then write the data bit that fits.
-                memcpy(rb->write_ptr, buffer, rem_len);
-                //Update vars so the code later on will write the rest of the data.
-                buffer+=rem_len;
-                rbuffer_size-=rem_len;
-                buffer_size-=rem_len;
-            } else {
-                //Huh, only the header fit. Mark as dummy so the receive function doesn't receive
-                //an useless zero-byte packet.
-                hdr->flags|=iflag_dummydata;
-            }
-            rb->write_ptr=rb->data;
+        //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
+        //ringbuffer... we need to split the write in two.
+        //First, see if this will fit at all.
+        if (ringbufferFreeMem(rb) < (sizeof(buf_entry_hdr_t)*2)+rbuffer_size) {
+            //Will not fit.
+            return pdFALSE;
+        }
+         //Because the code at the end of the function makes sure we always have 
+        //room for a header, this should never assert.
+        configASSERT(rem_len>=sizeof(buf_entry_hdr_t));
+         //Okay, it should fit. Write everything.
+        //First, place bit of buffer that does fit. Write header first...
+        buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
+        hdr->flags=0;
+        hdr->len=rem_len-sizeof(buf_entry_hdr_t);
+        rb->write_ptr+=sizeof(buf_entry_hdr_t);
+        rem_len-=sizeof(buf_entry_hdr_t);
+        if (rem_len!=0) {
+            //..then write the data bit that fits.
+            memcpy(rb->write_ptr, buffer, rem_len);
+            //Update vars so the code later on will write the rest of the data.
+            buffer+=rem_len;
+            rbuffer_size-=rem_len;
+            buffer_size-=rem_len;
         } else {
-            //Buffer plus header is not going to fit in the room from wr_pos to the end of the 
-            //ringbuffer... but we're not allowed to split the buffer. We need to fill the 
-            //rest of the ringbuffer with a dummy item so we can place the data at the _start_ of
-            //the ringbuffer..
-            //First, find out if we actually have enough space at the start of the ringbuffer to
-            //make this work (Again, we need 4 bytes extra because otherwise read_ptr==free_ptr)
-            if (rb->free_ptr-rb->data < rbuffer_size+sizeof(buf_entry_hdr_t)+4) {
-                //Will not fit.
-                return pdFALSE;
-            }
-            //If the read buffer hasn't wrapped around yet, there's no way this will work either.
-            if (rb->free_ptr > rb->write_ptr) {
-                //No luck.
-                return pdFALSE;
-            }
-
-            //Okay, it will fit. Mark the rest of the ringbuffer space with a dummy packet.
-            buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->write_ptr;
-            hdr->flags=iflag_dummydata;
-            //Reset the write pointer to the start of the ringbuffer so the code later on can
-            //happily write the data.
-            rb->write_ptr=rb->data;
+            //Huh, only the header fit. Mark as dummy so the receive function doesn't receive
+            //an useless zero-byte packet.
+            hdr->flags|=iflag_dummydata;
         }
+        rb->write_ptr=rb->data;
     } else {
         //No special handling needed. Checking if it's gonna fit probably still is a good idea.
         if (ringbufferFreeMem(rb) < sizeof(buf_entry_hdr_t)+rbuffer_size) {
@@ -174,9 +225,40 @@ static BaseType_t copyItemToRingbuf(ringbuf_t *rb, uint8_t *buffer, size_t buffe
     return pdTRUE;
 }
 
+
+//Copies a bunch of daya to the ring bytebuffer. Assumes there is space in the ringbuffer and
+//the ringbuffer is locked. Increases write_ptr to the next item. Returns pdTRUE on
+//success, pdFALSE if it can't make the item fit and the calling routine needs to retry
+//later or fail.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static BaseType_t copyItemToRingbufByteBuf(ringbuf_t *rb, uint8_t *buffer, size_t buffer_size) 
+{
+    size_t rem_len=(rb->data + rb->size) - rb->write_ptr; //length remaining until end of ringbuffer
+    
+    //See if we have enough contiguous space to write the buffer.
+    if (rem_len < buffer_size) {
+        //...Nope. Write the data bit that fits.
+        memcpy(rb->write_ptr, buffer, rem_len);
+        //Update vars so the code later on will write the rest of the data.
+        buffer+=rem_len;
+        buffer_size-=rem_len;
+        rb->write_ptr=rb->data;
+    }
+
+    //If we are here, the buffer is guaranteed to fit in the space starting at the write pointer.
+    memcpy(rb->write_ptr, buffer, buffer_size);
+    rb->write_ptr+=buffer_size;
+    //The buffer will wrap around if we're at the end.
+    if ((rb->data+rb->size)==rb->write_ptr) {
+        rb->write_ptr=rb->data;
+    }
+    return pdTRUE;
+}
+
 //Retrieves a pointer to the data of the next item, or NULL if this is not possible.
 //This function by itself is not threadsafe, always call from within a muxed section.
-static uint8_t *getItemFromRingbuf(ringbuf_t *rb, size_t *length)
+//Because we always return one item, this function ignores the wanted_length variable.
+static uint8_t *getItemFromRingbufDefault(ringbuf_t *rb, size_t *length, int wanted_length)
 {
     uint8_t *ret;
     configASSERT(((int)rb->read_ptr&3)==0);
@@ -210,10 +292,48 @@ static uint8_t *getItemFromRingbuf(ringbuf_t *rb, size_t *length)
     return ret;
 }
 
+//Retrieves a pointer to the data in the buffer, or NULL if this is not possible.
+//This function by itself is not threadsafe, always call from within a muxed section.
+//This function honours the wanted_length and will never return more data than this.
+static uint8_t *getItemFromRingbufByteBuf(ringbuf_t *rb, size_t *length, int wanted_length)
+{
+    uint8_t *ret;
+    if (rb->read_ptr != rb->free_ptr) {
+        //This type of ringbuff does not support multiple outstanding buffers.
+        return NULL;
+    }
+    if (rb->read_ptr == rb->write_ptr) {
+        //No data available.
+        return NULL;
+    }
+    ret=rb->read_ptr;
+    if (rb->read_ptr > rb->write_ptr) {
+        //Available data wraps around. Give data until the end of the buffer.
+        *length=rb->size-(rb->read_ptr - rb->data);
+        if (wanted_length != 0 && *length > wanted_length) {
+            *length=wanted_length;
+            rb->read_ptr+=wanted_length;
+        } else {
+            rb->read_ptr=rb->data;
+        }
+    } else {
+        //Return data up to write pointer.
+        *length=rb->write_ptr -rb->read_ptr;
+        if (wanted_length != 0 && *length > wanted_length) {
+            *length=wanted_length;
+            rb->read_ptr+=wanted_length;
+        } else {
+            rb->read_ptr=rb->write_ptr;
+        }
+    }
+    return ret;
+}
+
+
 //Returns an item to the ringbuffer. Will mark the item as free, and will see if the free pointer
 //can be increase.
 //This function by itself is not threadsafe, always call from within a muxed section.
-static void returnItemToRingbuf(ringbuf_t *rb, void *item) {
+static void returnItemToRingbufDefault(ringbuf_t *rb, void *item) {
     uint8_t *data=(uint8_t*)item;
     configASSERT(((int)rb->free_ptr&3)==0);
     configASSERT(data >= rb->data);
@@ -243,12 +363,26 @@ static void returnItemToRingbuf(ringbuf_t *rb, void *item) {
         if ((rb->data+rb->size)-rb->free_ptr < sizeof(buf_entry_hdr_t)) {
             rb->free_ptr=rb->data;
         }
+        //The free_ptr can not exceed read_ptr, otherwise write_ptr might overwrite read_ptr.
+        //Read_ptr can not set to rb->data with free_ptr, otherwise write_ptr might wrap around to rb->data.
+        if(rb->free_ptr == rb->read_ptr) break;
         //Next header
         hdr=(buf_entry_hdr_t *)rb->free_ptr;
     }
 }
 
 
+//Returns an item to the ringbuffer. Will mark the item as free, and will see if the free pointer
+//can be increase.
+//This function by itself is not threadsafe, always call from within a muxed section.
+static void returnItemToRingbufBytebuf(ringbuf_t *rb, void *item) {
+    uint8_t *data=(uint8_t*)item;
+    configASSERT(data >= rb->data);
+    configASSERT(data < rb->data+rb->size);
+    //Free the read memory.
+    rb->free_ptr=rb->read_ptr;
+}
+
 void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
 {
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
@@ -259,7 +393,7 @@ void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
 
 
 
-RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items)
+RingbufHandle_t xRingbufferCreate(size_t buf_length, ringbuf_type_t type)
 {
     ringbuf_t *rb = malloc(sizeof(ringbuf_t));
     if (rb==NULL) goto err;
@@ -273,9 +407,35 @@ RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_item
     rb->free_space_sem = xSemaphoreCreateBinary();
     rb->items_buffered_sem = xSemaphoreCreateBinary();
     rb->flags=0;
-    if (allow_split_items) rb->flags|=flag_allowsplit;
+    if (type==RINGBUF_TYPE_ALLOWSPLIT) {
+        rb->flags|=flag_allowsplit;
+        rb->copyItemToRingbufImpl=copyItemToRingbufAllowSplit;
+        rb->getItemFromRingbufImpl=getItemFromRingbufDefault;
+        rb->returnItemToRingbufImpl=returnItemToRingbufDefault;
+        //Calculate max item size. Worst case, we need to split an item into two, which means two headers of overhead.
+        rb->maxItemSize=rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
+    } else if (type==RINGBUF_TYPE_BYTEBUF) {
+        rb->flags|=flag_bytebuf;
+        rb->copyItemToRingbufImpl=copyItemToRingbufByteBuf;
+        rb->getItemFromRingbufImpl=getItemFromRingbufByteBuf;
+        rb->returnItemToRingbufImpl=returnItemToRingbufBytebuf;
+        //Calculate max item size. We have no headers and can split anywhere -> size is total size minus one.
+        rb->maxItemSize=rb->size-1;
+    } else if (type==RINGBUF_TYPE_NOSPLIT) {
+        rb->copyItemToRingbufImpl=copyItemToRingbufNoSplit;
+        rb->getItemFromRingbufImpl=getItemFromRingbufDefault;
+        rb->returnItemToRingbufImpl=returnItemToRingbufDefault;
+        //Calculate max item size. Worst case, we have the write ptr in such a position that we are lacking four bytes of free
+        //memory to put an item into the rest of the memory. If this happens, we have to dummy-fill
+        //(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
+        //with the real item. (item size being header+data)
+        rb->maxItemSize=(rb->size/2)-sizeof(buf_entry_hdr_t)-4;
+    } else {
+        configASSERT(0);
+    }
     if (rb->free_space_sem == NULL || rb->items_buffered_sem == NULL) goto err;
     vPortCPUInitializeMutex(&rb->mux);
+
     return (RingbufHandle_t)rb;
 
 err:
@@ -303,18 +463,7 @@ size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf)
 {
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
     configASSERT(rb);
-    //In both cases, we return 4 bytes less than what we actually can have. If the ringbuffer is
-    //indeed entirely filled, read_ptr==free_ptr, which throws off the free space calculation.
-    if (rb->flags & flag_allowsplit) {
-        //Worst case, we need to split an item into two, which means two headers of overhead.
-        return rb->size-(sizeof(buf_entry_hdr_t)*2)-4;
-    } else {
-        //Worst case, we have the write ptr in such a position that we are lacking four bytes of free
-        //memory to put an item into the rest of the memory. If this happens, we have to dummy-fill
-        //(item_data-4) bytes of buffer, then we only have (size-(item_data-4) bytes left to fill
-        //with the real item. (item size being header+data)
-        return (rb->size/2)-sizeof(buf_entry_hdr_t)-4;
-    }
+    return rb->maxItemSize;
 }
 
 BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
@@ -322,7 +471,8 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize,
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
     size_t needed_size=dataSize+sizeof(buf_entry_hdr_t);
     BaseType_t done=pdFALSE;
-    portTickType ticks_end=xTaskGetTickCount() + ticks_to_wait;
+    TickType_t ticks_end = xTaskGetTickCount() + ticks_to_wait;
+    TickType_t ticks_remaining = ticks_to_wait;
 
     configASSERT(rb);
 
@@ -337,22 +487,31 @@ BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize,
             if (ringbufferFreeMem(rb) < needed_size) {
                 //Data does not fit yet. Wait until the free_space_sem is given, then re-evaluate.
 
-                BaseType_t r = xSemaphoreTake(rb->free_space_sem, ticks_to_wait);
+                BaseType_t r = xSemaphoreTake(rb->free_space_sem, ticks_remaining);
                 if (r == pdFALSE) {
                     //Timeout.
                     return pdFALSE;
                 }
-                //Adjust ticks_to_wait; we may have waited less than that and in the case the free memory still is not enough,
+                //Adjust ticks_remaining; we may have waited less than that and in the case the free memory still is not enough,
                 //we will need to wait some more.
-                ticks_to_wait = ticks_end - xTaskGetTickCount();
+                if (ticks_to_wait != portMAX_DELAY) {
+                    ticks_remaining = ticks_end - xTaskGetTickCount();
+                }
+
+                // ticks_remaining will always be less than or equal to the original ticks_to_wait,
+                // unless the timeout is reached - in which case it unsigned underflows to a much
+                // higher value.
+                //
+                // (Check is written this non-intuitive way to allow for the case where xTaskGetTickCount()
+                // has overflowed but the ticks_end value has not overflowed.)
             }
-        } while (ringbufferFreeMem(rb) < needed_size && ticks_to_wait>=0);
-        
+        } while (ringbufferFreeMem(rb) < needed_size && ticks_remaining > 0 && ticks_remaining <= ticks_to_wait);
+
         //Lock the mux in order to make sure no one else is messing with the ringbuffer and do the copy.
         portENTER_CRITICAL(&rb->mux);
         //Another thread may have been able to sneak its write first. Check again now we locked the ringbuff, and retry
         //everything if this is the case. Otherwise, we can write and are done.
-        done=copyItemToRingbuf(rb, data, dataSize);
+        done=rb->copyItemToRingbufImpl(rb, data, dataSize);
         portEXIT_CRITICAL(&rb->mux);
     }
     xSemaphoreGive(rb->items_buffered_sem);
@@ -371,8 +530,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da
         //Does not fit in the remaining space in the ringbuffer.
         write_succeeded=pdFALSE;
     } else {
-        copyItemToRingbuf(rb, data, dataSize);
-        write_succeeded=pdTRUE;
+        write_succeeded = rb->copyItemToRingbufImpl(rb, data, dataSize);
     }
     portEXIT_CRITICAL_ISR(&rb->mux);
     if (write_succeeded) {
@@ -382,7 +540,7 @@ BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t da
 }
 
 
-void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait) 
+static void *xRingbufferReceiveGeneric(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size) 
 {
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
     uint8_t *itemData;
@@ -399,7 +557,7 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
         }
         //Okay, we seem to have data in the buffer. Grab the mux and copy it out if it's still there.
         portENTER_CRITICAL(&rb->mux);
-        itemData=getItemFromRingbuf(rb, item_size);
+        itemData=rb->getItemFromRingbufImpl(rb, item_size, wanted_size);
         portEXIT_CRITICAL(&rb->mux);
         if (itemData) {
             //We managed to get an item.
@@ -409,6 +567,11 @@ void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t
     return (void*)itemData;
 }
 
+void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait)
+{
+    return xRingbufferReceiveGeneric(ringbuf, item_size, ticks_to_wait, 0);
+}
+
 
 void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size) 
 {
@@ -416,7 +579,28 @@ void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size)
     uint8_t *itemData;
     configASSERT(rb);
     portENTER_CRITICAL_ISR(&rb->mux);
-    itemData=getItemFromRingbuf(rb, item_size);
+    itemData=rb->getItemFromRingbufImpl(rb, item_size, 0);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    return (void*)itemData;
+}
+
+void *xRingbufferReceiveUpTo(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait, size_t wanted_size) {
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    if (wanted_size == 0) return NULL;
+    configASSERT(rb);
+    configASSERT(rb->flags & flag_bytebuf);
+    return xRingbufferReceiveGeneric(ringbuf, item_size, ticks_to_wait, wanted_size);
+}
+
+void *xRingbufferReceiveUpToFromISR(RingbufHandle_t ringbuf, size_t *item_size, size_t wanted_size)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    uint8_t *itemData;
+    if (wanted_size == 0) return NULL;
+    configASSERT(rb);
+    configASSERT(rb->flags & flag_bytebuf);
+    portENTER_CRITICAL_ISR(&rb->mux);
+    itemData=rb->getItemFromRingbufImpl(rb, item_size, 0);
     portEXIT_CRITICAL_ISR(&rb->mux);
     return (void*)itemData;
 }
@@ -426,7 +610,7 @@ void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item)
 {
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
     portENTER_CRITICAL_ISR(&rb->mux);
-    returnItemToRingbuf(rb, item);
+    rb->returnItemToRingbufImpl(rb, item);
     portEXIT_CRITICAL_ISR(&rb->mux);
     xSemaphoreGive(rb->free_space_sem);
 }
@@ -436,7 +620,7 @@ void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_
 {
     ringbuf_t *rb=(ringbuf_t *)ringbuf;
     portENTER_CRITICAL_ISR(&rb->mux);
-    returnItemToRingbuf(rb, item);
+    rb->returnItemToRingbufImpl(rb, item);
     portEXIT_CRITICAL_ISR(&rb->mux);
     xSemaphoreGiveFromISR(rb->free_space_sem, higher_prio_task_awoken);
 }

+ 15 - 9
components/freertos/tasks.c

@@ -476,6 +476,7 @@ to its original value when it is released. */
 #if configUSE_TICK_HOOK > 0
 	extern void vApplicationTickHook( void );
 #endif
+extern void esp_vApplicationTickHook( void );
 
 #if  portFIRST_TASK_HOOK
 	extern void vPortFirstTaskHook(TaskFunction_t taskfn);
@@ -2360,22 +2361,21 @@ BaseType_t xSwitchRequired = pdFALSE;
 		  We can't really calculate what we need, that's done on core 0... just assume we need a switch.
 		  ToDo: Make this more intelligent? -- JD
 		*/
-		//We do need the tick hook to satisfy the int watchdog.
-		#if ( configUSE_TICK_HOOK == 1 )
 		{
 			/* Guard against the tick hook being called when the pended tick
 			count is being unwound (when the scheduler is being unlocked). */
 			if( ( uxSchedulerSuspended[ xPortGetCoreID() ] != ( UBaseType_t ) pdFALSE ) || uxPendedTicks == ( UBaseType_t ) 0U )
 			{
+				#if ( configUSE_TICK_HOOK == 1 )
 				vApplicationTickHook();
+				#endif /* configUSE_TICK_HOOK */
+				esp_vApplicationTickHook();
 			}
 			else
 			{
 				mtCOVERAGE_TEST_MARKER();
 			}
 		}
-		#endif /* configUSE_TICK_HOOK */
-
 
 		return pdTRUE;
 	}
@@ -2506,20 +2506,21 @@ BaseType_t xSwitchRequired = pdFALSE;
 		}
 		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
 
-		#if ( configUSE_TICK_HOOK == 1 )
 		{
 			/* Guard against the tick hook being called when the pended tick
 			count is being unwound (when the scheduler is being unlocked). */
 			if( uxPendedTicks == ( UBaseType_t ) 0U )
 			{
+				#if ( configUSE_TICK_HOOK == 1 )
 				vApplicationTickHook();
+				#endif /* configUSE_TICK_HOOK */
+				esp_vApplicationTickHook();
 			}
 			else
 			{
 				mtCOVERAGE_TEST_MARKER();
 			}
 		}
-		#endif /* configUSE_TICK_HOOK */
 		taskEXIT_CRITICAL_ISR(&xTaskQueueMutex);
 	}
 	else
@@ -2533,6 +2534,7 @@ BaseType_t xSwitchRequired = pdFALSE;
 			vApplicationTickHook();
 		}
 		#endif
+		esp_vApplicationTickHook();
 	}
 
 	#if ( configUSE_PREEMPTION == 1 )
@@ -2702,7 +2704,7 @@ void vTaskSwitchContext( void )
 		taskENTER_CRITICAL_ISR(&xTaskQueueMutex);
 		
 		unsigned portBASE_TYPE foundNonExecutingWaiter = pdFALSE, ableToSchedule = pdFALSE, resetListHead;
-		unsigned portBASE_TYPE uxDynamicTopReady = uxTopReadyPriority;
+		portBASE_TYPE uxDynamicTopReady = uxTopReadyPriority;
 		unsigned portBASE_TYPE holdTop=pdFALSE;
 		
 		/*
@@ -2715,8 +2717,6 @@ void vTaskSwitchContext( void )
 		
 		while ( ableToSchedule == pdFALSE && uxDynamicTopReady >= 0 )
 		{
-			configASSERT( uxTopReadyPriority>=0 );
-			configASSERT( uxDynamicTopReady>=0 );
 			resetListHead = pdFALSE;
 			// Nothing to do for empty lists
 			if (!listLIST_IS_EMPTY( &( pxReadyTasksLists[ uxDynamicTopReady ] ) )) {
@@ -3270,6 +3270,12 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
 			vApplicationIdleHook();
 		}
 		#endif /* configUSE_IDLE_HOOK */
+		{
+			/* Call the esp-idf hook system */
+			extern void esp_vApplicationIdleHook( void );
+			esp_vApplicationIdleHook();
+		}
+
 
 		/* This conditional compilation should use inequality to 0, not equality
 		to 1.  This is to ensure portSUPPRESS_TICKS_AND_SLEEP() is called when

+ 9 - 2
components/freertos/xtensa_intr.c

@@ -30,7 +30,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #include <xtensa/config/core.h>
 
+#include "freertos/FreeRTOS.h"
 #include "freertos/xtensa_api.h"
+#include "freertos/portable.h"
 
 #include "rom/ets_sys.h"
 
@@ -39,7 +41,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 /* Handler table is in xtensa_intr_asm.S */
 // Todo: Make multicore - JD
 
-extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM];
+extern xt_exc_handler _xt_exception_table[XCHAL_EXCCAUSE_NUM*portNUM_PROCESSORS];
 
 
 /*
@@ -66,6 +68,8 @@ xt_exc_handler xt_set_exception_handler(int n, xt_exc_handler f)
     if( n < 0 || n >= XCHAL_EXCCAUSE_NUM )
         return 0;       /* invalid exception number */
 
+    /* Convert exception number to _xt_exception_table name */
+    n = n * portNUM_PROCESSORS + xPortGetCoreID();
     old = _xt_exception_table[n];
 
     if (f) {
@@ -89,7 +93,7 @@ typedef struct xt_handler_table_entry {
     void * arg;
 } xt_handler_table_entry;
 
-extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS];
+extern xt_handler_table_entry _xt_interrupt_table[XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS];
 
 
 /*
@@ -118,6 +122,9 @@ xt_handler xt_set_interrupt_handler(int n, xt_handler f, void * arg)
     if( Xthal_intlevel[n] > XCHAL_EXCM_LEVEL )
         return 0;       /* priority level too high to safely handle in C */
 
+    /* Convert exception number to _xt_exception_table name */
+    n = n * portNUM_PROCESSORS + xPortGetCoreID();
+
     entry = _xt_interrupt_table + n;
     old   = entry->handler;
 

+ 21 - 2
components/freertos/xtensa_intr_asm.S

@@ -30,6 +30,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include <xtensa/config/core.h>
 
 #include "xtensa_context.h"
+#include "FreeRTOSConfig.h"
 
 #if XCHAL_HAVE_INTERRUPTS
 
@@ -59,6 +60,15 @@ _xt_vpri_mask:     .word   0xFFFFFFFF    /* Virtual priority mask */
   Table of C-callable interrupt handlers for each interrupt. Note that not all
   slots can be filled, because interrupts at level > EXCM_LEVEL will not be
   dispatched to a C handler by default.
+
+  Stored as:
+  int 0 cpu 0
+  int 0 cpu 1
+  ...
+  int 0 cpu n
+  int 1 cpu 0
+  int 1 cpu 1
+  etc
 -------------------------------------------------------------------------------
 */
 
@@ -69,7 +79,7 @@ _xt_vpri_mask:     .word   0xFFFFFFFF    /* Virtual priority mask */
 _xt_interrupt_table:
 
     .set    i, 0
-    .rept   XCHAL_NUM_INTERRUPTS
+    .rept   XCHAL_NUM_INTERRUPTS*portNUM_PROCESSORS
     .word   xt_unhandled_interrupt      /* handler address               */
     .word   i                           /* handler arg (default: intnum) */
     .set    i, i+1
@@ -85,6 +95,15 @@ _xt_interrupt_table:
   Table of C-callable exception handlers for each exception. Note that not all
   slots will be active, because some exceptions (e.g. coprocessor exceptions)
   are always handled by the OS and cannot be hooked by user handlers.
+
+  Stored as:
+  exc 0 cpu 0
+  exc 0 cpu 1
+  ...
+  exc 0 cpu n
+  exc 1 cpu 0
+  exc 1 cpu 1
+  etc
 -------------------------------------------------------------------------------
 */
 
@@ -93,7 +112,7 @@ _xt_interrupt_table:
     .align  4
 
 _xt_exception_table:
-    .rept   XCHAL_EXCCAUSE_NUM
+    .rept   XCHAL_EXCCAUSE_NUM * portNUM_PROCESSORS
     .word   xt_unhandled_exception    /* handler address */
     .endr
 

+ 26 - 0
components/freertos/xtensa_vectors.S

@@ -113,6 +113,27 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 #define XIE_ARG         4
 #define XIE_SIZE        8
 
+
+/*
+  Macro get_percpu_entry_for - convert a per-core ID into a multicore entry.
+  Basically does reg=reg*portNUM_PROCESSORS+current_core_id
+  Multiple versions here to optimize for specific portNUM_PROCESSORS values.
+*/
+    .macro get_percpu_entry_for reg scratch
+#if (portNUM_PROCESSORS == 1)
+    /* No need to do anything */
+#elif  (portNUM_PROCESSORS == 2)
+    /* Optimized 2-core code. */
+    getcoreid \scratch
+    addx2 \reg,\reg,\scratch
+#else
+    /* Generalized n-core code. Untested! */
+    movi \scratch,portNUM_PROCESSORS
+    mull \scratch,\reg,\scratch
+    getcoreid \reg
+    add \reg,\scratch,\reg
+#endif
+   .endm
 /*
 --------------------------------------------------------------------------------
   Macro extract_msb - return the input with only the highest bit set.
@@ -229,6 +250,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
     find_ms_setbit a3, a4, a3, 0            /* a3 = interrupt number */
 
+    get_percpu_entry_for a3, a12
     movi    a4, _xt_interrupt_table
     addx8   a3, a3, a4                      /* a3 = address of interrupt table entry */
     l32i    a4, a3, XIE_HANDLER             /* a4 = handler address */
@@ -395,6 +417,9 @@ panic_print_hex_ok:
     with index 0 containing the entry for user exceptions.
     Initialized with all 0s, meaning no handler is installed at each level.
     See comment in xtensa_rtos.h for more details.
+
+    *WARNING*  This array is for all CPUs, that is, installing a hook for 
+    one CPU will install it for all others as well!
 --------------------------------------------------------------------------------
 */
 
@@ -688,6 +713,7 @@ _xt_user_exc:
 
     rsr     a2, EXCCAUSE                    /* recover exc cause */
     movi    a3, _xt_exception_table
+    get_percpu_entry_for a3, a4
     addx4   a4, a2, a3                      /* a4 = address of exception table entry */
     l32i    a4, a4, 0                       /* a4 = handler address */
     #ifdef __XTENSA_CALL0_ABI__

+ 0 - 6
components/json/component.mk

@@ -1,13 +1,7 @@
 #
 # Component Makefile
 #
-# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default, 
-# this will take the sources in this directory, compile them and link them into 
-# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
-# please read the SDK documents if you need to do this.
-#
 COMPONENT_ADD_INCLUDEDIRS := include port/include
 
 COMPONENT_SRCDIRS := library port
 
-include $(IDF_PATH)/make/component_common.mk

+ 4 - 2
components/log/component.mk

@@ -1,3 +1,5 @@
-COMPONENT_ADD_INCLUDEDIRS := include
+#
+# Component Makefile
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
 
-include $(IDF_PATH)/make/component_common.mk

+ 4 - 0
components/log/include/esp_log.h

@@ -19,6 +19,10 @@
 #include <stdarg.h>
 #include "sdkconfig.h"
 
+#ifdef BOOTLOADER_BUILD
+#include <rom/ets_sys.h>
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif

+ 16 - 0
components/lwip/Kconfig

@@ -1,5 +1,21 @@
 menu "LWIP"
 
+config L2_TO_L3_COPY
+    bool "Enable copy between Layer2 and Layer3 packets"
+    default 0
+    help
+        If this feature is enabled, all traffic from layer2(WIFI Driver) will be
+        copied to a new buffer before sending it to layer3(LWIP stack), freeing
+        the layer2 buffer.
+        Please be notified that the total layer2 receiving buffer is fixed and 
+        ESP32 currently supports 25 layer2 receiving buffer, when layer2 buffer 
+        runs out of memory, then the incoming packets will be dropped in hardware. 
+        The layer3 buffer is allocated from the heap, so the total layer3 receiving
+        buffer depends on the available heap size, when heap runs out of memory,  
+        no copy will be sent to layer3 and packet will be dropped in layer2. 
+        Please make sure you fully understand the impact of this feature before 
+        enabling it.
+
 config LWIP_MAX_SOCKETS
     int "Max number of open sockets"
     range 1 16

+ 0 - 1
components/lwip/component.mk

@@ -8,4 +8,3 @@ COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/free
 
 CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
 
-include $(IDF_PATH)/make/component_common.mk

+ 7 - 0
components/lwip/include/lwip/lwip/opt.h

@@ -3008,6 +3008,13 @@
 #define LWIP_PERF                       0
 #endif
 
+/**
+ * ESP_L2_TO_L3_COPY: enable memcpy when receiving packet from L2
+ */
+#ifndef ESP_L2_TO_L3_COPY
+#define ESP_L2_TO_L3_COPY                   0
+#endif
+
 #ifndef ESP_THREAD_SAFE_DEBUG
 #define ESP_THREAD_SAFE_DEBUG               0
 #endif

+ 1 - 0
components/lwip/include/lwip/port/lwipopts.h

@@ -525,6 +525,7 @@ extern unsigned long os_random(void);
 #define ESP_RANDOM_TCP_PORT             1
 #define ESP_IP4_ATON                    1
 #define ESP_LIGHT_SLEEP                 1
+#define ESP_L2_TO_L3_COPY               CONFIG_L2_TO_L3_COPY
 
 #define TCP_WND_DEFAULT                      (4*TCP_MSS)
 #define TCP_SND_BUF_DEFAULT                  (2*TCP_MSS)

+ 18 - 21
components/lwip/port/netif/wlanif.c

@@ -161,40 +161,37 @@ low_level_output(struct netif *netif, struct pbuf *p)
  * @param netif the lwip network interface structure for this ethernetif
  */
 void
-#if ESP_LWIP
 wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb)
-#else
-wlanif_input(struct netif *netif, void *buffer, uint16 len)
-#endif
 {
   struct pbuf *p;
   
-#if ESP_LWIP
-    if(buffer== NULL)
-    	goto _exit;
-    if(netif == NULL)
+  if(!buffer || !netif)
     	goto _exit;
-#endif
 
-#if ESP_LWIP
+#if (ESP_L2_TO_L3_COPY == 1)
+  //p = pbuf_alloc(PBUF_IP, len, PBUF_POOL);
+  p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
+  if (p == NULL) {
+    #if ESP_PERF
+    g_rx_alloc_pbuf_fail_cnt++;
+    #endif
+    esp_wifi_internal_free_rx_buffer(eb);
+    return;
+  }
+  memcpy(p->payload, buffer, len);
+  esp_wifi_internal_free_rx_buffer(eb);
+#else
   p = pbuf_alloc(PBUF_RAW, len, PBUF_REF);
   if (p == NULL){
-#if ESP_PERF
-      g_rx_alloc_pbuf_fail_cnt++;
-#endif
-      return;
+    #if ESP_PERF
+    g_rx_alloc_pbuf_fail_cnt++;
+    #endif
+    return;
   }
   p->payload = buffer;
   p->eb = eb;
-#else
-  p = pbuf_alloc(PBUF_IP, len, PBUF_POOL);
-  if (p == NULL) {
-    return;
-  }
-  memcpy(p->payload, buffer, len);
 #endif
 
-
   /* full packet send to tcpip_thread to process */
   if (netif->input(p, netif) != ERR_OK) {
     LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));

+ 36 - 1
components/mbedtls/Kconfig

@@ -22,7 +22,7 @@ config MBEDTLS_SSL_MAX_CONTENT_LEN
 
 config MBEDTLS_DEBUG
    bool "Enable mbedTLS debugging"
-   default "no"
+   default n
    help
        Enable mbedTLS debugging functions.
        
@@ -34,4 +34,39 @@ config MBEDTLS_DEBUG
        functionality. See the "https_request_main" example for a
        sample function which connects the two together.
 
+config MBEDTLS_HARDWARE_AES
+   bool "Enable hardware AES acceleration"
+   default y
+   help
+       Enable hardware accelerated AES encryption & decryption.
+
+config MBEDTLS_HARDWARE_MPI
+   bool "Enable hardware MPI (bignum) acceleration"
+   default y
+   help
+       Enable hardware accelerated multiple precision integer operations.
+
+       Hardware accelerated multiplication, modulo multiplication,
+       and modular exponentiation for up to 4096 bit results.
+
+       These operations are used by RSA.
+
+config MBEDTLS_MPI_USE_INTERRUPT
+    bool "Use interrupt for MPI operations"
+    depends on MBEDTLS_HARDWARE_MPI
+    default y
+    help
+        Use an interrupt to coordinate MPI operations.
+
+        This allows other code to run on the CPU while an MPI operation is pending.
+        Otherwise the CPU busy-waits.
+
+config MBEDTLS_MPI_INTERRUPT_NUM
+    int "MPI Interrupt number"
+    depends on MBEDTLS_MPI_USE_INTERRUPT
+    default 18
+    help
+        CPU interrupt number for MPI interrupt to connect to. Must be otherwise unused.
+        Eventually this assignment will be handled automatically at runtime.
+
 endmenu

+ 0 - 1
components/mbedtls/component.mk

@@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include
 
 COMPONENT_SRCDIRS := library port
 
-include $(IDF_PATH)/make/component_common.mk

+ 7 - 1
components/mbedtls/library/bignum.c

@@ -1092,6 +1092,8 @@ int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint
     return( mbedtls_mpi_sub_mpi( X, A, &_B ) );
 }
 
+#if !defined(MBEDTLS_MPI_MUL_MPI_ALT) || !defined(MBEDTLS_MPI_EXP_MOD_ALT)
+
 /*
  * Helper for mbedtls_mpi multiplication
  */
@@ -1103,6 +1105,7 @@ static
  */
 __attribute__ ((noinline))
 #endif
+
 void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
 {
     mbedtls_mpi_uint c = 0, t = 0;
@@ -1164,6 +1167,8 @@ void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mp
     while( c != 0 );
 }
 
+#endif
+
 #if !defined(MBEDTLS_MPI_MUL_MPI_ALT)
 /*
  * Baseline multiplication: X = A * B  (HAC 14.12)
@@ -1526,6 +1531,8 @@ int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_
     return( 0 );
 }
 
+#if !defined(MBEDTLS_MPI_EXP_MOD_ALT)
+
 /*
  * Fast Montgomery initialization (thanks to Tom St Denis)
  */
@@ -1600,7 +1607,6 @@ static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint m
     return( mpi_montmul( A, &U, N, mm, T ) );
 }
 
-#if !defined(MBEDTLS_MPI_EXP_MOD_ALT)
 /*
  * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
  */

+ 410 - 396
components/mbedtls/port/esp_bignum.c

@@ -23,514 +23,528 @@
 #include <stdio.h>
 #include <string.h>
 #include <malloc.h>
+#include <limits.h>
+#include <assert.h>
 #include "mbedtls/bignum.h"
-#include "mbedtls/bn_mul.h"
 #include "rom/bigint.h"
+#include "soc/hwcrypto_reg.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_intr.h"
+#include "esp_attr.h"
 
-#if defined(MBEDTLS_MPI_MUL_MPI_ALT) || defined(MBEDTLS_MPI_EXP_MOD_ALT)
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
 
-/* Constants from mbedTLS bignum.c */
-#define ciL    (sizeof(mbedtls_mpi_uint))         /* chars in limb  */
-#define biL    (ciL << 3)               /* bits  in limb  */
+static const __attribute__((unused)) char *TAG = "bignum";
+
+#if defined(CONFIG_MBEDTLS_MPI_USE_INTERRUPT)
+static SemaphoreHandle_t op_complete_sem;
+
+static IRAM_ATTR void rsa_complete_isr(void *arg)
+{
+    BaseType_t higher_woken;
+    REG_WRITE(RSA_INTERRUPT_REG, 1);
+    xSemaphoreGiveFromISR(op_complete_sem, &higher_woken);
+    if (higher_woken) {
+        portYIELD_FROM_ISR();
+    }
+}
+
+static void rsa_isr_initialise()
+{
+    if (op_complete_sem == NULL) {
+        op_complete_sem = xSemaphoreCreateBinary();
+        intr_matrix_set(xPortGetCoreID(), ETS_RSA_INTR_SOURCE, CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
+        xt_set_interrupt_handler(CONFIG_MBEDTLS_MPI_INTERRUPT_NUM, &rsa_complete_isr, NULL);
+        xthal_set_intclear(1 << CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
+        xt_ints_on(1 << CONFIG_MBEDTLS_MPI_INTERRUPT_NUM);
+    }
+}
+
+#endif /* CONFIG_MBEDTLS_MPI_USE_INTERRUPT */
 
 static _lock_t mpi_lock;
 
-/* At the moment these hardware locking functions aren't exposed publically
-   for MPI. If you want to use the ROM bigint functions and co-exist with mbedTLS,
-   please raise a feature request.
-*/
-static void esp_mpi_acquire_hardware( void )
+void esp_mpi_acquire_hardware( void )
 {
     /* newlib locks lazy initialize on ESP-IDF */
     _lock_acquire(&mpi_lock);
     ets_bigint_enable();
+#ifdef CONFIG_MBEDTLS_MPI_USE_INTERRUPT
+    rsa_isr_initialise();
+#endif
 }
 
-static void esp_mpi_release_hardware( void )
+void esp_mpi_release_hardware( void )
 {
     ets_bigint_disable();
     _lock_release(&mpi_lock);
 }
 
-/*
- * Helper for mbedtls_mpi multiplication
- * copied/trimmed from mbedtls bignum.c
- */
-static void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b )
+/* Number of words used to hold 'mpi', rounded up to nearest
+   16 words (512 bits) to match hardware support.
+
+   Note that mpi->n (size of memory buffer) may be higher than this
+   number, if the high bits are mostly zeroes.
+
+   This implementation may cause the caller to leak a small amount of
+   timing information when an operation is performed (length of a
+   given mpi value, rounded to nearest 512 bits), but not all mbedTLS
+   RSA operations succeed if we use mpi->N as-is (buffers are too long).
+*/
+static inline size_t hardware_words_needed(const mbedtls_mpi *mpi)
 {
-    mbedtls_mpi_uint c = 0, t = 0;
-
-    for( ; i >= 16; i -= 16 )
-    {
-        MULADDC_INIT
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_STOP
+    size_t res = 1;
+    for(size_t i = 0; i < mpi->n; i++) {
+        if( mpi->p[i] != 0 ) {
+            res = i + 1;
+        }
     }
+    res = (res + 0xF) & ~0xF;
+    return res;
+}
 
-    for( ; i >= 8; i -= 8 )
-    {
-        MULADDC_INIT
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
+/* Convert number of bits to number of words, rounded up to nearest
+   512 bit (16 word) block count.
+*/
+static inline size_t bits_to_hardware_words(size_t num_bits)
+{
+    return ((num_bits + 511) / 512) * 16;
+}
 
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_CORE   MULADDC_CORE
-        MULADDC_STOP
-    }
+/* Copy mbedTLS MPI bignum 'mpi' to hardware memory block at 'mem_base'.
 
+   If num_words is higher than the number of words in the bignum then
+   these additional words will be zeroed in the memory buffer.
+*/
+static inline void mpi_to_mem_block(uint32_t mem_base, const mbedtls_mpi *mpi, size_t num_words)
+{
+    uint32_t *pbase = (uint32_t *)mem_base;
+    uint32_t copy_words = num_words < mpi->n ? num_words : mpi->n;
 
-    for( ; i > 0; i-- )
-    {
-        MULADDC_INIT
-        MULADDC_CORE
-        MULADDC_STOP
-    }
+    /* Copy MPI data to memory block registers */
+    memcpy(pbase, mpi->p, copy_words * 4);
 
-    t++;
+    /* Zero any remaining memory block data */
+    bzero(pbase + copy_words, (num_words - copy_words) * 4);
 
-    do {
-        *d += c; c = ( *d < c ); d++;
-    }
-    while( c != 0 );
+    /* Note: not executing memw here, can do it before we start a bignum operation */
 }
 
+/* Read mbedTLS MPI bignum back from hardware memory block.
 
-/*
- * Helper for mbedtls_mpi subtraction
- * Copied/adapter from mbedTLS bignum.c
- */
-static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d )
+   Reads num_words words from block.
+
+   Can return a failure result if fails to grow the MPI result.
+*/
+static inline int mem_block_to_mpi(mbedtls_mpi *x, uint32_t mem_base, int num_words)
 {
-    size_t i;
-    mbedtls_mpi_uint c, z;
+    int ret = 0;
 
-    for( i = c = 0; i < n; i++, s++, d++ )
-    {
-        z = ( *d <  c );     *d -=  c;
-        c = ( *d < *s ) + z; *d -= *s;
-    }
+    MBEDTLS_MPI_CHK( mbedtls_mpi_grow(x, num_words) );
 
-    while( c != 0 )
-    {
-        z = ( *d < c ); *d -= c;
-        c = z; i++; d++;
-    }
-}
+    /* Copy data from memory block registers */
+    memcpy(x->p, (uint32_t *)mem_base, num_words * 4);
 
+    /* Zero any remaining limbs in the bignum, if the buffer is bigger
+       than num_words */
+    for(size_t i = num_words; i < x->n; i++) {
+        x->p[i] = 0;
+    }
 
-/* The following 3 Montgomery arithmetic function are
-   copied from mbedTLS bigint.c verbatim as they are static.
+    asm volatile ("memw");
+ cleanup:
+    return ret;
+}
 
-   TODO: find a way to support making the versions in mbedtls
-   non-static.
-*/
 
-/*
- * Fast Montgomery initialization (thanks to Tom St Denis)
+/**
+ *
+ * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1,
+ * where B^-1(B-1) mod N=1. Actually, only the least significant part of
+ * N' is needed, hence the definition N0'=N' mod b. We reproduce below the
+ * simple algorithm from an article by Dusse and Kaliski to efficiently
+ * find N0' from N0 and b
  */
-static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N )
+static mbedtls_mpi_uint modular_inverse(const mbedtls_mpi *M)
 {
-    mbedtls_mpi_uint x, m0 = N->p[0];
-    unsigned int i;
-
-    x  = m0;
-    x += ( ( m0 + 2 ) & 4 ) << 1;
+    int i;
+    uint64_t t = 1;
+    uint64_t two_2_i_minus_1 = 2;   /* 2^(i-1) */
+    uint64_t two_2_i = 4;           /* 2^i */
+    uint64_t N = M->p[0];
+
+    for (i = 2; i <= 32; i++) {
+        if ((mbedtls_mpi_uint) N * t % two_2_i >= two_2_i_minus_1) {
+            t += two_2_i_minus_1;
+        }
 
-    for( i = biL; i >= 8; i /= 2 )
-        x *= ( 2 - ( m0 * x ) );
+        two_2_i_minus_1 <<= 1;
+        two_2_i <<= 1;
+    }
 
-    *mm = ~x + 1;
+    return (mbedtls_mpi_uint)(UINT32_MAX - t + 1);
 }
 
-/*
- * Montgomery multiplication: A = A * B * R^-1 mod N  (HAC 14.36)
+/* Calculate Rinv = RR^2 mod M, where:
+ *
+ *  R = b^n where b = 2^32, n=num_words,
+ *  R = 2^N (where N=num_bits)
+ *  RR = R^2 = 2^(2*N) (where N=num_bits=num_words*32)
+ *
+ * This calculation is computationally expensive (mbedtls_mpi_mod_mpi)
+ * so caller should cache the result where possible.
+ *
+ * DO NOT call this function while holding esp_mpi_acquire_hardware().
+ *
  */
-static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm,
-                         const mbedtls_mpi *T )
+static int calculate_rinv(mbedtls_mpi *Rinv, const mbedtls_mpi *M, int num_words)
 {
-    size_t i, n, m;
-    mbedtls_mpi_uint u0, u1, *d;
-
-    if( T->n < N->n + 1 || T->p == NULL )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
+    int ret;
+    size_t num_bits = num_words * 32;
+    mbedtls_mpi RR;
+    mbedtls_mpi_init(&RR);
+    MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&RR, num_bits * 2, 1));
+    MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(Rinv, &RR, M));
+
+ cleanup:
+    mbedtls_mpi_free(&RR);
+    return ret;
+}
 
-    memset( T->p, 0, T->n * ciL );
 
-    d = T->p;
-    n = N->n;
-    m = ( B->n < n ) ? B->n : n;
+/* Execute RSA operation. op_reg specifies which 'START' register
+   to write to.
+*/
+static inline void execute_op(uint32_t op_reg)
+{
+    /* Clear interrupt status */
+    REG_WRITE(RSA_INTERRUPT_REG, 1);
 
-    for( i = 0; i < n; i++ )
-    {
-        /*
-         * T = (T + u0*B + u1*N) / 2^biL
-         */
-        u0 = A->p[i];
-        u1 = ( d[0] + u0 * B->p[0] ) * mm;
+    /* Note: above REG_WRITE includes a memw, so we know any writes
+       to the memory blocks are also complete. */
 
-        mpi_mul_hlp( m, B->p, d, u0 );
-        mpi_mul_hlp( n, N->p, d, u1 );
+    REG_WRITE(op_reg, 1);
 
-        *d++ = u0; d[n + 1] = 0;
+#ifdef CONFIG_MBEDTLS_MPI_USE_INTERRUPT
+    if (!xSemaphoreTake(op_complete_sem, 2000 / portTICK_PERIOD_MS)) {
+        ESP_LOGE(TAG, "Timed out waiting for RSA operation (op_reg 0x%x int_reg 0x%x)",
+                 op_reg, REG_READ(RSA_INTERRUPT_REG));
+        abort(); /* indicates a fundamental problem with driver */
     }
+#else
+    while(REG_READ(RSA_INTERRUPT_REG) != 1)
+       { }
+#endif
 
-    memcpy( A->p, d, ( n + 1 ) * ciL );
-
-    if( mbedtls_mpi_cmp_abs( A, N ) >= 0 )
-        mpi_sub_hlp( n, N->p, A->p );
-    else
-        /* prevent timing attacks */
-        mpi_sub_hlp( n, A->p, T->p );
-
-    return( 0 );
+    /* clear the interrupt */
+    REG_WRITE(RSA_INTERRUPT_REG, 1);
 }
 
-/*
- * Montgomery reduction: A = A * R^-1 mod N
- */
-static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T )
-{
-    mbedtls_mpi_uint z = 1;
-    mbedtls_mpi U;
-
-    U.n = U.s = (int) z;
-    U.p = &z;
-
-    return( mpi_montmul( A, &U, N, mm, T ) );
-}
+/* Sub-stages of modulo multiplication/exponentiation operations */
+inline static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
 
+/* Z = (X * Y) mod M
 
-/* Allocate parameters used by hardware MPI multiply,
- and copy mbedtls_mpi structures into them */
-static int mul_pram_alloc(const mbedtls_mpi *A, const mbedtls_mpi *B, char **pA, char **pB, char **pX, size_t *bites)
+   Not an mbedTLS function
+*/
+int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M)
 {
-    char *sa, *sb, *sx;
-//	int algn;
-	int words, bytes;
-	int abytes, bbytes;
+    int ret;
+    size_t num_words = hardware_words_needed(M);
+    mbedtls_mpi Rinv;
+    mbedtls_mpi_uint Mprime;
 
-	if (A->n > B->n)
-		words = A->n;
-	else
-		words = B->n;
+    /* Calculate and load the first stage montgomery multiplication */
+    mbedtls_mpi_init(&Rinv);
+    MBEDTLS_MPI_CHK(calculate_rinv(&Rinv, M, num_words));
+    Mprime = modular_inverse(M);
 
-	bytes = (words / 16 + ((words % 16) ? 1 : 0 )) * 16 * 4 * 2;
+    esp_mpi_acquire_hardware();
 
-	abytes = A->n * 4;	
-	bbytes = B->n * 4;
+    /* Load M, X, Rinv, Mprime (Mprime is mod 2^32) */
+    mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words);
+    mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
+    mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, &Rinv, num_words);
+    REG_WRITE(RSA_M_DASH_REG, (uint32_t)Mprime);
 
-	sa = malloc(bytes);
-	if (!sa) {
-       return -1;
-	}
+    /* "mode" register loaded with number of 512-bit blocks, minus 1 */
+    REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1);
 
-	sb = malloc(bytes);
-	if (!sb) {
-	   free(sa);
-       return -1;
-	}
+    /* Execute first stage montgomery multiplication */
+    execute_op(RSA_MULT_START_REG);
 
-	sx = malloc(bytes);
-	if (!sx) {
-	   free(sa);
-	   free(sb);
-       return -1;
-	}
+    /* execute second stage */
+    MBEDTLS_MPI_CHK( modular_multiply_finish(Z, X, Y, num_words) );
 
-	memcpy(sa, A->p, abytes);
-	memset(sa + abytes, 0, bytes - abytes);
+    esp_mpi_release_hardware();
 
-	memcpy(sb, B->p, bbytes);
-	memset(sb + bbytes, 0, bytes - bbytes);
+ cleanup:
+    mbedtls_mpi_free(&Rinv);
+    return ret;
+}
 
-	*pA = sa;
-	*pB = sb;
+#if defined(MBEDTLS_MPI_EXP_MOD_ALT)
 
-	*pX = sx;
+/*
+ * Sliding-window exponentiation: Z = X^Y mod M  (HAC 14.85)
+ *
+ * _Rinv is optional pre-calculated version of Rinv (via calculate_rinv()).
+ *
+ * (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
+ *
+ */
+int mbedtls_mpi_exp_mod( mbedtls_mpi* Z, const mbedtls_mpi* X, const mbedtls_mpi* Y, const mbedtls_mpi* M, mbedtls_mpi* _Rinv )
+{
+    int ret = 0;
+    size_t z_words = hardware_words_needed(Z);
+    size_t x_words = hardware_words_needed(X);
+    size_t y_words = hardware_words_needed(Y);
+    size_t m_words = hardware_words_needed(M);
+    size_t num_words;
+
+    mbedtls_mpi Rinv_new; /* used if _Rinv == NULL */
+    mbedtls_mpi *Rinv;    /* points to _Rinv (if not NULL) othwerwise &RR_new */
+    mbedtls_mpi_uint Mprime;
+
+    /* "all numbers must be the same length", so choose longest number
+       as cardinal length of operation...
+    */
+    num_words = z_words;
+    if (x_words > num_words) {
+        num_words = x_words;
+    }
+    if (y_words > num_words) {
+        num_words = y_words;
+    }
+    if (m_words > num_words) {
+        num_words = m_words;
+    }
 
-	*bites = bytes * 4;
+    if (num_words * 32 > 4096) {
+        return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+    }
 
-	return 0;
-}
+    /* Determine RR pointer, either _RR for cached value
+       or local RR_new */
+    if (_Rinv == NULL) {
+        mbedtls_mpi_init(&Rinv_new);
+        Rinv = &Rinv_new;
+    } else {
+        Rinv = _Rinv;
+    }
+    if (Rinv->p == NULL) {
+        MBEDTLS_MPI_CHK(calculate_rinv(Rinv, M, num_words));
+    }
 
-#if defined(MBEDTLS_MPI_MUL_MPI_ALT)
+    Mprime = modular_inverse(M);
 
-int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B )
-{
-    int ret = -1;
-    size_t i, j;
-	char *s1 = NULL, *s2 = NULL, *dest = NULL;
-	size_t bites;
+    esp_mpi_acquire_hardware();
 
-    mbedtls_mpi TA, TB;
+    /* "mode" register loaded with number of 512-bit blocks, minus 1 */
+    REG_WRITE(RSA_MODEXP_MODE_REG, (num_words / 16) - 1);
 
-    mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB );
+    /* Load M, X, Rinv, M-prime (M-prime is mod 2^32) */
+    mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
+    mpi_to_mem_block(RSA_MEM_Y_BLOCK_BASE, Y, num_words);
+    mpi_to_mem_block(RSA_MEM_M_BLOCK_BASE, M, num_words);
+    mpi_to_mem_block(RSA_MEM_RB_BLOCK_BASE, Rinv, num_words);
+    REG_WRITE(RSA_M_DASH_REG, Mprime);
 
-    if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; }
-    if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; }
+    execute_op(RSA_START_MODEXP_REG);
 
-    for( i = A->n; i > 0; i-- )
-        if( A->p[i - 1] != 0 )
-            break;
+    ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, num_words);
 
-    for( j = B->n; j > 0; j-- )
-        if( B->p[j - 1] != 0 )
-            break;
+    esp_mpi_release_hardware();
 
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) );
+ cleanup:
+    if (_Rinv == NULL) {
+        mbedtls_mpi_free(&Rinv_new);
+    }
 
-	if (mul_pram_alloc(A, B, &s1, &s2, &dest, &bites)) {
-       goto cleanup;
-	}
+    return ret;
+}
 
-    esp_mpi_acquire_hardware();
-	if (ets_bigint_mult_prepare((uint32_t *)s1, (uint32_t *)s2, bites)){
-		ets_bigint_wait_finish();
-		if (ets_bigint_mult_getz((uint32_t *)dest, bites) == true) {
-			memcpy(X->p, dest, (i + j) * 4);
-			ret = 0;
-		} else {
-            printf("ets_bigint_mult_getz failed\n");
-		}
-	} else{
-		printf("Baseline multiplication failed\n");
-	}
-    esp_mpi_release_hardware();
+#endif /* MBEDTLS_MPI_EXP_MOD_ALT */
 
-    X->s = A->s * B->s;
+/* Second & final step of a modular multiply - load second multiplication
+ * factor Y, run the multiply, read back the result into Z.
+ *
+ * Called from both mbedtls_mpi_exp_mod and mbedtls_mpi_mod_mpi.
+ *
+ * @param Z result value
+ * @param X first multiplication factor (used to set sign of result).
+ * @param Y second multiplication factor.
+ * @param num_words size of modulo operation, in words (limbs).
+ *        Should already be rounded up to a multiple of 16 words (512 bits) & range checked.
+ *
+ *  Caller must have already called esp_mpi_acquire_hardware().
+ */
+static int modular_multiply_finish(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
+{
+    int ret;
+    /* Load Y to X input memory block, rerun */
+    mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, Y, num_words);
 
-    free(s1);
-    free(s2);
-    free(dest);
+    execute_op(RSA_MULT_START_REG);
 
-cleanup:
+    /* Read result into Z */
+    ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, num_words);
 
-    mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA );
+    Z->s = X->s * Y->s;
 
-    return( ret );
+    return ret;
 }
 
-#endif /* MBEDTLS_MPI_MUL_MPI_ALT */
+#if defined(MBEDTLS_MPI_MUL_MPI_ALT) /* MBEDTLS_MPI_MUL_MPI_ALT */
 
-#if defined(MBEDTLS_MPI_EXP_MOD_ALT)
-/*
- * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
- */
-int mbedtls_mpi_exp_mod( mbedtls_mpi* X, const mbedtls_mpi* A, const mbedtls_mpi* E, const mbedtls_mpi* N, mbedtls_mpi* _RR )
+static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words);
+
+/* Z = X * Y */
+int mbedtls_mpi_mul_mpi( mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y )
 {
     int ret;
-    size_t wbits, wsize, one = 1;
-    size_t i, j, nblimbs;
-    size_t bufsize, nbits;
-    mbedtls_mpi_uint ei, mm, state;
-    mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos;
-    int neg;
-
-    if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
-
-    if( mbedtls_mpi_cmp_int( E, 0 ) < 0 )
-        return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA );
-
-    /*
-     * Init temps and window size
-     */
-    mpi_montg_init( &mm, N );
-    mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T );
-    mbedtls_mpi_init( &Apos );
-    memset( W, 0, sizeof( W ) );
-
-    i = mbedtls_mpi_bitlen( E );
-
-    wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 :
-            ( i >  79 ) ? 4 : ( i >  23 ) ? 3 : 1;
-
-    if( wsize > MBEDTLS_MPI_WINDOW_SIZE )
-        wsize = MBEDTLS_MPI_WINDOW_SIZE;
-
-    j = N->n + 1;
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1],  j ) );
-    MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) );
-
-    /*
-     * Compensate for negative A (and correct at the end)
-     */
-    neg = ( A->s == -1 );
-    if( neg )
-    {
-        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) );
-        Apos.s = 1;
-        A = &Apos;
+    size_t bits_x, bits_y, words_x, words_y, words_mult, words_z;
+
+    /* Count words needed for X & Y in hardware */
+    bits_x = mbedtls_mpi_bitlen(X);
+    bits_y = mbedtls_mpi_bitlen(Y);
+    /* Convert bit counts to words, rounded up to 512-bit
+       (16 word) blocks */
+    words_x = bits_to_hardware_words(bits_x);
+    words_y = bits_to_hardware_words(bits_y);
+
+    /* Short-circuit eval if either argument is 0 or 1.
+
+       This is needed as the mpi modular division
+       argument will sometimes call in here when one
+       argument is too large for the hardware unit, but the other
+       argument is zero or one.
+
+       This leaks some timing information, although overall there is a
+       lot less timing variation than a software MPI approach.
+    */
+    if (bits_x == 0 || bits_y == 0) {
+        mbedtls_mpi_lset(Z, 0);
+        return 0;
     }
-
-    /*
-     * If 1st call, pre-compute R^2 mod N
-     */
-    if( _RR == NULL || _RR->p == NULL )
-    {
-        MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) );
-
-        if( _RR != NULL )
-            memcpy( _RR, &RR, sizeof( mbedtls_mpi) );
+    if (bits_x == 1) {
+        return mbedtls_mpi_copy(Z, Y);
     }
-    else
-        memcpy( &RR, _RR, sizeof( mbedtls_mpi) );
-
-    /*
-     * W[1] = A * R^2 * R^-1 mod N = A * R mod N
-     */
-    if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 )
-        MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) );
-    else
-        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) );
-
-    mpi_montmul( &W[1], &RR, N, mm, &T );
-
-    /*
-     * X = R^2 * R^-1 mod N = R mod N
-     */
-    MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) );
-    mpi_montred( X, N, mm, &T );
-
-    if( wsize > 1 )
-    {
-        /*
-         * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1)
-         */
-        j =  one << ( wsize - 1 );
-
-        MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) );
-        MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1]    ) );
-
-        for( i = 0; i < wsize - 1; i++ )
-            mpi_montmul( &W[j], &W[j], N, mm, &T );
-
-        /*
-         * W[i] = W[i - 1] * W[1]
-         */
-        for( i = j + 1; i < ( one << wsize ); i++ )
-        {
-            MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) );
-            MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) );
-
-            mpi_montmul( &W[i], &W[1], N, mm, &T );
-        }
+    if (bits_y == 1) {
+        return mbedtls_mpi_copy(Z, X);
     }
 
-    nblimbs = E->n;
-    bufsize = 0;
-    nbits   = 0;
-    wbits   = 0;
-    state   = 0;
+    words_mult = (words_x > words_y ? words_x : words_y);
 
-    while( 1 )
-    {
-        if( bufsize == 0 )
-        {
-            if( nblimbs == 0 )
-                break;
+    /* Result Z has to have room for double the larger factor */
+    words_z = words_mult * 2;
 
-            nblimbs--;
 
-            bufsize = sizeof( mbedtls_mpi_uint ) << 3;
+    /* If either factor is over 2048 bits, we can't use the standard hardware multiplier
+       (it assumes result is double longest factor, and result is max 4096 bits.)
+
+       However, we can fail over to mod_mult for up to 4096 bits of result (modulo
+       multiplication doesn't have the same restriction, so result is simply the
+       number of bits in X plus number of bits in in Y.)
+    */
+    if (words_mult * 32 > 2048) {
+        /* Calculate new length of Z */
+        words_z = bits_to_hardware_words(bits_x + bits_y);
+        if (words_z * 32 > 4096) {
+            ESP_LOGE(TAG, "ERROR: %d bit result %d bits * %d bits too large for hardware unit\n", words_z * 32, bits_x, bits_y);
+            return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE;
+        }
+        else {
+            return mpi_mult_mpi_failover_mod_mult(Z, X, Y, words_z);
         }
+    }
+
+    /* Otherwise, we can use the (faster) multiply hardware unit */
 
-        bufsize--;
+    esp_mpi_acquire_hardware();
 
-        ei = (E->p[nblimbs] >> bufsize) & 1;
+    /* Copy X (right-extended) & Y (left-extended) to memory block */
+    mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, words_mult);
+    mpi_to_mem_block(RSA_MEM_Z_BLOCK_BASE + words_mult * 4, Y, words_mult);
+    /* NB: as Y is left-extended, we don't zero the bottom words_mult words of Y block.
+       This is OK for now because zeroing is done by hardware when we do esp_mpi_acquire_hardware().
+    */
 
-        /*
-         * skip leading 0s
-         */
-        if( ei == 0 && state == 0 )
-            continue;
+    REG_WRITE(RSA_M_DASH_REG, 0);
 
-        if( ei == 0 && state == 1 )
-        {
-            /*
-             * out of window, square X
-             */
-            mpi_montmul( X, X, N, mm, &T );
-            continue;
-        }
+    /* "mode" register loaded with number of 512-bit blocks in result,
+       plus 7 (for range 9-12). (this is ((N~ / 32) - 1) + 8))
+    */
+    REG_WRITE(RSA_MULT_MODE_REG, (words_z / 16) + 7);
 
-        /*
-         * add ei to current window
-         */
-        state = 2;
-
-        nbits++;
-        wbits |= ( ei << ( wsize - nbits ) );
-
-        if( nbits == wsize )
-        {
-            /*
-             * X = X^wsize R^-1 mod N
-             */
-            for( i = 0; i < wsize; i++ )
-                mpi_montmul( X, X, N, mm, &T );
-
-            /*
-             * X = X * W[wbits] R^-1 mod N
-             */
-            mpi_montmul( X, &W[wbits], N, mm, &T );
-
-            state--;
-            nbits = 0;
-            wbits = 0;
-        }
-    }
+    execute_op(RSA_MULT_START_REG);
 
-    /*
-     * process the remaining bits
-     */
-    for( i = 0; i < nbits; i++ )
-    {
-        mpi_montmul( X, X, N, mm, &T );
+    /* Read back the result */
+    ret = mem_block_to_mpi(Z, RSA_MEM_Z_BLOCK_BASE, words_z);
 
-        wbits <<= 1;
+    Z->s = X->s * Y->s;
 
-        if( ( wbits & ( one << wsize ) ) != 0 )
-            mpi_montmul( X, &W[1], N, mm, &T );
-    }
+    esp_mpi_release_hardware();
+
+    return ret;
+}
 
-    /*
-     * X = A^E * R * R^-1 mod N = A^E mod N
-     */
-    mpi_montred( X, N, mm, &T );
+/* Special-case of mbedtls_mpi_mult_mpi(), where we use hardware montgomery mod
+   multiplication to calculate an mbedtls_mpi_mult_mpi result where either
+   A or B are >2048 bits so can't use the standard multiplication method.
 
-    if( neg )
-    {
-        X->s = -1;
-        MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) );
+   Result (A bits + B bits) must still be less than 4096 bits.
+
+   This case is simpler than the general case modulo multiply of
+   esp_mpi_mul_mpi_mod() because we can control the other arguments:
+
+   * Modulus is chosen with M=(2^num_bits - 1) (ie M=R-1), so output
+   isn't actually modulo anything.
+   * Mprime and Rinv are therefore predictable as follows:
+   Mprime = 1
+   Rinv = 1
+
+   (See RSA Accelerator section in Technical Reference for more about Mprime, Rinv)
+*/
+static int mpi_mult_mpi_failover_mod_mult(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, size_t num_words)
+{
+    int ret = 0;
+
+    /* Load coefficients to hardware */
+    esp_mpi_acquire_hardware();
+
+    /* M = 2^num_words - 1, so block is entirely FF */
+    for(int i = 0; i < num_words; i++) {
+        REG_WRITE(RSA_MEM_M_BLOCK_BASE + i * 4, UINT32_MAX);
     }
+    /* Mprime = 1 */
+    REG_WRITE(RSA_M_DASH_REG, 1);
 
-cleanup:
+    /* "mode" register loaded with number of 512-bit blocks, minus 1 */
+    REG_WRITE(RSA_MULT_MODE_REG, (num_words / 16) - 1);
 
-    for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ )
-        mbedtls_mpi_free( &W[i] );
+    /* Load X */
+    mpi_to_mem_block(RSA_MEM_X_BLOCK_BASE, X, num_words);
 
-    mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos );
+    /* Rinv = 1 */
+    REG_WRITE(RSA_MEM_RB_BLOCK_BASE, 1);
+    for(int i = 1; i < num_words; i++) {
+        REG_WRITE(RSA_MEM_RB_BLOCK_BASE + i * 4, 0);
+    }
 
-    if( _RR == NULL || _RR->p == NULL )
-        mbedtls_mpi_free( &RR );
+    execute_op(RSA_MULT_START_REG);
 
-    return( ret );
-}
+    /* finish the modular multiplication */
+    MBEDTLS_MPI_CHK( modular_multiply_finish(Z, X, Y, num_words) );
 
-#endif /* MBEDTLS_MPI_EXP_MOD_ALT */
+    esp_mpi_release_hardware();
 
-#endif /* MBEDTLS_MPI_MUL_MPI_ALT || MBEDTLS_MPI_EXP_MOD_ALT */
+ cleanup:
+    return ret;
+}
+
+#endif /* MBEDTLS_MPI_MUL_MPI_ALT */
 

+ 1 - 2
components/mbedtls/port/include/aes_alt.h

@@ -20,7 +20,6 @@
  *
  *
  */
-
 #ifndef AES_ALT_H
 #define AES_ALT_H
 
@@ -56,4 +55,4 @@ typedef esp_aes_context mbedtls_aes_context;
 }
 #endif
 
-#endif /* aes.h */
+#endif

+ 78 - 0
components/mbedtls/port/include/mbedtls/bignum.h

@@ -0,0 +1,78 @@
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#ifndef __ESP_MBEDTLS_BIGNUM_H__
+#define __ESP_MBEDTLS_BIGNUM_H__
+
+#include_next "mbedtls/bignum.h"
+
+/**
+ * This is a wrapper for the main mbedtls/bignum.h. This wrapper
+ * provides a few additional ESP32-only functions.
+ *
+ * This is because we don't set MBEDTLS_BIGNUM_ALT in the same way we
+ * do for AES, SHA, etc. Because we still use most of the bignum.h
+ * implementation and just replace a few hardware accelerated
+ * functions (see MBEDTLS_MPI_EXP_MOD_ALT & MBEDTLS_MPI_MUL_MPI_ALT in
+ * esp_config.h).
+ *
+ * @note Unlike the other hardware accelerator support functions in esp32/hwcrypto, there is no
+ * generic "hwcrypto/bignum.h" header for using these functions without mbedTLS. The reason for this
+ * is that all of the function implementations depend strongly upon the mbedTLS MPI implementation.
+ */
+
+/**
+ * @brief Lock access to RSA Accelerator (MPI/bignum operations)
+ *
+ * RSA Accelerator hardware unit can only be used by one
+ * consumer at a time.
+ *
+ * @note This function is non-recursive (do not call it twice from the
+ * same task.)
+ *
+ * @note You do not need to call this if you are using the mbedTLS bignum.h
+ * API or esp_mpi_xxx functions. This function is only needed if you
+ * want to call ROM RSA functions or access the registers directly.
+ *
+ */
+void esp_mpi_acquire_hardware(void);
+
+/**
+ * @brief Unlock access to RSA Accelerator (MPI/bignum operations)
+ *
+ * Has to be called once for each call to esp_mpi_acquire_hardware().
+ *
+ * @note You do not need to call this if you are using the mbedTLS bignum.h
+ * API or esp_mpi_xxx functions. This function is only needed if you
+ * want to call ROM RSA functions or access the registers directly.
+ */
+void esp_mpi_release_hardware(void);
+
+/* @brief MPI modular mupltiplication function
+ *
+ * Calculates Z = (X * Y) mod M using MPI hardware acceleration.
+ *
+ * This is not part of the standard mbedTLS bignum API.
+ *
+ * @note All of X, Y & Z should be less than 4096 bit long or an error is returned.
+ *
+ * @param Z Result bignum, should be pre-initialised with mbedtls_mpi_init().
+ * @param X First multiplication argument.
+ * @param Y Second multiplication argument.
+ * @param M Modulus value for result.
+ *
+ * @return 0 on success, mbedTLS MPI error codes on failure.
+ */
+int esp_mpi_mul_mpi_mod(mbedtls_mpi *Z, const mbedtls_mpi *X, const mbedtls_mpi *Y, const mbedtls_mpi *M);
+
+#endif

+ 6 - 4
components/mbedtls/port/include/mbedtls/esp_config.h

@@ -239,7 +239,9 @@
 /* The following units have ESP32 hardware support,
    uncommenting each _ALT macro will use the
    hardware-accelerated implementation. */
+#ifdef CONFIG_MBEDTLS_HARDWARE_AES
 #define MBEDTLS_AES_ALT
+#endif
 
 /* Currently hardware SHA does not work with TLS handshake,
    due to concurrency issue. Internal TW#7111. */
@@ -250,11 +252,11 @@
 /* The following MPI (bignum) functions have ESP32 hardware support,
    Uncommenting these macros will use the hardware-accelerated
    implementations.
-
-   Disabled as number of limbs limited by bug. Internal TW#7112.
 */
-//#define MBEDTLS_MPI_EXP_MOD_ALT
-//#define MBEDTLS_MPI_MUL_MPI_ALT
+#ifdef CONFIG_MBEDTLS_HARDWARE_MPI
+#define MBEDTLS_MPI_EXP_MOD_ALT
+#define MBEDTLS_MPI_MUL_MPI_ALT
+#endif
 
 /**
  * \def MBEDTLS_MD2_PROCESS_ALT

+ 13 - 4
components/mbedtls/port/include/sha1_alt.h

@@ -1,7 +1,16 @@
-/*
- * copyright (c) 2010 - 2012 Espressif System
- *
- */
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 #ifndef _SHA1_ALT_H_
 #define _SHA1_ALT_H_
 

+ 14 - 6
components/mbedtls/port/include/sha256_alt.h

@@ -1,8 +1,16 @@
-/*
- * copyright (c) 2010 - 2012 Espressif System
- *
- */
-
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 #ifndef _SHA256_ALT_H_
 #define _SHA256_ALT_H_
 
@@ -30,4 +38,4 @@ typedef esp_sha_context mbedtls_sha256_context;
 }
 #endif
 
-#endif /* sha256.h */
+#endif

+ 14 - 7
components/mbedtls/port/include/sha512_alt.h

@@ -1,9 +1,16 @@
-/*
- * copyright (c) 2010 - 2012 Espressif System
- *
- * esf Link List Descriptor
- */
-
+// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
 #ifndef _SHA512_ALT_H_
 #define _SHA512_ALT_H_
 
@@ -30,4 +37,4 @@ typedef esp_sha_context  mbedtls_sha512_context;
 }
 #endif
 
-#endif /* sha512.h */
+#endif

+ 8 - 0
components/micro-ecc/component.mk

@@ -0,0 +1,8 @@
+# only compile the micro-ecc/uECC.c source file
+# (SRCDIRS is needed so build system can find the source file)
+COMPONENT_SRCDIRS := micro-ecc
+COMPONENT_OBJS := micro-ecc/uECC.o
+
+COMPONENT_ADD_INCLUDEDIRS := micro-ecc
+
+COMPONENT_SUBMODULES := micro-ecc

+ 1 - 0
components/micro-ecc/micro-ecc

@@ -0,0 +1 @@
+Subproject commit 14222e062d77f45321676e813d9525f32a88e8fa

+ 1 - 2
components/newlib/component.mk

@@ -1,5 +1,4 @@
-COMPONENT_ADD_LDFLAGS := $(abspath lib/libc.a) $(abspath lib/libm.a) -lnewlib
+COMPONENT_ADD_LDFLAGS := $(COMPONENT_PATH)/lib/libc.a $(COMPONENT_PATH)/lib/libm.a -lnewlib
 
 COMPONENT_ADD_INCLUDEDIRS := include platform_include
 
-include $(IDF_PATH)/make/component_common.mk

+ 0 - 2
components/nghttp/component.mk

@@ -5,5 +5,3 @@
 COMPONENT_ADD_INCLUDEDIRS := port/include include
 
 COMPONENT_SRCDIRS := library port
-
-include $(IDF_PATH)/make/component_common.mk

+ 0 - 1
components/nvs_flash/component.mk

@@ -6,4 +6,3 @@ COMPONENT_ADD_INCLUDEDIRS := include
 
 COMPONENT_SRCDIRS := src
 
-include $(IDF_PATH)/make/component_common.mk

+ 84 - 21
components/nvs_flash/include/nvs.h

@@ -77,8 +77,9 @@ typedef enum {
  */
 esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_handle);
 
+/**@{*/
 /**
- * @brief      nvs_set_X - set value for given key
+ * @brief      set value for given key
  *
  * This family of functions set value for the key, given its name. Note that
  * actual storage will not be updated until nvs_commit function is called.
@@ -89,7 +90,6 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha
  *                     implementation, but is guaranteed to be at least
  *                     16 characters. Shouldn't be empty.
  * @param[in]  value   The value to set.
- * @param[in]  length  For nvs_set_blob: length of binary value to set, in bytes.
  *
  * @return
  *             - ESP_OK if value was set successfully
@@ -112,10 +112,39 @@ esp_err_t nvs_set_u32 (nvs_handle handle, const char* key, uint32_t value);
 esp_err_t nvs_set_i64 (nvs_handle handle, const char* key, int64_t value);
 esp_err_t nvs_set_u64 (nvs_handle handle, const char* key, uint64_t value);
 esp_err_t nvs_set_str (nvs_handle handle, const char* key, const char* value);
+/**@}*/ 
+
+/**
+ * @brief       set variable length binary value for given key
+ *
+ * This family of functions set value for the key, given its name. Note that
+ * actual storage will not be updated until nvs_commit function is called.
+ *
+ * @param[in]  handle  Handle obtained from nvs_open function.
+ *                     Handles that were opened read only cannot be used.
+ * @param[in]  key     Key name. Maximal length is determined by the underlying
+ *                     implementation, but is guaranteed to be at least
+ *                     16 characters. Shouldn't be empty.
+ * @param[in]  value   The value to set.
+ * @param[in]  length  length of binary value to set, in bytes.
+ *
+ * @return
+ *             - ESP_OK if value was set successfully
+ *             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
+ *             - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only
+ *             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
+ *             - ESP_ERR_NVS_NOT_ENOUGH_SPACE if there is not enough space in the
+ *               underlying storage to save the value
+ *             - ESP_ERR_NVS_REMOVE_FAILED if the value wasn't updated because flash
+ *               write operation has failed. The value was written however, and
+ *               update will be finished after re-initialization of nvs, provided that
+ *               flash operation doesn't fail again.
+ */
 esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, size_t length);
 
+/**@{*/
 /**
- * @brief      nvs_get_X - get value for given key
+ * @brief      get value for given key
  *
  * These functions retrieve value for the key, given its name. If key does not
  * exist, or the requested variable type doesn't match the type which was used
@@ -125,7 +154,55 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si
  *
  * All functions expect out_value to be a pointer to an already allocated variable
  * of the given type.
- * Additionally, nvs_get_str and nvs_get_blob support WinAPI-style length queries.
+ *
+ * \code{c}
+ * // Example of using nvs_get_i32:
+ * int32_t max_buffer_size = 4096; // default value
+ * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
+ * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
+ * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
+ * // have its default value.
+ *
+ * \endcode
+ *
+ * @param[in]     handle     Handle obtained from nvs_open function.
+ * @param[in]     key        Key name. Maximal length is determined by the underlying
+ *                           implementation, but is guaranteed to be at least
+ *                           16 characters. Shouldn't be empty.
+ * @param         out_value  Pointer to the output value.
+ *                           May be NULL for nvs_get_str and nvs_get_blob, in this
+ *                           case required length will be returned in length argument.
+ *
+ * @return
+ *             - ESP_OK if the value was retrieved successfully
+ *             - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
+ *             - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
+ *             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
+ *             - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
+ */
+esp_err_t nvs_get_i8  (nvs_handle handle, const char* key, int8_t* out_value);
+esp_err_t nvs_get_u8  (nvs_handle handle, const char* key, uint8_t* out_value);
+esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value);
+esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value);
+esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value);
+esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value);
+esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value);
+esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value);
+/**@}*/ 
+
+/**
+ * @brief      get value for given key
+ *
+ * These functions retrieve value for the key, given its name. If key does not
+ * exist, or the requested variable type doesn't match the type which was used
+ * when setting a value, an error is returned.
+ *
+ * In case of any error, out_value is not modified.
+ *
+ * All functions expect out_value to be a pointer to an already allocated variable
+ * of the given type.
+ * 
+ * nvs_get_str and nvs_get_blob functions support WinAPI-style length queries.
  * To get the size necessary to store the value, call nvs_get_str or nvs_get_blob
  * with zero out_value and non-zero pointer to length. Variable pointed to
  * by length argument will be set to the required length. For nvs_get_str,
@@ -136,13 +213,6 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si
  * nvs_get/set_blob used for arbitrary data structures.
  *
  * \code{c}
- * // Example of using nvs_get_i32:
- * int32_t max_buffer_size = 4096; // default value
- * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
- * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
- * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
- * // have its default value.
- *
  * // Example (without error checking) of using nvs_get_str to get a string into dynamic array:
  * size_t required_size;
  * nvs_get_str(my_handle, "server_name", NULL, &required_size);
@@ -163,8 +233,7 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si
  * @param         out_value  Pointer to the output value.
  *                           May be NULL for nvs_get_str and nvs_get_blob, in this
  *                           case required length will be returned in length argument.
- * @param[inout]  length     For nvs_get_str and nvs_get_blob, non-zero pointer
- *                           to the variable holding the length of out_value.
+ * @param[inout]  length     A non-zero pointer to the variable holding the length of out_value.
  *                           In case out_value a zero, will be set to the length
  *                           required to hold the value. In case out_value is not
  *                           zero, will be set to the actual length of the value
@@ -177,16 +246,10 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si
  *             - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints
  *             - ESP_ERR_NVS_INVALID_LENGTH if length is not sufficient to store data
  */
-esp_err_t nvs_get_i8  (nvs_handle handle, const char* key, int8_t* out_value);
-esp_err_t nvs_get_u8  (nvs_handle handle, const char* key, uint8_t* out_value);
-esp_err_t nvs_get_i16 (nvs_handle handle, const char* key, int16_t* out_value);
-esp_err_t nvs_get_u16 (nvs_handle handle, const char* key, uint16_t* out_value);
-esp_err_t nvs_get_i32 (nvs_handle handle, const char* key, int32_t* out_value);
-esp_err_t nvs_get_u32 (nvs_handle handle, const char* key, uint32_t* out_value);
-esp_err_t nvs_get_i64 (nvs_handle handle, const char* key, int64_t* out_value);
-esp_err_t nvs_get_u64 (nvs_handle handle, const char* key, uint64_t* out_value);
+/**@{*/
 esp_err_t nvs_get_str (nvs_handle handle, const char* key, char* out_value, size_t* length);
 esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size_t* length);
+/**@}*/
 
 /**
  * @brief      Erase key-value pair with given key name.

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff