Просмотр исходного кода

Merge branch 'master' into feature/btdm_bluedroid

feature/btdm_bluedroid use newest master

# Conflicts:
#	components/bt/component.mk
Tian Hao 9 лет назад
Родитель
Сommit
0b37621438
100 измененных файлов с 13469 добавлено и 1630 удалено
  1. 10 0
      .gitignore
  2. 19 1
      .gitlab-ci.yml
  3. 37 0
      CONTRIBUTING.md
  4. 9 9
      Kconfig
  5. 16 2
      README.md
  6. 4 0
      components/bootloader/src/main/bootloader_config.h
  7. 21 5
      components/bootloader/src/main/bootloader_start.c
  8. 18 12
      components/bt/Kconfig
  9. 41 28
      components/bt/bt.c
  10. 7 5
      components/bt/component.mk
  11. 11 8
      components/bt/include/bt.h
  12. 1 1
      components/bt/lib
  13. 31 18
      components/driver/gpio.c
  14. 3 3
      components/driver/include/driver/gpio.h
  15. 406 0
      components/driver/include/driver/ledc.h
  16. 70 0
      components/driver/include/driver/periph_ctrl.h
  17. 432 0
      components/driver/ledc.c
  18. 170 0
      components/driver/periph_ctrl.c
  19. 48 29
      components/esp32/Kconfig
  20. 14 17
      components/esp32/component.mk
  21. 43 49
      components/esp32/cpu_start.c
  22. 49 0
      components/esp32/deepsleep.c
  23. 38 124
      components/esp32/event_default_handlers.c
  24. 107 0
      components/esp32/event_loop.c
  25. 14 2
      components/esp32/include/esp_attr.h
  26. 137 0
      components/esp32/include/esp_deepsleep.h
  27. 7 0
      components/esp32/include/esp_err.h
  28. 12 43
      components/esp32/include/esp_event.h
  29. 81 0
      components/esp32/include/esp_event_loop.h
  30. 143 0
      components/esp32/include/esp_smartconfig.h
  31. 1 15
      components/esp32/include/esp_system.h
  32. 6 7
      components/esp32/include/esp_task.h
  33. 15 189
      components/esp32/include/esp_wifi.h
  34. 190 0
      components/esp32/include/esp_wifi_types.h
  35. 0 131
      components/esp32/include/esp_wps.h
  36. 13 13
      components/esp32/include/rom/rtc.h
  37. 126 124
      components/esp32/include/soc/io_mux_reg.h
  38. 68 127
      components/esp32/include/soc/ledc_struct.h
  39. 0 14
      components/esp32/ld/esp32.bt.ld
  40. 0 14
      components/esp32/ld/esp32.bt.trace.ld
  41. 15 3
      components/esp32/ld/esp32.common.ld
  42. 47 6
      components/esp32/ld/esp32.ld
  43. 5 1
      components/esp32/ld/esp32.rom.ld
  44. 0 14
      components/esp32/ld/esp32.trace.ld
  45. 1 1
      components/esp32/lib
  46. 4 5
      components/esp32/syscalls.c
  47. 0 115
      components/esp32/wifi.c
  48. 1 1
      components/esptool_py/Makefile.projbuild
  49. 1 1
      components/esptool_py/esptool
  50. 1 1
      components/expat/component.mk
  51. 22 0
      components/expat/expat.rst
  52. 132 124
      components/freertos/Kconfig
  53. 1 0
      components/freertos/croutine.c
  54. 0 7
      components/freertos/event_groups.c
  55. 12 0
      components/freertos/include/freertos/FreeRTOSConfig.h
  56. 206 0
      components/freertos/include/freertos/ringbuf.h
  57. 6 0
      components/freertos/include/freertos/task.h
  58. 2 2
      components/freertos/panic.c
  59. 90 304
      components/freertos/queue.c
  60. 474 0
      components/freertos/ringbuf.c
  61. 33 28
      components/freertos/tasks.c
  62. 20 0
      components/freertos/xtensa_vectors.S
  63. 7 7
      components/log/Kconfig
  64. 17 17
      components/lwip/Kconfig
  65. 1 1
      components/lwip/component.mk
  66. 11 1
      components/lwip/include/lwip/port/arch/sys_arch.h
  67. 8 0
      components/lwip/include/lwip/port/netif/wlanif.h
  68. 37 0
      components/mbedtls/Kconfig
  69. 5 1
      components/mbedtls/port/include/mbedtls/esp_config.h
  70. 23 0
      components/nghttp/COPYING
  71. 1 0
      components/nghttp/LICENSE
  72. 17 0
      components/nghttp/Makefile
  73. 4 0
      components/nghttp/Makefile.projbuild
  74. 1 0
      components/nghttp/README
  75. 9 0
      components/nghttp/component.mk
  76. 5030 0
      components/nghttp/include/nghttp2/nghttp2.h
  77. 42 0
      components/nghttp/include/nghttp2/nghttp2ver.h
  78. 388 0
      components/nghttp/include/nghttp2_buf.h
  79. 117 0
      components/nghttp/include/nghttp2_callbacks.h
  80. 581 0
      components/nghttp/include/nghttp2_frame.h
  81. 430 0
      components/nghttp/include/nghttp2_hd.h
  82. 77 0
      components/nghttp/include/nghttp2_hd_huffman.h
  83. 122 0
      components/nghttp/include/nghttp2_helper.h
  84. 97 0
      components/nghttp/include/nghttp2_http.h
  85. 58 0
      components/nghttp/include/nghttp2_int.h
  86. 144 0
      components/nghttp/include/nghttp2_map.h
  87. 45 0
      components/nghttp/include/nghttp2_mem.h
  88. 91 0
      components/nghttp/include/nghttp2_net.h
  89. 34 0
      components/nghttp/include/nghttp2_npn.h
  90. 116 0
      components/nghttp/include/nghttp2_option.h
  91. 166 0
      components/nghttp/include/nghttp2_outbound_item.h
  92. 128 0
      components/nghttp/include/nghttp2_pq.h
  93. 42 0
      components/nghttp/include/nghttp2_priority_spec.h
  94. 49 0
      components/nghttp/include/nghttp2_queue.h
  95. 80 0
      components/nghttp/include/nghttp2_rcbuf.h
  96. 878 0
      components/nghttp/include/nghttp2_session.h
  97. 436 0
      components/nghttp/include/nghttp2_stream.h
  98. 34 0
      components/nghttp/include/nghttp2_submit.h
  99. 494 0
      components/nghttp/library/nghttp2_buf.c
  100. 158 0
      components/nghttp/library/nghttp2_callbacks.c

+ 10 - 0
.gitignore

@@ -7,8 +7,18 @@ GTAGS
 GRTAGS
 GRTAGS
 GPATH
 GPATH
 
 
+# emacs
+.dir-locals.el
+
 # emacs temp file suffixes
 # emacs temp file suffixes
 *~
 *~
 .#*
 .#*
 \#*#
 \#*#
 
 
+# Example project files
+examples/*/sdkconfig
+examples/*/sdkconfig.old
+examples/*/build
+
+# Bootloader files
+components/bootloader/src/sdkconfig.old

+ 19 - 1
.gitlab-ci.yml

@@ -64,10 +64,28 @@ build_ssc:
   script:
   script:
     - git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git
     - git clone ssh://git@gitlab.espressif.cn:27227/yinling/SSC.git
     - cd SSC
     - cd SSC
+    - git checkout ${CI_BUILD_REF_NAME} || echo "Using SSC default branch..."
     - make defconfig
     - make defconfig
     - chmod +x gen_misc_ng.sh
     - chmod +x gen_misc_ng.sh
     - ./gen_misc_ng.sh
     - ./gen_misc_ng.sh
 
 
+build_examples:
+  <<: *build_template
+  artifacts:
+    paths:
+      - build_examples/*/*/build/*.bin
+      - build_examples/*/*/build/*.elf
+      - build_examples/*/*/build/*.map
+      - build_examples/*/*/build/bootloader/*.bin
+    expire_in: 6 mos
+
+  script:
+    # it's not possible to build 100% out-of-tree and have the "artifacts"
+    # mechanism work, but this is the next best thing
+    - mkdir build_examples
+    - cd build_examples
+    - ${IDF_PATH}/make/build_examples.sh
+
 test_nvs_on_host:
 test_nvs_on_host:
   stage: test
   stage: test
   image: espressif/esp32-ci-env
   image: espressif/esp32-ci-env
@@ -146,4 +164,4 @@ push_master_to_github:
     - chmod 600 ~/.ssh/id_rsa
     - chmod 600 ~/.ssh/id_rsa
     - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
     - echo -e "Host github.com\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
     - git remote add github git@github.com:espressif/esp-idf.git
     - git remote add github git@github.com:espressif/esp-idf.git
-    - git push github HEAD:master
+    - git push --follow-tags github HEAD:master

+ 37 - 0
CONTRIBUTING.md

@@ -0,0 +1,37 @@
+# Contributions Guide
+
+We welcome contributions to the esp-idf project!
+
+## How to Contribute
+
+Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/).
+
+## Before Contributing
+
+Before sending us a Pull Request, please consider this list of points:
+
+* Is the contribution entirely your own work, or already licensed under an Apache License 2.0 compatible Open Source License? If not then we unfortunately cannot accept it.
+
+* Does any new code conform to the esp-idf Style Guide? (Style Guide currently pending).
+
+* Is the code adequately commented for people to understand how it is structured?
+
+* Is there documentation or examples that go with code contributions? [There are additional suggestions for writing good examples in the examples README](examples/README.md).
+
+* Are comments and documentation written in clear English, with no spelling or grammar errors?
+
+* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" [squashed into previous commits](http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/)?
+
+* If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback.
+
+## Pull Request Process
+
+After you open the Pull Request, there will probably be some discussion in the comments field of the request itself.
+
+Once the Pull Request is ready to merge, it will first be merged into our internal git system for in-house automated testing.
+
+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](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process.

+ 9 - 9
Kconfig

@@ -7,18 +7,18 @@ mainmenu "Espressif IoT Development Framework Configuration"
 
 
 menu "SDK tool configuration"
 menu "SDK tool configuration"
 config TOOLPREFIX
 config TOOLPREFIX
-	string "Compiler toolchain path/prefix"
-	default "xtensa-esp32-elf-"
-	help
-		The prefix/path that is used to call the toolchain. The default setting assumes
-		a crosstool-ng gcc setup that is in your PATH.
+    string "Compiler toolchain path/prefix"
+    default "xtensa-esp32-elf-"
+    help
+        The prefix/path that is used to call the toolchain. The default setting assumes
+        a crosstool-ng gcc setup that is in your PATH.
 
 
 config PYTHON
 config PYTHON
     string "Python 2 interpreter"
     string "Python 2 interpreter"
-	default "python"
-	help
-	    The executable name/path that is used to run python. On some systems Python 2.x
-		may need to be invoked as python2.
+    default "python"
+    help
+        The executable name/path that is used to run python. On some systems Python 2.x
+        may need to be invoked as python2.
 endmenu
 endmenu
 
 
 source "$COMPONENT_KCONFIGS_PROJBUILD"
 source "$COMPONENT_KCONFIGS_PROJBUILD"

+ 16 - 2
README.md

@@ -1,6 +1,18 @@
 # Using Espressif IoT Development Framework with the ESP32
 # Using Espressif IoT Development Framework with the ESP32
 
 
-# Prerequisites
+# Setting Up ESP-IDF
+
+In the [docs](docs) directory you will find per-platform setup guides:
+
+* [Windows Setup Guide](docs/windows-setup.rst)
+* [Mac OS Setup Guide](docs/macos-setup.rst)
+* [Linux Setup Guide](docs/linux-setup.rst)
+
+# Finding A Project
+
+As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory.
+
+Once you've found the project you want to work with, change to its directory and you can configure and build it:
 
 
 # Configuring your project
 # Configuring your project
 
 
@@ -52,8 +64,10 @@ For more details about partition tables and how to create custom variations, vie
 
 
 # Resources
 # Resources
 
 
-* The [docs directory of the esp-idf repository](https://github.com/espressif/esp-idf/tree/master/docs) contains esp-idf documentation.
+* The [docs directory of the esp-idf repository](docs) contains esp-idf documentation.
 
 
 * The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources.
 * The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources.
 
 
 * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
 * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one.
+
+* If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file.

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

@@ -30,6 +30,10 @@ extern "C"
 #define IROM_HIGH   0x40400000
 #define IROM_HIGH   0x40400000
 #define DROM_LOW    0x3F400000
 #define DROM_LOW    0x3F400000
 #define DROM_HIGH   0x3F800000
 #define DROM_HIGH   0x3F800000
+#define RTC_IRAM_LOW  0x400C0000
+#define RTC_IRAM_HIGH 0x400C2000
+#define RTC_DATA_LOW  0x50000000
+#define RTC_DATA_HIGH 0x50002000
 
 
 /*spi mode,saved in third byte in flash */
 /*spi mode,saved in third byte in flash */
 enum {
 enum {

+ 21 - 5
components/bootloader/src/main/bootloader_start.c

@@ -22,6 +22,7 @@
 #include "rom/ets_sys.h"
 #include "rom/ets_sys.h"
 #include "rom/spi_flash.h"
 #include "rom/spi_flash.h"
 #include "rom/crc.h"
 #include "rom/crc.h"
+#include "rom/rtc.h"
 
 
 #include "soc/soc.h"
 #include "soc/soc.h"
 #include "soc/cpu.h"
 #include "soc/cpu.h"
@@ -362,11 +363,15 @@ void unpack_load_app(const partition_pos_t* partition)
     uint32_t irom_load_addr = 0;
     uint32_t irom_load_addr = 0;
     uint32_t irom_size = 0;
     uint32_t irom_size = 0;
 
 
+    /* Reload the RTC memory sections whenever a non-deepsleep reset
+       is occuring */
+    bool load_rtc_memory = rtc_get_reset_reason(0) != DEEPSLEEP_RESET;
+
     ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
     ESP_LOGD(TAG, "bin_header: %u %u %u %u %08x", image_header.magic,
-              image_header.blocks,
-              image_header.spi_mode,
-              image_header.spi_size,
-              (unsigned)image_header.entry_addr);
+             image_header.blocks,
+             image_header.spi_mode,
+             image_header.spi_size,
+             (unsigned)image_header.entry_addr);
 
 
     for (uint32_t section_index = 0;
     for (uint32_t section_index = 0;
             section_index < image_header.blocks;
             section_index < image_header.blocks;
@@ -406,7 +411,18 @@ void unpack_load_app(const partition_pos_t* partition)
             map = true;
             map = true;
         }
         }
 
 
-        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":"");
+		if(!load_rtc_memory && address >= RTC_IRAM_LOW && address < RTC_IRAM_HIGH) {
+			ESP_LOGD(TAG, "Skipping RTC code section at %08x\n", pos);
+			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);
+			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":"");
 
 
         if (!load) {
         if (!load) {
             pos += section_header.data_len;
             pos += section_header.data_len;

+ 18 - 12
components/bt/Kconfig

@@ -3,21 +3,27 @@ visible if MEMMAP_BT
 
 
 
 
 config BT_ENABLED
 config BT_ENABLED
-	bool
-	depends on ESP32_ENABLE_STACK_BT
-	help
-		This compiles in the low-level BT stack.
+    bool
+    depends on ESP32_ENABLE_STACK_BT
+    help
+        This compiles in the low-level BT stack.
 
 
 #config BT_BTLE
 #config BT_BTLE
-#	bool "Enable BTLE"
-#	depends on BT_ENABLED
-#	help
-#		This compiles BTLE support
+#    bool "Enable BTLE"
+#    depends on BT_ENABLED
+#    help
+#        This compiles BTLE support
 #
 #
 #config BT_BT
 #config BT_BT
-#	bool "Enable classic BT"
-#	depends on BT_ENABLED
-#	help
-#		This enables classic BT support
+#    bool "Enable classic BT"
+#    depends on BT_ENABLED
+#    help
+#        This enables classic BT support
 
 
 endmenu
 endmenu
+
+# Memory reserved at start of DRAM for Bluetooth stack
+config BT_RESERVE_DRAM
+    hex
+    default 0x10000 if MEMMAP_BT
+    default 0

+ 41 - 28
components/bt/bt.c

@@ -36,9 +36,6 @@ extern void btdm_osi_funcs_register(void *osi_funcs);
 extern void btdm_controller_init(void);
 extern void btdm_controller_init(void);
 
 
 
 
-static bt_app_startup_cb_t app_startup_cb;
-static void *app_startup_ctx;
-
 #define BT_DEBUG(...)
 #define BT_DEBUG(...)
 #define BT_API_CALL_CHECK(info, api_call, ret) \
 #define BT_API_CALL_CHECK(info, api_call, ret) \
 do{\
 do{\
@@ -56,8 +53,11 @@ struct osi_funcs_t {
     void (*_interrupt_restore)(void);
     void (*_interrupt_restore)(void);
     void (*_task_yield)(void);
     void (*_task_yield)(void);
     void *(*_semphr_create)(uint32_t max, uint32_t init);
     void *(*_semphr_create)(uint32_t max, uint32_t init);
-    void *(*_semphr_give_from_isr)(void *semphr, void *hptw);
-    void *(*_semphr_take)(void *semphr, uint32_t block_time);
+    int32_t (*_semphr_give_from_isr)(void *semphr, void *hptw);
+    int32_t (*_semphr_take)(void *semphr, uint32_t block_time_ms);
+    void *(*_mutex_create)(void);
+    int32_t (*_mutex_lock)(void *mutex);
+    int32_t (*_mutex_unlock)(void *mutex);
     esp_err_t (* _read_efuse_mac)(uint8_t mac[6]);
     esp_err_t (* _read_efuse_mac)(uint8_t mac[6]);
 };
 };
 
 
@@ -73,9 +73,34 @@ static void IRAM_ATTR interrupt_restore(void)
     portEXIT_CRITICAL(&global_int_mux);
     portEXIT_CRITICAL(&global_int_mux);
 }
 }
 
 
-static void * IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time)
+static void * IRAM_ATTR semphr_create_wrapper(uint32_t max, uint32_t init)
+{
+    return (void *)xSemaphoreCreateCounting(max, init);
+}
+
+static int32_t IRAM_ATTR semphr_give_from_isr_wrapper(void *semphr, void *hptw)
+{
+    return (int32_t)xSemaphoreGiveFromISR(semphr, hptw);
+}
+
+static int32_t IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time_ms)
+{
+    return (int32_t)xSemaphoreTake(semphr, block_time_ms / portTICK_RATE_MS);
+}
+
+static void * IRAM_ATTR mutex_create_wrapper(void)
+{
+    return (void *)xSemaphoreCreateMutex();
+}
+
+static int32_t IRAM_ATTR mutex_lock_wrapper(void *mutex)
+{
+    return (int32_t)xSemaphoreTake(mutex, portMAX_DELAY);
+}
+
+static int32_t IRAM_ATTR mutex_unlock_wrapper(void *mutex)
 {
 {
-    return (void *)xSemaphoreTake(semphr, block_time);
+    return (int32_t)xSemaphoreGive(mutex);
 }
 }
 
 
 static struct osi_funcs_t osi_funcs = {
 static struct osi_funcs_t osi_funcs = {
@@ -84,9 +109,12 @@ static struct osi_funcs_t osi_funcs = {
     ._interrupt_disable = interrupt_disable,
     ._interrupt_disable = interrupt_disable,
     ._interrupt_restore = interrupt_restore,
     ._interrupt_restore = interrupt_restore,
     ._task_yield = vPortYield,
     ._task_yield = vPortYield,
-    ._semphr_create = xQueueCreateCountingSemaphore,
-    ._semphr_give_from_isr = (void *)xQueueGiveFromISR,
+    ._semphr_create = semphr_create_wrapper,
+    ._semphr_give_from_isr = semphr_give_from_isr_wrapper,
     ._semphr_take = semphr_take_wrapper,
     ._semphr_take = semphr_take_wrapper,
+    ._mutex_create = mutex_create_wrapper,
+    ._mutex_lock = mutex_lock_wrapper,
+    ._mutex_unlock = mutex_unlock_wrapper,
     ._read_efuse_mac = system_efuse_read_mac,
     ._read_efuse_mac = system_efuse_read_mac,
 };
 };
 
 
@@ -96,26 +124,11 @@ static void bt_controller_task(void *pvParam)
     btdm_controller_init();
     btdm_controller_init();
 }
 }
 
 
-
-static void bt_init_task(void *pvParameters)
+void bt_controller_init()
 {
 {
-    xTaskCreatePinnedToCore(bt_controller_task, "btControllerTask", ESP_TASK_BT_CONTROLLER_STACK, NULL, ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0);
-
-    if (app_startup_cb) {
-        app_startup_cb(app_startup_ctx);
-    }
-
-    vTaskDelete(NULL);
+    xTaskCreatePinnedToCore(bt_controller_task, "btController",
+            ESP_TASK_BT_CONTROLLER_STACK, NULL,
+            ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0);
 }
 }
 
 
-
-esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx)
-{
-    app_startup_cb = cb;
-    app_startup_ctx = ctx;
-
-    xTaskCreatePinnedToCore(bt_init_task, "btInitTask", ESP_TASK_BT_INIT_STACK, NULL, ESP_TASK_BT_INIT_PRIO, NULL, 0);
-
-    return ESP_OK;
-}
 #endif
 #endif

+ 7 - 5
components/bt/component.mk

@@ -28,7 +28,7 @@ COMPONENT_ADD_INCLUDEDIRS :=	bluedroid/bta/include			\
 				bluedroid/include			\
 				bluedroid/include			\
 				include	
 				include	
 
 
-CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses -I./include
+CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses
 
 
 LIBS := btdm_app
 LIBS := btdm_app
 
 
@@ -36,10 +36,6 @@ COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \
                            $(addprefix -l,$(LIBS)) \
                            $(addprefix -l,$(LIBS)) \
                           $(LINKER_SCRIPTS)
                           $(LINKER_SCRIPTS)
 
 
-
-ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS))
-$(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
-
 COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 			bluedroid/bta/gatt			\
 			bluedroid/bta/gatt			\
 			bluedroid/bta/hh			\
 			bluedroid/bta/hh			\
@@ -76,3 +72,9 @@ COMPONENT_SRCDIRS := 	bluedroid/bta/dm			\
 			.
 			.
 
 
 include $(IDF_PATH)/make/component_common.mk
 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 SubmoduleRequiredForFiles,$(ALL_LIB_FILES)))

+ 11 - 8
components/bt/include/bt.h

@@ -15,7 +15,7 @@
 #ifndef __BT_H__
 #ifndef __BT_H__
 #define __BT_H__
 #define __BT_H__
 
 
-#include "freertos/FreeRTOS.h"
+#include <stdint.h>
 #include "esp_err.h"
 #include "esp_err.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -23,11 +23,14 @@ extern "C" {
 #endif
 #endif
 
 
 
 
-typedef void (* bt_app_startup_cb_t)(void *param);
-
-esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx);
+/**
+ * @brief  Initialize BT controller
+ *
+ * This function should be called only once, before any other BT functions are called.
+ */
+void bt_controller_init();
 
 
-/* @breif: vhci_host_callback
+/** @brief: vhci_host_callback
  *  used for vhci call host function to notify what host need to do
  *  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_send_available: notify host can send packet to controller
@@ -39,20 +42,20 @@ typedef struct vhci_host_callback {
     int (*notify_host_recv)(uint8_t *data, uint16_t len);
     int (*notify_host_recv)(uint8_t *data, uint16_t len);
 } vhci_host_callback_t;
 } vhci_host_callback_t;
 
 
-/* @breif: API_vhci_host_check_send_available
+/** @brief: API_vhci_host_check_send_available
  *  used for check actively if the host can send packet to controller or not.
  *  used for check actively if the host can send packet to controller or not.
  *  return true for ready to send, false means cannot send packet
  *  return true for ready to send, false means cannot send packet
  */
  */
 bool API_vhci_host_check_send_available(void);
 bool API_vhci_host_check_send_available(void);
 
 
-/* @breif: API_vhci_host_send_packet 
+/** @brief: API_vhci_host_send_packet
  * host send packet to controller
  * host send packet to controller
  * param data is the packet point, the param len is the packet length
  * param data is the packet point, the param len is the packet length
  * return void
  * return void
  */
  */
 void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
 void API_vhci_host_send_packet(uint8_t *data, uint16_t len);
 
 
-/* @breif: API_vhci_host_register_callback
+/** @brief: API_vhci_host_register_callback
  * register the vhci referece callback, the call back
  * register the vhci referece callback, the call back
  * struct defined by vhci_host_callback structure.
  * struct defined by vhci_host_callback structure.
  * param is the vhci_host_callback type variable
  * param is the vhci_host_callback type variable

+ 1 - 1
components/bt/lib

@@ -1 +1 @@
-Subproject commit 6c9a6de656262113a0aab63907d6871a64e00fae
+Subproject commit bcbc35215c6d87279da4b87a74d3360c537d6724

+ 31 - 18
components/driver/gpio.c

@@ -90,7 +90,6 @@ const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT] = {
     GPIO_PIN_REG_39
     GPIO_PIN_REG_39
 };
 };
 
 
-#define IS_VALID_GPIO(gpio_num)  ( (gpio_num < GPIO_PIN_COUNT && GPIO_PIN_MUX_REG[gpio_num] != 0))
 static int is_valid_gpio(int gpio_num)
 static int is_valid_gpio(int gpio_num)
 {
 {
     if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
     if(gpio_num >= GPIO_PIN_COUNT || GPIO_PIN_MUX_REG[gpio_num] == 0) {
@@ -102,8 +101,9 @@ static int is_valid_gpio(int gpio_num)
 
 
 esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(intr_type >= GPIO_INTR_MAX) {
     if(intr_type >= GPIO_INTR_MAX) {
         GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type);
         GPIO_ERROR("Unknown GPIO intr:%u\n",intr_type);
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
@@ -114,8 +114,9 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 
 
 esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(xPortGetCoreID() == 0) {
     if(xPortGetCoreID() == 0) {
         GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA;     //enable pro cpu intr
         GPIO.pin[gpio_num].int_ena = GPIO_PRO_CPU_INTR_ENA;     //enable pro cpu intr
     } else {
     } else {
@@ -126,16 +127,18 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num)
 
 
 esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
 esp_err_t gpio_intr_disable(gpio_num_t gpio_num)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     GPIO.pin[gpio_num].int_ena = 0;                             //disable GPIO intr
     GPIO.pin[gpio_num].int_ena = 0;                             //disable GPIO intr
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
 static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
 static esp_err_t gpio_output_disable(gpio_num_t gpio_num)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num < 32) {
     if(gpio_num < 32) {
         GPIO.enable_w1tc = (0x1 << gpio_num);
         GPIO.enable_w1tc = (0x1 << gpio_num);
     } else {
     } else {
@@ -150,8 +153,9 @@ static esp_err_t gpio_output_enable(gpio_num_t gpio_num)
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
     }
     }
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num < 32) {
     if(gpio_num < 32) {
         GPIO.enable_w1ts = (0x1 << gpio_num);
         GPIO.enable_w1ts = (0x1 << gpio_num);
     } else {
     } else {
@@ -162,18 +166,21 @@ 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)
 esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level)
 {
 {
-    if(!IS_VALID_GPIO(gpio_num))
+    if(!GPIO_IS_VALID_GPIO(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(level) {
     if(level) {
-        if(gpio_num < 32)
+        if(gpio_num < 32) {
             GPIO.out_w1ts = (1 << gpio_num);
             GPIO.out_w1ts = (1 << gpio_num);
-        else
+        } else {
             GPIO.out1_w1ts.data = (1 << (gpio_num - 32));
             GPIO.out1_w1ts.data = (1 << (gpio_num - 32));
+        }
     } else {
     } else {
-        if(gpio_num < 32)
+        if(gpio_num < 32) {
             GPIO.out_w1tc = (1 << gpio_num);
             GPIO.out_w1tc = (1 << gpio_num);
-        else
+        } else {
             GPIO.out1_w1tc.data = (1 << (gpio_num - 32));
             GPIO.out1_w1tc.data = (1 << (gpio_num - 32));
+        }
     }
     }
     return ESP_OK;
     return ESP_OK;
 }
 }
@@ -189,8 +196,9 @@ 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)
 esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     esp_err_t ret = ESP_OK;
     esp_err_t ret = ESP_OK;
     switch(pull) {
     switch(pull) {
         case GPIO_PULLUP_ONLY:
         case GPIO_PULLUP_ONLY:
@@ -219,8 +227,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)
 esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
     if(gpio_num >= 34 && (mode & (GPIO_MODE_DEF_OUTPUT))) {
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         GPIO_ERROR("io_num=%d can only be input\n",gpio_num);
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
@@ -290,7 +299,8 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
                 gpio_output_enable(io_num);
                 gpio_output_enable(io_num);
             } else {
             } else {
                 gpio_output_disable(io_num);
                 gpio_output_disable(io_num);
-            }GPIO_INFO("|");
+            }
+            GPIO_INFO("|");
             if(pGPIOConfig->pull_up_en) {
             if(pGPIOConfig->pull_up_en) {
                 GPIO_INFO("PU ");
                 GPIO_INFO("PU ");
                 PIN_PULLUP_EN(io_reg);
                 PIN_PULLUP_EN(io_reg);
@@ -310,7 +320,7 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig)
             } else {
             } else {
                 gpio_intr_disable(io_num);
                 gpio_intr_disable(io_num);
             }
             }
-            PIN_FUNC_SELECT(io_reg, GPIO_FUNC_SEL); /*function number 2 is GPIO_FUNC for each pin */
+            PIN_FUNC_SELECT(io_reg, PIN_FUNC_GPIO); /*function number 2 is GPIO_FUNC for each pin */
         } else if(bit_valid && (io_reg == 0)) {
         } else if(bit_valid && (io_reg == 0)) {
             GPIO_WARNING("io_num=%d does not exist\n",io_num);
             GPIO_WARNING("io_num=%d does not exist\n",io_num);
         }
         }
@@ -321,8 +331,9 @@ 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)
 esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg)
 {
 {
-    if(fn == NULL)
+    if(fn == NULL) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     ESP_INTR_DISABLE(gpio_intr_num);
     ESP_INTR_DISABLE(gpio_intr_num);
     intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
     intr_matrix_set(xPortGetCoreID(), ETS_GPIO_INTR_SOURCE, gpio_intr_num);
     xt_set_interrupt_handler(gpio_intr_num, fn, arg);
     xt_set_interrupt_handler(gpio_intr_num, fn, arg);
@@ -333,8 +344,9 @@ 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*/
 /*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)
 esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     esp_err_t ret = ESP_OK;
     esp_err_t ret = ESP_OK;
     if((intr_type == GPIO_INTR_LOW_LEVEL) || (intr_type == GPIO_INTR_HIGH_LEVEL)) {
     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].int_type = intr_type;
@@ -348,8 +360,9 @@ 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)
 esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num)
 {
 {
-    if(!is_valid_gpio(gpio_num))
+    if(!is_valid_gpio(gpio_num)) {
         return ESP_ERR_INVALID_ARG;
         return ESP_ERR_INVALID_ARG;
+    }
     GPIO.pin[gpio_num].wakeup_enable = 0;
     GPIO.pin[gpio_num].wakeup_enable = 0;
     return ESP_OK;
     return ESP_OK;
 }
 }

+ 3 - 3
components/driver/include/driver/gpio.h

@@ -14,7 +14,7 @@
 
 
 #ifndef _DRIVER_GPIO_H_
 #ifndef _DRIVER_GPIO_H_
 #define _DRIVER_GPIO_H_
 #define _DRIVER_GPIO_H_
-
+#include "esp_err.h"
 #include <esp_types.h>
 #include <esp_types.h>
 #include "soc/gpio_reg.h"
 #include "soc/gpio_reg.h"
 #include "soc/gpio_struct.h"
 #include "soc/gpio_struct.h"
@@ -65,8 +65,6 @@ extern "C" {
 #define GPIO_SEL_38             ((uint64_t)(((uint64_t)1)<<38))  /* Pin 38 selected */
 #define GPIO_SEL_38             ((uint64_t)(((uint64_t)1)<<38))  /* Pin 38 selected */
 #define GPIO_SEL_39             ((uint64_t)(((uint64_t)1)<<39))  /* Pin 39 selected */
 #define GPIO_SEL_39             ((uint64_t)(((uint64_t)1)<<39))  /* Pin 39 selected */
 
 
-#define GPIO_FUNC_SEL           2
-
 #define GPIO_PIN_REG_0          PERIPHS_IO_MUX_GPIO0_U
 #define GPIO_PIN_REG_0          PERIPHS_IO_MUX_GPIO0_U
 #define GPIO_PIN_REG_1          PERIPHS_IO_MUX_U0TXD_U
 #define GPIO_PIN_REG_1          PERIPHS_IO_MUX_U0TXD_U
 #define GPIO_PIN_REG_2          PERIPHS_IO_MUX_GPIO2_U
 #define GPIO_PIN_REG_2          PERIPHS_IO_MUX_GPIO2_U
@@ -115,6 +113,8 @@ extern "C" {
 
 
 #define GPIO_PIN_COUNT              40
 #define GPIO_PIN_COUNT              40
 extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT];
 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
 
 
 typedef enum {
 typedef enum {
     GPIO_NUM_0 = 0,
     GPIO_NUM_0 = 0,

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

@@ -0,0 +1,406 @@
+// 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_LEDC_H_
+#define _DRIVER_LEDC_H_
+#include "esp_err.h"
+#include "soc/soc.h"
+#include "soc/ledc_reg.h"
+#include "soc/ledc_reg.h"
+#include "soc/ledc_struct.h"
+#include "driver/gpio.h"
+#include "driver/periph_ctrl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LEDC_APB_CLK_HZ (APB_CLK_FREQ)
+#define LEDC_REF_CLK_HZ (1*1000000)
+
+typedef enum {
+    LEDC_HIGH_SPEED_MODE = 0, /*LEDC high speed speed_mode */
+    //in this version, we only support high speed speed_mode. We will access low speed speed_mode later
+    //LEDC_LOW_SPEED_MODE,    /*LEDC low speed speed_mode */
+    LEDC_SPEED_MODE_MAX,
+} ledc_mode_t;
+
+typedef enum {
+    LEDC_INTR_DISABLE = 0,    /*Disable LEDC interrupt */
+    LEDC_INTR_FADE_END,       /*Enable LEDC interrupt */
+} ledc_intr_type_t;
+
+typedef enum {
+    LEDC_DUTY_DIR_DECREASE = 0,    /*LEDC duty decrease direction */
+    LEDC_DUTY_DIR_INCREASE = 1,    /*LEDC duty increase direction */
+} ledc_duty_direction_t;
+
+typedef enum  {
+    LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */
+    LEDC_APB_CLK,      /*LEDC timer clock divided from APB clock(80Mhz)*/
+} ledc_clk_src_t;
+
+typedef enum {
+    LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */
+    LEDC_TIMER_1,     /*LEDC source timer TIMER1 */
+    LEDC_TIMER_2,     /*LEDC source timer TIMER2 */
+    LEDC_TIMER_3,     /*LEDC source timer TIMER3 */
+} ledc_timer_t;
+
+typedef enum {
+    LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */
+    LEDC_CHANNEL_1,     /*LEDC channel 1 */
+    LEDC_CHANNEL_2,     /*LEDC channel 2 */
+    LEDC_CHANNEL_3,     /*LEDC channel 3 */
+    LEDC_CHANNEL_4,     /*LEDC channel 4 */
+    LEDC_CHANNEL_5,     /*LEDC channel 5 */
+    LEDC_CHANNEL_6,     /*LEDC channel 6 */
+    LEDC_CHANNEL_7,     /*LEDC channel 7 */
+} ledc_channel_t;
+
+typedef enum {
+    LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */
+    LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */
+    LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */
+    LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */
+    LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */
+    LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */
+} ledc_timer_bit_t;
+
+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*/
+    ledc_channel_t channel;         /*LEDC channel(0 - 7)*/
+    ledc_intr_type_t intr_type;     /*configure interrupt, Fade interrupt enable  or Fade interrupt disable*/
+    ledc_timer_t timer_sel;         /*Select the timer source of channel (0 - 3)*/
+    uint32_t duty;                  /*LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */
+} ledc_channel_config_t;
+
+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*/
+    ledc_timer_t  timer_num;        /*The timer source of channel (0 - 3)*/
+    uint32_t freq_hz;               /*LEDC timer frequency(Hz)*/
+} ledc_timer_config_t;
+
+
+/**
+ * @brief      LEDC channel configuration
+ *
+ * User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth
+ *
+ * @param[in]  ledc_channel_config_t
+ *             ledc_channel_config_t.speed_mode     : LEDC speed speed_mode
+ *             ledc_channel_config_t.gpio_num       : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16
+ *             ledc_channel_config_t.channel        : LEDC channel(0 - 7)
+ *             ledc_channel_config_t.intr_type      : configure interrupt, Fade interrupt enable  or Fade interrupt disable
+ *             ledc_channel_config_t.timer_sel      : Select the timer source of channel (0 - 3), high speed channel must bind with high speed timer.
+ *             ledc_channel_config_t.duty           : LEDC channel duty, the duty range is [0, (2**timer_bit_num) - 1],
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *
+ */
+esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf);
+
+/**
+ * @brief      LEDC timer configuration
+ *
+ * User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num
+ *
+ * @param[in]  ledc_timer_config_t
+ *             ledc_timer_config_t.speed_mode     : LEDC speed speed_mode
+ *             ledc_timer_config_t.timer_num      : Select the timer source of channel (0 - 3)
+ *             ledc_timer_config_t.freq_hz        : LEDC channel frequency(Hz),
+ *             ledc_timer_config_t.bit_num        : LEDC channel duty depth
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
+ *
+ */
+esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf);
+
+/**
+ * @brief      LEDC update channel parameters
+ *
+ * Call this function to activate the LEDC updated parameters.
+ * After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings.
+ *
+ * @param[in]  speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel    : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *
+ */
+esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
+
+/**
+ * @brief   LEDC stop
+ *
+ * Disable LEDC output, and set idle level
+ *
+ * @param[in]  speed_mode   : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel      : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ */
+esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level);
+
+/**
+ * @brief      LEDC set channel frequency(Hz)
+ *
+ * Set LEDC frequency(Hz)
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_num   : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ * @param[in]  freq_hz     : set the LEDC frequency
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num.
+ */
+esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz);
+
+/**
+ * @brief      LEDC get channel frequency(Hz)
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_num   : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ * @return    0      :  error
+ *            others :  current LEDC frequency
+ *
+ */
+uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num);
+
+/**
+ * @brief      LEDC set duty
+ *
+ * Set LEDC duty, After the function calls the ledc_update_duty function, the function can take effect.
+ *
+ * @param[in]  speed_mode  : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel     : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @param[in]  duty        : set the LEDC duty, the duty range is [0, (2**bit_num) - 1]
+ *
+ * @return     ESP_OK:  success
+ *             ESP_ERR_INVALID_ARG: parameter error
+ */
+esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty);
+
+/**
+ * @brief      LEDC get duty
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel : LEDC channel(0-7), select from ledc_channel_t
+ *
+ *
+ * @return     -1: parameter error
+ *             other value: current LEDC duty
+ *
+ */
+int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
+
+/**
+ * @brief      LEDC set gradient
+ *
+ * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect.
+ *
+ * @param[in]  speed_mode           : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel              : LEDC channel(0-7), select from ledc_channel_t
+ *
+ * @param[in]  duty                 : set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1]
+ *
+ * @param[in]  gradule_direction    : set the direction of the gradient
+ *
+ * @param[in]  step_num             : set the number of the gradient
+ *
+ * @param[in]  duty_cyle_num        : set how many LEDC tick each time the gradient lasts
+ *
+ * @param[in]  duty_scale           : set gradient change amplitude
+ *
+ * @return     ESP_OK               : success
+ *             ESP_ERR_INVALID_ARG  : parameter error
+ */
+esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction,
+                        uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale);
+
+/**
+ * @brief   register LEDC interrupt handler, the handler is an ISR.
+ *          The 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.
+ *          TODO: to move INUM options to menu_config
+ * @param[in]   uint32_t ledc_intr_num    : LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details
+ * @param[in]   void (* fn)(void* )       : interrupt handler function.
+ *                                          Note that the handler function MUST be defined with attribution of "IRAM_ATTR".
+ * @param[in]   void * arg                : parameter for handler function
+ *
+ * @return      ESP_OK                    : success ;
+ *              ESP_ERR_INVALID_ARG       : function ptr error.
+ */
+esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg);
+
+/**
+ * @brief      configure LEDC settings
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : timer index(0-3), there are 4 timers in LEDC module
+ *
+ * @param[in]  div_num       : timer clock divide number, the timer clock is divided from the selected clock source
+ *
+ * @param[in]  bit_num       : the count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1)
+ *
+ * @param[in]  clk_src       : select LEDC source clock.
+ *
+ * @return     -1: parameter error
+ *             other value: current LEDC duty
+ *
+ */
+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);
+
+/**
+ * @brief      reset LEDC timer
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      pause LEDC timer counter
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      pause LEDC timer resume
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  timer_sel     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel);
+
+/**
+ * @brief      bind LEDC channel with the selected timer
+ *
+ * @param[in]  speed_mode    : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version
+ *
+ * @param[in]  channel       : LEDC channel index(0-7), select from ledc_channel_t
+ *
+ * @param[in]  timer_idx     : LEDC timer index(0-3), select from ledc_timer_t
+ *
+ *
+ * @return     ESP_ERR_INVALID_ARG: parameter error
+ *             ESP_OK: success
+ *
+ */
+esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx);
+
+/***************************EXAMPLE**********************************
+ *
+ *
+ * ----------------EXAMPLE OF LEDC SETTING ---------------------
+ *     //1. enable LEDC
+ *     periph_module_enable(PERIPH_LEDC_MODULE);                //enable LEDC module, or you can not set any register of it.
+ *
+ *     //2. set LEDC timer
+ *     ledc_timer_config_t timer_conf = {
+ *         .bit_num = LEDC_TIMER_12_BIT,                        //set timer counter bit number
+ *         .freq_hz = 1000,                                     //set frequency of pwm, here, 1000Hz
+ *         .speed_mode = LEDC_HIGH_SPEED_MODE                   //timer mode,
+ *         .timer_num = LEDC_TIMER_0,                           //timer number
+ *     };
+ *     ledc_timer_config(&timer_conf);                          //setup timer.
+ *
+ *     //3. set LEDC channel
+ *     ledc_channel_config_t ledc_conf = {
+ *         .channel = LEDC_CHANNEL_0;                           //set LEDC channel 0
+ *         .duty = 1000;                                        //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1)
+ *         .gpio_num = 16;                                      //GPIO number
+ *         .intr_type = LEDC_INTR_FADE_END;                     //GPIO INTR TYPE, as an example, we enable fade_end interrupt here.
+ *         .speed_mode = LEDC_HIGH_SPEED_MODE;                  //set LEDC mode, from ledc_mode_t
+ *         .timer_sel = LEDC_TIMER_0;                            //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same
+ *     }
+ *     ledc_channel_config(&ledc_conf);                                 //setup the configuration
+ *
+ * ----------------EXAMPLE OF SETTING DUTY --- -----------------
+ *     uint32_t ledc_channel = LEDC_CHANNEL_0;                  //LEDC channel(0-73)
+ *     uint32_t duty = 2000;                                    //duty range is 0 ~ ((2**bit_num)-1)
+ *     LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty.
+ *     ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel);    //after set duty, we need to call ledc_update_duty to update the settings.
+ *
+ *
+ * ----------------EXAMPLE OF LEDC INTERRUPT ------------------
+ *     //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here.
+ *     ledc_isr_register(18, ledc_isr_handler, NULL);           //hook the isr handler for LEDC interrupt
+ *                                                              //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system.
+ *                                                              //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source.
+ *                                                              //NOTE2:do not pick the INUM that already occupied by the system.
+ *                                                              //NOTE3:refer to soc.h to check which INUMs that can be used.
+ * ----------------EXAMPLE OF INTERRUPT HANDLER ---------------
+ * #include "esp_attr.h"
+ * void IRAM_ATTR ledc_isr_handler(void* arg)                   //we should add 'IRAM_ATTR' attribution when we declare the isr function
+ * {
+ *    uint32_t intr_st = LEDC.int_st.val;                       //read LEDC interrupt status.
+ *
+ *    //you will find which channels have triggered fade_end interrupt here,
+ *    //then, you can post some event to RTOS queue to process the event.
+ *    //later we will add a queue in the driver code.
+ *
+ *    LEDC.int_clr.val = intr_st;                               //clear LEDC interrupt status.
+ * }
+ *
+ *
+ *--------------------------END OF EXAMPLE --------------------------
+ */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_LEDC_H_ */

+ 70 - 0
components/driver/include/driver/periph_ctrl.h

@@ -0,0 +1,70 @@
+// 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_PERIPH_CTRL_H_
+#define _DRIVER_PERIPH_CTRL_H_
+#include "esp_err.h"
+#include "soc/soc.h"
+#include "soc/dport_reg.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    PERIPH_LEDC_MODULE = 0,
+    PERIPH_UART0_MODULE,
+    PERIPH_UART1_MODULE,
+    PERIPH_UART2_MODULE,
+    PERIPH_I2C0_MODULE,
+    PERIPH_I2C1_MODULE,
+    PERIPH_I2S0_MODULE,
+    PERIPH_I2S1_MODULE,
+    PERIPH_TIMG0_MODULE,
+    PERIPH_TIMG1_MODULE,
+    PERIPH_PWM0_MODULE,
+    PERIPH_PWM1_MODULE,
+    PERIPH_PWM2_MODULE,
+    PERIPH_PWM3_MODULE,
+    PERIPH_UHCI0_MODULE,
+    PERIPH_UHCI1_MODULE,
+} periph_module_t;
+
+/**
+ * @brief      enable peripheral module
+ *
+ * @param[in]  periph    :  Peripheral module name
+ *
+ *
+ * @return     NULL
+ *
+ */
+void periph_module_enable(periph_module_t periph);
+
+/**
+ * @brief      disable peripheral module
+ *
+ * @param[in]  periph    :  Peripheral module name
+ *
+ *
+ * @return     NULL
+ *
+ */
+void periph_module_disable(periph_module_t periph);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DRIVER_PERIPH_CTRL_H_ */

+ 432 - 0
components/driver/ledc.c

@@ -0,0 +1,432 @@
+// 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 <esp_types.h>
+#include "esp_intr.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "soc/gpio_sig_map.h"
+#include "driver/ledc.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 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;
+}
+
+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;
+    }
+    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;
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.bit_num = bit_num;
+    if(speed_mode != LEDC_HIGH_SPEED_MODE) {
+        LEDC.timer_group[speed_mode].timer[timer_sel].conf.low_speed_update = 1;
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+static esp_err_t ledc_duty_config(ledc_mode_t speed_mode, uint32_t channel_num, uint32_t hpoint_val, uint32_t duty_val,
+    uint32_t duty_direction, uint32_t duty_num, uint32_t duty_cycle, uint32_t duty_scale)
+{
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel_num].hpoint.hpoint = hpoint_val;
+    LEDC.channel_group[speed_mode].channel[channel_num].duty.duty = duty_val;
+    LEDC.channel_group[speed_mode].channel[channel_num].conf1.val = ((duty_direction & LEDC_DUTY_INC_HSCH0_V) << LEDC_DUTY_INC_HSCH0_S) |
+                                                                    ((duty_num & LEDC_DUTY_NUM_HSCH0_V) << LEDC_DUTY_NUM_HSCH0_S) |
+                                                                    ((duty_cycle & LEDC_DUTY_CYCLE_HSCH0_V) << LEDC_DUTY_CYCLE_HSCH0_S) |
+                                                                    ((duty_scale & LEDC_DUTY_SCALE_HSCH0_V) << LEDC_DUTY_SCALE_HSCH0_S);
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.channel_group[speed_mode].channel[channel].conf0.timer_sel = timer_idx;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    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;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 1;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    LEDC.timer_group[speed_mode].timer[timer_sel].conf.pause = 0;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    uint32_t value;
+    uint32_t intr_type = type;
+    portENTER_CRITICAL(&ledc_spinlock);
+    value = LEDC.int_ena.val;
+    if(intr_type == LEDC_INTR_FADE_END) {
+        LEDC.int_ena.val = value | BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel);
+    } else {
+        LEDC.int_ena.val = (value & (~(BIT(LEDC_DUTY_CHNG_END_HSCH0_INT_ENA_S + channel))));
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg)
+{
+    if(fn == NULL) {
+        return 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);
+    xt_set_interrupt_handler(ledc_intr_num, fn, arg);
+    ESP_INTR_ENABLE(ledc_intr_num);
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf)
+{
+    int freq_hz = timer_conf->freq_hz;
+    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;
+    }
+    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);
+        return ESP_ERR_INVALID_ARG;
+    }
+    if(timer_num > LEDC_TIMER_3) {
+        LEDC_ERROR("Time Select %u\n", timer_num);
+        return ESP_ERR_INVALID_ARG;
+    }
+    esp_err_t ret = ESP_OK;
+    uint32_t precision = (0x1 << bit_num);  //2**depth
+    uint64_t div_param = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision; //8bit fragment
+    int timer_clk_src;
+    /*Fail ,because the div_num overflow or too small*/
+    if(div_param <= 256 || div_param > LEDC_DIV_NUM_HSTIMER0_V) { //REF TICK
+        /*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);
+            ret = ESP_FAIL;
+        }
+        timer_clk_src = LEDC_REF_TICK;
+    } else { //APB TICK
+        timer_clk_src = LEDC_APB_CLK;
+    }
+    /*set timer parameters*/
+    /*timer settings decide the clk of counter and the period of PWM*/
+    ledc_timer_set(speed_mode, timer_num, div_param, bit_num, timer_clk_src);
+    /*   reset timer.*/
+    ledc_timer_rst(speed_mode, timer_num);
+    return ret;
+}
+
+esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf)
+{
+    uint32_t speed_mode = ledc_conf->speed_mode;
+    uint32_t gpio_num = ledc_conf->gpio_num;
+    uint32_t ledc_channel = ledc_conf->channel;
+    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;
+    }
+    esp_err_t ret = ESP_OK;
+    /*set channel parameters*/
+    /*   channel parameters decide how the waveform looks like in one period*/
+    /*   set channel duty, duty range is (0 ~ ((2 ** bit_num) - 1))*/
+    ledc_set_duty(speed_mode, ledc_channel, duty);
+    /*update duty settings*/
+    ledc_update_duty(speed_mode, ledc_channel);
+    /*bind the channel with the timer*/
+    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",
+        ledc_channel, gpio_num, duty, timer_select
+    );
+    /*set LEDC signal in gpio matrix*/
+    PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[gpio_num], PIN_FUNC_GPIO);
+    gpio_set_direction(gpio_num, GPIO_MODE_OUTPUT);
+    gpio_matrix_out(gpio_num, LEDC_HS_SIG_OUT0_IDX + ledc_channel, 0, 0);
+    return ret;
+}
+
+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;
+    }
+    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;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+
+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;
+    }
+    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;
+    LEDC.channel_group[speed_mode].channel[channel].conf1.duty_start = 0;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ESP_OK;
+}
+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;
+    }
+    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);
+        return ESP_ERR_INVALID_ARG;
+    }
+    ledc_duty_config(speed_mode,
+                     channel,        //uint32_t chan_num,
+                     0,              //uint32_t hpoint_val,
+                     duty << 4,      //uint32_t duty_val,the least 4 bits are decimal part
+                     fade_direction, //uint32_t increase,
+                     step_num,       //uint32_t duty_num,
+                     duty_cyle_num,  //uint32_t duty_cycle,
+                     duty_scale      //uint32_t duty_scale
+                     );
+    return ESP_OK;
+}
+
+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_duty_config(speed_mode,
+                     channel,         //uint32_t chan_num,
+                     0,               //uint32_t hpoint_val,
+                     duty << 4,       //uint32_t duty_val,the least 4 bits are decimal part
+                     1,               //uint32_t increase,
+                     1,               //uint32_t duty_num,
+                     1,               //uint32_t duty_cycle,
+                     0                //uint32_t duty_scale
+                     );
+    return ESP_OK;
+}
+
+int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return -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;
+    }
+    portENTER_CRITICAL(&ledc_spinlock);
+    esp_err_t ret = ESP_OK;
+    uint32_t div_num = 0;
+    uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
+    uint32_t timer_source_clk = LEDC.timer_group[speed_mode].timer[timer_num].conf.tick_sel;
+    uint32_t precision = (0x1 << bit_num);
+    if(timer_source_clk == LEDC_APB_CLK) {
+        div_num = ((uint64_t) LEDC_APB_CLK_HZ << 8) / freq_hz / precision;
+    } else {
+        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);
+        ret = ESP_FAIL;
+    }
+    LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num = div_num;
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return ret;
+}
+
+uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num)
+{
+    if(!ledc_is_valid_mode(speed_mode)) {
+        return 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;
+    uint32_t bit_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.bit_num;
+    uint32_t div_num = LEDC.timer_group[speed_mode].timer[timer_num].conf.div_num;
+    uint32_t precision = (0x1 << bit_num);
+    if(timer_source_clk == LEDC_APB_CLK) {
+        freq = ((uint64_t) LEDC_APB_CLK_HZ << 8) / precision / div_num;
+    } else {
+        freq = ((uint64_t) LEDC_REF_CLK_HZ << 8) / precision / div_num;
+    }
+    portEXIT_CRITICAL(&ledc_spinlock);
+    return freq;
+}

+ 170 - 0
components/driver/periph_ctrl.c

@@ -0,0 +1,170 @@
+// 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 <esp_types.h>
+#include "esp_intr.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/semphr.h"
+#include "freertos/xtensa_api.h"
+#include "soc/dport_reg.h"
+#include "driver/periph_ctrl.h"
+
+static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
+
+void periph_module_enable(periph_module_t periph)
+{
+    portENTER_CRITICAL(&periph_spinlock);
+    switch(periph) {
+        case PERIPH_LEDC_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
+            break;
+        case PERIPH_UART0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
+            break;
+        case PERIPH_UART1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
+            break;
+        case PERIPH_UART2_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
+            break;
+        case PERIPH_I2C0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
+            break;
+        case PERIPH_I2C1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
+            break;
+        case PERIPH_I2S0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+            break;
+        case PERIPH_I2S1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
+            break;
+        case PERIPH_TIMG0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
+            break;
+        case PERIPH_TIMG1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
+            break;
+        case PERIPH_PWM0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
+            break;
+        case PERIPH_PWM1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
+            break;
+        case PERIPH_PWM2_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
+            break;
+        case PERIPH_PWM3_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
+            break;
+        case PERIPH_UHCI0_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
+            break;
+        case PERIPH_UHCI1_MODULE:
+            SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
+            break;
+        default:
+            break;
+    }
+    portEXIT_CRITICAL(&periph_spinlock);
+}
+
+void periph_module_disable(periph_module_t periph)
+{
+    portENTER_CRITICAL(&periph_spinlock);
+    switch(periph) {
+        case PERIPH_LEDC_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_LEDC_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_LEDC_RST);
+            break;
+        case PERIPH_UART0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART_RST);
+            break;
+        case PERIPH_UART1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART1_RST);
+            break;
+        case PERIPH_UART2_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UART2_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UART2_RST);
+            break;
+        case PERIPH_I2C0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT0_RST);
+            break;
+        case PERIPH_I2C1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2C_EXT0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2C_EXT1_RST);
+            break;
+        case PERIPH_I2S0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
+            break;
+        case PERIPH_I2S1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
+            break;
+        case PERIPH_TIMG0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP_RST);
+            break;
+        case PERIPH_TIMG1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_TIMERGROUP1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_TIMERGROUP1_RST);
+            break;
+        case PERIPH_PWM0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM0_RST);
+            break;
+        case PERIPH_PWM1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM1_RST);
+            break;
+        case PERIPH_PWM2_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM2_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM2_RST);
+            break;
+        case PERIPH_PWM3_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_PWM3_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_PWM3_RST);
+            break;
+        case PERIPH_UHCI0_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI0_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI0_RST);
+            break;
+        case PERIPH_UHCI1_MODULE:
+            CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_UHCI1_CLK_EN);
+            SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_UHCI1_RST);
+            break;
+        default:
+            break;
+    }
+    portEXIT_CRITICAL(&periph_spinlock);
+}

+ 48 - 29
components/esp32/Kconfig

@@ -63,6 +63,12 @@ config MEMMAP_TRACEMEM
         of memory that can't be used for general purposes anymore. Disable this if you do not know
         of memory that can't be used for general purposes anymore. Disable this if you do not know
         what this is.
         what this is.
 
 
+# Memory to reverse for trace, used in linker script
+config TRACEMEM_RESERVE_DRAM
+    hex
+    default 0x8000 if MEMMAP_TRACEMEM
+    default 0x0
+
 config MEMMAP_SPISRAM
 config MEMMAP_SPISRAM
     bool "Use external SPI SRAM chip as main memory"
     bool "Use external SPI SRAM chip as main memory"
     default "n"
     default "n"
@@ -78,47 +84,60 @@ config WIFI_ENABLED
     help
     help
         This compiles in the low-level WiFi stack.
         This compiles in the low-level WiFi stack.
 
 
-		Temporarily, this option is not compatible with BT stack.
-
-config WIFI_AUTO_STARTUP
-    bool "Start WiFi with system startup"
-    default "y"
-    depends on WIFI_ENABLED
-    help
-        By default, WiFi is started with system startup, you can turn off this
-        feature and start by yourself.
-
-config WIFI_AUTO_CONNECT
-    bool "Enable auto connect"
-    default "y"
-    depends on WIFI_ENABLED
-    help
-        If station is enabled, and station config is set, this will enable WiFi
-        station auto connect when WiFi startup.
+        Temporarily, this option is not compatible with BT stack.
 
 
 config SYSTEM_EVENT_QUEUE_SIZE
 config SYSTEM_EVENT_QUEUE_SIZE
-    int "system event queue size"
+    int "System event queue size"
     default 32
     default 32
-    depends on WIFI_ENABLED
     help
     help
         Config system event queue size in different application.
         Config system event queue size in different application.
 
 
 config SYSTEM_EVENT_TASK_STACK_SIZE
 config SYSTEM_EVENT_TASK_STACK_SIZE
-    int "system event task stack size"
+    int "Event loop task stack size"
     default 2048
     default 2048
-    depends on WIFI_ENABLED
+    help
+        Config system event task stack size in different application.
+
+
+config MAIN_TASK_STACK_SIZE
+    int "Main task stack size"
+    default 4096
     help
     help
         Config system event task stack size in different application.
         Config system event task stack size in different application.
 
 
 
 
 config NEWLIB_STDOUT_ADDCR
 config NEWLIB_STDOUT_ADDCR
-	bool "Standard-out output adds carriage return before newline"
-	default y
-	help
-		Most people are used to end their printf strings with a newline. If this
-		is sent as is to the serial port, most terminal programs will only move the
-		cursor one line down, not also move it to the beginning of the line. This
-		is usually done by an added CR character. Enabling this will make the
-		standard output code automatically add a CR character before a LF.
+    bool "Standard-out output adds carriage return before newline"
+    default y
+    help
+        Most people are used to end their printf strings with a newline. If this
+        is sent as is to the serial port, most terminal programs will only move the
+        cursor one line down, not also move it to the beginning of the line. This
+        is usually done by an added CR character. Enabling this will make the
+        standard output code automatically add a CR character before a LF.
+
+config ULP_COPROC_ENABLED
+    bool "Enable Ultra Low Power (ULP) Coprocessor"
+    default "n"
+    help
+        Set to 'y' if you plan to load a firmware for the coprocessor.
+
+        If this option is enabled, further coprocessor configuration will appear in the Components menu.
+
+config ULP_COPROC_RESERVE_MEM
+    int "RTC slow memory reserved for coprocessor"
+    default 512
+    range 32 8192
+    depends on ULP_COPROC_ENABLED
+    help
+        Bytes of memory to reserve for ULP coprocessor firmware & data.
+
+        Data is reserved at the beginning of RTC slow memory.
+
+# Set CONFIG_ULP_COPROC_RESERVE_MEM to 0 if ULP is disabled
+config ULP_COPROC_RESERVE_MEM
+    int
+    default 0
+    depends on !ULP_COPROC_ENABLED
 
 
 endmenu
 endmenu

+ 14 - 17
components/esp32/component.mk

@@ -10,23 +10,9 @@
 
 
 COMPONENT_SRCDIRS := . hwcrypto
 COMPONENT_SRCDIRS := . hwcrypto
 
 
-LIBS := crypto core net80211 phy rtc pp wpa wps
-
-ifeq ($(CONFIG_MEMMAP_BT),y)
-    ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
-        LINKER_SCRIPTS = -T esp32.bt.trace.ld
-    else
-        LINKER_SCRIPTS = -T esp32.bt.ld
-    endif
-else
-    ifeq ($(CONFIG_MEMMAP_TRACEMEM),y)
-        LINKER_SCRIPTS = -T esp32.trace.ld
-    else
-        LINKER_SCRIPTS = -T esp32.ld
-    endif
-endif
-
-LINKER_SCRIPTS += -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
+LIBS := crypto core net80211 phy rtc pp wpa smartconfig
+
+LINKER_SCRIPTS += -T esp32_out.ld -T esp32.common.ld -T esp32.rom.ld -T esp32.peripherals.ld
 
 
 COMPONENT_ADD_LDFLAGS := -lesp32 \
 COMPONENT_ADD_LDFLAGS := -lesp32 \
                            $(abspath libhal.a) \
                            $(abspath libhal.a) \
@@ -51,3 +37,14 @@ $(eval $(call SubmoduleRequiredForFiles,$(ALL_LIB_FILES)))
 # It would be better for components to be able to expose any of these
 # It would be better for components to be able to expose any of these
 # non-standard dependencies via get_variable, but this will do for now.
 # non-standard dependencies via get_variable, but this will do for now.
 $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
 $(COMPONENT_LIBRARY): $(ALL_LIB_FILES)
+
+# Preprocess esp32.ld linker script into esp32_out.ld
+#
+# The library doesn't really depend on esp32_out.ld, but it
+# saves us from having to add the target to a Makefile.projbuild
+$(COMPONENT_LIBRARY): esp32_out.ld
+
+esp32_out.ld: $(COMPONENT_PATH)/ld/esp32.ld ../include/sdkconfig.h
+	$(CC) -I ../include -C -P -x c -E $< -o $@
+
+COMPONENT_EXTRA_CLEAN := esp32_out.ld

+ 43 - 49
components/esp32/cpu_start.c

@@ -43,14 +43,19 @@
 #include "esp_ipc.h"
 #include "esp_ipc.h"
 #include "esp_log.h"
 #include "esp_log.h"
 
 
-static void IRAM_ATTR user_start_cpu0(void);
-static void IRAM_ATTR call_user_start_cpu1();
-static void IRAM_ATTR user_start_cpu1(void);
+void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
+void start_cpu0_default(void) IRAM_ATTR;
+#if !CONFIG_FREERTOS_UNICORE
+static void IRAM_ATTR call_start_cpu1();
+void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default")));
+void start_cpu1_default(void) IRAM_ATTR;
+static bool app_cpu_started = false;
+#endif //!CONFIG_FREERTOS_UNICORE
+
+static void do_global_ctors(void);
+static void main_task(void* args);
 extern void ets_setup_syscalls(void);
 extern void ets_setup_syscalls(void);
-extern esp_err_t app_main(void *ctx);
-#if CONFIG_BT_ENABLED
-extern void bt_app_main(void *param);
-#endif
+extern void app_main(void);
 
 
 extern int _bss_start;
 extern int _bss_start;
 extern int _bss_end;
 extern int _bss_end;
@@ -60,14 +65,13 @@ extern void (*__init_array_end)(void);
 extern volatile int port_xSchedulerRunning[2];
 extern volatile int port_xSchedulerRunning[2];
 
 
 static const char* TAG = "cpu_start";
 static const char* TAG = "cpu_start";
-static bool app_cpu_started = false;
 
 
 /*
 /*
  * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
  * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized,
  * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
  * and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
  */
  */
 
 
-void IRAM_ATTR call_user_start_cpu0()
+void IRAM_ATTR call_start_cpu0()
 {
 {
     //Kill wdt
     //Kill wdt
     REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
     REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN);
@@ -90,14 +94,14 @@ void IRAM_ATTR call_user_start_cpu0()
 
 
     ESP_EARLY_LOGI(TAG, "Pro cpu up.");
     ESP_EARLY_LOGI(TAG, "Pro cpu up.");
 
 
-#ifndef CONFIG_FREERTOS_UNICORE
-    ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_user_start_cpu1);
+#if !CONFIG_FREERTOS_UNICORE
+    ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1);
 
 
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL);
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
     SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING);
-    ets_set_appcpu_boot_addr((uint32_t)call_user_start_cpu1);
+    ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1);
 
 
     while (!app_cpu_started) {
     while (!app_cpu_started) {
         ets_delay_us(100);
         ets_delay_us(100);
@@ -107,11 +111,11 @@ void IRAM_ATTR call_user_start_cpu0()
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
     CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN);
 #endif
 #endif
     ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
     ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
-    user_start_cpu0();
+    start_cpu0();
 }
 }
 
 
-
-void IRAM_ATTR call_user_start_cpu1()
+#if !CONFIG_FREERTOS_UNICORE
+void IRAM_ATTR call_start_cpu1()
 {
 {
     asm volatile (\
     asm volatile (\
                   "wsr    %0, vecbase\n" \
                   "wsr    %0, vecbase\n" \
@@ -121,10 +125,27 @@ void IRAM_ATTR call_user_start_cpu1()
 
 
     ESP_EARLY_LOGI(TAG, "App cpu up.");
     ESP_EARLY_LOGI(TAG, "App cpu up.");
     app_cpu_started = 1;
     app_cpu_started = 1;
-    user_start_cpu1();
+    start_cpu1();
+}
+#endif //!CONFIG_FREERTOS_UNICORE
+
+void start_cpu0_default(void)
+{
+    esp_set_cpu_freq();     // set CPU frequency configured in menuconfig
+    uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
+    ets_setup_syscalls();
+    do_global_ctors();
+    esp_ipc_init();
+    spi_flash_init();
+    xTaskCreatePinnedToCore(&main_task, "main",
+            ESP_TASK_MAIN_STACK, NULL,
+            ESP_TASK_MAIN_PRIO, NULL, 0);
+    ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
+    vTaskStartScheduler();
 }
 }
 
 
-void IRAM_ATTR user_start_cpu1(void)
+#if !CONFIG_FREERTOS_UNICORE
+void start_cpu1_default(void)
 {
 {
     // Wait for FreeRTOS initialization to finish on PRO CPU
     // Wait for FreeRTOS initialization to finish on PRO CPU
     while (port_xSchedulerRunning[0] == 0) {
     while (port_xSchedulerRunning[0] == 0) {
@@ -133,46 +154,19 @@ void IRAM_ATTR user_start_cpu1(void)
     ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
     ESP_LOGI(TAG, "Starting scheduler on APP CPU.");
     xPortStartScheduler();
     xPortStartScheduler();
 }
 }
+#endif //!CONFIG_FREERTOS_UNICORE
 
 
 static void do_global_ctors(void)
 static void do_global_ctors(void)
 {
 {
     void (**p)(void);
     void (**p)(void);
-    for (p = &__init_array_start; p != &__init_array_end; ++p) {
+    for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
         (*p)();
         (*p)();
     }
     }
 }
 }
 
 
-void user_start_cpu0(void)
+static void main_task(void* args)
 {
 {
-    esp_set_cpu_freq();     // set CPU frequency configured in menuconfig
-    uart_div_modify(0, (APB_CLK_FREQ << 4) / 115200);
-    ets_setup_syscalls();
-    do_global_ctors();
-    esp_ipc_init();
-    spi_flash_init();
-
-#if CONFIG_WIFI_ENABLED
-    esp_err_t ret = nvs_flash_init(5, 3);
-    if (ret != ESP_OK) {
-        ESP_LOGE(TAG, "nvs_flash_init failed, ret=%d", ret);
-    }
-
-    system_init();
-    esp_event_init(NULL, NULL);
-    tcpip_adapter_init();
-#endif
-
-#if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP
-#include "esp_wifi.h"
-	esp_wifi_startup(app_main, NULL);
-#elif CONFIG_BT_ENABLED
-#include "bt.h"
-        esp_bt_startup(bt_app_main, NULL);
-#else
-    app_main(NULL);
-#endif
-
-    ESP_LOGI(TAG, "Starting scheduler on PRO CPU.");
-    vTaskStartScheduler();
+    app_main();
+    vTaskDelete(NULL);
 }
 }
 
 

+ 49 - 0
components/esp32/deepsleep.c

@@ -0,0 +1,49 @@
+/* Wake from deep sleep stub
+
+   See esp_deepsleep.h esp_wake_deep_sleep() comments for details.
+*/
+#include <stddef.h>
+#include <sys/lock.h>
+#include "rom/cache.h"
+#include "rom/rtc.h"
+#include "soc/rtc_cntl_reg.h"
+#include "soc/dport_reg.h"
+#include "esp_attr.h"
+#include "esp_deepsleep.h"
+
+/* Updating RTC_MEMORY_CRC_REG register via set_rtc_memory_crc()
+   is not thread-safe. */
+static _lock_t lock_rtc_memory_crc;
+
+esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void)
+{
+    _lock_acquire(&lock_rtc_memory_crc);
+    uint32_t stored_crc = REG_READ(RTC_MEMORY_CRC_REG);
+    set_rtc_memory_crc();
+    uint32_t calc_crc = REG_READ(RTC_MEMORY_CRC_REG);
+    REG_WRITE(RTC_MEMORY_CRC_REG, stored_crc);
+    _lock_release(&lock_rtc_memory_crc);
+
+    if(stored_crc == calc_crc) {
+        return (esp_deep_sleep_wake_stub_fn_t)REG_READ(RTC_ENTRY_ADDR_REG);
+    } else {
+        return NULL;
+    }
+}
+
+void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub)
+{
+    _lock_acquire(&lock_rtc_memory_crc);
+    REG_WRITE(RTC_ENTRY_ADDR_REG, (uint32_t)new_stub);
+    set_rtc_memory_crc();
+    _lock_release(&lock_rtc_memory_crc);
+}
+
+void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) {
+    //
+    //mmu_init(0);
+    REG_SET_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
+    REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR);
+}
+
+void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void);

+ 38 - 124
components/esp32/event.c → components/esp32/event_default_handlers.c

@@ -19,6 +19,7 @@
 #include "esp_err.h"
 #include "esp_err.h"
 #include "esp_wifi.h"
 #include "esp_wifi.h"
 #include "esp_event.h"
 #include "esp_event.h"
+#include "esp_event_loop.h"
 #include "esp_task.h"
 #include "esp_task.h"
 
 
 #include "freertos/FreeRTOS.h"
 #include "freertos/FreeRTOS.h"
@@ -27,22 +28,15 @@
 #include "freertos/semphr.h"
 #include "freertos/semphr.h"
 
 
 #include "tcpip_adapter.h"
 #include "tcpip_adapter.h"
+#include "esp_log.h"
 
 
-#define ESP32_WORKAROUND 1
+const char* TAG = "event";
 
 
-#if CONFIG_WIFI_ENABLED
-static bool event_init_flag = false;
-static xQueueHandle g_event_handler = NULL;
-
-static system_event_cb_t g_event_handler_cb;
-static void *g_event_ctx;
-
-#define WIFI_DEBUG(...)
 #define WIFI_API_CALL_CHECK(info, api_call, ret) \
 #define WIFI_API_CALL_CHECK(info, api_call, ret) \
 do{\
 do{\
     esp_err_t __err = (api_call);\
     esp_err_t __err = (api_call);\
     if ((ret) != __err) {\
     if ((ret) != __err) {\
-        WIFI_DEBUG("%s %d %s ret=%d\n", __FUNCTION__, __LINE__, (info), __err);\
+        ESP_LOGE(TAG, "%s %d %s ret=%d", __FUNCTION__, __LINE__, (info), __err);\
         return __err;\
         return __err;\
     }\
     }\
 } while(0)
 } while(0)
@@ -71,7 +65,7 @@ static system_event_handle_t g_system_event_handle_table[] = {
     {SYSTEM_EVENT_STA_CONNECTED,       system_event_sta_connected_handle_default},
     {SYSTEM_EVENT_STA_CONNECTED,       system_event_sta_connected_handle_default},
     {SYSTEM_EVENT_STA_DISCONNECTED,    system_event_sta_disconnected_handle_default},
     {SYSTEM_EVENT_STA_DISCONNECTED,    system_event_sta_disconnected_handle_default},
     {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
     {SYSTEM_EVENT_STA_AUTHMODE_CHANGE, NULL},
-    {SYSTEM_EVENT_STA_GOT_IP,           system_event_sta_got_ip_default},
+    {SYSTEM_EVENT_STA_GOT_IP,          system_event_sta_got_ip_default},
     {SYSTEM_EVENT_AP_START,            system_event_ap_start_handle_default},
     {SYSTEM_EVENT_AP_START,            system_event_ap_start_handle_default},
     {SYSTEM_EVENT_AP_STOP,             system_event_ap_stop_handle_default},
     {SYSTEM_EVENT_AP_STOP,             system_event_ap_stop_handle_default},
     {SYSTEM_EVENT_AP_STACONNECTED,     NULL},
     {SYSTEM_EVENT_AP_STACONNECTED,     NULL},
@@ -85,7 +79,7 @@ static esp_err_t system_event_sta_got_ip_default(system_event_t *event)
     extern esp_err_t esp_wifi_set_sta_ip(void);
     extern esp_err_t esp_wifi_set_sta_ip(void);
     WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK);
     WIFI_API_CALL_CHECK("esp_wifi_set_sta_ip", esp_wifi_set_sta_ip(), ESP_OK);
 
 
-    printf("ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR "\n",
+    ESP_LOGI(TAG, "ip: " IPSTR ", mask: " IPSTR ", gw: " IPSTR,
            IP2STR(&event->event_info.got_ip.ip_info.ip),
            IP2STR(&event->event_info.got_ip.ip_info.ip),
            IP2STR(&event->event_info.got_ip.ip_info.netmask),
            IP2STR(&event->event_info.got_ip.ip_info.netmask),
            IP2STR(&event->event_info.got_ip.ip_info.gw));
            IP2STR(&event->event_info.got_ip.ip_info.gw));
@@ -161,7 +155,7 @@ esp_err_t system_event_sta_connected_handle_default(system_event_t *event)
 
 
             esp_event_send(&evt);
             esp_event_send(&evt);
         } else {
         } else {
-            WIFI_DEBUG("invalid static ip\n");
+            ESP_LOGE(TAG, "invalid static ip");
         }
         }
     }
     }
 
 
@@ -175,104 +169,89 @@ esp_err_t system_event_sta_disconnected_handle_default(system_event_t *event)
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
-static esp_err_t esp_wifi_post_event_to_user(system_event_t *event)
-{
-    if (g_event_handler_cb) {
-        return (*g_event_handler_cb)(g_event_ctx, event);
-    }
-
-    return ESP_OK;
-}
-
 static esp_err_t esp_system_event_debug(system_event_t *event)
 static esp_err_t esp_system_event_debug(system_event_t *event)
 {
 {
     if (event == NULL) {
     if (event == NULL) {
-        printf("Error: event is null!\n");
+        ESP_LOGE(TAG, "event is null!");
         return ESP_FAIL;
         return ESP_FAIL;
     }
     }
 
 
-    WIFI_DEBUG("received event: ");
     switch (event->event_id) {
     switch (event->event_id) {
     case SYSTEM_EVENT_WIFI_READY: {
     case SYSTEM_EVENT_WIFI_READY: {
-        WIFI_DEBUG("SYSTEM_EVENT_WIFI_READY\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_WIFI_READY");
         break;
         break;
     }
     }
     case SYSTEM_EVENT_SCAN_DONE: {
     case SYSTEM_EVENT_SCAN_DONE: {
-        system_event_sta_scan_done_t *scan_done;
-        scan_done = &event->event_info.scan_done;
-        WIFI_DEBUG("SYSTEM_EVENT_SCAN_DONE\nstatus:%d, number:%d\n",  scan_done->status, scan_done->number);
+        system_event_sta_scan_done_t *scan_done = &event->event_info.scan_done;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_SCAN_DONE, status:%d, number:%d",  scan_done->status, scan_done->number);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_START: {
     case SYSTEM_EVENT_STA_START: {
-        WIFI_DEBUG("SYSTEM_EVENT_STA_START\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_START");
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_STOP: {
     case SYSTEM_EVENT_STA_STOP: {
-        WIFI_DEBUG("SYSTEM_EVENT_STA_STOP\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_STOP");
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_CONNECTED: {
     case SYSTEM_EVENT_STA_CONNECTED: {
-        system_event_sta_connected_t *connected;
-        connected = &event->event_info.connected;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_CONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d\n", \
+        system_event_sta_connected_t *connected = &event->event_info.connected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_CONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, channel:%d, authmode:%d", \
                    connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \
                    connected->ssid, connected->ssid_len, connected->bssid[0], connected->bssid[0], connected->bssid[1], \
                    connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode);
                    connected->bssid[3], connected->bssid[4], connected->bssid[5], connected->channel, connected->authmode);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_DISCONNECTED: {
     case SYSTEM_EVENT_STA_DISCONNECTED: {
-        system_event_sta_disconnected_t *disconnected;
-        disconnected = &event->event_info.disconnected;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_DISCONNECTED\nssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d\n", \
+        system_event_sta_disconnected_t *disconnected = &event->event_info.disconnected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_DISCONNECTED, ssid:%s, ssid_len:%d, bssid:%02x:%02x:%02x:%02x:%02x:%02x, reason:%d", \
                    disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \
                    disconnected->ssid, disconnected->ssid_len, disconnected->bssid[0], disconnected->bssid[0], disconnected->bssid[1], \
                    disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason);
                    disconnected->bssid[3], disconnected->bssid[4], disconnected->bssid[5], disconnected->reason);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {
     case SYSTEM_EVENT_STA_AUTHMODE_CHANGE: {
-        system_event_sta_authmode_change_t *auth_change;
-        auth_change = &event->event_info.auth_change;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_AUTHMODE_CHNAGE\nold_mode:%d, new_mode:%d\n", auth_change->old_mode, auth_change->new_mode);
+        system_event_sta_authmode_change_t *auth_change = &event->event_info.auth_change;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_AUTHMODE_CHNAGE, old_mode:%d, new_mode:%d", auth_change->old_mode, auth_change->new_mode);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_STA_GOT_IP: {
     case SYSTEM_EVENT_STA_GOT_IP: {
-        system_event_sta_got_ip_t *got_ip;
-        got_ip = &event->event_info.got_ip;
-        WIFI_DEBUG("SYSTEM_EVENT_STA_GOTIP\n");
+        system_event_sta_got_ip_t *got_ip = &event->event_info.got_ip;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_STA_GOTIP, ip:" IPSTR ", mask:" IPSTR ", gw:" IPSTR,
+            IP2STR(&got_ip->ip_info.ip),
+            IP2STR(&got_ip->ip_info.netmask),
+            IP2STR(&got_ip->ip_info.gw));
         break;
         break;
     }
     }
     case SYSTEM_EVENT_AP_START: {
     case SYSTEM_EVENT_AP_START: {
-        WIFI_DEBUG("SYSTEM_EVENT_AP_START\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_START");
         break;
         break;
     }
     }
     case SYSTEM_EVENT_AP_STOP: {
     case SYSTEM_EVENT_AP_STOP: {
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STOP\n");
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STOP");
         break;
         break;
     }
     }
     case SYSTEM_EVENT_AP_STACONNECTED: {
     case SYSTEM_EVENT_AP_STACONNECTED: {
-        system_event_ap_staconnected_t *staconnected;
-        staconnected = &event->event_info.sta_connected;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STACONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
+        system_event_ap_staconnected_t *staconnected = &event->event_info.sta_connected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STACONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
                    staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
                    staconnected->mac[0], staconnected->mac[0], staconnected->mac[1], \
                    staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
                    staconnected->mac[3], staconnected->mac[4], staconnected->mac[5], staconnected->aid);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_AP_STADISCONNECTED: {
     case SYSTEM_EVENT_AP_STADISCONNECTED: {
-        system_event_ap_stadisconnected_t *stadisconnected;
-        stadisconnected = &event->event_info.sta_disconnected;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_STADISCONNECTED\nmac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d\n", \
+        system_event_ap_stadisconnected_t *stadisconnected = &event->event_info.sta_disconnected;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_STADISCONNECTED, mac:%02x:%02x:%02x:%02x:%02x:%02x, aid:%d", \
                    stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
                    stadisconnected->mac[0], stadisconnected->mac[0], stadisconnected->mac[1], \
                    stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
                    stadisconnected->mac[3], stadisconnected->mac[4], stadisconnected->mac[5], stadisconnected->aid);
         break;
         break;
     }
     }
     case SYSTEM_EVENT_AP_PROBEREQRECVED: {
     case SYSTEM_EVENT_AP_PROBEREQRECVED: {
-        system_event_ap_probe_req_rx_t *ap_probereqrecved;
-        ap_probereqrecved = &event->event_info.ap_probereqrecved;
-        WIFI_DEBUG("SYSTEM_EVENT_AP_PROBEREQRECVED\nrssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x\n", \
+        system_event_ap_probe_req_rx_t *ap_probereqrecved = &event->event_info.ap_probereqrecved;
+        ESP_LOGD(TAG, "SYSTEM_EVENT_AP_PROBEREQRECVED, rssi:%d, mac:%02x:%02x:%02x:%02x:%02x:%02x", \
                    ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \
                    ap_probereqrecved->rssi, ap_probereqrecved->mac[0], ap_probereqrecved->mac[0], ap_probereqrecved->mac[1], \
                    ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]);
                    ap_probereqrecved->mac[3], ap_probereqrecved->mac[4], ap_probereqrecved->mac[5]);
         break;
         break;
     }
     }
     default: {
     default: {
-        printf("Error: no such kind of event!\n");
+        ESP_LOGW(TAG, "no such kind of event!");
         break;
         break;
     }
     }
     }
     }
@@ -280,88 +259,23 @@ static esp_err_t esp_system_event_debug(system_event_t *event)
     return ESP_OK;
     return ESP_OK;
 }
 }
 
 
-static esp_err_t esp_system_event_handler(system_event_t *event)
+esp_err_t esp_event_process_default(system_event_t *event)
 {
 {
     if (event == NULL) {
     if (event == NULL) {
-        printf("Error: event is null!\n");
+        ESP_LOGE(TAG, "Error: event is null!");
         return ESP_FAIL;
         return ESP_FAIL;
     }
     }
 
 
     esp_system_event_debug(event);
     esp_system_event_debug(event);
     if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)) {
     if ((event->event_id < SYSTEM_EVENT_MAX) && (event->event_id == g_system_event_handle_table[event->event_id].event_id)) {
         if (g_system_event_handle_table[event->event_id].event_handle) {
         if (g_system_event_handle_table[event->event_id].event_handle) {
-            WIFI_DEBUG("enter default callback\n");
+            ESP_LOGV(TAG, "enter default callback");
             g_system_event_handle_table[event->event_id].event_handle(event);
             g_system_event_handle_table[event->event_id].event_handle(event);
-            WIFI_DEBUG("exit default callback\n");
+            ESP_LOGV(TAG, "exit default callback");
         }
         }
     } else {
     } else {
-        printf("mismatch or invalid event, id=%d\n", event->event_id);
-    }
-
-    return esp_wifi_post_event_to_user(event);
-}
-
-static void esp_system_event_task(void *pvParameters)
-{
-    system_event_t evt;
-    esp_err_t ret;
-
-    while (1) {
-        if (xQueueReceive(g_event_handler, &evt, portMAX_DELAY) == pdPASS) {
-            ret = esp_system_event_handler(&evt);
-            if (ret == ESP_FAIL) {
-                printf("esp wifi post event to user fail!\n");
-            }
-        }
-    }
-}
-
-system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx)
-{
-    system_event_cb_t old_cb = g_event_handler_cb;
-
-    g_event_handler_cb = cb;
-    g_event_ctx = ctx;
-
-    return old_cb;
-}
-
-esp_err_t esp_event_send(system_event_t *event)
-{
-    portBASE_TYPE ret;
-
-    ret = xQueueSendToBack((xQueueHandle)g_event_handler, event, 0);
-
-    if (pdPASS != ret) {
-        if (event) {
-            printf("e=%d f\n", event->event_id);
-        } else {
-            printf("e null\n");
-        }
-        return ESP_FAIL;
-    }
-
-    return ESP_OK;
-}
-
-void *esp_event_get_handler(void)
-{
-    return (void *)g_event_handler;
-}
-
-esp_err_t esp_event_init(system_event_cb_t cb, void *ctx)
-{
-    if (event_init_flag) {
+        ESP_LOGE(TAG, "mismatch or invalid event, id=%d", event->event_id);
         return ESP_FAIL;
         return ESP_FAIL;
     }
     }
-
-    g_event_handler_cb = cb;
-    g_event_ctx = ctx;
-
-    g_event_handler = xQueueCreate(CONFIG_SYSTEM_EVENT_QUEUE_SIZE, sizeof(system_event_t));
-
-    xTaskCreatePinnedToCore(esp_system_event_task, "eventTask", ESP_TASKD_EVENT_STACK, NULL, ESP_TASKD_EVENT_PRIO, NULL, 0);
     return ESP_OK;
     return ESP_OK;
 }
 }
-
-#endif

+ 107 - 0
components/esp32/event_loop.c

@@ -0,0 +1,107 @@
+// 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 "esp_err.h"
+#include "esp_wifi.h"
+#include "esp_event.h"
+#include "esp_event_loop.h"
+#include "esp_task.h"
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/queue.h"
+#include "freertos/semphr.h"
+
+#include "esp_log.h"
+#include "sdkconfig.h"
+
+
+static const char* TAG = "event";
+static bool s_event_init_flag = false;
+static QueueHandle_t s_event_queue = NULL;
+static system_event_cb_t s_event_handler_cb = NULL;
+static void *s_event_ctx = NULL;
+
+static esp_err_t esp_event_post_to_user(system_event_t *event)
+{
+    if (s_event_handler_cb) {
+        return (*s_event_handler_cb)(s_event_ctx, event);
+    }
+    return ESP_OK;
+}
+
+static void esp_event_loop_task(void *pvParameters)
+{
+    while (1) {
+        system_event_t evt;
+        if (xQueueReceive(s_event_queue, &evt, portMAX_DELAY) == pdPASS) {
+            esp_err_t ret = esp_event_process_default(&evt);
+            if (ret != ESP_OK) {
+                ESP_LOGE(TAG, "default event handler failed!");
+            }
+            ret = esp_event_post_to_user(&evt);
+            if (ret != ESP_OK) {
+                ESP_LOGE(TAG, "post event to user fail!");
+            }
+        }
+    }
+}
+
+system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx)
+{
+    system_event_cb_t old_cb = s_event_handler_cb;
+    s_event_handler_cb = cb;
+    s_event_ctx = ctx;
+    return old_cb;
+}
+
+esp_err_t esp_event_send(system_event_t *event)
+{
+    portBASE_TYPE ret = xQueueSendToBack(s_event_queue, event, 0);
+    if (ret != pdPASS) {
+        if (event) {
+            ESP_LOGE(TAG, "e=%d f", event->event_id);
+        } else {
+            ESP_LOGE(TAG, "e null");
+        }
+        return ESP_FAIL;
+    }
+    return ESP_OK;
+}
+
+QueueHandle_t esp_event_loop_get_queue(void)
+{
+    return s_event_queue;
+}
+
+esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx)
+{
+    if (s_event_init_flag) {
+        return ESP_FAIL;
+    }
+    s_event_handler_cb = cb;
+    s_event_ctx = ctx;
+    s_event_queue = xQueueCreate(CONFIG_SYSTEM_EVENT_QUEUE_SIZE, sizeof(system_event_t));
+
+    xTaskCreatePinnedToCore(esp_event_loop_task, "eventTask",
+            ESP_TASKD_EVENT_STACK, NULL, ESP_TASKD_EVENT_PRIO, NULL, 0);
+
+    s_event_init_flag = true;
+    return ESP_OK;
+}
+

+ 14 - 2
components/esp32/include/esp_attr.h

@@ -17,8 +17,8 @@
 #define ROMFN_ATTR
 #define ROMFN_ATTR
 
 
 //Normally, the linker script will put all code and rodata in flash,
 //Normally, the linker script will put all code and rodata in flash,
-//and all variables in shared RAM. This can be redirected to IRAM if
-//needed using these macros.
+//and all variables in shared RAM. These macros can be used to redirect
+//particular functions/variables to other memory regions.
 
 
 // Forces code into IRAM instead of flash
 // Forces code into IRAM instead of flash
 #define IRAM_ATTR __attribute__((section(".iram1")))
 #define IRAM_ATTR __attribute__((section(".iram1")))
@@ -26,4 +26,16 @@
 // Forces data into DRAM instead of flash
 // Forces data into DRAM instead of flash
 #define DRAM_ATTR __attribute__((section(".dram1")))
 #define DRAM_ATTR __attribute__((section(".dram1")))
 
 
+// Forces code into RTC fast memory
+#define RTC_IRAM_ATTR __attribute__((section(".rtc.text")))
+
+// Forces data into RTC slow memory
+// Any variable marked with this attribute will keep its value
+// during a deep sleep / wake cycle.
+#define RTC_DATA_ATTR __attribute__((section(".rtc.data")))
+
+// Forces read-only data into RTC slow memory
+// Makes constant data available to RTC wake stubs (see esp_deepsleep.h)
+#define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata")))
+
 #endif /* __ESP_ATTR_H__ */
 #endif /* __ESP_ATTR_H__ */

+ 137 - 0
components/esp32/include/esp_deepsleep.h

@@ -0,0 +1,137 @@
+// 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_DEEPSLEEP_H__
+#define __ESP_DEEPSLEEP_H_
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup Deep_Sleep_API Deep Sleep API
+  * @brief API for putting device into deep sleep
+  */
+
+/** @addtogroup Deep_Sleep_API
+  * @{
+  */
+
+/**
+  * @brief     Set the chip to deep-sleep mode.
+  *
+  *            The device will automatically wake up after the deep-sleep time set
+  *            by the users. Upon waking up, the device boots up from user_init.
+  *
+  * @attention  The parameter time_in_us to be "uint64" is for further development.
+  *                  Only the low 32 bits of parameter time_in_us are avalable now.
+  *
+  * @param     uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond
+  *
+  * @return    null
+  */
+void system_deep_sleep(uint64_t time_in_us);
+
+/**
+ * @brief Default stub to run on wake from deep sleep.
+ *
+ * Allows for executing code immediately on wake from sleep, before
+ * the software bootloader or esp-idf app has started up.
+ *
+ * This function is weak-linked, so you can implement your own version
+ * to run code immediately when the chip wakes from
+ * sleep.
+ *
+ * For example:
+ * @code
+ * void RTC_IRAM_ATTR esp_wake_deep_sleep(void) {
+ *    esp_default_wake_deep_sleep();
+ *    // Add additional functionality here
+ * }
+ *
+ * (Implementing this function is not required for normal operation,
+ * in the usual case your app will start normally when waking from
+ * deep sleep.)
+ *
+ * esp_wake_deep_sleep() functionality is limited:
+ *
+ * - Runs immediately on wake, so most of the SoC is freshly reset -
+ *   flash is unmapped and hardware is otherwise uninitialised.
+ *
+ * - Can only call functions implemented in ROM, or marked RTC_IRAM_ATTR.
+ *
+ * - Static variables marked RTC_DATA_ATTR will have initial values on
+ *   cold boot, and maintain these values between sleep/wake cycles.
+ *
+ * - Read-only data should be marked RTC_RODATA_ATTR. Strings must be
+ *   declared as variables also using RTC_RODATA_ATTR, like this:
+ *   RTC_RODATA_ATTR const char message[] = "Hello from very early boot!\n";
+ *
+ * - Any other static memory will not be initialised (either to zero,
+ *   or to any predefined value).
+ *
+ *
+ * - If you implement your own stub, the first call the stub makes
+     should be to esp_default_wake_deep_sleep().
+ */
+void esp_wake_deep_sleep(void);
+
+/**
+ * @brief Function type for stub to run on wake from sleep.
+ *
+ */
+typedef void (*esp_deep_sleep_wake_stub_fn_t)(void);
+
+/**
+ * @brief Install a new stub at runtime to run on wake from deep sleep
+ *
+ * If implementing esp_wake_deep_sleep() then it is not necessary to
+ * call this function.
+ *
+ * However, it is possible to call this function to substitute a
+ * different deep sleep stub. Any function used as a deep sleep stub
+ * must be marked RTC_IRAM_ATTR, and must obey the same rules given
+ * for esp_wake_deep_sleep().
+ */
+void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub);
+
+/**
+ * @brief Return current wake from deep sleep stub, or NULL if
+ * no stub is installed.
+ */
+esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void);
+
+/* The default esp-idf-provided esp_wake_deep_sleep() stub.
+
+   If you replace esp_wake_deep_sleep() in your program, or use
+   esp_set_deep_sleep_wake_stub(), then it is recommended you call
+   esp_default_wake_deep_sleep() as the first function in your stub.
+*/
+void esp_default_wake_deep_sleep(void);
+
+/**
+  * @}
+  */
+
+
+/**
+  * @}
+  */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_SYSTEM_H__ */

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

@@ -15,6 +15,7 @@
 #define __ESP_ERR_H__
 #define __ESP_ERR_H__
 
 
 #include <stdint.h>
 #include <stdint.h>
+#include <assert.h>
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -31,6 +32,12 @@ typedef int32_t esp_err_t;
 #define ESP_ERR_INVALID_ARG     0x102
 #define ESP_ERR_INVALID_ARG     0x102
 #define ESP_ERR_INVALID_STATE   0x103
 #define ESP_ERR_INVALID_STATE   0x103
 
 
+/**
+ * Macro which can be used to check the error code,
+ * and terminate the program in case the code is not ESP_OK.
+ * Prints the failed statement to serial output.
+ */
+#define ESP_ERROR_CHECK(x)   do { esp_err_t rc = (x); if (rc != ESP_OK) { assert(0 && #x);} } while(0);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 12 - 43
components/esp32/include/esp_event.h

@@ -19,8 +19,7 @@
 #include <stdbool.h>
 #include <stdbool.h>
 
 
 #include "esp_err.h"
 #include "esp_err.h"
-#include "esp_wifi.h"
-
+#include "esp_wifi_types.h"
 #include "tcpip_adapter.h"
 #include "tcpip_adapter.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
@@ -101,33 +100,11 @@ typedef union {
 } system_event_info_t;
 } system_event_info_t;
 
 
 typedef struct {
 typedef struct {
-    system_event_id_t     event_id;      /**< even ID */
+    system_event_id_t     event_id;      /**< event ID */
     system_event_info_t   event_info;    /**< event information */
     system_event_info_t   event_info;    /**< event information */
 } system_event_t;
 } system_event_t;
 
 
-/**
-  * @brief  Application specified event callback function
-  *
-  * @param  void *ctx : reserved for user
-  * @param  system_event_t *event : event type defined in this file
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event);
-
-/**
-  * @brief  Set application specified event callback function
-  *
-  * @attention 1. If cb is NULL, means application don't need to handle
-  *               If cb is not NULL, it will be call when an event is received, after the default event callback is completed
-  *
-  * @param  system_event_cb_t cb : callback
-  * @param  void *ctx : reserved for user
-  *
-  * @return system_event_cb_t : old callback
-  */
-system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx);
+typedef esp_err_t (*system_event_handler_t)(system_event_t *event);
 
 
 /**
 /**
   * @brief  Send a event to event task
   * @brief  Send a event to event task
@@ -142,28 +119,20 @@ system_event_cb_t esp_event_set_cb(system_event_cb_t cb, void *ctx);
 esp_err_t esp_event_send(system_event_t *event);
 esp_err_t esp_event_send(system_event_t *event);
 
 
 /**
 /**
-  * @brief  Get the event handler
+  * @brief  Default event handler for system events
   *
   *
-  * @attention : currently this API returns event queue handler, by this event queue,
-  *              users can notice when WiFi has done something like scanning done, connected to AP or disconnected from AP.
+  * This function performs default handling of system events.
+  * When using esp_event_loop APIs, it is called automatically before invoking the user-provided
+  * callback function.
   *
   *
-  * @param  null
+  * Applications which implement a custom event loop must call this function
+  * as part of event processing.
   *
   *
-  * @return void * : event queue pointer
+  * @param  event pointer to event to be handled
+  * @return ESP_OK if an event was handled successfully
   */
   */
-void *esp_event_get_handler(void);
+esp_err_t esp_event_process_default(system_event_t *event);
 
 
-/**
-  * @brief  Init the event module
-  *         Create the event handler and task
-  *
-  * @param  system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb
-  * @param  void *ctx : reserved for user
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-esp_err_t esp_event_init(system_event_cb_t cb, void *ctx);
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 81 - 0
components/esp32/include/esp_event_loop.h

@@ -0,0 +1,81 @@
+// 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_EVENT_LOOP_H__
+#define __ESP_EVENT_LOOP_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "esp_err.h"
+#include "esp_event.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+  * @brief  Application specified event callback function
+  *
+  * @param  void *ctx : reserved for user
+  * @param  system_event_t *event : event type defined in this file
+  *
+  * @return ESP_OK : succeed
+  * @return others : fail
+  */
+typedef esp_err_t (*system_event_cb_t)(void *ctx, system_event_t *event);
+
+/**
+  * @brief  Initialize event loop
+  *         Create the event handler and task
+  *
+  * @param  system_event_cb_t cb : application specified event callback, it can be modified by call esp_event_set_cb
+  * @param  void *ctx : reserved for user
+  *
+  * @return ESP_OK : succeed
+  * @return others : fail
+  */
+esp_err_t esp_event_loop_init(system_event_cb_t cb, void *ctx);
+
+/**
+  * @brief  Set application specified event callback function
+  *
+  * @attention 1. If cb is NULL, means application don't need to handle
+  *               If cb is not NULL, it will be call when an event is received, after the default event callback is completed
+  *
+  * @param  system_event_cb_t cb : callback
+  * @param  void *ctx : reserved for user
+  *
+  * @return system_event_cb_t : old callback
+  */
+system_event_cb_t esp_event_loop_set_cb(system_event_cb_t cb, void *ctx);
+
+/**
+  * @brief  Get the queue used by event loop
+  *
+  * @attention : currently this API is used to initialize "q" parameter
+  * of wifi_init structure.
+  *
+  * @return QueueHandle_t : event queue handle
+  */
+QueueHandle_t esp_event_loop_get_queue(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ESP_EVENT_LOOP_H__ */

+ 143 - 0
components/esp32/include/esp_smartconfig.h

@@ -0,0 +1,143 @@
+// 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_SMARTCONFIG_H__
+#define __ESP_SMARTCONFIG_H__
+#include <stdint.h>
+#include <esp_types.h>
+#include "esp_err.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    SC_STATUS_WAIT = 0,             /**< waiting, do not start connection in this phase */
+    SC_STATUS_FIND_CHANNEL,         /**< find target channel, start connection by APP in this phase */
+    SC_STATUS_GETTING_SSID_PSWD,    /**< getting SSID and password of target AP */
+    SC_STATUS_LINK,                 /**< connecting to target AP */
+    SC_STATUS_LINK_OVER,            /**< got IP, connect to AP successfully */
+} smartconfig_status_t;
+
+typedef enum {
+    SC_TYPE_ESPTOUCH = 0,       /**< protocol: ESPTouch */
+    SC_TYPE_AIRKISS,            /**< protocol: AirKiss */
+    SC_TYPE_ESPTOUCH_AIRKISS,   /**< protocol: ESPTouch and AirKiss */
+} smartconfig_type_t;
+
+/**
+  * @brief  The callback of SmartConfig, executed when smart-config status changed.
+  *
+  * @param  smartconfig_status_t status : status of SmartConfig:
+  *    -  if status == SC_STATUS_GETTING_SSID_PSWD, parameter void *pdata is a pointer
+                       of smartconfig_type_t, means SmartConfig type: AirKiss or ESP-TOUCH.
+  *    -  if status == SC_STATUS_LINK, parameter void *pdata is a pointer of struct station_config;
+  *    -  if status == SC_STATUS_LINK_OVER, parameter void *pdata is a pointer of mobile
+  *                    phone's IP address, 4 bytes. This is only available in ESPTOUCH, otherwise,
+  *                    it is NULL.
+  *    -  otherwise, parameter void *pdata is NULL.
+  * @param  void *pdata : data of SmartConfig
+  *
+  * @return null
+  */
+typedef void (*sc_callback_t)(smartconfig_status_t status, void *pdata);
+
+/**
+  * @brief  Get the version of SmartConfig.
+  *
+  * @param  null
+  *
+  * @return SmartConfig version
+  */
+const char *esp_smartconfig_get_version(void);
+
+/**
+  * @brief     Start SmartConfig mode.
+  *
+  *            Start SmartConfig mode, to connect ESP32 station to AP, by sniffing
+  *            for special packets from the air, containing SSID and password of desired AP.
+  *            You need to broadcast the SSID and password (e.g. from mobile device or computer)
+  *            with the SSID and password encoded.
+  *
+  * @attention 1. This API can only be called in station mode.
+  * @attention 2. During SmartConfig, ESP32 station and soft-AP are disabled.
+  * @attention 3. Can not call esp_smartconfig_start twice before it finish, please call
+  *               esp_smartconfig_stop first.
+  * @attention 4. Don't call any other APIs during SmartConfig, please call esp_smartconfig_stop first.
+  *
+  * @param     sc_callback_t cb : SmartConfig callback; executed when SmartConfig status changed;
+  * @param     uint8 log : 1, UART output logs; otherwise, UART only outputs the result.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_start(sc_callback_t cb, ...);
+
+/**
+  * @brief     Stop SmartConfig, free the buffer taken by esp_smartconfig_start.
+  *
+  * @attention Whether connect to AP succeed or not, this API should be called to free
+  *            memory taken by smartconfig_start.
+  *
+  * @param     null
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_stop(void);
+
+/**
+  * @brief     Set timeout of SmartConfig.
+  *
+  * @attention SmartConfig timeout start at SC_STATUS_FIND_CHANNEL, SmartConfig will
+  *            restart if timeout.
+  *
+  * @param     uint8 time_s : range 15s~255s, offset:45s.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_esptouch_set_timeout(uint8_t time_s);
+
+/**
+  * @brief     Set protocol type of SmartConfig.
+  *
+  * @attention If users need to set the SmartConfig type, please set it before calling
+  *            esp_smartconfig_start.
+  *
+  * @param     smartconfig_type_t type : AirKiss, ESP-TOUCH or both.
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_set_type(smartconfig_type_t type);
+
+/**
+  * @brief     Set mode of SmartConfig. default normal mode.
+  *
+  * @attention If users need to set the SmartConfig mode, please set it before calling
+  *            esp_smartconfig_start. Different mode should match different APP(phone).
+  *
+  * @param     bool enable : false-disable(default); true-enable; 
+  *
+  * @return    ESP_OK : succeed
+  * @return    others : fail
+  */
+esp_err_t esp_smartconfig_fast_mode(bool enable);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 1 - 15
components/esp32/include/esp_system.h

@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <stdint.h>
 
 
 #include "esp_err.h"
 #include "esp_err.h"
+#include "esp_deepsleep.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
@@ -62,21 +63,6 @@ void system_restore(void);
   */
   */
 void system_restart(void);
 void system_restart(void);
 
 
-/**
-  * @brief     Set the chip to deep-sleep mode.
-  *
-  *            The device will automatically wake up after the deep-sleep time set
-  *            by the users. Upon waking up, the device boots up from user_init.
-  *
-  * @attention  The parameter time_in_us to be "uint64" is for further development. 
-  *                  Only the low 32 bits of parameter time_in_us are avalable now.
-  *
-  * @param     uint64 time_in_us : deep-sleep time, only the low 32bits are avalable now. unit: microsecond
-  *
-  * @return    null
-  */
-void system_deep_sleep(uint64_t time_in_us);
-
 /**
 /**
   * @brief  Get system time, unit: microsecond.
   * @brief  Get system time, unit: microsecond.
   *
   *

+ 6 - 7
components/esp32/include/esp_task.h

@@ -15,10 +15,10 @@
 /* Notes:
 /* Notes:
  * 1. Put all task priority and stack size definition in this file
  * 1. Put all task priority and stack size definition in this file
  * 2. If the task priority is less than 10, use ESP_TASK_PRIO_MIN + X style,
  * 2. If the task priority is less than 10, use ESP_TASK_PRIO_MIN + X style,
- *    otherwise use ESP_TASK_PRIO_MIN - X style
- * 3. If this is a daemon task, the macro prifix is ESP_TASKD_, otherwise
+ *    otherwise use ESP_TASK_PRIO_MAX - X style
+ * 3. If this is a daemon task, the macro prefix is ESP_TASKD_, otherwise
  *    it's ESP_TASK_
  *    it's ESP_TASK_
- * 4. If the configMAX_PRIORITIES is modified, please make all prority are 
+ * 4. If the configMAX_PRIORITIES is modified, please make all priority are
  *    greater than 0
  *    greater than 0
  * 5. Make sure esp_task.h is consistent between wifi lib and idf
  * 5. Make sure esp_task.h is consistent between wifi lib and idf
  */
  */
@@ -51,10 +51,9 @@
 /* idf task */
 /* idf task */
 #define ESP_TASKD_EVENT_PRIO          (ESP_TASK_PRIO_MAX - 5)
 #define ESP_TASKD_EVENT_PRIO          (ESP_TASK_PRIO_MAX - 5)
 #define ESP_TASKD_EVENT_STACK         CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE
 #define ESP_TASKD_EVENT_STACK         CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE
-#define ESP_TASK_WIFI_STARTUP_PRIO    (ESP_TASK_PRIO_MAX - 7)
-#define ESP_TASK_WIFI_STARTUP_STACK   4096
 #define ESP_TASK_TCPIP_PRIO           (ESP_TASK_PRIO_MAX - 7)
 #define ESP_TASK_TCPIP_PRIO           (ESP_TASK_PRIO_MAX - 7)
 #define ESP_TASK_TCPIP_STACK          2048
 #define ESP_TASK_TCPIP_STACK          2048
-#define ESP_TASK_BT_INIT_PRIO         (ESP_TASK_PRIO_MAX - 7)
-#define ESP_TASK_BT_INIT_STACK        2048
+#define ESP_TASK_MAIN_PRIO            (ESP_TASK_PRIO_MIN + 1)
+#define ESP_TASK_MAIN_STACK           CONFIG_MAIN_TASK_STACK_SIZE
+
 #endif
 #endif

+ 15 - 189
components/esp32/include/esp_wifi.h

@@ -59,113 +59,26 @@
 
 
 #include <stdint.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdbool.h>
-
-#include "esp_err.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
 #include "rom/queue.h"
 #include "rom/queue.h"
+#include "esp_err.h"
+#include "esp_wifi_types.h"
+#include "esp_event.h"
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 extern "C" {
 extern "C" {
 #endif
 #endif
 
 
-typedef enum {
-    WIFI_MODE_NULL = 0,  /**< null mode */
-    WIFI_MODE_STA,       /**< WiFi station mode */
-    WIFI_MODE_AP,        /**< WiFi soft-AP mode */
-    WIFI_MODE_APSTA,     /**< WiFi station + soft-AP mode */
-    WIFI_MODE_MAX
-} wifi_mode_t;
-
-typedef enum {
-    WIFI_IF_STA = 0,     /**< ESP32 station interface */
-    WIFI_IF_AP,          /**< ESP32 soft-AP interface */
-    WIFI_IF_MAX
-} wifi_interface_t;
-
-typedef enum {
-    WIFI_COUNTRY_CN = 0, /**< country China, channel range [1, 14] */
-    WIFI_COUNTRY_JP,     /**< country Japan, channel range [1, 14] */
-    WIFI_COUNTRY_US,     /**< country USA, channel range [1, 11] */
-    WIFI_COUNTRY_EU,     /**< country Europe, channel range [1, 13] */
-    WIFI_COUNTRY_MAX
-} wifi_country_t;
-
-typedef enum {
-    WIFI_AUTH_OPEN = 0,      /**< authenticate mode : open */
-    WIFI_AUTH_WEP,           /**< authenticate mode : WEP */
-    WIFI_AUTH_WPA_PSK,       /**< authenticate mode : WPA_PSK */
-    WIFI_AUTH_WPA2_PSK,      /**< authenticate mode : WPA2_PSK */
-    WIFI_AUTH_WPA_WPA2_PSK,  /**< authenticate mode : WPA_WPA2_PSK */
-    WIFI_AUTH_MAX
-} wifi_auth_mode_t;
-
-enum {
-    WIFI_REASON_UNSPECIFIED              = 1,
-    WIFI_REASON_AUTH_EXPIRE              = 2,
-    WIFI_REASON_AUTH_LEAVE               = 3,
-    WIFI_REASON_ASSOC_EXPIRE             = 4,
-    WIFI_REASON_ASSOC_TOOMANY            = 5,
-    WIFI_REASON_NOT_AUTHED               = 6,
-    WIFI_REASON_NOT_ASSOCED              = 7,
-    WIFI_REASON_ASSOC_LEAVE              = 8,
-    WIFI_REASON_ASSOC_NOT_AUTHED         = 9,
-    WIFI_REASON_DISASSOC_PWRCAP_BAD      = 10,
-    WIFI_REASON_DISASSOC_SUPCHAN_BAD     = 11,
-    WIFI_REASON_IE_INVALID               = 13,
-    WIFI_REASON_MIC_FAILURE              = 14,
-    WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,
-    WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
-    WIFI_REASON_IE_IN_4WAY_DIFFERS       = 17,
-    WIFI_REASON_GROUP_CIPHER_INVALID     = 18,
-    WIFI_REASON_PAIRWISE_CIPHER_INVALID  = 19,
-    WIFI_REASON_AKMP_INVALID             = 20,
-    WIFI_REASON_UNSUPP_RSN_IE_VERSION    = 21,
-    WIFI_REASON_INVALID_RSN_IE_CAP       = 22,
-    WIFI_REASON_802_1X_AUTH_FAILED       = 23,
-    WIFI_REASON_CIPHER_SUITE_REJECTED    = 24,
-
-    WIFI_REASON_BEACON_TIMEOUT           = 200,
-    WIFI_REASON_NO_AP_FOUND              = 201,
-    WIFI_REASON_AUTH_FAIL                = 202,
-    WIFI_REASON_ASSOC_FAIL               = 203,
-    WIFI_REASON_HANDSHAKE_TIMEOUT        = 204,
-};
-
-typedef enum {
-    WIFI_SECOND_CHAN_NONE = 0,  /**< the channel width is HT20 */
-    WIFI_SECOND_CHAN_ABOVE,     /**< the channel width is HT40 and the second channel is above the primary channel */
-    WIFI_SECOND_CHAN_BELOW,     /**< the channel width is HT40 and the second channel is below the primary channel */
-} wifi_second_chan_t;
-
-/**
-  * @brief     startup WiFi driver and register application specific callback function
-  *
-  * @attention 1. This API should be called in application startup code to init WiFi driver
-  * @attention 2. The callback function is used to provide application specific WiFi configuration,
-  *               such as, set the WiFi mode, register the event callback, set AP SSID etc before
-  *               WiFi is startup
-  * @attention 3. Avoid to create application task in the callback, otherwise you may get wrong behavior
-  * @attention 4. If the callback return is not ESP_OK, the startup will fail!
-  * @attention 5. Before this API can be called, system_init()/esp_event_init()/tcpip_adapter_init() should
-  *               be called firstly
-  *
-  * @param  wifi_startup_cb_t cb : application specific callback function
-  * @param  void *ctx : reserved for user
-  *
-  * @return ESP_OK : succeed
-  * @return others : fail
-  */
-typedef esp_err_t (* wifi_startup_cb_t)(void *ctx);
-
-esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx);
-
 typedef struct {
 typedef struct {
-    void    *event_q;                 /**< WiFi event q handler, it's a freeRTOS queue */
-    uint8_t rx_ba_win;                /**< TBC */
-    uint8_t tx_ba_win;                /**< TBC */
-    uint8_t rx_buf_cnt;               /**< TBC */
-    uint8_t tx_buf_cnt;               /**< TBC */
+    system_event_handler_t event_handler;  /**< WiFi event handler */
 } wifi_init_config_t;
 } wifi_init_config_t;
 
 
+
+#define WIFI_INIT_CONFIG_DEFAULT() { \
+    .event_handler = &esp_event_send, \
+};
+
 /**
 /**
   * @brief  Init WiFi
   * @brief  Init WiFi
   *         Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer,
   *         Alloc resource for WiFi driver, such as WiFi control structure, RX/TX buffer,
@@ -176,7 +89,6 @@ typedef struct {
   *               to this queue when event happens, such as, when station connects to WiFi, WiFi driver
   *               to this queue when event happens, such as, when station connects to WiFi, WiFi driver
   *               will post station connected event to this queue. If the queue is not initialized, WiFi
   *               will post station connected event to this queue. If the queue is not initialized, WiFi
   *               will not post any events
   *               will not post any events
-  * @attention 3. For other parameters, currently it's not ready, just ignore it.
   *
   *
   * @param  wifi_init_config_t *config : provide WiFi init configuration
   * @param  wifi_init_config_t *config : provide WiFi init configuration
   *
   *
@@ -288,13 +200,6 @@ esp_err_t esp_wifi_clear_fast_connect(void);
   */
   */
 esp_err_t esp_wifi_kick_station(uint16_t aid);
 esp_err_t esp_wifi_kick_station(uint16_t aid);
 
 
-typedef struct {
-    char *ssid;          /**< SSID of AP */
-    uint8_t *bssid;      /**< MAC address of AP */
-    uint8_t channel;     /**< channel, scan the specific channel */
-    bool show_hidden;    /**< enable to scan AP whose SSID is hidden */
-} wifi_scan_config_t;
-
 /**
 /**
   * @brief     Scan all available APs.
   * @brief     Scan all available APs.
   *
   *
@@ -332,15 +237,6 @@ esp_err_t esp_wifi_scan_stop(void);
   */
   */
 esp_err_t esp_wifi_get_ap_num(uint16_t *number);
 esp_err_t esp_wifi_get_ap_num(uint16_t *number);
 
 
-typedef struct {
-    uint8_t bssid[6];                     /**< MAC address of AP */
-    uint8_t ssid[32];                     /**< SSID of AP */
-    uint8_t primary;                      /**< channel of AP */
-    wifi_second_chan_t second;            /**< second channel of AP */
-    int8_t  rssi;                         /**< signal strength of AP */
-    wifi_auth_mode_t authmode;            /**< authmode of AP */
-} wifi_ap_list_t;
-
 /**
 /**
   * @brief     Get AP list found in last scan
   * @brief     Get AP list found in last scan
   *
   *
@@ -353,13 +249,6 @@ typedef struct {
   */
   */
 esp_err_t esp_wifi_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list);
 esp_err_t esp_wifi_get_ap_list(uint16_t *number, wifi_ap_list_t *ap_list);
 
 
-typedef enum {
-    WIFI_PS_NONE,    /**< No power save */
-    WIFI_PS_MODEM,   /**< Modem power save */
-    WIFI_PS_LIGHT,   /**< Light power save */
-    WIFI_PS_MAC,     /**< MAC power save */
-} wifi_ps_type_t;
-
 /**
 /**
   * @brief     Set current power save type
   * @brief     Set current power save type
   *
   *
@@ -380,10 +269,6 @@ esp_err_t esp_wifi_set_ps(wifi_ps_type_t type);
   */
   */
 esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
 esp_err_t esp_wifi_get_ps(wifi_ps_type_t *type);
 
 
-#define WIFI_PROTOCOL_11B         1
-#define WIFI_PROTOCOL_11G         2
-#define WIFI_PROTOCOL_11N         4
-
 /**
 /**
   * @brief     Set protocol type of specified interface
   * @brief     Set protocol type of specified interface
   *            The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N)
   *            The default protocol is (WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N)
@@ -409,11 +294,6 @@ esp_err_t esp_wifi_set_protocol(wifi_interface_t ifx, uint8_t protocol_bitmap);
   */
   */
 esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
 esp_err_t esp_wifi_get_protocol(wifi_interface_t ifx, uint8_t *protocol_bitmap);
 
 
-typedef enum {
-    WIFI_BW_HT20 = 0, /* Bandwidth is HT20 */
-    WIFI_BW_HT40,     /* Bandwidth is HT40 */
-} wifi_bandwidth_t;
-
 /**
 /**
   * @brief     Set the bandwidth of ESP32 specified interface
   * @brief     Set the bandwidth of ESP32 specified interface
   *
   *
@@ -542,45 +422,22 @@ esp_err_t esp_wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb);
 /**
 /**
   * @brief     Enable the promiscuous mode.
   * @brief     Enable the promiscuous mode.
   *
   *
-  * @param     uint8 promiscuous : 0 - disable / 1 - enable
+  * @param     bool promiscuous : false - disable / true - enable
   *
   *
   * @return    ESP_OK : succeed
   * @return    ESP_OK : succeed
   * @return    others : fail
   * @return    others : fail
   */
   */
-esp_err_t esp_wifi_set_promiscuous(uint8_t enable);
+esp_err_t esp_wifi_set_promiscuous(bool en);
 
 
 /**
 /**
   * @brief     Get the promiscuous mode.
   * @brief     Get the promiscuous mode.
   *
   *
-  * @param     uint8 *enable : store the current status of promiscuous mode
+  * @param     bool *enable : store the current status of promiscuous mode
   *
   *
   * @return    ESP_OK : succeed
   * @return    ESP_OK : succeed
   * @return    others : fail
   * @return    others : fail
   */
   */
-esp_err_t esp_wifi_get_promiscuous(uint8_t *enable);
-
-typedef struct {
-    char ssid[32];              /**< SSID of ESP32 soft-AP */
-    char password[64];          /**< Password of ESP32 soft-AP */
-    uint8_t ssid_len;           /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
-    uint8_t channel;            /**< Channel of ESP32 soft-AP */
-    wifi_auth_mode_t authmode;  /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
-    uint8_t ssid_hidden;        /**< Broadcast SSID or not, default 0, broadcast the SSID */
-    uint8_t max_connection;     /**< Max number of stations allowed to connect in, default 4, max 4 */
-    uint16_t beacon_interval;   /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
-} wifi_ap_config_t;
-
-typedef struct {
-    char ssid[32];         /**< SSID of target AP*/
-    char password[64];     /**< password of target AP*/
-    bool bssid_set;        /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
-    uint8_t bssid[6];     /**< MAC address of target AP*/
-} wifi_sta_config_t;
-
-typedef union {
-    wifi_ap_config_t  ap;  /**< configuration of AP */
-    wifi_sta_config_t sta; /**< configuration of STA */
-} wifi_config_t;
+esp_err_t esp_wifi_get_promiscuous(bool *en);
 
 
 /**
 /**
   * @brief     Set the configuration of the ESP32 STA or AP
   * @brief     Set the configuration of the ESP32 STA or AP
@@ -609,11 +466,6 @@ esp_err_t esp_wifi_set_config(wifi_interface_t ifx, wifi_config_t *conf);
   */
   */
 esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
 esp_err_t esp_wifi_get_config(wifi_interface_t ifx, wifi_config_t *conf);
 
 
-struct station_info {
-    STAILQ_ENTRY(station_info) next;
-    uint8_t bssid[6];
-};
-
 /**
 /**
   * @brief     Get STAs associated with soft-AP
   * @brief     Get STAs associated with soft-AP
   *
   *
@@ -628,11 +480,6 @@ esp_err_t esp_wifi_get_station_list(struct station_info **station);
 
 
 esp_err_t esp_wifi_free_station_list(void);
 esp_err_t esp_wifi_free_station_list(void);
 
 
-typedef enum {
-    WIFI_STORAGE_FLASH,  /**< all configuration will strore in both memory and flash */
-    WIFI_STORAGE_RAM,    /**< all configuration will only store in the memory */
-} wifi_storage_t;
-
 /**
 /**
   * @brief     Set the WiFi API configuration storage type
   * @brief     Set the WiFi API configuration storage type
   *
   *
@@ -689,27 +536,6 @@ esp_err_t esp_wifi_set_auto_connect(bool en);
   */
   */
 esp_err_t esp_wifi_get_auto_connect(bool *en);
 esp_err_t esp_wifi_get_auto_connect(bool *en);
 
 
-/**
-  * @brief     Vendor IE type
-  *
-  */
-typedef enum {
-    WIFI_VND_IE_TYPE_BEACON,
-    WIFI_VND_IE_TYPE_PROBE_REQ,
-    WIFI_VND_IE_TYPE_PROBE_RESP,
-    WIFI_VND_IE_TYPE_ASSOC_REQ,
-    WIFI_VND_IE_TYPE_ASSOC_RESP,
-} wifi_vendor_ie_type_t;
-
-/**
-  * @brief     Vendor IE index
-  *
-  */
-typedef enum {
-    WIFI_VND_IE_ID_0,
-    WIFI_VND_IE_ID_1,
-} wifi_vendor_ie_id_t;
-
 /**
 /**
   * @brief     Set vendor specific element
   * @brief     Set vendor specific element
   *
   *

+ 190 - 0
components/esp32/include/esp_wifi_types.h

@@ -0,0 +1,190 @@
+// 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_WIFI_TYPES_H__
+#define __ESP_WIFI_TYPES_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "rom/queue.h"
+#include "esp_err.h"
+#include "esp_wifi_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    WIFI_MODE_NULL = 0,  /**< null mode */
+    WIFI_MODE_STA,       /**< WiFi station mode */
+    WIFI_MODE_AP,        /**< WiFi soft-AP mode */
+    WIFI_MODE_APSTA,     /**< WiFi station + soft-AP mode */
+    WIFI_MODE_MAX
+} wifi_mode_t;
+
+typedef enum {
+    WIFI_IF_STA = 0,     /**< ESP32 station interface */
+    WIFI_IF_AP,          /**< ESP32 soft-AP interface */
+    WIFI_IF_MAX
+} wifi_interface_t;
+
+typedef enum {
+    WIFI_COUNTRY_CN = 0, /**< country China, channel range [1, 14] */
+    WIFI_COUNTRY_JP,     /**< country Japan, channel range [1, 14] */
+    WIFI_COUNTRY_US,     /**< country USA, channel range [1, 11] */
+    WIFI_COUNTRY_EU,     /**< country Europe, channel range [1, 13] */
+    WIFI_COUNTRY_MAX
+} wifi_country_t;
+
+typedef enum {
+    WIFI_AUTH_OPEN = 0,      /**< authenticate mode : open */
+    WIFI_AUTH_WEP,           /**< authenticate mode : WEP */
+    WIFI_AUTH_WPA_PSK,       /**< authenticate mode : WPA_PSK */
+    WIFI_AUTH_WPA2_PSK,      /**< authenticate mode : WPA2_PSK */
+    WIFI_AUTH_WPA_WPA2_PSK,  /**< authenticate mode : WPA_WPA2_PSK */
+    WIFI_AUTH_MAX
+} wifi_auth_mode_t;
+
+enum {
+    WIFI_REASON_UNSPECIFIED              = 1,
+    WIFI_REASON_AUTH_EXPIRE              = 2,
+    WIFI_REASON_AUTH_LEAVE               = 3,
+    WIFI_REASON_ASSOC_EXPIRE             = 4,
+    WIFI_REASON_ASSOC_TOOMANY            = 5,
+    WIFI_REASON_NOT_AUTHED               = 6,
+    WIFI_REASON_NOT_ASSOCED              = 7,
+    WIFI_REASON_ASSOC_LEAVE              = 8,
+    WIFI_REASON_ASSOC_NOT_AUTHED         = 9,
+    WIFI_REASON_DISASSOC_PWRCAP_BAD      = 10,
+    WIFI_REASON_DISASSOC_SUPCHAN_BAD     = 11,
+    WIFI_REASON_IE_INVALID               = 13,
+    WIFI_REASON_MIC_FAILURE              = 14,
+    WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT   = 15,
+    WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT = 16,
+    WIFI_REASON_IE_IN_4WAY_DIFFERS       = 17,
+    WIFI_REASON_GROUP_CIPHER_INVALID     = 18,
+    WIFI_REASON_PAIRWISE_CIPHER_INVALID  = 19,
+    WIFI_REASON_AKMP_INVALID             = 20,
+    WIFI_REASON_UNSUPP_RSN_IE_VERSION    = 21,
+    WIFI_REASON_INVALID_RSN_IE_CAP       = 22,
+    WIFI_REASON_802_1X_AUTH_FAILED       = 23,
+    WIFI_REASON_CIPHER_SUITE_REJECTED    = 24,
+
+    WIFI_REASON_BEACON_TIMEOUT           = 200,
+    WIFI_REASON_NO_AP_FOUND              = 201,
+    WIFI_REASON_AUTH_FAIL                = 202,
+    WIFI_REASON_ASSOC_FAIL               = 203,
+    WIFI_REASON_HANDSHAKE_TIMEOUT        = 204,
+};
+
+typedef enum {
+    WIFI_SECOND_CHAN_NONE = 0,  /**< the channel width is HT20 */
+    WIFI_SECOND_CHAN_ABOVE,     /**< the channel width is HT40 and the second channel is above the primary channel */
+    WIFI_SECOND_CHAN_BELOW,     /**< the channel width is HT40 and the second channel is below the primary channel */
+} wifi_second_chan_t;
+
+typedef struct {
+    char *ssid;          /**< SSID of AP */
+    uint8_t *bssid;      /**< MAC address of AP */
+    uint8_t channel;     /**< channel, scan the specific channel */
+    bool show_hidden;    /**< enable to scan AP whose SSID is hidden */
+} wifi_scan_config_t;
+
+typedef struct {
+    uint8_t bssid[6];                     /**< MAC address of AP */
+    uint8_t ssid[32];                     /**< SSID of AP */
+    uint8_t primary;                      /**< channel of AP */
+    wifi_second_chan_t second;            /**< second channel of AP */
+    int8_t  rssi;                         /**< signal strength of AP */
+    wifi_auth_mode_t authmode;            /**< authmode of AP */
+} wifi_ap_list_t;
+
+typedef enum {
+    WIFI_PS_NONE,    /**< No power save */
+    WIFI_PS_MODEM,   /**< Modem power save */
+    WIFI_PS_LIGHT,   /**< Light power save */
+    WIFI_PS_MAC,     /**< MAC power save */
+} wifi_ps_type_t;
+
+#define WIFI_PROTOCOL_11B         1
+#define WIFI_PROTOCOL_11G         2
+#define WIFI_PROTOCOL_11N         4
+
+typedef enum {
+    WIFI_BW_HT20 = 0, /* Bandwidth is HT20 */
+    WIFI_BW_HT40,     /* Bandwidth is HT40 */
+} wifi_bandwidth_t;
+
+typedef struct {
+    char ssid[32];              /**< SSID of ESP32 soft-AP */
+    char password[64];          /**< Password of ESP32 soft-AP */
+    uint8_t ssid_len;           /**< Length of SSID. If softap_config.ssid_len==0, check the SSID until there is a termination character; otherwise, set the SSID length according to softap_config.ssid_len. */
+    uint8_t channel;            /**< Channel of ESP32 soft-AP */
+    wifi_auth_mode_t authmode;  /**< Auth mode of ESP32 soft-AP. Do not support AUTH_WEP in soft-AP mode */
+    uint8_t ssid_hidden;        /**< Broadcast SSID or not, default 0, broadcast the SSID */
+    uint8_t max_connection;     /**< Max number of stations allowed to connect in, default 4, max 4 */
+    uint16_t beacon_interval;   /**< Beacon interval, 100 ~ 60000 ms, default 100 ms */
+} wifi_ap_config_t;
+
+typedef struct {
+    char ssid[32];         /**< SSID of target AP*/
+    char password[64];     /**< password of target AP*/
+    bool bssid_set;        /**< whether set MAC address of target AP or not. Generally, station_config.bssid_set needs to be 0; and it needs to be 1 only when users need to check the MAC address of the AP.*/
+    uint8_t bssid[6];     /**< MAC address of target AP*/
+} wifi_sta_config_t;
+
+typedef union {
+    wifi_ap_config_t  ap;  /**< configuration of AP */
+    wifi_sta_config_t sta; /**< configuration of STA */
+} wifi_config_t;
+
+struct station_info {
+    STAILQ_ENTRY(station_info) next;
+    uint8_t bssid[6];
+};
+
+typedef enum {
+    WIFI_STORAGE_FLASH,  /**< all configuration will strore in both memory and flash */
+    WIFI_STORAGE_RAM,    /**< all configuration will only store in the memory */
+} wifi_storage_t;
+
+/**
+  * @brief     Vendor IE type
+  *
+  */
+typedef enum {
+    WIFI_VND_IE_TYPE_BEACON,
+    WIFI_VND_IE_TYPE_PROBE_REQ,
+    WIFI_VND_IE_TYPE_PROBE_RESP,
+    WIFI_VND_IE_TYPE_ASSOC_REQ,
+    WIFI_VND_IE_TYPE_ASSOC_RESP,
+} wifi_vendor_ie_type_t;
+
+/**
+  * @brief     Vendor IE index
+  *
+  */
+typedef enum {
+    WIFI_VND_IE_ID_0,
+    WIFI_VND_IE_ID_1,
+} wifi_vendor_ie_id_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __ESP_WIFI_TYPES_H__ */

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

@@ -1,131 +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.
-
-#ifndef __ESP_WPS_H__
-#define __ESP_WPS_H__
-
-#include <stdbool.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
-  * @{
-  */
-
-typedef enum wps_type {
-    WPS_TYPE_DISABLE = 0,
-    WPS_TYPE_PBC,
-    WPS_TYPE_PIN,
-    WPS_TYPE_DISPLAY,
-    WPS_TYPE_MAX,
-} WPS_TYPE_t;
-
-enum wps_cb_status {
-    WPS_CB_ST_SUCCESS = 0,     /**< WPS succeed */
-    WPS_CB_ST_FAILED,          /**< WPS fail */
-    WPS_CB_ST_TIMEOUT,         /**< WPS timeout, fail */
-    WPS_CB_ST_WEP,             /**< WPS failed because that WEP is not supported */
-    WPS_CB_ST_SCAN_ERR,        /**< can not find the target WPS AP */
-};
-
-/**
-  * @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 is supported
-  *
-  * @return    true  : succeed
-  * @return    false : fail
-  */
-bool wifi_wps_enable(WPS_TYPE_t wps_type);
-
-/**
-  * @brief  Disable Wi-Fi WPS function and release resource it taken.
-  *
-  * @param  null
-  *
-  * @return true  : succeed
-  * @return false : fail
-  */
-bool wifi_wps_disable(void);
-
-/**
-  * @brief     WPS starts to work.
-  *
-  * @attention WPS can only be used when ESP32 station is enabled.
-  *
-  * @param     null
-  *
-  * @return    true  : WPS starts to work successfully, but does not mean WPS succeed.
-  * @return    false : fail
-  */
-bool wifi_wps_start(void);
-
-/**
-  * @brief  WPS callback.
-  *
-  * @param  int status : status of WPS, enum wps_cb_status.
-  *    -  If parameter status == WPS_CB_ST_SUCCESS in WPS callback, it means WPS got AP's
-  *       information, user can call wifi_wps_disable to disable WPS and release resource,
-  *       then call wifi_station_connect to connect to target AP.
-  *    -  Otherwise, it means that WPS fail, user can create a timer to retry WPS by
-  *       wifi_wps_start after a while, or call wifi_wps_disable to disable WPS and release resource.
-  *
-  * @return null
-  */
-typedef void (*wps_st_cb_t)(int status);
-
-/**
-  * @brief     Set WPS callback.
-  *
-  * @attention WPS can only be used when ESP32 station is enabled.
-  *
-  * @param     wps_st_cb_t cb : callback.
-  *
-  * @return    true  : WPS starts to work successfully, but does not mean WPS succeed.
-  * @return    false : fail
-  */
-bool wifi_set_wps_cb(wps_st_cb_t cb);
-
-/**
-  * @}
-  */
-
-/**
-  * @}
-  */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __ESP_WPS_H__ */

+ 13 - 13
components/esp32/include/rom/rtc.h

@@ -44,25 +44,25 @@ extern "C" {
   *************************************************************************************
   *************************************************************************************
   *     rtc memory addr         type    size            usage
   *     rtc memory addr         type    size            usage
   *     0x3ff61000(0x50000000)  Slow    SIZE_CP         Co-Processor code/Reset Entry
   *     0x3ff61000(0x50000000)  Slow    SIZE_CP         Co-Processor code/Reset Entry
-  *     0x3ff61000+SIZE_CP      Slow    6144-SIZE_CP
-  *     0x3ff62800              Slow    2048            Reserved
+  *     0x3ff61000+SIZE_CP      Slow    4096-SIZE_CP
+  *     0x3ff62800              Slow    4096            Reserved
   *
   *
   *     0x3ff80000(0x400c0000)  Fast    8192            deep sleep entry code
   *     0x3ff80000(0x400c0000)  Fast    8192            deep sleep entry code
   *
   *
   *************************************************************************************
   *************************************************************************************
   *     Rtc store registers     usage
   *     Rtc store registers     usage
-  *     RTC_STORE0
-  *     RTC_STORE1
-  *     RTC_STORE2
-  *     RTC_STORE3
-  *     RTC_STORE4              Reserved
-  *     RTC_STORE5              External Xtal Frequency
-  *     RTC_STORE6              FAST_RTC_MEMORY_ENTRY
-  *     RTC_STORE7              FAST_RTC_MEMORY_CRC
+  *     RTC_CNTL_STORE0_REG
+  *     RTC_CNTL_STORE1_REG
+  *     RTC_CNTL_STORE2_REG
+  *     RTC_CNTL_STORE3_REG
+  *     RTC_CNTL_STORE4_REG     Reserved
+  *     RTC_CNTL_STORE5_REG     External Xtal Frequency
+  *     RTC_CNTL_STORE6_REG     FAST_RTC_MEMORY_ENTRY
+  *     RTC_CNTL_STORE7_REG     FAST_RTC_MEMORY_CRC
   *************************************************************************************
   *************************************************************************************
   */
   */
-#define RTC_ENTRY_ADDR RTC_STORE6
-#define RTC_MEMORY_CRC RTC_STORE7
+#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
+#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
 
 
 
 
 typedef enum {
 typedef enum {
@@ -161,7 +161,7 @@ WAKEUP_REASON rtc_get_wakeup_cause(void);
   *
   *
   * @param  uint32_t start_addr : 0 - 0x7ff for Fast RTC Memory.
   * @param  uint32_t start_addr : 0 - 0x7ff for Fast RTC Memory.
   *
   *
-  * @param  uint32_t crc_len : 0 - 0x7ff, 0 for 1 byte, 0x7ff for 0x800 byte.
+  * @param  uint32_t crc_len : 0 - 0x7ff, 0 for 4 byte, 0x7ff for 0x2000 byte.
   *
   *
   * @return uint32_t : CRC32 result
   * @return uint32_t : CRC32 result
   */
   */

+ 126 - 124
components/esp32/include/soc/io_mux_reg.h

@@ -40,6 +40,8 @@
 #define PIN_PULLDWN_EN(PIN_NAME)              REG_SET_BIT(PIN_NAME, FUN_PD)
 #define PIN_PULLDWN_EN(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_SELECT(PIN_NAME, FUNC)      REG_SET_FIELD(PIN_NAME, MCU_SEL, FUNC)
 
 
+#define PIN_FUNC_GPIO                               2
+
 #define PIN_CTRL                          (DR_REG_IO_MUX_BASE +0x00)
 #define PIN_CTRL                          (DR_REG_IO_MUX_BASE +0x00)
 #define CLK_OUT3                                    0xf
 #define CLK_OUT3                                    0xf
 #define CLK_OUT3_S                                  8
 #define CLK_OUT3_S                                  8
@@ -48,60 +50,86 @@
 #define CLK_OUT1                                    0xf
 #define CLK_OUT1                                    0xf
 #define CLK_OUT1_S                                  0
 #define CLK_OUT1_S                                  0
 
 
-#define PERIPHS_IO_MUX_GPIO36_U           (DR_REG_IO_MUX_BASE +0x04)
-#define FUNC_GPIO36_GPIO36                          2
-#define FUNC_GPIO36_GPIO36_0                        0
+#define PERIPHS_IO_MUX_GPIO0_U            (DR_REG_IO_MUX_BASE +0x44)
+#define FUNC_GPIO0_EMAC_TX_CLK                      5
+#define FUNC_GPIO0_GPIO0                            2
+#define FUNC_GPIO0_CLK_OUT1                         1
+#define FUNC_GPIO0_GPIO0_0                          0
 
 
-#define PERIPHS_IO_MUX_GPIO37_U           (DR_REG_IO_MUX_BASE +0x08)
-#define FUNC_GPIO37_GPIO37                          2
-#define FUNC_GPIO37_GPIO37_0                        0
+#define PERIPHS_IO_MUX_U0TXD_U            (DR_REG_IO_MUX_BASE +0x88)
+#define FUNC_U0TXD_EMAC_RXD2                        3
+#define FUNC_U0TXD_GPIO1                            2
+#define FUNC_U0TXD_CLK_OUT3                         1
+#define FUNC_U0TXD_U0TXD                            0
 
 
-#define PERIPHS_IO_MUX_GPIO38_U           (DR_REG_IO_MUX_BASE +0x0c)
-#define FUNC_GPIO38_GPIO38                          2
-#define FUNC_GPIO38_GPIO38_0                        0
+#define PERIPHS_IO_MUX_GPIO2_U            (DR_REG_IO_MUX_BASE +0x40)
+#define FUNC_GPIO2_SD_DATA0                         4
+#define FUNC_GPIO2_HS2_DATA0                        3
+#define FUNC_GPIO2_GPIO2                            2
+#define FUNC_GPIO2_HSPIWP                           1
+#define FUNC_GPIO2_GPIO2_0                          0
 
 
-#define PERIPHS_IO_MUX_GPIO39_U           (DR_REG_IO_MUX_BASE +0x10)
-#define FUNC_GPIO39_GPIO39                          2
-#define FUNC_GPIO39_GPIO39_0                        0
+#define PERIPHS_IO_MUX_U0RXD_U            (DR_REG_IO_MUX_BASE +0x84)
+#define FUNC_U0RXD_GPIO3                            2
+#define FUNC_U0RXD_CLK_OUT2                         1
+#define FUNC_U0RXD_U0RXD                            0
 
 
-#define PERIPHS_IO_MUX_GPIO34_U           (DR_REG_IO_MUX_BASE +0x14)
-#define FUNC_GPIO34_GPIO34                          2
-#define FUNC_GPIO34_GPIO34_0                        0
+#define PERIPHS_IO_MUX_GPIO4_U            (DR_REG_IO_MUX_BASE +0x48)
+#define FUNC_GPIO4_EMAC_TX_ER                       5
+#define FUNC_GPIO4_SD_DATA1                         4
+#define FUNC_GPIO4_HS2_DATA1                        3
+#define FUNC_GPIO4_GPIO4                            2
+#define FUNC_GPIO4_HSPIHD                           1
+#define FUNC_GPIO4_GPIO4_0                          0
 
 
-#define PERIPHS_IO_MUX_GPIO35_U           (DR_REG_IO_MUX_BASE +0x18)
-#define FUNC_GPIO35_GPIO35                          2
-#define FUNC_GPIO35_GPIO35_0                        0
+#define PERIPHS_IO_MUX_GPIO5_U            (DR_REG_IO_MUX_BASE +0x6c)
+#define FUNC_GPIO5_EMAC_RX_CLK                      5
+#define FUNC_GPIO5_HS1_DATA6                        3
+#define FUNC_GPIO5_GPIO5                            2
+#define FUNC_GPIO5_VSPICS0                          1
+#define FUNC_GPIO5_GPIO5_0                          0
 
 
-#define PERIPHS_IO_MUX_GPIO32_U           (DR_REG_IO_MUX_BASE +0x1c)
-#define FUNC_GPIO32_GPIO32                          2
-#define FUNC_GPIO32_GPIO32_0                        0
+#define PERIPHS_IO_MUX_SD_CLK_U           (DR_REG_IO_MUX_BASE +0x60)
+#define FUNC_SD_CLK_U1CTS                           4
+#define FUNC_SD_CLK_HS1_CLK                         3
+#define FUNC_SD_CLK_GPIO6                           2
+#define FUNC_SD_CLK_SPICLK                          1
+#define FUNC_SD_CLK_SD_CLK                          0
 
 
-#define PERIPHS_IO_MUX_GPIO33_U           (DR_REG_IO_MUX_BASE +0x20)
-#define FUNC_GPIO33_GPIO33                          2
-#define FUNC_GPIO33_GPIO33_0                        0
+#define PERIPHS_IO_MUX_SD_DATA0_U         (DR_REG_IO_MUX_BASE +0x64)
+#define FUNC_SD_DATA0_U2RTS                         4
+#define FUNC_SD_DATA0_HS1_DATA0                     3
+#define FUNC_SD_DATA0_GPIO7                         2
+#define FUNC_SD_DATA0_SPIQ                          1
+#define FUNC_SD_DATA0_SD_DATA0                      0
 
 
-#define PERIPHS_IO_MUX_GPIO25_U           (DR_REG_IO_MUX_BASE +0x24)
-#define FUNC_GPIO25_EMAC_RXD0                       5 
-#define FUNC_GPIO25_GPIO25                          2
-#define FUNC_GPIO25_GPIO25_0                        0
+#define PERIPHS_IO_MUX_SD_DATA1_U         (DR_REG_IO_MUX_BASE +0x68)
+#define FUNC_SD_DATA1_U2CTS                         4
+#define FUNC_SD_DATA1_HS1_DATA1                     3
+#define FUNC_SD_DATA1_GPIO8                         2
+#define FUNC_SD_DATA1_SPID                          1
+#define FUNC_SD_DATA1_SD_DATA1                      0
 
 
-#define PERIPHS_IO_MUX_GPIO26_U           (DR_REG_IO_MUX_BASE +0x28)
-#define FUNC_GPIO26_EMAC_RXD1                       5
-#define FUNC_GPIO26_GPIO26                          2
-#define FUNC_GPIO26_GPIO26_0                        0
+#define PERIPHS_IO_MUX_SD_DATA2_U         (DR_REG_IO_MUX_BASE +0x54)
+#define FUNC_SD_DATA2_U1RXD                         4
+#define FUNC_SD_DATA2_HS1_DATA2                     3
+#define FUNC_SD_DATA2_GPIO9                         2
+#define FUNC_SD_DATA2_SPIHD                         1
+#define FUNC_SD_DATA2_SD_DATA2                      0
 
 
-#define PERIPHS_IO_MUX_GPIO27_U           (DR_REG_IO_MUX_BASE +0x2c)
-#define FUNC_GPIO27_EMAC_RX_DV                      5
-#define FUNC_GPIO27_GPIO27                          2
-#define FUNC_GPIO27_GPIO27_0                        0
+#define PERIPHS_IO_MUX_SD_DATA3_U         (DR_REG_IO_MUX_BASE +0x58)
+#define FUNC_SD_DATA3_U1TXD                         4
+#define FUNC_SD_DATA3_HS1_DATA3                     3
+#define FUNC_SD_DATA3_GPIO10                        2
+#define FUNC_SD_DATA3_SPIWP                         1
+#define FUNC_SD_DATA3_SD_DATA3                      0
 
 
-#define PERIPHS_IO_MUX_MTMS_U             (DR_REG_IO_MUX_BASE +0x30)
-#define FUNC_MTMS_EMAC_TXD2                         5
-#define FUNC_MTMS_SD_CLK                            4
-#define FUNC_MTMS_HS2_CLk                           3
-#define FUNC_MTMS_GPIO14                            2
-#define FUNC_MTMS_HSPICLK                           1
-#define FUNC_MTMS_MTMS                              0
+#define PERIPHS_IO_MUX_SD_CMD_U           (DR_REG_IO_MUX_BASE +0x5c)
+#define FUNC_SD_CMD_U1RTS                           4
+#define FUNC_SD_CMD_HS1_CMD                         3
+#define FUNC_SD_CMD_GPIO11                          2
+#define FUNC_SD_CMD_SPICS0                          1
+#define FUNC_SD_CMD_SD_CMD                          0
 
 
 #define PERIPHS_IO_MUX_MTDI_U             (DR_REG_IO_MUX_BASE +0x34)
 #define PERIPHS_IO_MUX_MTDI_U             (DR_REG_IO_MUX_BASE +0x34)
 #define FUNC_MTDI_EMAC_TXD3                         5
 #define FUNC_MTDI_EMAC_TXD3                         5
@@ -119,6 +147,14 @@
 #define FUNC_MTCK_HSPID                             1
 #define FUNC_MTCK_HSPID                             1
 #define FUNC_MTCK_MTCK                              0
 #define FUNC_MTCK_MTCK                              0
 
 
+#define PERIPHS_IO_MUX_MTMS_U             (DR_REG_IO_MUX_BASE +0x30)
+#define FUNC_MTMS_EMAC_TXD2                         5
+#define FUNC_MTMS_SD_CLK                            4
+#define FUNC_MTMS_HS2_CLk                           3
+#define FUNC_MTMS_GPIO14                            2
+#define FUNC_MTMS_HSPICLK                           1
+#define FUNC_MTMS_MTMS                              0
+
 #define PERIPHS_IO_MUX_MTDO_U             (DR_REG_IO_MUX_BASE +0x3c)
 #define PERIPHS_IO_MUX_MTDO_U             (DR_REG_IO_MUX_BASE +0x3c)
 #define FUNC_MTDO_EMAC_RXD3                         5
 #define FUNC_MTDO_EMAC_RXD3                         5
 #define FUNC_MTDO_SD_CMD                            4
 #define FUNC_MTDO_SD_CMD                            4
@@ -127,27 +163,6 @@
 #define FUNC_MTDO_HSPICS0                           1
 #define FUNC_MTDO_HSPICS0                           1
 #define FUNC_MTDO_MTDO                              0
 #define FUNC_MTDO_MTDO                              0
 
 
-#define PERIPHS_IO_MUX_GPIO2_U            (DR_REG_IO_MUX_BASE +0x40)
-#define FUNC_GPIO2_SD_DATA0                         4
-#define FUNC_GPIO2_HS2_DATA0                        3
-#define FUNC_GPIO2_GPIO2                            2
-#define FUNC_GPIO2_HSPIWP                           1
-#define FUNC_GPIO2_GPIO2_0                          0
-
-#define PERIPHS_IO_MUX_GPIO0_U            (DR_REG_IO_MUX_BASE +0x44)
-#define FUNC_GPIO0_EMAC_TX_CLK                      5
-#define FUNC_GPIO0_GPIO0                            2
-#define FUNC_GPIO0_CLK_OUT1                         1
-#define FUNC_GPIO0_GPIO0_0                          0
-
-#define PERIPHS_IO_MUX_GPIO4_U            (DR_REG_IO_MUX_BASE +0x48)
-#define FUNC_GPIO4_EMAC_TX_ER                       5
-#define FUNC_GPIO4_SD_DATA1                         4
-#define FUNC_GPIO4_HS2_DATA1                        3
-#define FUNC_GPIO4_GPIO4                            2
-#define FUNC_GPIO4_HSPIHD                           1
-#define FUNC_GPIO4_GPIO4_0                          0
-
 #define PERIPHS_IO_MUX_GPIO16_U           (DR_REG_IO_MUX_BASE +0x4c)
 #define PERIPHS_IO_MUX_GPIO16_U           (DR_REG_IO_MUX_BASE +0x4c)
 #define FUNC_GPIO16_EMAC_CLK_OUT                    5
 #define FUNC_GPIO16_EMAC_CLK_OUT                    5
 #define FUNC_GPIO16_U2RXD                           4
 #define FUNC_GPIO16_U2RXD                           4
@@ -162,55 +177,6 @@
 #define FUNC_GPIO17_GPIO17                          2
 #define FUNC_GPIO17_GPIO17                          2
 #define FUNC_GPIO17_GPIO17_0                        0
 #define FUNC_GPIO17_GPIO17_0                        0
 
 
-#define PERIPHS_IO_MUX_SD_DATA2_U         (DR_REG_IO_MUX_BASE +0x54)
-#define FUNC_SD_DATA2_U1RXD                         4
-#define FUNC_SD_DATA2_HS1_DATA2                     3
-#define FUNC_SD_DATA2_GPIO9                         2
-#define FUNC_SD_DATA2_SPIHD                         1
-#define FUNC_SD_DATA2_SD_DATA2                      0
-
-#define PERIPHS_IO_MUX_SD_DATA3_U         (DR_REG_IO_MUX_BASE +0x58)
-#define FUNC_SD_DATA3_U1TXD                         4
-#define FUNC_SD_DATA3_HS1_DATA3                     3
-#define FUNC_SD_DATA3_GPIO10                        2
-#define FUNC_SD_DATA3_SPIWP                         1
-#define FUNC_SD_DATA3_SD_DATA3                      0
-
-#define PERIPHS_IO_MUX_SD_CMD_U           (DR_REG_IO_MUX_BASE +0x5c)
-#define FUNC_SD_CMD_U1RTS                           4
-#define FUNC_SD_CMD_HS1_CMD                         3
-#define FUNC_SD_CMD_GPIO11                          2
-#define FUNC_SD_CMD_SPICS0                          1
-#define FUNC_SD_CMD_SD_CMD                          0
-
-#define PERIPHS_IO_MUX_SD_CLK_U           (DR_REG_IO_MUX_BASE +0x60)
-#define FUNC_SD_CLK_U1CTS                           4
-#define FUNC_SD_CLK_HS1_CLK                         3
-#define FUNC_SD_CLK_GPIO6                           2
-#define FUNC_SD_CLK_SPICLK                          1
-#define FUNC_SD_CLK_SD_CLK                          0
-
-#define PERIPHS_IO_MUX_SD_DATA0_U         (DR_REG_IO_MUX_BASE +0x64)
-#define FUNC_SD_DATA0_U2RTS                         4
-#define FUNC_SD_DATA0_HS1_DATA0                     3
-#define FUNC_SD_DATA0_GPIO7                         2
-#define FUNC_SD_DATA0_SPIQ                          1
-#define FUNC_SD_DATA0_SD_DATA0                      0
-
-#define PERIPHS_IO_MUX_SD_DATA1_U         (DR_REG_IO_MUX_BASE +0x68)
-#define FUNC_SD_DATA1_U2CTS                         4
-#define FUNC_SD_DATA1_HS1_DATA1                     3
-#define FUNC_SD_DATA1_GPIO8                         2
-#define FUNC_SD_DATA1_SPID                          1
-#define FUNC_SD_DATA1_SD_DATA1                      0
-
-#define PERIPHS_IO_MUX_GPIO5_U            (DR_REG_IO_MUX_BASE +0x6c)
-#define FUNC_GPIO5_EMAC_RX_CLK                      5
-#define FUNC_GPIO5_HS1_DATA6                        3
-#define FUNC_GPIO5_GPIO5                            2
-#define FUNC_GPIO5_VSPICS0                          1
-#define FUNC_GPIO5_GPIO5_0                          0
-
 #define PERIPHS_IO_MUX_GPIO18_U           (DR_REG_IO_MUX_BASE +0x70)
 #define PERIPHS_IO_MUX_GPIO18_U           (DR_REG_IO_MUX_BASE +0x70)
 #define FUNC_GPIO18_HS1_DATA7                       3
 #define FUNC_GPIO18_HS1_DATA7                       3
 #define FUNC_GPIO18_GPIO18                          2
 #define FUNC_GPIO18_GPIO18                          2
@@ -241,17 +207,6 @@
 #define FUNC_GPIO22_VSPIWP                          1
 #define FUNC_GPIO22_VSPIWP                          1
 #define FUNC_GPIO22_GPIO22_0                        0
 #define FUNC_GPIO22_GPIO22_0                        0
 
 
-#define PERIPHS_IO_MUX_U0RXD_U            (DR_REG_IO_MUX_BASE +0x84)
-#define FUNC_U0RXD_GPIO3                            2
-#define FUNC_U0RXD_CLK_OUT2                         1
-#define FUNC_U0RXD_U0RXD                            0
-
-#define PERIPHS_IO_MUX_U0TXD_U            (DR_REG_IO_MUX_BASE +0x88)
-#define FUNC_U0TXD_EMAC_RXD2                        3
-#define FUNC_U0TXD_GPIO1                            2
-#define FUNC_U0TXD_CLK_OUT3                         1
-#define FUNC_U0TXD_U0TXD                            0
-
 #define PERIPHS_IO_MUX_GPIO23_U           (DR_REG_IO_MUX_BASE +0x8c)
 #define PERIPHS_IO_MUX_GPIO23_U           (DR_REG_IO_MUX_BASE +0x8c)
 #define FUNC_GPIO23_HS1_STROBE                      3
 #define FUNC_GPIO23_HS1_STROBE                      3
 #define FUNC_GPIO23_GPIO23                          2
 #define FUNC_GPIO23_GPIO23                          2
@@ -262,4 +217,51 @@
 #define FUNC_GPIO24_GPIO24                          2
 #define FUNC_GPIO24_GPIO24                          2
 #define FUNC_GPIO24_GPIO24_0                        0
 #define FUNC_GPIO24_GPIO24_0                        0
 
 
+#define PERIPHS_IO_MUX_GPIO25_U           (DR_REG_IO_MUX_BASE +0x24)
+#define FUNC_GPIO25_EMAC_RXD0                       5
+#define FUNC_GPIO25_GPIO25                          2
+#define FUNC_GPIO25_GPIO25_0                        0
+
+#define PERIPHS_IO_MUX_GPIO26_U           (DR_REG_IO_MUX_BASE +0x28)
+#define FUNC_GPIO26_EMAC_RXD1                       5
+#define FUNC_GPIO26_GPIO26                          2
+#define FUNC_GPIO26_GPIO26_0                        0
+
+#define PERIPHS_IO_MUX_GPIO27_U           (DR_REG_IO_MUX_BASE +0x2c)
+#define FUNC_GPIO27_EMAC_RX_DV                      5
+#define FUNC_GPIO27_GPIO27                          2
+#define FUNC_GPIO27_GPIO27_0                        0
+
+#define PERIPHS_IO_MUX_GPIO32_U           (DR_REG_IO_MUX_BASE +0x1c)
+#define FUNC_GPIO32_GPIO32                          2
+#define FUNC_GPIO32_GPIO32_0                        0
+
+#define PERIPHS_IO_MUX_GPIO33_U           (DR_REG_IO_MUX_BASE +0x20)
+#define FUNC_GPIO33_GPIO33                          2
+#define FUNC_GPIO33_GPIO33_0                        0
+
+#define PERIPHS_IO_MUX_GPIO34_U           (DR_REG_IO_MUX_BASE +0x14)
+#define FUNC_GPIO34_GPIO34                          2
+#define FUNC_GPIO34_GPIO34_0                        0
+
+#define PERIPHS_IO_MUX_GPIO35_U           (DR_REG_IO_MUX_BASE +0x18)
+#define FUNC_GPIO35_GPIO35                          2
+#define FUNC_GPIO35_GPIO35_0                        0
+
+#define PERIPHS_IO_MUX_GPIO36_U           (DR_REG_IO_MUX_BASE +0x04)
+#define FUNC_GPIO36_GPIO36                          2
+#define FUNC_GPIO36_GPIO36_0                        0
+
+#define PERIPHS_IO_MUX_GPIO37_U           (DR_REG_IO_MUX_BASE +0x08)
+#define FUNC_GPIO37_GPIO37                          2
+#define FUNC_GPIO37_GPIO37_0                        0
+
+#define PERIPHS_IO_MUX_GPIO38_U           (DR_REG_IO_MUX_BASE +0x0c)
+#define FUNC_GPIO38_GPIO38                          2
+#define FUNC_GPIO38_GPIO38_0                        0
+
+#define PERIPHS_IO_MUX_GPIO39_U           (DR_REG_IO_MUX_BASE +0x10)
+#define FUNC_GPIO39_GPIO39                          2
+#define FUNC_GPIO39_GPIO39_0                        0
+
 #endif /* _SOC_IO_MUX_REG_H_ */
 #endif /* _SOC_IO_MUX_REG_H_ */

+ 68 - 127
components/esp32/include/soc/ledc_struct.h

@@ -14,133 +14,74 @@
 #ifndef _SOC_LEDC_STRUCT_H_
 #ifndef _SOC_LEDC_STRUCT_H_
 #define _SOC_LEDC_STRUCT_H_
 #define _SOC_LEDC_STRUCT_H_
 typedef volatile struct {
 typedef volatile struct {
-    struct{
-        union {
-            struct {
-                uint32_t timer_sel:  2;              /*There are four high speed timers  the two bits are used to select one of them for high speed channel.  2'b00: seletc hstimer0.   2'b01: select hstimer1.  2'b10: select hstimer2.    2'b11: select hstimer3.*/
-                uint32_t sig_out_en: 1;              /*This is the output enable control bit for high speed channel*/
-                uint32_t idle_lv:    1;              /*This bit is used to control the output value when high speed channel is off.*/
-                uint32_t reserved4: 27;
-                uint32_t clk_en:     1;              /*This bit is clock gating control signal. when software configure LED_PWM internal registers  it controls the register clock.*/
-            };
-            uint32_t val;
-        } conf0;
-        union {
-            struct {
-                uint32_t hpoint:     20;             /*The output value changes to high when htimerx(x=[0 3]) selected by high speed channel has reached reg_hpoint_hsch0[19:0]*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } hpoint;
-        union {
-            struct {
-                uint32_t duty:      25;              /*The register is used to control output duty. When hstimerx(x=[0 3]) chosen by high speed channel  has reached reg_lpoint_hsch0 the output signal changes to low. reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4])          (1)  reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty;
-        union {
-            struct {
-                uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for high speed channel.*/
-                uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_hsch0 cycles for high speed channel.*/
-                uint32_t duty_num:  10;              /*This register is used to control the number of increased or decreased times for high speed channel.*/
-                uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel.*/
-                uint32_t duty_start: 1;              /*When reg_duty_num_hsch0 reg_duty_cycle_hsch0 and reg_duty_scale_hsch0 has been configured. these register won't take effect until set reg_duty_start_hsch0. this bit is automatically cleared by hardware.*/
-            };
-            uint32_t val;
-        } conf1;
-        union {
-            struct {
-                uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for high speed channel.*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty_rd;
-    } high_speed_channel[8];
-    struct{
-        union {
-            struct {
-                uint32_t timer_sel:  2;              /*There are four low speed timers  the two bits are used to select one of them for low speed channel.  2'b00: seletc lstimer0.   2'b01: select lstimer1.  2'b10: select lstimer2.    2'b11: select lstimer3.*/
-                uint32_t sig_out_en: 1;              /*This is the output enable control bit for low speed channel.*/
-                uint32_t idle_lv:    1;              /*This bit is used to control the output value when low speed channel is off.*/
-                uint32_t para_up:    1;              /*This bit is used to update register LEDC_LSCH0_HPOINT and LEDC_LSCH0_DUTY for low speed channel.*/
-                uint32_t reserved5: 27;
-            };
-            uint32_t val;
-        } conf0;
-        union {
-            struct {
-                uint32_t hpoint:     20;             /*The output value changes to high when lstimerx(x=[0 3]) selected by low speed channel has reached reg_hpoint_lsch0[19:0]*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } hpoint;
-        union {
-            struct {
-                uint32_t duty:      25;              /*The register is used to control output duty. When lstimerx(x=[0 3]) choosed by low speed channel has reached reg_lpoint_lsch0 the output signal changes to low. reg_lpoint_lsch0=(reg_hpoint_lsch0[19:0]+reg_duty_lsch0[24:4])          (1)  reg_lpoint_lsch0=(reg_hpoint_lsch0[19:0]+reg_duty_lsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty;
-        union {
-            struct {
-                uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for low speed channel.*/
-                uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_lsch0 cycles for low speed channel.*/
-                uint32_t duty_num:  10;              /*This register is used to control the num of increased or decreased times for low speed channel6.*/
-                uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for low speed channel6.*/
-                uint32_t duty_start: 1;              /*When reg_duty_num_hsch1 reg_duty_cycle_hsch1 and reg_duty_scale_hsch1 has been configured. these register won't take effect until set reg_duty_start_hsch1. this bit is automatically cleared by hardware.*/
-            };
-            uint32_t val;
-        } conf1;
-        union {
-            struct {
-                uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for low speed channel.*/
-                uint32_t reserved25: 7;
-            };
-            uint32_t val;
-        } duty_r;
-    } low_speed_channel[8];
-    struct{
-        union {
-            struct {
-                uint32_t timer_lim:  5;               /*This register controls the range of the counter in high speed timer. the counter range is [0 2**reg_hstimer0_lim] the max bit width for counter is 20.*/
-                uint32_t div_num:   18;               /*This register is used to configure parameter for divider in high speed timer the least significant eight bits represent the decimal part.*/
-                uint32_t pause:      1;               /*This bit is used to pause the counter in high speed timer*/
-                uint32_t rst:        1;               /*This bit is used to reset high speed timer the counter will be 0 after reset.*/
-                uint32_t tick_sel:   1;               /*This bit is used to choose apb_clk or ref_tick for high speed timer. 1'b1:apb_clk  0:ref_tick*/
-                uint32_t reserved26: 6;
-            };
-            uint32_t val;
-        } conf;
-        union {
-            struct {
-                uint32_t timer_cnt:  20;               /*software can read this register to get the current counter value in high speed timer*/
-                uint32_t reserved20: 12;
-            };
-            uint32_t val;
-        } value;
-    } high_speed_timer[4];
-    struct{
-        union {
-            struct {
-                uint32_t timer_lim:    5;              /*This register controls the range of the counter in low speed timer. the counter range is [0 2**reg_lstimer0_lim] the max bit width for counter is 20.*/
-                uint32_t div_num:     18;              /*This register is used to configure parameter for divider in low speed timer the least significant eight bits represent the decimal part.*/
-                uint32_t pause:        1;              /*This bit is used to pause the counter in low speed timer.*/
-                uint32_t rst:          1;              /*This bit is used to reset low speed timer the counter will be 0 after reset.*/
-                uint32_t tick_sel:     1;              /*This bit is used to choose slow_clk or ref_tick for low speed timer. 1'b1:slow_clk  0:ref_tick*/
-                uint32_t param_update: 1;              /*Set this bit  to update  reg_div_num_lstime0 and  reg_lstimer0_lim.*/
-                uint32_t reserved27:   5;
-            };
-            uint32_t val;
-        } conf;
-        union {
-            struct {
-                uint32_t timer_cnt:   20;              /*software can read this register to get the current counter value in low speed timer.*/
-                uint32_t reserved20:  12;
-            };
-            uint32_t val;
-        } value;
-    } low_speed_timer[4];
+    struct {
+        struct {
+            union {
+                struct {
+                    uint32_t timer_sel:  2;              /*There are four high speed timers  the two bits are used to select one of them for high speed channel.  2'b00: seletc hstimer0.   2'b01: select hstimer1.  2'b10: select hstimer2.    2'b11: select hstimer3.*/
+                    uint32_t sig_out_en: 1;              /*This is the output enable control bit for high speed channel*/
+                    uint32_t idle_lv:    1;              /*This bit is used to control the output value when high speed channel is off.*/
+                    uint32_t reserved4: 27;
+                    uint32_t clk_en:     1;              /*This bit is clock gating control signal. when software configure LED_PWM internal registers  it controls the register clock.*/
+                };
+                uint32_t val;
+            } conf0;
+            union {
+                struct {
+                    uint32_t hpoint:     20;             /*The output value changes to high when htimerx(x=[0 3]) selected by high speed channel has reached reg_hpoint_hsch0[19:0]*/
+                    uint32_t reserved20: 12;
+                };
+                uint32_t val;
+            } hpoint;
+            union {
+                struct {
+                    uint32_t duty:      25;              /*The register is used to control output duty. When hstimerx(x=[0 3]) chosen by high speed channel  has reached reg_lpoint_hsch0 the output signal changes to low. reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4])          (1)  reg_lpoint_hsch0=(reg_hpoint_hsch0[19:0]+reg_duty_hsch0[24:4] +1)     (2)  The least four bits in this register represent the decimal part and determines when to choose (1) or (2)*/
+                    uint32_t reserved25: 7;
+                };
+                uint32_t val;
+            } duty;
+            union {
+                struct {
+                    uint32_t duty_scale:10;              /*This register controls the increase or decrease step scale for high speed channel.*/
+                    uint32_t duty_cycle:10;              /*This register is used to increase or decrease the duty every reg_duty_cycle_hsch0 cycles for high speed channel.*/
+                    uint32_t duty_num:  10;              /*This register is used to control the number of increased or decreased times for high speed channel.*/
+                    uint32_t duty_inc:   1;              /*This register is used to increase the duty of output signal or decrease the duty of output signal for high speed channel.*/
+                    uint32_t duty_start: 1;              /*When reg_duty_num_hsch0 reg_duty_cycle_hsch0 and reg_duty_scale_hsch0 has been configured. these register won't take effect until set reg_duty_start_hsch0. this bit is automatically cleared by hardware.*/
+                };
+                uint32_t val;
+            } conf1;
+            union {
+                struct {
+                    uint32_t duty_read: 25;              /*This register represents the current duty of the output signal for high speed channel.*/
+                    uint32_t reserved25: 7;
+                };
+                uint32_t val;
+            } duty_rd;
+        } channel[8];
+    } channel_group[2];                                /*two channel groups : 0: high-speed channels; 1: low-speed channels*/
+    struct {
+        struct {
+            union {
+                struct {
+                    uint32_t bit_num:  5;                 /*This register controls the range of the counter in high speed timer. the counter range is [0 2**reg_hstimer0_lim] the max bit width for counter is 20.*/
+                    uint32_t div_num:   18;               /*This register is used to configure parameter for divider in high speed timer the least significant eight bits represent the decimal part.*/
+                    uint32_t pause:      1;               /*This bit is used to pause the counter in high speed timer*/
+                    uint32_t rst:        1;               /*This bit is used to reset high speed timer the counter will be 0 after reset.*/
+                    uint32_t tick_sel:   1;               /*This bit is used to choose apb_clk or ref_tick for high speed timer. 1'b1:apb_clk  0:ref_tick*/
+                    uint32_t low_speed_update: 1;         /*This bit is only useful for low speed timer channels, reserved for high speed timers*/
+                    uint32_t reserved26: 5;
+                };
+                uint32_t val;
+            } conf;
+            union {
+                struct {
+                    uint32_t timer_cnt:  20;               /*software can read this register to get the current counter value in high speed timer*/
+                    uint32_t reserved20: 12;
+                };
+                uint32_t val;
+            } value;
+        } timer[4];
+    } timer_group[2];                                    /*two channel groups : 0: high-speed channels; 1: low-speed channels*/
     union {
     union {
         struct {
         struct {
             uint32_t hstimer0_ovf:        1;           /*The interrupt raw bit for high speed channel0  counter overflow.*/
             uint32_t hstimer0_ovf:        1;           /*The interrupt raw bit for high speed channel0  counter overflow.*/

+ 0 - 14
components/esp32/ld/esp32.bt.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFC0000, len = 0x40000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x40000000;

+ 0 - 14
components/esp32/ld/esp32.bt.trace.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFC0000, len = 0x38000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x3FFF8000;

+ 15 - 3
components/esp32/ld/esp32.common.ld

@@ -1,5 +1,5 @@
 /*  Default entry point:  */
 /*  Default entry point:  */
-ENTRY(call_user_start_cpu0);
+ENTRY(call_start_cpu0);
 
 
 SECTIONS
 SECTIONS
 {
 {
@@ -102,7 +102,7 @@ SECTIONS
     _rodata_start = ABSOLUTE(.);
     _rodata_start = ABSOLUTE(.);
     *(.rodata)
     *(.rodata)
     *(.rodata.*)
     *(.rodata.*)
-	*(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
+    *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */
     *(.gnu.linkonce.r.*)
     *(.gnu.linkonce.r.*)
     *(.rodata1)
     *(.rodata1)
     __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
     __XT_EXCEPTION_TABLE_ = ABSOLUTE(.);
@@ -132,7 +132,7 @@ SECTIONS
     *(.dynamic)
     *(.dynamic)
     *(.gnu.version_d)
     *(.gnu.version_d)
     _rodata_end = ABSOLUTE(.);
     _rodata_end = ABSOLUTE(.);
-	/* Literals are also RO data. */
+    /* Literals are also RO data. */
     _lit4_start = ABSOLUTE(.);
     _lit4_start = ABSOLUTE(.);
     *(*.lit4)
     *(*.lit4)
     *(.lit4.*)
     *(.lit4.*)
@@ -153,4 +153,16 @@ SECTIONS
     _text_end = ABSOLUTE(.);
     _text_end = ABSOLUTE(.);
     _etext = .;
     _etext = .;
   } >iram0_2_seg
   } >iram0_2_seg
+
+  .rtc.text :
+  {
+    . = ALIGN(4);
+    *(.rtc.literal .rtc.text)
+  } >rtc_iram_seg
+
+  .rtc.data :
+  {
+    *(.rtc.data)
+    *(.rtc.rodata)
+  } > rtc_slow_seg
 }
 }

+ 47 - 6
components/esp32/ld/esp32.ld

@@ -1,14 +1,55 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
+/* ESP32 Linker Script Memory Layout
+
+   This file describes the memory layout (memory blocks) as virtual
+   memory addresses.
+
+   esp32.common.ld contains output sections to link compiler output
+   into these memory blocks.
+
+   ***
+
+   This linker script is passed through the C preprocessor to include
+   configuration options.
+
+   Please use preprocessor features sparingly! Restrict
+   to simple macros with numeric values, and/or #if/#endif blocks.
+*/
+#include "sdkconfig.h"
+
 MEMORY
 MEMORY
 {
 {
   /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
   /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
   of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
   of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
   are connected to the data port of the CPU and eg allow bytewise access. */
   are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFB0000, len = 0x50000   /* Shared RAM, minus rom bss/data/stack.*/
+
+  /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
+  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000
+
+  /* Even though the segment name is iram, it is actually mapped to flash */
+  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000
+
+  /* Shared data RAM, excluding memory reserved for ROM bss/data/stack.
+
+     Enabling Bluetooth & Trace Memory features in menuconfig will decrease
+     the amount of RAM available.
+  */
+  dram0_0_seg (RW) :                 org = 0x3FFB0000 + CONFIG_BT_RESERVE_DRAM,
+                                     len = 0x50000 - CONFIG_TRACEMEM_RESERVE_DRAM - CONFIG_BT_RESERVE_DRAM
+
+  /* Flash mapped constant data */
   drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
   drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
+
+  /* RTC fast memory (executable). Persists over deep sleep.
+   */
+  rtc_iram_seg(RWX) :                org = 0x400C0000, len = 0x2000
+
+  /* RTC slow memory (data accessible). Persists over deep sleep.
+
+     Start of RTC slow memory is reserved for ULP co-processor code + data, if enabled.
+  */
+  rtc_slow_seg(RW)  :                org = 0x50000000 + CONFIG_ULP_COPROC_RESERVE_MEM,
+                                     len = 0x1000 - CONFIG_ULP_COPROC_RESERVE_MEM
 }
 }
 
 
-_heap_end = 0x40000000;
+/* Heap ends at top of dram0_0_seg */
+_heap_end = 0x40000000 - CONFIG_TRACEMEM_RESERVE_DRAM;

+ 5 - 1
components/esp32/ld/esp32.rom.ld

@@ -99,6 +99,10 @@ PROVIDE ( _data_end = 0x4000d5c8 );
 PROVIDE ( _data_end_btdm_rom = 0x4000d4f8 );
 PROVIDE ( _data_end_btdm_rom = 0x4000d4f8 );
 PROVIDE ( _data_start = 0x4000d4f8 );
 PROVIDE ( _data_start = 0x4000d4f8 );
 PROVIDE ( _data_start_btdm_rom = 0x4000d4f4 );
 PROVIDE ( _data_start_btdm_rom = 0x4000d4f4 );
+PROVIDE ( _data_start_btdm = 0x3ffae6e0);
+PROVIDE ( _data_end_btdm = 0x3ffaff10);
+PROVIDE ( _bss_start_btdm = 0x3ffb8000);
+PROVIDE ( _bss_end_btdm = 0x3ffbff70);
 PROVIDE ( _daylight = 0x3ffae0a4 );
 PROVIDE ( _daylight = 0x3ffae0a4 );
 PROVIDE ( dbg_default_handler = 0x3ff97218 );
 PROVIDE ( dbg_default_handler = 0x3ff97218 );
 PROVIDE ( dbg_state = 0x3ffb8d5d );
 PROVIDE ( dbg_state = 0x3ffb8d5d );
@@ -445,7 +449,6 @@ PROVIDE ( _lseek_r = 0x4000bd8c );
 PROVIDE ( __lshrdi3 = 0x4000c84c );
 PROVIDE ( __lshrdi3 = 0x4000c84c );
 PROVIDE ( __ltdf2 = 0x40063790 );
 PROVIDE ( __ltdf2 = 0x40063790 );
 PROVIDE ( __ltsf2 = 0x4006342c );
 PROVIDE ( __ltsf2 = 0x4006342c );
-PROVIDE ( main = 0x400076c4 );
 PROVIDE ( malloc = 0x4000bea0 );
 PROVIDE ( malloc = 0x4000bea0 );
 PROVIDE ( _malloc_r = 0x4000bbb4 );
 PROVIDE ( _malloc_r = 0x4000bbb4 );
 PROVIDE ( maxSecretKey_256 = 0x3ff97448 );
 PROVIDE ( maxSecretKey_256 = 0x3ff97448 );
@@ -1378,6 +1381,7 @@ PROVIDE ( rom_iq_est_disable = 0x40005590 );
 PROVIDE ( rom_iq_est_enable = 0x40005514 );
 PROVIDE ( rom_iq_est_enable = 0x40005514 );
 PROVIDE ( rom_linear_to_db = 0x40005f64 );
 PROVIDE ( rom_linear_to_db = 0x40005f64 );
 PROVIDE ( rom_loopback_mode_en = 0x400030f8 );
 PROVIDE ( rom_loopback_mode_en = 0x400030f8 );
+PROVIDE ( rom_main = 0x400076c4 );
 PROVIDE ( rom_meas_tone_pwr_db = 0x40006004 );
 PROVIDE ( rom_meas_tone_pwr_db = 0x40006004 );
 PROVIDE ( rom_mhz2ieee = 0x4000404c );
 PROVIDE ( rom_mhz2ieee = 0x4000404c );
 PROVIDE ( rom_noise_floor_auto_set = 0x40003bdc );
 PROVIDE ( rom_noise_floor_auto_set = 0x40003bdc );

+ 0 - 14
components/esp32/ld/esp32.trace.ld

@@ -1,14 +0,0 @@
-/* THESE ARE THE VIRTUAL RUNTIME ADDRESSES  */
-/* The load addresses are defined later using the AT statements. */
-MEMORY
-{
-  /* All these values assume the flash cache is on, and have the blocks this uses subtracted from the length
-  of the various regions. The 'data access port' dram/drom regions map to the same iram/irom regions but
-  are connected to the data port of the CPU and eg allow bytewise access. */
-  iram0_0_seg (RX) :                 org = 0x40080000, len = 0x20000   /* IRAM for PRO cpu. Not sure if happy with this, this is MMU area... */
-  iram0_2_seg (RX) :                 org = 0x400D0018, len = 0x330000  /* Even though the segment name is iram, it is actually mapped to flash */
-  dram0_0_seg (RW) :                 org = 0x3FFB0000, len = 0x48000   /* Shared RAM, minus rom bss/data/stack.*/
-  drom0_0_seg (R) :                  org = 0x3F400010, len = 0x800000
-}
-
-_heap_end = 0x3FFF8000;

+ 1 - 1
components/esp32/lib

@@ -1 +1 @@
-Subproject commit f6d558367a08b6c9b18c2de515bd0a6740d2c45c
+Subproject commit a1e5f8b953c7934677ba7a6ed0a6dd2da0e6bd0f

+ 4 - 5
components/esp32/syscalls.c

@@ -143,7 +143,7 @@ int _open_r(struct _reent *r, const char * path, int flags, int mode) {
 }
 }
 
 
 ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
 ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
-    const char* p = (const char*) data;
+    const char *data_c = (const char *)data;
     if (fd == STDOUT_FILENO) {
     if (fd == STDOUT_FILENO) {
         static _lock_t stdout_lock; /* lazily initialised */
         static _lock_t stdout_lock; /* lazily initialised */
         /* Even though newlib does stream locking on stdout, we need
         /* Even though newlib does stream locking on stdout, we need
@@ -160,14 +160,13 @@ ssize_t _write_r(struct _reent *r, int fd, const void * data, size_t size) {
            which aren't fully valid.)
            which aren't fully valid.)
         */
         */
         _lock_acquire_recursive(&stdout_lock);
         _lock_acquire_recursive(&stdout_lock);
-        while(size--) {
+        for (size_t i = 0; i < size; i++) {
 #if CONFIG_NEWLIB_STDOUT_ADDCR
 #if CONFIG_NEWLIB_STDOUT_ADDCR
-            if (*p=='\n') {
+            if (data_c[i]=='\n') {
                 uart_tx_one_char('\r');
                 uart_tx_one_char('\r');
             }
             }
 #endif
 #endif
-            uart_tx_one_char(*p);
-            ++p;
+            uart_tx_one_char(data_c[i]);
         }
         }
         _lock_release_recursive(&stdout_lock);
         _lock_release_recursive(&stdout_lock);
     }
     }

+ 0 - 115
components/esp32/wifi.c

@@ -1,115 +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 <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "esp_err.h"
-#include "esp_wifi.h"
-#include "esp_event.h"
-#include "esp_task.h"
-
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "freertos/queue.h"
-#include "freertos/semphr.h"
-
-#if CONFIG_WIFI_ENABLED
-
-static bool wifi_startup_flag = false;
-
-static wifi_startup_cb_t startup_cb;
-static void *startup_ctx;
-
-#define WIFI_DEBUG(...)
-#define WIFI_API_CALL_CHECK(info, api_call, ret) \
-do{\
-    esp_err_t __err = (api_call);\
-    if ((ret) != __err) {\
-        WIFI_DEBUG("%s %d %s ret=%d\n", __FUNCTION__, __LINE__, (info), __err);\
-        return __err;\
-    }\
-} while(0)
-
-
-
-static void esp_wifi_task(void *pvParameters)
-{
-    esp_err_t err;
-    wifi_init_config_t cfg;
-    cfg.event_q = (xQueueHandle)esp_event_get_handler();
-
-    do {
-        err = esp_wifi_init(&cfg);
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_init fail, ret=%d\n", err);
-            break;
-        }
-
-        if (startup_cb) {
-            err = (*startup_cb)(startup_ctx);
-            if (err != ESP_OK) {
-                WIFI_DEBUG("startup_cb fail, ret=%d\n", err);
-                break;
-            }
-        }
-
-        err = esp_wifi_start();
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_start fail, ret=%d\n", err);
-            break;
-        }
-
-#if CONFIG_WIFI_AUTO_CONNECT
-        wifi_mode_t mode;
-        bool auto_connect;
-        err = esp_wifi_get_mode(&mode);
-        if (err != ESP_OK) {
-            WIFI_DEBUG("esp_wifi_get_mode fail, ret=%d\n", err);
-        }
-
-        err = esp_wifi_get_auto_connect(&auto_connect);
-        if ((mode == WIFI_MODE_STA || mode == WIFI_MODE_APSTA) && auto_connect) {
-            err = esp_wifi_connect();
-            if (err != ESP_OK) {
-                WIFI_DEBUG("esp_wifi_connect fail, ret=%d\n", err);
-                break;
-            }
-        }
-#endif
-    } while (0);
-
-    if (err != ESP_OK) {
-        WIFI_DEBUG("wifi startup fail, deinit\n");
-        esp_wifi_deinit();
-    }
-
-    vTaskDelete(NULL);
-}
-
-esp_err_t esp_wifi_startup(wifi_startup_cb_t cb, void *ctx)
-{
-    if (wifi_startup_flag) {
-        return ESP_FAIL;
-    }
-
-    startup_cb = cb;
-    startup_ctx = ctx;
-
-    xTaskCreatePinnedToCore(esp_wifi_task, "wifiTask", ESP_TASK_WIFI_STARTUP_STACK, NULL, ESP_TASK_WIFI_STARTUP_PRIO, NULL, 0);
-
-    return ESP_OK;
-}
-#endif

+ 1 - 1
components/esptool_py/Makefile.projbuild

@@ -16,7 +16,7 @@ ESPTOOLPY := $(PYTHON) $(ESPTOOLPY_SRC) --chip esp32
 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
 ESPTOOLPY_SERIAL := $(ESPTOOLPY) --port $(ESPPORT) --baud $(ESPBAUD)
 
 
 # the no-stub argument is temporary until esptool.py fully supports compressed uploads
 # the no-stub argument is temporary until esptool.py fully supports compressed uploads
-ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) $(if $(CONFIG_ESPTOOLPY_COMPRESSED),--no-stub) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
+ESPTOOLPY_WRITE_FLASH=$(ESPTOOLPY_SERIAL) write_flash $(if $(CONFIG_ESPTOOLPY_COMPRESSED),-z) --flash_mode $(ESPFLASHMODE) --flash_freq $(ESPFLASHFREQ)
 
 
 ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
 ESPTOOL_ALL_FLASH_ARGS += $(CONFIG_APP_OFFSET) $(APP_BIN)
 
 

+ 1 - 1
components/esptool_py/esptool

@@ -1 +1 @@
-Subproject commit 7c84dd433512bac80e4c01c569e42b4fe76646a7
+Subproject commit 197ba605fe0c05e16bf4c5ec07b726adc8d86abc

+ 1 - 1
components/expat/component.mk

@@ -10,6 +10,6 @@ COMPONENT_ADD_INCLUDEDIRS := port/include include/expat
 
 
 COMPONENT_SRCDIRS := library port
 COMPONENT_SRCDIRS := library port
 
 
-CFLAGS += -Wno-error=address -Waddress -DHAVE_EXPAT_CONFIG_H
+CFLAGS += -Wno-unused-function -DHAVE_EXPAT_CONFIG_H
 
 
 include $(IDF_PATH)/make/component_common.mk
 include $(IDF_PATH)/make/component_common.mk

+ 22 - 0
components/expat/expat.rst

@@ -0,0 +1,22 @@
+The Expat XML Parse Instruction
+=============================
+
+Expat is an XML parser library written in C which be used for parse XML documents.
+
+It is a stream-oriented parser in which an application registers handlers for things the parser might find in the XML document.
+
+It can parse some larger files.
+
+-   Expat XML Parser support many different processor, but for the most part function you only need the following functions:
+
+    **XML_ParserCreate**: Create a new parser object
+
+    **XML_SetElementHandler**: Set handlers for start and end tags
+
+    **XML_SetCharacterDataHandler**: Set handler for text
+
+    **XML_Parse**: Pass a buffer full of document to the parser
+
+More information about Expat library can be found on http://expat.sourceforge.net
+
+An introductory article on using Expat is available on http://xml.com

+ 132 - 124
components/freertos/Kconfig

@@ -2,192 +2,200 @@ menu "FreeRTOS"
 
 
 # This is actually also handled in the ESP32 startup code, not only in FreeRTOS.
 # This is actually also handled in the ESP32 startup code, not only in FreeRTOS.
 config FREERTOS_UNICORE
 config FREERTOS_UNICORE
-	bool "Run FreeRTOS only on first core"
-	default n
-	help
-		This version of FreeRTOS normally takes control of all cores of 
-		the CPU. Select this if you only want to start it on the first core.
-		This is needed when e.g. another process needs complete control
-		over the second core.
+    bool "Run FreeRTOS only on first core"
+    default n
+    help
+        This version of FreeRTOS normally takes control of all cores of 
+        the CPU. Select this if you only want to start it on the first core.
+        This is needed when e.g. another process needs complete control
+        over the second core.
 
 
 
 
 choice FREERTOS_CORETIMER
 choice FREERTOS_CORETIMER
-	prompt "Xtensa timer to use as the FreeRTOS tick source"
-	default CONFIG_FREERTOS_CORETIMER_0
-	help
-		FreeRTOS needs a timer with an associated interrupt to use as
-		the main tick source to increase counters, run timers and do
-		pre-emptive multitasking with. There are multiple timers available
-		to do this, with different interrupt priorities. Check 
+    prompt "Xtensa timer to use as the FreeRTOS tick source"
+    default CONFIG_FREERTOS_CORETIMER_0
+    help
+        FreeRTOS needs a timer with an associated interrupt to use as
+        the main tick source to increase counters, run timers and do
+        pre-emptive multitasking with. There are multiple timers available
+        to do this, with different interrupt priorities. Check 
 
 
 config FREERTOS_CORETIMER_0
 config FREERTOS_CORETIMER_0
-	bool "Timer 0 (int 6, level 1)"
-	help
-		Select this to use timer 0
+    bool "Timer 0 (int 6, level 1)"
+    help
+        Select this to use timer 0
 
 
 config FREERTOS_CORETIMER_1
 config FREERTOS_CORETIMER_1
-	bool "Timer 1 (int 15, level 3)"
-	help
-		Select this to use timer 1
+    bool "Timer 1 (int 15, level 3)"
+    help
+        Select this to use timer 1
 
 
 config FREERTOS_CORETIMER_2
 config FREERTOS_CORETIMER_2
-	bool "Timer 2 (int 16, level 5)"
-	help
-		Select this to use timer 2
+    bool "Timer 2 (int 16, level 5)"
+    help
+        Select this to use timer 2
 
 
 endchoice
 endchoice
 
 
 config FREERTOS_HZ
 config FREERTOS_HZ
-	int "Tick rate (Hz)"
-	range 1 10000
-	default 100
+    int "Tick rate (Hz)"
+    range 1 10000
+    default 100
+    help
+        Select the tick rate at which FreeRTOS does pre-emptive context switching.
+
+config FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
+	bool "Halt when an SMP-untested function is called"
+	default y
 	help
 	help
-		Select the tick rate at which FreeRTOS does pre-emptive context switching.
+		Some functions in FreeRTOS have not been thoroughly tested yet when moving to
+		the SMP implementation of FreeRTOS. When this option is enabled, these fuctions
+		will throw an assert().
 
 
 choice FREERTOS_CHECK_STACKOVERFLOW
 choice FREERTOS_CHECK_STACKOVERFLOW
-	prompt "Check for stack overflow"
-	default FREERTOS_CHECK_STACKOVERFLOW_QUICK
-	help
-		FreeRTOS can check for stack overflows in threads and trigger an user function
-		called vApplicationStackOverflowHook when this happens.
+    prompt "Check for stack overflow"
+    default FREERTOS_CHECK_STACKOVERFLOW_QUICK
+    help
+        FreeRTOS can check for stack overflows in threads and trigger an user function
+        called vApplicationStackOverflowHook when this happens.
 
 
 config FREERTOS_CHECK_STACKOVERFLOW_NONE
 config FREERTOS_CHECK_STACKOVERFLOW_NONE
-	bool "No checking"
-	help
-		Do not check for stack overflows (configCHECK_FOR_STACK_OVERFLOW=0)
+    bool "No checking"
+    help
+        Do not check for stack overflows (configCHECK_FOR_STACK_OVERFLOW=0)
 
 
 config FREERTOS_CHECK_STACKOVERFLOW_PTRVAL
 config FREERTOS_CHECK_STACKOVERFLOW_PTRVAL
-	bool "Check by stack pointer value"
-	help
-		Check for stack overflows on each context switch by checking if
-		the stack pointer is in a valid range. Quick but does not detect
-		stack overflows that happened between context switches
-		(configCHECK_FOR_STACK_OVERFLOW=1)
+    bool "Check by stack pointer value"
+    help
+        Check for stack overflows on each context switch by checking if
+        the stack pointer is in a valid range. Quick but does not detect
+        stack overflows that happened between context switches
+        (configCHECK_FOR_STACK_OVERFLOW=1)
 
 
 config FREERTOS_CHECK_STACKOVERFLOW_CANARY
 config FREERTOS_CHECK_STACKOVERFLOW_CANARY
-	bool "Check using canary bytes"
-	help
-		Places some magic bytes at the end of the stack area and on each 
-		context switch, check if these bytes are still intact. More thorough
-		than just checking the pointer, but also slightly slower.
-		(configCHECK_FOR_STACK_OVERFLOW=2)
+    bool "Check using canary bytes"
+    help
+        Places some magic bytes at the end of the stack area and on each 
+        context switch, check if these bytes are still intact. More thorough
+        than just checking the pointer, but also slightly slower.
+        (configCHECK_FOR_STACK_OVERFLOW=2)
 endchoice
 endchoice
 
 
 config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
 config FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
-	int "Amount of thread local storage pointers"
-	range 0 256 if !WIFI_ENABLED
-	range 1 256 if WIFI_ENABLED
-	default 1
-	help
-		FreeRTOS has the ability to store per-thread pointers in the task
-		control block. This controls the amount of pointers available;
-		0 turns off this functionality.
+    int "Amount of thread local storage pointers"
+    range 0 256 if !WIFI_ENABLED
+    range 1 256 if WIFI_ENABLED
+    default 1
+    help
+        FreeRTOS has the ability to store per-thread pointers in the task
+        control block. This controls the amount of pointers available;
+        0 turns off this functionality.
 
 
-		If using the WiFi stack, this value must be at least 1.
+        If using the WiFi stack, this value must be at least 1.
 
 
 #This still needs to be implemented.
 #This still needs to be implemented.
 choice FREERTOS_PANIC
 choice FREERTOS_PANIC
-	prompt "Panic handler behaviour"
-	default FREERTOS_PANIC_PRINT_REBOOT
-	help
-		If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is 
-		invoked. Configure the panic handlers action here.
+    prompt "Panic handler behaviour"
+    default FREERTOS_PANIC_PRINT_REBOOT
+    help
+        If FreeRTOS detects unexpected behaviour or an unhandled exception, the panic handler is 
+        invoked. Configure the panic handlers action here.
 
 
 config FREERTOS_PANIC_PRINT_HALT
 config FREERTOS_PANIC_PRINT_HALT
-	bool "Print registers and halt"
-	help
-		Outputs the relevant registers over the serial port and halt the 
-		processor. Needs a manual reset to restart.
+    bool "Print registers and halt"
+    help
+        Outputs the relevant registers over the serial port and halt the 
+        processor. Needs a manual reset to restart.
 
 
 config FREERTOS_PANIC_PRINT_REBOOT
 config FREERTOS_PANIC_PRINT_REBOOT
-	bool "Print registers and reboot"
-	help
-		Outputs the relevant registers over the serial port and immediately
-		reset the processor.
+    bool "Print registers and reboot"
+    help
+        Outputs the relevant registers over the serial port and immediately
+        reset the processor.
 
 
 config FREERTOS_PANIC_SILENT_REBOOT
 config FREERTOS_PANIC_SILENT_REBOOT
-	bool "Silent reboot"
-	help
-		Just resets the processor without outputting anything
+    bool "Silent reboot"
+    help
+        Just resets the processor without outputting anything
 
 
 config FREERTOS_PANIC_GDBSTUB
 config FREERTOS_PANIC_GDBSTUB
-	bool "Invoke GDBStub"
-	help
-		Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
-		of the crash.
+    bool "Invoke GDBStub"
+    help
+        Invoke gdbstub on the serial port, allowing for gdb to attach to it to do a postmortem
+        of the crash.
 endchoice
 endchoice
 
 
 config FREERTOS_DEBUG_OCDAWARE
 config FREERTOS_DEBUG_OCDAWARE
-	bool "Make exception and panic handlers JTAG/OCD aware"
-	default y
-	help
-		The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
-		instead of panicking, have the debugger stop on the offending instruction.
+    bool "Make exception and panic handlers JTAG/OCD aware"
+    default y
+    help
+        The FreeRTOS panic and unhandled exception handers can detect a JTAG OCD debugger and
+        instead of panicking, have the debugger stop on the offending instruction.
 
 
 choice FREERTOS_ASSERT
 choice FREERTOS_ASSERT
-	prompt "FreeRTOS assertions"
-	default FREERTOS_ASSERT_FAIL_ABORT
-	help
-		Failed FreeRTOS configASSERT() assertions can be configured to
-		behave in different ways.
+    prompt "FreeRTOS assertions"
+    default FREERTOS_ASSERT_FAIL_ABORT
+    help
+        Failed FreeRTOS configASSERT() assertions can be configured to
+        behave in different ways.
 
 
 config FREERTOS_ASSERT_FAIL_ABORT
 config FREERTOS_ASSERT_FAIL_ABORT
-	bool "abort() on failed assertions"
-	help
-		If a FreeRTOS configASSERT() fails, FreeRTOS will abort() and
-		halt execution. The panic handler can be configured to handle
-		the outcome of an abort() in different ways.
+    bool "abort() on failed assertions"
+    help
+        If a FreeRTOS configASSERT() fails, FreeRTOS will abort() and
+        halt execution. The panic handler can be configured to handle
+        the outcome of an abort() in different ways.
 
 
 config FREERTOS_ASSERT_FAIL_PRINT_CONTINUE
 config FREERTOS_ASSERT_FAIL_PRINT_CONTINUE
-	bool "Print and continue failed assertions"
-	help
-		If a FreeRTOS assertion fails, print it out and continue.
+    bool "Print and continue failed assertions"
+    help
+        If a FreeRTOS assertion fails, print it out and continue.
 
 
 config FREERTOS_ASSERT_DISABLE
 config FREERTOS_ASSERT_DISABLE
-	bool "Disable FreeRTOS assertions"
-	help
-		FreeRTOS configASSERT() will not be compiled into the binary.
+    bool "Disable FreeRTOS assertions"
+    help
+        FreeRTOS configASSERT() will not be compiled into the binary.
 
 
 endchoice
 endchoice
 
 
 config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
 config FREERTOS_BREAK_ON_SCHEDULER_START_JTAG
-	bool "Stop program on scheduler start when JTAG/OCD is detected"
-	depends on FREERTOS_DEBUG_OCDAWARE
-	default y
-	help
-		If JTAG/OCD is connected, stop execution when the scheduler is started and the first
-		task is executed.
+    bool "Stop program on scheduler start when JTAG/OCD is detected"
+    depends on FREERTOS_DEBUG_OCDAWARE
+    default y
+    help
+        If JTAG/OCD is connected, stop execution when the scheduler is started and the first
+        task is executed.
 
 
 menuconfig ENABLE_MEMORY_DEBUG
 menuconfig ENABLE_MEMORY_DEBUG
-	bool "Enable heap memory debug"
-	default n
-	help
-		Enable this option to show malloc heap block and memory crash detect
+    bool "Enable heap memory debug"
+    default n
+    help
+        Enable this option to show malloc heap block and memory crash detect
 
 
 menuconfig FREERTOS_DEBUG_INTERNALS
 menuconfig FREERTOS_DEBUG_INTERNALS
-	bool "Debug FreeRTOS internals"
-	default n
-	help
-		Enable this option to show the menu with internal FreeRTOS debugging features.
-		This option does not change any code by itself, it just shows/hides some options.
+    bool "Debug FreeRTOS internals"
+    default n
+    help
+        Enable this option to show the menu with internal FreeRTOS debugging features.
+        This option does not change any code by itself, it just shows/hides some options.
 
 
 if FREERTOS_DEBUG_INTERNALS
 if FREERTOS_DEBUG_INTERNALS
 
 
 config FREERTOS_PORTMUX_DEBUG
 config FREERTOS_PORTMUX_DEBUG
-	bool "Debug portMUX portENTER_CRITICAL/portEXIT_CRITICAL"
-	depends on FREERTOS_DEBUG_INTERNALS
-	default n
-	help
-		If enabled, debug information (including integrity checks) will be printed
-	 	to UART for the port-specific MUX implementation.
+    bool "Debug portMUX portENTER_CRITICAL/portEXIT_CRITICAL"
+    depends on FREERTOS_DEBUG_INTERNALS
+    default n
+    help
+        If enabled, debug information (including integrity checks) will be printed
+        to UART for the port-specific MUX implementation.
 
 
 config FREERTOS_PORTMUX_DEBUG_RECURSIVE
 config FREERTOS_PORTMUX_DEBUG_RECURSIVE
-	bool "Debug portMUX Recursion"
-	depends on FREERTOS_PORTMUX_DEBUG
-	default n
-	help
-		If enabled, additional debug information will be printed for recursive
-		portMUX usage.
+    bool "Debug portMUX Recursion"
+    depends on FREERTOS_PORTMUX_DEBUG
+    default n
+    help
+        If enabled, additional debug information will be printed for recursive
+        portMUX usage.
 
 
 endif # FREERTOS_DEBUG_INTERNALS
 endif # FREERTOS_DEBUG_INTERNALS
 
 

+ 1 - 0
components/freertos/croutine.c

@@ -143,6 +143,7 @@ BaseType_t xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, UBaseType_t uxPri
 BaseType_t xReturn;
 BaseType_t xReturn;
 CRCB_t *pxCoRoutine;
 CRCB_t *pxCoRoutine;
 
 
+	UNTESTED_FUNCTION(); //Actually, coroutines are entirely unsupported
 	/* Allocate the memory that will store the co-routine control block. */
 	/* Allocate the memory that will store the co-routine control block. */
 	pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
 	pxCoRoutine = ( CRCB_t * ) pvPortMalloc( sizeof( CRCB_t ) );
 	if( pxCoRoutine )
 	if( pxCoRoutine )

+ 0 - 7
components/freertos/event_groups.c

@@ -124,7 +124,6 @@ typedef struct xEventGroupDefinition
 
 
 /* Again: one mux for all events. Maybe this can be made more granular. ToDo: look into that. -JD */
 /* Again: one mux for all events. Maybe this can be made more granular. ToDo: look into that. -JD */
 static portMUX_TYPE xEventGroupMux = portMUX_INITIALIZER_UNLOCKED;
 static portMUX_TYPE xEventGroupMux = portMUX_INITIALIZER_UNLOCKED;
-static BaseType_t xMuxInitialized = pdFALSE;
 
 
 
 
 /*-----------------------------------------------------------*/
 /*-----------------------------------------------------------*/
@@ -145,12 +144,6 @@ EventGroupHandle_t xEventGroupCreate( void )
 {
 {
 EventGroup_t *pxEventBits;
 EventGroup_t *pxEventBits;
 
 
-	//Initialize mux, if needed
-	if ( xMuxInitialized == pdFALSE ) {
-		vPortCPUInitializeMutex( & xEventGroupMux );
-		xMuxInitialized = pdTRUE;
-	}
-	
 	pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );
 	pxEventBits = pvPortMalloc( sizeof( EventGroup_t ) );
 	if( pxEventBits != NULL )
 	if( pxEventBits != NULL )
 	{
 	{

+ 12 - 0
components/freertos/include/freertos/FreeRTOSConfig.h

@@ -124,6 +124,16 @@
         abort();                                                        \
         abort();                                                        \
         }
         }
 #endif
 #endif
+
+#if CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION
+#include <stdlib.h>
+#include "rom/ets_sys.h"
+#define UNTESTED_FUNCTION() { ets_printf("Untested FreeRTOS function %s\r\n", __FUNCTION__); configASSERT(false); } while(0)
+#else
+#define UNTESTED_FUNCTION()
+#endif
+
+
 #endif /* def __ASSEMBLER__ */
 #endif /* def __ASSEMBLER__ */
 
 
 
 
@@ -263,5 +273,7 @@
 #define configXT_SIMULATOR					0
 #define configXT_SIMULATOR					0
 
 
 
 
+
+
 #endif /* FREERTOS_CONFIG_H */
 #endif /* FREERTOS_CONFIG_H */
 
 

+ 206 - 0
components/freertos/include/freertos/ringbuf.h

@@ -0,0 +1,206 @@
+#ifndef FREERTOS_RINGBUF_H
+#define FREERTOS_RINGBUF_H
+
+/*
+Header definitions for a FreeRTOS ringbuffer object
+
+A ringbuffer instantiated by these functions essentially acts like a FreeRTOS queue, with the
+difference that it's strictly FIFO and with the main advantage that you can put in randomly-sized
+items. The capacity, accordingly, isn't measured in the amount of items, but the amount of memory
+that is used for storing the items. Dependent on the size of the items, more or less of them will 
+fit in the ring buffer.
+
+This ringbuffer tries to be efficient with memory: when inserting an item, the item data will
+be copied to the ringbuffer memory. When retrieving an item, however, a reference to ringbuffer
+memory will be returned. The returned memory is guaranteed to be 32-bit aligned and contiguous.
+The application can use this memory, but as long as it does, ringbuffer writes that would write
+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
+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
+unused and instead will put the entire item at the start of the ringbuffer, as soon as there is 
+enough free space.
+
+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.
+*/
+
+//An opaque handle for a ringbuff object.
+typedef void * RingbufHandle_t;
+
+
+/**
+ * @brief  Create a ring buffer
+ *
+ * @param  buf_length : Length of circular buffer, in bytes. Each entry will take up its own length, plus a header
+ *                      that at the moment is equal to sizeof(size_t).
+ * @param allow_split_items : pdTRUE if it is acceptable that item data is inserted as two
+ *                            items instead of one.
+ *
+ * @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);
+
+
+/**
+ * @brief  Delete a ring buffer
+ *
+ * @param  ringbuf - Ring buffer to delete
+ *
+ * @return void
+ */
+void vRingbufferDelete(RingbufHandle_t ringbuf);
+
+
+/**
+ * @brief  Get maximum size of an item that can be placed in the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to query
+ *
+ * @return Maximum size, in bytes, of an item that can be placed in a ring buffer.
+ */
+size_t xRingbufferGetMaxItemSize(RingbufHandle_t ringbuf);
+
+
+/**
+ * @brief  Insert an item into the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to insert the item into
+ * @param  data - Pointer to data to insert. NULL is allowed if data_size is 0.
+ * @param  data_size - Size of data to insert. A value of 0 is allowed.
+ * @param  xTicksToWait - Ticks to wait for room in the ringbuffer.
+ *
+ * @return pdTRUE if succeeded, pdFALSE on time-out or when the buffer is larger 
+ *         than indicated by xRingbufferGetMaxItemSize(ringbuf).
+ */
+BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t data_size, TickType_t ticks_to_wait);
+
+
+/**
+ * @brief  Insert an item into the ring buffer from an ISR
+ *
+ * @param  ringbuf - Ring buffer to insert the item into
+ * @param  data - Pointer to data to insert. NULL is allowed if data_size is 0.
+ * @param  data_size - Size of data to insert. A value of 0 is allowed.
+ * @param  higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
+ *                                     priority task.
+ *
+ * @return pdTRUE if succeeded, pdFALSE when the ring buffer does not have space.
+ */
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t data_size, BaseType_t *higher_prio_task_awoken);
+
+/**
+ * @brief  Retrieve an item from the ring buffer
+ *
+ * @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 *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait);
+
+
+/**
+ * @brief  Retrieve an item from the ring buffer 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 *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size);
+
+
+/**
+ * @brief  Return a previously-retrieved item to the ringbuffer
+ *
+ * @param  ringbuf - Ring buffer the item was retrieved from
+ * @param  item - Item that was received earlier
+ *
+ * @return void
+ */
+void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item);
+
+
+
+/**
+ * @brief  Return a previously-retrieved item to the ringbuffer from an ISR
+ *
+ * @param  ringbuf - Ring buffer the item was retrieved from
+ * @param  item - Item that was received earlier
+ * @param  higher_prio_task_awoken - Value pointed to will be set to pdTRUE if the push woke up a higher
+ *                                     priority task.
+ *
+ * @return void
+ */
+void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_t *higher_prio_task_awoken);
+
+
+/**
+ * @brief  Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
+ *         more space has become available in the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to add to the queue set
+ * @param  xQueueSet - Queue set to add the ringbuffer to
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Add the ringbuffer to a queue set. This specifically adds the semaphore that indicates
+ *         something has been written into the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to add to the queue set
+ * @param  xQueueSet - Queue set to add the ringbuffer to
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
+ *         more space has become available in the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to remove from the queue set
+ * @param  xQueueSet - Queue set to remove the ringbuffer from
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Remove the ringbuffer from a queue set. This specifically removes the semaphore that indicates
+ *         something has been written to the ringbuffer.
+ *
+ * @param  ringbuf - Ring buffer to remove from the queue set
+ * @param  xQueueSet - Queue set to remove the ringbuffer from
+ *
+ * @return pdTRUE on success, pdFALSE otherwise
+ */
+BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet);
+
+
+/**
+ * @brief  Debugging function to print the internal pointers in the ring buffer
+ *
+ * @param  ringbuf - Ring buffer to show
+ *
+ * @return void
+ */
+void xRingbufferPrintInfo(RingbufHandle_t ringbuf);
+
+
+#endif

+ 6 - 0
components/freertos/include/freertos/task.h

@@ -1979,6 +1979,12 @@ BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcN
  */
  */
 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
 UBaseType_t uxTaskGetTaskNumber( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
 
 
+
+/*
+ * Get the current core affinity of a task
+ */
+BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
+
 /*
 /*
  * Set the uxTaskNumber of the task referenced by the xTask parameter to
  * Set the uxTaskNumber of the task referenced by the xTask parameter to
  * uxHandle.
  * uxHandle.

+ 2 - 2
components/freertos/panic.c

@@ -81,7 +81,7 @@ int xPortGetCoreID();
 void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
 void  __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
 	panicPutStr("***ERROR*** A stack overflow in task");
 	panicPutStr("***ERROR*** A stack overflow in task");
 	panicPutStr((char*)pcTaskName);
 	panicPutStr((char*)pcTaskName);
-	panicPutStr("has been detected.\n");
+	panicPutStr("has been detected.\r\n");
 }
 }
 
 
 static const char *edesc[]={
 static const char *edesc[]={
@@ -160,7 +160,7 @@ void xt_unhandled_exception(XtExcFrame *frame) {
 	panicPutStr("Guru Meditation Error of type ");
 	panicPutStr("Guru Meditation Error of type ");
 	x=regs[20];
 	x=regs[20];
 	if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
 	if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
-	panicPutStr(" occured on core ");
+	panicPutStr(" occurred on core ");
 	panicPutDec(xPortGetCoreID());
 	panicPutDec(xPortGetCoreID());
 	if (inOCDMode()) {
 	if (inOCDMode()) {
 		panicPutStr(" at pc=");
 		panicPutStr(" at pc=");

+ 90 - 304
components/freertos/queue.c

@@ -100,11 +100,6 @@ header files above, but not in this file, in order to generate the correct
 privileged Vs unprivileged linkage and placement. */
 privileged Vs unprivileged linkage and placement. */
 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
 #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750. */
 
 
-
-/* Constants used with the xRxLock and xTxLock structure members. */
-#define queueUNLOCKED					( ( BaseType_t ) -1 )
-#define queueLOCKED_UNMODIFIED			( ( BaseType_t ) 0 )
-
 /* When the Queue_t structure is used to represent a base queue its pcHead and
 /* When the Queue_t structure is used to represent a base queue its pcHead and
 pcTail members are used as pointers into the queue storage area.  When the
 pcTail members are used as pointers into the queue storage area.  When the
 Queue_t structure is used to represent a mutex pcHead and pcTail pointers are
 Queue_t structure is used to represent a mutex pcHead and pcTail pointers are
@@ -163,9 +158,6 @@ typedef struct QueueDefinition
 	UBaseType_t uxLength;			/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
 	UBaseType_t uxLength;			/*< The length of the queue defined as the number of items it will hold, not the number of bytes. */
 	UBaseType_t uxItemSize;			/*< The size of each items that the queue will hold. */
 	UBaseType_t uxItemSize;			/*< The size of each items that the queue will hold. */
 
 
-	volatile BaseType_t xRxLock;	/*< Stores the number of items received from the queue (removed from the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
-	volatile BaseType_t xTxLock;	/*< Stores the number of items transmitted to the queue (added to the queue) while the queue was locked.  Set to queueUNLOCKED when the queue is not locked. */
-
 	#if ( configUSE_TRACE_FACILITY == 1 )
 	#if ( configUSE_TRACE_FACILITY == 1 )
 		UBaseType_t uxQueueNumber;
 		UBaseType_t uxQueueNumber;
 		uint8_t ucQueueType;
 		uint8_t ucQueueType;
@@ -212,15 +204,6 @@ typedef xQUEUE Queue_t;
 
 
 #endif /* configQUEUE_REGISTRY_SIZE */
 #endif /* configQUEUE_REGISTRY_SIZE */
 
 
-/*
- * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not
- * prevent an ISR from adding or removing items to the queue, but does prevent
- * an ISR from removing tasks from the queue event lists.  If an ISR finds a
- * queue is locked it will instead increment the appropriate queue lock count
- * to indicate that a task may require unblocking.  When the queue in unlocked
- * these lock counts are inspected, and the appropriate action taken.
- */
-static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
 
 
 /*
 /*
  * Uses a critical section to determine if there is any data in a queue.
  * Uses a critical section to determine if there is any data in a queue.
@@ -255,27 +238,6 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer
 	static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION;
 	static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue, const BaseType_t xCopyPosition ) PRIVILEGED_FUNCTION;
 #endif
 #endif
 
 
-/*-----------------------------------------------------------*/
-
-/*
- * Macro to mark a queue as locked.  Locking a queue prevents an ISR from
- * accessing the queue event lists.
- */
-#define prvLockQueue( pxQueue )								\
-	taskENTER_CRITICAL(&pxQueue->mux);									\
-	{														\
-		if( ( pxQueue )->xRxLock == queueUNLOCKED )			\
-		{													\
-			( pxQueue )->xRxLock = queueLOCKED_UNMODIFIED;	\
-		}													\
-		if( ( pxQueue )->xTxLock == queueUNLOCKED )			\
-		{													\
-			( pxQueue )->xTxLock = queueLOCKED_UNMODIFIED;	\
-		}													\
-	}														\
-	taskEXIT_CRITICAL(&pxQueue->mux)
-/*-----------------------------------------------------------*/
-
 BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
 BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
 {
 {
 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
@@ -292,8 +254,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 		pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 		pxQueue->pcWriteTo = pxQueue->pcHead;
 		pxQueue->pcWriteTo = pxQueue->pcHead;
 		pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
 		pxQueue->u.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - ( UBaseType_t ) 1U ) * pxQueue->uxItemSize );
-		pxQueue->xRxLock = queueUNLOCKED;
-		pxQueue->xTxLock = queueUNLOCKED;
 
 
 		if( xNewQueue == pdFALSE )
 		if( xNewQueue == pdFALSE )
 		{
 		{
@@ -441,8 +401,6 @@ int8_t *pcAllocatedBuffer;
 			pxNewQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 			pxNewQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
 			pxNewQueue->uxLength = ( UBaseType_t ) 1U;
 			pxNewQueue->uxLength = ( UBaseType_t ) 1U;
 			pxNewQueue->uxItemSize = ( UBaseType_t ) 0U;
 			pxNewQueue->uxItemSize = ( UBaseType_t ) 0U;
-			pxNewQueue->xRxLock = queueUNLOCKED;
-			pxNewQueue->xTxLock = queueUNLOCKED;
 
 
 			#if ( configUSE_TRACE_FACILITY == 1 )
 			#if ( configUSE_TRACE_FACILITY == 1 )
 			{
 			{
@@ -787,7 +745,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		now the critical section has been exited. */
 		now the critical section has been exited. */
 
 
 		taskENTER_CRITICAL(&pxQueue->mux);
 		taskENTER_CRITICAL(&pxQueue->mux);
-//		prvLockQueue( pxQueue );
 
 
 		/* Update the timeout state to see if it has expired yet. */
 		/* Update the timeout state to see if it has expired yet. */
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@@ -797,13 +754,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				traceBLOCKING_ON_QUEUE_SEND( pxQueue );
 				traceBLOCKING_ON_QUEUE_SEND( pxQueue );
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
 
 
-				/* Unlocking the queue means queue events can effect the
-				event list.  It is possible	that interrupts occurring now
-				remove this task from the event	list again - but as the
-				scheduler is suspended the task will go onto the pending
-				ready last instead of the actual ready list. */
-//				prvUnlockQueue( pxQueue );
-
 
 
 				/* Resuming the scheduler will move tasks from the pending
 				/* Resuming the scheduler will move tasks from the pending
 				ready list into the ready list - so it is feasible that this
 				ready list into the ready list - so it is feasible that this
@@ -816,14 +766,12 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			else
 			else
 			{
 			{
 				/* Try again. */
 				/* Try again. */
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 				taskEXIT_CRITICAL(&pxQueue->mux);
 			}
 			}
 		}
 		}
 		else
 		else
 		{
 		{
 			/* The timeout has expired. */
 			/* The timeout has expired. */
-//			prvUnlockQueue( pxQueue );
 			taskEXIT_CRITICAL(&pxQueue->mux);
 			taskEXIT_CRITICAL(&pxQueue->mux);
 
 
 			/* Return to the original privilege level before exiting the
 			/* Return to the original privilege level before exiting the
@@ -940,7 +888,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 
 		configASSERT( pxQueue );
 		configASSERT( pxQueue );
 		configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
 		configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
-		ets_printf("Not Supported: %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		for( ;; )
 		for( ;; )
 		{
 		{
 			taskENTER_CRITICAL();
 			taskENTER_CRITICAL();
@@ -1129,27 +1077,18 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			disinheritance here or to clear the mutex holder TCB member. */
 			disinheritance here or to clear the mutex holder TCB member. */
 			( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
 			( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
 
 
-			/* The event list is not altered if the queue is locked.  This will
-			be done when the queue is unlocked later. */
-			if( pxQueue->xTxLock == queueUNLOCKED )
+			#if ( configUSE_QUEUE_SETS == 1 )
 			{
 			{
-				#if ( configUSE_QUEUE_SETS == 1 )
+				if( pxQueue->pxQueueSetContainer != NULL )
 				{
 				{
-					if( pxQueue->pxQueueSetContainer != NULL )
+					if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
 					{
 					{
-						if( prvNotifyQueueSetContainer( pxQueue, xCopyPosition ) == pdTRUE )
+						/* The queue is a member of a queue set, and posting
+						to the queue set caused a higher priority task to
+						unblock.  A context switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
 						{
 						{
-							/* The queue is a member of a queue set, and posting
-							to the queue set caused a higher priority task to
-							unblock.  A context switch is required. */
-							if( pxHigherPriorityTaskWoken != NULL )
-							{
-								*pxHigherPriorityTaskWoken = pdTRUE;
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
+							*pxHigherPriorityTaskWoken = pdTRUE;
 						}
 						}
 						else
 						else
 						{
 						{
@@ -1158,40 +1097,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 					}
 					}
 					else
 					else
 					{
 					{
-						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-						{
-							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-							{
-								/* The task waiting has a higher priority so
-								record that a context switch is required. */
-								if( pxHigherPriorityTaskWoken != NULL )
-								{
-									*pxHigherPriorityTaskWoken = pdTRUE;
-								}
-								else
-								{
-									mtCOVERAGE_TEST_MARKER();
-								}
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						mtCOVERAGE_TEST_MARKER();
 					}
 					}
 				}
 				}
-				#else /* configUSE_QUEUE_SETS */
+				else
 				{
 				{
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					{
 					{
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						{
 						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
+							/* The task waiting has a higher priority so
+							record that a context switch is required. */
 							if( pxHigherPriorityTaskWoken != NULL )
 							if( pxHigherPriorityTaskWoken != NULL )
 							{
 							{
 								*pxHigherPriorityTaskWoken = pdTRUE;
 								*pxHigherPriorityTaskWoken = pdTRUE;
@@ -1211,15 +1127,35 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 						mtCOVERAGE_TEST_MARKER();
 						mtCOVERAGE_TEST_MARKER();
 					}
 					}
 				}
 				}
-				#endif /* configUSE_QUEUE_SETS */
 			}
 			}
-			else
+			#else /* configUSE_QUEUE_SETS */
 			{
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was posted while it was locked. */
-				++( pxQueue->xTxLock );
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+					{
+						/* The task waiting has a higher priority so record that a
+						context	switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
+						{
+							*pxHigherPriorityTaskWoken = pdTRUE;
+						}
+						else
+						{
+							mtCOVERAGE_TEST_MARKER();
+						}
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
 			}
 			}
-
+			#endif /* configUSE_QUEUE_SETS */
 			xReturn = pdPASS;
 			xReturn = pdPASS;
 		}
 		}
 		else
 		else
@@ -1285,27 +1221,18 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 
 			++( pxQueue->uxMessagesWaiting );
 			++( pxQueue->uxMessagesWaiting );
 
 
-			/* The event list is not altered if the queue is locked.  This will
-			be done when the queue is unlocked later. */
-			if( pxQueue->xTxLock == queueUNLOCKED )
+			#if ( configUSE_QUEUE_SETS == 1 )
 			{
 			{
-				#if ( configUSE_QUEUE_SETS == 1 )
+				if( pxQueue->pxQueueSetContainer != NULL )
 				{
 				{
-					if( pxQueue->pxQueueSetContainer != NULL )
+					if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
 					{
 					{
-						if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
+						/* The semaphore is a member of a queue set, and
+						posting	to the queue set caused a higher priority
+						task to	unblock.  A context switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
 						{
 						{
-							/* The semaphore is a member of a queue set, and
-							posting	to the queue set caused a higher priority
-							task to	unblock.  A context switch is required. */
-							if( pxHigherPriorityTaskWoken != NULL )
-							{
-								*pxHigherPriorityTaskWoken = pdTRUE;
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
+							*pxHigherPriorityTaskWoken = pdTRUE;
 						}
 						}
 						else
 						else
 						{
 						{
@@ -1314,40 +1241,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 					}
 					}
 					else
 					else
 					{
 					{
-						if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-						{
-							if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-							{
-								/* The task waiting has a higher priority so
-								record that a context switch is required. */
-								if( pxHigherPriorityTaskWoken != NULL )
-								{
-									*pxHigherPriorityTaskWoken = pdTRUE;
-								}
-								else
-								{
-									mtCOVERAGE_TEST_MARKER();
-								}
-							}
-							else
-							{
-								mtCOVERAGE_TEST_MARKER();
-							}
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						mtCOVERAGE_TEST_MARKER();
 					}
 					}
 				}
 				}
-				#else /* configUSE_QUEUE_SETS */
+				else
 				{
 				{
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
 					{
 					{
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
 						{
 						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
+							/* The task waiting has a higher priority so
+							record that a context switch is required. */
 							if( pxHigherPriorityTaskWoken != NULL )
 							if( pxHigherPriorityTaskWoken != NULL )
 							{
 							{
 								*pxHigherPriorityTaskWoken = pdTRUE;
 								*pxHigherPriorityTaskWoken = pdTRUE;
@@ -1367,14 +1271,35 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 						mtCOVERAGE_TEST_MARKER();
 						mtCOVERAGE_TEST_MARKER();
 					}
 					}
 				}
 				}
-				#endif /* configUSE_QUEUE_SETS */
 			}
 			}
-			else
+			#else /* configUSE_QUEUE_SETS */
 			{
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was posted while it was locked. */
-				++( pxQueue->xTxLock );
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+					{
+						/* The task waiting has a higher priority so record that a
+						context	switch is required. */
+						if( pxHigherPriorityTaskWoken != NULL )
+						{
+							*pxHigherPriorityTaskWoken = pdTRUE;
+						}
+						else
+						{
+							mtCOVERAGE_TEST_MARKER();
+						}
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
 			}
 			}
+			#endif /* configUSE_QUEUE_SETS */
 
 
 			xReturn = pdPASS;
 			xReturn = pdPASS;
 		}
 		}
@@ -1525,7 +1450,6 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		now the critical section has been exited. */
 		now the critical section has been exited. */
 
 
 		taskENTER_CRITICAL(&pxQueue->mux);
 		taskENTER_CRITICAL(&pxQueue->mux);
-//		prvLockQueue( pxQueue );
 
 
 		/* Update the timeout state to see if it has expired yet. */
 		/* Update the timeout state to see if it has expired yet. */
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@@ -1548,20 +1472,17 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				#endif
 				#endif
 
 
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
 				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 				taskEXIT_CRITICAL(&pxQueue->mux);
 				portYIELD_WITHIN_API();
 				portYIELD_WITHIN_API();
 			}
 			}
 			else
 			else
 			{
 			{
 				/* Try again. */
 				/* Try again. */
-//				prvUnlockQueue( pxQueue );
 				taskEXIT_CRITICAL(&pxQueue->mux);
 				taskEXIT_CRITICAL(&pxQueue->mux);
 			}
 			}
 		}
 		}
 		else
 		else
 		{
 		{
-//			prvUnlockQueue( pxQueue );
 			taskEXIT_CRITICAL(&pxQueue->mux);
 			taskEXIT_CRITICAL(&pxQueue->mux);
 			traceQUEUE_RECEIVE_FAILED( pxQueue );
 			traceQUEUE_RECEIVE_FAILED( pxQueue );
 			return errQUEUE_EMPTY;
 			return errQUEUE_EMPTY;
@@ -1606,26 +1527,15 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			prvCopyDataFromQueue( pxQueue, pvBuffer );
 			prvCopyDataFromQueue( pxQueue, pvBuffer );
 			--( pxQueue->uxMessagesWaiting );
 			--( pxQueue->uxMessagesWaiting );
 
 
-			/* If the queue is locked the event list will not be modified.
-			Instead update the lock count so the task that unlocks the queue
-			will know that an ISR has removed data while the queue was
-			locked. */
-			if( pxQueue->xRxLock == queueUNLOCKED )
+			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
 			{
 			{
-				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
 				{
 				{
-					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+					/* The task waiting has a higher priority than us so
+					force a context switch. */
+					if( pxHigherPriorityTaskWoken != NULL )
 					{
 					{
-						/* The task waiting has a higher priority than us so
-						force a context switch. */
-						if( pxHigherPriorityTaskWoken != NULL )
-						{
-							*pxHigherPriorityTaskWoken = pdTRUE;
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						*pxHigherPriorityTaskWoken = pdTRUE;
 					}
 					}
 					else
 					else
 					{
 					{
@@ -1639,9 +1549,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			}
 			}
 			else
 			else
 			{
 			{
-				/* Increment the lock count so the task that unlocks the queue
-				knows that data was removed while it was locked. */
-				++( pxQueue->xRxLock );
+				mtCOVERAGE_TEST_MARKER();
 			}
 			}
 
 
 			xReturn = pdPASS;
 			xReturn = pdPASS;
@@ -1902,129 +1810,7 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue, void * const pvBuffer
 		( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports.  Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */
 		( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 MISRA exception as the casts are only redundant for some ports.  Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0. */
 	}
 	}
 }
 }
-/*-----------------------------------------------------------*/
-
-static void prvUnlockQueue( Queue_t * const pxQueue )
-{
-	/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
 
 
-	/* The lock counts contains the number of extra data items placed or
-	removed from the queue while the queue was locked.  When a queue is
-	locked items can be added or removed, but the event lists cannot be
-	updated. */
-	taskENTER_CRITICAL(&pxQueue->mux);
-	{
-		/* See if data was added to the queue while it was locked. */
-		while( pxQueue->xTxLock > queueLOCKED_UNMODIFIED )
-		{
-			/* Data was posted while the queue was locked.  Are any tasks
-			blocked waiting for data to become available? */
-			#if ( configUSE_QUEUE_SETS == 1 )
-			{
-				if( pxQueue->pxQueueSetContainer != NULL )
-				{
-					if( prvNotifyQueueSetContainer( pxQueue, queueSEND_TO_BACK ) == pdTRUE )
-					{
-						/* The queue is a member of a queue set, and posting to
-						the queue set caused a higher priority task to unblock.
-						A context switch is required. */
-						taskEXIT_CRITICAL(&pxQueue->mux); //ToDo: Is aquire/release needed around any of the bTaskMissedYield calls?
-						vTaskMissedYield();
-						taskENTER_CRITICAL(&pxQueue->mux);
-					}
-					else
-					{
-						mtCOVERAGE_TEST_MARKER();
-					}
-				}
-				else
-				{
-					/* Tasks that are removed from the event list will get added to
-					the pending ready list as the scheduler is still suspended. */
-					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-					{
-						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-						{
-							/* The task waiting has a higher priority so record that a
-							context	switch is required. */
-							taskEXIT_CRITICAL(&pxQueue->mux);
-							vTaskMissedYield();
-							taskENTER_CRITICAL(&pxQueue->mux);
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
-					}
-					else
-					{
-						break;
-					}
-				}
-			}
-			#else /* configUSE_QUEUE_SETS */
-			{
-				/* Tasks that are removed from the event list will get added to
-				the pending ready list as the scheduler is still suspended. */
-				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-				{
-					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-					{
-						/* The task waiting has a higher priority so record that a
-						context	switch is required. */
-						taskEXIT_CRITICAL(&pxQueue->mux);
-						vTaskMissedYield();
-						taskENTER_CRITICAL(&pxQueue->mux);
-					}
-					else
-					{
-						mtCOVERAGE_TEST_MARKER();
-					}
-				}
-				else
-				{
-					break;
-				}
-			}
-			#endif /* configUSE_QUEUE_SETS */
-
-			--( pxQueue->xTxLock );
-		}
-
-		pxQueue->xTxLock = queueUNLOCKED;
-	}
-	taskEXIT_CRITICAL(&pxQueue->mux);
-
-	/* Do the same for the Rx lock. */
-	taskENTER_CRITICAL(&pxQueue->mux);
-	{
-		while( pxQueue->xRxLock > queueLOCKED_UNMODIFIED )
-		{
-			if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
-			{
-				if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
-				{
-					taskEXIT_CRITICAL(&pxQueue->mux);
-					vTaskMissedYield();
-					taskENTER_CRITICAL(&pxQueue->mux);
-				}
-				else
-				{
-					mtCOVERAGE_TEST_MARKER();
-				}
-
-				--( pxQueue->xRxLock );
-			}
-			else
-			{
-				break;
-			}
-		}
-
-		pxQueue->xRxLock = queueUNLOCKED;
-	}
-	taskEXIT_CRITICAL(&pxQueue->mux);
-}
 /*-----------------------------------------------------------*/
 /*-----------------------------------------------------------*/
 
 
 static BaseType_t prvIsQueueEmpty( Queue_t *pxQueue )
 static BaseType_t prvIsQueueEmpty( Queue_t *pxQueue )
@@ -2117,6 +1903,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 	BaseType_t xReturn;
 	BaseType_t xReturn;
 	Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 	Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 
+		UNTESTED_FUNCTION();
 		/* If the queue is already full we may have to block.  A critical section
 		/* If the queue is already full we may have to block.  A critical section
 		is required to prevent an interrupt removing something from the queue
 		is required to prevent an interrupt removing something from the queue
 		between the check to see if the queue is full and blocking on the queue. */
 		between the check to see if the queue is full and blocking on the queue. */
@@ -2390,7 +2177,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 	void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	void vQueueAddToRegistry( QueueHandle_t xQueue, const char *pcQueueName ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	{
 	{
 	UBaseType_t ux;
 	UBaseType_t ux;
-
+		
+		UNTESTED_FUNCTION();
 		/* See if there is an empty space in the registry.  A NULL name denotes
 		/* See if there is an empty space in the registry.  A NULL name denotes
 		a free slot. */
 		a free slot. */
 		for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
 		for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
@@ -2458,10 +2246,8 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		/* Only do anything if there are no messages in the queue.  This function
 		/* Only do anything if there are no messages in the queue.  This function
 		will not actually cause the task to block, just place it on a blocked
 		will not actually cause the task to block, just place it on a blocked
 		list.  It will not block until the scheduler is unlocked - at which
 		list.  It will not block until the scheduler is unlocked - at which
-		time a yield will be performed.  If an item is added to the queue while
-		the queue is locked, and the calling task blocks on the queue, then the
-		calling task will be immediately unblocked when the queue is unlocked. */
-//		prvLockQueue( pxQueue );
+		time a yield will be performed.  */
+		taskENTER_CRITICAL(&pxQueue->mux);
 		if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
 		if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
 		{
 		{
 			/* There is nothing in the queue, block for the specified period. */
 			/* There is nothing in the queue, block for the specified period. */
@@ -2471,7 +2257,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		{
 		{
 			mtCOVERAGE_TEST_MARKER();
 			mtCOVERAGE_TEST_MARKER();
 		}
 		}
-//		prvUnlockQueue( pxQueue );
+		taskEXIT_CRITICAL(&pxQueue->mux);
 	}
 	}
 
 
 #endif /* configUSE_TIMERS */
 #endif /* configUSE_TIMERS */

+ 474 - 0
components/freertos/ringbuf.c

@@ -0,0 +1,474 @@
+// 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 "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+#include "freertos/queue.h"
+#include "freertos/xtensa_api.h"
+#include "freertos/ringbuf.h"
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef enum {
+    flag_allowsplit = 1,
+} rbflag_t;
+
+typedef enum {
+    iflag_free = 1,             //Buffer is not read and given back by application, free to overwrite
+    iflag_dummydata = 2,        //Data from here to end of ringbuffer is dummy. Restart reading at start of ringbuffer.
+} itemflag_t;
+
+
+//The ringbuffer structure
+typedef struct {
+    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
+    uint8_t *write_ptr;                         //Pointer where the next item is written
+    uint8_t *read_ptr;                          //Pointer from where the next item is read
+    uint8_t *free_ptr;                          //Pointer to the last block that hasn't been given back to the ringbuffer yet
+    uint8_t *data;                              //Data storage
+    portMUX_TYPE mux;                           //Spinlock for actual data/ptr/struct modification
+    rbflag_t flags;
+} ringbuf_t;
+
+
+
+/*
+Remark: A counting semaphore for items_buffered_sem would be more logical, but counting semaphores in
+FreeRTOS need a maximum count, and allocate more memory the larger the maximum count is. Here, we
+would need to set the maximum to the maximum amount of times a null-byte unit firs in the buffer,
+which is quite high and so would waste a fair amount of memory.
+*/
+
+
+//The header prepended to each ringbuffer entry. Size is assumed to be a multiple of 32bits.
+typedef struct {
+    size_t len;
+    itemflag_t flags;
+} buf_entry_hdr_t;
+
+
+//Calculate space free in the buffer
+static int ringbufferFreeMem(ringbuf_t *rb) 
+{
+    int free_size = rb->free_ptr-rb->write_ptr;
+    if (free_size <= 0) free_size += rb->size;
+    //Reserve one byte. If we do not do this and the entire buffer is filled, we get a situation 
+    //where read_ptr == free_ptr, messing up the next calculation.
+    return free_size-1;
+}
+
+//Copies a single item to the ring buffer. 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) 
+{
+    size_t 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)) {
+        //The buffer can't be contiguously written to the ringbuffer, but needs special handling. Do
+        //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;
+        } 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;
+        }
+    } 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;
+}
+
+//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)
+{
+    uint8_t *ret;
+    configASSERT(((int)rb->read_ptr&3)==0);
+    if (rb->read_ptr == rb->write_ptr) {
+        //No data available.
+        return NULL;
+    }
+    //The item written at the point of the read pointer may be a dummy item.
+    //We need to skip past it first, if that's the case.
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t *)rb->read_ptr;
+    configASSERT((hdr->len < rb->size) || (hdr->flags & iflag_dummydata));
+    if (hdr->flags & iflag_dummydata) {
+        //Hdr is dummy data. Reset to start of ringbuffer.
+        rb->read_ptr=rb->data;
+        //Get real header
+        hdr=(buf_entry_hdr_t *)rb->read_ptr;
+        configASSERT(hdr->len < rb->size);
+        //No need to re-check if the ringbuffer is empty: the write routine will
+        //always write a dummy item plus the real data item in one go, so now we must
+        //be at the real data item by definition.
+    }
+    //Okay, pass the data back.
+    ret=rb->read_ptr+sizeof(buf_entry_hdr_t);
+    *length=hdr->len;
+    //...and move the read pointer past the data.
+    rb->read_ptr+=sizeof(buf_entry_hdr_t)+((hdr->len+3)&~3);
+    //The buffer will wrap around if we don't have room for a header anymore.
+    if ((rb->data + rb->size) - rb->read_ptr < sizeof(buf_entry_hdr_t)) {
+        rb->read_ptr=rb->data;
+    }
+    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) {
+    uint8_t *data=(uint8_t*)item;
+    configASSERT(((int)rb->free_ptr&3)==0);
+    configASSERT(data >= rb->data);
+    configASSERT(data < rb->data+rb->size);
+    //Grab the buffer entry that preceeds the buffer
+    buf_entry_hdr_t *hdr=(buf_entry_hdr_t*)(data-sizeof(buf_entry_hdr_t));
+    configASSERT(hdr->len < rb->size);
+    configASSERT((hdr->flags & iflag_dummydata)==0);
+    configASSERT((hdr->flags & iflag_free)==0);
+    //Mark the buffer as free.
+    hdr->flags|=iflag_free;
+
+    //Do a cleanup pass.
+    hdr=(buf_entry_hdr_t *)rb->free_ptr;
+    //basically forward free_ptr until we run into either a block that is still in use or the write pointer.
+    while (((hdr->flags & iflag_free) || (hdr->flags & iflag_dummydata)) && rb->free_ptr != rb->write_ptr) {
+        if (hdr->flags & iflag_dummydata) {
+            //Rest is dummy data. Reset to start of ringbuffer.
+            rb->free_ptr=rb->data;
+        } else {
+            //Skip past item
+            size_t len=(hdr->len+3)&~3;
+            rb->free_ptr+=len+sizeof(buf_entry_hdr_t);
+            configASSERT(rb->free_ptr<=rb->data+rb->size);
+        }
+        //The buffer will wrap around if we don't have room for a header anymore.
+        if ((rb->data+rb->size)-rb->free_ptr < sizeof(buf_entry_hdr_t)) {
+            rb->free_ptr=rb->data;
+        }
+        //Next header
+        hdr=(buf_entry_hdr_t *)rb->free_ptr;
+    }
+}
+
+
+void xRingbufferPrintInfo(RingbufHandle_t ringbuf)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    ets_printf("Rb size %d free %d rptr %d freeptr %d wptr %d\n",
+            rb->size, ringbufferFreeMem(rb), rb->read_ptr-rb->data, rb->free_ptr-rb->data, rb->write_ptr-rb->data);
+}
+
+
+
+RingbufHandle_t xRingbufferCreate(size_t buf_length, BaseType_t allow_split_items)
+{
+    ringbuf_t *rb = malloc(sizeof(ringbuf_t));
+    if (rb==NULL) goto err;
+    memset(rb, 0, sizeof(ringbuf_t));
+    rb->data = malloc(buf_length);
+    if (rb->data == NULL) goto err;
+    rb->size = buf_length;
+    rb->free_ptr = rb->data;
+    rb->read_ptr = rb->data;
+    rb->write_ptr = rb->data;
+    rb->free_space_sem = xSemaphoreCreateBinary();
+    rb->items_buffered_sem = xSemaphoreCreateBinary();
+    rb->flags=0;
+    if (allow_split_items) rb->flags|=flag_allowsplit;
+    if (rb->free_space_sem == NULL || rb->items_buffered_sem == NULL) goto err;
+    vPortCPUInitializeMutex(&rb->mux);
+    return (RingbufHandle_t)rb;
+
+err:
+    //Some error has happened. Free/destroy all allocated things and return NULL.
+    if (rb) {
+        free(rb->data);
+        if (rb->free_space_sem) vSemaphoreDelete(rb->free_space_sem);
+        if (rb->items_buffered_sem) vSemaphoreDelete(rb->items_buffered_sem);
+    }
+    free(rb);
+    return NULL;
+}
+
+void vRingbufferDelete(RingbufHandle_t ringbuf) {
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    if (rb) {
+        free(rb->data);
+        if (rb->free_space_sem) vSemaphoreDelete(rb->free_space_sem);
+        if (rb->items_buffered_sem) vSemaphoreDelete(rb->items_buffered_sem);
+    }
+    free(rb);
+}
+
+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;
+    }
+}
+
+BaseType_t xRingbufferSend(RingbufHandle_t ringbuf, void *data, size_t dataSize, TickType_t ticks_to_wait)
+{
+    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;
+
+    configASSERT(rb);
+
+    if (dataSize > xRingbufferGetMaxItemSize(ringbuf)) {
+        //Data will never ever fit in the queue.
+        return pdFALSE;
+    }
+
+    while (!done) {
+        //Check if there is enough room in the buffer. If not, wait until there is.
+        do {
+            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);
+                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,
+                //we will need to wait some more.
+                ticks_to_wait = ticks_end - xTaskGetTickCount();
+            }
+        } while (ringbufferFreeMem(rb) < needed_size && ticks_to_wait>=0);
+        
+        //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);
+        portEXIT_CRITICAL(&rb->mux);
+    }
+    xSemaphoreGive(rb->items_buffered_sem);
+    return pdTRUE;
+}
+
+
+BaseType_t xRingbufferSendFromISR(RingbufHandle_t ringbuf, void *data, size_t dataSize, BaseType_t *higher_prio_task_awoken) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    BaseType_t write_succeeded;
+    configASSERT(rb);
+    size_t needed_size=dataSize+sizeof(buf_entry_hdr_t);
+    portENTER_CRITICAL_ISR(&rb->mux);
+    if (needed_size>ringbufferFreeMem(rb)) {
+        //Does not fit in the remaining space in the ringbuffer.
+        write_succeeded=pdFALSE;
+    } else {
+        copyItemToRingbuf(rb, data, dataSize);
+        write_succeeded=pdTRUE;
+    }
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    if (write_succeeded) {
+        xSemaphoreGiveFromISR(rb->items_buffered_sem, higher_prio_task_awoken);
+    }
+    return write_succeeded;
+}
+
+
+void *xRingbufferReceive(RingbufHandle_t ringbuf, size_t *item_size, TickType_t ticks_to_wait) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    uint8_t *itemData;
+    BaseType_t done=pdFALSE;
+    configASSERT(rb);
+    while(!done) {
+        //See if there's any data available. If not, wait until there is.
+        while (rb->read_ptr == rb->write_ptr) {
+            BaseType_t r=xSemaphoreTake(rb->items_buffered_sem, ticks_to_wait);
+            if (r == pdFALSE) {
+                //Timeout.
+                return NULL;
+            }
+        }
+        //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);
+        portEXIT_CRITICAL(&rb->mux);
+        if (itemData) {
+            //We managed to get an item.
+            done=pdTRUE;
+        }
+    }
+    return (void*)itemData;
+}
+
+
+void *xRingbufferReceiveFromISR(RingbufHandle_t ringbuf, size_t *item_size) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    uint8_t *itemData;
+    configASSERT(rb);
+    portENTER_CRITICAL_ISR(&rb->mux);
+    itemData=getItemFromRingbuf(rb, item_size);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    return (void*)itemData;
+}
+
+
+void vRingbufferReturnItem(RingbufHandle_t ringbuf, void *item) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    portENTER_CRITICAL_ISR(&rb->mux);
+    returnItemToRingbuf(rb, item);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    xSemaphoreGive(rb->free_space_sem);
+}
+
+
+void vRingbufferReturnItemFromISR(RingbufHandle_t ringbuf, void *item, BaseType_t *higher_prio_task_awoken) 
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    portENTER_CRITICAL_ISR(&rb->mux);
+    returnItemToRingbuf(rb, item);
+    portEXIT_CRITICAL_ISR(&rb->mux);
+    xSemaphoreGiveFromISR(rb->free_space_sem, higher_prio_task_awoken);
+}
+
+
+BaseType_t xRingbufferAddToQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueAddToSet(rb->items_buffered_sem, xQueueSet);
+}
+
+
+BaseType_t xRingbufferAddToQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueAddToSet(rb->free_space_sem, xQueueSet);
+}
+
+
+BaseType_t xRingbufferRemoveFromQueueSetRead(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueRemoveFromSet(rb->items_buffered_sem, xQueueSet);
+}
+
+BaseType_t xRingbufferRemoveFromQueueSetWrite(RingbufHandle_t ringbuf, QueueSetHandle_t xQueueSet)
+{
+    ringbuf_t *rb=(ringbuf_t *)ringbuf;
+    configASSERT(rb);
+    return xQueueRemoveFromSet(rb->free_space_sem, xQueueSet);
+}
+

+ 33 - 28
components/freertos/tasks.c

@@ -129,6 +129,9 @@ functions but without including stdio.h here. */
 					} while(0)
 					} while(0)
 #endif
 #endif
 
 
+
+
+
 /* Value that can be assigned to the eNotifyState member of the TCB. */
 /* Value that can be assigned to the eNotifyState member of the TCB. */
 typedef enum
 typedef enum
 {
 {
@@ -157,7 +160,7 @@ typedef struct tskTaskControlBlock
 	StackType_t			*pxStack;			/*< Points to the start of the stack. */
 	StackType_t			*pxStack;			/*< Points to the start of the stack. */
 	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 	BaseType_t			xCoreID;			/*< Core this task is pinned to */
 	BaseType_t			xCoreID;			/*< Core this task is pinned to */
-
+											/* If this moves around (other than pcTaskName size changes), please change the define in xtensa_vectors.S as well. */
 	#if ( portSTACK_GROWTH > 0 )
 	#if ( portSTACK_GROWTH > 0 )
 		StackType_t		*pxEndOfStack;		/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
 		StackType_t		*pxEndOfStack;		/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
 	#endif
 	#endif
@@ -275,9 +278,7 @@ when the scheduler is unsuspended.  The pending ready list itself can only be
 accessed from a critical section. */
 accessed from a critical section. */
 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended[ portNUM_PROCESSORS ]	= { ( UBaseType_t ) pdFALSE };
 PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended[ portNUM_PROCESSORS ]	= { ( UBaseType_t ) pdFALSE };
 
 
-/* Muxes used in the task code */
-PRIVILEGED_DATA static portBASE_TYPE xMutexesInitialised = pdFALSE;
-/* For now, we use just one mux for all the critical sections. ToDo: give evrything a bit more granularity;
+/* For now, we use just one mux for all the critical sections. ToDo: give everything a bit more granularity;
   that could improve performance by not needlessly spinning in spinlocks for unrelated resources. */
   that could improve performance by not needlessly spinning in spinlocks for unrelated resources. */
 PRIVILEGED_DATA static portMUX_TYPE xTaskQueueMutex = portMUX_INITIALIZER_UNLOCKED;
 PRIVILEGED_DATA static portMUX_TYPE xTaskQueueMutex = portMUX_INITIALIZER_UNLOCKED;
 PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCKED;
 PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCKED;
@@ -577,15 +578,6 @@ static void prvResetNextTaskUnblockTime( void );
 
 
 #endif
 #endif
 
 
-/*-----------------------------------------------------------*/
-
-
-static void vTaskInitializeLocalMuxes( void )
-{
-	vPortCPUInitializeMutex(&xTaskQueueMutex);
-	vPortCPUInitializeMutex(&xTickCountMutex);
-	xMutexesInitialised = pdTRUE;
-}
 
 
 /*-----------------------------------------------------------*/
 /*-----------------------------------------------------------*/
 
 
@@ -595,10 +587,6 @@ BaseType_t xReturn;
 TCB_t * pxNewTCB;
 TCB_t * pxNewTCB;
 StackType_t *pxTopOfStack;
 StackType_t *pxTopOfStack;
 BaseType_t i;
 BaseType_t i;
-	
-	/* Initialize mutexes, if they're not already initialized. */
-	if (xMutexesInitialised == pdFALSE) vTaskInitializeLocalMuxes();
-	
 	configASSERT( pxTaskCode );
 	configASSERT( pxTaskCode );
 	configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
 	configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
 	configASSERT( (xCoreID>=0 && xCoreID<portNUM_PROCESSORS) || (xCoreID==tskNO_AFFINITY) );
 	configASSERT( (xCoreID>=0 && xCoreID<portNUM_PROCESSORS) || (xCoreID==tskNO_AFFINITY) );
@@ -873,7 +861,7 @@ BaseType_t i;
 	TickType_t xTimeToWake;
 	TickType_t xTimeToWake;
 	BaseType_t xAlreadyYielded=pdFALSE, xShouldDelay = pdFALSE;
 	BaseType_t xAlreadyYielded=pdFALSE, xShouldDelay = pdFALSE;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		configASSERT( pxPreviousWakeTime );
 		configASSERT( pxPreviousWakeTime );
 		configASSERT( ( xTimeIncrement > 0U ) );
 		configASSERT( ( xTimeIncrement > 0U ) );
 		configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 );
 		configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 );
@@ -1043,7 +1031,7 @@ BaseType_t i;
 	List_t *pxStateList;
 	List_t *pxStateList;
 	const TCB_t * const pxTCB = ( TCB_t * ) xTask;
 	const TCB_t * const pxTCB = ( TCB_t * ) xTask;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		configASSERT( pxTCB );
 		configASSERT( pxTCB );
 
 
 		if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
 		if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
@@ -1113,7 +1101,7 @@ BaseType_t i;
 	TCB_t *pxTCB;
 	TCB_t *pxTCB;
 	UBaseType_t uxReturn;
 	UBaseType_t uxReturn;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 		{
 			/* If null is passed in here then we are changing the
 			/* If null is passed in here then we are changing the
@@ -1321,7 +1309,7 @@ BaseType_t i;
 	{
 	{
 	TCB_t *pxTCB;
 	TCB_t *pxTCB;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 		{
 			/* If null is passed in here then it is the running task that is
 			/* If null is passed in here then it is the running task that is
@@ -1462,7 +1450,7 @@ BaseType_t i;
 	{
 	{
 	TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
 	TCB_t * const pxTCB = ( TCB_t * ) xTaskToResume;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		/* It does not make sense to resume the calling task. */
 		/* It does not make sense to resume the calling task. */
 		configASSERT( xTaskToResume );
 		configASSERT( xTaskToResume );
 
 
@@ -1725,10 +1713,6 @@ BaseType_t xAlreadyYielded = pdFALSE;
 	scheduler has been resumed it is safe to move all the pending ready
 	scheduler has been resumed it is safe to move all the pending ready
 	tasks from this list into their appropriate ready list. */
 	tasks from this list into their appropriate ready list. */
 
 
-	//This uses a mux, but can be called before tasks are scheduled. Make sure muxes are inited.
-	/* Initialize mutexes, if they're not already initialized. */
-	if (xMutexesInitialised == pdFALSE) vTaskInitializeLocalMuxes();
-
 	taskENTER_CRITICAL(&xTaskQueueMutex);
 	taskENTER_CRITICAL(&xTaskQueueMutex);
 	{
 	{
 		--uxSchedulerSuspended[ xPortGetCoreID() ];
 		--uxSchedulerSuspended[ xPortGetCoreID() ];
@@ -1868,7 +1852,7 @@ UBaseType_t uxTaskGetNumberOfTasks( void )
 	{
 	{
 	UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
 	UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		vTaskSuspendAll(); //WARNING: This only suspends one CPU. ToDo: suspend others as well. Mux using taskQueueMutex maybe?
 		vTaskSuspendAll(); //WARNING: This only suspends one CPU. ToDo: suspend others as well. Mux using taskQueueMutex maybe?
 		{
 		{
 			/* Is there a space in the array for each task in the system? */
 			/* Is there a space in the array for each task in the system? */
@@ -3154,7 +3138,7 @@ UBaseType_t x;
 	{
 	{
 	TCB_t *pxTCB;
 	TCB_t *pxTCB;
 
 
-		ets_printf("ToDo %s\n", __FUNCTION__);
+		UNTESTED_FUNCTION();
 		/* If null is passed in here then we are deleting ourselves. */
 		/* If null is passed in here then we are deleting ourselves. */
 		pxTCB = prvGetTCBFromHandle( xTaskToModify );
 		pxTCB = prvGetTCBFromHandle( xTaskToModify );
 
 
@@ -3355,6 +3339,18 @@ TCB_t *pxNewTCB;
 }
 }
 /*-----------------------------------------------------------*/
 /*-----------------------------------------------------------*/
 
 
+BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
+{
+	TCB_t *pxTCB;
+	UBaseType_t uxReturn;
+
+	pxTCB = prvGetTCBFromHandle( xTask );
+
+	return pxTCB->xCoreID;
+}
+/*-----------------------------------------------------------*/
+
+
 #if ( configUSE_TRACE_FACILITY == 1 )
 #if ( configUSE_TRACE_FACILITY == 1 )
 
 
 	static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
 	static UBaseType_t prvListTaskWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
@@ -3362,6 +3358,7 @@ TCB_t *pxNewTCB;
 	volatile TCB_t *pxNextTCB, *pxFirstTCB;
 	volatile TCB_t *pxNextTCB, *pxFirstTCB;
 	UBaseType_t uxTask = 0;
 	UBaseType_t uxTask = 0;
 
 
+		UNTESTED_FUNCTION();
 		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
 		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
 		{
 		{
 			listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
 			listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList );
@@ -3468,6 +3465,7 @@ TCB_t *pxNewTCB;
 	uint8_t *pucEndOfStack;
 	uint8_t *pucEndOfStack;
 	UBaseType_t uxReturn;
 	UBaseType_t uxReturn;
 
 
+		UNTESTED_FUNCTION();
 		pxTCB = prvGetTCBFromHandle( xTask );
 		pxTCB = prvGetTCBFromHandle( xTask );
 
 
 		#if portSTACK_GROWTH < 0
 		#if portSTACK_GROWTH < 0
@@ -3899,6 +3897,7 @@ scheduler will re-enable the interrupts instead. */
 	TaskStatus_t *pxTaskStatusArray;
 	TaskStatus_t *pxTaskStatusArray;
 	volatile UBaseType_t uxArraySize, x;
 	volatile UBaseType_t uxArraySize, x;
 	char cStatus;
 	char cStatus;
+		UNTESTED_FUNCTION();
 
 
 		/*
 		/*
 		 * PLEASE NOTE:
 		 * PLEASE NOTE:
@@ -3992,6 +3991,7 @@ scheduler will re-enable the interrupts instead. */
 	volatile UBaseType_t uxArraySize, x;
 	volatile UBaseType_t uxArraySize, x;
 	uint32_t ulTotalTime, ulStatsAsPercentage;
 	uint32_t ulTotalTime, ulStatsAsPercentage;
 
 
+		UNTESTED_FUNCTION();
 		#if( configUSE_TRACE_FACILITY != 1 )
 		#if( configUSE_TRACE_FACILITY != 1 )
 		{
 		{
 			#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
 			#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
@@ -4149,6 +4149,7 @@ TickType_t uxReturn;
 	TickType_t xTimeToWake;
 	TickType_t xTimeToWake;
 	uint32_t ulReturn;
 	uint32_t ulReturn;
 
 
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 		{
 			/* Only block if the notification count is not already non-zero. */
 			/* Only block if the notification count is not already non-zero. */
@@ -4259,6 +4260,7 @@ TickType_t uxReturn;
 	TickType_t xTimeToWake;
 	TickType_t xTimeToWake;
 	BaseType_t xReturn;
 	BaseType_t xReturn;
 
 
+		UNTESTED_FUNCTION();
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		taskENTER_CRITICAL(&xTaskQueueMutex);
 		{
 		{
 			/* Only block if a notification is not already pending. */
 			/* Only block if a notification is not already pending. */
@@ -4381,6 +4383,7 @@ TickType_t uxReturn;
 	eNotifyValue eOriginalNotifyState;
 	eNotifyValue eOriginalNotifyState;
 	BaseType_t xReturn = pdPASS;
 	BaseType_t xReturn = pdPASS;
 
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 		configASSERT( xTaskToNotify );
 		pxTCB = ( TCB_t * ) xTaskToNotify;
 		pxTCB = ( TCB_t * ) xTaskToNotify;
 
 
@@ -4465,6 +4468,7 @@ TickType_t uxReturn;
 	eNotifyValue eOriginalNotifyState;
 	eNotifyValue eOriginalNotifyState;
 	BaseType_t xReturn = pdPASS;
 	BaseType_t xReturn = pdPASS;
 
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 		configASSERT( xTaskToNotify );
 
 
 		pxTCB = ( TCB_t * ) xTaskToNotify;
 		pxTCB = ( TCB_t * ) xTaskToNotify;
@@ -4558,6 +4562,7 @@ TickType_t uxReturn;
 	TCB_t * pxTCB;
 	TCB_t * pxTCB;
 	eNotifyValue eOriginalNotifyState;
 	eNotifyValue eOriginalNotifyState;
 
 
+		UNTESTED_FUNCTION();
 		configASSERT( xTaskToNotify );
 		configASSERT( xTaskToNotify );
 
 
 
 

+ 20 - 0
components/freertos/xtensa_vectors.S

@@ -92,6 +92,12 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 
 #include "xtensa_rtos.h"
 #include "xtensa_rtos.h"
 
 
+/*
+  Define for workaround: pin no-cpu-affinity tasks to a cpu when fpu is used.
+  Please change this when the tcb structure is changed
+*/
+#define TASKTCB_XCOREID_OFFSET (0x3C+configMAX_TASK_NAME_LEN+3)&~3
+.extern pxCurrentTCB
 
 
 /* Enable stack backtrace across exception/interrupt - see below */
 /* Enable stack backtrace across exception/interrupt - see below */
 #define XT_DEBUG_BACKTRACE    0
 #define XT_DEBUG_BACKTRACE    0
@@ -892,6 +898,20 @@ _xt_coproc_exc:
     addx4   a0, a5, a0                      /* a0 = &_xt_coproc_mask[n] */
     addx4   a0, a5, a0                      /* a0 = &_xt_coproc_mask[n] */
     l32i    a0, a0, 0                       /* a0 = (n << 16) | (1 << n) */
     l32i    a0, a0, 0                       /* a0 = (n << 16) | (1 << n) */
 
 
+    /* TODO: Remove this as soon as coprocessor state moving works across cores - JD */
+    /* FPU operations are incompatible with non-pinned tasks. If we have a FPU operation
+       here, to keep the entire thing from crashing, it's better to pin the task to whatever
+       core we're running on now. */
+    movi    a2, pxCurrentTCB
+    getcoreid a3
+    slli    a3,  a3, 2
+    add     a2,  a2, a3
+    l32i    a2, a2, 0                       /* a2 = start of pxCurrentTCB[cpuid] */
+    addi    a2, a2, TASKTCB_XCOREID_OFFSET  /* offset to xCoreID in tcb struct */
+    getcoreid a3
+    s32i    a3, a2, 0                       /* store current cpuid */
+
+	/* Grab correct xt_coproc_owner_sa for this core */
 	getcoreid a2
 	getcoreid a2
 	movi    a3, XCHAL_CP_MAX << 2
 	movi    a3, XCHAL_CP_MAX << 2
 	mull    a2, a2, a3
 	mull    a2, a2, a3

+ 7 - 7
components/log/Kconfig

@@ -28,13 +28,13 @@ config LOG_DEFAULT_LEVEL_VERBOSE
 endchoice
 endchoice
 
 
 config LOG_DEFAULT_LEVEL
 config LOG_DEFAULT_LEVEL
-	int
-	default 0 if LOG_DEFAULT_LEVEL_NONE
-	default 1 if LOG_DEFAULT_LEVEL_ERROR
-	default 2 if LOG_DEFAULT_LEVEL_WARN
-	default 3 if LOG_DEFAULT_LEVEL_INFO
-	default 4 if LOG_DEFAULT_LEVEL_DEBUG
-	default 5 if LOG_DEFAULT_LEVEL_VERBOSE
+    int
+    default 0 if LOG_DEFAULT_LEVEL_NONE
+    default 1 if LOG_DEFAULT_LEVEL_ERROR
+    default 2 if LOG_DEFAULT_LEVEL_WARN
+    default 3 if LOG_DEFAULT_LEVEL_INFO
+    default 4 if LOG_DEFAULT_LEVEL_DEBUG
+    default 5 if LOG_DEFAULT_LEVEL_VERBOSE
 
 
 config LOG_COLORS
 config LOG_COLORS
    bool "Use ANSI terminal colors in log output"
    bool "Use ANSI terminal colors in log output"

+ 17 - 17
components/lwip/Kconfig

@@ -1,27 +1,27 @@
 menu "LWIP"
 menu "LWIP"
 
 
 config LWIP_MAX_SOCKETS
 config LWIP_MAX_SOCKETS
-	int "Max number of open sockets"
-	range 1 16
-	default 4
-	help
-		Sockets take up a certain amount of memory, and allowing fewer
-		sockets to be open at the same time conserves memory. Specify
-		the maximum amount of sockets here.
+    int "Max number of open sockets"
+    range 1 16
+    default 4
+    help
+        Sockets take up a certain amount of memory, and allowing fewer
+        sockets to be open at the same time conserves memory. Specify
+        the maximum amount of sockets here.
 
 
 config LWIP_THREAD_LOCAL_STORAGE_INDEX
 config LWIP_THREAD_LOCAL_STORAGE_INDEX
-	int "Index for thread-local-storage pointer for lwip"
-	default 0
-	help
-		Specify the thread-local-storage-pointer index for lwip
-		use.
+    int "Index for thread-local-storage pointer for lwip"
+    default 0
+    help
+        Specify the thread-local-storage-pointer index for lwip
+        use.
 
 
 config LWIP_SO_REUSE
 config LWIP_SO_REUSE
-	bool "Enable SO_REUSEADDR option"
-	default 0
-	help
-		Enabling this option allows binding to a port which remains in 
-		TIME_WAIT.
+    bool "Enable SO_REUSEADDR option"
+    default 0
+    help
+        Enabling this option allows binding to a port which remains in
+        TIME_WAIT.
 
 
 endmenu
 endmenu
 
 

+ 1 - 1
components/lwip/component.mk

@@ -6,6 +6,6 @@ COMPONENT_ADD_INCLUDEDIRS := include/lwip include/lwip/port include/lwip/posix
 
 
 COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/freertos port/netif port
 COMPONENT_SRCDIRS := api apps/sntp apps core/ipv4 core/ipv6 core netif port/freertos port/netif port
 
 
-CFLAGS += -Wno-error=address -Waddress
+CFLAGS += -Wno-address -Wno-unused-variable -Wno-unused-but-set-variable
 
 
 include $(IDF_PATH)/make/component_common.mk
 include $(IDF_PATH)/make/component_common.mk

+ 11 - 1
components/lwip/include/lwip/port/arch/sys_arch.h

@@ -38,6 +38,11 @@
 #include "freertos/queue.h"
 #include "freertos/queue.h"
 #include "freertos/semphr.h"
 #include "freertos/semphr.h"
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
 typedef xSemaphoreHandle sys_sem_t;
 typedef xSemaphoreHandle sys_sem_t;
 typedef xSemaphoreHandle sys_mutex_t;
 typedef xSemaphoreHandle sys_mutex_t;
 typedef xTaskHandle sys_thread_t;
 typedef xTaskHandle sys_thread_t;
@@ -67,6 +72,11 @@ uint32_t system_get_time(void);
 void sys_delay_ms(uint32_t ms);
 void sys_delay_ms(uint32_t ms);
 sys_sem_t* sys_thread_sem_init(void);
 sys_sem_t* sys_thread_sem_init(void);
 void sys_thread_sem_deinit(void);
 void sys_thread_sem_deinit(void);
-sys_sem_t* sys_thread_sem_get(void);
+sys_sem_t* sys_thread_sem_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* __SYS_ARCH_H__ */
 #endif /* __SYS_ARCH_H__ */
 
 

+ 8 - 0
components/lwip/include/lwip/port/netif/wlanif.h

@@ -10,6 +10,10 @@
 
 
 #include "lwip/err.h"
 #include "lwip/err.h"
 
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 err_t wlanif_init(struct netif *netif);
 err_t wlanif_init(struct netif *netif);
 
 
 void wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb);
 void wlanif_input(struct netif *netif, void *buffer, u16_t len, void* eb);
@@ -20,4 +24,8 @@ wifi_interface_t wifi_get_interface(void *dev);
 
 
 void netif_reg_addr_change_cb(void* cb);
 void netif_reg_addr_change_cb(void* cb);
 
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /*  _WLAN_LWIP_IF_H_ */
 #endif /*  _WLAN_LWIP_IF_H_ */

+ 37 - 0
components/mbedtls/Kconfig

@@ -0,0 +1,37 @@
+menu "mbedTLS"
+
+config MBEDTLS_SSL_MAX_CONTENT_LEN
+    int "TLS maximum message content length"
+    default 16384
+    range 512 16384
+    help
+        Maximum TLS message length (in bytes) supported by mbedTLS.
+        
+        16384 is the default and this value is required to comply
+        fully with TLS standards.
+        
+        However you can set a lower value in order to save RAM. This
+        is safe if the other end of the connection supports Maximum
+        Fragment Length Negotiation Extension (max_fragment_length,
+        see RFC6066) or you know for certain that it will never send a
+        message longer than a certain number of bytes.
+        
+        If the value is set too low, symptoms are a failed TLS
+        handshake or a return value of MBEDTLS_ERR_SSL_INVALID_RECORD
+        (-0x7200).
+
+config MBEDTLS_DEBUG
+   bool "Enable mbedTLS debugging"
+   default "no"
+   help
+       Enable mbedTLS debugging functions.
+       
+       If this option is enabled, use the mbedtls_debug_set_threshold()
+       and mbedtls_ssl_conf_dbg() functions to obtain debugging output
+       from mbedTLS.
+       
+       Note thatm mbedTLS debugging is not related to the ESP logging
+       functionality. See the "https_request_main" example for a
+       sample function which connects the two together.
+
+endmenu

+ 5 - 1
components/mbedtls/port/include/mbedtls/esp_config.h

@@ -27,6 +27,8 @@
 #ifndef MBEDTLS_CONFIG_H
 #ifndef MBEDTLS_CONFIG_H
 #define MBEDTLS_CONFIG_H
 #define MBEDTLS_CONFIG_H
 
 
+#include "sdkconfig.h"
+
 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
 #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
 #define _CRT_SECURE_NO_DEPRECATE 1
 #define _CRT_SECURE_NO_DEPRECATE 1
 #endif
 #endif
@@ -1659,7 +1661,9 @@
  *
  *
  * This module provides debugging functions.
  * This module provides debugging functions.
  */
  */
+#if CONFIG_MBEDTLS_DEBUG
 #define MBEDTLS_DEBUG_C
 #define MBEDTLS_DEBUG_C
+#endif
 
 
 /**
 /**
  * \def MBEDTLS_DES_C
  * \def MBEDTLS_DES_C
@@ -2481,7 +2485,7 @@
 
 
 /* SSL options */
 /* SSL options */
 
 
-#define MBEDTLS_SSL_MAX_CONTENT_LEN             5120 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
+#define MBEDTLS_SSL_MAX_CONTENT_LEN             CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */
 //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME     86400 /**< Lifetime of session tickets (if enabled) */
 //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME     86400 /**< Lifetime of session tickets (if enabled) */
 //#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
 //#define MBEDTLS_PSK_MAX_LEN               32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
 //#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
 //#define MBEDTLS_SSL_COOKIE_TIMEOUT        60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */

+ 23 - 0
components/nghttp/COPYING

@@ -0,0 +1,23 @@
+The MIT License
+
+Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
+Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 1 - 0
components/nghttp/LICENSE

@@ -0,0 +1 @@
+See COPYING

+ 17 - 0
components/nghttp/Makefile

@@ -0,0 +1,17 @@
+#
+# 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
+
+COMPONENT_SRCDIRS := library port
+
+#EXTRA_CFLAGS += -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"'
+
+EXTRA_CFLAGS := -Wno-error=address -Waddress -DHAVE_CONFIG_H
+
+include $(IDF_PATH)/make/component.mk

+ 4 - 0
components/nghttp/Makefile.projbuild

@@ -0,0 +1,4 @@
+# Anyone compiling mbedTLS code needs the name of the
+# alternative config file
+
+CFLAGS += -DHAVE_CONFIG_H

+ 1 - 0
components/nghttp/README

@@ -0,0 +1 @@
+See README.rst

+ 9 - 0
components/nghttp/component.mk

@@ -0,0 +1,9 @@
+#
+# Component Makefile
+#
+
+COMPONENT_ADD_INCLUDEDIRS := port/include include
+
+COMPONENT_SRCDIRS := library port
+
+include $(IDF_PATH)/make/component_common.mk

+ 5030 - 0
components/nghttp/include/nghttp2/nghttp2.h

@@ -0,0 +1,5030 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013, 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_H
+#define NGHTTP2_H
+
+/* Define WIN32 when build target is Win32 API (borrowed from
+   libcurl) */
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#define WIN32
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdlib.h>
+#if defined(_MSC_VER) && (_MSC_VER < 1800)
+/* MSVC < 2013 does not have inttypes.h because it is not C99
+   compliant.  See compiler macros and version number in
+   https://sourceforge.net/p/predef/wiki/Compilers/ */
+#include <stdint.h>
+#else /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+#include <inttypes.h>
+#endif /* !defined(_MSC_VER) || (_MSC_VER >= 1800) */
+#include <sys/types.h>
+
+#include <nghttp2/nghttp2ver.h>
+
+#ifdef NGHTTP2_STATICLIB
+#define NGHTTP2_EXTERN
+#elif defined(WIN32)
+#ifdef BUILDING_NGHTTP2
+#define NGHTTP2_EXTERN __declspec(dllexport)
+#else /* !BUILDING_NGHTTP2 */
+#define NGHTTP2_EXTERN __declspec(dllimport)
+#endif /* !BUILDING_NGHTTP2 */
+#else  /* !defined(WIN32) */
+#ifdef BUILDING_NGHTTP2
+#define NGHTTP2_EXTERN __attribute__((visibility("default")))
+#else /* !BUILDING_NGHTTP2 */
+#define NGHTTP2_EXTERN
+#endif /* !BUILDING_NGHTTP2 */
+#endif /* !defined(WIN32) */
+
+/**
+ * @macro
+ *
+ * The protocol version identification string of this library
+ * supports.  This identifier is used if HTTP/2 is used over TLS.
+ */
+#define NGHTTP2_PROTO_VERSION_ID "h2"
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_PROTO_VERSION_ID`.
+ */
+#define NGHTTP2_PROTO_VERSION_ID_LEN 2
+
+/**
+ * @macro
+ *
+ * The serialized form of ALPN protocol identifier this library
+ * supports.  Notice that first byte is the length of following
+ * protocol identifier.  This is the same wire format of `TLS ALPN
+ * extension <https://tools.ietf.org/html/rfc7301>`_.  This is useful
+ * to process incoming ALPN tokens in wire format.
+ */
+#define NGHTTP2_PROTO_ALPN "\x2h2"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_PROTO_ALPN`.
+ */
+#define NGHTTP2_PROTO_ALPN_LEN (sizeof(NGHTTP2_PROTO_ALPN) - 1)
+
+/**
+ * @macro
+ *
+ * The protocol version identification string of this library
+ * supports.  This identifier is used if HTTP/2 is used over cleartext
+ * TCP.
+ */
+#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "h2c"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_CLEARTEXT_PROTO_VERSION_ID`.
+ */
+#define NGHTTP2_CLEARTEXT_PROTO_VERSION_ID_LEN 3
+
+struct nghttp2_session;
+/**
+ * @struct
+ *
+ * The primary structure to hold the resources needed for a HTTP/2
+ * session.  The details of this structure are intentionally hidden
+ * from the public API.
+ */
+typedef struct nghttp2_session nghttp2_session;
+
+/**
+ * @macro
+ *
+ * The age of :type:`nghttp2_info`
+ */
+#define NGHTTP2_VERSION_AGE 1
+
+/**
+ * @struct
+ *
+ * This struct is what `nghttp2_version()` returns.  It holds
+ * information about the particular nghttp2 version.
+ */
+typedef struct {
+  /**
+   * Age of this struct.  This instance of nghttp2 sets it to
+   * :macro:`NGHTTP2_VERSION_AGE` but a future version may bump it and
+   * add more struct fields at the bottom
+   */
+  int age;
+  /**
+   * the :macro:`NGHTTP2_VERSION_NUM` number (since age ==1)
+   */
+  int version_num;
+  /**
+   * points to the :macro:`NGHTTP2_VERSION` string (since age ==1)
+   */
+  const char *version_str;
+  /**
+   * points to the :macro:`NGHTTP2_PROTO_VERSION_ID` string this
+   * instance implements (since age ==1)
+   */
+  const char *proto_str;
+  /* -------- the above fields all exist when age == 1 */
+} nghttp2_info;
+
+/**
+ * @macro
+ *
+ * The default weight of stream dependency.
+ */
+#define NGHTTP2_DEFAULT_WEIGHT 16
+
+/**
+ * @macro
+ *
+ * The maximum weight of stream dependency.
+ */
+#define NGHTTP2_MAX_WEIGHT 256
+
+/**
+ * @macro
+ *
+ * The minimum weight of stream dependency.
+ */
+#define NGHTTP2_MIN_WEIGHT 1
+
+/**
+ * @macro
+ *
+ * The maximum window size
+ */
+#define NGHTTP2_MAX_WINDOW_SIZE ((int32_t)((1U << 31) - 1))
+
+/**
+ * @macro
+ *
+ * The initial window size for stream level flow control.
+ */
+#define NGHTTP2_INITIAL_WINDOW_SIZE ((1 << 16) - 1)
+/**
+ * @macro
+ *
+ * The initial window size for connection level flow control.
+ */
+#define NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE ((1 << 16) - 1)
+
+/**
+ * @macro
+ *
+ * The default header table size.
+ */
+#define NGHTTP2_DEFAULT_HEADER_TABLE_SIZE (1 << 12)
+
+/**
+ * @macro
+ *
+ * The client magic string, which is the first 24 bytes byte string of
+ * client connection preface.
+ */
+#define NGHTTP2_CLIENT_MAGIC "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+
+/**
+ * @macro
+ *
+ * The length of :macro:`NGHTTP2_CLIENT_MAGIC`.
+ */
+#define NGHTTP2_CLIENT_MAGIC_LEN 24
+
+/**
+ * @enum
+ *
+ * Error codes used in this library.  The code range is [-999, -500],
+ * inclusive. The following values are defined:
+ */
+typedef enum {
+  /**
+   * Invalid argument passed.
+   */
+  NGHTTP2_ERR_INVALID_ARGUMENT = -501,
+  /**
+   * Out of buffer space.
+   */
+  NGHTTP2_ERR_BUFFER_ERROR = -502,
+  /**
+   * The specified protocol version is not supported.
+   */
+  NGHTTP2_ERR_UNSUPPORTED_VERSION = -503,
+  /**
+   * Used as a return value from :type:`nghttp2_send_callback`,
+   * :type:`nghttp2_recv_callback` and
+   * :type:`nghttp2_send_data_callback` to indicate that the operation
+   * would block.
+   */
+  NGHTTP2_ERR_WOULDBLOCK = -504,
+  /**
+   * General protocol error
+   */
+  NGHTTP2_ERR_PROTO = -505,
+  /**
+   * The frame is invalid.
+   */
+  NGHTTP2_ERR_INVALID_FRAME = -506,
+  /**
+   * The peer performed a shutdown on the connection.
+   */
+  NGHTTP2_ERR_EOF = -507,
+  /**
+   * Used as a return value from
+   * :func:`nghttp2_data_source_read_callback` to indicate that data
+   * transfer is postponed.  See
+   * :func:`nghttp2_data_source_read_callback` for details.
+   */
+  NGHTTP2_ERR_DEFERRED = -508,
+  /**
+   * Stream ID has reached the maximum value.  Therefore no stream ID
+   * is available.
+   */
+  NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE = -509,
+  /**
+   * The stream is already closed; or the stream ID is invalid.
+   */
+  NGHTTP2_ERR_STREAM_CLOSED = -510,
+  /**
+   * RST_STREAM has been added to the outbound queue.  The stream is
+   * in closing state.
+   */
+  NGHTTP2_ERR_STREAM_CLOSING = -511,
+  /**
+   * The transmission is not allowed for this stream (e.g., a frame
+   * with END_STREAM flag set has already sent).
+   */
+  NGHTTP2_ERR_STREAM_SHUT_WR = -512,
+  /**
+   * The stream ID is invalid.
+   */
+  NGHTTP2_ERR_INVALID_STREAM_ID = -513,
+  /**
+   * The state of the stream is not valid (e.g., DATA cannot be sent
+   * to the stream if response HEADERS has not been sent).
+   */
+  NGHTTP2_ERR_INVALID_STREAM_STATE = -514,
+  /**
+   * Another DATA frame has already been deferred.
+   */
+  NGHTTP2_ERR_DEFERRED_DATA_EXIST = -515,
+  /**
+   * Starting new stream is not allowed (e.g., GOAWAY has been sent
+   * and/or received).
+   */
+  NGHTTP2_ERR_START_STREAM_NOT_ALLOWED = -516,
+  /**
+   * GOAWAY has already been sent.
+   */
+  NGHTTP2_ERR_GOAWAY_ALREADY_SENT = -517,
+  /**
+   * The received frame contains the invalid header block (e.g., There
+   * are duplicate header names; or the header names are not encoded
+   * in US-ASCII character set and not lower cased; or the header name
+   * is zero-length string; or the header value contains multiple
+   * in-sequence NUL bytes).
+   */
+  NGHTTP2_ERR_INVALID_HEADER_BLOCK = -518,
+  /**
+   * Indicates that the context is not suitable to perform the
+   * requested operation.
+   */
+  NGHTTP2_ERR_INVALID_STATE = -519,
+  /**
+   * The user callback function failed due to the temporal error.
+   */
+  NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE = -521,
+  /**
+   * The length of the frame is invalid, either too large or too small.
+   */
+  NGHTTP2_ERR_FRAME_SIZE_ERROR = -522,
+  /**
+   * Header block inflate/deflate error.
+   */
+  NGHTTP2_ERR_HEADER_COMP = -523,
+  /**
+   * Flow control error
+   */
+  NGHTTP2_ERR_FLOW_CONTROL = -524,
+  /**
+   * Insufficient buffer size given to function.
+   */
+  NGHTTP2_ERR_INSUFF_BUFSIZE = -525,
+  /**
+   * Callback was paused by the application
+   */
+  NGHTTP2_ERR_PAUSE = -526,
+  /**
+   * There are too many in-flight SETTING frame and no more
+   * transmission of SETTINGS is allowed.
+   */
+  NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS = -527,
+  /**
+   * The server push is disabled.
+   */
+  NGHTTP2_ERR_PUSH_DISABLED = -528,
+  /**
+   * DATA or HEADERS frame for a given stream has been already
+   * submitted and has not been fully processed yet.  Application
+   * should wait for the transmission of the previously submitted
+   * frame before submitting another.
+   */
+  NGHTTP2_ERR_DATA_EXIST = -529,
+  /**
+   * The current session is closing due to a connection error or
+   * `nghttp2_session_terminate_session()` is called.
+   */
+  NGHTTP2_ERR_SESSION_CLOSING = -530,
+  /**
+   * Invalid HTTP header field was received and stream is going to be
+   * closed.
+   */
+  NGHTTP2_ERR_HTTP_HEADER = -531,
+  /**
+   * Violation in HTTP messaging rule.
+   */
+  NGHTTP2_ERR_HTTP_MESSAGING = -532,
+  /**
+   * Stream was refused.
+   */
+  NGHTTP2_ERR_REFUSED_STREAM = -533,
+  /**
+   * Unexpected internal error, but recovered.
+   */
+  NGHTTP2_ERR_INTERNAL = -534,
+  /**
+   * Indicates that a processing was canceled.
+   */
+  NGHTTP2_ERR_CANCEL = -535,
+  /**
+   * The errors < :enum:`NGHTTP2_ERR_FATAL` mean that the library is
+   * under unexpected condition and processing was terminated (e.g.,
+   * out of memory).  If application receives this error code, it must
+   * stop using that :type:`nghttp2_session` object and only allowed
+   * operation for that object is deallocate it using
+   * `nghttp2_session_del()`.
+   */
+  NGHTTP2_ERR_FATAL = -900,
+  /**
+   * Out of memory.  This is a fatal error.
+   */
+  NGHTTP2_ERR_NOMEM = -901,
+  /**
+   * The user callback function failed.  This is a fatal error.
+   */
+  NGHTTP2_ERR_CALLBACK_FAILURE = -902,
+  /**
+   * Invalid client magic (see :macro:`NGHTTP2_CLIENT_MAGIC`) was
+   * received and further processing is not possible.
+   */
+  NGHTTP2_ERR_BAD_CLIENT_MAGIC = -903,
+  /**
+   * Possible flooding by peer was detected in this HTTP/2 session.
+   * Flooding is measured by how many PING and SETTINGS frames with
+   * ACK flag set are queued for transmission.  These frames are
+   * response for the peer initiated frames, and peer can cause memory
+   * exhaustion on server side to send these frames forever and does
+   * not read network.
+   */
+  NGHTTP2_ERR_FLOODED = -904
+} nghttp2_error;
+
+/**
+ * @struct
+ *
+ * The object representing single contiguous buffer.
+ */
+typedef struct {
+  /**
+   * The pointer to the buffer.
+   */
+  uint8_t *base;
+  /**
+   * The length of the buffer.
+   */
+  size_t len;
+} nghttp2_vec;
+
+struct nghttp2_rcbuf;
+
+/**
+ * @struct
+ *
+ * The object representing reference counted buffer.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_rcbuf nghttp2_rcbuf;
+
+/**
+ * @function
+ *
+ * Increments the reference count of |rcbuf| by 1.
+ */
+NGHTTP2_EXTERN void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @function
+ *
+ * Decrements the reference count of |rcbuf| by 1.  If the reference
+ * count becomes zero, the object pointed by |rcbuf| will be freed.
+ * In this case, application must not use |rcbuf| again.
+ */
+NGHTTP2_EXTERN void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @function
+ *
+ * Returns the underlying buffer managed by |rcbuf|.
+ */
+NGHTTP2_EXTERN nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf);
+
+/**
+ * @enum
+ *
+ * The flags for header field name/value pair.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_NV_FLAG_NONE = 0,
+  /**
+   * Indicates that this name/value pair must not be indexed ("Literal
+   * Header Field never Indexed" representation must be used in HPACK
+   * encoding).  Other implementation calls this bit as "sensitive".
+   */
+  NGHTTP2_NV_FLAG_NO_INDEX = 0x01,
+  /**
+   * This flag is set solely by application.  If this flag is set, the
+   * library does not make a copy of header field name.  This could
+   * improve performance.
+   */
+  NGHTTP2_NV_FLAG_NO_COPY_NAME = 0x02,
+  /**
+   * This flag is set solely by application.  If this flag is set, the
+   * library does not make a copy of header field value.  This could
+   * improve performance.
+   */
+  NGHTTP2_NV_FLAG_NO_COPY_VALUE = 0x04
+} nghttp2_nv_flag;
+
+/**
+ * @struct
+ *
+ * The name/value pair, which mainly used to represent header fields.
+ */
+typedef struct {
+  /**
+   * The |name| byte string.  If this struct is presented from library
+   * (e.g., :type:`nghttp2_on_frame_recv_callback`), |name| is
+   * guaranteed to be NULL-terminated.  For some callbacks
+   * (:type:`nghttp2_before_frame_send_callback`,
+   * :type:`nghttp2_on_frame_send_callback`, and
+   * :type:`nghttp2_on_frame_not_send_callback`), it may not be
+   * NULL-terminated if header field is passed from application with
+   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`).  When application
+   * is constructing this struct, |name| is not required to be
+   * NULL-terminated.
+   */
+  uint8_t *name;
+  /**
+   * The |value| byte string.  If this struct is presented from
+   * library (e.g., :type:`nghttp2_on_frame_recv_callback`), |value|
+   * is guaranteed to be NULL-terminated.  For some callbacks
+   * (:type:`nghttp2_before_frame_send_callback`,
+   * :type:`nghttp2_on_frame_send_callback`, and
+   * :type:`nghttp2_on_frame_not_send_callback`), it may not be
+   * NULL-terminated if header field is passed from application with
+   * the flag :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE`).  When
+   * application is constructing this struct, |value| is not required
+   * to be NULL-terminated.
+   */
+  uint8_t *value;
+  /**
+   * The length of the |name|, excluding terminating NULL.
+   */
+  size_t namelen;
+  /**
+   * The length of the |value|, excluding terminating NULL.
+   */
+  size_t valuelen;
+  /**
+   * Bitwise OR of one or more of :type:`nghttp2_nv_flag`.
+   */
+  uint8_t flags;
+} nghttp2_nv;
+
+/**
+ * @enum
+ *
+ * The frame types in HTTP/2 specification.
+ */
+typedef enum {
+  /**
+   * The DATA frame.
+   */
+  NGHTTP2_DATA = 0,
+  /**
+   * The HEADERS frame.
+   */
+  NGHTTP2_HEADERS = 0x01,
+  /**
+   * The PRIORITY frame.
+   */
+  NGHTTP2_PRIORITY = 0x02,
+  /**
+   * The RST_STREAM frame.
+   */
+  NGHTTP2_RST_STREAM = 0x03,
+  /**
+   * The SETTINGS frame.
+   */
+  NGHTTP2_SETTINGS = 0x04,
+  /**
+   * The PUSH_PROMISE frame.
+   */
+  NGHTTP2_PUSH_PROMISE = 0x05,
+  /**
+   * The PING frame.
+   */
+  NGHTTP2_PING = 0x06,
+  /**
+   * The GOAWAY frame.
+   */
+  NGHTTP2_GOAWAY = 0x07,
+  /**
+   * The WINDOW_UPDATE frame.
+   */
+  NGHTTP2_WINDOW_UPDATE = 0x08,
+  /**
+   * The CONTINUATION frame.  This frame type won't be passed to any
+   * callbacks because the library processes this frame type and its
+   * preceding HEADERS/PUSH_PROMISE as a single frame.
+   */
+  NGHTTP2_CONTINUATION = 0x09,
+  /**
+   * The ALTSVC frame, which is defined in `RFC 7383
+   * <https://tools.ietf.org/html/rfc7838#section-4>`_.
+   */
+  NGHTTP2_ALTSVC = 0x0a
+} nghttp2_frame_type;
+
+/**
+ * @enum
+ *
+ * The flags for HTTP/2 frames.  This enum defines all flags for all
+ * frames.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_FLAG_NONE = 0,
+  /**
+   * The END_STREAM flag.
+   */
+  NGHTTP2_FLAG_END_STREAM = 0x01,
+  /**
+   * The END_HEADERS flag.
+   */
+  NGHTTP2_FLAG_END_HEADERS = 0x04,
+  /**
+   * The ACK flag.
+   */
+  NGHTTP2_FLAG_ACK = 0x01,
+  /**
+   * The PADDED flag.
+   */
+  NGHTTP2_FLAG_PADDED = 0x08,
+  /**
+   * The PRIORITY flag.
+   */
+  NGHTTP2_FLAG_PRIORITY = 0x20
+} nghttp2_flag;
+
+/**
+ * @enum
+ * The SETTINGS ID.
+ */
+typedef enum {
+  /**
+   * SETTINGS_HEADER_TABLE_SIZE
+   */
+  NGHTTP2_SETTINGS_HEADER_TABLE_SIZE = 0x01,
+  /**
+   * SETTINGS_ENABLE_PUSH
+   */
+  NGHTTP2_SETTINGS_ENABLE_PUSH = 0x02,
+  /**
+   * SETTINGS_MAX_CONCURRENT_STREAMS
+   */
+  NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS = 0x03,
+  /**
+   * SETTINGS_INITIAL_WINDOW_SIZE
+   */
+  NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE = 0x04,
+  /**
+   * SETTINGS_MAX_FRAME_SIZE
+   */
+  NGHTTP2_SETTINGS_MAX_FRAME_SIZE = 0x05,
+  /**
+   * SETTINGS_MAX_HEADER_LIST_SIZE
+   */
+  NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE = 0x06
+} nghttp2_settings_id;
+/* Note: If we add SETTINGS, update the capacity of
+   NGHTTP2_INBOUND_NUM_IV as well */
+
+/**
+ * @macro
+ *
+ * .. warning::
+ *
+ *   Deprecated.  The initial max concurrent streams is 0xffffffffu.
+ *
+ * Default maximum number of incoming concurrent streams.  Use
+ * `nghttp2_submit_settings()` with
+ * :enum:`NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS` to change the
+ * maximum number of incoming concurrent streams.
+ *
+ * .. note::
+ *
+ *   The maximum number of outgoing concurrent streams is 100 by
+ *   default.
+ */
+#define NGHTTP2_INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+
+/**
+ * @enum
+ * The status codes for the RST_STREAM and GOAWAY frames.
+ */
+typedef enum {
+  /**
+   * No errors.
+   */
+  NGHTTP2_NO_ERROR = 0x00,
+  /**
+   * PROTOCOL_ERROR
+   */
+  NGHTTP2_PROTOCOL_ERROR = 0x01,
+  /**
+   * INTERNAL_ERROR
+   */
+  NGHTTP2_INTERNAL_ERROR = 0x02,
+  /**
+   * FLOW_CONTROL_ERROR
+   */
+  NGHTTP2_FLOW_CONTROL_ERROR = 0x03,
+  /**
+   * SETTINGS_TIMEOUT
+   */
+  NGHTTP2_SETTINGS_TIMEOUT = 0x04,
+  /**
+   * STREAM_CLOSED
+   */
+  NGHTTP2_STREAM_CLOSED = 0x05,
+  /**
+   * FRAME_SIZE_ERROR
+   */
+  NGHTTP2_FRAME_SIZE_ERROR = 0x06,
+  /**
+   * REFUSED_STREAM
+   */
+  NGHTTP2_REFUSED_STREAM = 0x07,
+  /**
+   * CANCEL
+   */
+  NGHTTP2_CANCEL = 0x08,
+  /**
+   * COMPRESSION_ERROR
+   */
+  NGHTTP2_COMPRESSION_ERROR = 0x09,
+  /**
+   * CONNECT_ERROR
+   */
+  NGHTTP2_CONNECT_ERROR = 0x0a,
+  /**
+   * ENHANCE_YOUR_CALM
+   */
+  NGHTTP2_ENHANCE_YOUR_CALM = 0x0b,
+  /**
+   * INADEQUATE_SECURITY
+   */
+  NGHTTP2_INADEQUATE_SECURITY = 0x0c,
+  /**
+   * HTTP_1_1_REQUIRED
+   */
+  NGHTTP2_HTTP_1_1_REQUIRED = 0x0d
+} nghttp2_error_code;
+
+/**
+ * @struct
+ * The frame header.
+ */
+typedef struct {
+  /**
+   * The length field of this frame, excluding frame header.
+   */
+  size_t length;
+  /**
+   * The stream identifier (aka, stream ID)
+   */
+  int32_t stream_id;
+  /**
+   * The type of this frame.  See `nghttp2_frame_type`.
+   */
+  uint8_t type;
+  /**
+   * The flags.
+   */
+  uint8_t flags;
+  /**
+   * Reserved bit in frame header.  Currently, this is always set to 0
+   * and application should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_frame_hd;
+
+/**
+ * @union
+ *
+ * This union represents the some kind of data source passed to
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+typedef union {
+  /**
+   * The integer field, suitable for a file descriptor.
+   */
+  int fd;
+  /**
+   * The pointer to an arbitrary object.
+   */
+  void *ptr;
+} nghttp2_data_source;
+
+/**
+ * @enum
+ *
+ * The flags used to set in |data_flags| output parameter in
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_DATA_FLAG_NONE = 0,
+  /**
+   * Indicates EOF was sensed.
+   */
+  NGHTTP2_DATA_FLAG_EOF = 0x01,
+  /**
+   * Indicates that END_STREAM flag must not be set even if
+   * NGHTTP2_DATA_FLAG_EOF is set.  Usually this flag is used to send
+   * trailer fields with `nghttp2_submit_request()` or
+   * `nghttp2_submit_response()`.
+   */
+  NGHTTP2_DATA_FLAG_NO_END_STREAM = 0x02,
+  /**
+   * Indicates that application will send complete DATA frame in
+   * :type:`nghttp2_send_data_callback`.
+   */
+  NGHTTP2_DATA_FLAG_NO_COPY = 0x04
+} nghttp2_data_flag;
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the library wants to read data from
+ * the |source|.  The read data is sent in the stream |stream_id|.
+ * The implementation of this function must read at most |length|
+ * bytes of data from |source| (or possibly other places) and store
+ * them in |buf| and return number of data stored in |buf|.  If EOF is
+ * reached, set :enum:`NGHTTP2_DATA_FLAG_EOF` flag in |*data_flags|.
+ *
+ * Sometime it is desirable to avoid copying data into |buf| and let
+ * application to send data directly.  To achieve this, set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` to |*data_flags| (and possibly
+ * other flags, just like when we do copy), and return the number of
+ * bytes to send without copying data into |buf|.  The library, seeing
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY`, will invoke
+ * :type:`nghttp2_send_data_callback`.  The application must send
+ * complete DATA frame in that callback.
+ *
+ * If this callback is set by `nghttp2_submit_request()`,
+ * `nghttp2_submit_response()` or `nghttp2_submit_headers()` and
+ * `nghttp2_submit_data()` with flag parameter
+ * :enum:`NGHTTP2_FLAG_END_STREAM` set, and
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` flag is set to |*data_flags|, DATA
+ * frame will have END_STREAM flag set.  Usually, this is expected
+ * behaviour and all are fine.  One exception is send trailer fields.
+ * You cannot send trailer fields after sending frame with END_STREAM
+ * set.  To avoid this problem, one can set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM` along with
+ * :enum:`NGHTTP2_DATA_FLAG_EOF` to signal the library not to set
+ * END_STREAM in DATA frame.  Then application can use
+ * `nghttp2_submit_trailer()` to send trailer fields.
+ * `nghttp2_submit_trailer()` can be called inside this callback.
+ *
+ * If the application wants to postpone DATA frames (e.g.,
+ * asynchronous I/O, or reading data blocks for long time), it is
+ * achieved by returning :enum:`NGHTTP2_ERR_DEFERRED` without reading
+ * any data in this invocation.  The library removes DATA frame from
+ * the outgoing queue temporarily.  To move back deferred DATA frame
+ * to outgoing queue, call `nghttp2_session_resume_data()`.  In case
+ * of error, there are 2 choices. Returning
+ * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close the stream
+ * by issuing RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
+ * failure.
+ */
+typedef ssize_t (*nghttp2_data_source_read_callback)(
+    nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
+    uint32_t *data_flags, nghttp2_data_source *source, void *user_data);
+
+/**
+ * @struct
+ *
+ * This struct represents the data source and the way to read a chunk
+ * of data from it.
+ */
+typedef struct {
+  /**
+   * The data source.
+   */
+  nghttp2_data_source source;
+  /**
+   * The callback function to read a chunk of data from the |source|.
+   */
+  nghttp2_data_source_read_callback read_callback;
+} nghttp2_data_provider;
+
+/**
+ * @struct
+ *
+ * The DATA frame.  The received data is delivered via
+ * :type:`nghttp2_on_data_chunk_recv_callback`.
+ */
+typedef struct {
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+} nghttp2_data;
+
+/**
+ * @enum
+ *
+ * The category of HEADERS, which indicates the role of the frame.  In
+ * HTTP/2 spec, request, response, push response and other arbitrary
+ * headers (e.g., trailer fields) are all called just HEADERS.  To
+ * give the application the role of incoming HEADERS frame, we define
+ * several categories.
+ */
+typedef enum {
+  /**
+   * The HEADERS frame is opening new stream, which is analogous to
+   * SYN_STREAM in SPDY.
+   */
+  NGHTTP2_HCAT_REQUEST = 0,
+  /**
+   * The HEADERS frame is the first response headers, which is
+   * analogous to SYN_REPLY in SPDY.
+   */
+  NGHTTP2_HCAT_RESPONSE = 1,
+  /**
+   * The HEADERS frame is the first headers sent against reserved
+   * stream.
+   */
+  NGHTTP2_HCAT_PUSH_RESPONSE = 2,
+  /**
+   * The HEADERS frame which does not apply for the above categories,
+   * which is analogous to HEADERS in SPDY.  If non-final response
+   * (e.g., status 1xx) is used, final response HEADERS frame will be
+   * categorized here.
+   */
+  NGHTTP2_HCAT_HEADERS = 3
+} nghttp2_headers_category;
+
+/**
+ * @struct
+ *
+ * The structure to specify stream dependency.
+ */
+typedef struct {
+  /**
+   * The stream ID of the stream to depend on.  Specifying 0 makes
+   * stream not depend any other stream.
+   */
+  int32_t stream_id;
+  /**
+   * The weight of this dependency.
+   */
+  int32_t weight;
+  /**
+   * nonzero means exclusive dependency
+   */
+  uint8_t exclusive;
+} nghttp2_priority_spec;
+
+/**
+ * @struct
+ *
+ * The HEADERS frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+  /**
+   * The priority specification
+   */
+  nghttp2_priority_spec pri_spec;
+  /**
+   * The name/value pairs.
+   */
+  nghttp2_nv *nva;
+  /**
+   * The number of name/value pairs in |nva|.
+   */
+  size_t nvlen;
+  /**
+   * The category of this HEADERS frame.
+   */
+  nghttp2_headers_category cat;
+} nghttp2_headers;
+
+/**
+ * @struct
+ *
+ * The PRIORITY frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The priority specification.
+   */
+  nghttp2_priority_spec pri_spec;
+} nghttp2_priority;
+
+/**
+ * @struct
+ *
+ * The RST_STREAM frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The error code.  See :type:`nghttp2_error_code`.
+   */
+  uint32_t error_code;
+} nghttp2_rst_stream;
+
+/**
+ * @struct
+ *
+ * The SETTINGS ID/Value pair.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The SETTINGS ID.  See :type:`nghttp2_settings_id`.
+   */
+  int32_t settings_id;
+  /**
+   * The value of this entry.
+   */
+  uint32_t value;
+} nghttp2_settings_entry;
+
+/**
+ * @struct
+ *
+ * The SETTINGS frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The number of SETTINGS ID/Value pairs in |iv|.
+   */
+  size_t niv;
+  /**
+   * The pointer to the array of SETTINGS ID/Value pair.
+   */
+  nghttp2_settings_entry *iv;
+} nghttp2_settings;
+
+/**
+ * @struct
+ *
+ * The PUSH_PROMISE frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The length of the padding in this frame.  This includes PAD_HIGH
+   * and PAD_LOW.
+   */
+  size_t padlen;
+  /**
+   * The name/value pairs.
+   */
+  nghttp2_nv *nva;
+  /**
+   * The number of name/value pairs in |nva|.
+   */
+  size_t nvlen;
+  /**
+   * The promised stream ID
+   */
+  int32_t promised_stream_id;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_push_promise;
+
+/**
+ * @struct
+ *
+ * The PING frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The opaque data
+   */
+  uint8_t opaque_data[8];
+} nghttp2_ping;
+
+/**
+ * @struct
+ *
+ * The GOAWAY frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The last stream stream ID.
+   */
+  int32_t last_stream_id;
+  /**
+   * The error code.  See :type:`nghttp2_error_code`.
+   */
+  uint32_t error_code;
+  /**
+   * The additional debug data
+   */
+  uint8_t *opaque_data;
+  /**
+   * The length of |opaque_data| member.
+   */
+  size_t opaque_data_len;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_goaway;
+
+/**
+ * @struct
+ *
+ * The WINDOW_UPDATE frame.  It has the following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The window size increment.
+   */
+  int32_t window_size_increment;
+  /**
+   * Reserved bit.  Currently this is always set to 0 and application
+   * should not expect something useful in here.
+   */
+  uint8_t reserved;
+} nghttp2_window_update;
+
+/**
+ * @struct
+ *
+ * The extension frame.  It has following members:
+ */
+typedef struct {
+  /**
+   * The frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The pointer to extension payload.  The exact pointer type is
+   * determined by hd.type.
+   *
+   * Currently, no extension is supported.  This is a place holder for
+   * the future extensions.
+   */
+  void *payload;
+} nghttp2_extension;
+
+/**
+ * @union
+ *
+ * This union includes all frames to pass them to various function
+ * calls as nghttp2_frame type.  The CONTINUATION frame is omitted
+ * from here because the library deals with it internally.
+ */
+typedef union {
+  /**
+   * The frame header, which is convenient to inspect frame header.
+   */
+  nghttp2_frame_hd hd;
+  /**
+   * The DATA frame.
+   */
+  nghttp2_data data;
+  /**
+   * The HEADERS frame.
+   */
+  nghttp2_headers headers;
+  /**
+   * The PRIORITY frame.
+   */
+  nghttp2_priority priority;
+  /**
+   * The RST_STREAM frame.
+   */
+  nghttp2_rst_stream rst_stream;
+  /**
+   * The SETTINGS frame.
+   */
+  nghttp2_settings settings;
+  /**
+   * The PUSH_PROMISE frame.
+   */
+  nghttp2_push_promise push_promise;
+  /**
+   * The PING frame.
+   */
+  nghttp2_ping ping;
+  /**
+   * The GOAWAY frame.
+   */
+  nghttp2_goaway goaway;
+  /**
+   * The WINDOW_UPDATE frame.
+   */
+  nghttp2_window_update window_update;
+  /**
+   * The extension frame.
+   */
+  nghttp2_extension ext;
+} nghttp2_frame;
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when |session| wants to send data to the
+ * remote peer.  The implementation of this function must send at most
+ * |length| bytes of data stored in |data|.  The |flags| is currently
+ * not used and always 0. It must return the number of bytes sent if
+ * it succeeds.  If it cannot send any single byte without blocking,
+ * it must return :enum:`NGHTTP2_ERR_WOULDBLOCK`.  For other errors,
+ * it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * This callback is required if the application uses
+ * `nghttp2_session_send()` to send data to the remote endpoint.  If
+ * the application uses solely `nghttp2_session_mem_send()` instead,
+ * this callback function is unnecessary.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_send_callback()`.
+ *
+ * .. note::
+ *
+ *   The |length| may be very small.  If that is the case, and
+ *   application disables Nagle algorithm (``TCP_NODELAY``), then just
+ *   writing |data| to the network stack leads to very small packet,
+ *   and it is very inefficient.  An application should be responsible
+ *   to buffer up small chunks of data as necessary to avoid this
+ *   situation.
+ */
+typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
+                                         const uint8_t *data, size_t length,
+                                         int flags, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is
+ * used in :type:`nghttp2_data_source_read_callback` to send complete
+ * DATA frame.
+ *
+ * The |frame| is a DATA frame to send.  The |framehd| is the
+ * serialized frame header (9 bytes). The |length| is the length of
+ * application data to send (this does not include padding).  The
+ * |source| is the same pointer passed to
+ * :type:`nghttp2_data_source_read_callback`.
+ *
+ * The application first must send frame header |framehd| of length 9
+ * bytes.  If ``frame->data.padlen > 0``, send 1 byte of value
+ * ``frame->data.padlen - 1``.  Then send exactly |length| bytes of
+ * application data.  Finally, if ``frame->data.padlen > 1``, send
+ * ``frame->data.padlen - 1`` bytes of zero as padding.
+ *
+ * The application has to send complete DATA frame in this callback.
+ * If all data were written successfully, return 0.
+ *
+ * If it cannot send any data at all, just return
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`; the library will call this callback
+ * with the same parameters later (It is recommended to send complete
+ * DATA frame at once in this function to deal with error; if partial
+ * frame data has already sent, it is impossible to send another data
+ * in that state, and all we can do is tear down connection).  When
+ * data is fully processed, but application wants to make
+ * `nghttp2_session_mem_send()` or `nghttp2_session_send()` return
+ * immediately without processing next frames, return
+ * :enum:`NGHTTP2_ERR_PAUSE`.  If application decided to reset this
+ * stream, return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`, then
+ * the library will send RST_STREAM with INTERNAL_ERROR as error code.
+ * The application can also return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, which will result in
+ * connection closure.  Returning any other value is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.
+ */
+typedef int (*nghttp2_send_data_callback)(nghttp2_session *session,
+                                          nghttp2_frame *frame,
+                                          const uint8_t *framehd, size_t length,
+                                          nghttp2_data_source *source,
+                                          void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when |session| wants to receive data from
+ * the remote peer.  The implementation of this function must read at
+ * most |length| bytes of data and store it in |buf|.  The |flags| is
+ * currently not used and always 0.  It must return the number of
+ * bytes written in |buf| if it succeeds.  If it cannot read any
+ * single byte without blocking, it must return
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  If it gets EOF before it reads any
+ * single byte, it must return :enum:`NGHTTP2_ERR_EOF`.  For other
+ * errors, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ * Returning 0 is treated as :enum:`NGHTTP2_ERR_WOULDBLOCK`.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * This callback is required if the application uses
+ * `nghttp2_session_recv()` to receive data from the remote endpoint.
+ * If the application uses solely `nghttp2_session_mem_recv()`
+ * instead, this callback function is unnecessary.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_recv_callback()`.
+ */
+typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
+                                         size_t length, int flags,
+                                         void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
+ * member of their data structure are always ``NULL`` and 0
+ * respectively.  The header name/value pairs are emitted via
+ * :type:`nghttp2_on_header_callback`.
+ *
+ * For HEADERS, PUSH_PROMISE and DATA frames, this callback may be
+ * called after stream is closed (see
+ * :type:`nghttp2_on_stream_close_callback`).  The application should
+ * check that stream is still alive using its own stream management or
+ * :func:`nghttp2_session_get_stream_user_data()`.
+ *
+ * Only HEADERS and DATA frame can signal the end of incoming data.
+ * If ``frame->hd.flags & NGHTTP2_FLAG_END_STREAM`` is nonzero, the
+ * |frame| is the last frame from the remote peer in this stream.
+ *
+ * This callback won't be called for CONTINUATION frames.
+ * HEADERS/PUSH_PROMISE + CONTINUATIONs are treated as single frame.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero value is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
+ */
+typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
+                                              const nghttp2_frame *frame,
+                                              void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received.  The error is indicated by the |lib_error_code|, which is
+ * one of the values defined in :type:`nghttp2_error`.  When this
+ * callback function is invoked, the library automatically submits
+ * either RST_STREAM or GOAWAY frame.  The |user_data| pointer is the
+ * third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * If frame is HEADERS or PUSH_PROMISE, the ``nva`` and ``nvlen``
+ * member of their data structure are always ``NULL`` and 0
+ * respectively.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
+ */
+typedef int (*nghttp2_on_invalid_frame_recv_callback)(
+    nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
+    void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a chunk of data in DATA frame is
+ * received.  The |stream_id| is the stream ID this DATA frame belongs
+ * to.  The |flags| is the flags of DATA frame which this data chunk
+ * is contained.  ``(flags & NGHTTP2_FLAG_END_STREAM) != 0`` does not
+ * necessarily mean this chunk of data is the last one in the stream.
+ * You should use :type:`nghttp2_on_frame_recv_callback` to know all
+ * data frames are received.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * If the application uses `nghttp2_session_mem_recv()`, it can return
+ * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
+ * return without processing further input bytes.  The memory by
+ * pointed by the |data| is retained until
+ * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
+ * The application must retain the input bytes which was used to
+ * produce the |data| parameter, because it may refer to the memory
+ * region included in the input bytes.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error, and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
+ */
+typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
+                                                   uint8_t flags,
+                                                   int32_t stream_id,
+                                                   const uint8_t *data,
+                                                   size_t len, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked just before the non-DATA frame |frame| is
+ * sent.  The |user_data| pointer is the third argument passed in to
+ * the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It can also return :enum:`NGHTTP2_ERR_CANCEL` to cancel the
+ * transmission of the given frame.
+ *
+ * If there is a fatal error while executing this callback, the
+ * implementation should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`,
+ * which makes `nghttp2_session_send()` and
+ * `nghttp2_session_mem_send()` functions immediately return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * If the other value is returned, it is treated as if
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned.  But the
+ * implementation should not rely on this since the library may define
+ * new return value to extend its capability.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_before_frame_send_callback()`.
+ */
+typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session,
+                                                  const nghttp2_frame *frame,
+                                                  void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked after the frame |frame| is sent.  The
+ * |user_data| pointer is the third argument passed in to the call to
+ * `nghttp2_session_client_new()` or `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_send_callback()`.
+ */
+typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
+                                              const nghttp2_frame *frame,
+                                              void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked after the non-DATA frame |frame| is not
+ * sent because of the error.  The error is indicated by the
+ * |lib_error_code|, which is one of the values defined in
+ * :type:`nghttp2_error`.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * `nghttp2_session_get_stream_user_data()` can be used to get
+ * associated data.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_frame_not_send_callback()`.
+ */
+typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
+                                                  const nghttp2_frame *frame,
+                                                  int lib_error_code,
+                                                  void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the stream |stream_id| is closed.
+ * The reason of closure is indicated by the |error_code|.  The
+ * |error_code| is usually one of :enum:`nghttp2_error_code`, but that
+ * is not guaranteed.  The stream_user_data, which was specified in
+ * `nghttp2_submit_request()` or `nghttp2_submit_headers()`, is still
+ * available in this function.  The |user_data| pointer is the third
+ * argument passed in to the call to `nghttp2_session_client_new()` or
+ * `nghttp2_session_server_new()`.
+ *
+ * This function is also called for a stream in reserved state.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()`, `nghttp2_session_mem_recv()`,
+ * `nghttp2_session_send()`, and `nghttp2_session_mem_send()`
+ * functions immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_stream_close_callback()`.
+ */
+typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
+                                                int32_t stream_id,
+                                                uint32_t error_code,
+                                                void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the reception of header block in
+ * HEADERS or PUSH_PROMISE is started.  Each header name/value pair
+ * will be emitted by :type:`nghttp2_on_header_callback`.
+ *
+ * The ``frame->hd.flags`` may not have
+ * :enum:`NGHTTP2_FLAG_END_HEADERS` flag set, which indicates that one
+ * or more CONTINUATION frames are involved.  But the application does
+ * not need to care about that because the header name/value pairs are
+ * emitted transparently regardless of CONTINUATION frames.
+ *
+ * The server applications probably create an object to store
+ * information about new stream if ``frame->hd.type ==
+ * NGHTTP2_HEADERS`` and ``frame->headers.cat ==
+ * NGHTTP2_HCAT_REQUEST``.  If |session| is configured as server side,
+ * ``frame->headers.cat`` is either ``NGHTTP2_HCAT_REQUEST``
+ * containing request headers or ``NGHTTP2_HCAT_HEADERS`` containing
+ * trailer fields and never get PUSH_PROMISE in this callback.
+ *
+ * For the client applications, ``frame->hd.type`` is either
+ * ``NGHTTP2_HEADERS`` or ``NGHTTP2_PUSH_PROMISE``.  In case of
+ * ``NGHTTP2_HEADERS``, ``frame->headers.cat ==
+ * NGHTTP2_HCAT_RESPONSE`` means that it is the first response
+ * headers, but it may be non-final response which is indicated by 1xx
+ * status code.  In this case, there may be zero or more HEADERS frame
+ * with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS`` which has
+ * non-final response code and finally client gets exactly one HEADERS
+ * frame with ``frame->headers.cat == NGHTTP2_HCAT_HEADERS``
+ * containing final response headers (non-1xx status code).  The
+ * trailer fields also has ``frame->headers.cat ==
+ * NGHTTP2_HCAT_HEADERS`` which does not contain any status code.
+ *
+ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * :type:`nghttp2_on_header_callback` and
+ * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It can return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` to
+ * reset the stream (promised stream if frame is PUSH_PROMISE).  For
+ * critical errors, it must return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the other value is
+ * returned, it is treated as if :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ * is returned.  If :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * `nghttp2_session_mem_recv()` function will immediately return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
+ */
+typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
+                                                 const nghttp2_frame *frame,
+                                                 void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a header name/value pair is received
+ * for the |frame|.  The |name| of length |namelen| is header name.
+ * The |value| of length |valuelen| is header value.  The |flags| is
+ * bitwise OR of one or more of :type:`nghttp2_nv_flag`.
+ *
+ * If :enum:`NGHTTP2_NV_FLAG_NO_INDEX` is set in |flags|, the receiver
+ * must not index this name/value pair when forwarding it to the next
+ * hop.  More specifically, "Literal Header Field never Indexed"
+ * representation must be used in HPACK encoding.
+ *
+ * When this callback is invoked, ``frame->hd.type`` is either
+ * :enum:`NGHTTP2_HEADERS` or :enum:`NGHTTP2_PUSH_PROMISE`.  After all
+ * header name/value pairs are processed with this callback, and no
+ * error has been detected, :type:`nghttp2_on_frame_recv_callback`
+ * will be invoked.  If there is an error in decompression,
+ * :type:`nghttp2_on_frame_recv_callback` for the |frame| will not be
+ * invoked.
+ *
+ * Both |name| and |value| are guaranteed to be NULL-terminated.  The
+ * |namelen| and |valuelen| do not include terminal NULL.  If
+ * `nghttp2_option_set_no_http_messaging()` is used with nonzero
+ * value, NULL character may be included in |name| or |value| before
+ * terminating NULL.
+ *
+ * Please note that unless `nghttp2_option_set_no_http_messaging()` is
+ * used, nghttp2 library does perform validation against the |name|
+ * and the |value| using `nghttp2_check_header_name()` and
+ * `nghttp2_check_header_value()`.  In addition to this, nghttp2
+ * performs validation based on HTTP Messaging rule, which is briefly
+ * explained in :ref:`http-messaging` section.
+ *
+ * If the application uses `nghttp2_session_mem_recv()`, it can return
+ * :enum:`NGHTTP2_ERR_PAUSE` to make `nghttp2_session_mem_recv()`
+ * return without processing further input bytes.  The memory pointed
+ * by |frame|, |name| and |value| parameters are retained until
+ * `nghttp2_session_mem_recv()` or `nghttp2_session_recv()` is called.
+ * The application must retain the input bytes which was used to
+ * produce these parameters, because it may refer to the memory region
+ * included in the input bytes.
+ *
+ * Returning :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE` will close
+ * the stream (promised stream if frame is PUSH_PROMISE) by issuing
+ * RST_STREAM with :enum:`NGHTTP2_INTERNAL_ERROR`.  In this case,
+ * :type:`nghttp2_on_header_callback` and
+ * :type:`nghttp2_on_frame_recv_callback` will not be invoked.  If a
+ * different error code is desirable, use
+ * `nghttp2_submit_rst_stream()` with a desired error code and then
+ * return :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  Again, use
+ * ``frame->push_promise.promised_stream_id`` as stream_id parameter
+ * in `nghttp2_submit_rst_stream()` if frame is PUSH_PROMISE.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * It may return :enum:`NGHTTP2_ERR_PAUSE` or
+ * :enum:`NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE`.  For other critical
+ * failures, it must return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
+ * the other nonzero value is returned, it is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` is returned,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_header_callback()`.
+ *
+ * .. warning::
+ *
+ *   Application should properly limit the total buffer size to store
+ *   incoming header fields.  Without it, peer may send large number
+ *   of header fields or large header fields to cause out of memory in
+ *   local endpoint.  Due to how HPACK works, peer can do this
+ *   effectively without using much memory on their own.
+ */
+typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
+                                          const nghttp2_frame *frame,
+                                          const uint8_t *name, size_t namelen,
+                                          const uint8_t *value, size_t valuelen,
+                                          uint8_t flags, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a header name/value pair is received
+ * for the |frame|.  The |name| is header name.  The |value| is header
+ * value.  The |flags| is bitwise OR of one or more of
+ * :type:`nghttp2_nv_flag`.
+ *
+ * This callback behaves like :type:`nghttp2_on_header_callback`,
+ * except that |name| and |value| are stored in reference counted
+ * buffer.  If application wishes to keep these references without
+ * copying them, use `nghttp2_rcbuf_incref()` to increment their
+ * reference count.  It is the application's responsibility to call
+ * `nghttp2_rcbuf_decref()` if they called `nghttp2_rcbuf_incref()` so
+ * as not to leak memory.  If the |session| is created by
+ * `nghttp2_session_server_new3()` or `nghttp2_session_client_new3()`,
+ * the function to free memory is the one belongs to the mem
+ * parameter.  As long as this free function alives, |name| and
+ * |value| can live after |session| was destroyed.
+ */
+typedef int (*nghttp2_on_header_callback2)(nghttp2_session *session,
+                                           const nghttp2_frame *frame,
+                                           nghttp2_rcbuf *name,
+                                           nghttp2_rcbuf *value, uint8_t flags,
+                                           void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when the library asks application how
+ * many padding bytes are required for the transmission of the
+ * |frame|.  The application must choose the total length of payload
+ * including padded bytes in range [frame->hd.length, max_payloadlen],
+ * inclusive.  Choosing number not in this range will be treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Returning
+ * ``frame->hd.length`` means no padding is added.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will make
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_select_padding_callback()`.
+ */
+typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session,
+                                                   const nghttp2_frame *frame,
+                                                   size_t max_payloadlen,
+                                                   void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library wants to get max length of
+ * data to send data to the remote peer.  The implementation of this
+ * function should return a value in the following range.  [1,
+ * min(|session_remote_window_size|, |stream_remote_window_size|,
+ * |remote_max_frame_size|)].  If a value greater than this range is
+ * returned than the max allow value will be used.  Returning a value
+ * smaller than this range is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  The |frame_type| is provided
+ * for future extensibility and identifies the type of frame (see
+ * :type:`nghttp2_frame_type`) for which to get the length for.
+ * Currently supported frame types are: :enum:`NGHTTP2_DATA`.
+ *
+ * This callback can be used to control the length in bytes for which
+ * :type:`nghttp2_data_source_read_callback` is allowed to send to the
+ * remote endpoint.  This callback is optional.  Returning
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
+ * failure.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
+ */
+typedef ssize_t (*nghttp2_data_source_read_length_callback)(
+    nghttp2_session *session, uint8_t frame_type, int32_t stream_id,
+    int32_t session_remote_window_size, int32_t stream_remote_window_size,
+    uint32_t remote_max_frame_size, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when a frame header is received.  The
+ * |hd| points to received frame header.
+ *
+ * Unlike :type:`nghttp2_on_frame_recv_callback`, this callback will
+ * also be called when frame header of CONTINUATION frame is received.
+ *
+ * If both :type:`nghttp2_on_begin_frame_callback` and
+ * :type:`nghttp2_on_begin_headers_callback` are set and HEADERS or
+ * PUSH_PROMISE is received, :type:`nghttp2_on_begin_frame_callback`
+ * will be called first.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ * If nonzero value is returned, it is treated as fatal error and
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ *
+ * To set this callback to :type:`nghttp2_session_callbacks`, use
+ * `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
+ */
+typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
+                                               const nghttp2_frame_hd *hd,
+                                               void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when chunk of extension frame payload is
+ * received.  The |hd| points to frame header.  The received
+ * chunk is |data| of length |len|.
+ *
+ * The implementation of this function must return 0 if it succeeds.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef int (*nghttp2_on_extension_chunk_recv_callback)(
+    nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
+    size_t len, void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library asks the application to
+ * unpack extension payload from its wire format.  The extension
+ * payload has been passed to the application using
+ * :type:`nghttp2_on_extension_chunk_recv_callback`.  The frame header
+ * is already unpacked by the library and provided as |hd|.
+ *
+ * To receive extension frames, the application must tell desired
+ * extension frame type to the library using
+ * `nghttp2_option_set_user_recv_extension_type()`.
+ *
+ * The implementation of this function may store the pointer to the
+ * created object as a result of unpacking in |*payload|, and returns
+ * 0.  The pointer stored in |*payload| is opaque to the library, and
+ * the library does not own its pointer.  |*payload| is initialized as
+ * ``NULL``.  The |*payload| is available as ``frame->ext.payload`` in
+ * :type:`nghttp2_on_frame_recv_callback`.  Therefore if application
+ * can free that memory inside :type:`nghttp2_on_frame_recv_callback`
+ * callback.  Of course, application has a liberty not ot use
+ * |*payload|, and do its own mechanism to process extension frames.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_recv()` and `nghttp2_session_mem_recv()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef int (*nghttp2_unpack_extension_callback)(nghttp2_session *session,
+                                                 void **payload,
+                                                 const nghttp2_frame_hd *hd,
+                                                 void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library asks the application to pack
+ * extension payload in its wire format.  The frame header will be
+ * packed by library.  Application must pack payload only.
+ * ``frame->ext.payload`` is the object passed to
+ * `nghttp2_submit_extension()` as payload parameter.  Application
+ * must pack extension payload to the |buf| of its capacity |len|
+ * bytes.  The |len| is at least 16KiB.
+ *
+ * The implementation of this function should return the number of
+ * bytes written into |buf| when it succeeds.
+ *
+ * To abort processing this extension frame, return
+ * :enum:`NGHTTP2_ERR_CANCEL`, and
+ * :type:`nghttp2_on_frame_not_send_callback` will be invoked.
+ *
+ * If fatal error occurred, application should return
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * `nghttp2_session_send()` and `nghttp2_session_mem_send()` functions
+ * immediately return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the
+ * other values are returned, currently they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  If the return value is
+ * strictly larger than |len|, it is treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.
+ */
+typedef ssize_t (*nghttp2_pack_extension_callback)(nghttp2_session *session,
+                                                   uint8_t *buf, size_t len,
+                                                   const nghttp2_frame *frame,
+                                                   void *user_data);
+
+/**
+ * @functypedef
+ *
+ * Callback function invoked when library provides the error message
+ * intended for human consumption.  This callback is solely for
+ * debugging purpose.  The |msg| is typically NULL-terminated string
+ * of length |len|.  |len| does not include the sentinel NULL
+ * character.
+ *
+ * The format of error message may change between nghttp2 library
+ * versions.  The application should not depend on the particular
+ * format.
+ *
+ * Normally, application should return 0 from this callback.  If fatal
+ * error occurred while doing something in this callback, application
+ * should return :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  In this case,
+ * library will return immediately with return value
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`.  Currently, if nonzero value
+ * is returned from this callback, they are treated as
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`, but application should not
+ * rely on this details.
+ */
+typedef int (*nghttp2_error_callback)(nghttp2_session *session, const char *msg,
+                                      size_t len, void *user_data);
+
+struct nghttp2_session_callbacks;
+
+/**
+ * @struct
+ *
+ * Callback functions for :type:`nghttp2_session`.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_session_callbacks nghttp2_session_callbacks;
+
+/**
+ * @function
+ *
+ * Initializes |*callbacks_ptr| with NULL values.
+ *
+ * The initialized object can be used when initializing multiple
+ * :type:`nghttp2_session` objects.
+ *
+ * When the application finished using this object, it can use
+ * `nghttp2_session_callbacks_del()` to free its memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |callbacks|.  If |callbacks| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a session wants to send data to
+ * the remote peer.  This callback is not necessary if the application
+ * uses solely `nghttp2_session_mem_send()` to serialize data to
+ * transmit.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the a session wants to receive
+ * data from the remote peer.  This callback is not necessary if the
+ * application uses solely `nghttp2_session_mem_recv()` to process
+ * received data.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_recv_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when a frame is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_recv_callback on_frame_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked by `nghttp2_session_recv()` and
+ * `nghttp2_session_mem_recv()` when an invalid non-DATA frame is
+ * received.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a chunk of data in DATA frame
+ * is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked before a non-DATA frame is sent.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_before_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_before_frame_send_callback before_frame_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked after a frame is sent.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_send_callback on_frame_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a non-DATA frame is not sent
+ * because of an error.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_frame_not_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_not_send_callback on_frame_not_send_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the stream is closed.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_stream_close_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_stream_close_callback on_stream_close_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the reception of header block
+ * in HEADERS or PUSH_PROMISE is started.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_headers_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_headers_callback on_begin_headers_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a header name/value pair is
+ * received.  If both
+ * `nghttp2_session_callbacks_set_on_header_callback()` and
+ * `nghttp2_session_callbacks_set_on_header_callback2()` are used to
+ * set callbacks, the latter has the precedence.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback on_header_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a header name/value pair is
+ * received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_header_callback2(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback2 on_header_callback2);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks application
+ * how many padding bytes are required for the transmission of the
+ * given frame.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_select_padding_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_select_padding_callback select_padding_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function determine the length allowed in
+ * :type:`nghttp2_data_source_read_callback`.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_data_source_read_length_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_data_source_read_length_callback data_source_read_length_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when a frame header is received.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_on_begin_frame_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_frame_callback on_begin_frame_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when
+ * :enum:`NGHTTP2_DATA_FLAG_NO_COPY` is used in
+ * :type:`nghttp2_data_source_read_callback` to avoid data copy.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_send_data_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_send_data_callback send_data_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks the
+ * application to pack extension frame payload in wire format.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_pack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_pack_extension_callback pack_extension_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when the library asks the
+ * application to unpack extension frame payload from wire format.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_unpack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_unpack_extension_callback unpack_extension_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when chunk of extension frame
+ * payload is received.
+ */
+NGHTTP2_EXTERN void
+nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback);
+
+/**
+ * @function
+ *
+ * Sets callback function invoked when library tells error message to
+ * the application.
+ */
+NGHTTP2_EXTERN void nghttp2_session_callbacks_set_error_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace malloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_malloc)(size_t size, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace free().  The |mem_user_data| is
+ * the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void (*nghttp2_free)(void *ptr, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace calloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_calloc)(size_t nmemb, size_t size, void *mem_user_data);
+
+/**
+ * @functypedef
+ *
+ * Custom memory allocator to replace realloc().  The |mem_user_data|
+ * is the mem_user_data member of :type:`nghttp2_mem` structure.
+ */
+typedef void *(*nghttp2_realloc)(void *ptr, size_t size, void *mem_user_data);
+
+/**
+ * @struct
+ *
+ * Custom memory allocator functions and user defined pointer.  The
+ * |mem_user_data| member is passed to each allocator function.  This
+ * can be used, for example, to achieve per-session memory pool.
+ *
+ * In the following example code, ``my_malloc``, ``my_free``,
+ * ``my_calloc`` and ``my_realloc`` are the replacement of the
+ * standard allocators ``malloc``, ``free``, ``calloc`` and
+ * ``realloc`` respectively::
+ *
+ *     void *my_malloc_cb(size_t size, void *mem_user_data) {
+ *       return my_malloc(size);
+ *     }
+ *
+ *     void my_free_cb(void *ptr, void *mem_user_data) { my_free(ptr); }
+ *
+ *     void *my_calloc_cb(size_t nmemb, size_t size, void *mem_user_data) {
+ *       return my_calloc(nmemb, size);
+ *     }
+ *
+ *     void *my_realloc_cb(void *ptr, size_t size, void *mem_user_data) {
+ *       return my_realloc(ptr, size);
+ *     }
+ *
+ *     void session_new() {
+ *       nghttp2_session *session;
+ *       nghttp2_session_callbacks *callbacks;
+ *       nghttp2_mem mem = {NULL, my_malloc_cb, my_free_cb, my_calloc_cb,
+ *                          my_realloc_cb};
+ *
+ *       ...
+ *
+ *       nghttp2_session_client_new3(&session, callbacks, NULL, NULL, &mem);
+ *
+ *       ...
+ *     }
+ */
+typedef struct {
+  /**
+   * An arbitrary user supplied data.  This is passed to each
+   * allocator function.
+   */
+  void *mem_user_data;
+  /**
+   * Custom allocator function to replace malloc().
+   */
+  nghttp2_malloc malloc;
+  /**
+   * Custom allocator function to replace free().
+   */
+  nghttp2_free free;
+  /**
+   * Custom allocator function to replace calloc().
+   */
+  nghttp2_calloc calloc;
+  /**
+   * Custom allocator function to replace realloc().
+   */
+  nghttp2_realloc realloc;
+} nghttp2_mem;
+
+struct nghttp2_option;
+
+/**
+ * @struct
+ *
+ * Configuration options for :type:`nghttp2_session`.  The details of
+ * this structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_option nghttp2_option;
+
+/**
+ * @function
+ *
+ * Initializes |*option_ptr| with default values.
+ *
+ * When the application finished using this object, it can use
+ * `nghttp2_option_del()` to free its memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_option_new(nghttp2_option **option_ptr);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |option|.  If |option| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void nghttp2_option_del(nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * This option prevents the library from sending WINDOW_UPDATE for a
+ * connection automatically.  If this option is set to nonzero, the
+ * library won't send WINDOW_UPDATE for DATA until application calls
+ * `nghttp2_session_consume()` to indicate the consumed amount of
+ * data.  Don't use `nghttp2_submit_window_update()` for this purpose.
+ * By default, this option is set to zero.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
+ * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
+ * remote endpoint as if it is received in SETTINGS frame.  Without
+ * specifying this option, before the local endpoint receives
+ * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
+ * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited.  This may
+ * cause problem if local endpoint submits lots of requests initially
+ * and sending them at once to the remote peer may lead to the
+ * rejection of some requests.  Specifying this option to the sensible
+ * value, say 100, may avoid this kind of issue. This value will be
+ * overwritten if the local endpoint receives
+ * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
+                                               uint32_t val);
+
+/**
+ * @function
+ *
+ * By default, nghttp2 library, if configured as server, requires
+ * first 24 bytes of client magic byte string (MAGIC).  In most cases,
+ * this will simplify the implementation of server.  But sometimes
+ * server may want to detect the application protocol based on first
+ * few bytes on clear text communication.
+ *
+ * If this option is used with nonzero |val|, nghttp2 library does not
+ * handle MAGIC.  It still checks following SETTINGS frame.  This
+ * means that applications should deal with MAGIC by themselves.
+ *
+ * If this option is not used or used with zero value, if MAGIC does
+ * not match :macro:`NGHTTP2_CLIENT_MAGIC`, `nghttp2_session_recv()`
+ * and `nghttp2_session_mem_recv()` will return error
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`, which is fatal error.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val);
+
+/**
+ * @function
+ *
+ * By default, nghttp2 library enforces subset of HTTP Messaging rules
+ * described in `HTTP/2 specification, section 8
+ * <https://tools.ietf.org/html/rfc7540#section-8>`_.  See
+ * :ref:`http-messaging` section for details.  For those applications
+ * who use nghttp2 library as non-HTTP use, give nonzero to |val| to
+ * disable this enforcement.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_no_http_messaging(nghttp2_option *option,
+                                                         int val);
+
+/**
+ * @function
+ *
+ * RFC 7540 does not enforce any limit on the number of incoming
+ * reserved streams (in RFC 7540 terms, streams in reserved (remote)
+ * state).  This only affects client side, since only server can push
+ * streams.  Malicious server can push arbitrary number of streams,
+ * and make client's memory exhausted.  This option can set the
+ * maximum number of such incoming streams to avoid possible memory
+ * exhaustion.  If this option is set, and pushed streams are
+ * automatically closed on reception, without calling user provided
+ * callback, if they exceed the given limit.  The default value is
+ * 200.  If session is configured as server side, this option has no
+ * effect.  Server can control the number of streams to push.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
+                                               uint32_t val);
+
+/**
+ * @function
+ *
+ * Sets extension frame type the application is willing to handle with
+ * user defined callbacks (see
+ * :type:`nghttp2_on_extension_chunk_recv_callback` and
+ * :type:`nghttp2_unpack_extension_callback`).  The |type| is
+ * extension frame type, and must be strictly greater than 0x9.
+ * Otherwise, this function does nothing.  The application can call
+ * this function multiple times to set more than one frame type to
+ * receive.  The application does not have to call this function if it
+ * just sends extension frames.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
+                                            uint8_t type);
+
+/**
+ * @function
+ *
+ * Sets extension frame type the application is willing to receive
+ * using builtin handler.  The |type| is the extension frame type to
+ * receive, and must be strictly greater than 0x9.  Otherwise, this
+ * function does nothing.  The application can call this function
+ * multiple times to set more than one frame type to receive.  The
+ * application does not have to call this function if it just sends
+ * extension frames.
+ *
+ * If same frame type is passed to both
+ * `nghttp2_option_set_builtin_recv_extension_type()` and
+ * `nghttp2_option_set_user_recv_extension_type()`, the latter takes
+ * precedence.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
+                                               uint8_t type);
+
+/**
+ * @function
+ *
+ * This option prevents the library from sending PING frame with ACK
+ * flag set automatically when PING frame without ACK flag set is
+ * received.  If this option is set to nonzero, the library won't send
+ * PING frame with ACK flag set in the response for incoming PING
+ * frame.  The application can send PING frame with ACK flag set using
+ * `nghttp2_submit_ping()` with :enum:`NGHTTP2_FLAG_ACK` as flags
+ * parameter.
+ */
+NGHTTP2_EXTERN void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option,
+                                                        int val);
+
+/**
+ * @function
+ *
+ * This option sets the maximum length of header block (a set of
+ * header fields per one HEADERS frame) to send.  The length of a
+ * given set of header fields is calculated using
+ * `nghttp2_hd_deflate_bound()`.  The default value is 64KiB.  If
+ * application attempts to send header fields larger than this limit,
+ * the transmission of the frame fails with error code
+ * :enum:`NGHTTP2_ERR_FRAME_SIZE_ERROR`.
+ */
+NGHTTP2_EXTERN void
+nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
+                                                size_t val);
+
+/**
+ * @function
+ *
+ * Initializes |*session_ptr| for client use.  The all members of
+ * |callbacks| are copied to |*session_ptr|.  Therefore |*session_ptr|
+ * does not store |callbacks|.  The |user_data| is an arbitrary user
+ * supplied data, which will be passed to the callback functions.
+ *
+ * The :type:`nghttp2_send_callback` must be specified.  If the
+ * application code uses `nghttp2_session_recv()`, the
+ * :type:`nghttp2_recv_callback` must be specified.  The other members
+ * of |callbacks| can be ``NULL``.
+ *
+ * If this function fails, |*session_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_client_new(nghttp2_session **session_ptr,
+                           const nghttp2_session_callbacks *callbacks,
+                           void *user_data);
+
+/**
+ * @function
+ *
+ * Initializes |*session_ptr| for server use.  The all members of
+ * |callbacks| are copied to |*session_ptr|. Therefore |*session_ptr|
+ * does not store |callbacks|.  The |user_data| is an arbitrary user
+ * supplied data, which will be passed to the callback functions.
+ *
+ * The :type:`nghttp2_send_callback` must be specified.  If the
+ * application code uses `nghttp2_session_recv()`, the
+ * :type:`nghttp2_recv_callback` must be specified.  The other members
+ * of |callbacks| can be ``NULL``.
+ *
+ * If this function fails, |*session_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_server_new(nghttp2_session **session_ptr,
+                           const nghttp2_session_callbacks *callbacks,
+                           void *user_data);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_client_new()`, but with additional options
+ * specified in the |option|.
+ *
+ * The |option| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_client_new()`.
+ *
+ * This function does not take ownership |option|.  The application is
+ * responsible for freeing |option| if it finishes using the object.
+ *
+ * The library code does not refer to |option| after this function
+ * returns.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_client_new2(nghttp2_session **session_ptr,
+                            const nghttp2_session_callbacks *callbacks,
+                            void *user_data, const nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_server_new()`, but with additional options
+ * specified in the |option|.
+ *
+ * The |option| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_server_new()`.
+ *
+ * This function does not take ownership |option|.  The application is
+ * responsible for freeing |option| if it finishes using the object.
+ *
+ * The library code does not refer to |option| after this function
+ * returns.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_server_new2(nghttp2_session **session_ptr,
+                            const nghttp2_session_callbacks *callbacks,
+                            void *user_data, const nghttp2_option *option);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_client_new2()`, but with additional custom
+ * memory allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_client_new2()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_client_new3(
+    nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+    void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_server_new2()`, but with additional custom
+ * memory allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_session_server_new2()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_server_new3(
+    nghttp2_session **session_ptr, const nghttp2_session_callbacks *callbacks,
+    void *user_data, const nghttp2_option *option, nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Frees any resources allocated for |session|.  If |session| is
+ * ``NULL``, this function does nothing.
+ */
+NGHTTP2_EXTERN void nghttp2_session_del(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Sends pending frames to the remote peer.
+ *
+ * This function retrieves the highest prioritized frame from the
+ * outbound queue and sends it to the remote peer.  It does this as
+ * many as possible until the user callback
+ * :type:`nghttp2_send_callback` returns
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK` or the outbound queue becomes empty.
+ * This function calls several callback functions which are passed
+ * when initializing the |session|.  Here is the simple time chart
+ * which tells when each callback is invoked:
+ *
+ * 1. Get the next frame to send from outbound queue.
+ *
+ * 2. Prepare transmission of the frame.
+ *
+ * 3. If the control frame cannot be sent because some preconditions
+ *    are not met (e.g., request HEADERS cannot be sent after GOAWAY),
+ *    :type:`nghttp2_on_frame_not_send_callback` is invoked.  Abort
+ *    the following steps.
+ *
+ * 4. If the frame is HEADERS, PUSH_PROMISE or DATA,
+ *    :type:`nghttp2_select_padding_callback` is invoked.
+ *
+ * 5. If the frame is request HEADERS, the stream is opened here.
+ *
+ * 6. :type:`nghttp2_before_frame_send_callback` is invoked.
+ *
+ * 7. If :enum:`NGHTTP2_ERR_CANCEL` is returned from
+ *    :type:`nghttp2_before_frame_send_callback`, the current frame
+ *    transmission is canceled, and
+ *    :type:`nghttp2_on_frame_not_send_callback` is invoked.  Abort
+ *    the following steps.
+ *
+ * 8. :type:`nghttp2_send_callback` is invoked one or more times to
+ *    send the frame.
+ *
+ * 9. :type:`nghttp2_on_frame_send_callback` is invoked.
+ *
+ * 10. If the transmission of the frame triggers closure of the
+ *     stream, the stream is closed and
+ *     :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ */
+NGHTTP2_EXTERN int nghttp2_session_send(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the serialized data to send.
+ *
+ * This function behaves like `nghttp2_session_send()` except that it
+ * does not use :type:`nghttp2_send_callback` to transmit data.
+ * Instead, it assigns the pointer to the serialized data to the
+ * |*data_ptr| and returns its length.  The other callbacks are called
+ * in the same way as they are in `nghttp2_session_send()`.
+ *
+ * If no data is available to send, this function returns 0.
+ *
+ * This function may not return all serialized data in one invocation.
+ * To get all data, call this function repeatedly until it returns 0
+ * or one of negative error codes.
+ *
+ * The assigned |*data_ptr| is valid until the next call of
+ * `nghttp2_session_mem_send()` or `nghttp2_session_send()`.
+ *
+ * The caller must send all data before sending the next chunk of
+ * data.
+ *
+ * This function returns the length of the data pointed by the
+ * |*data_ptr| if it succeeds, or one of the following negative error
+ * codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ *
+ * .. note::
+ *
+ *   This function may produce very small byte string.  If that is the
+ *   case, and application disables Nagle algorithm (``TCP_NODELAY``),
+ *   then writing this small chunk leads to very small packet, and it
+ *   is very inefficient.  An application should be responsible to
+ *   buffer up small chunks of data as necessary to avoid this
+ *   situation.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_session_mem_send(nghttp2_session *session, const uint8_t **data_ptr);
+
+/**
+ * @function
+ *
+ * Receives frames from the remote peer.
+ *
+ * This function receives as many frames as possible until the user
+ * callback :type:`nghttp2_recv_callback` returns
+ * :enum:`NGHTTP2_ERR_WOULDBLOCK`.  This function calls several
+ * callback functions which are passed when initializing the
+ * |session|.  Here is the simple time chart which tells when each
+ * callback is invoked:
+ *
+ * 1. :type:`nghttp2_recv_callback` is invoked one or more times to
+ *    receive frame header.
+ *
+ * 2. When frame header is received,
+ *    :type:`nghttp2_on_begin_frame_callback` is invoked.
+ *
+ * 3. If the frame is DATA frame:
+ *
+ *    1. :type:`nghttp2_recv_callback` is invoked to receive DATA
+ *       payload. For each chunk of data,
+ *       :type:`nghttp2_on_data_chunk_recv_callback` is invoked.
+ *
+ *    2. If one DATA frame is completely received,
+ *       :type:`nghttp2_on_frame_recv_callback` is invoked.  If the
+ *       reception of the frame triggers the closure of the stream,
+ *       :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ * 4. If the frame is the control frame:
+ *
+ *    1. :type:`nghttp2_recv_callback` is invoked one or more times to
+ *       receive whole frame.
+ *
+ *    2. If the received frame is valid, then following actions are
+ *       taken.  If the frame is either HEADERS or PUSH_PROMISE,
+ *       :type:`nghttp2_on_begin_headers_callback` is invoked.  Then
+ *       :type:`nghttp2_on_header_callback` is invoked for each header
+ *       name/value pair.  After all name/value pairs are emitted
+ *       successfully, :type:`nghttp2_on_frame_recv_callback` is
+ *       invoked.  For other frames,
+ *       :type:`nghttp2_on_frame_recv_callback` is invoked.  If the
+ *       reception of the frame triggers the closure of the stream,
+ *       :type:`nghttp2_on_stream_close_callback` is invoked.
+ *
+ *    3. If the received frame is unpacked but is interpreted as
+ *       invalid, :type:`nghttp2_on_invalid_frame_recv_callback` is
+ *       invoked.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_EOF`
+ *     The remote peer did shutdown on the connection.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ *     Invalid client magic was detected.  This error only returns
+ *     when |session| was configured as server and
+ *     `nghttp2_option_set_no_recv_client_magic()` is not used with
+ *     nonzero value.
+ * :enum:`NGHTTP2_ERR_FLOODED`
+ *     Flooding was detected in this HTTP/2 session, and it must be
+ *     closed.  This is most likely caused by misbehaviour of peer.
+ */
+NGHTTP2_EXTERN int nghttp2_session_recv(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Processes data |in| as an input from the remote endpoint.  The
+ * |inlen| indicates the number of bytes in the |in|.
+ *
+ * This function behaves like `nghttp2_session_recv()` except that it
+ * does not use :type:`nghttp2_recv_callback` to receive data; the
+ * |in| is the only data for the invocation of this function.  If all
+ * bytes are processed, this function returns.  The other callbacks
+ * are called in the same way as they are in `nghttp2_session_recv()`.
+ *
+ * In the current implementation, this function always tries to
+ * processes all input data unless either an error occurs or
+ * :enum:`NGHTTP2_ERR_PAUSE` is returned from
+ * :type:`nghttp2_on_header_callback` or
+ * :type:`nghttp2_on_data_chunk_recv_callback`.  If
+ * :enum:`NGHTTP2_ERR_PAUSE` is used, the return value includes the
+ * number of bytes which was used to produce the data or frame for the
+ * callback.
+ *
+ * This function returns the number of processed bytes, or one of the
+ * following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_CALLBACK_FAILURE`
+ *     The callback function failed.
+ * :enum:`NGHTTP2_ERR_BAD_CLIENT_MAGIC`
+ *     Invalid client magic was detected.  This error only returns
+ *     when |session| was configured as server and
+ *     `nghttp2_option_set_no_recv_client_magic()` is not used with
+ *     nonzero value.
+ * :enum:`NGHTTP2_ERR_FLOODED`
+ *     Flooding was detected in this HTTP/2 session, and it must be
+ *     closed.  This is most likely caused by misbehaviour of peer.
+ */
+NGHTTP2_EXTERN ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
+                                                const uint8_t *in,
+                                                size_t inlen);
+
+/**
+ * @function
+ *
+ * Puts back previously deferred DATA frame in the stream |stream_id|
+ * to the outbound queue.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The stream does not exist; or no deferred data exist.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_resume_data(nghttp2_session *session,
+                                               int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns nonzero value if |session| wants to receive data from the
+ * remote peer.
+ *
+ * If both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0, the application should
+ * drop the connection.
+ */
+NGHTTP2_EXTERN int nghttp2_session_want_read(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero value if |session| wants to send data to the remote
+ * peer.
+ *
+ * If both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0, the application should
+ * drop the connection.
+ */
+NGHTTP2_EXTERN int nghttp2_session_want_write(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns stream_user_data for the stream |stream_id|.  The
+ * stream_user_data is provided by `nghttp2_submit_request()`,
+ * `nghttp2_submit_headers()` or
+ * `nghttp2_session_set_stream_user_data()`.  Unless it is set using
+ * `nghttp2_session_set_stream_user_data()`, if the stream is
+ * initiated by the remote endpoint, stream_user_data is always
+ * ``NULL``.  If the stream does not exist, this function returns
+ * ``NULL``.
+ */
+NGHTTP2_EXTERN void *
+nghttp2_session_get_stream_user_data(nghttp2_session *session,
+                                     int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Sets the |stream_user_data| to the stream denoted by the
+ * |stream_id|.  If a stream user data is already set to the stream,
+ * it is replaced with the |stream_user_data|.  It is valid to specify
+ * ``NULL`` in the |stream_user_data|, which nullifies the associated
+ * data pointer.
+ *
+ * It is valid to set the |stream_user_data| to the stream reserved by
+ * PUSH_PROMISE frame.
+ *
+ * This function returns 0 if it succeeds, or one of following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The stream does not exist
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_set_stream_user_data(nghttp2_session *session,
+                                     int32_t stream_id, void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Returns the number of frames in the outbound queue.  This does not
+ * include the deferred DATA frames.
+ */
+NGHTTP2_EXTERN size_t
+nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the number of DATA payload in bytes received without
+ * WINDOW_UPDATE transmission for the stream |stream_id|.  The local
+ * (receive) window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective data length.  In particular, if the
+ * local window size is reduced by submitting negative
+ * window_size_increment with `nghttp2_submit_window_update()`, this
+ * function returns the number of bytes less than actually received.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session,
+                                                      int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the local (receive) window size for the stream |stream_id|.
+ * The local window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective window size.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
+                                                       int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the number of DATA payload in bytes received without
+ * WINDOW_UPDATE transmission for a connection.  The local (receive)
+ * window size can be adjusted by `nghttp2_submit_window_update()`.
+ * This function takes into account that and returns effective data
+ * length.  In particular, if the local window size is reduced by
+ * submitting negative window_size_increment with
+ * `nghttp2_submit_window_update()`, this function returns the number
+ * of bytes less than actually received.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the local (receive) window size for a connection.  The
+ * local window size can be adjusted by
+ * `nghttp2_submit_window_update()`.  This function takes into account
+ * that and returns effective window size.
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the remote window size for a given stream |stream_id|.
+ *
+ * This is the amount of flow-controlled payload (e.g., DATA) that the
+ * local endpoint can send without stream level WINDOW_UPDATE.  There
+ * is also connection level flow control, so the effective size of
+ * payload that the local endpoint can actually send is
+ * min(`nghttp2_session_get_stream_remote_window_size()`,
+ * `nghttp2_session_get_remote_window_size()`).
+ *
+ * This function returns -1 if it fails.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
+                                              int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns the remote window size for a connection.
+ *
+ * This function always succeeds.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_remote_window_size(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns 1 if local peer half closed the given stream |stream_id|.
+ * Returns 0 if it did not.  Returns -1 if no such stream exists.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_local_close(nghttp2_session *session,
+                                       int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Returns 1 if remote peer half closed the given stream |stream_id|.
+ * Returns 0 if it did not.  Returns -1 if no such stream exists.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_get_stream_remote_close(nghttp2_session *session,
+                                        int32_t stream_id);
+
+/**
+ * @function
+ *
+ * Signals the session so that the connection should be terminated.
+ *
+ * The last stream ID is the minimum value between the stream ID of a
+ * stream for which :type:`nghttp2_on_frame_recv_callback` was called
+ * most recently and the last stream ID we have sent to the peer
+ * previously.
+ *
+ * The |error_code| is the error code of this GOAWAY frame.  The
+ * pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * After the transmission, both `nghttp2_session_want_read()` and
+ * `nghttp2_session_want_write()` return 0.
+ *
+ * This function should be called when the connection should be
+ * terminated after sending GOAWAY.  If the remaining streams should
+ * be processed after GOAWAY, use `nghttp2_submit_goaway()` instead.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_session_terminate_session(nghttp2_session *session,
+                                                     uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Signals the session so that the connection should be terminated.
+ *
+ * This function behaves like `nghttp2_session_terminate_session()`,
+ * but the last stream ID can be specified by the application for fine
+ * grained control of stream.  The HTTP/2 specification does not allow
+ * last_stream_id to be increased.  So the actual value sent as
+ * last_stream_id is the minimum value between the given
+ * |last_stream_id| and the last_stream_id we have previously sent to
+ * the peer.
+ *
+ * The |last_stream_id| is peer's stream ID or 0.  So if |session| is
+ * initialized as client, |last_stream_id| must be even or 0.  If
+ * |session| is initialized as server, |last_stream_id| must be odd or
+ * 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |last_stream_id| is invalid.
+ */
+NGHTTP2_EXTERN int nghttp2_session_terminate_session2(nghttp2_session *session,
+                                                      int32_t last_stream_id,
+                                                      uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Signals to the client that the server started graceful shutdown
+ * procedure.
+ *
+ * This function is only usable for server.  If this function is
+ * called with client side session, this function returns
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ *
+ * To gracefully shutdown HTTP/2 session, server should call this
+ * function to send GOAWAY with last_stream_id (1u << 31) - 1.  And
+ * after some delay (e.g., 1 RTT), send another GOAWAY with the stream
+ * ID that the server has some processing using
+ * `nghttp2_submit_goaway()`.  See also
+ * `nghttp2_session_get_last_proc_stream_id()`.
+ *
+ * Unlike `nghttp2_submit_goaway()`, this function just sends GOAWAY
+ * and does nothing more.  This is a mere indication to the client
+ * that session shutdown is imminent.  The application should call
+ * `nghttp2_submit_goaway()` with appropriate last_stream_id after
+ * this call.
+ *
+ * If one or more GOAWAY frame have been already sent by either
+ * `nghttp2_submit_goaway()` or `nghttp2_session_terminate_session()`,
+ * this function has no effect.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The |session| is initialized as client.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_shutdown_notice(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the value of SETTINGS |id| notified by a remote endpoint.
+ * The |id| must be one of values defined in
+ * :enum:`nghttp2_settings_id`.
+ */
+NGHTTP2_EXTERN uint32_t
+nghttp2_session_get_remote_settings(nghttp2_session *session,
+                                    nghttp2_settings_id id);
+
+/**
+ * @function
+ *
+ * Tells the |session| that next stream ID is |next_stream_id|.  The
+ * |next_stream_id| must be equal or greater than the value returned
+ * by `nghttp2_session_get_next_stream_id()`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |next_stream_id| is strictly less than the value
+ *     `nghttp2_session_get_next_stream_id()` returns; or
+ *     |next_stream_id| is invalid (e.g., even integer for client, or
+ *     odd integer for server).
+ */
+NGHTTP2_EXTERN int nghttp2_session_set_next_stream_id(nghttp2_session *session,
+                                                      int32_t next_stream_id);
+
+/**
+ * @function
+ *
+ * Returns the next outgoing stream ID.  Notice that return type is
+ * uint32_t.  If we run out of stream ID for this session, this
+ * function returns 1 << 31.
+ */
+NGHTTP2_EXTERN uint32_t
+nghttp2_session_get_next_stream_id(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Tells the |session| that |size| bytes for a stream denoted by
+ * |stream_id| were consumed by application and are ready to
+ * WINDOW_UPDATE.  The consumed bytes are counted towards both
+ * connection and stream level WINDOW_UPDATE (see
+ * `nghttp2_session_consume_connection()` and
+ * `nghttp2_session_consume_stream()` to update consumption
+ * independently).  This function is intended to be used without
+ * automatic window update (see
+ * `nghttp2_option_set_no_auto_window_update()`).
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume(nghttp2_session *session,
+                                           int32_t stream_id, size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for connection level.  Note that
+ * HTTP/2 maintains connection and stream level flow control windows
+ * independently.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_connection(nghttp2_session *session,
+                                                      size_t size);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_session_consume()`, but this only tells library that
+ * |size| bytes were consumed only for stream denoted by |stream_id|.
+ * Note that HTTP/2 maintains connection and stream level flow control
+ * windows independently.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     Automatic WINDOW_UPDATE is not disabled.
+ */
+NGHTTP2_EXTERN int nghttp2_session_consume_stream(nghttp2_session *session,
+                                                  int32_t stream_id,
+                                                  size_t size);
+
+/**
+ * @function
+ *
+ * Changes priority of existing stream denoted by |stream_id|.  The
+ * new priority specification is |pri_spec|.
+ *
+ * The priority is changed silently and instantly, and no PRIORITY
+ * frame will be sent to notify the peer of this change.  This
+ * function may be useful for server to change the priority of pushed
+ * stream.
+ *
+ * If |session| is initialized as server, and ``pri_spec->stream_id``
+ * points to the idle stream, the idle stream is created if it does
+ * not exist.  The created idle stream will depend on root stream
+ * (stream 0) with weight 16.
+ *
+ * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not
+ * found, we use default priority instead of given |pri_spec|.  That
+ * is make stream depend on root stream with weight 16.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Attempted to depend on itself; or no stream exist for the given
+ *     |stream_id|; or |stream_id| is 0
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_change_stream_priority(nghttp2_session *session,
+                                       int32_t stream_id,
+                                       const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Creates idle stream with the given |stream_id|, and priority
+ * |pri_spec|.
+ *
+ * The stream creation is done without sending PRIORITY frame, which
+ * means that peer does not know about the existence of this idle
+ * stream in the local endpoint.
+ *
+ * RFC 7540 does not disallow the use of creation of idle stream with
+ * odd or even stream ID regardless of client or server.  So this
+ * function can create odd or even stream ID regardless of client or
+ * server.  But probably it is a bit safer to use the stream ID the
+ * local endpoint can initiate (in other words, use odd stream ID for
+ * client, and even stream ID for server), to avoid potential
+ * collision from peer's instruction.  Also we can use
+ * `nghttp2_session_set_next_stream_id()` to avoid to open created
+ * idle streams accidentally if we follow this recommendation.
+ *
+ * If |session| is initialized as server, and ``pri_spec->stream_id``
+ * points to the idle stream, the idle stream is created if it does
+ * not exist.  The created idle stream will depend on root stream
+ * (stream 0) with weight 16.
+ *
+ * Otherwise, if stream denoted by ``pri_spec->stream_id`` is not
+ * found, we use default priority instead of given |pri_spec|.  That
+ * is make stream depend on root stream with weight 16.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Attempted to depend on itself; or stream denoted by |stream_id|
+ *     already exists; or |stream_id| cannot be used to create idle
+ *     stream (in other words, local endpoint has already opened
+ *     stream ID greater than or equal to the given stream ID; or
+ *     |stream_id| is 0
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_create_idle_stream(nghttp2_session *session, int32_t stream_id,
+                                   const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Performs post-process of HTTP Upgrade request.  This function can
+ * be called from both client and server, but the behavior is very
+ * different in each other.
+ *
+ * .. warning::
+ *
+ *   This function is deprecated in favor of
+ *   `nghttp2_session_upgrade2()`, because this function lacks the
+ *   parameter to tell the library the request method used in the
+ *   original HTTP request.  This information is required for client
+ *   to validate actual response body length against content-length
+ *   header field (see `nghttp2_option_set_no_http_messaging()`).  If
+ *   HEAD is used in request, the length of response body must be 0
+ *   regardless of value included in content-length header field.
+ *
+ * If called from client side, the |settings_payload| must be the
+ * value sent in ``HTTP2-Settings`` header field and must be decoded
+ * by base64url decoder.  The |settings_payloadlen| is the length of
+ * |settings_payload|.  The |settings_payload| is unpacked and its
+ * setting values will be submitted using `nghttp2_submit_settings()`.
+ * This means that the client application code does not need to submit
+ * SETTINGS by itself.  The stream with stream ID=1 is opened and the
+ * |stream_user_data| is used for its stream_user_data.  The opened
+ * stream becomes half-closed (local) state.
+ *
+ * If called from server side, the |settings_payload| must be the
+ * value received in ``HTTP2-Settings`` header field and must be
+ * decoded by base64url decoder.  The |settings_payloadlen| is the
+ * length of |settings_payload|.  It is treated as if the SETTINGS
+ * frame with that payload is received.  Thus, callback functions for
+ * the reception of SETTINGS frame will be invoked.  The stream with
+ * stream ID=1 is opened.  The |stream_user_data| is ignored.  The
+ * opened stream becomes half-closed (remote).
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |settings_payload| is badly formed.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The stream ID 1 is already used or closed; or is not available.
+ */
+NGHTTP2_EXTERN int nghttp2_session_upgrade(nghttp2_session *session,
+                                           const uint8_t *settings_payload,
+                                           size_t settings_payloadlen,
+                                           void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Performs post-process of HTTP Upgrade request.  This function can
+ * be called from both client and server, but the behavior is very
+ * different in each other.
+ *
+ * If called from client side, the |settings_payload| must be the
+ * value sent in ``HTTP2-Settings`` header field and must be decoded
+ * by base64url decoder.  The |settings_payloadlen| is the length of
+ * |settings_payload|.  The |settings_payload| is unpacked and its
+ * setting values will be submitted using `nghttp2_submit_settings()`.
+ * This means that the client application code does not need to submit
+ * SETTINGS by itself.  The stream with stream ID=1 is opened and the
+ * |stream_user_data| is used for its stream_user_data.  The opened
+ * stream becomes half-closed (local) state.
+ *
+ * If called from server side, the |settings_payload| must be the
+ * value received in ``HTTP2-Settings`` header field and must be
+ * decoded by base64url decoder.  The |settings_payloadlen| is the
+ * length of |settings_payload|.  It is treated as if the SETTINGS
+ * frame with that payload is received.  Thus, callback functions for
+ * the reception of SETTINGS frame will be invoked.  The stream with
+ * stream ID=1 is opened.  The |stream_user_data| is ignored.  The
+ * opened stream becomes half-closed (remote).
+ *
+ * If the request method is HEAD, pass nonzero value to
+ * |head_request|.  Otherwise, pass 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |settings_payload| is badly formed.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The stream ID 1 is already used or closed; or is not available.
+ */
+NGHTTP2_EXTERN int nghttp2_session_upgrade2(nghttp2_session *session,
+                                            const uint8_t *settings_payload,
+                                            size_t settings_payloadlen,
+                                            int head_request,
+                                            void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Serializes the SETTINGS values |iv| in the |buf|.  The size of the
+ * |buf| is specified by |buflen|.  The number of entries in the |iv|
+ * array is given by |niv|.  The required space in |buf| for the |niv|
+ * entries is ``8*niv`` bytes and if the given buffer is too small, an
+ * error is returned.  This function is used mainly for creating a
+ * SETTINGS payload to be sent with the ``HTTP2-Settings`` header
+ * field in an HTTP Upgrade request.  The data written in |buf| is NOT
+ * base64url encoded and the application is responsible for encoding.
+ *
+ * This function returns the number of bytes written in |buf|, or one
+ * of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |iv| contains duplicate settings ID or invalid value.
+ *
+ * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ *     The provided |buflen| size is too small to hold the output.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
+                              const nghttp2_settings_entry *iv, size_t niv);
+
+/**
+ * @function
+ *
+ * Returns string describing the |lib_error_code|.  The
+ * |lib_error_code| must be one of the :enum:`nghttp2_error`.
+ */
+NGHTTP2_EXTERN const char *nghttp2_strerror(int lib_error_code);
+
+/**
+ * @function
+ *
+ * Returns string representation of HTTP/2 error code |error_code|
+ * (e.g., ``PROTOCOL_ERROR`` is returned if ``error_code ==
+ * NGHTTP2_PROTOCOL_ERROR``).  If string representation is unknown for
+ * given |error_code|, this function returns string ``unknown``.
+ */
+NGHTTP2_EXTERN const char *nghttp2_http2_strerror(uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Initializes |pri_spec| with the |stream_id| of the stream to depend
+ * on with |weight| and its exclusive flag.  If |exclusive| is
+ * nonzero, exclusive flag is set.
+ *
+ * The |weight| must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.
+ */
+NGHTTP2_EXTERN void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
+                                               int32_t stream_id,
+                                               int32_t weight, int exclusive);
+
+/**
+ * @function
+ *
+ * Initializes |pri_spec| with the default values.  The default values
+ * are: stream_id = 0, weight = :macro:`NGHTTP2_DEFAULT_WEIGHT` and
+ * exclusive = 0.
+ */
+NGHTTP2_EXTERN void
+nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the |pri_spec| is filled with default values.
+ */
+NGHTTP2_EXTERN int
+nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Submits HEADERS frame and optionally one or more DATA frames.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * means the default priority (see
+ * `nghttp2_priority_spec_default_init()`).  To specify the priority,
+ * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
+ * this function will copy its data members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * HTTP/2 specification has requirement about header fields in the
+ * request HEADERS.  See the specification for more details.
+ *
+ * If |data_prd| is not ``NULL``, it provides data which will be sent
+ * in subsequent DATA frames.  In this case, a method that allows
+ * request message bodies
+ * (https://tools.ietf.org/html/rfc7231#section-4) must be specified
+ * with ``:method`` key in |nva| (e.g. ``POST``).  This function does
+ * not take ownership of the |data_prd|.  The function copies the
+ * members of the |data_prd|.  If |data_prd| is ``NULL``, HEADERS have
+ * END_STREAM set.  The |stream_user_data| is data associated to the
+ * stream opened by this request and can be an arbitrary pointer,
+ * which can be retrieved later by
+ * `nghttp2_session_get_stream_user_data()`.
+ *
+ * This function returns assigned stream ID if it succeeds, or one of
+ * the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     Trying to depend on itself (new stream ID equals
+ *     ``pri_spec->stream_id``).
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |session| is server session.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned stream ID if it succeeds.  But
+ *   that stream is not opened yet.  The application must not submit
+ *   frame to that stream ID before
+ *   :type:`nghttp2_before_frame_send_callback` is called for this
+ *   frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_request(nghttp2_session *session,
+                       const nghttp2_priority_spec *pri_spec,
+                       const nghttp2_nv *nva, size_t nvlen,
+                       const nghttp2_data_provider *data_prd,
+                       void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits response HEADERS frame and optionally one or more DATA
+ * frames against the stream |stream_id|.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * HTTP/2 specification has requirement about header fields in the
+ * response HEADERS.  See the specification for more details.
+ *
+ * If |data_prd| is not ``NULL``, it provides data which will be sent
+ * in subsequent DATA frames.  This function does not take ownership
+ * of the |data_prd|.  The function copies the members of the
+ * |data_prd|.  If |data_prd| is ``NULL``, HEADERS will have
+ * END_STREAM flag set.
+ *
+ * This method can be used as normal HTTP response and push response.
+ * When pushing a resource using this function, the |session| must be
+ * configured using `nghttp2_session_server_new()` or its variants and
+ * the target stream denoted by the |stream_id| must be reserved using
+ * `nghttp2_submit_push_promise()`.
+ *
+ * To send non-final response headers (e.g., HTTP status 101), don't
+ * use this function because this function half-closes the outbound
+ * stream.  Instead, use `nghttp2_submit_headers()` for this purpose.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.  Normally, this does not happen, but when
+ *     application wrongly calls `nghttp2_submit_response()` twice,
+ *     this may happen.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |session| is client session.
+ *
+ * .. warning::
+ *
+ *   Calling this function twice for the same stream ID may lead to
+ *   program crash.  It is generally considered to a programming error
+ *   to commit response twice.
+ */
+NGHTTP2_EXTERN int
+nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
+                        const nghttp2_nv *nva, size_t nvlen,
+                        const nghttp2_data_provider *data_prd);
+
+/**
+ * @function
+ *
+ * Submits trailer fields HEADERS against the stream |stream_id|.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible not to include
+ * pseudo-header fields (header field whose name starts with ":") in
+ * |nva|.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * For server, trailer fields must follow response HEADERS or response
+ * DATA without END_STREAM flat set.  The library does not enforce
+ * this requirement, and applications should do this for themselves.
+ * If `nghttp2_submit_trailer()` is called before any response HEADERS
+ * submission (usually by `nghttp2_submit_response()`), the content of
+ * |nva| will be sent as response headers, which will result in error.
+ *
+ * This function has the same effect with `nghttp2_submit_headers()`,
+ * with flags = :enum:`NGHTTP2_FLAG_END_STREAM` and both pri_spec and
+ * stream_user_data to NULL.
+ *
+ * To submit trailer fields after `nghttp2_submit_response()` is
+ * called, the application has to specify
+ * :type:`nghttp2_data_provider` to `nghttp2_submit_response()`.
+ * Inside of :type:`nghttp2_data_source_read_callback`, when setting
+ * :enum:`NGHTTP2_DATA_FLAG_EOF`, also set
+ * :enum:`NGHTTP2_DATA_FLAG_NO_END_STREAM`.  After that, the
+ * application can send trailer fields using
+ * `nghttp2_submit_trailer()`.  `nghttp2_submit_trailer()` can be used
+ * inside :type:`nghttp2_data_source_read_callback`.
+ *
+ * This function returns 0 if it succeeds and |stream_id| is -1.
+ * Otherwise, this function returns 0 if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_trailer(nghttp2_session *session,
+                                          int32_t stream_id,
+                                          const nghttp2_nv *nva, size_t nvlen);
+
+/**
+ * @function
+ *
+ * Submits HEADERS frame. The |flags| is bitwise OR of the
+ * following values:
+ *
+ * * :enum:`NGHTTP2_FLAG_END_STREAM`
+ *
+ * If |flags| includes :enum:`NGHTTP2_FLAG_END_STREAM`, this frame has
+ * END_STREAM flag set.
+ *
+ * The library handles the CONTINUATION frame internally and it
+ * correctly sets END_HEADERS to the last sequence of the PUSH_PROMISE
+ * or CONTINUATION frame.
+ *
+ * If the |stream_id| is -1, this frame is assumed as request (i.e.,
+ * request HEADERS frame which opens new stream).  In this case, the
+ * assigned stream ID will be returned.  Otherwise, specify stream ID
+ * in |stream_id|.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * means the default priority (see
+ * `nghttp2_priority_spec_default_init()`).  To specify the priority,
+ * use `nghttp2_priority_spec_init()`.  If |pri_spec| is not ``NULL``,
+ * this function will copy its data members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * The |stream_user_data| is a pointer to an arbitrary data which is
+ * associated to the stream this frame will open.  Therefore it is
+ * only used if this frame opens streams, in other words, it changes
+ * stream state from idle or reserved to open.
+ *
+ * This function is low-level in a sense that the application code can
+ * specify flags directly.  For usual HTTP request,
+ * `nghttp2_submit_request()` is useful.  Likewise, for HTTP response,
+ * prefer `nghttp2_submit_response()`.
+ *
+ * This function returns newly assigned stream ID if it succeeds and
+ * |stream_id| is -1.  Otherwise, this function returns 0 if it
+ * succeeds, or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; or trying to depend on itself (stream ID
+ *     equals ``pri_spec->stream_id``).
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.  This happens if stream denoted by |stream_id|
+ *     is in reserved state.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     The |stream_id| is -1, and |session| is server session.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned stream ID if it succeeds and
+ *   |stream_id| is -1.  But that stream is not opened yet.  The
+ *   application must not submit frame to that stream ID before
+ *   :type:`nghttp2_before_frame_send_callback` is called for this
+ *   frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
+                       int32_t stream_id, const nghttp2_priority_spec *pri_spec,
+                       const nghttp2_nv *nva, size_t nvlen,
+                       void *stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits one or more DATA frames to the stream |stream_id|.  The
+ * data to be sent are provided by |data_prd|.  If |flags| contains
+ * :enum:`NGHTTP2_FLAG_END_STREAM`, the last DATA frame has END_STREAM
+ * flag set.
+ *
+ * This function does not take ownership of the |data_prd|.  The
+ * function copies the members of the |data_prd|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *     DATA or HEADERS has been already submitted and not fully
+ *     processed yet.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ *     The stream was already closed; or the |stream_id| is invalid.
+ *
+ * .. note::
+ *
+ *   Currently, only one DATA or HEADERS is allowed for a stream at a
+ *   time.  Submitting these frames more than once before first DATA
+ *   or HEADERS is finished results in :enum:`NGHTTP2_ERR_DATA_EXIST`
+ *   error code.  The earliest callback which tells that previous
+ *   frame is done is :type:`nghttp2_on_frame_send_callback`.  In side
+ *   that callback, new data can be submitted using
+ *   `nghttp2_submit_data()`.  Of course, all data except for last one
+ *   must not have :enum:`NGHTTP2_FLAG_END_STREAM` flag set in
+ *   |flags|.  This sounds a bit complicated, and we recommend to use
+ *   `nghttp2_submit_request()` and `nghttp2_submit_response()` to
+ *   avoid this cascading issue.  The experience shows that for HTTP
+ *   use, these two functions are enough to implement both client and
+ *   server.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
+                                       int32_t stream_id,
+                                       const nghttp2_data_provider *data_prd);
+
+/**
+ * @function
+ *
+ * Submits PRIORITY frame to change the priority of stream |stream_id|
+ * to the priority specification |pri_spec|.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |pri_spec| is priority specification of this request.  ``NULL``
+ * is not allowed for this function. To specify the priority, use
+ * `nghttp2_priority_spec_init()`.  This function will copy its data
+ * members.
+ *
+ * The ``pri_spec->weight`` must be in [:enum:`NGHTTP2_MIN_WEIGHT`,
+ * :enum:`NGHTTP2_MAX_WEIGHT`], inclusive.  If ``pri_spec->weight`` is
+ * strictly less than :enum:`NGHTTP2_MIN_WEIGHT`, it becomes
+ * :enum:`NGHTTP2_MIN_WEIGHT`.  If it is strictly greater than
+ * :enum:`NGHTTP2_MAX_WEIGHT`, it becomes :enum:`NGHTTP2_MAX_WEIGHT`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; or the |pri_spec| is NULL; or trying to
+ *     depend on itself.
+ */
+NGHTTP2_EXTERN int
+nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
+                        int32_t stream_id,
+                        const nghttp2_priority_spec *pri_spec);
+
+/**
+ * @function
+ *
+ * Submits RST_STREAM frame to cancel/reject the stream |stream_id|
+ * with the error code |error_code|.
+ *
+ * The pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_rst_stream(nghttp2_session *session,
+                                             uint8_t flags, int32_t stream_id,
+                                             uint32_t error_code);
+
+/**
+ * @function
+ *
+ * Stores local settings and submits SETTINGS frame.  The |iv| is the
+ * pointer to the array of :type:`nghttp2_settings_entry`.  The |niv|
+ * indicates the number of :type:`nghttp2_settings_entry`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This function does not take ownership of the |iv|.  This function
+ * copies all the elements in the |iv|.
+ *
+ * While updating individual stream's local window size, if the window
+ * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
+ * RST_STREAM is issued against such a stream.
+ *
+ * SETTINGS with :enum:`NGHTTP2_FLAG_ACK` is automatically submitted
+ * by the library and application could not send it at its will.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |iv| contains invalid value (e.g., initial window size
+ *     strictly greater than (1 << 31) - 1.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_settings(nghttp2_session *session,
+                                           uint8_t flags,
+                                           const nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+/**
+ * @function
+ *
+ * Submits PUSH_PROMISE frame.
+ *
+ * The |flags| is currently ignored.  The library handles the
+ * CONTINUATION frame internally and it correctly sets END_HEADERS to
+ * the last sequence of the PUSH_PROMISE or CONTINUATION frame.
+ *
+ * The |stream_id| must be client initiated stream ID.
+ *
+ * The |nva| is an array of name/value pair :type:`nghttp2_nv` with
+ * |nvlen| elements.  The application is responsible to include
+ * required pseudo-header fields (header field whose name starts with
+ * ":") in |nva| and must place pseudo-headers before regular header
+ * fields.
+ *
+ * This function creates copies of all name/value pairs in |nva|.  It
+ * also lower-cases all names in |nva|.  The order of elements in
+ * |nva| is preserved.  For header fields with
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME` and
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_VALUE` are set, header field name
+ * and value are not copied respectively.  With
+ * :enum:`NGHTTP2_NV_FLAG_NO_COPY_NAME`, application is responsible to
+ * pass header field name in lowercase.  The application should
+ * maintain the references to them until
+ * :type:`nghttp2_on_frame_send_callback` or
+ * :type:`nghttp2_on_frame_not_send_callback` is called.
+ *
+ * The |promised_stream_user_data| is a pointer to an arbitrary data
+ * which is associated to the promised stream this frame will open and
+ * make it in reserved state.  It is available using
+ * `nghttp2_session_get_stream_user_data()`.  The application can
+ * access it in :type:`nghttp2_before_frame_send_callback` and
+ * :type:`nghttp2_on_frame_send_callback` of this frame.
+ *
+ * The client side is not allowed to use this function.
+ *
+ * To submit response headers and data, use
+ * `nghttp2_submit_response()`.
+ *
+ * This function returns assigned promised stream ID if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_PROTO`
+ *     This function was invoked when |session| is initialized as
+ *     client.
+ * :enum:`NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE`
+ *     No stream ID is available because maximum stream ID was
+ *     reached.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is 0; The |stream_id| does not designate stream
+ *     that peer initiated.
+ * :enum:`NGHTTP2_ERR_STREAM_CLOSED`
+ *     The stream was already closed; or the |stream_id| is invalid.
+ *
+ * .. warning::
+ *
+ *   This function returns assigned promised stream ID if it succeeds.
+ *   As of 1.16.0, stream object for pushed resource is created when
+ *   this function succeeds.  In that case, the application can submit
+ *   push response for the promised frame.
+ *
+ *   In 1.15.0 or prior versions, pushed stream is not opened yet when
+ *   this function succeeds.  The application must not submit frame to
+ *   that stream ID before :type:`nghttp2_before_frame_send_callback`
+ *   is called for this frame.
+ *
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
+                            int32_t stream_id, const nghttp2_nv *nva,
+                            size_t nvlen, void *promised_stream_user_data);
+
+/**
+ * @function
+ *
+ * Submits PING frame.  You don't have to send PING back when you
+ * received PING frame.  The library automatically submits PING frame
+ * in this case.
+ *
+ * The |flags| is bitwise OR of 0 or more of the following value.
+ *
+ * * :enum:`NGHTTP2_FLAG_ACK`
+ *
+ * Unless `nghttp2_option_set_no_auto_ping_ack()` is used, the |flags|
+ * should be :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * If the |opaque_data| is non ``NULL``, then it should point to the 8
+ * bytes array of memory to specify opaque data to send with PING
+ * frame.  If the |opaque_data| is ``NULL``, zero-cleared 8 bytes will
+ * be sent as opaque data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
+                                       const uint8_t *opaque_data);
+
+/**
+ * @function
+ *
+ * Submits GOAWAY frame with the last stream ID |last_stream_id| and
+ * the error code |error_code|.
+ *
+ * The pre-defined error code is one of :enum:`nghttp2_error_code`.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |last_stream_id| is peer's stream ID or 0.  So if |session| is
+ * initialized as client, |last_stream_id| must be even or 0.  If
+ * |session| is initialized as server, |last_stream_id| must be odd or
+ * 0.
+ *
+ * The HTTP/2 specification says last_stream_id must not be increased
+ * from the value previously sent.  So the actual value sent as
+ * last_stream_id is the minimum value between the given
+ * |last_stream_id| and the last_stream_id previously sent to the
+ * peer.
+ *
+ * If the |opaque_data| is not ``NULL`` and |opaque_data_len| is not
+ * zero, those data will be sent as additional debug data.  The
+ * library makes a copy of the memory region pointed by |opaque_data|
+ * with the length |opaque_data_len|, so the caller does not need to
+ * keep this memory after the return of this function.  If the
+ * |opaque_data_len| is 0, the |opaque_data| could be ``NULL``.
+ *
+ * After successful transmission of GOAWAY, following things happen.
+ * All incoming streams having strictly more than |last_stream_id| are
+ * closed.  All incoming HEADERS which starts new stream are simply
+ * ignored.  After all active streams are handled, both
+ * `nghttp2_session_want_read()` and `nghttp2_session_want_write()`
+ * return 0 and the application can close session.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |opaque_data_len| is too large; the |last_stream_id| is
+ *     invalid.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_goaway(nghttp2_session *session,
+                                         uint8_t flags, int32_t last_stream_id,
+                                         uint32_t error_code,
+                                         const uint8_t *opaque_data,
+                                         size_t opaque_data_len);
+
+/**
+ * @function
+ *
+ * Returns the last stream ID of a stream for which
+ * :type:`nghttp2_on_frame_recv_callback` was invoked most recently.
+ * The returned value can be used as last_stream_id parameter for
+ * `nghttp2_submit_goaway()` and
+ * `nghttp2_session_terminate_session2()`.
+ *
+ * This function always succeeds.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_session_get_last_proc_stream_id(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero if new request can be sent from local endpoint.
+ *
+ * This function return 0 if request is not allowed for this session.
+ * There are several reasons why request is not allowed.  Some of the
+ * reasons are: session is server; stream ID has been spent; GOAWAY
+ * has been sent or received.
+ *
+ * The application can call `nghttp2_submit_request()` without
+ * consulting this function.  In that case, `nghttp2_submit_request()`
+ * may return error.  Or, request is failed to sent, and
+ * :type:`nghttp2_on_stream_close_callback` is called.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_check_request_allowed(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns nonzero if |session| is initialized as server side session.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_check_server_session(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Submits WINDOW_UPDATE frame.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |stream_id| is the stream ID to send this WINDOW_UPDATE.  To
+ * send connection level WINDOW_UPDATE, specify 0 to |stream_id|.
+ *
+ * If the |window_size_increment| is positive, the WINDOW_UPDATE with
+ * that value as window_size_increment is queued.  If the
+ * |window_size_increment| is larger than the received bytes from the
+ * remote endpoint, the local window size is increased by that
+ * difference.  If the sole purpose is to increase the local window
+ * size, consider to use `nghttp2_session_set_local_window_size()`.
+ *
+ * If the |window_size_increment| is negative, the local window size
+ * is decreased by -|window_size_increment|.  If automatic
+ * WINDOW_UPDATE is enabled
+ * (`nghttp2_option_set_no_auto_window_update()`), and the library
+ * decided that the WINDOW_UPDATE should be submitted, then
+ * WINDOW_UPDATE is queued with the current received bytes count.  If
+ * the sole purpose is to decrease the local window size, consider to
+ * use `nghttp2_session_set_local_window_size()`.
+ *
+ * If the |window_size_increment| is 0, the function does nothing and
+ * returns 0.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_FLOW_CONTROL`
+ *     The local window size overflow or gets negative.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_window_update(nghttp2_session *session,
+                                                uint8_t flags,
+                                                int32_t stream_id,
+                                                int32_t window_size_increment);
+
+/**
+ * @function
+ *
+ * Set local window size (local endpoints's window size) to the given
+ * |window_size| for the given stream denoted by |stream_id|.  To
+ * change connection level window size, specify 0 to |stream_id|.  To
+ * increase window size, this function may submit WINDOW_UPDATE frame
+ * to transmission queue.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * This sounds similar to `nghttp2_submit_window_update()`, but there
+ * are 2 differences.  The first difference is that this function
+ * takes the absolute value of window size to set, rather than the
+ * delta.  To change the window size, this may be easier to use since
+ * the application just declares the intended window size, rather than
+ * calculating delta.  The second difference is that
+ * `nghttp2_submit_window_update()` affects the received bytes count
+ * which has not acked yet.  By the specification of
+ * `nghttp2_submit_window_update()`, to strictly increase the local
+ * window size, we have to submit delta including all received bytes
+ * count, which might not be desirable in some cases.  On the other
+ * hand, this function does not affect the received bytes count.  It
+ * just sets the local window size to the given value.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The |stream_id| is negative.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_session_set_local_window_size(nghttp2_session *session, uint8_t flags,
+                                      int32_t stream_id, int32_t window_size);
+
+/**
+ * @function
+ *
+ * Submits extension frame.
+ *
+ * Application can pass arbitrary frame flags and stream ID in |flags|
+ * and |stream_id| respectively.  The |payload| is opaque pointer, and
+ * it can be accessible though ``frame->ext.payload`` in
+ * :type:`nghttp2_pack_extension_callback`.  The library will not own
+ * passed |payload| pointer.
+ *
+ * The application must set :type:`nghttp2_pack_extension_callback`
+ * using `nghttp2_session_callbacks_set_pack_extension_callback()`.
+ *
+ * The application should retain the memory pointed by |payload| until
+ * the transmission of extension frame is done (which is indicated by
+ * :type:`nghttp2_on_frame_send_callback`), or transmission fails
+ * (which is indicated by :type:`nghttp2_on_frame_not_send_callback`).
+ * If application does not touch this memory region after packing it
+ * into a wire format, application can free it inside
+ * :type:`nghttp2_pack_extension_callback`.
+ *
+ * The standard HTTP/2 frame cannot be sent with this function, so
+ * |type| must be strictly grater than 0x9.  Otherwise, this function
+ * will fail with error code :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     If :type:`nghttp2_pack_extension_callback` is not set.
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     If  |type| specifies  standard  HTTP/2 frame  type.  The  frame
+ *     types  in the  rage [0x0,  0x9], both  inclusive, are  standard
+ *     HTTP/2 frame type, and cannot be sent using this function.
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory
+ */
+NGHTTP2_EXTERN int nghttp2_submit_extension(nghttp2_session *session,
+                                            uint8_t type, uint8_t flags,
+                                            int32_t stream_id, void *payload);
+
+/**
+ * @struct
+ *
+ * The payload of ALTSVC frame.  ALTSVC frame is a non-critical
+ * extension to HTTP/2.  If this frame is received, and
+ * `nghttp2_option_set_user_recv_extension_type()` is not set, and
+ * `nghttp2_option_set_builtin_recv_extension_type()` is set for
+ * :enum:`NGHTTP2_ALTSVC`, ``nghttp2_extension.payload`` will point to
+ * this struct.
+ *
+ * It has the following members:
+ */
+typedef struct {
+  /**
+   * The pointer to origin which this alternative service is
+   * associated with.  This is not necessarily NULL-terminated.
+   */
+  uint8_t *origin;
+  /**
+   * The length of the |origin|.
+   */
+  size_t origin_len;
+  /**
+   * The pointer to Alt-Svc field value contained in ALTSVC frame.
+   * This is not necessarily NULL-terminated.
+   */
+  uint8_t *field_value;
+  /**
+   * The length of the |field_value|.
+   */
+  size_t field_value_len;
+} nghttp2_ext_altsvc;
+
+/**
+ * @function
+ *
+ * Submits ALTSVC frame.
+ *
+ * ALTSVC frame is a non-critical extension to HTTP/2, and defined in
+ * is defined in `RFC 7383
+ * <https://tools.ietf.org/html/rfc7838#section-4>`_.
+ *
+ * The |flags| is currently ignored and should be
+ * :enum:`NGHTTP2_FLAG_NONE`.
+ *
+ * The |origin| points to the origin this alternative service is
+ * associated with.  The |origin_len| is the length of the origin.  If
+ * |stream_id| is 0, the origin must be specified.  If |stream_id| is
+ * not zero, the origin must be empty (in other words, |origin_len|
+ * must be 0).
+ *
+ * The ALTSVC frame is only usable from server side.  If this function
+ * is invoked with client side session, this function returns
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The function is called from client side session
+ * :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
+ *     The sum of |origin_len| and |field_value_len| is larger than
+ *     16382; or |origin_len| is 0 while |stream_id| is 0; or
+ *     |origin_len| is not 0 while |stream_id| is not 0.
+ */
+NGHTTP2_EXTERN int nghttp2_submit_altsvc(nghttp2_session *session,
+                                         uint8_t flags, int32_t stream_id,
+                                         const uint8_t *origin,
+                                         size_t origin_len,
+                                         const uint8_t *field_value,
+                                         size_t field_value_len);
+
+/**
+ * @function
+ *
+ * Compares ``lhs->name`` of length ``lhs->namelen`` bytes and
+ * ``rhs->name`` of length ``rhs->namelen`` bytes.  Returns negative
+ * integer if ``lhs->name`` is found to be less than ``rhs->name``; or
+ * returns positive integer if ``lhs->name`` is found to be greater
+ * than ``rhs->name``; or returns 0 otherwise.
+ */
+NGHTTP2_EXTERN int nghttp2_nv_compare_name(const nghttp2_nv *lhs,
+                                           const nghttp2_nv *rhs);
+
+/**
+ * @function
+ *
+ * A helper function for dealing with NPN in client side or ALPN in
+ * server side.  The |in| contains peer's protocol list in preferable
+ * order.  The format of |in| is length-prefixed and not
+ * null-terminated.  For example, ``h2`` and
+ * ``http/1.1`` stored in |in| like this::
+ *
+ *     in[0] = 2
+ *     in[1..2] = "h2"
+ *     in[3] = 8
+ *     in[4..11] = "http/1.1"
+ *     inlen = 12
+ *
+ * The selection algorithm is as follows:
+ *
+ * 1. If peer's list contains HTTP/2 protocol the library supports,
+ *    it is selected and returns 1. The following step is not taken.
+ *
+ * 2. If peer's list contains ``http/1.1``, this function selects
+ *    ``http/1.1`` and returns 0.  The following step is not taken.
+ *
+ * 3. This function selects nothing and returns -1 (So called
+ *    non-overlap case).  In this case, |out| and |outlen| are left
+ *    untouched.
+ *
+ * Selecting ``h2`` means that ``h2`` is written into |*out| and its
+ * length (which is 2) is assigned to |*outlen|.
+ *
+ * For ALPN, refer to https://tools.ietf.org/html/rfc7301
+ *
+ * See http://technotes.googlecode.com/git/nextprotoneg.html for more
+ * details about NPN.
+ *
+ * For NPN, to use this method you should do something like::
+ *
+ *     static int select_next_proto_cb(SSL* ssl,
+ *                                     unsigned char **out,
+ *                                     unsigned char *outlen,
+ *                                     const unsigned char *in,
+ *                                     unsigned int inlen,
+ *                                     void *arg)
+ *     {
+ *         int rv;
+ *         rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
+ *         if (rv == -1) {
+ *             return SSL_TLSEXT_ERR_NOACK;
+ *         }
+ *         if (rv == 1) {
+ *             ((MyType*)arg)->http2_selected = 1;
+ *         }
+ *         return SSL_TLSEXT_ERR_OK;
+ *     }
+ *     ...
+ *     SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, my_obj);
+ *
+ */
+NGHTTP2_EXTERN int nghttp2_select_next_protocol(unsigned char **out,
+                                                unsigned char *outlen,
+                                                const unsigned char *in,
+                                                unsigned int inlen);
+
+/**
+ * @function
+ *
+ * Returns a pointer to a nghttp2_info struct with version information
+ * about the run-time library in use.  The |least_version| argument
+ * can be set to a 24 bit numerical value for the least accepted
+ * version number and if the condition is not met, this function will
+ * return a ``NULL``.  Pass in 0 to skip the version checking.
+ */
+NGHTTP2_EXTERN nghttp2_info *nghttp2_version(int least_version);
+
+/**
+ * @function
+ *
+ * Returns nonzero if the :type:`nghttp2_error` library error code
+ * |lib_error| is fatal.
+ */
+NGHTTP2_EXTERN int nghttp2_is_fatal(int lib_error_code);
+
+/**
+ * @function
+ *
+ * Returns nonzero if HTTP header field name |name| of length |len| is
+ * valid according to http://tools.ietf.org/html/rfc7230#section-3.2
+ *
+ * Because this is a header field name in HTTP2, the upper cased alphabet
+ * is treated as error.
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_name(const uint8_t *name, size_t len);
+
+/**
+ * @function
+ *
+ * Returns nonzero if HTTP header field value |value| of length |len|
+ * is valid according to
+ * http://tools.ietf.org/html/rfc7230#section-3.2
+ */
+NGHTTP2_EXTERN int nghttp2_check_header_value(const uint8_t *value, size_t len);
+
+/* HPACK API */
+
+struct nghttp2_hd_deflater;
+
+/**
+ * @struct
+ *
+ * HPACK deflater object.
+ */
+typedef struct nghttp2_hd_deflater nghttp2_hd_deflater;
+
+/**
+ * @function
+ *
+ * Initializes |*deflater_ptr| for deflating name/values pairs.
+ *
+ * The |deflate_hd_table_bufsize_max| is the upper bound of header
+ * table size the deflater will use.
+ *
+ * If this function fails, |*deflater_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
+                                          size_t deflate_hd_table_bufsize_max);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_hd_deflate_new()`, but with additional custom memory
+ * allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_hd_deflate_new()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
+                                           size_t deflate_hd_table_bufsize_max,
+                                           nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Deallocates any resources allocated for |deflater|.
+ */
+NGHTTP2_EXTERN void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Changes header table size of the |deflater| to
+ * |settings_hd_table_bufsize_max| bytes.  This may trigger eviction
+ * in the dynamic table.
+ *
+ * The |settings_hd_table_bufsize_max| should be the value received in
+ * SETTINGS_HEADER_TABLE_SIZE.
+ *
+ * The deflater never uses more memory than
+ * ``deflate_hd_table_bufsize_max`` bytes specified in
+ * `nghttp2_hd_deflate_new()`.  Therefore, if
+ * |settings_hd_table_bufsize_max| > ``deflate_hd_table_bufsize_max``,
+ * resulting maximum table size becomes
+ * ``deflate_hd_table_bufsize_max``.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
+                                     size_t settings_hd_table_bufsize_max);
+
+/**
+ * @function
+ *
+ * Deflates the |nva|, which has the |nvlen| name/value pairs, into
+ * the |buf| of length |buflen|.
+ *
+ * If |buf| is not large enough to store the deflated header block,
+ * this function fails with :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`.  The
+ * caller should use `nghttp2_hd_deflate_bound()` to know the upper
+ * bound of buffer size required to deflate given header name/value
+ * pairs.
+ *
+ * Once this function fails, subsequent call of this function always
+ * returns :enum:`NGHTTP2_ERR_HEADER_COMP`.
+ *
+ * After this function returns, it is safe to delete the |nva|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Deflation process has failed.
+ * :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
+ *     The provided |buflen| size is too small to hold the output.
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
+                      size_t buflen, const nghttp2_nv *nva, size_t nvlen);
+
+/**
+ * @function
+ *
+ * Returns an upper bound on the compressed size after deflation of
+ * |nva| of length |nvlen|.
+ */
+NGHTTP2_EXTERN size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
+                                               const nghttp2_nv *nva,
+                                               size_t nvlen);
+
+/**
+ * @function
+ *
+ * Returns the number of entries that header table of |deflater|
+ * contains.  This is the sum of the number of static table and
+ * dynamic table, so the return value is at least 61.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Returns the table entry denoted by |idx| from header table of
+ * |deflater|.  The |idx| is 1-based, and idx=1 returns first entry of
+ * static table.  idx=62 returns first entry of dynamic table if it
+ * exists.  Specifying idx=0 is error, and this function returns NULL.
+ * If |idx| is strictly greater than the number of entries the tables
+ * contain, this function returns NULL.
+ */
+NGHTTP2_EXTERN
+const nghttp2_nv *
+nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx);
+
+/**
+ * @function
+ *
+ * Returns the used dynamic table size, including the overhead 32
+ * bytes per entry described in RFC 7541.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater);
+
+/**
+ * @function
+ *
+ * Returns the maximum dynamic table size.
+ */
+NGHTTP2_EXTERN
+size_t
+nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater);
+
+struct nghttp2_hd_inflater;
+
+/**
+ * @struct
+ *
+ * HPACK inflater object.
+ */
+typedef struct nghttp2_hd_inflater nghttp2_hd_inflater;
+
+/**
+ * @function
+ *
+ * Initializes |*inflater_ptr| for inflating name/values pairs.
+ *
+ * If this function fails, |*inflater_ptr| is left untouched.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr);
+
+/**
+ * @function
+ *
+ * Like `nghttp2_hd_inflate_new()`, but with additional custom memory
+ * allocator specified in the |mem|.
+ *
+ * The |mem| can be ``NULL`` and the call is equivalent to
+ * `nghttp2_hd_inflate_new()`.
+ *
+ * This function does not take ownership |mem|.  The application is
+ * responsible for freeing |mem|.
+ *
+ * The library code does not refer to |mem| pointer after this
+ * function returns, so the application can safely free it.
+ */
+NGHTTP2_EXTERN int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
+                                           nghttp2_mem *mem);
+
+/**
+ * @function
+ *
+ * Deallocates any resources allocated for |inflater|.
+ */
+NGHTTP2_EXTERN void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Changes header table size in the |inflater|.  This may trigger
+ * eviction in the dynamic table.
+ *
+ * The |settings_hd_table_bufsize_max| should be the value transmitted
+ * in SETTINGS_HEADER_TABLE_SIZE.
+ *
+ * This function must not be called while header block is being
+ * inflated.  In other words, this function must be called after
+ * initialization of |inflater|, but before calling
+ * `nghttp2_hd_inflate_hd2()`, or after
+ * `nghttp2_hd_inflate_end_headers()`.  Otherwise,
+ * `NGHTTP2_ERR_INVALID_STATE` was returned.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_INVALID_STATE`
+ *     The function is called while header block is being inflated.
+ *     Probably, application missed to call
+ *     `nghttp2_hd_inflate_end_headers()`.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_change_table_size(nghttp2_hd_inflater *inflater,
+                                     size_t settings_hd_table_bufsize_max);
+
+/**
+ * @enum
+ *
+ * The flags for header inflation.
+ */
+typedef enum {
+  /**
+   * No flag set.
+   */
+  NGHTTP2_HD_INFLATE_NONE = 0,
+  /**
+   * Indicates all headers were inflated.
+   */
+  NGHTTP2_HD_INFLATE_FINAL = 0x01,
+  /**
+   * Indicates a header was emitted.
+   */
+  NGHTTP2_HD_INFLATE_EMIT = 0x02
+} nghttp2_hd_inflate_flag;
+
+/**
+ * @function
+ *
+ * .. warning::
+ *
+ *   Deprecated.  Use `nghttp2_hd_inflate_hd2()` instead.
+ *
+ * Inflates name/value block stored in |in| with length |inlen|.  This
+ * function performs decompression.  For each successful emission of
+ * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * |*inflate_flags| and name/value pair is assigned to the |nv_out|
+ * and the function returns.  The caller must not free the members of
+ * |nv_out|.
+ *
+ * The |nv_out| may include pointers to the memory region in the |in|.
+ * The caller must retain the |in| while the |nv_out| is used.
+ *
+ * The application should call this function repeatedly until the
+ * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and
+ * return value is non-negative.  This means the all input values are
+ * processed successfully.  Then the application must call
+ * `nghttp2_hd_inflate_end_headers()` to prepare for the next header
+ * block input.
+ *
+ * The caller can feed complete compressed header block.  It also can
+ * feed it in several chunks.  The caller must set |in_final| to
+ * nonzero if the given input is the last block of the compressed
+ * header.
+ *
+ * This function returns the number of bytes processed if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Inflation process has failed.
+ * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ *     The header field name or value is too large.
+ *
+ * Example follows::
+ *
+ *     int inflate_header_block(nghttp2_hd_inflater *hd_inflater,
+ *                              uint8_t *in, size_t inlen, int final)
+ *     {
+ *         ssize_t rv;
+ *
+ *         for(;;) {
+ *             nghttp2_nv nv;
+ *             int inflate_flags = 0;
+ *
+ *             rv = nghttp2_hd_inflate_hd(hd_inflater, &nv, &inflate_flags,
+ *                                        in, inlen, final);
+ *
+ *             if(rv < 0) {
+ *                 fprintf(stderr, "inflate failed with error code %zd", rv);
+ *                 return -1;
+ *             }
+ *
+ *             in += rv;
+ *             inlen -= rv;
+ *
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
+ *                 fwrite(nv.name, nv.namelen, 1, stderr);
+ *                 fprintf(stderr, ": ");
+ *                 fwrite(nv.value, nv.valuelen, 1, stderr);
+ *                 fprintf(stderr, "\n");
+ *             }
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
+ *                 nghttp2_hd_inflate_end_headers(hd_inflater);
+ *                 break;
+ *             }
+ *             if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
+ *                inlen == 0) {
+ *                break;
+ *             }
+ *         }
+ *
+ *         return 0;
+ *     }
+ *
+ */
+NGHTTP2_EXTERN ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
+                                             nghttp2_nv *nv_out,
+                                             int *inflate_flags, uint8_t *in,
+                                             size_t inlen, int in_final);
+
+/**
+ * @function
+ *
+ * Inflates name/value block stored in |in| with length |inlen|.  This
+ * function performs decompression.  For each successful emission of
+ * header name/value pair, :enum:`NGHTTP2_HD_INFLATE_EMIT` is set in
+ * |*inflate_flags| and name/value pair is assigned to the |nv_out|
+ * and the function returns.  The caller must not free the members of
+ * |nv_out|.
+ *
+ * The |nv_out| may include pointers to the memory region in the |in|.
+ * The caller must retain the |in| while the |nv_out| is used.
+ *
+ * The application should call this function repeatedly until the
+ * ``(*inflate_flags) & NGHTTP2_HD_INFLATE_FINAL`` is nonzero and
+ * return value is non-negative.  This means the all input values are
+ * processed successfully.  Then the application must call
+ * `nghttp2_hd_inflate_end_headers()` to prepare for the next header
+ * block input.
+ *
+ * The caller can feed complete compressed header block.  It also can
+ * feed it in several chunks.  The caller must set |in_final| to
+ * nonzero if the given input is the last block of the compressed
+ * header.
+ *
+ * This function returns the number of bytes processed if it succeeds,
+ * or one of the following negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ * :enum:`NGHTTP2_ERR_HEADER_COMP`
+ *     Inflation process has failed.
+ * :enum:`NGHTTP2_ERR_BUFFER_ERROR`
+ *     The header field name or value is too large.
+ *
+ * Example follows::
+ *
+ *     int inflate_header_block(nghttp2_hd_inflater *hd_inflater,
+ *                              uint8_t *in, size_t inlen, int final)
+ *     {
+ *         ssize_t rv;
+ *
+ *         for(;;) {
+ *             nghttp2_nv nv;
+ *             int inflate_flags = 0;
+ *
+ *             rv = nghttp2_hd_inflate_hd2(hd_inflater, &nv, &inflate_flags,
+ *                                         in, inlen, final);
+ *
+ *             if(rv < 0) {
+ *                 fprintf(stderr, "inflate failed with error code %zd", rv);
+ *                 return -1;
+ *             }
+ *
+ *             in += rv;
+ *             inlen -= rv;
+ *
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
+ *                 fwrite(nv.name, nv.namelen, 1, stderr);
+ *                 fprintf(stderr, ": ");
+ *                 fwrite(nv.value, nv.valuelen, 1, stderr);
+ *                 fprintf(stderr, "\n");
+ *             }
+ *             if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
+ *                 nghttp2_hd_inflate_end_headers(hd_inflater);
+ *                 break;
+ *             }
+ *             if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
+ *                inlen == 0) {
+ *                break;
+ *             }
+ *         }
+ *
+ *         return 0;
+ *     }
+ *
+ */
+NGHTTP2_EXTERN ssize_t
+nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
+                       int *inflate_flags, const uint8_t *in, size_t inlen,
+                       int in_final);
+
+/**
+ * @function
+ *
+ * Signals the end of decompression for one header block.
+ *
+ * This function returns 0 if it succeeds. Currently this function
+ * always succeeds.
+ */
+NGHTTP2_EXTERN int
+nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the number of entries that header table of |inflater|
+ * contains.  This is the sum of the number of static table and
+ * dynamic table, so the return value is at least 61.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the table entry denoted by |idx| from header table of
+ * |inflater|.  The |idx| is 1-based, and idx=1 returns first entry of
+ * static table.  idx=62 returns first entry of dynamic table if it
+ * exists.  Specifying idx=0 is error, and this function returns NULL.
+ * If |idx| is strictly greater than the number of entries the tables
+ * contain, this function returns NULL.
+ */
+NGHTTP2_EXTERN
+const nghttp2_nv *
+nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx);
+
+/**
+ * @function
+ *
+ * Returns the used dynamic table size, including the overhead 32
+ * bytes per entry described in RFC 7541.
+ */
+NGHTTP2_EXTERN
+size_t nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater);
+
+/**
+ * @function
+ *
+ * Returns the maximum dynamic table size.
+ */
+NGHTTP2_EXTERN
+size_t
+nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater);
+
+struct nghttp2_stream;
+
+/**
+ * @struct
+ *
+ * The structure to represent HTTP/2 stream.  The details of this
+ * structure are intentionally hidden from the public API.
+ */
+typedef struct nghttp2_stream nghttp2_stream;
+
+/**
+ * @function
+ *
+ * Returns pointer to :type:`nghttp2_stream` object denoted by
+ * |stream_id|.  If stream was not found, returns NULL.
+ *
+ * Returns imaginary root stream (see
+ * `nghttp2_session_get_root_stream()`) if 0 is given in |stream_id|.
+ *
+ * Unless |stream_id| == 0, the returned pointer is valid until next
+ * call of `nghttp2_session_send()`, `nghttp2_session_mem_send()`,
+ * `nghttp2_session_recv()`, and `nghttp2_session_mem_recv()`.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_session_find_stream(nghttp2_session *session, int32_t stream_id);
+
+/**
+ * @enum
+ *
+ * State of stream as described in RFC 7540.
+ */
+typedef enum {
+  /**
+   * idle state.
+   */
+  NGHTTP2_STREAM_STATE_IDLE = 1,
+  /**
+   * open state.
+   */
+  NGHTTP2_STREAM_STATE_OPEN,
+  /**
+   * reserved (local) state.
+   */
+  NGHTTP2_STREAM_STATE_RESERVED_LOCAL,
+  /**
+   * reserved (remote) state.
+   */
+  NGHTTP2_STREAM_STATE_RESERVED_REMOTE,
+  /**
+   * half closed (local) state.
+   */
+  NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL,
+  /**
+   * half closed (remote) state.
+   */
+  NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE,
+  /**
+   * closed state.
+   */
+  NGHTTP2_STREAM_STATE_CLOSED
+} nghttp2_stream_proto_state;
+
+/**
+ * @function
+ *
+ * Returns state of |stream|.  The root stream retrieved by
+ * `nghttp2_session_get_root_stream()` will have stream state
+ * :enum:`NGHTTP2_STREAM_STATE_IDLE`.
+ */
+NGHTTP2_EXTERN nghttp2_stream_proto_state
+nghttp2_stream_get_state(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns root of dependency tree, which is imaginary stream with
+ * stream ID 0.  The returned pointer is valid until |session| is
+ * freed by `nghttp2_session_del()`.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_session_get_root_stream(nghttp2_session *session);
+
+/**
+ * @function
+ *
+ * Returns the parent stream of |stream| in dependency tree.  Returns
+ * NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_parent(nghttp2_stream *stream);
+
+NGHTTP2_EXTERN int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the next sibling stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_next_sibling(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the previous sibling stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_previous_sibling(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the first child stream of |stream| in dependency tree.
+ * Returns NULL if there is no such stream.
+ */
+NGHTTP2_EXTERN nghttp2_stream *
+nghttp2_stream_get_first_child(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns dependency weight to the parent stream of |stream|.
+ */
+NGHTTP2_EXTERN int32_t nghttp2_stream_get_weight(nghttp2_stream *stream);
+
+/**
+ * @function
+ *
+ * Returns the sum of the weight for |stream|'s children.
+ */
+NGHTTP2_EXTERN int32_t
+nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NGHTTP2_H */

+ 42 - 0
components/nghttp/include/nghttp2/nghttp2ver.h

@@ -0,0 +1,42 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2VER_H
+#define NGHTTP2VER_H
+
+/**
+ * @macro
+ * Version number of the nghttp2 library release
+ */
+#define NGHTTP2_VERSION "@PACKAGE_VERSION@"
+
+/**
+ * @macro
+ * Numerical representation of the version number of the nghttp2 library
+ * release. This is a 24 bit number with 8 bits for major number, 8 bits
+ * for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
+ */
+#define NGHTTP2_VERSION_NUM 0x010203
+
+#endif /* NGHTTP2VER_H */

+ 388 - 0
components/nghttp/include/nghttp2_buf.h

@@ -0,0 +1,388 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_BUF_H
+#define NGHTTP2_BUF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+typedef struct {
+  /* This points to the beginning of the buffer. The effective range
+     of buffer is [begin, end). */
+  uint8_t *begin;
+  /* This points to the memory one byte beyond the end of the
+     buffer. */
+  uint8_t *end;
+  /* The position indicator for effective start of the buffer. pos <=
+     last must be hold. */
+  uint8_t *pos;
+  /* The position indicator for effective one beyond of the end of the
+     buffer. last <= end must be hold. */
+  uint8_t *last;
+  /* Mark arbitrary position in buffer [begin, end) */
+  uint8_t *mark;
+} nghttp2_buf;
+
+#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos))
+#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last))
+#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last))
+#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin))
+
+#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin))
+#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin))
+
+#define nghttp2_buf_shift_right(BUF, AMT)                                      \
+  do {                                                                         \
+    (BUF)->pos += AMT;                                                         \
+    (BUF)->last += AMT;                                                        \
+  } while (0)
+
+#define nghttp2_buf_shift_left(BUF, AMT)                                       \
+  do {                                                                         \
+    (BUF)->pos -= AMT;                                                         \
+    (BUF)->last -= AMT;                                                        \
+  } while (0)
+
+/*
+ * Initializes the |buf|. No memory is allocated in this function. Use
+ * nghttp2_buf_reserve() to allocate memory.
+ */
+void nghttp2_buf_init(nghttp2_buf *buf);
+
+/*
+ * Initializes the |buf| and allocates at least |initial| bytes of
+ * memory.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);
+
+/*
+ * Frees buffer in |buf|.
+ */
+void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
+
+/*
+ * Extends buffer so that nghttp2_buf_cap() returns at least
+ * |new_cap|. If extensions took place, buffer pointers in |buf| will
+ * change.
+ *
+ * This function returns 0 if it succeeds, or one of the followings
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);
+
+/*
+ * Resets pos, last, mark member of |buf| to buf->begin.
+ */
+void nghttp2_buf_reset(nghttp2_buf *buf);
+
+/*
+ * Initializes |buf| using supplied buffer |begin| of length
+ * |len|. Semantically, the application should not call *_reserve() or
+ * nghttp2_free() functions for |buf|.
+ */
+void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
+
+struct nghttp2_buf_chain;
+
+typedef struct nghttp2_buf_chain nghttp2_buf_chain;
+
+/* Chains 2 buffers */
+struct nghttp2_buf_chain {
+  /* Points to the subsequent buffer. NULL if there is no such
+     buffer. */
+  nghttp2_buf_chain *next;
+  nghttp2_buf buf;
+};
+
+typedef struct {
+  /* Points to the first buffer */
+  nghttp2_buf_chain *head;
+  /* Buffer pointer where write occurs. */
+  nghttp2_buf_chain *cur;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* The buffer capacity of each buf */
+  size_t chunk_length;
+  /* The maximum number of nghttp2_buf_chain */
+  size_t max_chunk;
+  /* The number of nghttp2_buf_chain allocated */
+  size_t chunk_used;
+  /* The number of nghttp2_buf_chain to keep on reset */
+  size_t chunk_keep;
+  /* pos offset from begin in each buffers. On initialization and
+     reset, buf->pos and buf->last are positioned at buf->begin +
+     offset. */
+  size_t offset;
+} nghttp2_bufs;
+
+/*
+ * This is the same as calling nghttp2_bufs_init2 with the given
+ * arguments and offset = 0.
+ */
+int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
+                      nghttp2_mem *mem);
+
+/*
+ * This is the same as calling nghttp2_bufs_init3 with the given
+ * arguments and chunk_keep = max_chunk.
+ */
+int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t offset, nghttp2_mem *mem);
+
+/*
+ * Initializes |bufs|. Each buffer size is given in the
+ * |chunk_length|.  The maximum number of buffers is given in the
+ * |max_chunk|.  On reset, first |chunk_keep| buffers are kept and
+ * remaining buffers are deleted.  Each buffer will have bufs->pos and
+ * bufs->last shifted to left by |offset| bytes on creation and reset.
+ *
+ * This function allocates first buffer.  bufs->head and bufs->cur
+ * will point to the first buffer after this call.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     chunk_keep is 0; or max_chunk < chunk_keep; or offset is too
+ *     long.
+ */
+int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t chunk_keep, size_t offset,
+                       nghttp2_mem *mem);
+
+/*
+ * Frees any related resources to the |bufs|.
+ */
+void nghttp2_bufs_free(nghttp2_bufs *bufs);
+
+/*
+ * Initializes |bufs| using supplied buffer |begin| of length |len|.
+ * The first buffer bufs->head uses buffer |begin|.  The buffer size
+ * is fixed and no allocate extra chunk buffer is allocated.  In other
+ * words, max_chunk = chunk_keep = 1.  To free the resource allocated
+ * for |bufs|, use nghttp2_bufs_wrap_free().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
+                           nghttp2_mem *mem);
+
+/*
+ * Frees any related resource to the |bufs|.  This function does not
+ * free supplied buffer provided in nghttp2_bufs_wrap_init().
+ */
+void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
+
+/*
+ * Reallocates internal buffer using |chunk_length|.  The max_chunk,
+ * chunk_keep and offset do not change.  After successful allocation
+ * of new buffer, previous buffers are deallocated without copying
+ * anything into new buffers.  chunk_used is reset to 1.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     chunk_length < offset
+ */
+int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
+
+/*
+ * Appends the |data| of length |len| to the |bufs|. The write starts
+ * at bufs->cur->buf.last. A new buffers will be allocated to store
+ * all data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);
+
+/*
+ * Appends a single byte |b| to the |bufs|. The write starts at
+ * bufs->cur->buf.last. A new buffers will be allocated to store all
+ * data.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
+
+/*
+ * Behaves like nghttp2_bufs_addb(), but this does not update
+ * buf->last pointer.
+ */
+int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
+
+#define nghttp2_bufs_fast_addb(BUFS, B)                                        \
+  do {                                                                         \
+    *(BUFS)->cur->buf.last++ = B;                                              \
+  } while (0)
+
+#define nghttp2_bufs_fast_addb_hold(BUFS, B)                                   \
+  do {                                                                         \
+    *(BUFS)->cur->buf.last = B;                                                \
+  } while (0)
+
+/*
+ * Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
+ * will be allocated if necessary.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
+
+/*
+ * Behaves like nghttp2_bufs_orb(), but does not update buf->last
+ * pointer.
+ */
+int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
+
+#define nghttp2_bufs_fast_orb(BUFS, B)                                         \
+  do {                                                                         \
+    uint8_t **p = &(BUFS)->cur->buf.last;                                      \
+    **p = (uint8_t)(**p | (B));                                                \
+    ++(*p);                                                                    \
+  } while (0)
+
+#define nghttp2_bufs_fast_orb_hold(BUFS, B)                                    \
+  do {                                                                         \
+    uint8_t *p = (BUFS)->cur->buf.last;                                        \
+    *p = (uint8_t)(*p | (B));                                                  \
+  } while (0)
+
+/*
+ * Copies all data stored in |bufs| to the contiguous buffer.  This
+ * function allocates the contiguous memory to store all data in
+ * |bufs| and assigns it to |*out|.
+ *
+ * The contents of |bufs| is left unchanged.
+ *
+ * This function returns the length of copied data and assigns the
+ * pointer to copied data to |*out| if it succeeds, or one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
+
+/*
+ * Copies all data stored in |bufs| to |out|.  This function assumes
+ * that the buffer space pointed by |out| has at least
+ * nghttp2_bufs(bufs) bytes.
+ *
+ * The contents of |bufs| is left unchanged.
+ *
+ * This function returns the length of copied data.
+ */
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
+
+/*
+ * Resets |bufs| and makes the buffers empty.
+ */
+void nghttp2_bufs_reset(nghttp2_bufs *bufs);
+
+/*
+ * Moves bufs->cur to bufs->cur->next.  If resulting bufs->cur is
+ * NULL, this function allocates new buffers and bufs->cur points to
+ * it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_bufs_advance(nghttp2_bufs *bufs);
+
+/* Sets bufs->cur to bufs->head */
+#define nghttp2_bufs_rewind(BUFS)                                              \
+  do {                                                                         \
+    (BUFS)->cur = (BUFS)->head;                                                \
+  } while (0)
+
+/*
+ * Move bufs->cur, from the current position, using next member, to
+ * the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf
+ * which satisfies nghttp2_buf_len(buf) == 0.  If
+ * nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL,
+ * bufs->cur is unchanged.
+ */
+void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
+
+/*
+ * Returns nonzero if bufs->cur->next is not emtpy.
+ */
+int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
+
+#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
+
+/*
+ * Returns the buffer length of |bufs|.
+ */
+size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
+
+#endif /* NGHTTP2_BUF_H */

+ 117 - 0
components/nghttp/include/nghttp2_callbacks.h

@@ -0,0 +1,117 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_CALLBACKS_H
+#define NGHTTP2_CALLBACKS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * Callback functions.
+ */
+struct nghttp2_session_callbacks {
+  /**
+   * Callback function invoked when the session wants to send data to
+   * the remote peer.  This callback is not necessary if the
+   * application uses solely `nghttp2_session_mem_send()` to serialize
+   * data to transmit.
+   */
+  nghttp2_send_callback send_callback;
+  /**
+   * Callback function invoked when the session wants to receive data
+   * from the remote peer.  This callback is not necessary if the
+   * application uses solely `nghttp2_session_mem_recv()` to process
+   * received data.
+   */
+  nghttp2_recv_callback recv_callback;
+  /**
+   * Callback function invoked by `nghttp2_session_recv()` when a
+   * frame is received.
+   */
+  nghttp2_on_frame_recv_callback on_frame_recv_callback;
+  /**
+   * Callback function invoked by `nghttp2_session_recv()` when an
+   * invalid non-DATA frame is received.
+   */
+  nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
+  /**
+   * Callback function invoked when a chunk of data in DATA frame is
+   * received.
+   */
+  nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
+  /**
+   * Callback function invoked before a non-DATA frame is sent.
+   */
+  nghttp2_before_frame_send_callback before_frame_send_callback;
+  /**
+   * Callback function invoked after a frame is sent.
+   */
+  nghttp2_on_frame_send_callback on_frame_send_callback;
+  /**
+   * The callback function invoked when a non-DATA frame is not sent
+   * because of an error.
+   */
+  nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
+  /**
+   * Callback function invoked when the stream is closed.
+   */
+  nghttp2_on_stream_close_callback on_stream_close_callback;
+  /**
+   * Callback function invoked when the reception of header block in
+   * HEADERS or PUSH_PROMISE is started.
+   */
+  nghttp2_on_begin_headers_callback on_begin_headers_callback;
+  /**
+   * Callback function invoked when a header name/value pair is
+   * received.
+   */
+  nghttp2_on_header_callback on_header_callback;
+  nghttp2_on_header_callback2 on_header_callback2;
+  /**
+   * Callback function invoked when the library asks application how
+   * many padding bytes are required for the transmission of the given
+   * frame.
+   */
+  nghttp2_select_padding_callback select_padding_callback;
+  /**
+   * The callback function used to determine the length allowed in
+   * `nghttp2_data_source_read_callback()`
+   */
+  nghttp2_data_source_read_length_callback read_length_callback;
+  /**
+   * Sets callback function invoked when a frame header is received.
+   */
+  nghttp2_on_begin_frame_callback on_begin_frame_callback;
+  nghttp2_send_data_callback send_data_callback;
+  nghttp2_pack_extension_callback pack_extension_callback;
+  nghttp2_unpack_extension_callback unpack_extension_callback;
+  nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
+  nghttp2_error_callback error_callback;
+};
+
+#endif /* NGHTTP2_CALLBACKS_H */

+ 581 - 0
components/nghttp/include/nghttp2_frame.h

@@ -0,0 +1,581 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_FRAME_H
+#define NGHTTP2_FRAME_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_hd.h"
+#include "nghttp2_buf.h"
+
+#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
+#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
+#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
+#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
+#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
+
+/* The number of bytes of frame header. */
+#define NGHTTP2_FRAME_HDLEN 9
+
+#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
+#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
+
+#define NGHTTP2_MAX_PAYLOADLEN 8192//16384--LiuHan/0812
+/* The one frame buffer length for tranmission.  We may use several of
+   them to support CONTINUATION.  To account for Pad Length field, we
+   allocate extra 1 byte, which saves extra large memcopying. */
+#define NGHTTP2_FRAMEBUF_CHUNKLEN                                              \
+  (NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
+
+/* The default length of DATA frame payload. */
+#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
+
+/* Maximum headers block size to send, calculated using
+   nghttp2_hd_deflate_bound().  This is the default value, and can be
+   overridden by nghttp2_option_set_max_send_header_block_size(). */
+#define NGHTTP2_MAX_HEADERSLEN 65536
+
+/* The number of bytes for each SETTINGS entry */
+#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6
+
+/* Length of priority related fields in HEADERS/PRIORITY frames */
+#define NGHTTP2_PRIORITY_SPECLEN 5
+
+/* Maximum length of padding in bytes. */
+#define NGHTTP2_MAX_PADLEN 256
+
+/* Union of extension frame payload */
+typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
+
+void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
+
+void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
+
+/**
+ * Initializes frame header |hd| with given parameters.  Reserved bit
+ * is set to 0.
+ */
+void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
+                           uint8_t flags, int32_t stream_id);
+
+/**
+ * Returns the number of priority field depending on the |flags|.  If
+ * |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
+ * NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
+ */
+size_t nghttp2_frame_priority_len(uint8_t flags);
+
+/**
+ * Packs the |pri_spec| in |buf|.  This function assumes |buf| has
+ * enough space for serialization.
+ */
+void nghttp2_frame_pack_priority_spec(uint8_t *buf,
+                                      const nghttp2_priority_spec *pri_spec);
+
+/**
+ * Unpacks the priority specification from payload |payload| of length
+ * |payloadlen| to |pri_spec|.  The |flags| is used to determine what
+ * kind of priority specification is in |payload|.  This function
+ * assumes the |payload| contains whole priority specification.
+ */
+void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
+                                        uint8_t flags, const uint8_t *payload,
+                                        size_t payloadlen);
+
+/*
+ * Returns the offset from the HEADERS frame payload where the
+ * compressed header block starts. The frame payload does not include
+ * frame header.
+ */
+size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
+
+/*
+ * Packs HEADERS frame |frame| in wire format and store it in |bufs|.
+ * This function expands |bufs| as necessary to store frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * frame->hd.length is assigned after length is determined during
+ * packing process.  CONTINUATION frames are also serialized in this
+ * function. This function does not handle padding.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_HEADER_COMP
+ *     The deflate operation failed.
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
+                               nghttp2_hd_deflater *deflater);
+
+/*
+ * Unpacks HEADERS frame byte sequence into |frame|.  This function
+ * only unapcks bytes that come before name/value header block and
+ * after possible Pad Length field.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen);
+
+/*
+ * Packs PRIORITY frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
+
+/*
+ * Unpacks PRIORITY wire format into |frame|.
+ */
+void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
+                                           const uint8_t *payload,
+                                           size_t payloadlen);
+
+/*
+ * Packs RST_STREAM frame |frame| in wire frame format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
+                                  nghttp2_rst_stream *frame);
+
+/*
+ * Unpacks RST_STREAM frame byte sequence into |frame|.
+ */
+void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
+                                             const uint8_t *payload,
+                                             size_t payloadlen);
+
+/*
+ * Packs SETTINGS frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the frame is too large.
+ */
+int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
+
+/*
+ * Packs the |iv|, which includes |niv| entries, in the |buf|,
+ * assuming the |buf| has at least 8 * |niv| bytes.
+ *
+ * Returns the number of bytes written into the |buf|.
+ */
+size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
+                                           const nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
+                                         const uint8_t *payload);
+
+/*
+ * Initializes payload of frame->settings.  The |frame| takes
+ * ownership of |iv|.
+ */
+void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
+                                           nghttp2_settings_entry *iv,
+                                           size_t niv);
+
+/*
+ * Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
+ * assigned to the |*niv_ptr|. This function allocates enough memory
+ * to store the result in |*iv_ptr|. The caller is responsible to free
+ * |*iv_ptr| after its use.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
+                                           size_t *niv_ptr,
+                                           const uint8_t *payload,
+                                           size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs PUSH_PROMISE frame |frame| in wire format and store it in
+ * |bufs|.  This function expands |bufs| as necessary to store
+ * frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * frame->hd.length is assigned after length is determined during
+ * packing process.  CONTINUATION frames are also serialized in this
+ * function. This function does not handle padding.
+ *
+ * This function returns 0 if it succeeds, or returns one of the
+ * following negative error codes:
+ *
+ * NGHTTP2_ERR_HEADER_COMP
+ *     The deflate operation failed.
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
+                                    nghttp2_push_promise *frame,
+                                    nghttp2_hd_deflater *deflater);
+
+/*
+ * Unpacks PUSH_PROMISE frame byte sequence into |frame|.  This
+ * function only unapcks bytes that come before name/value header
+ * block and after possible Pad Length field.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_PROTO
+ *     TODO END_HEADERS flag is not set
+ */
+int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
+                                              const uint8_t *payload,
+                                              size_t payloadlen);
+
+/*
+ * Packs PING frame |frame| in wire format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
+
+/*
+ * Unpacks PING wire format into |frame|.
+ */
+void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
+                                       const uint8_t *payload,
+                                       size_t payloadlen);
+
+/*
+ * Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
+ * This function expands |bufs| as necessary to store frame.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the frame is too large.
+ */
+int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
+
+/*
+ * Unpacks GOAWAY wire format into |frame|.  The |payload| of length
+ * |payloadlen| contains first 8 bytes of payload.  The
+ * |var_gift_payload| of length |var_gift_payloadlen| contains
+ * remaining payload and its buffer is gifted to the function and then
+ * |frame|.  The |var_gift_payloadlen| must be freed by
+ * nghttp2_frame_goaway_free().
+ */
+void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen,
+                                         uint8_t *var_gift_payload,
+                                         size_t var_gift_payloadlen);
+
+/*
+ * Unpacks GOAWAY wire format into |frame|.  This function only exists
+ * for unit test.  After allocating buffer for debug data, this
+ * function internally calls nghttp2_frame_unpack_goaway_payload().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
+ * in |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
+                                     nghttp2_window_update *frame);
+
+/*
+ * Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
+ */
+void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
+                                                const uint8_t *payload,
+                                                size_t payloadlen);
+
+/*
+ * Packs ALTSVC frame |frame| in wire frame format and store it in
+ * |bufs|.
+ *
+ * The caller must make sure that nghttp2_bufs_reset(bufs) is called
+ * before calling this function.
+ *
+ * This function always succeeds and returns 0.
+ */
+int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
+
+/*
+ * Unpacks ALTSVC wire format into |frame|.  The |payload| of
+ * |payloadlen| bytes contains frame payload.  This function assumes
+ * that frame->payload points to the nghttp2_ext_altsvc object.
+ *
+ * This function always succeeds and returns 0.
+ */
+void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
+                                         size_t origin_len, uint8_t *payload,
+                                         size_t payloadlen);
+
+/*
+ * Unpacks ALTSVC wire format into |frame|.  This function only exists
+ * for unit test.  After allocating buffer for fields, this function
+ * internally calls nghttp2_frame_unpack_altsvc_payload().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The payload is too small.
+ */
+int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
+                                         const uint8_t *payload,
+                                         size_t payloadlen, nghttp2_mem *mem);
+
+/*
+ * Initializes HEADERS frame |frame| with given values.  |frame| takes
+ * ownership of |nva|, so caller must not free it. If |stream_id| is
+ * not assigned yet, it must be -1.
+ */
+void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
+                                int32_t stream_id, nghttp2_headers_category cat,
+                                const nghttp2_priority_spec *pri_spec,
+                                nghttp2_nv *nva, size_t nvlen);
+
+void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
+
+void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
+                                 const nghttp2_priority_spec *pri_spec);
+
+void nghttp2_frame_priority_free(nghttp2_priority *frame);
+
+void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
+                                   uint32_t error_code);
+
+void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
+
+/*
+ * Initializes PUSH_PROMISE frame |frame| with given values.  |frame|
+ * takes ownership of |nva|, so caller must not free it.
+ */
+void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
+                                     int32_t stream_id,
+                                     int32_t promised_stream_id,
+                                     nghttp2_nv *nva, size_t nvlen);
+
+void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
+                                     nghttp2_mem *mem);
+
+/*
+ * Initializes SETTINGS frame |frame| with given values. |frame| takes
+ * ownership of |iv|, so caller must not free it. The |flags| are
+ * bitwise-OR of one or more of nghttp2_settings_flag.
+ */
+void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
+                                 nghttp2_settings_entry *iv, size_t niv);
+
+void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
+
+/*
+ * Initializes PING frame |frame| with given values. If the
+ * |opqeue_data| is not NULL, it must point to 8 bytes memory region
+ * of data. The data pointed by |opaque_data| is copied. It can be
+ * NULL. In this case, 8 bytes NULL is used.
+ */
+void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
+                             const uint8_t *opque_data);
+
+void nghttp2_frame_ping_free(nghttp2_ping *frame);
+
+/*
+ * Initializes GOAWAY frame |frame| with given values. On success,
+ * this function takes ownership of |opaque_data|, so caller must not
+ * free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
+ */
+void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
+                               uint32_t error_code, uint8_t *opaque_data,
+                               size_t opaque_data_len);
+
+void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
+
+void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
+                                      uint8_t flags, int32_t stream_id,
+                                      int32_t window_size_increment);
+
+void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
+
+void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
+                                  uint8_t flags, int32_t stream_id,
+                                  void *payload);
+
+void nghttp2_frame_extension_free(nghttp2_extension *frame);
+
+/*
+ * Initializes ALTSVC frame |frame| with given values.  This function
+ * assumes that frame->payload points to nghttp2_ext_altsvc object.
+ * Also |origin| and |field_value| are allocated in single buffer,
+ * starting |origin|.  On success, this function takes ownership of
+ * |origin|, so caller must not free it.
+ */
+void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
+                               uint8_t *origin, size_t origin_len,
+                               uint8_t *field_value, size_t field_value_len);
+
+/*
+ * Frees up resources under |frame|.  This function does not free
+ * nghttp2_ext_altsvc object pointed by frame->payload.  This function
+ * only frees origin pointed by nghttp2_ext_altsvc.origin.  Therefore,
+ * other fields must be allocated in the same buffer with origin.
+ */
+void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
+
+/*
+ * Returns the number of padding bytes after payload.  The total
+ * padding length is given in the |padlen|.  The returned value does
+ * not include the Pad Length field.  If |padlen| is 0, this function
+ * returns 0, regardless of frame->hd.flags.
+ */
+size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
+
+void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
+                             int32_t stream_id);
+
+void nghttp2_frame_data_free(nghttp2_data *frame);
+
+/*
+ * Makes copy of |iv| and return the copy. The |niv| is the number of
+ * entries in |iv|. This function returns the pointer to the copy if
+ * it succeeds, or NULL.
+ */
+nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
+                                              size_t niv, nghttp2_mem *mem);
+
+/*
+ * Sorts the |nva| in ascending order of name and value. If names are
+ * equivalent, sort them by value.
+ */
+void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
+
+/*
+ * Copies name/value pairs from |nva|, which contains |nvlen| pairs,
+ * to |*nva_ptr|, which is dynamically allocated so that all items can
+ * be stored.  The resultant name and value in nghttp2_nv are
+ * guaranteed to be NULL-terminated even if the input is not
+ * null-terminated.
+ *
+ * The |*nva_ptr| must be freed using nghttp2_nv_array_del().
+ *
+ * This function returns 0 if it succeeds or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
+                          size_t nvlen, nghttp2_mem *mem);
+
+/*
+ * Returns nonzero if the name/value pair |a| equals to |b|. The name
+ * is compared in case-sensitive, because we ensure that this function
+ * is called after the name is lower-cased.
+ */
+int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
+
+/*
+ * Frees |nva|.
+ */
+void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
+
+/*
+ * Checks that the |iv|, which includes |niv| entries, does not have
+ * invalid values.
+ *
+ * This function returns nonzero if it succeeds, or 0.
+ */
+int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
+
+/*
+ * Sets Pad Length field and flags and adjusts frame header position
+ * of each buffers in |bufs|.  The number of padding is given in the
+ * |padlen| including Pad Length field.  The |hd| is the frame header
+ * for the serialized data.  This function fills zeros padding region
+ * unless framehd_only is nonzero.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FRAME_SIZE_ERROR
+ *     The length of the resulting frame is too large.
+ */
+int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
+                          size_t padlen, int framehd_only);
+
+#endif /* NGHTTP2_FRAME_H */

+ 430 - 0
components/nghttp/include/nghttp2_hd.h

@@ -0,0 +1,430 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_HD_H
+#define NGHTTP2_HD_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#include "nghttp2_hd_huffman.h"
+#include "nghttp2_buf.h"
+#include "nghttp2_mem.h"
+#include "nghttp2_rcbuf.h"
+
+#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
+#define NGHTTP2_HD_ENTRY_OVERHEAD 32
+
+/* The maximum length of one name/value pair.  This is the sum of the
+   length of name and value.  This is not specified by the spec. We
+   just chose the arbitrary size */
+#define NGHTTP2_HD_MAX_NV 65536
+
+/* Default size of maximum table buffer size for encoder. Even if
+   remote decoder notifies larger buffer size for its decoding,
+   encoder only uses the memory up to this value. */
+#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
+
+/* Exported for unit test */
+#define NGHTTP2_STATIC_TABLE_LENGTH 61
+
+/* Generated by genlibtokenlookup.py */
+typedef enum {
+  NGHTTP2_TOKEN__AUTHORITY = 0,
+  NGHTTP2_TOKEN__METHOD = 1,
+  NGHTTP2_TOKEN__PATH = 3,
+  NGHTTP2_TOKEN__SCHEME = 5,
+  NGHTTP2_TOKEN__STATUS = 7,
+  NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
+  NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
+  NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
+  NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
+  NGHTTP2_TOKEN_ACCEPT = 18,
+  NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
+  NGHTTP2_TOKEN_AGE = 20,
+  NGHTTP2_TOKEN_ALLOW = 21,
+  NGHTTP2_TOKEN_AUTHORIZATION = 22,
+  NGHTTP2_TOKEN_CACHE_CONTROL = 23,
+  NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
+  NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
+  NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
+  NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
+  NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
+  NGHTTP2_TOKEN_CONTENT_RANGE = 29,
+  NGHTTP2_TOKEN_CONTENT_TYPE = 30,
+  NGHTTP2_TOKEN_COOKIE = 31,
+  NGHTTP2_TOKEN_DATE = 32,
+  NGHTTP2_TOKEN_ETAG = 33,
+  NGHTTP2_TOKEN_EXPECT = 34,
+  NGHTTP2_TOKEN_EXPIRES = 35,
+  NGHTTP2_TOKEN_FROM = 36,
+  NGHTTP2_TOKEN_HOST = 37,
+  NGHTTP2_TOKEN_IF_MATCH = 38,
+  NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
+  NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
+  NGHTTP2_TOKEN_IF_RANGE = 41,
+  NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
+  NGHTTP2_TOKEN_LAST_MODIFIED = 43,
+  NGHTTP2_TOKEN_LINK = 44,
+  NGHTTP2_TOKEN_LOCATION = 45,
+  NGHTTP2_TOKEN_MAX_FORWARDS = 46,
+  NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
+  NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
+  NGHTTP2_TOKEN_RANGE = 49,
+  NGHTTP2_TOKEN_REFERER = 50,
+  NGHTTP2_TOKEN_REFRESH = 51,
+  NGHTTP2_TOKEN_RETRY_AFTER = 52,
+  NGHTTP2_TOKEN_SERVER = 53,
+  NGHTTP2_TOKEN_SET_COOKIE = 54,
+  NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
+  NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
+  NGHTTP2_TOKEN_USER_AGENT = 57,
+  NGHTTP2_TOKEN_VARY = 58,
+  NGHTTP2_TOKEN_VIA = 59,
+  NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
+  NGHTTP2_TOKEN_TE,
+  NGHTTP2_TOKEN_CONNECTION,
+  NGHTTP2_TOKEN_KEEP_ALIVE,
+  NGHTTP2_TOKEN_PROXY_CONNECTION,
+  NGHTTP2_TOKEN_UPGRADE,
+} nghttp2_token;
+
+struct nghttp2_hd_entry;
+typedef struct nghttp2_hd_entry nghttp2_hd_entry;
+
+typedef struct {
+  /* The buffer containing header field name.  NULL-termination is
+     guaranteed. */
+  nghttp2_rcbuf *name;
+  /* The buffer containing header field value.  NULL-termination is
+     guaranteed. */
+  nghttp2_rcbuf *value;
+  /* nghttp2_token value for name.  It could be -1 if we have no token
+     for that header field name. */
+  int32_t token;
+  /* Bitwise OR of one or more of nghttp2_nv_flag. */
+  uint8_t flags;
+} nghttp2_hd_nv;
+
+struct nghttp2_hd_entry {
+  /* The header field name/value pair */
+  nghttp2_hd_nv nv;
+  /* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
+     APIs to keep backward compatibility. */
+  nghttp2_nv cnv;
+  /* The next entry which shares same bucket in hash table. */
+  nghttp2_hd_entry *next;
+  /* The sequence number.  We will increment it by one whenever we
+     store nghttp2_hd_entry to dynamic header table. */
+  uint32_t seq;
+  /* The hash value for header name (nv.name). */
+  uint32_t hash;
+};
+
+/* The entry used for static header table. */
+typedef struct {
+  nghttp2_rcbuf name;
+  nghttp2_rcbuf value;
+  nghttp2_nv cnv;
+  int32_t token;
+  uint32_t hash;
+} nghttp2_hd_static_entry;
+
+typedef struct {
+  nghttp2_hd_entry **buffer;
+  size_t mask;
+  size_t first;
+  size_t len;
+} nghttp2_hd_ringbuf;
+
+typedef enum {
+  NGHTTP2_HD_OPCODE_NONE,
+  NGHTTP2_HD_OPCODE_INDEXED,
+  NGHTTP2_HD_OPCODE_NEWNAME,
+  NGHTTP2_HD_OPCODE_INDNAME
+} nghttp2_hd_opcode;
+
+typedef enum {
+  NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
+  NGHTTP2_HD_STATE_INFLATE_START,
+  NGHTTP2_HD_STATE_OPCODE,
+  NGHTTP2_HD_STATE_READ_TABLE_SIZE,
+  NGHTTP2_HD_STATE_READ_INDEX,
+  NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
+  NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
+  NGHTTP2_HD_STATE_CHECK_VALUELEN,
+  NGHTTP2_HD_STATE_READ_VALUELEN,
+  NGHTTP2_HD_STATE_READ_VALUEHUFF,
+  NGHTTP2_HD_STATE_READ_VALUE
+} nghttp2_hd_inflate_state;
+
+typedef enum {
+  NGHTTP2_HD_WITH_INDEXING,
+  NGHTTP2_HD_WITHOUT_INDEXING,
+  NGHTTP2_HD_NEVER_INDEXING
+} nghttp2_hd_indexing_mode;
+
+typedef struct {
+  /* dynamic header table */
+  nghttp2_hd_ringbuf hd_table;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* Abstract buffer size of hd_table as described in the spec. This
+     is the sum of length of name/value in hd_table +
+     NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
+  size_t hd_table_bufsize;
+  /* The effective header table size. */
+  size_t hd_table_bufsize_max;
+  /* Next sequence number for nghttp2_hd_entry */
+  uint32_t next_seq;
+  /* If inflate/deflate error occurred, this value is set to 1 and
+     further invocation of inflate/deflate will fail with
+     NGHTTP2_ERR_HEADER_COMP. */
+  uint8_t bad;
+} nghttp2_hd_context;
+
+#define HD_MAP_SIZE 128
+
+typedef struct { nghttp2_hd_entry *table[HD_MAP_SIZE]; } nghttp2_hd_map;
+
+struct nghttp2_hd_deflater {
+  nghttp2_hd_context ctx;
+  nghttp2_hd_map map;
+  /* The upper limit of the header table size the deflater accepts. */
+  size_t deflate_hd_table_bufsize_max;
+  /* Minimum header table size notified in the next context update */
+  size_t min_hd_table_bufsize_max;
+  /* If nonzero, send header table size using encoding context update
+     in the next deflate process */
+  uint8_t notify_table_size_change;
+};
+
+struct nghttp2_hd_inflater {
+  nghttp2_hd_context ctx;
+  /* Stores current state of huffman decoding */
+  nghttp2_hd_huff_decode_context huff_decode_ctx;
+  /* header buffer */
+  nghttp2_buf namebuf, valuebuf;
+  nghttp2_rcbuf *namercbuf, *valuercbuf;
+  /* Pointer to the name/value pair which are used in the current
+     header emission. */
+  nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
+  /* The number of bytes to read */
+  size_t left;
+  /* The index in indexed repr or indexed name */
+  size_t index;
+  /* The maximum header table size the inflater supports. This is the
+     same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
+  size_t settings_hd_table_bufsize_max;
+  /* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
+  size_t min_hd_table_bufsize_max;
+  /* The number of next shift to decode integer */
+  size_t shift;
+  nghttp2_hd_opcode opcode;
+  nghttp2_hd_inflate_state state;
+  /* nonzero if string is huffman encoded */
+  uint8_t huffman_encoded;
+  /* nonzero if deflater requires that current entry is indexed */
+  uint8_t index_required;
+  /* nonzero if deflater requires that current entry must not be
+     indexed */
+  uint8_t no_index;
+};
+
+/*
+ * Initializes the |ent| members.  The reference counts of nv->name
+ * and nv->value are increased by one for each.
+ */
+void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
+
+/*
+ * This function decreases the reference counts of nv->name and
+ * nv->value.
+ */
+void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
+
+/*
+ * Initializes |deflater| for deflating name/values pairs.
+ *
+ * The encoder only uses up to
+ * NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
+ * even if the larger value is specified later in
+ * nghttp2_hd_change_table_size().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
+
+/*
+ * Initializes |deflater| for deflating name/values pairs.
+ *
+ * The encoder only uses up to |deflate_hd_table_bufsize_max| bytes
+ * for header table even if the larger value is specified later in
+ * nghttp2_hd_change_table_size().
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
+                             size_t deflate_hd_table_bufsize_max,
+                             nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |deflater|.
+ */
+void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
+
+/*
+ * Deflates the |nva|, which has the |nvlen| name/value pairs, into
+ * the |bufs|.
+ *
+ * This function expands |bufs| as necessary to store the result. If
+ * buffers is full and the process still requires more space, this
+ * funtion fails and returns NGHTTP2_ERR_HEADER_COMP.
+ *
+ * After this function returns, it is safe to delete the |nva|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_HEADER_COMP
+ *     Deflation process has failed.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
+                               nghttp2_bufs *bufs, const nghttp2_nv *nva,
+                               size_t nvlen);
+
+/*
+ * Initializes |inflater| for inflating name/values pairs.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * :enum:`NGHTTP2_ERR_NOMEM`
+ *     Out of memory.
+ */
+int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |inflater|.
+ */
+void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
+
+/*
+ * Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
+ * instead of nghttp2_nv as output parameter |nv_out|.  Other than
+ * that return values and semantics are the same as
+ * nghttp2_hd_inflate_hd().
+ */
+ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
+                                 nghttp2_hd_nv *nv_out, int *inflate_flags,
+                                 const uint8_t *in, size_t inlen, int in_final);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
+                                  nghttp2_nv *nv, int indexing_mode);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
+                                  int indexing_mode);
+
+/* For unittesting purpose */
+int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
+
+/* For unittesting purpose */
+nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
+
+/* For unittesting purpose */
+ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final,
+                                 uint32_t initial, size_t shift, uint8_t *in,
+                                 uint8_t *last, size_t prefix);
+
+/* Huffman encoding/decoding functions */
+
+/*
+ * Counts the required bytes to encode |src| with length |len|.
+ *
+ * This function returns the number of required bytes to encode given
+ * data, including padding of prefix of terminal symbol code. This
+ * function always succeeds.
+ */
+size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
+
+/*
+ * Encodes the given data |src| with length |srclen| to the |bufs|.
+ * This function expands extra buffers in |bufs| if necessary.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_BUFFER_ERROR
+ *     Out of buffer space.
+ */
+int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
+                           size_t srclen);
+
+void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
+
+/*
+ * Decodes the given data |src| with length |srclen|.  The |ctx| must
+ * be initialized by nghttp2_hd_huff_decode_context_init(). The result
+ * will be written to |buf|.  This function assumes that |buf| has the
+ * enough room to store the decoded byte string.
+ *
+ * The caller must set the |final| to nonzero if the given input is
+ * the final block.
+ *
+ * This function returns the number of read bytes from the |in|.
+ *
+ * If this function fails, it returns one of the following negative
+ * return codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_HEADER_COMP
+ *     Decoding process has failed.
+ */
+ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
+                               nghttp2_buf *buf, const uint8_t *src,
+                               size_t srclen, int final);
+
+#endif /* NGHTTP2_HD_H */

+ 77 - 0
components/nghttp/include/nghttp2_hd_huffman.h

@@ -0,0 +1,77 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2013 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_HD_HUFFMAN_H
+#define NGHTTP2_HD_HUFFMAN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+typedef enum {
+  /* FSA accepts this state as the end of huffman encoding
+     sequence. */
+  NGHTTP2_HUFF_ACCEPTED = 1,
+  /* This state emits symbol */
+  NGHTTP2_HUFF_SYM = (1 << 1),
+  /* If state machine reaches this state, decoding fails. */
+  NGHTTP2_HUFF_FAIL = (1 << 2)
+} nghttp2_huff_decode_flag;
+
+typedef struct {
+  /* huffman decoding state, which is actually the node ID of internal
+     huffman tree.  We have 257 leaf nodes, but they are identical to
+     root node other than emitting a symbol, so we have 256 internal
+     nodes [1..255], inclusive. */
+  uint8_t state;
+  /* bitwise OR of zero or more of the nghttp2_huff_decode_flag */
+  uint8_t flags;
+  /* symbol if NGHTTP2_HUFF_SYM flag set */
+  uint8_t sym;
+} nghttp2_huff_decode;
+
+typedef nghttp2_huff_decode huff_decode_table_type[16];
+
+typedef struct {
+  /* Current huffman decoding state. We stripped leaf nodes, so the
+     value range is [0..255], inclusive. */
+  uint8_t state;
+  /* nonzero if we can say that the decoding process succeeds at this
+     state */
+  uint8_t accept;
+} nghttp2_hd_huff_decode_context;
+
+typedef struct {
+  /* The number of bits in this code */
+  uint32_t nbits;
+  /* Huffman code aligned to LSB */
+  uint32_t code;
+} nghttp2_huff_sym;
+
+extern const nghttp2_huff_sym huff_sym_table[];
+extern const nghttp2_huff_decode huff_decode_table[][16];
+
+#endif /* NGHTTP2_HD_HUFFMAN_H */

+ 122 - 0
components/nghttp/include/nghttp2_helper.h

@@ -0,0 +1,122 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_HELPER_H
+#define NGHTTP2_HELPER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stddef.h>
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_mem.h"
+
+#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
+#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
+
+#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
+
+#define nghttp2_struct_of(ptr, type, member)                                   \
+  ((type *)(void *)((char *)(ptr)-offsetof(type, member)))
+
+/*
+ * Copies 2 byte unsigned integer |n| in host byte order to |buf| in
+ * network byte order.
+ */
+void nghttp2_put_uint16be(uint8_t *buf, uint16_t n);
+
+/*
+ * Copies 4 byte unsigned integer |n| in host byte order to |buf| in
+ * network byte order.
+ */
+void nghttp2_put_uint32be(uint8_t *buf, uint32_t n);
+
+/*
+ * Retrieves 2 byte unsigned integer stored in |data| in network byte
+ * order and returns it in host byte order.
+ */
+uint16_t nghttp2_get_uint16(const uint8_t *data);
+
+/*
+ * Retrieves 4 byte unsigned integer stored in |data| in network byte
+ * order and returns it in host byte order.
+ */
+uint32_t nghttp2_get_uint32(const uint8_t *data);
+
+void nghttp2_downcase(uint8_t *s, size_t len);
+
+/*
+ * Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
+ * |*recv_reduction_ptr| with |*delta_ptr| which is the
+ * WINDOW_UPDATE's window_size_increment sent from local side. If
+ * |delta| is strictly larger than |*recv_window_size_ptr|,
+ * |*local_window_size_ptr| is increased by delta -
+ * *recv_window_size_ptr. If |delta| is negative,
+ * |*local_window_size_ptr| is decreased by delta.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_FLOW_CONTROL
+ *     local_window_size overflow or gets negative.
+ */
+int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
+                                     int32_t *recv_window_size_ptr,
+                                     int32_t *recv_reduction_ptr,
+                                     int32_t *delta_ptr);
+
+/*
+ * This function works like nghttp2_adjust_local_window_size().  The
+ * difference is that this function assumes *delta_ptr >= 0, and
+ * *recv_window_size_ptr is not decreased by *delta_ptr.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_FLOW_CONTROL
+ *     local_window_size overflow or gets negative.
+ */
+int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
+                                       int32_t *recv_window_size_ptr,
+                                       int32_t *recv_reduction_ptr,
+                                       int32_t *delta_ptr);
+
+/*
+ * Returns non-zero if the function decided that WINDOW_UPDATE should
+ * be sent.
+ */
+int nghttp2_should_send_window_update(int32_t local_window_size,
+                                      int32_t recv_window_size);
+
+/*
+ * Copies the buffer |src| of length |len| to the destination pointed
+ * by the |dest|, assuming that the |dest| is at lest |len| bytes long
+ * . Returns dest + len.
+ */
+uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
+
+#endif /* NGHTTP2_HELPER_H */

+ 97 - 0
components/nghttp/include/nghttp2_http.h

@@ -0,0 +1,97 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2015 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_HTTP_H
+#define NGHTTP2_HTTP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_session.h"
+#include "nghttp2_stream.h"
+
+/*
+ * This function is called when HTTP header field |nv| in |frame| is
+ * received for |stream|.  This function will validate |nv| against
+ * the current state of stream.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_HTTP_HEADER
+ *     Invalid HTTP header field was received.
+ * NGHTTP2_ERR_IGN_HTTP_HEADER
+ *     Invalid HTTP header field was received but it can be treated as
+ *     if it was not received because of compatibility reasons.
+ */
+int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
+                           nghttp2_frame *frame, nghttp2_hd_nv *nv,
+                           int trailer);
+
+/*
+ * This function is called when request header is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_request_headers(nghttp2_stream *stream,
+                                    nghttp2_frame *frame);
+
+/*
+ * This function is called when response header is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_response_headers(nghttp2_stream *stream);
+
+/*
+ * This function is called trailer header (for both request and
+ * response) is received.  This function performs validation and
+ * returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
+                                    nghttp2_frame *frame);
+
+/*
+ * This function is called when END_STREAM flag is seen in incoming
+ * frame.  This function performs validation and returns 0 if it
+ * succeeds, or -1.
+ */
+int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream);
+
+/*
+ * This function is called when chunk of data is received.  This
+ * function performs validation and returns 0 if it succeeds, or -1.
+ */
+int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
+
+/*
+ * This function inspects header field in |frame| and records its
+ * method in stream->http_flags.  If frame->hd.type is neither
+ * NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does
+ * nothing.
+ */
+void nghttp2_http_record_request_method(nghttp2_stream *stream,
+                                        nghttp2_frame *frame);
+
+#endif /* NGHTTP2_HTTP_H */

+ 58 - 0
components/nghttp/include/nghttp2_int.h

@@ -0,0 +1,58 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_INT_H
+#define NGHTTP2_INT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+/* Macros, types and constants for internal use */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x)                                                              \
+  do {                                                                         \
+  } while (0)
+#endif
+
+/* "less" function, return nonzero if |lhs| is less than |rhs|. */
+typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
+
+/* Internal error code. They must be in the range [-499, -100],
+   inclusive. */
+typedef enum {
+  NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
+  NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
+  NGHTTP2_ERR_IGN_PAYLOAD = -104,
+  /*
+   * Invalid HTTP header field was received but it can be treated as
+   * if it was not received because of compatibility reasons.
+   */
+  NGHTTP2_ERR_IGN_HTTP_HEADER = -105
+} nghttp2_internal_error;
+
+#endif /* NGHTTP2_INT_H */

+ 144 - 0
components/nghttp/include/nghttp2_map.h

@@ -0,0 +1,144 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_MAP_H
+#define NGHTTP2_MAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+/* Implementation of unordered map */
+
+typedef int32_t key_type;
+
+typedef struct nghttp2_map_entry {
+  struct nghttp2_map_entry *next;
+  key_type key;
+#if SIZEOF_INT_P == 4
+  /* we requires 8 bytes aligment */
+  int64_t pad;
+#endif
+} nghttp2_map_entry;
+
+typedef struct {
+  nghttp2_map_entry **table;
+  nghttp2_mem *mem;
+  size_t size;
+  uint32_t tablelen;
+} nghttp2_map;
+
+/*
+ * Initializes the map |map|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *   Out of memory
+ */
+int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |map|. The stored entries
+ * are not freed by this function. Use nghttp2_map_each_free() to free
+ * each entries.
+ */
+void nghttp2_map_free(nghttp2_map *map);
+
+/*
+ * Deallocates each entries using |func| function and any resources
+ * allocated for |map|. The |func| function is responsible for freeing
+ * given the |entry| object. The |ptr| will be passed to the |func| as
+ * send argument. The return value of the |func| will be ignored.
+ */
+void nghttp2_map_each_free(nghttp2_map *map,
+                           int (*func)(nghttp2_map_entry *entry, void *ptr),
+                           void *ptr);
+
+/*
+ * Initializes the |entry| with the |key|. All entries to be inserted
+ * to the map must be initialized with this function.
+ */
+void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
+
+/*
+ * Inserts the new |entry| with the key |entry->key| to the map |map|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The item associated by |key| already exists.
+ * NGHTTP2_ERR_NOMEM
+ *   Out of memory
+ */
+int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
+
+/*
+ * Returns the entry associated by the key |key|.  If there is no such
+ * entry, this function returns NULL.
+ */
+nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
+
+/*
+ * Removes the entry associated by the key |key| from the |map|.  The
+ * removed entry is not freed by this function.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The entry associated by |key| does not exist.
+ */
+int nghttp2_map_remove(nghttp2_map *map, key_type key);
+
+/*
+ * Returns the number of items stored in the map |map|.
+ */
+size_t nghttp2_map_size(nghttp2_map *map);
+
+/*
+ * Applies the function |func| to each entry in the |map| with the
+ * optional user supplied pointer |ptr|.
+ *
+ * If the |func| returns 0, this function calls the |func| with the
+ * next entry. If the |func| returns nonzero, it will not call the
+ * |func| for further entries and return the return value of the
+ * |func| immediately.  Thus, this function returns 0 if all the
+ * invocations of the |func| return 0, or nonzero value which the last
+ * invocation of |func| returns.
+ *
+ * Don't use this function to free each entry. Use
+ * nghttp2_map_each_free() instead.
+ */
+int nghttp2_map_each(nghttp2_map *map,
+                     int (*func)(nghttp2_map_entry *entry, void *ptr),
+                     void *ptr);
+
+#endif /* NGHTTP2_MAP_H */

+ 45 - 0
components/nghttp/include/nghttp2_mem.h

@@ -0,0 +1,45 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_MEM_H
+#define NGHTTP2_MEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/* The default, system standard memory allocator */
+nghttp2_mem *nghttp2_mem_default(void);
+
+/* Convenient wrapper functions to call allocator function in
+   |mem|. */
+void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size);
+void nghttp2_mem_free(nghttp2_mem *mem, void *ptr);
+void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data);
+void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size);
+void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size);
+
+#endif /* NGHTTP2_MEM_H */

+ 91 - 0
components/nghttp/include/nghttp2_net.h

@@ -0,0 +1,91 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_NET_H
+#define NGHTTP2_NET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif /* HAVE_ARPA_INET_H */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif /* HAVE_NETINET_IN_H */
+
+#include <nghttp2/nghttp2.h>
+
+#if defined(WIN32)
+/* Windows requires ws2_32 library for ntonl family functions.  We
+   define inline functions for those function so that we don't have
+   dependeny on that lib. */
+
+#ifdef _MSC_VER
+#define STIN static __inline
+#else
+#define STIN static inline
+#endif
+
+STIN uint32_t htonl(uint32_t hostlong) {
+  uint32_t res;
+  unsigned char *p = (unsigned char *)&res;
+  *p++ = hostlong >> 24;
+  *p++ = (hostlong >> 16) & 0xffu;
+  *p++ = (hostlong >> 8) & 0xffu;
+  *p = hostlong & 0xffu;
+  return res;
+}
+
+STIN uint16_t htons(uint16_t hostshort) {
+  uint16_t res;
+  unsigned char *p = (unsigned char *)&res;
+  *p++ = hostshort >> 8;
+  *p = hostshort & 0xffu;
+  return res;
+}
+
+STIN uint32_t ntohl(uint32_t netlong) {
+  uint32_t res;
+  unsigned char *p = (unsigned char *)&netlong;
+  res = *p++ << 24;
+  res += *p++ << 16;
+  res += *p++ << 8;
+  res += *p;
+  return res;
+}
+
+STIN uint16_t ntohs(uint16_t netshort) {
+  uint16_t res;
+  unsigned char *p = (unsigned char *)&netshort;
+  res = *p++ << 8;
+  res += *p;
+  return res;
+}
+
+#endif /* WIN32 */
+
+#endif /* NGHTTP2_NET_H */

+ 34 - 0
components/nghttp/include/nghttp2_npn.h

@@ -0,0 +1,34 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_NPN_H
+#define NGHTTP2_NPN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#endif /* NGHTTP2_NPN_H */

+ 116 - 0
components/nghttp/include/nghttp2_option.h

@@ -0,0 +1,116 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_OPTION_H
+#define NGHTTP2_OPTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/**
+ * Configuration options
+ */
+typedef enum {
+  /**
+   * This option prevents the library from sending WINDOW_UPDATE for a
+   * connection automatically.  If this option is set to nonzero, the
+   * library won't send WINDOW_UPDATE for DATA until application calls
+   * nghttp2_session_consume() to indicate the amount of consumed
+   * DATA.  By default, this option is set to zero.
+   */
+  NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
+  /**
+   * This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
+   * remote endpoint as if it is received in SETTINGS frame. Without
+   * specifying this option, before the local endpoint receives
+   * SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
+   * endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
+   * cause problem if local endpoint submits lots of requests
+   * initially and sending them at once to the remote peer may lead to
+   * the rejection of some requests. Specifying this option to the
+   * sensible value, say 100, may avoid this kind of issue. This value
+   * will be overwritten if the local endpoint receives
+   * SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
+   */
+  NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
+  NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
+  NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
+  NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
+  NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
+  NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
+  NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
+  NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
+} nghttp2_option_flag;
+
+/**
+ * Struct to store option values for nghttp2_session.
+ */
+struct nghttp2_option {
+  /**
+   * NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
+   */
+  size_t max_send_header_block_length;
+  /**
+   * Bitwise OR of nghttp2_option_flag to determine that which fields
+   * are specified.
+   */
+  uint32_t opt_set_mask;
+  /**
+   * NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
+   */
+  uint32_t peer_max_concurrent_streams;
+  /**
+   * NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
+   */
+  uint32_t max_reserved_remote_streams;
+  /**
+   * NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES
+   */
+  uint32_t builtin_recv_ext_types;
+  /**
+   * NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
+   */
+  int no_auto_window_update;
+  /**
+   * NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
+   */
+  int no_recv_client_magic;
+  /**
+   * NGHTTP2_OPT_NO_HTTP_MESSAGING
+   */
+  int no_http_messaging;
+  /**
+   * NGHTTP2_OPT_NO_AUTO_PING_ACK
+   */
+  int no_auto_ping_ack;
+  /**
+   * NGHTTP2_OPT_USER_RECV_EXT_TYPES
+   */
+  uint8_t user_recv_ext_types[32];
+};
+
+#endif /* NGHTTP2_OPTION_H */

+ 166 - 0
components/nghttp/include/nghttp2_outbound_item.h

@@ -0,0 +1,166 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_OUTBOUND_ITEM_H
+#define NGHTTP2_OUTBOUND_ITEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_frame.h"
+#include "nghttp2_mem.h"
+
+/* struct used for HEADERS and PUSH_PROMISE frame */
+typedef struct {
+  nghttp2_data_provider data_prd;
+  void *stream_user_data;
+  /* error code when request HEADERS is canceled by RST_STREAM while
+     it is in queue. */
+  uint32_t error_code;
+  /* nonzero if request HEADERS is canceled.  The error code is stored
+     in |error_code|. */
+  uint8_t canceled;
+} nghttp2_headers_aux_data;
+
+/* struct used for DATA frame */
+typedef struct {
+  /**
+   * The data to be sent for this DATA frame.
+   */
+  nghttp2_data_provider data_prd;
+  /**
+   * The flags of DATA frame.  We use separate flags here and
+   * nghttp2_data frame.  The latter contains flags actually sent to
+   * peer.  This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
+   * when |eof| becomes nonzero, flags in nghttp2_data has
+   * NGHTTP2_FLAG_END_STREAM set.
+   */
+  uint8_t flags;
+  /**
+   * The flag to indicate whether EOF was reached or not. Initially
+   * |eof| is 0. It becomes 1 after all data were read.
+   */
+  uint8_t eof;
+  /**
+   * The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
+   */
+  uint8_t no_copy;
+} nghttp2_data_aux_data;
+
+typedef enum {
+  NGHTTP2_GOAWAY_AUX_NONE = 0x0,
+  /* indicates that session should be terminated after the
+     transmission of this frame. */
+  NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1,
+  /* indicates that this GOAWAY is just a notification for graceful
+     shutdown.  No nghttp2_session.goaway_flags should be updated on
+     the reaction to this frame. */
+  NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
+} nghttp2_goaway_aux_flag;
+
+/* struct used for GOAWAY frame */
+typedef struct {
+  /* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */
+  uint8_t flags;
+} nghttp2_goaway_aux_data;
+
+/* struct used for extension frame */
+typedef struct {
+  /* nonzero if this extension frame is serialized by library
+     function, instead of user-defined callbacks. */
+  uint8_t builtin;
+} nghttp2_ext_aux_data;
+
+/* Additional data which cannot be stored in nghttp2_frame struct */
+typedef union {
+  nghttp2_data_aux_data data;
+  nghttp2_headers_aux_data headers;
+  nghttp2_goaway_aux_data goaway;
+  nghttp2_ext_aux_data ext;
+} nghttp2_aux_data;
+
+struct nghttp2_outbound_item;
+typedef struct nghttp2_outbound_item nghttp2_outbound_item;
+
+struct nghttp2_outbound_item {
+  nghttp2_frame frame;
+  /* Storage for extension frame payload.  frame->ext.payload points
+     to this structure to avoid frequent memory allocation. */
+  nghttp2_ext_frame_payload ext_frame_payload;
+  nghttp2_aux_data aux_data;
+  /* The priority used in priority comparion.  Smaller is served
+     ealier.  For PING, SETTINGS and non-DATA frames (excluding
+     response HEADERS frame) have dedicated cycle value defined above.
+     For DATA frame, cycle is computed by taking into account of
+     effective weight and frame payload length previously sent, so
+     that the amount of transmission is distributed across streams
+     proportional to effective weight (inside a tree). */
+  uint64_t cycle;
+  nghttp2_outbound_item *qnext;
+  /* nonzero if this object is queued, except for DATA or HEADERS
+     which are attached to stream as item. */
+  uint8_t queued;
+};
+
+/*
+ * Initializes |item|.  No memory allocation is done in this function.
+ * Don't call nghttp2_outbound_item_free() until frame member is
+ * initialized.
+ */
+void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
+
+/*
+ * Deallocates resource for |item|. If |item| is NULL, this function
+ * does nothing.
+ */
+void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
+
+/*
+ * queue for nghttp2_outbound_item.
+ */
+typedef struct {
+  nghttp2_outbound_item *head, *tail;
+  /* number of items in this queue. */
+  size_t n;
+} nghttp2_outbound_queue;
+
+void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
+
+/* Pushes |item| into |q| */
+void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
+                                 nghttp2_outbound_item *item);
+
+/* Pops |item| at the top from |q|.  If |q| is empty, nothing
+   happens. */
+void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
+
+/* Returns the top item. */
+#define nghttp2_outbound_queue_top(Q) ((Q)->head)
+
+/* Returns the size of the queue */
+#define nghttp2_outbound_queue_size(Q) ((Q)->n)
+
+#endif /* NGHTTP2_OUTBOUND_ITEM_H */

+ 128 - 0
components/nghttp/include/nghttp2_pq.h

@@ -0,0 +1,128 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_PQ_H
+#define NGHTTP2_PQ_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_int.h"
+#include "nghttp2_mem.h"
+
+/* Implementation of priority queue */
+
+typedef struct { size_t index; } nghttp2_pq_entry;
+
+typedef struct {
+  /* The pointer to the pointer to the item stored */
+  nghttp2_pq_entry **q;
+  /* Memory allocator */
+  nghttp2_mem *mem;
+  /* The number of items sotred */
+  size_t length;
+  /* The maximum number of items this pq can store. This is
+     automatically extended when length is reached to this value. */
+  size_t capacity;
+  /* The less function between items */
+  nghttp2_less less;
+} nghttp2_pq;
+
+/*
+ * Initializes priority queue |pq| with compare function |cmp|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
+
+/*
+ * Deallocates any resources allocated for |pq|.  The stored items are
+ * not freed by this function.
+ */
+void nghttp2_pq_free(nghttp2_pq *pq);
+
+/*
+ * Adds |item| to the priority queue |pq|.
+ *
+ * This function returns 0 if it succeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item);
+
+/*
+ * Returns item at the top of the queue |pq|. If the queue is empty,
+ * this function returns NULL.
+ */
+nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq);
+
+/*
+ * Pops item at the top of the queue |pq|. The popped item is not
+ * freed by this function.
+ */
+void nghttp2_pq_pop(nghttp2_pq *pq);
+
+/*
+ * Returns nonzero if the queue |pq| is empty.
+ */
+int nghttp2_pq_empty(nghttp2_pq *pq);
+
+/*
+ * Returns the number of items in the queue |pq|.
+ */
+size_t nghttp2_pq_size(nghttp2_pq *pq);
+
+typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
+
+/*
+ * Updates each item in |pq| using function |fun| and re-construct
+ * priority queue. The |fun| must return non-zero if it modifies the
+ * item in a way that it affects ordering in the priority queue. The
+ * |arg| is passed to the 2nd parameter of |fun|.
+ */
+void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
+
+/*
+ * Applys |fun| to each item in |pq|.  The |arg| is passed as arg
+ * parameter to callback function.  This function must not change the
+ * ordering key.  If the return value from callback is nonzero, this
+ * function returns 1 immediately without iterating remaining items.
+ * Otherwise this function returns 0.
+ */
+int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
+
+/*
+ * Removes |item| from priority queue.
+ */
+void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item);
+
+#endif /* NGHTTP2_PQ_H */

+ 42 - 0
components/nghttp/include/nghttp2_priority_spec.h

@@ -0,0 +1,42 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_PRIORITY_SPEC_H
+#define NGHTTP2_PRIORITY_SPEC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+/*
+ * This function normalizes pri_spec->weight if it is out of range.
+ * If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to
+ * NGHTTP2_MIN_WEIGHT.  If pri_spec->weight is larger than
+ * NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT.
+ */
+void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec);
+
+#endif /* NGHTTP2_PRIORITY_SPEC_H */

+ 49 - 0
components/nghttp/include/nghttp2_queue.h

@@ -0,0 +1,49 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_QUEUE_H
+#define NGHTTP2_QUEUE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+typedef struct nghttp2_queue_cell {
+  void *data;
+  struct nghttp2_queue_cell *next;
+} nghttp2_queue_cell;
+
+typedef struct { nghttp2_queue_cell *front, *back; } nghttp2_queue;
+
+void nghttp2_queue_init(nghttp2_queue *queue);
+void nghttp2_queue_free(nghttp2_queue *queue);
+int nghttp2_queue_push(nghttp2_queue *queue, void *data);
+void nghttp2_queue_pop(nghttp2_queue *queue);
+void *nghttp2_queue_front(nghttp2_queue *queue);
+void *nghttp2_queue_back(nghttp2_queue *queue);
+int nghttp2_queue_empty(nghttp2_queue *queue);
+
+#endif /* NGHTTP2_QUEUE_H */

+ 80 - 0
components/nghttp/include/nghttp2_rcbuf.h

@@ -0,0 +1,80 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2016 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_RCBUF_H
+#define NGHTTP2_RCBUF_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+struct nghttp2_rcbuf {
+  /* custom memory allocator belongs to the mem parameter when
+     creating this object. */
+  void *mem_user_data;
+  nghttp2_free free;
+  /* The pointer to the underlying buffer */
+  uint8_t *base;
+  /* Size of buffer pointed by |base|. */
+  size_t len;
+  /* Reference count */
+  int32_t ref;
+};
+
+/*
+ * Allocates nghttp2_rcbuf object with |size| as initial buffer size.
+ * When the function succeeds, the reference count becomes 1.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM:
+ *     Out of memory.
+ */
+int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem);
+
+/*
+ * Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of
+ * length |srclen|.  This function allocates additional byte at the
+ * end and puts '\0' into it, so that the resulting buffer could be
+ * used as NULL-terminated string.  Still (*rcbuf_ptr)->len equals to
+ * |srclen|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM:
+ *     Out of memory.
+ */
+int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
+                       size_t srclen, nghttp2_mem *mem);
+
+/*
+ * Frees |rcbuf| itself, regardless of its reference cout.
+ */
+void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf);
+
+#endif /* NGHTTP2_RCBUF_H */

+ 878 - 0
components/nghttp/include/nghttp2_session.h

@@ -0,0 +1,878 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_SESSION_H
+#define NGHTTP2_SESSION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_map.h"
+#include "nghttp2_frame.h"
+#include "nghttp2_hd.h"
+#include "nghttp2_stream.h"
+#include "nghttp2_outbound_item.h"
+#include "nghttp2_int.h"
+#include "nghttp2_buf.h"
+#include "nghttp2_callbacks.h"
+#include "nghttp2_mem.h"
+
+/* The global variable for tests where we want to disable strict
+   preface handling. */
+extern int nghttp2_enable_strict_preface;
+
+/*
+ * Option flags.
+ */
+typedef enum {
+  NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
+  NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
+  NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
+  NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3
+} nghttp2_optmask;
+
+/*
+ * bitmask for built-in type to enable the default handling for that
+ * type of the frame.
+ */
+typedef enum {
+  NGHTTP2_TYPEMASK_NONE = 0,
+  NGHTTP2_TYPEMASK_ALTSVC = 1 << 0
+} nghttp2_typemask;
+
+typedef enum {
+  NGHTTP2_OB_POP_ITEM,
+  NGHTTP2_OB_SEND_DATA,
+  NGHTTP2_OB_SEND_NO_COPY,
+  NGHTTP2_OB_SEND_CLIENT_MAGIC
+} nghttp2_outbound_state;
+
+typedef struct {
+  nghttp2_outbound_item *item;
+  nghttp2_bufs framebufs;
+  nghttp2_outbound_state state;
+} nghttp2_active_outbound_item;
+
+/* Buffer length for inbound raw byte stream used in
+   nghttp2_session_recv(). */
+#define NGHTTP2_INBOUND_BUFFER_LENGTH 3072//16384--LiuHan/08.12
+
+/* The default maximum number of incoming reserved streams */
+#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
+
+/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
+   number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
+#define NGHTTP2_MIN_IDLE_STREAMS 16
+
+/* The maximum number of items in outbound queue, which is considered
+   as flooding caused by peer.  All frames are not considered here.
+   We only consider PING + ACK and SETTINGS + ACK.  This is because
+   they both are response to the frame initiated by peer and peer can
+   send as many of them as they want.  If peer does not read network,
+   response frames are stacked up, which leads to memory exhaustion.
+   The value selected here is arbitrary, but safe value and if we have
+   these frames in this number, it is considered suspicious. */
+#define NGHTTP2_MAX_OBQ_FLOOD_ITEM 10000
+
+/* The default value of maximum number of concurrent streams. */
+#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
+
+/* Internal state when receiving incoming frame */
+typedef enum {
+  /* Receiving frame header */
+  NGHTTP2_IB_READ_CLIENT_MAGIC,
+  NGHTTP2_IB_READ_FIRST_SETTINGS,
+  NGHTTP2_IB_READ_HEAD,
+  NGHTTP2_IB_READ_NBYTE,
+  NGHTTP2_IB_READ_HEADER_BLOCK,
+  NGHTTP2_IB_IGN_HEADER_BLOCK,
+  NGHTTP2_IB_IGN_PAYLOAD,
+  NGHTTP2_IB_FRAME_SIZE_ERROR,
+  NGHTTP2_IB_READ_SETTINGS,
+  NGHTTP2_IB_READ_GOAWAY_DEBUG,
+  NGHTTP2_IB_EXPECT_CONTINUATION,
+  NGHTTP2_IB_IGN_CONTINUATION,
+  NGHTTP2_IB_READ_PAD_DATA,
+  NGHTTP2_IB_READ_DATA,
+  NGHTTP2_IB_IGN_DATA,
+  NGHTTP2_IB_IGN_ALL,
+  NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
+  NGHTTP2_IB_READ_EXTENSION_PAYLOAD
+} nghttp2_inbound_state;
+
+typedef struct {
+  nghttp2_frame frame;
+  /* Storage for extension frame payload.  frame->ext.payload points
+     to this structure to avoid frequent memory allocation. */
+  nghttp2_ext_frame_payload ext_frame_payload;
+  /* The received SETTINGS entry.  For the standard settings entries,
+     we only keep the last seen value.  For
+     SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
+     last index. */
+  nghttp2_settings_entry *iv;
+  /* buffer pointers to small buffer, raw_sbuf */
+  nghttp2_buf sbuf;
+  /* buffer pointers to large buffer, raw_lbuf */
+  nghttp2_buf lbuf;
+  /* Large buffer, malloced on demand */
+  uint8_t *raw_lbuf;
+  /* The number of entry filled in |iv| */
+  size_t niv;
+  /* The number of entries |iv| can store. */
+  size_t max_niv;
+  /* How many bytes we still need to receive for current frame */
+  size_t payloadleft;
+  /* padding length for the current frame */
+  size_t padlen;
+  nghttp2_inbound_state state;
+  /* Small buffer.  Currently the largest contiguous chunk to buffer
+     is frame header.  We buffer part of payload, but they are smaller
+     than frame header. */
+  uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
+} nghttp2_inbound_frame;
+
+typedef struct {
+  uint32_t header_table_size;
+  uint32_t enable_push;
+  uint32_t max_concurrent_streams;
+  uint32_t initial_window_size;
+  uint32_t max_frame_size;
+  uint32_t max_header_list_size;
+} nghttp2_settings_storage;
+
+typedef enum {
+  NGHTTP2_GOAWAY_NONE = 0,
+  /* Flag means that connection should be terminated after sending GOAWAY. */
+  NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
+  /* Flag means GOAWAY to terminate session has been sent */
+  NGHTTP2_GOAWAY_TERM_SENT = 0x2,
+  /* Flag means GOAWAY was sent */
+  NGHTTP2_GOAWAY_SENT = 0x4,
+  /* Flag means GOAWAY was received */
+  NGHTTP2_GOAWAY_RECV = 0x8
+} nghttp2_goaway_flag;
+
+/* nghttp2_inflight_settings stores the SETTINGS entries which local
+   endpoint has sent to the remote endpoint, and has not received ACK
+   yet. */
+struct nghttp2_inflight_settings {
+  struct nghttp2_inflight_settings *next;
+  nghttp2_settings_entry *iv;
+  size_t niv;
+};
+
+typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
+
+struct nghttp2_session {
+  nghttp2_map /* <nghttp2_stream*> */ streams;
+  /* root of dependency tree*/
+  nghttp2_stream root;
+  /* Queue for outbound urgent frames (PING and SETTINGS) */
+  nghttp2_outbound_queue ob_urgent;
+  /* Queue for non-DATA frames */
+  nghttp2_outbound_queue ob_reg;
+  /* Queue for outbound stream-creating HEADERS (request or push
+     response) frame, which are subject to
+     SETTINGS_MAX_CONCURRENT_STREAMS limit. */
+  nghttp2_outbound_queue ob_syn;
+  nghttp2_active_outbound_item aob;
+  nghttp2_inbound_frame iframe;
+  nghttp2_hd_deflater hd_deflater;
+  nghttp2_hd_inflater hd_inflater;
+  nghttp2_session_callbacks callbacks;
+  /* Memory allocator */
+  nghttp2_mem mem;
+  /* Base value when we schedule next DATA frame write.  This is
+     updated when one frame was written. */
+  uint64_t last_cycle;
+  void *user_data;
+  /* Points to the latest incoming closed stream.  NULL if there is no
+     closed stream.  Only used when session is initialized as
+     server. */
+  nghttp2_stream *closed_stream_head;
+  /* Points to the oldest incoming closed stream.  NULL if there is no
+     closed stream.  Only used when session is initialized as
+     server. */
+  nghttp2_stream *closed_stream_tail;
+  /* Points to the latest idle stream.  NULL if there is no idle
+     stream.  Only used when session is initialized as server .*/
+  nghttp2_stream *idle_stream_head;
+  /* Points to the oldest idle stream.  NULL if there is no idle
+     stream.  Only used when session is initialized as erver. */
+  nghttp2_stream *idle_stream_tail;
+  /* Queue of In-flight SETTINGS values.  SETTINGS bearing ACK is not
+     considered as in-flight. */
+  nghttp2_inflight_settings *inflight_settings_head;
+  /* The number of outgoing streams. This will be capped by
+     remote_settings.max_concurrent_streams. */
+  size_t num_outgoing_streams;
+  /* The number of incoming streams. This will be capped by
+     local_settings.max_concurrent_streams. */
+  size_t num_incoming_streams;
+  /* The number of incoming reserved streams.  This is the number of
+     streams in reserved (remote) state.  RFC 7540 does not limit this
+     number.  nghttp2 offers
+     nghttp2_option_set_max_reserved_remote_streams() to achieve this.
+     If it is used, num_incoming_streams is capped by
+     max_incoming_reserved_streams.  Client application should
+     consider to set this because without that server can send
+     arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
+  size_t num_incoming_reserved_streams;
+  /* The maximum number of incoming reserved streams (reserved
+     (remote) state).  RST_STREAM will be sent for the pushed stream
+     which exceeds this limit. */
+  size_t max_incoming_reserved_streams;
+  /* The number of closed streams still kept in |streams| hash.  The
+     closed streams can be accessed through single linked list
+     |closed_stream_head|.  The current implementation only keeps
+     incoming streams and session is initialized as server. */
+  size_t num_closed_streams;
+  /* The number of idle streams kept in |streams| hash.  The idle
+     streams can be accessed through doubly linked list
+     |idle_stream_head|.  The current implementation only keeps idle
+     streams if session is initialized as server. */
+  size_t num_idle_streams;
+  /* The number of bytes allocated for nvbuf */
+  size_t nvbuflen;
+  /* Counter for detecting flooding in outbound queue */
+  size_t obq_flood_counter_;
+  /* The maximum length of header block to send.  Calculated by the
+     same way as nghttp2_hd_deflate_bound() does. */
+  size_t max_send_header_block_length;
+  /* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
+  uint32_t next_stream_id;
+  /* The last stream ID this session initiated.  For client session,
+     this is the last stream ID it has sent.  For server session, it
+     is the last promised stream ID sent in PUSH_PROMISE. */
+  int32_t last_sent_stream_id;
+  /* The largest stream ID received so far */
+  int32_t last_recv_stream_id;
+  /* The largest stream ID which has been processed in some way. This
+     value will be used as last-stream-id when sending GOAWAY
+     frame. */
+  int32_t last_proc_stream_id;
+  /* Counter of unique ID of PING. Wraps when it exceeds
+     NGHTTP2_MAX_UNIQUE_ID */
+  uint32_t next_unique_id;
+  /* This is the last-stream-ID we have sent in GOAWAY */
+  int32_t local_last_stream_id;
+  /* This is the value in GOAWAY frame received from remote endpoint. */
+  int32_t remote_last_stream_id;
+  /* Current sender window size. This value is computed against the
+     current initial window size of remote endpoint. */
+  int32_t remote_window_size;
+  /* Keep track of the number of bytes received without
+     WINDOW_UPDATE. This could be negative after submitting negative
+     value to WINDOW_UPDATE. */
+  int32_t recv_window_size;
+  /* The number of bytes consumed by the application and now is
+     subject to WINDOW_UPDATE.  This is only used when auto
+     WINDOW_UPDATE is turned off. */
+  int32_t consumed_size;
+  /* The amount of recv_window_size cut using submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_reduction;
+  /* window size for local flow control. It is initially set to
+     NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be
+     increased/decreased by submitting WINDOW_UPDATE. See
+     nghttp2_submit_window_update(). */
+  int32_t local_window_size;
+  /* Settings value received from the remote endpoint. We just use ID
+     as index. The index = 0 is unused. */
+  nghttp2_settings_storage remote_settings;
+  /* Settings value of the local endpoint. */
+  nghttp2_settings_storage local_settings;
+  /* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
+  uint32_t opt_flags;
+  /* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
+     to refuse the incoming stream if it exceeds this value. */
+  uint32_t pending_local_max_concurrent_stream;
+  /* The bitwose OR of zero or more of nghttp2_typemask to indicate
+     that the default handling of extension frame is enabled. */
+  uint32_t builtin_recv_ext_types;
+  /* Unacked local ENABLE_PUSH value.  We use this to refuse
+     PUSH_PROMISE before SETTINGS ACK is received. */
+  uint8_t pending_enable_push;
+  /* Nonzero if the session is server side. */
+  uint8_t server;
+  /* Flags indicating GOAWAY is sent and/or recieved. The flags are
+     composed by bitwise OR-ing nghttp2_goaway_flag. */
+  uint8_t goaway_flags;
+  /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
+     this session.  The nonzero does not necessarily mean
+     WINDOW_UPDATE is not queued. */
+  uint8_t window_update_queued;
+  /* Bitfield of extension frame types that application is willing to
+     receive.  To designate the bit of given frame type i, use
+     user_recv_ext_types[i / 8] & (1 << (i & 0x7)).  First 10 frame
+     types are standard frame types and not used in this bitfield.  If
+     bit is set, it indicates that incoming frame with that type is
+     passed to user defined callbacks, otherwise they are ignored. */
+  uint8_t user_recv_ext_types[32];
+};
+
+/* Struct used when updating initial window size of each active
+   stream. */
+typedef struct {
+  nghttp2_session *session;
+  int32_t new_window_size, old_window_size;
+} nghttp2_update_window_size_arg;
+
+typedef struct {
+  nghttp2_session *session;
+  /* linked list of streams to close */
+  nghttp2_stream *head;
+  int32_t last_stream_id;
+  /* nonzero if GOAWAY is sent to peer, which means we are going to
+     close incoming streams.  zero if GOAWAY is received from peer and
+     we are going to close outgoing streams. */
+  int incoming;
+} nghttp2_close_stream_on_goaway_arg;
+
+/* TODO stream timeout etc */
+
+/*
+ * Returns nonzero value if |stream_id| is initiated by local
+ * endpoint.
+ */
+int nghttp2_session_is_my_stream_id(nghttp2_session *session,
+                                    int32_t stream_id);
+
+/*
+ * Adds |item| to the outbound queue in |session|.  When this function
+ * succeeds, it takes ownership of |item|. So caller must not free it
+ * on success.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_STREAM_CLOSED
+ *     Stream already closed (DATA and PUSH_PROMISE frame only)
+ */
+int nghttp2_session_add_item(nghttp2_session *session,
+                             nghttp2_outbound_item *item);
+
+/*
+ * Adds RST_STREAM frame for the stream |stream_id| with the error
+ * code |error_code|. This is a convenient function built on top of
+ * nghttp2_session_add_frame() to add RST_STREAM easily.
+ *
+ * This function simply returns 0 without adding RST_STREAM frame if
+ * given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
+ * RST_STREAM for a stream is redundant.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
+                                   uint32_t error_code);
+
+/*
+ * Adds PING frame. This is a convenient functin built on top of
+ * nghttp2_session_add_frame() to add PING easily.
+ *
+ * If the |opaque_data| is not NULL, it must point to 8 bytes memory
+ * region of data. The data pointed by |opaque_data| is copied. It can
+ * be NULL. In this case, 8 bytes NULL is used.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue; this only happens
+ *     if NGHTTP2_FLAG_ACK is set in |flags|
+ */
+int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
+                             const uint8_t *opaque_data);
+
+/*
+ * Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the
+ * error code |error_code|. This is a convenient function built on top
+ * of nghttp2_session_add_frame() to add GOAWAY easily.  The
+ * |aux_flags| are bitwise-OR of one or more of
+ * nghttp2_goaway_aux_flag.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The |opaque_data_len| is too large.
+ */
+int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
+                               uint32_t error_code, const uint8_t *opaque_data,
+                               size_t opaque_data_len, uint8_t aux_flags);
+
+/*
+ * Adds WINDOW_UPDATE frame with stream ID |stream_id| and
+ * window-size-increment |window_size_increment|. This is a convenient
+ * function built on top of nghttp2_session_add_frame() to add
+ * WINDOW_UPDATE easily.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ */
+int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
+                                      int32_t stream_id,
+                                      int32_t window_size_increment);
+
+/*
+ * Adds SETTINGS frame.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue; this only happens
+ *     if NGHTTP2_FLAG_ACK is set in |flags|
+ */
+int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
+                                 const nghttp2_settings_entry *iv, size_t niv);
+
+/*
+ * Creates new stream in |session| with stream ID |stream_id|,
+ * priority |pri_spec| and flags |flags|.  The |flags| is bitwise OR
+ * of nghttp2_stream_flag.  Since this function is called when initial
+ * HEADERS is sent or received, these flags are taken from it.  The
+ * state of stream is set to |initial_state|. The |stream_user_data|
+ * is a pointer to the arbitrary user supplied data to be associated
+ * to this stream.
+ *
+ * If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
+ * NGHTTP2_STREAM_FLAG_PUSH flag set.
+ *
+ * This function returns a pointer to created new stream object, or
+ * NULL.
+ *
+ * This function adjusts neither the number of closed streams or idle
+ * streams.  The caller should manually call
+ * nghttp2_session_adjust_closed_stream() or
+ * nghttp2_session_adjust_idle_stream() respectively.
+ */
+nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
+                                            int32_t stream_id, uint8_t flags,
+                                            nghttp2_priority_spec *pri_spec,
+                                            nghttp2_stream_state initial_state,
+                                            void *stream_user_data);
+
+/*
+ * Closes stream whose stream ID is |stream_id|. The reason of closure
+ * is indicated by the |error_code|. When closing the stream,
+ * on_stream_close_callback will be called.
+ *
+ * If the session is initialized as server and |stream| is incoming
+ * stream, stream is just marked closed and this function calls
+ * nghttp2_session_keep_closed_stream() with |stream|.  Otherwise,
+ * |stream| will be deleted from memory.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The specified stream does not exist.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The callback function failed.
+ */
+int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
+                                 uint32_t error_code);
+
+/*
+ * Deletes |stream| from memory.  After this function returns, stream
+ * cannot be accessed.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_destroy_stream(nghttp2_session *session,
+                                   nghttp2_stream *stream);
+
+/*
+ * Tries to keep incoming closed stream |stream|.  Due to the
+ * limitation of maximum number of streams in memory, |stream| is not
+ * closed and just deleted from memory (see
+ * nghttp2_session_destroy_stream).
+ */
+void nghttp2_session_keep_closed_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream);
+
+/*
+ * Appends |stream| to linked list |session->idle_stream_head|.  We
+ * apply fixed limit for list size.  To fit into that limit, one or
+ * more oldest streams are removed from list as necessary.
+ */
+void nghttp2_session_keep_idle_stream(nghttp2_session *session,
+                                      nghttp2_stream *stream);
+
+/*
+ * Detaches |stream| from idle streams linked list.
+ */
+void nghttp2_session_detach_idle_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream);
+
+/*
+ * Deletes closed stream to ensure that number of incoming streams
+ * including active and closed is in the maximum number of allowed
+ * stream.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
+
+/*
+ * Deletes idle stream to ensure that number of idle streams is in
+ * certain limit.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
+
+/*
+ * If further receptions and transmissions over the stream |stream_id|
+ * are disallowed, close the stream with error code NGHTTP2_NO_ERROR.
+ *
+ * This function returns 0 if it
+ * succeeds, or one of the following negative error codes:
+ *
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The specified stream does not exist.
+ */
+int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
+                                              nghttp2_stream *stream);
+
+int nghttp2_session_on_request_headers_received(nghttp2_session *session,
+                                                nghttp2_frame *frame);
+
+int nghttp2_session_on_response_headers_received(nghttp2_session *session,
+                                                 nghttp2_frame *frame,
+                                                 nghttp2_stream *stream);
+
+int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
+                                                      nghttp2_frame *frame,
+                                                      nghttp2_stream *stream);
+
+/*
+ * Called when HEADERS is received, assuming |frame| is properly
+ * initialized.  This function does first validate received frame and
+ * then open stream and call callback functions.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_IGN_HEADER_BLOCK
+ *     Frame was rejected and header block must be decoded but
+ *     result must be ignored.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_headers_received(nghttp2_session *session,
+                                        nghttp2_frame *frame,
+                                        nghttp2_stream *stream);
+
+/*
+ * Called when PRIORITY is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_priority_received(nghttp2_session *session,
+                                         nghttp2_frame *frame);
+
+/*
+ * Called when RST_STREAM is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
+                                           nghttp2_frame *frame);
+
+/*
+ * Called when SETTINGS is received, assuming |frame| is properly
+ * initialized. If |noack| is non-zero, SETTINGS with ACK will not be
+ * submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
+ * with ACK will not be submitted regardless of |noack|.
+ *
+ * This function returns 0 if it succeeds, or one the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue, and this is most
+ *     likely caused by misbehaviour of peer.
+ */
+int nghttp2_session_on_settings_received(nghttp2_session *session,
+                                         nghttp2_frame *frame, int noack);
+
+/*
+ * Called when PUSH_PROMISE is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_IGN_HEADER_BLOCK
+ *     Frame was rejected and header block must be decoded but
+ *     result must be ignored.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed
+ */
+int nghttp2_session_on_push_promise_received(nghttp2_session *session,
+                                             nghttp2_frame *frame);
+
+/*
+ * Called when PING is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ * NGHTTP2_ERR_FLOODED
+ *     There are too many items in outbound queue, and this is most
+ *     likely caused by misbehaviour of peer.
+ */
+int nghttp2_session_on_ping_received(nghttp2_session *session,
+                                     nghttp2_frame *frame);
+
+/*
+ * Called when GOAWAY is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_goaway_received(nghttp2_session *session,
+                                       nghttp2_frame *frame);
+
+/*
+ * Called when WINDOW_UPDATE is recieved, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_window_update_received(nghttp2_session *session,
+                                              nghttp2_frame *frame);
+
+/*
+ * Called when ALTSVC is recieved, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_altsvc_received(nghttp2_session *session,
+                                       nghttp2_frame *frame);
+
+/*
+ * Called when DATA is received, assuming |frame| is properly
+ * initialized.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *   The callback function failed.
+ */
+int nghttp2_session_on_data_received(nghttp2_session *session,
+                                     nghttp2_frame *frame);
+
+/*
+ * Returns nghttp2_stream* object whose stream ID is |stream_id|.  It
+ * could be NULL if such stream does not exist.  This function returns
+ * NULL if stream is marked as closed.
+ */
+nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
+                                           int32_t stream_id);
+
+/*
+ * This function behaves like nghttp2_session_get_stream(), but it
+ * returns stream object even if it is marked as closed or in
+ * NGHTTP2_STREAM_IDLE state.
+ */
+nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
+                                               int32_t stream_id);
+
+/*
+ * Packs DATA frame |frame| in wire frame format and stores it in
+ * |bufs|.  Payload will be read using |aux_data->data_prd|.  The
+ * length of payload is at most |datamax| bytes.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_DEFERRED
+ *     The DATA frame is postponed.
+ * NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
+ *     The read_callback failed (stream error).
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_CALLBACK_FAILURE
+ *     The read_callback failed (session error).
+ */
+int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
+                              size_t datamax, nghttp2_frame *frame,
+                              nghttp2_data_aux_data *aux_data,
+                              nghttp2_stream *stream);
+
+/*
+ * Pops and returns next item to send.  If there is no such item,
+ * returns NULL.  This function takes into account max concurrent
+ * streams.  That means if session->ob_syn has item and max concurrent
+ * streams is reached, the even if other queues contain items, then
+ * this function returns NULL.
+ */
+nghttp2_outbound_item *
+nghttp2_session_pop_next_ob_item(nghttp2_session *session);
+
+/*
+ * Returns next item to send.  If there is no such item, this function
+ * returns NULL.  This function takes into account max concurrent
+ * streams.  That means if session->ob_syn has item and max concurrent
+ * streams is reached, the even if other queues contain items, then
+ * this function returns NULL.
+ */
+nghttp2_outbound_item *
+nghttp2_session_get_next_ob_item(nghttp2_session *session);
+
+/*
+ * Updates local settings with the |iv|. The number of elements in the
+ * array pointed by the |iv| is given by the |niv|.  This function
+ * assumes that the all settings_id member in |iv| are in range 1 to
+ * NGHTTP2_SETTINGS_MAX, inclusive.
+ *
+ * While updating individual stream's local window size, if the window
+ * size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
+ * RST_STREAM is issued against such a stream.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_update_local_settings(nghttp2_session *session,
+                                          nghttp2_settings_entry *iv,
+                                          size_t niv);
+
+/*
+ * Re-prioritize |stream|. The new priority specification is
+ * |pri_spec|.  Caller must ensure that stream->hd.stream_id !=
+ * pri_spec->stream_id.
+ *
+ * This function does not adjust the number of idle streams.  The
+ * caller should call nghttp2_session_adjust_idle_stream() later.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_session_reprioritize_stream(nghttp2_session *session,
+                                        nghttp2_stream *stream,
+                                        const nghttp2_priority_spec *pri_spec);
+
+/*
+ * Terminates current |session| with the |error_code|.  The |reason|
+ * is NULL-terminated debug string.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory.
+ * NGHTTP2_ERR_INVALID_ARGUMENT
+ *     The |reason| is too long.
+ */
+int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
+                                                  uint32_t error_code,
+                                                  const char *reason);
+
+#endif /* NGHTTP2_SESSION_H */

+ 436 - 0
components/nghttp/include/nghttp2_stream.h

@@ -0,0 +1,436 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_STREAM_H
+#define NGHTTP2_STREAM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+#include "nghttp2_outbound_item.h"
+#include "nghttp2_map.h"
+#include "nghttp2_pq.h"
+#include "nghttp2_int.h"
+
+/*
+ * If local peer is stream initiator:
+ * NGHTTP2_STREAM_OPENING : upon sending request HEADERS
+ * NGHTTP2_STREAM_OPENED : upon receiving response HEADERS
+ * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
+ *
+ * If remote peer is stream initiator:
+ * NGHTTP2_STREAM_OPENING : upon receiving request HEADERS
+ * NGHTTP2_STREAM_OPENED : upon sending response HEADERS
+ * NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
+ */
+typedef enum {
+  /* Initial state */
+  NGHTTP2_STREAM_INITIAL,
+  /* For stream initiator: request HEADERS has been sent, but response
+     HEADERS has not been received yet.  For receiver: request HEADERS
+     has been received, but it does not send response HEADERS yet. */
+  NGHTTP2_STREAM_OPENING,
+  /* For stream initiator: response HEADERS is received. For receiver:
+     response HEADERS is sent. */
+  NGHTTP2_STREAM_OPENED,
+  /* RST_STREAM is received, but somehow we need to keep stream in
+     memory. */
+  NGHTTP2_STREAM_CLOSING,
+  /* PUSH_PROMISE is received or sent */
+  NGHTTP2_STREAM_RESERVED,
+  /* Stream is created in this state if it is used as anchor in
+     dependency tree. */
+  NGHTTP2_STREAM_IDLE
+} nghttp2_stream_state;
+
+typedef enum {
+  NGHTTP2_SHUT_NONE = 0,
+  /* Indicates further receptions will be disallowed. */
+  NGHTTP2_SHUT_RD = 0x01,
+  /* Indicates further transmissions will be disallowed. */
+  NGHTTP2_SHUT_WR = 0x02,
+  /* Indicates both further receptions and transmissions will be
+     disallowed. */
+  NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
+} nghttp2_shut_flag;
+
+typedef enum {
+  NGHTTP2_STREAM_FLAG_NONE = 0,
+  /* Indicates that this stream is pushed stream and not opened
+     yet. */
+  NGHTTP2_STREAM_FLAG_PUSH = 0x01,
+  /* Indicates that this stream was closed */
+  NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
+  /* Indicates the item is deferred due to flow control. */
+  NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
+  /* Indicates the item is deferred by user callback */
+  NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
+  /* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
+     NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
+  NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
+
+} nghttp2_stream_flag;
+
+/* HTTP related flags to enforce HTTP semantics */
+typedef enum {
+  NGHTTP2_HTTP_FLAG_NONE = 0,
+  /* header field seen so far */
+  NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
+  NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
+  NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
+  NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
+  /* host is not pseudo header, but we require either host or
+     :authority */
+  NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
+  NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
+  /* required header fields for HTTP request except for CONNECT
+     method. */
+  NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
+                                  NGHTTP2_HTTP_FLAG__PATH |
+                                  NGHTTP2_HTTP_FLAG__SCHEME,
+  NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
+  /* HTTP method flags */
+  NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
+  NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
+  NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
+  NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
+  NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
+                               NGHTTP2_HTTP_FLAG_METH_HEAD |
+                               NGHTTP2_HTTP_FLAG_METH_OPTIONS |
+                               NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
+  /* :path category */
+  /* path starts with "/" */
+  NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
+  /* path "*" */
+  NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
+  /* scheme */
+  /* "http" or "https" scheme */
+  NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
+  /* set if final response is expected */
+  NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14
+} nghttp2_http_flag;
+
+struct nghttp2_stream {
+  /* Intrusive Map */
+  nghttp2_map_entry map_entry;
+  /* Entry for dep_prev->obq */
+  nghttp2_pq_entry pq_entry;
+  /* Priority Queue storing direct descendant (nghttp2_stream).  Only
+     streams which itself has some data to send, or has a descendant
+     which has some data to sent. */
+  nghttp2_pq obq;
+  /* Content-Length of request/response body.  -1 if unknown. */
+  int64_t content_length;
+  /* Received body so far */
+  int64_t recv_content_length;
+  /* Base last_cycle for direct descendent streams. */
+  uint32_t descendant_last_cycle;
+  /* Next scheduled time to sent item */
+  uint32_t cycle;
+  /* Next seq used for direct descendant streams */
+  uint64_t descendant_next_seq;
+  /* Secondary key for prioritization to break a tie for cycle.  This
+     value is monotonically increased for single parent stream. */
+  uint64_t seq;
+  /* pointers to form dependency tree.  If multiple streams depend on
+     a stream, only one stream (left most) has non-NULL dep_prev which
+     points to the stream it depends on. The remaining streams are
+     linked using sib_prev and sib_next.  The stream which has
+     non-NULL dep_prev always NULL sib_prev.  The right most stream
+     has NULL sib_next.  If this stream is a root of dependency tree,
+     dep_prev and sib_prev are NULL. */
+  nghttp2_stream *dep_prev, *dep_next;
+  nghttp2_stream *sib_prev, *sib_next;
+  /* When stream is kept after closure, it may be kept in doubly
+     linked list pointed by nghttp2_session closed_stream_head.
+     closed_next points to the next stream object if it is the element
+     of the list. */
+  nghttp2_stream *closed_prev, *closed_next;
+  /* The arbitrary data provided by user for this stream. */
+  void *stream_user_data;
+  /* Item to send */
+  nghttp2_outbound_item *item;
+  /* Last written length of frame payload */
+  size_t last_writelen;
+  /* stream ID */
+  int32_t stream_id;
+  /* Current remote window size. This value is computed against the
+     current initial window size of remote endpoint. */
+  int32_t remote_window_size;
+  /* Keep track of the number of bytes received without
+     WINDOW_UPDATE. This could be negative after submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_window_size;
+  /* The number of bytes consumed by the application and now is
+     subject to WINDOW_UPDATE.  This is only used when auto
+     WINDOW_UPDATE is turned off. */
+  int32_t consumed_size;
+  /* The amount of recv_window_size cut using submitting negative
+     value to WINDOW_UPDATE */
+  int32_t recv_reduction;
+  /* window size for local flow control. It is initially set to
+     NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
+     submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
+  int32_t local_window_size;
+  /* weight of this stream */
+  int32_t weight;
+  /* This is unpaid penalty (offset) when calculating cycle. */
+  uint32_t pending_penalty;
+  /* sum of weight of direct descendants */
+  int32_t sum_dep_weight;
+  nghttp2_stream_state state;
+  /* status code from remote server */
+  int16_t status_code;
+  /* Bitwise OR of zero or more nghttp2_http_flag values */
+  uint16_t http_flags;
+  /* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
+  uint8_t flags;
+  /* Bitwise OR of zero or more nghttp2_shut_flag values */
+  uint8_t shut_flags;
+  /* Nonzero if this stream has been queued to stream pointed by
+     dep_prev.  We maintain the invariant that if a stream is queued,
+     then its ancestors, except for root, are also queued.  This
+     invariant may break in fatal error condition. */
+  uint8_t queued;
+  /* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
+     this stream.  The nonzero does not necessarily mean WINDOW_UPDATE
+     is not queued. */
+  uint8_t window_update_queued;
+};
+
+void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
+                         uint8_t flags, nghttp2_stream_state initial_state,
+                         int32_t weight, int32_t remote_initial_window_size,
+                         int32_t local_initial_window_size,
+                         void *stream_user_data, nghttp2_mem *mem);
+
+void nghttp2_stream_free(nghttp2_stream *stream);
+
+/*
+ * Disallow either further receptions or transmissions, or both.
+ * |flag| is bitwise OR of one or more of nghttp2_shut_flag.
+ */
+void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
+
+/*
+ * Defer |stream->item|.  We won't call this function in the situation
+ * where |stream->item| == NULL.  The |flags| is bitwise OR of zero or
+ * more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
+ * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL.  The |flags| indicates
+ * the reason of this action.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
+
+/*
+ * Put back deferred data in this stream to active state.  The |flags|
+ * are one or more of bitwise OR of the following values:
+ * NGHTTP2_STREAM_FLAG_DEFERRED_USER and
+ * NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
+ * cleared if they are set.  So even if this function is called, if
+ * one of flag is still set, data does not become active.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
+
+/*
+ * Returns nonzero if item is deferred by whatever reason.
+ */
+int nghttp2_stream_check_deferred_item(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if item is deferred by flow control.
+ */
+int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
+
+/*
+ * Updates the remote window size with the new value
+ * |new_initial_window_size|. The |old_initial_window_size| is used to
+ * calculate the current window size.
+ *
+ * This function returns 0 if it succeeds or -1. The failure is due to
+ * overflow.
+ */
+int nghttp2_stream_update_remote_initial_window_size(
+    nghttp2_stream *stream, int32_t new_initial_window_size,
+    int32_t old_initial_window_size);
+
+/*
+ * Updates the local window size with the new value
+ * |new_initial_window_size|. The |old_initial_window_size| is used to
+ * calculate the current window size.
+ *
+ * This function returns 0 if it succeeds or -1. The failure is due to
+ * overflow.
+ */
+int nghttp2_stream_update_local_initial_window_size(
+    nghttp2_stream *stream, int32_t new_initial_window_size,
+    int32_t old_initial_window_size);
+
+/*
+ * Call this function if promised stream |stream| is replied with
+ * HEADERS.  This function makes the state of the |stream| to
+ * NGHTTP2_STREAM_OPENED.
+ */
+void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if |target| is an ancestor of |stream|.
+ */
+int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
+                                     nghttp2_stream *target);
+
+/*
+ * Computes distributed weight of a stream of the |weight| under the
+ * |stream| if |stream| is removed from a dependency tree.
+ */
+int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
+                                              int32_t weight);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * exclusive.  All existing direct descendants of |dep_stream| become
+ * the descendants of the |stream|.  This function assumes
+ * |stream->item| is NULL.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
+                              nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * not exclusive.  This function assumes |stream->item| is NULL.
+ */
+void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
+
+/*
+ * Removes the |stream| from the current dependency tree.  This
+ * function assumes |stream->item| is NULL.
+ */
+int nghttp2_stream_dep_remove(nghttp2_stream *stream);
+
+/*
+ * Attaches |item| to |stream|.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_attach_item(nghttp2_stream *stream,
+                               nghttp2_outbound_item *item);
+
+/*
+ * Detaches |stream->item|.  This function does not free
+ * |stream->item|.  The caller must free it.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_detach_item(nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * exclusive.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
+                                      nghttp2_stream *stream);
+
+/*
+ * Makes the |stream| depend on the |dep_stream|.  This dependency is
+ * not exclusive.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
+                                   nghttp2_stream *stream);
+
+/*
+ * Removes subtree whose root stream is |stream|.  The
+ * effective_weight of streams in removed subtree is not updated.
+ *
+ * This function returns 0 if it succeeds, or one of the following
+ * negative error codes:
+ *
+ * NGHTTP2_ERR_NOMEM
+ *     Out of memory
+ */
+void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
+
+/*
+ * Returns nonzero if |stream| is in any dependency tree.
+ */
+int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
+
+/*
+ * Schedules transmission of |stream|'s item, assuming stream->item is
+ * attached, and stream->last_writelen was updated.
+ */
+void nghttp2_stream_reschedule(nghttp2_stream *stream);
+
+/*
+ * Changes |stream|'s weight to |weight|.  If |stream| is queued, it
+ * will be rescheduled based on new weight.
+ */
+void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
+
+/*
+ * Returns a stream which has highest priority, updating
+ * descendant_last_cycle of selected stream's ancestors.
+ */
+nghttp2_outbound_item *
+nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
+
+#endif /* NGHTTP2_STREAM */

+ 34 - 0
components/nghttp/include/nghttp2_submit.h

@@ -0,0 +1,34 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2012 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef NGHTTP2_SUBMIT_H
+#define NGHTTP2_SUBMIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <nghttp2/nghttp2.h>
+
+#endif /* NGHTTP2_SUBMIT_H */

+ 494 - 0
components/nghttp/library/nghttp2_buf.c

@@ -0,0 +1,494 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_buf.h"
+
+#include <stdio.h>
+
+#include "nghttp2_helper.h"
+
+void nghttp2_buf_init(nghttp2_buf *buf) {
+  buf->begin = NULL;
+  buf->end = NULL;
+  buf->pos = NULL;
+  buf->last = NULL;
+  buf->mark = NULL;
+}
+
+int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
+  nghttp2_buf_init(buf);
+  return nghttp2_buf_reserve(buf, initial, mem);
+}
+
+void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
+  if (buf == NULL) {
+    return;
+  }
+
+  nghttp2_mem_free(mem, buf->begin);
+  buf->begin = NULL;
+}
+
+int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
+  uint8_t *ptr;
+  size_t cap;
+
+  cap = nghttp2_buf_cap(buf);
+
+  if (cap >= new_cap) {
+    return 0;
+  }
+
+  new_cap = nghttp2_max(new_cap, cap * 2);
+
+  ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
+  if (ptr == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  buf->pos = ptr + (buf->pos - buf->begin);
+  buf->last = ptr + (buf->last - buf->begin);
+  buf->mark = ptr + (buf->mark - buf->begin);
+  buf->begin = ptr;
+  buf->end = ptr + new_cap;
+
+  return 0;
+}
+
+void nghttp2_buf_reset(nghttp2_buf *buf) {
+  buf->pos = buf->last = buf->mark = buf->begin;
+}
+
+void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
+  buf->begin = buf->pos = buf->last = buf->mark = begin;
+  buf->end = begin + len;
+}
+
+static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
+                         nghttp2_mem *mem) {
+  int rv;
+
+  *chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
+  if (*chain == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  (*chain)->next = NULL;
+
+  rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
+  if (rv != 0) {
+    nghttp2_mem_free(mem, *chain);
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  return 0;
+}
+
+static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
+  nghttp2_buf_free(&chain->buf, mem);
+  nghttp2_mem_free(mem, chain);
+}
+
+int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
+                      nghttp2_mem *mem) {
+  return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
+}
+
+int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t offset, nghttp2_mem *mem) {
+  return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
+                            mem);
+}
+
+int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
+                       size_t max_chunk, size_t chunk_keep, size_t offset,
+                       nghttp2_mem *mem) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  rv = buf_chain_new(&chain, chunk_length, mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  bufs->mem = mem;
+  bufs->offset = offset;
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, offset);
+
+  bufs->chunk_length = chunk_length;
+  bufs->chunk_used = 1;
+  bufs->max_chunk = max_chunk;
+  bufs->chunk_keep = chunk_keep;
+
+  return 0;
+}
+
+int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (chunk_length < bufs->offset) {
+    return NGHTTP2_ERR_INVALID_ARGUMENT;
+  }
+
+  rv = buf_chain_new(&chain, chunk_length, bufs->mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  nghttp2_bufs_free(bufs);
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
+
+  bufs->chunk_length = chunk_length;
+  bufs->chunk_used = 1;
+
+  return 0;
+}
+
+void nghttp2_bufs_free(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain, *next_chain;
+
+  if (bufs == NULL) {
+    return;
+  }
+
+  for (chain = bufs->head; chain;) {
+    next_chain = chain->next;
+
+    buf_chain_del(chain, bufs->mem);
+
+    chain = next_chain;
+  }
+
+  bufs->head = NULL;
+}
+
+int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
+                           nghttp2_mem *mem) {
+  nghttp2_buf_chain *chain;
+
+  chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
+  if (chain == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  chain->next = NULL;
+
+  nghttp2_buf_wrap_init(&chain->buf, begin, len);
+
+  bufs->mem = mem;
+  bufs->offset = 0;
+
+  bufs->head = chain;
+  bufs->cur = bufs->head;
+
+  bufs->chunk_length = len;
+  bufs->chunk_used = 1;
+  bufs->max_chunk = 1;
+  bufs->chunk_keep = 1;
+
+  return 0;
+}
+
+void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
+  if (bufs == NULL) {
+    return;
+  }
+
+  nghttp2_mem_free(bufs->mem, bufs->head);
+  bufs->head = NULL;
+}
+
+void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *ci;
+
+  for (ci = bufs->cur; ci; ci = ci->next) {
+    if (nghttp2_buf_len(&ci->buf) == 0) {
+      return;
+    } else {
+      bufs->cur = ci;
+    }
+  }
+}
+
+size_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *ci;
+  size_t len;
+
+  len = 0;
+  for (ci = bufs->head; ci; ci = ci->next) {
+    len += nghttp2_buf_len(&ci->buf);
+  }
+
+  return len;
+}
+
+static size_t bufs_avail(nghttp2_bufs *bufs) {
+  return nghttp2_buf_avail(&bufs->cur->buf) +
+         (bufs->chunk_length - bufs->offset) *
+             (bufs->max_chunk - bufs->chunk_used);
+}
+
+static int bufs_alloc_chain(nghttp2_bufs *bufs) {
+  int rv;
+  nghttp2_buf_chain *chain;
+
+  if (bufs->cur->next) {
+    bufs->cur = bufs->cur->next;
+
+    return 0;
+  }
+
+  if (bufs->max_chunk == bufs->chunk_used) {
+    return NGHTTP2_ERR_BUFFER_ERROR;
+  }
+
+  rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
+  if (rv != 0) {
+    return rv;
+  }
+
+  DEBUGF(fprintf(stderr,
+                 "new buffer %zu bytes allocated for bufs %p, used %zu\n",
+                 bufs->chunk_length, bufs, bufs->chunk_used));
+
+  ++bufs->chunk_used;
+
+  bufs->cur->next = chain;
+  bufs->cur = chain;
+
+  nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
+
+  return 0;
+}
+
+int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
+  int rv;
+  size_t nwrite;
+  nghttp2_buf *buf;
+  const uint8_t *p;
+
+  if (bufs_avail(bufs) < len) {
+    return NGHTTP2_ERR_BUFFER_ERROR;
+  }
+
+  p = data;
+
+  while (len) {
+    buf = &bufs->cur->buf;
+
+    nwrite = nghttp2_min(nghttp2_buf_avail(buf), len);
+    if (nwrite == 0) {
+      rv = bufs_alloc_chain(bufs);
+      if (rv != 0) {
+        return rv;
+      }
+      continue;
+    }
+
+    buf->last = nghttp2_cpymem(buf->last, p, nwrite);
+    p += nwrite;
+    len -= nwrite;
+  }
+
+  return 0;
+}
+
+static int bufs_ensure_addb(nghttp2_bufs *bufs) {
+  int rv;
+  nghttp2_buf *buf;
+
+  buf = &bufs->cur->buf;
+
+  if (nghttp2_buf_avail(buf) > 0) {
+    return 0;
+  }
+
+  rv = bufs_alloc_chain(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  return 0;
+}
+
+int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last++ = b;
+
+  return 0;
+}
+
+int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last = b;
+
+  return 0;
+}
+
+int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last++ |= b;
+
+  return 0;
+}
+
+int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
+  int rv;
+
+  rv = bufs_ensure_addb(bufs);
+  if (rv != 0) {
+    return rv;
+  }
+
+  *bufs->cur->buf.last |= b;
+
+  return 0;
+}
+
+ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
+  size_t len;
+  nghttp2_buf_chain *chain;
+  nghttp2_buf *buf;
+  uint8_t *res;
+  nghttp2_buf resbuf;
+
+  len = 0;
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    len += nghttp2_buf_len(&chain->buf);
+  }
+
+  if (len == 0) {
+    res = NULL;
+    return 0;
+  }
+
+  res = nghttp2_mem_malloc(bufs->mem, len);
+  if (res == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  nghttp2_buf_wrap_init(&resbuf, res, len);
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    buf = &chain->buf;
+    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
+  }
+
+  *out = res;
+
+  return (ssize_t)len;
+}
+
+size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
+  size_t len;
+  nghttp2_buf_chain *chain;
+  nghttp2_buf *buf;
+  nghttp2_buf resbuf;
+
+  len = nghttp2_bufs_len(bufs);
+
+  nghttp2_buf_wrap_init(&resbuf, out, len);
+
+  for (chain = bufs->head; chain; chain = chain->next) {
+    buf = &chain->buf;
+    resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
+  }
+
+  return len;
+}
+
+void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain, *ci;
+  size_t k;
+
+  k = bufs->chunk_keep;
+
+  for (ci = bufs->head; ci; ci = ci->next) {
+    nghttp2_buf_reset(&ci->buf);
+    nghttp2_buf_shift_right(&ci->buf, bufs->offset);
+
+    if (--k == 0) {
+      break;
+    }
+  }
+
+  if (ci) {
+    chain = ci->next;
+    ci->next = NULL;
+
+    for (ci = chain; ci;) {
+      chain = ci->next;
+
+      buf_chain_del(ci, bufs->mem);
+
+      ci = chain;
+    }
+
+    bufs->chunk_used = bufs->chunk_keep;
+  }
+
+  bufs->cur = bufs->head;
+}
+
+int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
+
+int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
+  nghttp2_buf_chain *chain;
+
+  chain = bufs->cur->next;
+
+  return chain && nghttp2_buf_len(&chain->buf);
+}

+ 158 - 0
components/nghttp/library/nghttp2_callbacks.c

@@ -0,0 +1,158 @@
+/*
+ * nghttp2 - HTTP/2 C Library
+ *
+ * Copyright (c) 2014 Tatsuhiro Tsujikawa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "nghttp2_callbacks.h"
+
+#include <stdlib.h>
+
+int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) {
+  *callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
+
+  if (*callbacks_ptr == NULL) {
+    return NGHTTP2_ERR_NOMEM;
+  }
+
+  return 0;
+}
+
+void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
+  free(callbacks);
+}
+
+void nghttp2_session_callbacks_set_send_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
+  cbs->send_callback = send_callback;
+}
+
+void nghttp2_session_callbacks_set_recv_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
+  cbs->recv_callback = recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_recv_callback on_frame_recv_callback) {
+  cbs->on_frame_recv_callback = on_frame_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
+  cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
+  cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_before_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_before_frame_send_callback before_frame_send_callback) {
+  cbs->before_frame_send_callback = before_frame_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_send_callback on_frame_send_callback) {
+  cbs->on_frame_send_callback = on_frame_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_frame_not_send_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
+  cbs->on_frame_not_send_callback = on_frame_not_send_callback;
+}
+
+void nghttp2_session_callbacks_set_on_stream_close_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_stream_close_callback on_stream_close_callback) {
+  cbs->on_stream_close_callback = on_stream_close_callback;
+}
+
+void nghttp2_session_callbacks_set_on_begin_headers_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_headers_callback on_begin_headers_callback) {
+  cbs->on_begin_headers_callback = on_begin_headers_callback;
+}
+
+void nghttp2_session_callbacks_set_on_header_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback on_header_callback) {
+  cbs->on_header_callback = on_header_callback;
+}
+
+void nghttp2_session_callbacks_set_on_header_callback2(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_header_callback2 on_header_callback2) {
+  cbs->on_header_callback2 = on_header_callback2;
+}
+
+void nghttp2_session_callbacks_set_select_padding_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_select_padding_callback select_padding_callback) {
+  cbs->select_padding_callback = select_padding_callback;
+}
+
+void nghttp2_session_callbacks_set_data_source_read_length_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_data_source_read_length_callback data_source_read_length_callback) {
+  cbs->read_length_callback = data_source_read_length_callback;
+}
+
+void nghttp2_session_callbacks_set_on_begin_frame_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_begin_frame_callback on_begin_frame_callback) {
+  cbs->on_begin_frame_callback = on_begin_frame_callback;
+}
+
+void nghttp2_session_callbacks_set_send_data_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_send_data_callback send_data_callback) {
+  cbs->send_data_callback = send_data_callback;
+}
+
+void nghttp2_session_callbacks_set_pack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_pack_extension_callback pack_extension_callback) {
+  cbs->pack_extension_callback = pack_extension_callback;
+}
+
+void nghttp2_session_callbacks_set_unpack_extension_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_unpack_extension_callback unpack_extension_callback) {
+  cbs->unpack_extension_callback = unpack_extension_callback;
+}
+
+void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
+    nghttp2_session_callbacks *cbs,
+    nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
+  cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
+}
+
+void nghttp2_session_callbacks_set_error_callback(
+    nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
+  cbs->error_callback = error_callback;
+}

Некоторые файлы не были показаны из-за большого количества измененных файлов