Ver Fonte

[esp-hosted] update the esp-hosted code and move hci driver and component to the porting layer

Evlers há 11 meses atrás
pai
commit
20a0f1401a
100 ficheiros alterados com 5286 adições e 357 exclusões
  1. 10 10
      SConscript
  2. 5 3
      esp-hosted/.gitignore
  3. 89 0
      esp-hosted/CMakeLists.txt
  4. 1018 0
      esp-hosted/Kconfig
  5. 21 32
      esp-hosted/README.md
  6. 271 47
      esp-hosted/docs/bluetooth_design.md
  7. 1 1
      esp-hosted/docs/design_consideration.md
  8. 4 1
      esp-hosted/docs/esp32_p4_function_ev_board.md
  9. 10 13
      esp-hosted/docs/spi_full_duplex.md
  10. 3 3
      esp-hosted/docs/spi_half_duplex.md
  11. 8 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/CMakeLists.txt
  12. 59 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/README.md
  13. 180 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/ble_compatibility_test_case.md
  14. 3 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/CMakeLists.txt
  15. 730 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/ble_compatibility_test.c
  16. 31 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/ble_compatibility_test.h
  17. 5 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/idf_component.yml
  18. 8 0
      esp-hosted/examples/host_bluedroid_ble_compatibility_test/sdkconfig.defaults
  19. 9 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/CMakeLists.txt
  20. 298 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/README.md
  21. 8 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/CMakeLists.txt
  22. 15 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/Kconfig.projbuild
  23. 5 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/idf_component.yml
  24. 483 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/main.c
  25. 7 0
      esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/sdkconfig.defaults
  26. 8 0
      esp-hosted/examples/host_bluedroid_host_only/CMakeLists.txt
  27. 100 0
      esp-hosted/examples/host_bluedroid_host_only/README.md
  28. 3 0
      esp-hosted/examples/host_bluedroid_host_only/main/CMakeLists.txt
  29. 5 0
      esp-hosted/examples/host_bluedroid_host_only/main/idf_component.yml
  30. 307 0
      esp-hosted/examples/host_bluedroid_host_only/main/main.c
  31. 4 0
      esp-hosted/examples/host_bluedroid_host_only/sdkconfig.defaults
  32. 6 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/CMakeLists.txt
  33. 202 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/README.md
  34. 5 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/CMakeLists.txt
  35. 80 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/Kconfig.projbuild
  36. 35 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/bleprph.h
  37. 247 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/gatt_svr.c
  38. 7 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/idf_component.yml
  39. 550 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/main.c
  40. 22 0
      esp-hosted/examples/host_nimble_bleprph_host_only_vhci/sdkconfig.defaults
  41. 0 1
      esp-hosted/host/api/include/esp_hosted_api.h
  42. 21 0
      esp-hosted/host/drivers/bt/esp_hosted_bt.h
  43. 0 11
      esp-hosted/host/drivers/bt/hci_drv.h
  44. 31 6
      esp-hosted/host/drivers/bt/hci_stub_drv.c
  45. 165 64
      esp-hosted/host/drivers/bt/vhci_drv.c
  46. 2 2
      esp-hosted/host/drivers/mempool/mempool.c
  47. 7 6
      esp-hosted/host/drivers/rpc/core/rpc_core.c
  48. 0 3
      esp-hosted/host/drivers/rpc/core/rpc_rsp.c
  49. 5 5
      esp-hosted/host/drivers/rpc/slaveif/rpc_slave_if.c
  50. 16 14
      esp-hosted/host/drivers/rpc/wrap/rpc_wrap.c
  51. 3 3
      esp-hosted/host/drivers/serial/serial_drv.c
  52. 5 5
      esp-hosted/host/drivers/transport/spi/spi_drv.c
  53. 1 1
      esp-hosted/host/drivers/transport/transport_drv.h
  54. 70 108
      esp-hosted/host/drivers/transport/uart/uart_drv.c
  55. 17 0
      esp-hosted/host/esp_hosted.h
  56. 26 0
      esp-hosted/host/esp_hosted_host_init.c
  57. 2 6
      esp-hosted/host/hosted_os_adapter.h
  58. 47 0
      esp-hosted/host/port/esp_hosted_bt_config.h
  59. 0 0
      esp-hosted/host/port/esp_hosted_config.c
  60. 6 10
      esp-hosted/host/port/esp_hosted_config.h
  61. 0 0
      esp-hosted/host/port/esp_hosted_transport_config.c
  62. 0 2
      esp-hosted/host/port/esp_hosted_transport_config.h
  63. 0 0
      esp-hosted/host/port/esp_hosted_wifi_config.h
  64. 0 0
      esp-hosted/host/port/examples/wifi/iperf/CMakeLists.txt
  65. 0 0
      esp-hosted/host/port/examples/wifi/iperf/README.md
  66. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/CMakeLists.txt
  67. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/Kconfig
  68. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/Kconfig.projbuild
  69. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/cmd_decl.h
  70. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/cmd_wifi.c
  71. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/cmd_wifi.h
  72. 0 0
      esp-hosted/host/port/examples/wifi/iperf/main/iperf_example_main.c
  73. 0 0
      esp-hosted/host/port/examples/wifi/iperf/pytest_iperf.py
  74. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.00
  75. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.01
  76. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.02
  77. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.03
  78. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.04
  79. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.05
  80. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.06
  81. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.07
  82. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.99
  83. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults
  84. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32
  85. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c2
  86. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c3
  87. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c6
  88. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32s2
  89. 0 0
      esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32s3
  90. 0 0
      esp-hosted/host/port/examples/wifi/scan/CMakeLists.txt
  91. 0 0
      esp-hosted/host/port/examples/wifi/scan/README.md
  92. 0 0
      esp-hosted/host/port/examples/wifi/scan/main/CMakeLists.txt
  93. 0 0
      esp-hosted/host/port/examples/wifi/scan/main/Kconfig
  94. 0 0
      esp-hosted/host/port/examples/wifi/scan/main/Kconfig.projbuild
  95. 0 0
      esp-hosted/host/port/examples/wifi/scan/main/scan.c
  96. 0 0
      esp-hosted/host/port/examples/wifi/softAP/CMakeLists.txt
  97. 0 0
      esp-hosted/host/port/examples/wifi/softAP/README.md
  98. 0 0
      esp-hosted/host/port/examples/wifi/softAP/main/CMakeLists.txt
  99. 0 0
      esp-hosted/host/port/examples/wifi/softAP/main/Kconfig
  100. 0 0
      esp-hosted/host/port/examples/wifi/softAP/main/Kconfig.projbuild

+ 10 - 10
SConscript

@@ -24,14 +24,14 @@ src += Glob('esp-hosted/host/api/src/*.c')
 path += [cwd + '/esp-hosted/host/api/include']
 
 # add components source and header files
-src += Glob('esp-hosted/host/components/log/*.c')
-src += Glob('esp-hosted/host/components/utils/*.c')
-src += Glob('esp-hosted/host/components/esp_wifi/*.c')
-src += Glob('esp-hosted/host/components/esp_wifi_remote/*.c')
-path += [cwd + '/esp-hosted/host/components/log']
-path += [cwd + '/esp-hosted/host/components/utils']
-path += [cwd + '/esp-hosted/host/components/esp_wifi/include']
-path += [cwd + '/esp-hosted/host/components/esp_netif/include']
+src += Glob('porting/components/log/*.c')
+src += Glob('porting/components/utils/*.c')
+src += Glob('porting/components/esp_wifi/*.c')
+src += Glob('porting/components/esp_wifi_remote/*.c')
+path += [cwd + '/porting/components/log']
+path += [cwd + '/porting/components/utils']
+path += [cwd + '/porting/components/esp_wifi/include']
+path += [cwd + '/porting/components/esp_netif/include']
 
 # add host drivers source and header files
 src += Glob('esp-hosted/host/drivers/mempool/*.c')
@@ -66,13 +66,13 @@ path += [cwd + '/porting/ota']
 # add bt source and header files
 if GetDepend(['ESP_HOSTED_BT_USING_VHCI_DEVICE_DRIVER']):
     # add vhci device driver source and header files
-    src += Glob('porting/bt/*.c')
+    src += Glob('porting/bt/vhci_dev.c')
     src += Glob('porting/bt/vhci/*.c')
     path += [cwd + '/porting/bt/vhci']
 
 if GetDepend(['ESP_HOSTED_BT_USING_NIMBLE_STACK']):
     # add nimble hci driver source and header files
-    src += Glob('esp-hosted/host/drivers/bt/*.c')
+    src += Glob('porting/bt/vhci_drv.c')
 path += [cwd + '/esp-hosted/host/drivers/bt']
 
 # add host wlan source files

+ 5 - 3
esp-hosted/.gitignore

@@ -1,5 +1,7 @@
-slave/build
-slave/sdkconfig
-slave/sdkconfig.old
+build
+dependencies.lock
+managed_components
+sdkconfig
+sdkconfig.old
 slave/main/coprocessor_fw_version.h
 slave/main/coprocessor_fw_version.txt

+ 89 - 0
esp-hosted/CMakeLists.txt

@@ -0,0 +1,89 @@
+if(CONFIG_ESP_HOSTED_ENABLED)
+	message(STATUS "Using Hosted Wi-Fi")
+	set(FG_root_dir ".")
+	set(host_dir "${FG_root_dir}/host")
+
+	set(COMPONENT_ADD_INCLUDEDIRS "${host_dir}" "${host_dir}/api")
+	set(COMPONENT_SRCS "${host_dir}/esp_hosted_host_init.c" "${host_dir}/api/src/esp_wifi_weak.c" "${host_dir}/api/src/esp_hosted_api.c" "${host_dir}/drivers/transport/transport_drv.c" "${host_dir}/drivers/serial/serial_ll_if.c" "${host_dir}/utils/common.c" "${host_dir}/utils/util.c" "${host_dir}/utils/stats.c" "${host_dir}/drivers/serial/serial_drv.c")
+
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "." "${host_dir}/api/include" "${host_dir}/drivers/transport" "${host_dir}/drivers/transport/spi" "${host_dir}/drivers/transport/sdio" "${host_dir}/drivers/serial" "${host_dir}/utils")
+
+	# rpc files - wrap -> slaveif -> core
+	set(rpc_dir "${host_dir}/drivers/rpc")
+	set(rpc_core_dir "${rpc_dir}/core")
+	set(rpc_slaveif_dir "${rpc_dir}/slaveif")
+	set(rpc_wrap_dir "${rpc_dir}/wrap")
+	list(APPEND COMPONENT_SRCS  "${rpc_core_dir}/rpc_core.c" "${rpc_core_dir}/rpc_req.c" "${rpc_core_dir}/rpc_rsp.c" "${rpc_core_dir}/rpc_evt.c"
+		"${rpc_slaveif_dir}/rpc_slave_if.c"
+		"${rpc_wrap_dir}/rpc_wrap.c")
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${rpc_core_dir}" "${rpc_slaveif_dir}" "${rpc_wrap_dir}")
+
+	# virtual serial
+	set(virt_serial_dir "${host_dir}/drivers/virtual_serial_if")
+	list(APPEND COMPONENT_SRCS  "${virt_serial_dir}/serial_if.c")
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${virt_serial_dir}")
+
+	# mempool
+	list(APPEND COMPONENT_SRCS "${host_dir}/drivers/mempool/mempool.c")
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${host_dir}/drivers/mempool" )
+
+	# slave and host common files
+	set(common_dir "${FG_root_dir}/common")
+	list(APPEND COMPONENT_SRCS "${common_dir}/protobuf-c/protobuf-c/protobuf-c.c" "${common_dir}/proto/esp_hosted_rpc.pb-c.c" )
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${common_dir}/include" "${common_dir}/protobuf-c" "${common_dir}/proto" )
+
+	# bt (NimBLE)
+	### TODO config for HCI over UART
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${host_dir}/drivers/bt")
+	if(CONFIG_ESP_NIMBLE_HCI_VHCI OR CONFIG_ESP_BLUEDROID_HCI_VHCI)
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/bt/vhci_drv.c")
+	else()
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/bt/hci_stub_drv.c")
+	endif()
+
+	# transport files
+	if(CONFIG_ESP_SDIO_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/transport/sdio/sdio_drv.c")
+	elseif(CONFIG_ESP_SPI_HD_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/transport/spi_hd/spi_hd_drv.c")
+	elseif(CONFIG_ESP_SPI_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/transport/spi/spi_drv.c")
+	elseif(CONFIG_ESP_UART_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/drivers/transport/uart/uart_drv.c")
+	endif()
+
+	# config files
+	list(APPEND COMPONENT_ADD_INCLUDEDIRS "${host_dir}/port")
+	list(APPEND COMPONENT_SRCS "${host_dir}/port/esp_hosted_config.c" "${host_dir}/port/esp_hosted_transport_config.c")
+
+	# transport port files
+	list(APPEND COMPONENT_SRCS "${host_dir}/port/os_wrapper.c")
+	if(CONFIG_ESP_SDIO_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/port/sdio_wrapper.c")
+	elseif(CONFIG_ESP_SPI_HD_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/port/spi_hd_wrapper.c")
+	elseif(CONFIG_ESP_SPI_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/port/spi_wrapper.c")
+	elseif(CONFIG_ESP_UART_HOST_INTERFACE)
+		list(APPEND COMPONENT_SRCS "${host_dir}/port/uart_wrapper.c")
+	endif()
+
+endif()
+
+idf_component_register(SRCS ${COMPONENT_SRCS}
+	REQUIRES soc esp_event esp_netif esp_timer driver esp_wifi bt esp_http_client
+	EXCLUDE_SRCS ${EXCLUDE_COMPONENT_SRCS}
+	INCLUDE_DIRS ${COMPONENT_ADD_INCLUDEDIRS})
+
+idf_component_set_property(${COMPONENT_NAME} WHOLE_ARCHIVE TRUE)
+
+if(CONFIG_ESP_SDIO_HOST_INTERFACE)
+	idf_component_optional_requires(PRIVATE sdmmc)
+endif()
+
+# Required if using ESP-IDF without commit 6b6065de509b5de39e4655fd425bf96f43b365f7:
+# fix(driver_spi): fix p4 cache auto writeback during spi(dma) rx
+# if(CONFIG_IDF_TARGET_ESP32P4 AND (CONFIG_ESP_SPI_HOST_INTERFACE OR CONFIG_ESP_SPI_HD_HOST_INTERFACE))
+# 	# used to workaround SPI transfer issue
+# 	idf_component_optional_requires(PRIVATE esp_mm)
+# endif()

+ 1018 - 0
esp-hosted/Kconfig

@@ -0,0 +1,1018 @@
+config ESP_HOSTED_ENABLED
+	bool
+	default y if ESP_WIFI_REMOTE_ENABLED && ESP_WIFI_REMOTE_LIBRARY_HOSTED
+	default n
+
+menu "ESP-Hosted config"
+	depends on ESP_HOSTED_ENABLED
+
+	choice ESP_HOST_INTERFACE
+		bool "Transport layer"
+		default ESP_SDIO_HOST_INTERFACE if IDF_TARGET_ESP32
+		default ESP_SDIO_HOST_INTERFACE if IDF_TARGET_ESP32P4
+		default ESP_SPI_HOST_INTERFACE
+		help
+			Bus interface to be used for communication with the host
+
+		config ESP_SPI_HOST_INTERFACE
+			bool "SPI Full-duplex"
+			help
+				Enable/Disable SPI Full-duplex host interface
+
+		config ESP_SDIO_HOST_INTERFACE
+			bool "SDIO"
+				depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
+			help
+				Enable/Disable SDIO host interface
+
+		# SPI Half Duplex is not supported in ESP32
+		config ESP_SPI_HD_HOST_INTERFACE
+			depends on !IDF_TARGET_ESP32
+			bool "SPI Half-duplex"
+			help
+				Enable/Disable SPI Half-duplex host interface
+
+		config ESP_UART_HOST_INTERFACE
+			bool "UART"
+			help
+				Enable/Disable UART host interface
+	endchoice
+
+	choice ESP_HOSTED_SLAVE_CHIPSET_USED
+		bool "Slave chipset to be used"
+		default SLAVE_CHIPSET_ESP32C6
+
+		config SLAVE_CHIPSET_ESP32
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SDIO_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32"
+
+		config SLAVE_CHIPSET_ESP32S2
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32S2"
+
+		config SLAVE_CHIPSET_ESP32S3
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32S3"
+
+		config SLAVE_CHIPSET_ESP32C2
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32C2"
+
+		config SLAVE_CHIPSET_ESP32C3
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32C3"
+
+		config SLAVE_CHIPSET_ESP32C6
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SDIO_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32C6"
+
+		config SLAVE_CHIPSET_ESP32C5
+			depends on ESP_SPI_HOST_INTERFACE || ESP_SPI_HD_HOST_INTERFACE || ESP_UART_HOST_INTERFACE
+			bool "Slave as ESP32C5"
+	endchoice
+
+	config IDF_SLAVE_TARGET
+		string
+		default "esp32" if SLAVE_CHIPSET_ESP32
+		default "esp32s2" if SLAVE_CHIPSET_ESP32S2
+		default "esp32s3" if SLAVE_CHIPSET_ESP32S3
+		default "esp32c2" if SLAVE_CHIPSET_ESP32C2
+		default "esp32c3" if SLAVE_CHIPSET_ESP32C3
+		default "esp32c6" if SLAVE_CHIPSET_ESP32C6
+		default "esp32c5" if SLAVE_CHIPSET_ESP32C5
+		default "invalid"
+
+	menu "Task defaults"
+		config ESP_RPC_TASK_STACK
+			int "RPC task stack size"
+			default 4096
+
+		config ESP_DFLT_TASK_STACK
+			int "Hosted default task size"
+			default 3072
+	endmenu
+
+	menu "SPI Configuration"
+		depends on ESP_SPI_HOST_INTERFACE
+
+		choice ESP_SPI_PRIV_MODE_ESP32
+			depends on SLAVE_CHIPSET_ESP32
+			bool "Host SPI mode"
+			default ESP_SPI_PRIV_MODE_2_ESP32
+
+			config ESP_SPI_PRIV_MODE_0_ESP32
+				bool "Host SPI mode 0"
+
+			config ESP_SPI_PRIV_MODE_1_ESP32
+				bool "Host SPI mode 1"
+
+			config ESP_SPI_PRIV_MODE_2_ESP32
+				bool "Host SPI mode 2"
+
+			config ESP_SPI_PRIV_MODE_3_ESP32
+				bool "Host SPI mode 3"
+		endchoice
+
+		choice ESP_SPI_PRIV_MODE_ESP32XX
+			depends on !SLAVE_CHIPSET_ESP32
+			bool "Host SPI mode"
+			default ESP_SPI_PRIV_MODE_3_ESP32XX
+
+			config ESP_SPI_PRIV_MODE_0_ESP32XX
+				bool "Host  SPI mode 0"
+
+			config ESP_SPI_PRIV_MODE_1_ESP32XX
+				bool "Host  SPI mode 1"
+
+			config ESP_SPI_PRIV_MODE_2_ESP32XX
+				bool "Host  SPI mode 2"
+
+			config ESP_SPI_PRIV_MODE_3_ESP32XX
+				bool "Host  SPI mode 3"
+		endchoice
+
+		config ESP_SPI_MODE
+			int
+			default 0 if ESP_SPI_PRIV_MODE_0_ESP32
+			default 1 if ESP_SPI_PRIV_MODE_1_ESP32
+			default 2 if ESP_SPI_PRIV_MODE_2_ESP32
+			default 3 if ESP_SPI_PRIV_MODE_3_ESP32
+			default 0 if ESP_SPI_PRIV_MODE_0_ESP32XX
+			default 1 if ESP_SPI_PRIV_MODE_1_ESP32XX
+			default 2 if ESP_SPI_PRIV_MODE_2_ESP32XX
+			default 3 if ESP_SPI_PRIV_MODE_3_ESP32XX
+
+		choice SPI_CONTROLLER
+			bool "Host SPI controller to use"
+			default SPI_HSPI
+
+			config SPI_HSPI
+				bool "HSPI/FSPI"
+				help
+					"HSPI/FSPI: SPI_controller_1"
+
+			config SPI_VSPI
+				depends on IDF_TARGET_ESP32
+				bool "VSPI"
+				help
+					"VSPI: SPI_controller_2"
+
+		endchoice
+
+		config ESP_SPI_CONTROLLER
+			int
+			default 2 if SPI_VSPI
+			default 1
+
+		menu "Host SPI GPIOs Config"
+
+			choice SPI_HANDSHAKE_GPIO_CONFIG
+				bool "Handshake GPIO Config"
+				default HS_ACTIVE_HIGH
+
+				config HS_ACTIVE_HIGH
+					bool "HS: Active High"
+				config HS_ACTIVE_LOW
+					bool "HS: Active Low"
+			endchoice
+
+			choice SPI_DATAREADY__GPIO_CONFIG
+				bool "DataReady GPIO Config"
+				default DR_ACTIVE_HIGH
+
+				config DR_ACTIVE_HIGH
+					bool "DR: Active High"
+				config DR_ACTIVE_LOW
+					bool "DR: Active Low"
+			endchoice
+
+			config ESP_SPI_HSPI_GPIO_MOSI
+				depends on SPI_HSPI
+				int "GPIO pin for Host MOSI"
+				default 14 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 13 if IDF_TARGET_ESP32
+				default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+				default 7
+				help
+					SPI controller Host MOSI
+
+			config ESP_SPI_HSPI_GPIO_MISO
+				depends on SPI_HSPI
+				int "GPIO pin for Host MISO"
+				default 15 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 12 if IDF_TARGET_ESP32
+				default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+				default 2
+				help
+					SPI controller Host MISO
+
+			config ESP_SPI_HSPI_GPIO_CLK
+				depends on SPI_HSPI
+				int "GPIO pin for Host CLK"
+				default 18 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 14 if IDF_TARGET_ESP32
+				default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+				default 6
+				help
+					SPI controller Host CLK
+
+			config ESP_SPI_HSPI_GPIO_CS
+				depends on SPI_HSPI
+				int "GPIO pin for Host  CS"
+				default 19 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 15 if IDF_TARGET_ESP32
+				default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+				default 10
+				help
+					SPI controller Host CS
+
+			config ESP_SPI_VSPI_GPIO_MOSI
+				depends on SPI_VSPI
+				int "GPIO pin for Host MOSI"
+				default 23
+				help
+					SPI controller Host MOSI
+
+			config ESP_SPI_VSPI_GPIO_MISO
+				depends on SPI_VSPI
+				int "GPIO pin for Host MISO"
+				default 19
+				help
+					SPI controller Host MISO
+
+			config ESP_SPI_VSPI_GPIO_CLK
+				depends on SPI_VSPI
+				int "GPIO pin for Host CLK"
+				default 18
+				help
+					SPI controller Host CLK
+
+			config ESP_SPI_VSPI_GPIO_CS
+				depends on SPI_VSPI
+				int "GPIO pin for Host CS"
+				default 5
+				help
+					SPI controller Host CS
+
+			config ESP_SPI_GPIO_MOSI
+				int
+				default ESP_SPI_VSPI_GPIO_MOSI if SPI_VSPI
+				default ESP_SPI_HSPI_GPIO_MOSI
+
+			config ESP_SPI_GPIO_MISO
+				int
+				default ESP_SPI_VSPI_GPIO_MISO if SPI_VSPI
+				default ESP_SPI_HSPI_GPIO_MISO
+
+			config ESP_SPI_GPIO_CLK
+				int
+				default ESP_SPI_VSPI_GPIO_CLK if SPI_VSPI
+				default ESP_SPI_HSPI_GPIO_CLK
+
+			config ESP_SPI_GPIO_CS
+				int
+				default ESP_SPI_VSPI_GPIO_CS if SPI_VSPI
+				default ESP_SPI_HSPI_GPIO_CS
+
+			config ESP_SPI_GPIO_HANDSHAKE
+				int "GPIO pin for handshake"
+				default 16 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 3 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C6
+				default 17 if IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32S2
+				default 26
+				help
+					GPIO pin to use for handshake with other spi controller
+
+			config ESP_SPI_GPIO_DATA_READY
+				int "GPIO pin for data ready interrupt"
+				default 17 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 4
+				help
+					GPIO pin for indicating host that SPI slave has data to be read by host
+
+			config ESP_SPI_GPIO_RESET_SLAVE
+				int "GPIO pin for Reseting slave ESP"
+				default 54 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 5
+				help
+					GPIO pin for Resetting ESP SPI slave device. Should be connected to RST/EN of ESP SPI slave device.
+		endmenu
+
+ESP32XX_SPI_CLK_FREQ_RANGE_MIN := 1
+ESP32_SPI_CLK_FREQ_RANGE_MAX := 10
+ESP32C6_SPI_CLK_FREQ_RANGE_MAX := 26
+ESP32XX_SPI_CLK_FREQ_RANGE_MAX := 40
+
+	config ESP_SPI_FREQ_ESP32
+		depends on SLAVE_CHIPSET_ESP32
+		int "SPI Clock Freq (MHz)"
+		default 10
+		range $(ESP32XX_SPI_CLK_FREQ_RANGE_MIN) $(ESP32_SPI_CLK_FREQ_RANGE_MAX)
+		help
+			"Optimize SPI CLK by increasing till host practically can support"
+
+	config ESP_SPI_FREQ_ESP32C6
+		depends on SLAVE_CHIPSET_ESP32C6
+		int "SPI Clock Freq (MHz)"
+		default 10 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+		default 26
+		range $(ESP32XX_SPI_CLK_FREQ_RANGE_MIN) $(ESP32C6_SPI_CLK_FREQ_RANGE_MAX)
+		help
+			"Optimize SPI CLK by increasing till host practically can support"
+
+	config ESP_SPI_FREQ_ESP32XX
+		depends on SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+		int "SPI Clock Freq"
+		default 30 if SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+		range $(ESP32XX_SPI_CLK_FREQ_RANGE_MIN) $(ESP32XX_SPI_CLK_FREQ_RANGE_MAX)
+		help
+			"Optimize SPI CLK by increasing till host practically can support"
+
+	config ESP_SPI_CLK_FREQ
+		int
+		default ESP_SPI_FREQ_ESP32 if SLAVE_CHIPSET_ESP32
+		default ESP_SPI_FREQ_ESP32C6 if SLAVE_CHIPSET_ESP32C6
+		default ESP_SPI_FREQ_ESP32XX if SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+		help
+			"Optimize SPI CLK by increasing till host practically can support"
+
+		config ESP_SPI_TX_Q_SIZE
+			int "ESP to Host SPI queue size"
+			default 20
+			help
+				Very small tx queue will lower ESP -- SPI --> Host data rate
+
+		config ESP_SPI_RX_Q_SIZE
+			int "Host to ESP SPI queue size"
+			default 20
+			help
+				Very small RX queue will lower ESP <-- SPI -- Host data rate
+
+	endmenu
+
+		menu "Hosted SDIO Configuration"
+			depends on ESP_SDIO_HOST_INTERFACE
+
+			choice SDIO_RESET_GPIO_CONFIG
+				bool "RESET GPIO Config"
+				default SDIO_RESET_ACTIVE_HIGH
+				help
+					"If Active High, High->Low->High will trigger reset (Low will trigger reset)
+					 If Active Low, Low->High->Low will trigger reset (High will trigger reset)"
+
+				config SDIO_RESET_ACTIVE_HIGH
+					bool "RESET: Active High"
+				config SDIO_RESET_ACTIVE_LOW
+					bool "RESET: Active Low"
+			endchoice
+
+			choice ESP_SDIO_RX_OPTIMIZATION
+				bool "SDIO Receive Optimization"
+				default ESP_SDIO_OPTIMIZATION_RX_STREAMING_MODE
+
+				config ESP_SDIO_OPTIMIZATION_RX_NONE
+					bool "No optimization"
+					help
+						Use SDIO as is, with no optimizations.
+
+				config ESP_SDIO_OPTIMIZATION_RX_MAX_SIZE
+					bool "Always Rx Max Packet size"
+					help
+						Always read max Rx Packet Size (512 * 3 bytes). This saves one SDIO
+						transaction (get Rx Packet Size) when reading data from slave by
+						always transferring a fixed amount of data. Extra data at end of valid
+						packet data is discarded.
+
+				config ESP_SDIO_OPTIMIZATION_RX_STREAMING_MODE
+					bool "Use Streaming Mode"
+					help
+						Receive a stream of queued data from the slave, made up of one or more
+						packets of data. Host extracts packets from the stream. This improves
+						SDIO read performance by doing one large read transaction instead of
+						many smaller read transactions for each packet.
+						(Note: requires slave to support streaming mode.)
+
+				endchoice
+
+			config ESP_SDIO_GPIO_RESET_SLAVE
+				int "GPIO pin for Reseting slave ESP"
+				default 54 if IDF_TARGET_ESP32P4
+				default 42 if IDF_TARGET_ESP32S3
+				default 5
+				help
+					GPIO pin for Resetting ESP SDIO slave device. Should be connected to RST/EN of ESP SDIO slave device.
+
+			choice
+				prompt "SDIO Bus Width"
+				default ESP_SDIO_4_BIT_BUS
+				help
+					Select the SDIO Bus Width to use
+
+				config ESP_SDIO_4_BIT_BUS
+					bool "4 Bits"
+
+				config ESP_SDIO_1_BIT_BUS
+					bool "1 Bit"
+			endchoice
+
+			config ESP_SDIO_BUS_WIDTH
+				int
+				default 1 if ESP_SDIO_1_BIT_BUS
+				default 4
+
+ESP32_SDIO_CLK_FREQ_KHZ_RANGE_MIN := 400
+ESP32_SDIO_CLK_FREQ_KHZ_RANGE_MAX := 40000
+ESP32XX_SDIO_CLK_FREQ_KHZ_RANGE_MIN := 400
+ESP32XX_SDIO_CLK_FREQ_KHZ_RANGE_MAX := 80000
+
+			config ESP_SDIO_CLOCK_FREQ_KHZ
+				int "SDIO Clock Freq (in kHz)"
+				default 40000
+				range $(ESP32_SDIO_CLK_FREQ_KHZ_RANGE_MIN) $(ESP32_SDIO_CLK_FREQ_KHZ_RANGE_MAX) if IDF_TARGET_ESP32
+				range $(ESP32XX_SDIO_CLK_FREQ_KHZ_RANGE_MIN) $(ESP32XX_SDIO_CLK_FREQ_KHZ_RANGE_MAX) if IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32P4
+				help
+					"Optimize SDIO CLK by increasing till host practically can support"
+
+			config ESP_SDIO_PIN_CMD
+				int "CMD GPIO number"
+				default 47 if IDF_TARGET_ESP32S3
+				default 19 if IDF_TARGET_ESP32P4
+				range 15 15 if IDF_TARGET_ESP32
+				help
+					"Value can only be configured for some targets. Displayed always for reference."
+
+			config ESP_SDIO_PIN_CLK
+				int "CLK GPIO number"
+				default 19 if IDF_TARGET_ESP32S3
+				default 18 if IDF_TARGET_ESP32P4
+				range 14 14 if IDF_TARGET_ESP32
+				help
+					"Value can only be configured for some targets. Displayed always for reference."
+
+			config ESP_SDIO_PIN_D0
+				int "D0 GPIO number"
+				default 13 if IDF_TARGET_ESP32S3
+				default 14 if IDF_TARGET_ESP32P4
+				range 2 2 if IDF_TARGET_ESP32
+				help
+					"Value can only be configured for some targets. Displayed always for reference."
+
+			if ESP_SDIO_4_BIT_BUS
+				config ESP_SDIO_PIN_D1
+					int "D1 GPIO number"
+					default 35 if IDF_TARGET_ESP32S3
+					default 15 if IDF_TARGET_ESP32P4
+					range 4 4 if IDF_TARGET_ESP32
+					help
+						"Value can only be configured for some targets. Displayed always for reference."
+
+				config ESP_SDIO_PIN_D2
+					int "D2 GPIO number"
+					default 20 if IDF_TARGET_ESP32S3
+					default 16 if IDF_TARGET_ESP32P4
+					range 12 12 if IDF_TARGET_ESP32
+					help
+						"Value can only be configured for some targets. Displayed always for reference."
+
+				config ESP_SDIO_PIN_D3
+					int "D3 GPIO number"
+					default 9 if IDF_TARGET_ESP32S3
+					default 17 if IDF_TARGET_ESP32P4
+					range 13 13 if IDF_TARGET_ESP32
+					help
+						"Value can only be configured for some targets. Displayed always for reference."
+			endif
+
+			if !ESP_SDIO_4_BIT_BUS
+				config ESP_SDIO_PIN_D1
+					int "D1 GPIO number (Interrupt Line)"
+					default 35 if IDF_TARGET_ESP32S3
+					default 15 if IDF_TARGET_ESP32P4
+					range 4 4 if IDF_TARGET_ESP32
+					help
+						"Value can only be configured for some targets. Displayed always for reference."
+			endif
+
+
+			config ESP_SDIO_TX_Q_SIZE
+				int "Host SDIO Tx queue size"
+				default 20
+				help
+					Very small tx queue will lower data rate
+
+			config ESP_SDIO_RX_Q_SIZE
+				int "Host SDIO Rx queue size"
+				default 20
+				help
+					Very small RX queue will lower data rate
+
+			config ESP_SDIO_CHECKSUM
+				bool "SDIO checksum ENABLE/DISABLE"
+				help
+					ENABLE/DISABLE software SDIO checksum
+		endmenu
+
+	menu "SPI Half-duplex Configuration"
+		depends on ESP_SPI_HD_HOST_INTERFACE
+
+		config ESP_SPI_HD_MODE
+			int "SPI Mode to use"
+			default 3
+			range 0 3
+			help
+				SPI Mode to use. The same mode must be used on both host and slave.
+
+		choice ESP_SPI_HD_PRIV_INTERFACE_NUM_DATA_LINES
+			bool "Num Data Lines to use"
+			default ESP_SPI_HD_PRIV_INTERFACE_4_DATA_LINES
+			help
+				Number of Data Lines to use in the SPI HD interface
+
+			config ESP_SPI_HD_PRIV_INTERFACE_4_DATA_LINES
+				bool "4 data lines"
+
+			config ESP_SPI_HD_PRIV_INTERFACE_2_DATA_LINES
+				bool "2 data lines"
+		endchoice
+
+		config ESP_SPI_HD_INTERFACE_NUM_DATA_LINES
+			int
+			default 4 if ESP_SPI_HD_PRIV_INTERFACE_4_DATA_LINES
+			default 2 if ESP_SPI_HD_PRIV_INTERFACE_2_DATA_LINES
+
+		choice SPI_HD_RESET_GPIO_CONFIG
+			bool "RESET GPIO Config"
+			default SPI_HD_RESET_ACTIVE_HIGH
+			help
+				"If Active High, High->Low->High will trigger reset (Low will trigger reset)
+				 If Active Low, Low->High->Low will trigger reset (High will trigger reset)"
+
+			config SPI_HD_RESET_ACTIVE_HIGH
+				bool "RESET: Active High"
+			config SPI_HD_RESET_ACTIVE_LOW
+				bool "RESET: Active Low"
+		endchoice
+
+		choice SPI_HD_DATAREADY_GPIO_CONFIG
+			bool "DataReady GPIO Config"
+			default SPI_HD_DR_ACTIVE_HIGH
+
+			config SPI_HD_DR_ACTIVE_HIGH
+				bool "DR: Active High"
+			config SPI_HD_DR_ACTIVE_LOW
+				bool "DR: Active Low"
+		endchoice
+
+		menu "Host GPIOs Config"
+			config ESP_SPI_HD_GPIO_CS
+				int "GPIO pin for Host CS"
+				default 10 if IDF_TARGET_ESP32S3
+				default 19 if IDF_TARGET_ESP32P4
+				default 15
+				help
+					SPI Half-duplex controller Host CS
+
+			config ESP_SPI_HD_GPIO_CLK
+				int "GPIO pin for Host CLK"
+				default 12 if IDF_TARGET_ESP32S3
+				default 18 if IDF_TARGET_ESP32P4
+				default 18
+				help
+					SPI Half-duplex controller Host CLK
+
+			config ESP_SPI_HD_GPIO_D0
+				int "GPIO pin for Host D0"
+				default 11 if IDF_TARGET_ESP32S3
+				default 14 if IDF_TARGET_ESP32P4
+				default 2
+				help
+					SPI Half-duplex controller Host D0
+
+			config ESP_SPI_HD_GPIO_D1
+				int "GPIO pin for Host D1"
+				default 13 if IDF_TARGET_ESP32S3
+				default 15 if IDF_TARGET_ESP32P4
+				default 4
+				help
+					SPI Half-duplex controller Host D1
+
+			config ESP_SPI_HD_GPIO_D2
+				depends on ESP_SPI_HD_PRIV_INTERFACE_4_DATA_LINES
+				int "GPIO pin for Host D2"
+				default 14 if IDF_TARGET_ESP32S3
+				default 16 if IDF_TARGET_ESP32P4
+				default 12
+				help
+					SPI Half-duplex controller Host D2
+
+			config ESP_SPI_HD_GPIO_D3
+				depends on ESP_SPI_HD_PRIV_INTERFACE_4_DATA_LINES
+				int "GPIO pin for Host D3"
+				default 9 if IDF_TARGET_ESP32S3
+				default 17 if IDF_TARGET_ESP32P4
+				default 13
+				help
+					SPI Half-duplex controller Host D3
+
+			config ESP_SPI_HD_GPIO_DATA_READY
+				int "GPIO pin for data ready interrupt"
+				default 4 if IDF_TARGET_ESP32S3
+				default 6 if IDF_TARGET_ESP32P4
+				default 8
+				help
+					GPIO pin for indicating host that slave has data to be read by host
+
+			config ESP_SPI_HD_GPIO_RESET_SLAVE
+				int "GPIO pin for Reseting slave ESP"
+				default 5 if IDF_TARGET_ESP32S3
+				default 54 if IDF_TARGET_ESP32P4 && SLAVE_CHIPSET_ESP32C6
+				default 5
+				help
+					GPIO pin for Resetting ESP slave device. Should be connected to RST/EN of ESP SPI slave device.
+		endmenu
+
+ESP32XX_SPI_HD_CLK_FREQ_RANGE_MIN := 1
+ESP32_SPI_HD_CLK_FREQ_RANGE_MAX := 10
+ESP32C6_SPI_HD_CLK_FREQ_RANGE_MAX := 40
+ESP32XX_SPI_HD_CLK_FREQ_RANGE_MAX := 40
+
+		config ESP_SPI_HD_FREQ_ESP32C6
+			depends on SLAVE_CHIPSET_ESP32C6
+			int "SPI HD Clock Freq (MHz)"
+			default 10
+			range $(ESP32XX_SPI_HD_CLK_FREQ_RANGE_MIN) $(ESP32C6_SPI_HD_CLK_FREQ_RANGE_MAX)
+			help
+				"Optimize CLK by increasing till host practically can support"
+
+		config ESP_SPI_HD_FREQ_ESP32XX
+			depends on SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+			int "SPI HD Clock Freq (MHz)"
+			default 10 if SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+			range $(ESP32XX_SPI_HD_CLK_FREQ_RANGE_MIN) $(ESP32XX_SPI_HD_CLK_FREQ_RANGE_MAX)
+			help
+				"Optimize CLK by increasing till host practically can support"
+
+		config ESP_SPI_HD_CLK_FREQ
+			int
+			default ESP_SPI_HD_FREQ_ESP32C6 if SLAVE_CHIPSET_ESP32C6
+			default ESP_SPI_HD_FREQ_ESP32XX if SLAVE_CHIPSET_ESP32C2 || SLAVE_CHIPSET_ESP32C3 || SLAVE_CHIPSET_ESP32S2 || SLAVE_CHIPSET_ESP32S3 || SLAVE_CHIPSET_ESP32C5
+			help
+				"Optimize CLK by increasing till host practically can support"
+
+		config ESP_SPI_HD_TX_Q_SIZE
+			int "ESP to Host queue size"
+			default 20
+			help
+				Very small tx queue will lower ESP -- SPI Half-duplex --> Host data rate
+
+		config ESP_SPI_HD_RX_Q_SIZE
+			int "Host to ESP queue size"
+			default 20
+			help
+				Very small RX queue will lower ESP <-- SPI Half-duplex -- Host data rate
+
+		config ESP_SPI_HD_CHECKSUM
+				bool "Checksum ENABLE/DISABLE"
+				default y
+				help
+					ENABLE/DISABLE software checksum
+	endmenu
+
+	menu "UART Configuration"
+		depends on ESP_UART_HOST_INTERFACE
+
+		choice ESP_UART_RESET_GPIO_CONFIG
+			bool "RESET GPIO Config"
+			default ESP_UART_RESET_ACTIVE_HIGH
+			help
+				"If Active High, High->Low->High will trigger reset (Low will trigger reset)
+				 If Active Low, Low->High->Low will trigger reset (High will trigger reset)"
+
+			config ESP_UART_RESET_ACTIVE_HIGH
+				bool "RESET: Active High"
+			config ESP_UART_RESET_ACTIVE_LOW
+				bool "RESET: Active Low"
+		endchoice
+
+		config ESP_UART_PORT
+			int "UART Port to Use"
+			default 1
+			range 0 2 if IDF_TARGET_ESP32
+			range 0 1 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C5 || IDF_TARGET_ESP32C6
+			range 0 2 if IDF_TARGET_ESP32C61
+			range 0 1 if IDF_TARGET_ESP32S2
+			range 0 2 if IDF_TARGET_ESP32S3
+			range 0 4 if IDF_TARGET_ESP32P4
+			help
+				Select UART Port to Use. Do not select the UART Port used for console output (if enabled)
+
+		config ESP_UART_PIN_TX
+			int "TX GPIO number"
+			default 13 if IDF_TARGET_ESP32
+			default 5 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
+			default 14 if IDF_TARGET_ESP32C5
+			default 21 if IDF_TARGET_ESP32C6
+			default 5 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+			default 14 if IDF_TARGET_ESP32P4
+			help
+				GPIO used for UART TX
+
+		config ESP_UART_PIN_RX
+			int "RX GPIO number"
+			default 12 if IDF_TARGET_ESP32
+			default 4 if IDF_TARGET_ESP32C2 || IDF_TARGET_ESP32C3
+			default 13 if IDF_TARGET_ESP32C5
+			default 20 if IDF_TARGET_ESP32C6
+			default 4 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
+			default 15 if IDF_TARGET_ESP32P4
+			help
+				GPIO used for UART RX
+
+		config ESP_UART_BAUDRATE
+			int "Baud Rate"
+			default 921600
+			range 9600 3500000
+			help
+				Baud Rate to Use. Make sure Hardware supports the rate. Standard rates are 9600, 19200, 38400, 57600, 115200, 460800, 921600
+
+		config ESP_UART_NUM_DATA_BITS
+			int "Number of Data Bits"
+			default 8
+			range 5 8
+			help
+				Number of Data Bits to use
+
+		choice ESP_UART_PRIV_PARITY
+			bool "Parity"
+
+			config ESP_UART_PRIV_PARITY_NONE
+				bool "None"
+
+			config ESP_UART_PRIV_PARITY_EVEN
+				bool "Even"
+
+			config ESP_UART_PRIV_PARITY_ODD
+				bool "Odd"
+		endchoice
+
+		config ESP_UART_PARITY
+			int
+			default 0 if ESP_UART_PRIV_PARITY_NONE
+			default 1 if ESP_UART_PRIV_PARITY_EVEN
+			default 2 if ESP_UART_PRIV_PARITY_ODD
+
+		choice ESP_UART_PRIV_STOP_BITS
+			bool "Number of Stop Bits"
+
+			config ESP_UART_PRIV_STOP_BITS_1
+				bool "1"
+
+			config ESP_UART_PRIV_STOP_BITS_1_5
+				bool "1.5"
+
+			config ESP_UART_PRIV_STOP_BITS_2
+				bool "2"
+		endchoice
+
+		config ESP_UART_STOP_BITS
+			int
+			default 0 if ESP_UART_PRIV_STOP_BITS_1
+			default 1 if ESP_UART_PRIV_STOP_BITS_1_5
+			default 2 if ESP_UART_PRIV_STOP_BITS_2
+
+		config ESP_UART_GPIO_RESET_SLAVE
+			int "GPIO pin for Reseting slave ESP"
+			default 54 if IDF_TARGET_ESP32P4
+			default 42 if IDF_TARGET_ESP32S3
+			default 5
+			help
+				GPIO pin for Resetting ESP SDIO slave device. Should be connected to RST/EN of ESP SDIO slave device.
+
+		config ESP_UART_TX_Q_SIZE
+			int "Tx Queue Size"
+			default 5
+			help
+				UART rates are low, so large queue sizes are not required
+
+		config ESP_UART_RX_Q_SIZE
+			int "Rx Queue Size"
+			default 5
+			help
+				UART rates are low, so large queue sizes are not required
+
+		config ESP_UART_CHECKSUM
+			bool "UART checksum ENABLE/DISABLE"
+			default y
+			help
+				ENABLE/DISABLE software UART checksum
+	endmenu
+
+		config ESP_GPIO_SLAVE_RESET_SLAVE
+			int
+			default ESP_SPI_GPIO_RESET_SLAVE if ESP_SPI_HOST_INTERFACE
+			default ESP_SDIO_GPIO_RESET_SLAVE if ESP_SDIO_HOST_INTERFACE
+			default ESP_SPI_HD_GPIO_RESET_SLAVE if ESP_SPI_HD_HOST_INTERFACE
+			default ESP_UART_GPIO_RESET_SLAVE if ESP_UART_HOST_INTERFACE
+
+		config RESET_GPIO_ACTIVE_LOW
+			bool
+			default n if SDIO_RESET_ACTIVE_HIGH || SPI_RESET_ACTIVE_HIGH || SPI_HD_RESET_ACTIVE_HIGH || ESP_UART_RESET_ACTIVE_HIGH
+			default y if SDIO_RESET_ACTIVE_LOW || SPI_RESET_ACTIVE_LOW || SPI_HD_RESET_ACTIVE_LOW || ESP_UART_RESET_ACTIVE_LOW
+
+	menu "Bluetooth Support"
+
+		comment "Following options must be set before this option can be enabled"
+			depends on !BT_ENABLED || BT_CONTROLLER_ONLY || (BT_NIMBLE_ENABLED && (BT_NIMBLE_TRANSPORT_UART || BT_CONTROLLER_ENABLED)) || (BT_BLUEDROID_ENABLED && BT_CONTROLLER_ENABLED)
+
+		comment "'Component config->Bluetooth' must be enabled"
+			depends on !BT_ENABLED
+
+		comment "'Component config->Bluetooth->Host' must be enabled"
+			depends on BT_ENABLED && BT_CONTROLLER_ONLY
+
+		comment "'Component config->Bluetooth->Controller' must be disabled"
+			depends on BT_ENABLED && BT_CONTROLLER_ENABLED
+
+		comment "'Component config->Bluetooth->NimBLE Options->Host-controller Transport->Uart Transport' must be disabled"
+			depends on BT_NIMBLE_ENABLED && BT_NIMBLE_TRANSPORT_UART
+
+		if BT_ENABLED && BT_BLUEDROID_ENABLED && !BT_CONTROLLER_ENABLED
+			config ESP_ENABLE_BT_BLUEDROID
+				bool "Enable Hosted Bluedroid Bluetooth support"
+				default n
+				help
+					Enable Bluetooth Support for Bluedroid via Hosted
+
+			choice ESP_BLUEDROID_HCI_TYPE
+				bool "BT Bluedroid HCI Type"
+				default ESP_BLUEDROID_HCI_VHCI
+				depends on ESP_ENABLE_BT_BLUEDROID
+				help
+					Selects the HCI to use
+
+				config ESP_BLUEDROID_HCI_VHCI
+					bool "VHCI"
+					help
+						Bluetooth data is sent through the selected transport layer
+			endchoice
+		endif
+
+		if BT_ENABLED && BT_NIMBLE_ENABLED && !BT_CONTROLLER_ENABLED && !BT_NIMBLE_TRANSPORT_UART
+			config ESP_ENABLE_BT_NIMBLE
+				bool "Enable Hosted Nimble Bluetooth support"
+				default n
+				help
+					Enable Bluetooth Support via Hosted
+
+			choice ESP_NIMBLE_HCI_TYPE
+				bool "BT Nimble HCI Type"
+				default ESP_NIMBLE_HCI_VHCI
+				depends on ESP_ENABLE_BT_NIMBLE
+				help
+					Selects the HCI to use
+
+				config ESP_NIMBLE_HCI_VHCI
+					bool "VHCI"
+					help
+						Bluetooth data is sent through the selected transport layer
+			endchoice
+		endif
+	endmenu
+
+	config ESP_USE_MEMPOOL
+		bool "Cache allocated memory like mempool - helps to reduce malloc calls"
+		default y
+		help
+			Cache allocated memory - reduces number of malloc calls
+
+	config ESP_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS
+		int "Maximum number of simultaneous synchronous RPC Request"
+		default 5
+		help
+			Sets the maximum number of simultaneous synchronous RPC Requests.
+			(Synchronous RPC Request: each sending task waits for the response.)
+			Usually, the host application may send up to 3 simultaneous RPC requests to the slave.
+			Increase this number if you need to send more simultaneous RPC requests.
+			Note: the slave will only process one RPC request (sync and async) at a time
+
+	config ESP_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS
+		int "Maximum number of simultaneous asynchronous RPC Request"
+		default 5
+		help
+			Sets the maximum number of simultaneous asynchronous RPC Requests.
+			(Asynchronous RPC Request: each sending task registers a callback to get the response.)
+			Usually, the host application may send up to 3 simultaneous RPC requests to the slave.
+			Increase this number if you need to send more simultaneous RPC requests.
+			Note: the slave will only process one RPC request (sync and async) at a time
+
+	menu "Debug Settings"
+
+		config ESP_RAW_THROUGHPUT_TRANSPORT
+			bool "RawTP: Transport level throughput debug test"
+			default n
+				help
+					Find max transport performance which helps to assess stability of porting done
+
+		choice ESP_RAW_THROUGHPUT_DIRECTION
+			bool "RawTP: Send data from:"
+			depends on ESP_RAW_THROUGHPUT_TRANSPORT
+
+			config ESP_RAW_THROUGHPUT_TX_TO_SLAVE
+				bool "Host to Slave"
+				help
+					Sends data from Host to Slave
+
+			config ESP_RAW_THROUGHPUT_RX_FROM_SLAVE
+				bool "Slave to Host"
+				help
+					Sends data from Slave to Slave
+
+			config ESP_RAW_THROUGHPUT_BIDIRECTIONAL
+				bool "Bidirectional"
+				help
+					Sends data in both directions
+		endchoice
+
+		config ESP_RAW_TP_HOST_TO_ESP_PKT_LEN
+			depends on ESP_RAW_THROUGHPUT_TRANSPORT
+			int "RawTP: Host to ESP packet size"
+			range 1 1500
+			default 1460
+
+		config ESP_RAW_TP_REPORT_INTERVAL
+			depends on ESP_RAW_THROUGHPUT_TRANSPORT
+			int "RawTP: periodic duration to report stats accumulated"
+			default 5
+
+		config ESP_PKT_STATS
+			bool "Transport level packet stats"
+			default n
+			help
+				On comparing with slave packet stats helps to understand any packet loss at hosted
+
+	endmenu
+
+	menu "Data path options"
+		config HOST_TO_ESP_WIFI_DATA_THROTTLE
+			bool "Report WiFi queue utilization to host"
+			default y
+			help
+				Proactively drop Host->slave Wi-Fi data when Slave Wi-Fi is under load
+				Slave Wi-Fi may drop ingress bursty or higher than capacity packets.
+				To have synchronous way of packet dropped for application,
+				Host will throttle incoming data if the slave datapath Rx load is high
+
+		config PRIV_WIFI_TX_SPI_HIGH_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE && ESP_SPI_HOST_INTERFACE
+			int "High threshold to report host to drop data when wifi highly loaded"
+			range 0 100
+			default 90
+			help
+				Host will throttle incoming data if the slave datapath Rx load goes beyond this threshold
+				0 value will disable this function
+
+		config PRIV_WIFI_TX_SDIO_HIGH_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE && ESP_SDIO_HOST_INTERFACE
+			int "High threshold to report host to drop data when wifi highly loaded"
+			range 0 100
+			default 80
+			help
+				Host will throttle incoming data if the slave datapath Rx load goes beyond this threshold
+				0 value will disable this function
+
+		config PRIV_WIFI_TX_SPI_HD_HIGH_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE && ESP_SPI_HD_HOST_INTERFACE
+			int "High threshold to report host to drop data when wifi highly loaded"
+			range 0 100
+			default 80
+			help
+				Host will throttle incoming data if the slave datapath Rx load goes beyond this threshold
+				0 value will disable this function
+
+		config PRIV_WIFI_TX_UART_HIGH_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE && ESP_UART_HOST_INTERFACE
+			int "High threshold to report host to drop data when wifi highly loaded"
+			range 0 100
+			default 80
+			help
+				Host will throttle incoming data if the slave datapath Rx load goes beyond this threshold
+				0 value will disable this function
+
+		config TO_WIFI_DATA_THROTTLE_HIGH_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE
+			int
+			default PRIV_WIFI_TX_SPI_HIGH_THRESHOLD if ESP_SPI_HOST_INTERFACE
+			default PRIV_WIFI_TX_SDIO_HIGH_THRESHOLD if ESP_SDIO_HOST_INTERFACE
+			default PRIV_WIFI_TX_SPI_HD_HIGH_THRESHOLD if ESP_SPI_HD_HOST_INTERFACE
+			default PRIV_WIFI_TX_UART_HIGH_THRESHOLD if ESP_UART_HOST_INTERFACE
+
+		config TO_WIFI_DATA_THROTTLE_LOW_THRESHOLD
+			depends on HOST_TO_ESP_WIFI_DATA_THROTTLE
+			int "Low threshold to report host to stop dropping data"
+			range 0 TO_WIFI_DATA_THROTTLE_HIGH_THRESHOLD
+			default 60
+			help
+				Once the Wi-Fi is no more stressed, data throttling would be stopped, once slave Wi-Fi load
+				is lower than this threshold
+	endmenu
+endmenu

+ 21 - 32
esp-hosted/README.md

@@ -12,26 +12,10 @@ This high-level block diagram shows ESP-Hosted's relationship with the host MCU
 
 For detailed design diagrams in Wi-Fi and Bluetooth, refer to the following design documents:
 
-- [WiFi Design](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/wifi_design.md)
-- [Bluetooth Design](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/bluetooth_design.md)
+- [WiFi Design](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/wifi_design.md)
+- [Bluetooth Design](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/bluetooth_design.md)
 
-This branch, `feature/esp_as_mcu_host` is dedicated for any host as MCU support. If you are interested in Linux as host, please refer to [`master`](https://github.com/espressif/esp-hosted/blob/master) branch.
-
-## 1.1 STM32 Example
-
-ESP-Hosted has been [ported to the STM32H743ZIT6 (NUCLEO-H743ZI2 development board)](docs/host_port_stm32.md), communicating with an ESP32 as a co-processor. Some examples of ESP-Hosted running on the STM32 and using the ESP32 as a network co-processor are provided:
-
-- running iPerf in client / server mode with UDP / TCP
-- getting RSSI, firmware version, and AP BSSID
-- configuring Wi-Fi in STA and SoftAP modes
-- performing OTA update on the co-processor firmware
-- doing Wi-Fi scanning
-- basic Station mode (joining an AP)
-- using Ethernet with ESP-NETIF (an example of managing a network interface using ESP-NETIF, which is what ESP-Hosted uses). See [Making STM32 Ethernet Work With ESP-NETIF](docs/stm32_ethernet.md) for notes on getting the Ethernet interface working on the development board.
-
-### 1.1.1 Status of the STM32 Port
-
-See the [STM32 Status document](docs/stm32_status.md) to check the status of the STM32 port.
+`esp-hosted-mcu` is dedicated for any host as MCU support. If you are interested in Linux as host, please refer to the [`esp-hosted`](https://github.com/espressif/esp-hosted) repository.
 
 ## 2 Architecture
 
@@ -97,14 +81,13 @@ No worries if you don't have an ESP32-P4. In fact, most users don't. You can cho
 
 ### 5.1 ESP-Hosted-MCU Source Code
 
-- ESP-Hosted-MCU code can be found at Espressif Registry Component [`esp_hosted` (ESP-Hosted)](https://components.espressif.com/components/espressif/esp_hosted) or GitHub repo at [`ESP-Hosted`](https://github.com/espressif/esp-hosted/tree/feature/esp_as_mcu_host)
+- ESP-Hosted-MCU code can be found at Espressif Registry Component [`esp_hosted` (ESP-Hosted)](https://components.espressif.com/components/espressif/esp_hosted) or GitHub repo at [`esp-hosted-mcu`](https://github.com/espressif/esp-hosted-mcu/)
 
 - ESP-Hosted repo clone is **not** required if you have ESP as host.
   - Reason: [ESP component manager](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/tools/idf-component-manager.html) automatically clones esp-hosted component while building.
 - However, For non-ESP host development, you can clone the repo using command:
 ```bash
-git clone --recurse-submodules --branch feature/esp_as_mcu_host --depth 1 \
-https://github.com/espressif/esp-hosted esp_hosted_mcu
+git clone --recurse-submodules --depth 1 https://github.com/espressif/esp-hosted-mcu.git
 ```
 
 ### 5.2 Dependencies
@@ -118,7 +101,7 @@ ESP-Hosted-MCU Solution is dependent on `ESP-IDF`, `esp_wifi_remote` and `protob
 
 ###### Wi-Fi Remote
   - [`esp_wifi_remote`](https://components.espressif.com/components/espressif/esp_wifi_remote) i.e. 'Wi-Fi Remote' is very thin interface made up of ESP-IDF Wi-Fi APIs with empty weak definitions. Real definitions for these APIs are provided by ESP-Hosted-MCU
-  - Wi-Fi Remote Code can be found at either [GitHub Repo](https://github.com/espressif/esp-protocols/tree/master/components/esp_wifi_remote) or [Espressif Registry Component](https://components.espressif.com/components/espressif/esp_wifi_remote)
+  - Wi-Fi Remote Code can be found at either [GitHub Repo](https://github.com/espressif/esp-wifi-remote/) or [Espressif Registry Component](https://components.espressif.com/components/espressif/esp_wifi_remote)
 
 ###### Protobuf
   - [`protobuf-c`](https://github.com/protobuf-c/protobuf-c) is data serialization framework provided by Google. RPC messages communicated in host and slave are protobuf encoded.
@@ -237,7 +220,7 @@ Once you decided the transport to use, this section should guide how to set this
 
 > [!IMPORTANT]
 >
-> [Design Considerations](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/design_consideration.md) that could be reffered to, before you stick to any transport option. Referring to these consideration would help to get you faster to solution, make your design stable and less error-prone.
+> [Design Considerations](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/design_consideration.md) that could be referred to, before you stick to any transport option. Referring to these consideration would help to get you faster to solution, make your design stable and less error-prone.
 
 
 Irrespective of transport chosen, following steps are needed, which are step-wise explained in each transport.
@@ -254,24 +237,30 @@ Irrespective of transport chosen, following steps are needed, which are step-wis
   - Host flashing
   - Host logs
 
-- [**Standard SPI (Full duplex)**](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/spi_full_duplex.md)
+- [**Standard SPI (Full duplex)**](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/spi_full_duplex.md)
 
-- [**SPI - Dual / Quad Half Duplex**](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/spi_half_duplex.md)
+- [**SPI - Dual / Quad Half Duplex**](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/spi_half_duplex.md)
 
-- [**SDIO (1-Bit / 4-Bit)**](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/sdio.md)
+- [**SDIO (1-Bit / 4-Bit)**](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/sdio.md)
 
-- [**UART for Wi-Fi and Bluetooth**](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/uart.md)
+- [**UART for Wi-Fi and Bluetooth**](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/uart.md)
 
 ## 9 Examples
-Check [examples](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/examples) directory for sample applications using ESP-Hosted.
- - `examples/bleprph_host_only_vhci`
-   - Bluetooth without needing extra GPIOs
+Check [examples](https://github.com/espressif/esp-hosted-mcu/tree/main/examples) directory for sample applications using ESP-Hosted.
+ - `examples/host_bluedroid_ble_compatibility_test`
+   - host BlueDroid Bluetooth example to test the Bluetooth compatibility and mobile phones
+ - `examples/host_bluedroid_bt_hid_mouse_device`
+   - host BlueDroid Bluetooth example to show how to implement a Bluetooth HID device using the APIs provided by Classic Bluetooth HID profile
+ - `examples/host_bluedroid_host_only`
+   - host BlueDroid Bluetooth example Bluetooth Host using ESP-Hosted as HCI IO to the BT Controller
+ - `examples/host_nimble_bleprph_host_only_vhci`
+   - host NimBLE Bluetooth example without needing extra GPIOs for HCI transport
 
 ## 10 Troubleshooting
 
 If you encounter issues with using ESP-Hosted, see the following guide:
 
-- [Troubleshooting Guide](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/docs/troubleshooting.md)
+- [Troubleshooting Guide](https://github.com/espressif/esp-hosted-mcu/blob/main/docs/troubleshooting.md)
 
 ## 11 References
 

+ 271 - 47
esp-hosted/docs/bluetooth_design.md

@@ -3,64 +3,97 @@
 **Table of Contents**
 
 - [1. Introduction](#1-introduction)
+  - [1.1 Choosing a Bluetooth Host stack](#11-choosing-a-bluetooth-host-stack)
 - [2. Bluetooth Controller](#2-bluetooth-controller)
 - [3. Bluetooth Interface](#3-bluetooth-interface)
 - [4. NimBLE Host Stack](#4-nimble-host-stack)
-- [5. Transporting HCI data using vHCI](#5-transporting-hci-data-using-vhci)
-  - [5.1. Bluetooth Host vHCI Initialization](#51-bluetooth-host-vhci-initialization)
-  - [5.2. Bluetooth Host Sending Data through vHCI](#52-bluetooth-host-sending-data-through-vhci)
-  - [5.3. Bluetooth Host Receiving Data from vHCI](#53-bluetooth-host-receiving-data-from-vhci)
-- [6. Transporting HCI data using UART](#6-transporting-hci-data-using-uart)
-  - [6.1. Bluetooth Host HCI Initialization](#61-bluetooth-host-hci-initialization)
-  - [6.2. Bluetooth Host Sending Data using HCI](#62-bluetooth-host-sending-data-using-hci)
-  - [6.3. Bluetooth Host Receiving Data using HCI](#63-bluetooth-host-receiving-data-using-hci)
-- [7. References](#7-references)
+  - [4.1. Transporting HCI data using vHCI in NimBLE](#41-transporting-hci-data-using-vhci-in-nimble)
+    - [4.1.1. Bluetooth Host vHCI Initialization](#411-bluetooth-host-vhci-initialization)
+    - [4.1.2. Bluetooth Host Sending Data through vHCI in NimBLE](#412-bluetooth-host-sending-data-through-vhci-in-nimble)
+    - [4.1.3. Bluetooth Host Receiving Data from vHCI in NimBLE](#413-bluetooth-host-receiving-data-from-vhci-in-nimble)
+  - [4.2. Transporting HCI data using UART](#42-transporting-hci-data-using-uart)
+    - [4.2.1. Bluetooth Host HCI Initialization](#421-bluetooth-host-hci-initialization)
+    - [4.2.2. Bluetooth Host Sending Data using HCI](#422-bluetooth-host-sending-data-using-hci)
+    - [4.2.3. Bluetooth Host Receiving Data using HCI](#423-bluetooth-host-receiving-data-using-hci)
+- [5. BlueDroid Host Stack](#5-bluedroid-host-stack)
+  - [5.1. Transporting HCI data using vHCI in BlueDroid](#51-transporting-hci-data-using-vhci-in-bluedroid)
+    - [5.1.1. Bluetooth Host vHCI Initialization](#511-bluetooth-host-vhci-initialization)
+    - [5.1.2. Bluetooth Host Sending Data through vHCI in BlueDroid](#512-bluetooth-host-sending-data-through-vhci-in-bluedroid)
+    - [5.1.3. Bluetooth Host Receiving Data from vHCI in BlueDroid](#513-bluetooth-host-receiving-data-from-vhci-in-bluedroid)
+  - [5.2. Transporting HCI data using UART](#52-transporting-hci-data-using-uart)
+    - [5.2.1. Bluetooth Host HCI Initialization](#521-bluetooth-host-hci-initialization)
+    - [5.2.2. Bluetooth Host Sending Data using HCI](#522-bluetooth-host-sending-data-using-hci)
+    - [5.2.3. Bluetooth Host Receiving Data using HCI](#523-bluetooth-host-receiving-data-using-hci)
+- [6. References](#6-references)
 
 ## 1. Introduction
 
 ESP-Hosted can transport Bluetooth HCI packets between the Bluetooth
 Host on the Hosted Master and the Bluetooth Controller on the Hosted
-Slave. The Host MCU implement the Bluetooth app and Bluetooth Host
-Stack and the Slave runs the Bluetooth controller and hardware.
+Co-processor. The Host MCU implement the Bluetooth app and Bluetooth
+Host Stack and the co-processor runs the Bluetooth controller and
+hardware.
 
 > [!NOTE]
 > Check that the memory requirement for your preferred Bluetooth host
 > stack can be satisfied on the Host.
 
-ESP-Hosted has not preferred Bluetooth stack. To showcase ESP-Hosted's
-Bluetooth support, `esp-nimble` is used here. Users can use their own
-preferred Bluetooth stack with some porting effort.
+ESP-Hosted has is Bluetooth stack agnostic. To showcase ESP-Hosted's
+Bluetooth support, Both `esp-nimble` and `esp-bluedroid` are used
+here. Users can use their own preferred Bluetooth stack with some
+porting effort.
 
 `esp-nimble` is a fork of Apache NimBLE and available from
 ESP-IDF. The NimBLE Bluetooth slack proves Bluetooth Low Energy (BLE)
 only functionality.
 
+`esp-bluedroid` is a fork of the Bluedroid based stack and available
+from ESP-IDF. The BlueDroid stack supports classic Bluetooth as well
+as Bluetooth Low Energy.
+
 See [References](#7-references) for links with more information.
 
+### 1.1 Choosing a Bluetooth Host stack
+
+For usecases involving classic Bluetooth as well as Bluetooth Low
+Energy, BlueDroid should be used.
+
+For Bluetooth Low Energy-only usecases, using NimBLE is
+recommended. It is less demanding in terms of code footprint and
+runtime memory, making it suitable for such scenarios.
+
 ## 2. Bluetooth Controller
 
-ESP-Hosted uses the Bluetooth controller running on the slave. The Slave
-is expected to be configured to use BT Controller-only mode.
+ESP-Hosted uses the Bluetooth controller running on the
+co-processor. The co-processor is expected to be configured to use
+ESP-Hosted as the transport.
 
-As ESP-Hosted is just communication medium, it doesn't limit to BLE
-only. Classic BT stacks are also supported, given the slave has
-Classic-BT controller. The Classic-BT or BLE or both availability
-depends upon the Bluetooth stack support and ESP chipset chosen. As of
-today, ESP32 supports Classic-BT+BLE, whereas, the other ESP slave
-chipsets support BLE only.
+As ESP-Hosted is just the communication medium, it isn't limited to
+BLE only. Classic BT stacks are also supported, if the co-processor
+has a Classic-BT controller. The Classic-BT or BLE or both
+availability depends upon the Bluetooth stack support and ESP chipset
+chosen. As of today, ESP32 supports Classic-BT+BLE, whereas, the other
+ESP chipsets support BLE only.
 
 ## 3. Bluetooth Interface
 
 Hosted provides two ways to let the Bluetooth Host stack running on
-the Host to communicate with the Bluetooth controller on the Slave.
+the Host to communicate with the Bluetooth controller on the
+co-processor.
 
 **vHCI**
 
+vHCI works in shared mode. Bluetooth traffic is multiplexed with other
+traffic types on same bus, each with different Interface types. See
+the [traffic types](../README.md#72-interface-types) support
+by ESP-Hosted message headers.
+
 - vHCI is standard HCI with extra headers or metadata added
 - vHCI embeds the ESP-Hosted header and re-uses the underlying
   ESP-Hosted transport, such as SPI/SDIO
-- this option is easier to set up. Once the existing SPI or SDIO
-  transport has been set up, Bluetooth works
+- this option is easier to set up. Once the existing ESP-Hosted
+  Transport (SPI or SDIO, for example) has been set up, Bluetooth
+  just works
 
 Use this option if you want:
 
@@ -70,19 +103,24 @@ Use this option if you want:
 
 **Standard HCI**
 
+Standard HCI works in dedicated mode. Bluetooth traffic cannot be
+multiplexed with other traffic, so a dedicated transport is
+needed. Bluetooth HCI frames (without any hosted header) are
+transferred over the dedicated transport.
+
 - standard HCI is a transparent way of handling HCI messages
 - HCI messages originating from the Bluetooth stack on the Host are
-  sent through an interface (like UART) to the Bluetooth controller on
-  the Slave
+  sent through an interface (like UART) directly to the Bluetooth
+  controller on the co-processor.
 - requires extra GPIO for the HCI interface, independent of the GPIOs
   used for the ESP-Hosted interface
 
 Use this option if you want:
 
 - transparency: no extra data added to the HCI messages
-- portability: because it is standard HCI, you can replace the Slave
-  with any other co-processor (ESP or otherwise) that has a Bluetooth
-  controller
+- portability: because it is standard HCI, you can replace the
+  co-processor with any other co-processor (ESP or otherwise) that has
+  a Bluetooth controller
 
 > [!NOTE]
 > If Hosted is configured as the Bluetooth transport (vHCI), then your
@@ -102,11 +140,11 @@ NimBLE Bluetooth stack to initialize, send and receive Bluetooth data:
 - `ble_transport_to_hs_acl`
 
 The following sequence diagrams show how to send and receive Bluetooth
-on both the Hosted Master and Slave.
+on both the Hosted Master and co-processor.
 
-## 5. Transporting HCI data using vHCI
+### 4.1. Transporting HCI data using vHCI in NimBLE
 
-### 5.1. Bluetooth Host vHCI Initialization
+#### 4.1.1. Bluetooth Host vHCI Initialization
 
 ```mermaid
 sequenceDiagram
@@ -116,7 +154,7 @@ sequenceDiagram
     participant master as SPI/SDIO Interface
     end
 
-    box Grey Hosted Slave
+    box Grey Hosted Co-processor
     participant sinterface as SPI/SDIO Interface
     participant slave as Bluetooth Controller
     end
@@ -132,7 +170,7 @@ sequenceDiagram
 
 **Bluetooth Host Initialization**
 
-### 5.2. Bluetooth Host Sending Data through vHCI
+#### 4.1.2. Bluetooth Host Sending Data through vHCI in NimBLE
 
 ```mermaid
 sequenceDiagram
@@ -142,7 +180,7 @@ sequenceDiagram
     participant master as SPI/SDIO Interface
     end
 
-    box Grey Hosted Slave
+    box Grey Hosted Co-processor
     participant sinterface as SPI/SDIO Interface
     participant slave as Bluetooth Controller
     end
@@ -153,7 +191,7 @@ sequenceDiagram
     Note over master : add Hosted header
     master ->> +sinterface: SPI/SDIO
     Note over master,sinterface : (VHCI data)
-    master -->> -vhci : 
+    master -->> -vhci :  
     vhci -->> -ble : 
 
     Note over sinterface : remove Hosted header
@@ -162,7 +200,7 @@ sequenceDiagram
 
 **Bluetooth Host Sending Data**
 
-### 5.3. Bluetooth Host Receiving Data from vHCI
+#### 4.1.3. Bluetooth Host Receiving Data from vHCI in NimBLE
 
 ```mermaid
 sequenceDiagram
@@ -172,7 +210,7 @@ sequenceDiagram
     participant master as SPI/SDIO Interface
     end
 
-    box Grey Hosted Slave
+    box Grey Hosted Co-processor
     participant sinterface as SPI/SDIO Interface
     participant slave as Bluetooth Controller
     end
@@ -200,9 +238,9 @@ sequenceDiagram
 
 **Bluetooth Host Receiving Data**
 
-## 6. Transporting HCI data using UART
+### 4.2. Transporting HCI data using UART
 
-### 6.1. Bluetooth Host HCI Initialization
+#### 4.2.1. Bluetooth Host HCI Initialization
 
 ```mermaid
 sequenceDiagram
@@ -211,7 +249,7 @@ sequenceDiagram
     participant huart as UART Driver
     end
 
-    box Grey Slave
+    box Grey Co-processor
     participant slave as Bluetooth Controller with UART Interface
     end
 
@@ -226,7 +264,7 @@ sequenceDiagram
 
 **Bluetooth Host Initialization**
 
-### 6.2. Bluetooth Host Sending Data using HCI
+#### 4.2.2. Bluetooth Host Sending Data using HCI
 
 ```mermaid
 sequenceDiagram
@@ -235,7 +273,7 @@ sequenceDiagram
     participant huart as UART Driver
     end
 
-    box Grey Slave
+    box Grey Co-processor
     participant slave as Bluetooth Controller with UART Interface
     end
 
@@ -248,7 +286,7 @@ sequenceDiagram
 
 **Bluetooth Host Sending Data**
 
-### 6.3. Bluetooth Host Receiving Data using HCI
+#### 4.2.3. Bluetooth Host Receiving Data using HCI
 
 ```mermaid
 sequenceDiagram
@@ -257,7 +295,7 @@ sequenceDiagram
     participant huart as UART Driver
     end
 
-    box Grey Slave
+    box Grey Co-processor
     participant slave as Bluetooth Controller with UART Interface
     end
 
@@ -277,7 +315,193 @@ sequenceDiagram
 
 **Bluetooth Host Receiving Data**
 
-## 7. References
+## 5. BlueDroid Host Stack
+
+The ESP-Hosted Master implements the set of API calls required by the
+BlueDroid Bluetooth stack to initialise, send and receive Bluetooth
+data.
+
+- `hosted_hci_bluedroid_open`
+- `hosted_hci_bluedroid_close`
+- `hosted_hci_bluedroid_send`
+- `hosted_hci_bluedroid_check_send_available`
+- `hosted_hci_bluedroid_register_host_callback`
+
+`hosted_hci_bluedroid_open` must be called by the application before
+attaching the transport APIs to BlueDroid and starting BlueDroid. This
+initializes the underlying transport.
+
+`hosted_hci_bluedroid_register_host_callback` records the callback provided by BlueDroid that is use to notify the Bluetooth stack of incoming HCI data (as `notify_host_recv`).
+
+The following sequence diagrams show how to send and receive Bluetooth
+on both the Hosted Master and Co-processor.
+
+### 5.1. Transporting HCI data using vHCI in BlueDroid
+
+#### 5.1.1. Bluetooth Host vHCI Initialization
+
+```mermaid
+sequenceDiagram
+    box Grey Hosted Master
+    participant bt as Host Application
+    participant vhci as VHCI Driver
+    participant master as SPI/SDIO Interface
+    end
+
+    box Grey Hosted Co-processor
+    participant sinterface as SPI/SDIO Interface
+    participant slave as Bluetooth Controller
+    end
+
+    bt ->> +vhci : hosted_hci_bluedroid_open()
+	Note over vhci: do any init required
+    vhci -->> -bt : 
+```
+
+**Bluetooth Host Initialization**
+
+#### 5.1.2. Bluetooth Host Sending Data through vHCI in BlueDroid
+
+```mermaid
+sequenceDiagram
+    box Grey Hosted Master
+    participant bt as BlueDroid Host Bluetooth Stack
+    participant vhci as VHCI Driver
+    participant master as SPI/SDIO Interface
+    end
+
+    box Grey Hosted Co-processor
+    participant sinterface as SPI/SDIO Interface
+    participant slave as Bluetooth Controller
+    end
+
+    bt ->> +vhci : hosted_hci_bluedroid_send()
+    Note over vhci : HCI data
+    vhci ->> +master : esp_hosted_tx()
+    Note over master : add Hosted header
+    master ->> +sinterface: SPI/SDIO
+    Note over master,sinterface : (VHCI data)
+    master -->> -vhci :  
+    vhci -->> -bt : 
+
+    Note over sinterface : remove Hosted header
+    sinterface ->> -slave : HCI data
+```
+
+**Bluetooth Host Sending Data**
+
+#### 5.1.3. Bluetooth Host Receiving Data from vHCI in BlueDroid
+
+```mermaid
+sequenceDiagram
+    box Grey Hosted Master
+    participant bt as BlueDroid Host Bluetooth Stack
+    participant vhci as VHCI Driver
+    participant master as SPI/SDIO Interface
+    end
+
+    box Grey Hosted Co-processor
+    participant sinterface as SPI/SDIO Interface
+    participant slave as Bluetooth Controller
+    end
+
+    slave ->> +sinterface : HCI data
+    Note over sinterface : Add Hosted header
+    sinterface ->> -master : SPI/SDIO
+    Note over sinterface,master : (VHCI data)
+    Note over master : Remove Hosted header
+
+    master ->> +vhci : hci_rx_handler()
+
+    vhci ->> bt : notify_host_recv()
+    Note over vhci, bt: HCI data
+
+    vhci -->> -master : 
+```
+
+**Bluetooth Host Receiving Data**
+
+### 5.2. Transporting HCI data using UART
+
+When using BlueDroid Host Bluetooth Stack with UART, UART functions
+that do the following are required:
+
+- `uart_open` to open the UART driver and initialise the UART (set GPIOs, Baud Rate, etc.)
+- `uart_tx` to transmit data over UART
+- `UART RX` is a thread that waits for incoming UART data
+- `notify_host_recv` is a BlueDroid callback registered with `UART RX` to receive UART data
+
+`uart_open` is called before starting BlueDroid, while `uart_tx` and
+`notify_host_recv` are registered by BlueDroid with the UART Driver. See this [ESP-IDF BlueDroid Example using UART](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/bluedroid_host_only/bluedroid_host_only_uart) for an example implementation.
+
+#### 5.2.1. Bluetooth Host HCI Initialization
+
+```mermaid
+sequenceDiagram
+    box Grey Master
+    participant bt as Host Application
+    participant huart as UART Driver
+    end
+
+    box Grey Co-processor
+    participant slave as Bluetooth Controller with UART Interface
+    end
+
+    bt ->> +huart : uart_open()
+	Note over huart: do any uart init required
+    huart -->> -bt : 
+```
+
+**Bluetooth Host Initialization**
+
+#### 5.2.2. Bluetooth Host Sending Data using HCI
+
+```mermaid
+sequenceDiagram
+    box Grey Master
+    participant bt as BlueDroid Host Bluetooth Stack
+    participant huart as UART Driver
+    end
+
+    box Grey Co-processor
+    participant slave as Bluetooth Controller with UART Interface
+    end
+
+    bt ->> huart : uart_tx()
+    huart ->> slave : UART TX 
+    Note over huart,slave : (standard HCI)
+    huart -->> bt : 
+```
+
+**Bluetooth Host Sending Data**
+
+#### 5.2.3. Bluetooth Host Receiving Data using HCI
+
+```mermaid
+sequenceDiagram
+    box Grey Master
+    participant bt as BlueDroid Host Bluetooth Stack
+    participant huart as UART Driver
+    end
+
+    box Grey Co-processor
+    participant slave as Bluetooth Controller with UART Interface
+    end
+
+    slave ->> huart : UART RX
+    Note over slave,huart: (standard HCI)
+    huart ->> bt : notify_host_recv()
+    Note over huart, bt: HCI data
+
+    bt -->> huart: 
+```
+
+**Bluetooth Host Receiving Data**
+
+## 6. References
 
 - esp-nimble: https://github.com/espressif/esp-nimble
 - ESP-IDF NimBLE-based Host APIs: https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/bluetooth/nimble/index.html
+- Bluetooth API: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/index.html
+- ESP-IDF example using NimBLE on Host to send HCI through UART to co-processor: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/nimble/bleprph_host_only
+- ESP-IDF example using BlueDroid on Host to send HCI through UART to co-processor: https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/bluedroid_host_only/bluedroid_host_only_uart

+ 1 - 1
esp-hosted/docs/design_consideration.md

@@ -184,7 +184,7 @@ solution to your problem may have already been provided.
 **External Links**
 
 - ESP Product Selector: https://products.espressif.com/
-- ESP-Hosted Github Issues: https://github.com/espressif/esp-hosted/issues
+- ESP-Hosted Github Issues: https://github.com/espressif/esp-hosted-mcu/issues
 
 **ESP-Hosted Documentation Links**
 

+ 4 - 1
esp-hosted/docs/esp32_p4_function_ev_board.md

@@ -370,9 +370,12 @@ Use GPIOs 36 or lower on the P4 DevKit to avoid LDO power issues with high numbe
 | CLK        | 26   |
 | CS         | 6    |
 | Handshake  | 20   |
-| Data Ready | 36   |
+| Data Ready | 32   |
 | Reset      | 2    |
 
+> [!NOTE]
+> Avoid using GPIO 35 and 36 as they affect the ESP32-P4 Bootloader Mode. See [ESP32-P4 Boot Mode Selection](https://docs.espressif.com/projects/esptool/en/latest/esp32p4/advanced-topics/boot-mode-selection.html#select-bootloader-mode) for more information.
+
 ## 9. References
 
 - ESP32-P4-Function-EV-Board: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/

+ 10 - 13
esp-hosted/docs/spi_full_duplex.md

@@ -121,11 +121,11 @@ The SPI used is full duplex. Handshake, Data Ready and Reset are additional GPIO
 For a detailed implementation of SPI full duplex communication using the ESP-Hosted framework, refer to the following code files in the ESP-Hosted repository:
 
 - **Master SPI Communication Code**:
-  - [spi_drv.c](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/host/drivers/transport/spi/spi_drv.c): Contains the implementation for configuring and handling SPI transactions on the master side.
-  - [spi_wrapper.c](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/host/port/esp_idf/spi_wrapper.c): Provides an OS abstraction layer for SPI operations, making it easier to handle SPI communication in a platform-independent manner.
+  - [spi_drv.c](https://github.com/espressif/esp-hosted-mcu/blob/main/host/drivers/transport/spi/spi_drv.c): Contains the implementation for configuring and handling SPI transactions on the master side.
+  - [spi_wrapper.c](https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/spi_wrapper.c): Provides an OS abstraction layer for SPI operations, making it easier to handle SPI communication in a platform-independent manner.
 
 - **Co-processor SPI Communication Code**:
-  - [spi_slave_apis.c](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/firmware/components/esp_slave/spi_slave_apis.c): Includes the setup and transaction handling for the SPI co-processor, detailing how the co-processor should configure its SPI interface and handle incoming and outgoing data.
+  - [spi_slave_api.c](https://github.com/espressif/esp-hosted-mcu/blob/main/slave/main/spi_slave_api.c): Includes the setup and transaction handling for the SPI co-processor, detailing how the co-processor should configure its SPI interface and handle incoming and outgoing data.
 
 ## 4 Hardware Considerations
 
@@ -306,11 +306,10 @@ idf.py -p <co-processor_serial_port> flash
 ```
 
 > [!NOTE]
->
 > If you are not able to flash the co-processor, there might be a chance that host is not allowing to to do so.
-> 
+>
 > Put host in bootloader mode using following command and then retry flashing the co-processor
-> 
+>
 > ```bash
 > esptool.py -p <host_serial_port> --before default_reset --after no_reset run
 > ```
@@ -403,10 +402,9 @@ Now that ESP-IDF is set up, follow these steps to prepare the host:
    This step is necessary because esp-extconn and esp-hosted cannot work together.
 
 ###### 4. Disable native Wi-Fi if available
-   If your host ESP chip already has native Wi-Fi support, disable it by editing the `components/soc/<soc>/include/soc/Kconfig.soc_caps.in` file and changing all `WIFI` related configs to `n`.
-     
-    If you happen to have both, host and co-processor as same ESP chipset type (for example two ESP32-C2), note an [additional step](docs/troubleshooting/#1-esp-host-to-evaluate-already-has-native-wi-fi)
-    
+If your host ESP chip already has native Wi-Fi support, disable it by editing the `components/soc/<soc>/include/soc/Kconfig.soc_caps.in` file and changing all `WIFI` related configs to `n`.
+
+If you happen to have both, host and co-processor as same ESP chipset type (for example two ESP32-C2), note an [additional step](docs/troubleshooting/#1-esp-host-to-evaluate-already-has-native-wi-fi)
 
 ### 8.3 Menuconfig, Build and Flash Host
 
@@ -457,7 +455,6 @@ Now that ESP-IDF is set up, follow these steps to prepare the host:
    - SPI Checksum Enable/Disable (Checksum is recommended to be enabled as spi hardware doesn't have any error detection)
 
 > [!NOTE]
-> 
 > The actual clock frequency used is determined by the hardware. Use an oscilloscope or logic analyzer to check the clock frequency.
 
 ###### 4. Build the project:
@@ -491,7 +488,7 @@ After flashing both the co-processor and host devices, follow these steps to con
 3. Verify the connection:
    - Check the serial output of both devices for successful initialization messages.
    - Look for messages indicating that the SPI Full Duplex transport layer has been established
-   
+
 4. Logs at both sides:
    - Host:
 
@@ -560,7 +557,7 @@ After flashing both the co-processor and host devices, follow these steps to con
 9. Monitoring and debugging:
    - Use the serial monitor on both devices to observe the communication between the host and co-processor.
    - For more detailed debugging, consider using a logic analyzer to examine the SPI signals.
-   
+
 ## 10 References
 - [ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/)
 - [ESP32 Hardware Design Guidelines](https://www.espressif.com/en/products/hardware/esp32/resources)

+ 3 - 3
esp-hosted/docs/spi_half_duplex.md

@@ -332,9 +332,9 @@ sequenceDiagram
 
 ### 5.4 Code Reference
 
-- [`slave/main/spi_hd_slave_api.c`](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/slave/main/spi_hd_slave_api.c) implements the code to run the SPI HD driver on the co-processor
-- [`host/drivers/transport/spi_hd/spi_hd_drv.c`](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/host/drivers/transport/spi_hd/spi_hd_drv.c) implements the generic code to run the SPI HD driver on the host
-- [`host/port/spi_hd_wrapper.c`](https://github.com/espressif/esp-hosted/blob/feature/esp_as_mcu_host/host/port/spi_hd_wrapper.c) implements the ESP-IDF specific code used by the generic SPI HD driver on the host
+- [`slave/main/spi_hd_slave_api.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/slave/main/spi_hd_slave_api.c) implements the code to run the SPI HD driver on the co-processor
+- [`host/drivers/transport/spi_hd/spi_hd_drv.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/host/drivers/transport/spi_hd/spi_hd_drv.c) implements the generic code to run the SPI HD driver on the host
+- [`host/port/spi_hd_wrapper.c`](https://github.com/espressif/esp-hosted-mcu/blob/main/host/port/spi_hd_wrapper.c) implements the ESP-IDF specific code used by the generic SPI HD driver on the host
 
 ## 6 Hardware Considerations
 

+ 8 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/CMakeLists.txt

@@ -0,0 +1,8 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
+idf_build_set_property(MINIMAL_BUILD ON)
+project(ble_compatibility_test)

+ 59 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/README.md

@@ -0,0 +1,59 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 | ESP32-P4 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
+
+# ESP-IDF BLE Compatibility Test Example
+
+This example is to test the Bluetooth compatibility and mobile phones.
+
+## How to Use Example
+
+This example has been modified to work with ESP-Hosted. The original ESP-IDF example is at [ https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/ble_compatibility_test ].
+
+This example is able to run on the ESP32-P4 Dev Board, acting as the BT Host, connected to a ESP32 co-processor via the GPIO header, using SPI FD (full duplex) as ESP-Hosted transport (VHCI). The ESP32-P4 acts as the BT Controller. The following GPIO settings were used:
+
+| SPI Function | ESP32 GPIO | ESP32-P4 GPIO |
+| :---         |       ---: |          ---: |
+| MOSI         |         13 |             4 |
+| MISO         |         12 |             5 |
+| CLK          |         14 |            26 |
+| CS           |         15 |             6 |
+| Handshake    |         26 |            20 |
+| Data Ready   |          4 |            36 |
+| Reset        |         -1 |             2 |
+
+> [!NOTE]
+> SPI Mode 2 was used on both the ESP32-P4 and ESP32.
+
+Users are free to choose which supported ESP-Hosted transport to use. See the [main ESP-Hosted README](https://github.com/espressif/esp-hosted-mcu/blob/main/README.md#6-decide-the-communication-bus-in-between-host-and-slave) for a list of supported transports.
+
+Before project configuration and build, be sure to set the correct chip target using:
+
+```bash
+idf.py set-target <chip_name>
+```
+
+### Test Scenario
+
+* ESP32-P4-Function-EV-Board connected to a ESP32 via the GPIO header
+* [Test case](ble_compatibility_test_case.md)
+* Test APK: LightBlue V2.0.5
+
+### Configure the project
+
+On the ESP32-P4 Dev Board, run `idf.py menuconfig`.
+
+* Check and enable Classic Bluetooth and Classic BT HID Device under `Component config --> Bluetooth --> Bluedroid Options`
+* Ensure that `Component config --> Bluetooth --> Controller` is `Disabled`.
+* Under `Component config --> ESP-Hosted config`:
+  * Configure ESP-Hosted to use `SPI Full-duplex` as the transport
+  * Set the Slave chipset used as `ESP32`
+  * Check and enable `Bluetooth Support`
+  * Configure the GPIOs used for SPI FD on both the ESP32-P4 and ESP32, following the table above
+
+### Build and Flash
+
+Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the [Getting Started Guide](https://idf.espressif.com/) for full steps to configure and use ESP-IDF to build projects.

+ 180 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/ble_compatibility_test_case.md

@@ -0,0 +1,180 @@
+# Test Case for BLE Smartphone Compatibility
+
+This document provides a test case for BLE smartphone compatibility and includes detailed procedures for various test items.
+
+## Preparation
+
+### What You Need
+
+* ESP device which needs to flash [this test program](main/ble_compatibility_test.c)
+* Smartphone with LightBlue® Explorer app
+
+### Initialization
+
+Prior to conducting tests, please initialize the smartphone and the ESP device as follows:
+
+* Set the device name as `BLE_COMP_TEST`.
+* Set the maximum transmission unit (MTU) of the device to 33 bytes, to test the assembly and division of data packets.
+* If the smartphone has been paired with the ESP device before, please delete the pairing in the Bluetooth setting as follows: `Bluetooth` -> `My Devices` -> `Find this device with "i" in a circle on the right` -> `Forget this device`. Then restart the Bluetooth service.
+* Before flashing the test program onto the ESP device, make sure to erase the contents of the flash by executing the command `make erase_flash flash` in the Terminal.
+* When the ESP device restarts, the pairing information will be erased automatically. After that, make sure that the pairing information in the Bluetooth setting of the smartphone is deleted.
+
+**Note:**
+
+* For tests marked with (*) further in the document, please bear in mind the following:
+	* Your phone performance may affect the results of these tests. If such a test fails, it does not mean the phone fails to meet the test requirements, but that you need to arrange targeted tests.
+	* Taking "Test for Connection Success Rate" as an example: if the test cannot be passed for 10 consecutive times, you need to record how many times the test was passed and then arrange targeted tests.
+* For extended testing, please use the [examples] (https://github.com/espressif/esp-idf/tree/master/examples/bluetooth) provided by Espressif.
+
+## Test for ADV Performance (*)
+
+### Search Device
+
+Refresh the scanning in LightBlue® Explorer to check if the device to be tested can be found quickly. Please repeat this action 10 times.
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* The device starts advertizing and outputs the log `(0) ***** advertising start successfully *****`.
+* LightBlue® Explorer scans and successfully discovers ` BLE_COMP_TEST` each time.
+
+**Note:**
+
+* The device broadcasts on 3 channels, with an ADV interval of 40 ms.
+* Check if the ADV packet can be received.
+* Check if the Scan Response packet can be received.
+* The device name is included in Scan Response packets only and cannot be found in ADV packets.
+
+## Test for Pairing Performance
+
+### Connect Device
+
+* Open the LightBlue® Explorer scan list and tap on the device name ` BLE_COMP_TEST` to establish connection.
+* ESP device prints a passkey: `The passkey notify number: 123456`.
+* A prompt on the smartphone appears asking if you want to pair. Tap on *Pair*, and then enter the passkey "123456".
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* If the connection is successful:
+   * Smartphone shows DATA beginning with `ADVERTISEMENT DATA`
+   * ESP device outputs the log: `ESP_GATTS_CONNECT_EVT`
+* When the pairing is established, the device shows the following log in green: `(1) ***** pair status = success *****`
+
+## Test for Service Discovery Performance
+
+### Test Procedures
+
+In LightBlue® Explorer, check the contents of `GATT SERVICES & CHARACTERISTICS`.
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* Service that starts with ``000000ff`` appears at the bottom of your smartphone.
+* This service contains 3 characteristics
+   * `Char_1_Short_WR`
+   * `Char_2_Long_WR`
+   * `Char_3_Short_Notify`
+
+## Test for Read and Encrypt
+
+### Test Procedures
+
+Read the value of `Char_1` in LightBlue, and tap on `READ AGAIN`.
+
+### Test Results
+
+* Encryption is successful, if your smartphone shows the value "11 22 33 44", and the ESP device prints the log: `(2) ***** read char_1 *****`.
+* Encryption fails, if your smartphone shows a blank screen, and the ESP device outputs the error log in red: `GATT_INSUF_AUTHENTICATION: MITM Required`.
+
+## Test for Short Read and Write
+
+### Test Procedures
+
+* Navigate to the WRITE interface in LightBlue® Explorer, and write the value "88 99" to `Char_1`.
+* Read `Char_1` and check if its value is consistent with the data you have written to it.
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* ESP device prints the log: `(3)***** short write success *****`.
+* LightBlue® Explorer shows "88 99" below `READ AGAIN`.
+
+## Test for Long Read and Write
+
+### Test Procedures
+
+* Navigate to the WRITE interface in LightBlue® Explorer, and write the string `0x001122…FF001122…FF` of 256 bytes to `Char_2`. The data takes up 16 lines and looks as follows:
+
+	```
+	00112233445566778899AABBCCDDEEFF
+	00112233445566778899AABBCCDDEEFF
+	…
+	00112233445566778899AABBCCDDEEFF
+	00112233445566778899AABBCCDDEEFF
+	```
+
+* Read `Char_2` and check if its value is consistent with the data you have written to it.
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* The device prints the log: ``ESP_GATTS_EXEC_WRITE_EVT, Length=256`` and ``(4) ***** long write success *****``.
+* LightBlue® Explorer shows `(5) ***** read char_2 *****` below `READ AGAIN`.
+
+**Note:**
+
+The data to be written can be copied from a text file and pasted into LightBlue® Explorer.
+
+## Test for Short Notify
+
+### Test Procedures
+
+* Enter `Char_3` and tap on `SUBSCRIBE` to enable its Notify function.
+* Your phone automatically receives Notify data from the device.
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* ESP device prints the log: `(6) ***** send notify AA BB *****`.
+* "AA BB" appears on your smartphone.
+
+## Test for Connection Success Rate (*)
+
+### Test procedures
+
+* Break the connection
+* Re-establish the connection
+* Repeat 10 times
+
+### Test Results
+
+The test is passed, if you get the following results:
+
+* Your phone establishes the connection successfully, and the ESP device outputs the log: `(1) ***** pair status = success *****`.
+* Your phone breaks the connection, and the device outputs the log: `ESP_GATTS_DISCONNECT_EVT`.
+* Connection can be set up each time with no issues.
+
+## Test for Long Connection Stability
+
+The connection must be stable throughout the tests.
+
+**Note:**
+
+If the existing connection breaks:
+
+* LightBlue® Explorer prints `Disconnected`.
+* ESP device outputs the log: ``ESP_GATTS_DISCONNECT_EVT, reason = (0) ***** advertising start successfully *****``.
+
+## Further Information
+
+* If you see any log entry in red, please record it for future reference or feedback it to our engineer.
+* Tests to be added in the future:
+   * Multi-connection Test
+   * Automatic Re-connection Test

+ 3 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/CMakeLists.txt

@@ -0,0 +1,3 @@
+idf_component_register(SRCS "ble_compatibility_test.c"
+                    PRIV_REQUIRES bt nvs_flash esp_hosted
+                    INCLUDE_DIRS ".")

+ 730 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/ble_compatibility_test.c

@@ -0,0 +1,730 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+/********************************************************************************
+*
+* This file is for gatt server. It can send adv data, and get connected by client.
+*
+*********************************************************************************/
+
+#include <inttypes.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "nvs_flash.h"
+// #include "esp_bt.h"
+
+#include "esp_gap_ble_api.h"
+#include "esp_gatts_api.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "ble_compatibility_test.h"
+#include "esp_gatt_common_api.h"
+
+#include "esp_hosted_bt.h"
+
+#define DEBUG_ON  0
+
+#if DEBUG_ON
+#define EXAMPLE_DEBUG ESP_LOGI
+#else
+#define EXAMPLE_DEBUG( tag, format, ... )
+#endif
+
+#define EXAMPLE_TAG "BLE_COMP"
+
+#define PROFILE_NUM                 1
+#define PROFILE_APP_IDX             0
+#define ESP_APP_ID                  0x55
+#define SAMPLE_DEVICE_NAME          "BLE_COMP_TEST"
+#define SVC_INST_ID                 0
+
+/* The max length of characteristic value. When the gatt client write or prepare write,
+*  the data length must be less than GATTS_EXAMPLE_CHAR_VAL_LEN_MAX.
+*/
+#define GATTS_EXAMPLE_CHAR_VAL_LEN_MAX 500
+#define LONG_CHAR_VAL_LEN           500
+#define SHORT_CHAR_VAL_LEN          10
+#define GATTS_NOTIFY_FIRST_PACKET_LEN_MAX 20
+
+#define PREPARE_BUF_MAX_SIZE        1024
+#define CHAR_DECLARATION_SIZE       (sizeof(uint8_t))
+
+#define ADV_CONFIG_FLAG             (1 << 0)
+#define SCAN_RSP_CONFIG_FLAG        (1 << 1)
+
+static uint8_t adv_config_done       = 0;
+
+uint16_t gatt_db_handle_table[HRS_IDX_NB];
+
+typedef struct {
+    uint8_t                 *prepare_buf;
+    int                     prepare_len;
+} prepare_type_env_t;
+
+static prepare_type_env_t prepare_write_env;
+
+//#define CONFIG_SET_RAW_ADV_DATA
+#ifdef CONFIG_SET_RAW_ADV_DATA
+static uint8_t raw_adv_data[] = {
+    /* Flags */
+    0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
+    /* TX Power */
+    0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
+    /* Service UUID */
+    0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xFF, 0x00,
+    /* Device Name */
+    0x0E, ESP_BLE_AD_TYPE_NAME_CMPL, 'B', 'L', 'E', '_', 'C', 'O', 'M', 'P', '_', 'T', 'E', 'S', 'T'
+};
+
+static uint8_t raw_scan_rsp_data[] = {
+    /* Flags */
+    0x02, ESP_BLE_AD_TYPE_FLAG, 0x06,
+    /* TX Power */
+    0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xeb,
+    /* Service UUID */
+    0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xFF, 0x00
+};
+
+#else
+static uint8_t service_uuid[16] = {
+    /* LSB <--------------------------------------------------------------------------------> MSB */
+    //first uuid, 16bit, [12],[13] is the value
+    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
+};
+
+/* The length of adv data must be less than 31 bytes */
+static esp_ble_adv_data_t adv_data = {
+    .set_scan_rsp        = false,
+    .include_name        = true,
+    .include_txpower     = true,
+    .min_interval        = 0x20,
+    .max_interval        = 0x40,
+    .appearance          = 0x00,
+    .manufacturer_len    = 0,    //TEST_MANUFACTURER_DATA_LEN,
+    .p_manufacturer_data = NULL, //test_manufacturer,
+    .service_data_len    = 0,
+    .p_service_data      = NULL,
+    .service_uuid_len    = sizeof(service_uuid),
+    .p_service_uuid      = service_uuid,
+    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
+};
+
+// scan response data
+static esp_ble_adv_data_t scan_rsp_data = {
+    .set_scan_rsp        = true,
+    .include_name        = true,
+    .include_txpower     = true,
+    .min_interval        = 0x20,
+    .max_interval        = 0x40,
+    .appearance          = 0x00,
+    .manufacturer_len    = 0, //TEST_MANUFACTURER_DATA_LEN,
+    .p_manufacturer_data = NULL, //&test_manufacturer[0],
+    .service_data_len    = 0,
+    .p_service_data      = NULL,
+    .service_uuid_len    = 16,
+    .p_service_uuid      = service_uuid,
+    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
+};
+#endif /* CONFIG_SET_RAW_ADV_DATA */
+
+static esp_ble_adv_params_t adv_params = {
+    .adv_int_min         = 0x40,
+    .adv_int_max         = 0x40,
+    .adv_type            = ADV_TYPE_IND,
+    .own_addr_type       = BLE_ADDR_TYPE_PUBLIC,
+    .channel_map         = ADV_CHNL_ALL,
+    .adv_filter_policy   = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
+};
+
+struct gatts_profile_inst {
+    esp_gatts_cb_t gatts_cb;
+    uint16_t gatts_if;
+    uint16_t app_id;
+    uint16_t conn_id;
+    uint16_t service_handle;
+    esp_gatt_srvc_id_t service_id;
+    uint16_t char_handle;
+    esp_bt_uuid_t char_uuid;
+    esp_gatt_perm_t perm;
+    esp_gatt_char_prop_t property;
+    uint16_t descr_handle;
+    esp_bt_uuid_t descr_uuid;
+};
+
+static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
+					esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
+
+/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
+static struct gatts_profile_inst heart_rate_profile_tab[PROFILE_NUM] = {
+    [PROFILE_APP_IDX] = {
+        .gatts_cb = gatts_profile_event_handler,
+        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
+    },
+};
+
+/* Service */
+static const uint16_t GATTS_SERVICE_UUID_TEST      = 0x00FF;
+static const uint16_t CHAR_1_SHORT_WR              = 0xFF01;
+static const uint16_t CHAR_2_LONG_WR               = 0xFF02;
+static const uint16_t CHAR_3_SHORT_NOTIFY          = 0xFF03;
+
+static const uint16_t primary_service_uuid         = ESP_GATT_UUID_PRI_SERVICE;
+static const uint16_t character_declaration_uuid   = ESP_GATT_UUID_CHAR_DECLARE;
+static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
+static const uint16_t character_user_description   = ESP_GATT_UUID_CHAR_DESCRIPTION;
+static const uint8_t char_prop_notify              = ESP_GATT_CHAR_PROP_BIT_NOTIFY;
+static const uint8_t char_prop_read_write          = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ;
+static const uint8_t char1_name[]  = "Char_1_Short_WR";
+static const uint8_t char2_name[]  = "Char_2_Long_WR";
+static const uint8_t char3_name[]  = "Char_3_Short_Notify";
+static const uint8_t char_ccc[2]   = {0x00, 0x00};
+static const uint8_t char_value[4] = {0x11, 0x22, 0x33, 0x44};
+
+
+/* Full Database Description - Used to add attributes into the database */
+static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
+{
+    // Service Declaration
+    [IDX_SVC]        =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
+      sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID_TEST), (uint8_t *)&GATTS_SERVICE_UUID_TEST}},
+
+    /* Characteristic Declaration */
+    [IDX_CHAR_A]     =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
+      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}},
+
+    /* Characteristic Value */
+    [IDX_CHAR_VAL_A] =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&CHAR_1_SHORT_WR, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE | ESP_GATT_PERM_READ_ENC_MITM,
+      SHORT_CHAR_VAL_LEN, sizeof(char_value), (uint8_t *)char_value}},
+
+    /* Characteristic User Descriptor */
+    [IDX_CHAR_CFG_A]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_user_description, ESP_GATT_PERM_READ,
+      sizeof(char1_name), sizeof(char1_name), (uint8_t *)char1_name}},
+
+    /* Characteristic Declaration */
+    [IDX_CHAR_B]      =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
+      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write}},
+
+    /* Characteristic Value */
+    [IDX_CHAR_VAL_B]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&CHAR_2_LONG_WR, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
+      LONG_CHAR_VAL_LEN, sizeof(char_value), (uint8_t *)char_value}},
+
+       /* Characteristic User Descriptor */
+    [IDX_CHAR_CFG_B]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_user_description, ESP_GATT_PERM_READ,
+      sizeof(char2_name), sizeof(char2_name), (uint8_t *)char2_name}},
+
+   /* Characteristic Declaration */
+    [IDX_CHAR_C]      =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
+      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_notify}},
+
+    /* Characteristic Value */
+    [IDX_CHAR_VAL_C]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&CHAR_3_SHORT_NOTIFY, 0,
+      LONG_CHAR_VAL_LEN, sizeof(char_value), (uint8_t *)char_value}},
+
+    /* Characteristic User Descriptor */
+    [IDX_CHAR_CFG_C]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_user_description, ESP_GATT_PERM_READ,
+      sizeof(char3_name), sizeof(char3_name), (uint8_t *)char3_name}},
+
+    /* Characteristic Client Configuration Descriptor */
+    [IDX_CHAR_CFG_C_2]  =
+    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
+      sizeof(uint16_t), sizeof(char_ccc), (uint8_t *)char_ccc}},
+
+};
+
+static void show_bonded_devices(void)
+{
+    int dev_num = esp_ble_get_bond_device_num();
+    if (dev_num == 0) {
+        ESP_LOGI(EXAMPLE_TAG, "Bonded devices number zero\n");
+        return;
+    }
+
+    esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
+    if (!dev_list) {
+        ESP_LOGE(EXAMPLE_TAG, "malloc failed, return\n");
+        return;
+    }
+    esp_ble_get_bond_device_list(&dev_num, dev_list);
+    EXAMPLE_DEBUG(EXAMPLE_TAG, "Bonded devices number : %d\n", dev_num);
+
+    EXAMPLE_DEBUG(EXAMPLE_TAG, "Bonded devices list : %d\n", dev_num);
+    for (int i = 0; i < dev_num; i++) {
+        #if DEBUG_ON
+        ESP_LOG_BUFFER_HEX(EXAMPLE_TAG, (void *)dev_list[i].bd_addr, sizeof(esp_bd_addr_t));
+        #endif
+    }
+
+    free(dev_list);
+}
+
+static void __attribute__((unused)) remove_all_bonded_devices(void)
+{
+    int dev_num = esp_ble_get_bond_device_num();
+    if (dev_num == 0) {
+        ESP_LOGI(EXAMPLE_TAG, "Bonded devices number zero\n");
+        return;
+    }
+
+    esp_ble_bond_dev_t *dev_list = (esp_ble_bond_dev_t *)malloc(sizeof(esp_ble_bond_dev_t) * dev_num);
+    if (!dev_list) {
+        ESP_LOGE(EXAMPLE_TAG, "malloc failed, return\n");
+        return;
+    }
+    esp_ble_get_bond_device_list(&dev_num, dev_list);
+    for (int i = 0; i < dev_num; i++) {
+        esp_ble_remove_bond_device(dev_list[i].bd_addr);
+    }
+
+    free(dev_list);
+}
+
+static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
+{
+    switch (event) {
+    #ifdef CONFIG_SET_RAW_ADV_DATA
+        case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
+            adv_config_done &= (~ADV_CONFIG_FLAG);
+            if (adv_config_done == 0){
+                esp_ble_gap_start_advertising(&adv_params);
+            }
+            break;
+        case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
+            adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
+            if (adv_config_done == 0){
+                esp_ble_gap_start_advertising(&adv_params);
+            }
+            break;
+    #else
+        case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
+            adv_config_done &= (~ADV_CONFIG_FLAG);
+            if (adv_config_done == 0){
+                esp_ble_gap_start_advertising(&adv_params);
+            }
+            break;
+        case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
+            adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
+            if (adv_config_done == 0){
+                esp_ble_gap_start_advertising(&adv_params);
+            }
+            break;
+    #endif
+        case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
+            /* advertising start complete event to indicate advertising start successfully or failed */
+            if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+                ESP_LOGE(EXAMPLE_TAG, "advertising start failed");
+            }else{
+                ESP_LOGI(EXAMPLE_TAG, "(0) ***** advertising start successfully ***** ");
+            }
+            break;
+        case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
+            if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
+                ESP_LOGE(EXAMPLE_TAG, "Advertising stop failed");
+            }
+            else {
+                ESP_LOGI(EXAMPLE_TAG, "Stop adv successfully");
+            }
+            break;
+        case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "update connection params status = %d, conn_int = %d, latency = %d, timeout = %d",
+                  param->update_conn_params.status,
+                  param->update_conn_params.conn_int,
+                  param->update_conn_params.latency,
+                  param->update_conn_params.timeout);
+            break;
+        case ESP_GAP_BLE_PASSKEY_REQ_EVT:                           /* passkey request event */
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT");
+            //esp_ble_passkey_reply(heart_rate_profile_tab[HEART_PROFILE_APP_IDX].remote_bda, true, 0x00);
+            break;
+
+        case ESP_GAP_BLE_NC_REQ_EVT:
+            /* The app will receive this event when the IO has DisplayYesNO capability and the peer device IO also has DisplayYesNo capability.
+            show the passkey number to the user to confirm it with the number displayed by peer device. */
+            ESP_LOGI(EXAMPLE_TAG, "ESP_GAP_BLE_NC_REQ_EVT, the passkey Notify number:%" PRIu32, param->ble_security.key_notif.passkey);
+            break;
+        case ESP_GAP_BLE_SEC_REQ_EVT:
+            /* send the positive(true) security response to the peer device to accept the security request.
+            If not accept the security request, should send the security response with negative(false) accept value*/
+            esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
+            break;
+        case ESP_GAP_BLE_PASSKEY_NOTIF_EVT:  ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability.
+            ///show the passkey number to the user to input it in the peer device.
+            ESP_LOGI(EXAMPLE_TAG, "The passkey notify number:%06" PRIu32, param->ble_security.key_notif.passkey);
+            break;
+        case ESP_GAP_BLE_KEY_EVT:
+            //shows the ble key info share with peer device to the user.
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "key type = %s", esp_key_type_to_str(param->ble_security.ble_key.key_type));
+            break;
+        case ESP_GAP_BLE_AUTH_CMPL_EVT: {
+            esp_bd_addr_t bd_addr;
+            memcpy(bd_addr, param->ble_security.auth_cmpl.bd_addr, sizeof(esp_bd_addr_t));
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "remote BD_ADDR: %08x%04x",\
+                    (bd_addr[0] << 24) + (bd_addr[1] << 16) + (bd_addr[2] << 8) + bd_addr[3],
+                    (bd_addr[4] << 8) + bd_addr[5]);
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "address type = %d", param->ble_security.auth_cmpl.addr_type);
+            if (param->ble_security.auth_cmpl.success){
+                ESP_LOGI(EXAMPLE_TAG, "(1) ***** pair status = success ***** ");
+            }
+            else {
+                ESP_LOGI(EXAMPLE_TAG, "***** pair status = fail, reason = 0x%x *****", param->ble_security.auth_cmpl.fail_reason);
+            }
+            show_bonded_devices();
+            break;
+        }
+        case ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT: {
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "ESP_GAP_BLE_REMOVE_BOND_DEV_COMPLETE_EVT status = %d", param->remove_bond_dev_cmpl.status);
+            #if DEBUG_ON
+            ESP_LOG_BUFFER_HEX(EXAMPLE_TAG, (void *)param->remove_bond_dev_cmpl.bd_addr, sizeof(esp_bd_addr_t));
+            #endif
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "------------------------------------");
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
+{
+    EXAMPLE_DEBUG(EXAMPLE_TAG, "prepare write, handle = %d, value len = %d", param->write.handle, param->write.len);
+    esp_gatt_status_t status = ESP_GATT_OK;
+    if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
+        status = ESP_GATT_INVALID_OFFSET;
+    } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
+        status = ESP_GATT_INVALID_ATTR_LEN;
+    }
+
+    if (status == ESP_GATT_OK && prepare_write_env->prepare_buf == NULL) {
+        prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
+        prepare_write_env->prepare_len = 0;
+        if (prepare_write_env->prepare_buf == NULL) {
+            ESP_LOGE(EXAMPLE_TAG, "%s, Gatt_server prep no mem", __func__);
+            status = ESP_GATT_NO_RESOURCES;
+        }
+    }
+
+    /*send response when param->write.need_rsp is true */
+    if (param->write.need_rsp){
+        esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
+        if (gatt_rsp != NULL){
+            gatt_rsp->attr_value.len = param->write.len;
+            gatt_rsp->attr_value.handle = param->write.handle;
+            gatt_rsp->attr_value.offset = param->write.offset;
+            gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
+            memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
+            esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
+            if (response_err != ESP_OK){
+               ESP_LOGE(EXAMPLE_TAG, "Send response error");
+            }
+            free(gatt_rsp);
+        }else{
+            ESP_LOGE(EXAMPLE_TAG, "%s, malloc failed, and no resource to send response", __func__);
+            status = ESP_GATT_NO_RESOURCES;
+        }
+    }
+    if (status != ESP_GATT_OK){
+        return;
+    }
+    memcpy(prepare_write_env->prepare_buf + param->write.offset,
+           param->write.value,
+           param->write.len);
+    prepare_write_env->prepare_len += param->write.len;
+
+}
+uint8_t long_write[16] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF};
+void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
+    if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC && prepare_write_env->prepare_buf){
+        if(prepare_write_env->prepare_len == 256) {
+            bool long_write_success = true;
+            for(uint16_t i = 0; i < prepare_write_env->prepare_len; i ++) {
+                if(prepare_write_env->prepare_buf[i] != long_write[i%16]) {
+                    long_write_success = false;
+                    break;
+                }
+            }
+            if(long_write_success) {
+                ESP_LOGI(EXAMPLE_TAG, "(4) ***** long write success ***** ");
+            }
+        }
+    }else{
+        ESP_LOGI(EXAMPLE_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
+    }
+    if (prepare_write_env->prepare_buf) {
+        free(prepare_write_env->prepare_buf);
+        prepare_write_env->prepare_buf = NULL;
+    }
+    prepare_write_env->prepare_len = 0;
+}
+
+static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
+{
+    switch (event) {
+        case ESP_GATTS_REG_EVT:{
+            esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
+            if (set_dev_name_ret){
+                ESP_LOGE(EXAMPLE_TAG, "set device name failed, error code = %x", set_dev_name_ret);
+            }
+    #ifdef CONFIG_SET_RAW_ADV_DATA
+            esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
+            if (raw_adv_ret){
+                ESP_LOGE(EXAMPLE_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
+            }
+            adv_config_done |= ADV_CONFIG_FLAG;
+            esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data));
+            if (raw_scan_ret){
+                ESP_LOGE(EXAMPLE_TAG, "config raw scan rsp data failed, error code = %x", raw_scan_ret);
+            }
+            adv_config_done |= SCAN_RSP_CONFIG_FLAG;
+    #else
+            //config adv data
+            esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
+            if (ret){
+                ESP_LOGE(EXAMPLE_TAG, "config adv data failed, error code = %x", ret);
+            }
+            adv_config_done |= ADV_CONFIG_FLAG;
+            //config scan response data
+            ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
+            if (ret){
+                ESP_LOGE(EXAMPLE_TAG, "config scan response data failed, error code = %x", ret);
+            }
+            adv_config_done |= SCAN_RSP_CONFIG_FLAG;
+    #endif
+            esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
+            if (create_attr_ret){
+                ESP_LOGE(EXAMPLE_TAG, "create attr table failed, error code = %x", create_attr_ret);
+            }
+        }
+       	    break;
+        case ESP_GATTS_READ_EVT:
+            //ESP_LOGE(EXAMPLE_TAG, "ESP_GATTS_READ_EVT, handle=0x%d, offset=%d", param->read.handle, param->read.offset);
+            if(gatt_db_handle_table[IDX_CHAR_VAL_A] == param->read.handle) {
+                ESP_LOGE(EXAMPLE_TAG, "(2) ***** read char1 ***** ");
+            }
+            if(gatt_db_handle_table[IDX_CHAR_VAL_B] == param->read.handle) {
+                ESP_LOGE(EXAMPLE_TAG, "(5) ***** read char2 ***** ");
+            }
+       	    break;
+        case ESP_GATTS_WRITE_EVT:
+            if (!param->write.is_prep){
+                // the data length of gattc write  must be less than GATTS_EXAMPLE_CHAR_VAL_LEN_MAX.
+                if (gatt_db_handle_table[IDX_CHAR_CFG_C_2] == param->write.handle && param->write.len == 2){
+                    uint16_t descr_value = param->write.value[1]<<8 | param->write.value[0];
+                    uint8_t notify_data[2];
+                    notify_data[0] = 0xAA;
+                    notify_data[1] = 0xBB;
+
+                    if (descr_value == 0x0001){
+                        //the size of notify_data[] need less than MTU size
+                        esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatt_db_handle_table[IDX_CHAR_VAL_C],
+                                                sizeof(notify_data), notify_data, false);
+                        ESP_LOGI(EXAMPLE_TAG, "(6) ***** send notify AA BB ***** ");
+                    }else if (descr_value == 0x0002){
+                        //the size of indicate_data[] need less than MTU size
+                        esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gatt_db_handle_table[IDX_CHAR_VAL_C],
+                                            sizeof(notify_data), notify_data, true);
+                    }
+                    else if (descr_value == 0x0000){
+                        ESP_LOGI(EXAMPLE_TAG, "notify/indicate disable ");
+                    }else{
+                        ESP_LOGE(EXAMPLE_TAG, "unknown descr value");
+                        ESP_LOG_BUFFER_HEX(EXAMPLE_TAG, param->write.value, param->write.len);
+                    }
+
+                }
+                if(gatt_db_handle_table[IDX_CHAR_VAL_A] == param->write.handle && param->write.len == 2) {
+                    uint8_t write_data[2] = {0x88, 0x99};
+                    if(memcmp(write_data, param->write.value, param->write.len) == 0) {
+                        ESP_LOGI(EXAMPLE_TAG, "(3)***** short write success ***** ");
+                    }
+                }
+
+                /* send response when param->write.need_rsp is true*/
+                if (param->write.need_rsp){
+                    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
+                }
+            }else{
+                /* handle prepare write */
+                example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
+            }
+      	    break;
+        case ESP_GATTS_EXEC_WRITE_EVT:
+            // the length of gattc prepare write data must be less than GATTS_EXAMPLE_CHAR_VAL_LEN_MAX.
+            ESP_LOGI(EXAMPLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT, Length=%d",  prepare_write_env.prepare_len);
+            example_exec_write_event_env(&prepare_write_env, param);
+            break;
+        case ESP_GATTS_MTU_EVT:
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
+            break;
+        case ESP_GATTS_CONF_EVT:
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "ESP_GATTS_CONF_EVT, status = %d", param->conf.status);
+            break;
+        case ESP_GATTS_START_EVT:
+            EXAMPLE_DEBUG(EXAMPLE_TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
+            break;
+        case ESP_GATTS_CONNECT_EVT:
+            ESP_LOGI(EXAMPLE_TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
+            /* start security connect with peer device when receive the connect event sent by the master */
+            esp_ble_set_encryption(param->connect.remote_bda, ESP_BLE_SEC_ENCRYPT_MITM);
+            break;
+        case ESP_GATTS_DISCONNECT_EVT:
+            ESP_LOGI(EXAMPLE_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = %d", param->disconnect.reason);
+            esp_ble_gap_start_advertising(&adv_params);
+            break;
+        case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
+            if (param->add_attr_tab.status != ESP_GATT_OK){
+                ESP_LOGE(EXAMPLE_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
+            }
+            else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
+                ESP_LOGE(EXAMPLE_TAG, "create attribute table abnormally, num_handle (%d) \
+                        doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB);
+            }
+            else {
+                ESP_LOGI(EXAMPLE_TAG, "create attribute table successfully, the number handle = %d",param->add_attr_tab.num_handle);
+                memcpy(gatt_db_handle_table, param->add_attr_tab.handles, sizeof(gatt_db_handle_table));
+                esp_ble_gatts_start_service(gatt_db_handle_table[IDX_SVC]);
+            }
+            break;
+        }
+        default:
+            break;
+    }
+}
+
+
+static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
+{
+
+    /* If event is register event, store the gatts_if for each profile */
+    if (event == ESP_GATTS_REG_EVT) {
+        if (param->reg.status == ESP_GATT_OK) {
+            heart_rate_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
+        } else {
+            ESP_LOGE(EXAMPLE_TAG, "reg app failed, app_id %04x, status %d",
+                    param->reg.app_id,
+                    param->reg.status);
+            return;
+        }
+    }
+    do {
+        int idx;
+        for (idx = 0; idx < PROFILE_NUM; idx++) {
+            /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
+            if (gatts_if == ESP_GATT_IF_NONE || gatts_if == heart_rate_profile_tab[idx].gatts_if) {
+                if (heart_rate_profile_tab[idx].gatts_cb) {
+                    heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param);
+                }
+            }
+        }
+    } while (0);
+}
+
+void app_main(void)
+{
+    esp_err_t ret;
+
+    /* Initialize NVS. */
+    ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+    /* initialize TRANSPORT first */
+    hosted_hci_bluedroid_open();
+
+    /* get HCI driver operations */
+    esp_bluedroid_hci_driver_operations_t operations = {
+        .send = hosted_hci_bluedroid_send,
+        .check_send_available = hosted_hci_bluedroid_check_send_available,
+        .register_host_callback = hosted_hci_bluedroid_register_host_callback,
+    };
+    esp_bluedroid_attach_hci_driver(&operations);
+
+
+#if 0
+    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
+
+    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+    ret = esp_bt_controller_init(&bt_cfg);
+    if (ret) {
+        ESP_LOGE(EXAMPLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
+    if (ret) {
+        ESP_LOGE(EXAMPLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+#endif
+
+    ret = esp_bluedroid_init();
+    if (ret) {
+        ESP_LOGE(EXAMPLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    ret = esp_bluedroid_enable();
+    if (ret) {
+        ESP_LOGE(EXAMPLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    ret = esp_ble_gatts_register_callback(gatts_event_handler);
+    if (ret){
+        ESP_LOGE(EXAMPLE_TAG, "gatts register error, error code = %x", ret);
+        return;
+    }
+
+    ret = esp_ble_gap_register_callback(gap_event_handler);
+    if (ret){
+        ESP_LOGE(EXAMPLE_TAG, "gap register error, error code = %x", ret);
+        return;
+    }
+
+    ret = esp_ble_gatts_app_register(ESP_APP_ID);
+    if (ret){
+        ESP_LOGE(EXAMPLE_TAG, "gatts app register error, error code = %x", ret);
+        return;
+    }
+
+    esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(33);
+    if (local_mtu_ret){
+        ESP_LOGE(EXAMPLE_TAG, "set local  MTU failed, error code = %x", local_mtu_ret);
+    }
+
+    /* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
+    esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND;     //bonding with peer device after authentication
+    esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT;           //set the IO capability to No output No input
+    uint8_t key_size = 16;      //the key size should be 7~16 bytes
+    uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
+    uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
+    uint32_t passkey = 123456;
+    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
+    esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
+    esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
+    esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
+    /* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribute to you,
+    and the response key means which key you can distribute to the Master;
+    If your BLE device act as a master, the response key means you hope which types of key of the slave should distribute to you,
+    and the init key means which key you can distribute to the slave. */
+    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
+    esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
+
+}

+ 31 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/ble_compatibility_test.h

@@ -0,0 +1,31 @@
+/*
+ * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+/* Attributes State Machine */
+enum
+{
+    IDX_SVC,
+    IDX_CHAR_A,
+    IDX_CHAR_VAL_A,
+    IDX_CHAR_CFG_A,
+
+    IDX_CHAR_B,
+    IDX_CHAR_VAL_B,
+    IDX_CHAR_CFG_B,
+
+    IDX_CHAR_C,
+    IDX_CHAR_VAL_C,
+    IDX_CHAR_CFG_C,
+    IDX_CHAR_CFG_C_2,
+
+    HRS_IDX_NB,
+};

+ 5 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/main/idf_component.yml

@@ -0,0 +1,5 @@
+dependencies:
+  espressif/esp_wifi_remote:
+    version: "~0.5.1"
+    rules:
+      - if: "target in [esp32p4, esp32h2]"

+ 8 - 0
esp-hosted/examples/host_bluedroid_ble_compatibility_test/sdkconfig.defaults

@@ -0,0 +1,8 @@
+# This file was generated using idf.py save-defconfig. It can be edited manually.
+# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
+#
+CONFIG_BT_ENABLED=y
+CONFIG_BT_BLE_50_FEATURES_SUPPORTED=n
+CONFIG_BT_BLE_42_FEATURES_SUPPORTED=y
+# CONFIG_BT_LE_50_FEATURE_SUPPORT is not used on ESP32, ESP32-C3 and ESP32-S3.
+CONFIG_BT_LE_50_FEATURE_SUPPORT=n

+ 9 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/CMakeLists.txt

@@ -0,0 +1,9 @@
+
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
+idf_build_set_property(MINIMAL_BUILD ON)
+project(bt_hid_mouse_device)

+ 298 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/README.md

@@ -0,0 +1,298 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 | ESP32-P4 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
+
+# Bluetooth HID Device example
+
+This example aims to show how to implement a Bluetooth HID device using the APIs provided by Classic Bluetooth HID profile.
+
+This example simulates a Bluetooth HID mouse device that periodically sends report to remote Bluetooth HID host after connection. The report indicates a horizontally moving pointer and can be observed on the display on the HID host side. If you want to build an HID device, this can be your first example to look at.
+
+## How to use example
+
+This example has been modified to work with ESP-Hosted. The original ESP-IDF example is at [ https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/classic_bt/bt_hid_mouse_device/ ].
+
+### Hardware Required
+
+* This example is able to run on the ESP32-P4 Dev Board, acting as the BT Host, connected to a ESP32 co-processor via the GPIO header, using SPI FD (full duplex) as ESP-Hosted transport (VHCI). The ESP32 acts as the BT Controller. The following GPIO settings were used:
+
+| SPI Function | ESP32 GPIO | ESP32-P4 GPIO |
+| :---         |       ---: |          ---: |
+| MOSI         |         13 |             4 |
+| MISO         |         12 |             5 |
+| CLK          |         14 |            26 |
+| CS           |         15 |             6 |
+| Handshake    |         26 |            20 |
+| Data Ready   |          4 |            36 |
+| Reset        |         -1 |             2 |
+
+> [!NOTE]
+> SPI Mode 2 was used on both the ESP32-P4 and ESP32.
+
+Users are free to choose which supported ESP-Hosted transport to use. See the [main ESP-Hosted README](https://github.com/espressif/esp-hosted-mcu/blob/main/README.md#6-decide-the-communication-bus-in-between-host-and-slave) for a list of supported transports.
+
+* This example is supposed to connect to a Classic Bluetooth HID Host device, e.g. laptop or tablet.
+
+### Configure the project
+
+On the ESP32-P4 Dev Board, run `idf.py menuconfig`.
+
+* Check and enable Classic Bluetooth and Classic BT HID Device under `Component config --> Bluetooth --> Bluedroid Options`
+* Ensure that `Component config --> Bluetooth --> Controller` is `Disabled`.
+* Under `Component config --> ESP-Hosted config`:
+  * Configure ESP-Hosted to use `SPI Full-duplex` as the transport
+  * Set the Slave chipset used as `ESP32`
+  * Check and enable `Bluetooth Support`
+  * Configure the GPIOs used for SPI FD on both the ESP32-P4 and ESP32, following the table above
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+```
+idf.py -p PORT flash monitor
+```
+
+(Replace PORT with the name of the serial port to use.)
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+The following log will be shown on the IDF monitor console:
+
+```
+I (499) main_task: Calling app_main()
+I (509) transport: Attempt connection with slave: retry[0]
+I (509) transport: Reset slave using GPIO[2]
+I (509) os_wrapper_esp: GPIO [2] configured
+I (509) gpio: GPIO[2]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
+I (1699) transport: Received INIT event from ESP32 peripheral
+I (1699) transport: EVENT: 12
+I (1699) transport: EVENT: 11
+I (1699) transport: capabilities: 0xf8
+I (1709) transport: Features supported are:
+I (1709) transport:        - HCI over SPI
+I (1709) transport:        - BT/BLE dual mode
+I (1719) transport: EVENT: 13
+I (1719) transport: ESP board type is : 0
+
+I (1719) transport: Base transport is set-up
+
+I (1729) transport: Slave chip Id[12]
+I (1729) vhci_drv: Host BT Support: Enabled
+I (1729) vhci_drv:      BT Transport Type: VHCI
+I (1739) spi: Received INIT event
+I (2799) app_main: setting device name
+I (2799) esp_bt_gap_cb: event: 10
+I (2799) app_main: setting cod major, peripheral
+I (4799) app_main: register hid device callback
+I (4799) app_main: starting hid device
+I (4799) esp_bt_hidd_cb: setting hid parameters
+I (4799) esp_bt_gap_cb: event: 10
+I (4799) esp_bt_hidd_cb: setting hid parameters success!
+I (4799) esp_bt_hidd_cb: setting to connectable, discoverable
+I (4809) app_main: Own address:[10:97:bd:d5:8a:62]
+I (4809) app_main: exiting
+```
+
+The messages show the successful initialization of Bluetooth stack and HID application. ESP32-P4 will become discoverable with the Bluetooth device name as "HID Mouse Example", by nearby Bluetooth HID Host device.
+
+Connect to ESP32-P4 on the HID Host side, then finish bonding. After that the HID connection will be established. IDF monitor console will continue to print messages like:
+
+```
+W (21229) BT_HCI: hcif conn complete: hdl 0x80, st 0x0
+I (21229) esp_bt_gap_cb: event: 16
+I (21859) esp_bt_gap_cb: authentication success: XXXXXXXX
+I (21859) esp_bt_gap_cb: 64 49 7d d0 fd 99
+I (21889) esp_bt_gap_cb: event: 21
+W (22299) BT_HIDD: hidd_l2cif_config_cfm: config failed, retry
+W (22319) BT_APPL: new conn_srvc id:20, app_id:1
+I (22319) esp_bt_hidd_cb: connected to 64:49:7d:d0:fd:99
+I (22319) mouse_move_task: starting
+I (22319) esp_bt_hidd_cb: making self non-discoverable and non-connectable.
+W (22329) BT_HCI: hci cmd send: sniff: hdl 0x80, intv(10 18)
+I (22339) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+W (22349) BT_HCI: hcif mode change: hdl 0x80, mode 2, intv 18, status 0x0
+I (22349) esp_bt_gap_cb: ESP_BT_GAP_MODE_CHG_EVT mode:2
+I (22369) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+I (22419) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+I (22469) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+I (22519) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+I (22569) esp_bt_hidd_cb: ESP_HIDD_SEND_REPORT_EVT id:0x00, type:1
+```
+
+ESP32-P4 will generate and send HID mouse reports periodically. On the screen of HID Host, the cursor will move horizontally from left to right and then right to left, and so on so forth.
+
+## Example Breakdown
+
+### Initial settings for Bluetooth HID device profile
+
+Bluetooth HID device requires the specific major and minor device type in the Class of Device (CoD), the following lines of source code performs the configuration of CoD:
+
+```
+void app_main(void) {
+    ...
+    ESP_LOGI(TAG, "setting cod major, peripheral");
+    esp_bt_cod_t cod;
+    cod.major = ESP_BT_COD_MAJOR_DEV_PERIPHERAL;
+    esp_bt_gap_set_cod(cod, ESP_BT_SET_COD_MAJOR_MINOR);
+    ...
+}
+```
+
+Bluetooth HID device profile requires the information of service name, provide, device subclass, report descriptor for SDP server, as well as L2CAP QoS configurations from the application. Following lines in function `app_main` initialize these information fields:
+
+```
+void app_main(void) {
+    ...
+    // Initialize HID SDP information and L2CAP parameters.
+    // to be used in the call of `esp_bt_hid_device_register_app` after profile initialization finishes
+    do {
+        s_local_param.app_param.name = "Mouse";
+        s_local_param.app_param.description = "Mouse Example";
+        s_local_param.app_param.provider = "ESP32";
+        s_local_param.app_param.subclass = ESP_HID_CLASS_MIC;
+        s_local_param.app_param.desc_list = hid_mouse_descriptor;
+        s_local_param.app_param.desc_list_len = hid_mouse_descriptor_len;
+
+        memset(&s_local_param.both_qos, 0, sizeof(esp_hidd_qos_param_t)); // don't set the qos parameters
+    } while (0);
+
+    // Report Protocol Mode is the default mode, according to Bluetooth HID specification
+    s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE;
+
+    ESP_LOGI(TAG, "register hid device callback");
+    esp_bt_hid_device_register_callback(esp_bt_hidd_cb);
+
+    ESP_LOGI(TAG, "starting hid device");
+    esp_bt_hid_device_init();
+    ...
+}
+```
+
+The information is set to global struct `s_local_param` and will be used upon successful profile initialization, i.e. reception of `ESP_HIDD_INIT_EVT` which is generated after the call of `esp_bt_hid_device_init()`:
+
+```
+void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
+{
+    ...
+    switch (event) {
+    case ESP_HIDD_INIT_EVT:
+        if (param->init.status == ESP_HIDD_SUCCESS) {
+            ESP_LOGI(TAG, "setting hid parameters");
+            esp_bt_hid_device_register_app(&s_local_param.app_param, &s_local_param.both_qos, &s_local_param.both_qos);
+        } else {
+            ESP_LOGE(TAG, "init hidd failed!");
+        }
+        break;
+    ...
+    }
+    ...
+}
+```
+
+### Determination of HID Report Mode
+
+There are two HID report modes: Report Protocol Mode and Boot Protocol Mode. The former is the default mode. The two report modes differ in the report contents and format. The example supports both of the two modes.
+
+Report Mode requires report descriptor to describe the usage and format of the reports. For Bluetooth HID device, the report descriptor shall be provided in the SDP server, which can be discovered and used by remote HID Host.
+
+Boot Mode only supports keyboards and mice, with pre-defined report formats. Therefore it does not require a report descriptor parser on the remote HID Host. It is originally used to simplify the design of PC BIOSs.
+
+The following code lines set Report Protocol Mode as the default Report Mode:
+
+```
+void app_main(void) {
+    ...
+    // Report Protocol Mode is the default mode, according to Bluetooth HID specification
+    s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE;
+    ...
+}
+```
+
+Report Mode can be choosen by remote HID Host through the SET_PROTOCOL request:
+
+```
+void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
+{
+    ...
+    switch (event) {
+    ...
+    case ESP_HIDD_SET_PROTOCOL_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_SET_PROTOCOL_EVT");
+        if (param->set_protocol.protocol_mode == ESP_HIDD_BOOT_MODE) {
+            ESP_LOGI(TAG, "  - boot protocol");
+            xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+            s_local_param.x_dir = -1;
+            xSemaphoreGive(s_local_param.mouse_mutex);
+        } else if (param->set_protocol.protocol_mode == ESP_HIDD_REPORT_MODE) {
+            ESP_LOGI(TAG, "  - report protocol");
+        }
+        xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+        s_local_param.protocol_mode = param->set_protocol.protocol_mode;
+        xSemaphoreGive(s_local_param.mouse_mutex);
+        break;
+    ....
+    }
+    ....
+}
+```
+
+### Report generation
+
+The example simulates a mouse by creating a FreeRTOS task that periodically generates and sends the HID mouse report:
+
+```
+// move the mouse left and right
+void mouse_move_task(void* pvParameters)
+{
+    const char* TAG = "mouse_move_task";
+
+    ESP_LOGI(TAG, "starting");
+    for(;;) {
+        s_local_param.x_dir = 1;
+        int8_t step = 10;
+        for (int i = 0; i < 2; i++) {
+            xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+            s_local_param.x_dir *= -1;
+            xSemaphoreGive(s_local_param.mouse_mutex);
+            for (int j = 0; j < 100; j++) {
+                send_mouse_report(0, s_local_param.x_dir * step, 0, 0);
+                vTaskDelay(50 / portTICK_PERIOD_MS);
+            }
+        }
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+}
+```
+
+Function `send_mouse_report` is used to pack the information into a mouse HID report and sends it to HID Host, according to the Report Mode applied:
+
+```
+// send the buttons, change in x, and change in y
+void send_mouse_report(uint8_t buttons, char dx, char dy, char wheel)
+{
+    uint8_t report_id;
+    uint16_t report_size;
+    xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+    if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) {
+        report_id = 0;
+        report_size = REPORT_PROTOCOL_MOUSE_REPORT_SIZE;
+        s_local_param.buffer[0] = buttons;
+        s_local_param.buffer[1] = dx;
+        s_local_param.buffer[2] = dy;
+        s_local_param.buffer[3] = wheel;
+    } else {
+        // Boot Mode
+        report_id = ESP_HIDD_BOOT_REPORT_ID_MOUSE;
+        report_size = ESP_HIDD_BOOT_REPORT_SIZE_MOUSE - 1;
+        s_local_param.buffer[0] = buttons;
+        s_local_param.buffer[1] = dx;
+        s_local_param.buffer[2] = dy;
+    }
+    esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, report_id, report_size, s_local_param.buffer);
+    xSemaphoreGive(s_local_param.mouse_mutex);
+}
+```

+ 8 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/CMakeLists.txt

@@ -0,0 +1,8 @@
+#set(COMPONENT_SRCS "main.c")
+#set(COMPONENT_ADD_INCLUDEDIRS "")
+
+#register_component()
+
+idf_component_register(SRCS "main.c"
+                    PRIV_REQUIRES bt nvs_flash esp_hosted
+                    INCLUDE_DIRS ".")

+ 15 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/Kconfig.projbuild

@@ -0,0 +1,15 @@
+menu "HID Example Configuration"
+    config EXAMPLE_SSP_ENABLED
+        bool "Secure Simple Pairing"
+        depends on BT_CLASSIC_ENABLED
+        default y
+        help
+            This enables the Secure Simple Pairing. If disable this option,
+            Bluedroid will only support Legacy Pairing
+
+    config EXAMPLE_LOCAL_DEVICE_NAME
+        string "Local Device Name"
+        default "HID Mouse Example"
+        help
+            Use this option to set local device name.
+endmenu

+ 5 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/idf_component.yml

@@ -0,0 +1,5 @@
+dependencies:
+  espressif/esp_wifi_remote:
+    version: "~0.5.1"
+    rules:
+      - if: "target in [esp32p4, esp32h2]"

+ 483 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/main/main.c

@@ -0,0 +1,483 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+#include "esp_log.h"
+#include "esp_hidd_api.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_err.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "esp_gap_bt_api.h"
+#include <string.h>
+#include <inttypes.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/semphr.h"
+
+#include "esp_hosted_bt.h"
+
+#define REPORT_PROTOCOL_MOUSE_REPORT_SIZE      (4)
+#define REPORT_BUFFER_SIZE                     REPORT_PROTOCOL_MOUSE_REPORT_SIZE
+
+static const char local_device_name[] = CONFIG_EXAMPLE_LOCAL_DEVICE_NAME;
+
+typedef struct {
+    esp_hidd_app_param_t app_param;
+    esp_hidd_qos_param_t both_qos;
+    uint8_t protocol_mode;
+    SemaphoreHandle_t mouse_mutex;
+    TaskHandle_t mouse_task_hdl;
+    uint8_t buffer[REPORT_BUFFER_SIZE];
+    int8_t x_dir;
+} local_param_t;
+
+static local_param_t s_local_param = {0};
+
+// HID report descriptor for a generic mouse. The contents of the report are:
+// 3 buttons, moving information for X and Y cursors, information for a wheel.
+uint8_t hid_mouse_descriptor[] = {
+    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
+    0x09, 0x02,                    // USAGE (Mouse)
+    0xa1, 0x01,                    // COLLECTION (Application)
+
+    0x09, 0x01,                    //   USAGE (Pointer)
+    0xa1, 0x00,                    //   COLLECTION (Physical)
+
+    0x05, 0x09,                    //     USAGE_PAGE (Button)
+    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
+    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
+    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
+    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
+    0x95, 0x03,                    //     REPORT_COUNT (3)
+    0x75, 0x01,                    //     REPORT_SIZE (1)
+    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
+    0x95, 0x01,                    //     REPORT_COUNT (1)
+    0x75, 0x05,                    //     REPORT_SIZE (5)
+    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
+
+    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
+    0x09, 0x30,                    //     USAGE (X)
+    0x09, 0x31,                    //     USAGE (Y)
+    0x09, 0x38,                    //     USAGE (Wheel)
+    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
+    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
+    0x75, 0x08,                    //     REPORT_SIZE (8)
+    0x95, 0x03,                    //     REPORT_COUNT (3)
+    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
+
+    0xc0,                          //   END_COLLECTION
+    0xc0                           // END_COLLECTION
+};
+
+static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
+{
+    if (bda == NULL || str == NULL || size < 18) {
+        return NULL;
+    }
+
+    uint8_t *p = bda;
+    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+            p[0], p[1], p[2], p[3], p[4], p[5]);
+    return str;
+}
+
+const int hid_mouse_descriptor_len = sizeof(hid_mouse_descriptor);
+
+/**
+ * @brief Integrity check of the report ID and report type for GET_REPORT request from HID host.
+ *        Boot Protocol Mode requires report ID. For Report Protocol Mode, when the report descriptor
+ *        does not declare report ID Global ITEMS, the report ID does not exist in the GET_REPORT request,
+ *        and a value of 0 for report_id will occur in ESP_HIDD_GET_REPORT_EVT callback parameter.
+ */
+bool check_report_id_type(uint8_t report_id, uint8_t report_type)
+{
+    bool ret = false;
+    xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+    do {
+        if (report_type != ESP_HIDD_REPORT_TYPE_INPUT) {
+            break;
+        }
+        if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
+            if (report_id == ESP_HIDD_BOOT_REPORT_ID_MOUSE) {
+                ret = true;
+                break;
+            }
+        } else {
+            if (report_id == 0) {
+                ret = true;
+                break;
+            }
+        }
+    } while (0);
+
+    if (!ret) {
+        if (s_local_param.protocol_mode == ESP_HIDD_BOOT_MODE) {
+            esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID);
+        } else {
+            esp_bt_hid_device_report_error(ESP_HID_PAR_HANDSHAKE_RSP_ERR_INVALID_REP_ID);
+        }
+    }
+    xSemaphoreGive(s_local_param.mouse_mutex);
+    return ret;
+}
+
+// send the buttons, change in x, and change in y
+void send_mouse_report(uint8_t buttons, char dx, char dy, char wheel)
+{
+    uint8_t report_id;
+    uint16_t report_size;
+    xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+    if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) {
+        report_id = 0;
+        report_size = REPORT_PROTOCOL_MOUSE_REPORT_SIZE;
+        s_local_param.buffer[0] = buttons;
+        s_local_param.buffer[1] = dx;
+        s_local_param.buffer[2] = dy;
+        s_local_param.buffer[3] = wheel;
+    } else {
+        // Boot Mode
+        report_id = ESP_HIDD_BOOT_REPORT_ID_MOUSE;
+        report_size = ESP_HIDD_BOOT_REPORT_SIZE_MOUSE - 1;
+        s_local_param.buffer[0] = buttons;
+        s_local_param.buffer[1] = dx;
+        s_local_param.buffer[2] = dy;
+    }
+    esp_bt_hid_device_send_report(ESP_HIDD_REPORT_TYPE_INTRDATA, report_id, report_size, s_local_param.buffer);
+    xSemaphoreGive(s_local_param.mouse_mutex);
+}
+
+// move the mouse left and right
+void mouse_move_task(void *pvParameters)
+{
+    const char *TAG = "mouse_move_task";
+
+    ESP_LOGI(TAG, "starting");
+    for (;;) {
+        s_local_param.x_dir = 1;
+        int8_t step = 10;
+        for (int i = 0; i < 2; i++) {
+            xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+            s_local_param.x_dir *= -1;
+            xSemaphoreGive(s_local_param.mouse_mutex);
+            for (int j = 0; j < 100; j++) {
+                send_mouse_report(0, s_local_param.x_dir * step, 0, 0);
+                vTaskDelay(50 / portTICK_PERIOD_MS);
+            }
+        }
+        vTaskDelay(1000 / portTICK_PERIOD_MS);
+    }
+}
+
+void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
+{
+    const char *TAG = "esp_bt_gap_cb";
+    switch (event) {
+    case ESP_BT_GAP_AUTH_CMPL_EVT: {
+        if (param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS) {
+            ESP_LOGI(TAG, "authentication success: %s", param->auth_cmpl.device_name);
+            ESP_LOG_BUFFER_HEX(TAG, param->auth_cmpl.bda, ESP_BD_ADDR_LEN);
+        } else {
+            ESP_LOGE(TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
+        }
+        break;
+    }
+    case ESP_BT_GAP_PIN_REQ_EVT: {
+        ESP_LOGI(TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
+        if (param->pin_req.min_16_digit) {
+            ESP_LOGI(TAG, "Input pin code: 0000 0000 0000 0000");
+            esp_bt_pin_code_t pin_code = {0};
+            esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
+        } else {
+            ESP_LOGI(TAG, "Input pin code: 1234");
+            esp_bt_pin_code_t pin_code;
+            pin_code[0] = '1';
+            pin_code[1] = '2';
+            pin_code[2] = '3';
+            pin_code[3] = '4';
+            esp_bt_gap_pin_reply(param->pin_req.bda, true, 4, pin_code);
+        }
+        break;
+    }
+
+#if (CONFIG_EXAMPLE_SSP_ENABLED == true)
+    case ESP_BT_GAP_CFM_REQ_EVT:
+        ESP_LOGI(TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %"PRIu32, param->cfm_req.num_val);
+        esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda, true);
+        break;
+    case ESP_BT_GAP_KEY_NOTIF_EVT:
+        ESP_LOGI(TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%"PRIu32, param->key_notif.passkey);
+        break;
+    case ESP_BT_GAP_KEY_REQ_EVT:
+        ESP_LOGI(TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
+        break;
+#endif
+    case ESP_BT_GAP_MODE_CHG_EVT:
+        ESP_LOGI(TAG, "ESP_BT_GAP_MODE_CHG_EVT mode:%d", param->mode_chg.mode);
+        break;
+    default:
+        ESP_LOGI(TAG, "event: %d", event);
+        break;
+    }
+    return;
+}
+
+void bt_app_task_start_up(void)
+{
+    s_local_param.mouse_mutex = xSemaphoreCreateMutex();
+    memset(s_local_param.buffer, 0, REPORT_BUFFER_SIZE);
+    xTaskCreate(mouse_move_task, "mouse_move_task", 2 * 1024, NULL, configMAX_PRIORITIES - 3, &s_local_param.mouse_task_hdl);
+    return;
+}
+
+void bt_app_task_shut_down(void)
+{
+    if (s_local_param.mouse_task_hdl) {
+        vTaskDelete(s_local_param.mouse_task_hdl);
+        s_local_param.mouse_task_hdl = NULL;
+    }
+
+    if (s_local_param.mouse_mutex) {
+        vSemaphoreDelete(s_local_param.mouse_mutex);
+        s_local_param.mouse_mutex = NULL;
+    }
+    return;
+}
+
+void esp_bt_hidd_cb(esp_hidd_cb_event_t event, esp_hidd_cb_param_t *param)
+{
+    static const char *TAG = "esp_bt_hidd_cb";
+    switch (event) {
+    case ESP_HIDD_INIT_EVT:
+        if (param->init.status == ESP_HIDD_SUCCESS) {
+            ESP_LOGI(TAG, "setting hid parameters");
+            esp_bt_hid_device_register_app(&s_local_param.app_param, &s_local_param.both_qos, &s_local_param.both_qos);
+        } else {
+            ESP_LOGE(TAG, "init hidd failed!");
+        }
+        break;
+    case ESP_HIDD_DEINIT_EVT:
+        break;
+    case ESP_HIDD_REGISTER_APP_EVT:
+        if (param->register_app.status == ESP_HIDD_SUCCESS) {
+            ESP_LOGI(TAG, "setting hid parameters success!");
+            ESP_LOGI(TAG, "setting to connectable, discoverable");
+            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            if (param->register_app.in_use) {
+                ESP_LOGI(TAG, "start virtual cable plug!");
+                esp_bt_hid_device_connect(param->register_app.bd_addr);
+            }
+        } else {
+            ESP_LOGE(TAG, "setting hid parameters failed!");
+        }
+        break;
+    case ESP_HIDD_UNREGISTER_APP_EVT:
+        if (param->unregister_app.status == ESP_HIDD_SUCCESS) {
+            ESP_LOGI(TAG, "unregister app success!");
+        } else {
+            ESP_LOGE(TAG, "unregister app failed!");
+        }
+        break;
+    case ESP_HIDD_OPEN_EVT:
+        if (param->open.status == ESP_HIDD_SUCCESS) {
+            if (param->open.conn_status == ESP_HIDD_CONN_STATE_CONNECTING) {
+                ESP_LOGI(TAG, "connecting...");
+            } else if (param->open.conn_status == ESP_HIDD_CONN_STATE_CONNECTED) {
+                ESP_LOGI(TAG, "connected to %02x:%02x:%02x:%02x:%02x:%02x", param->open.bd_addr[0],
+                         param->open.bd_addr[1], param->open.bd_addr[2], param->open.bd_addr[3], param->open.bd_addr[4],
+                         param->open.bd_addr[5]);
+                bt_app_task_start_up();
+                ESP_LOGI(TAG, "making self non-discoverable and non-connectable.");
+                esp_bt_gap_set_scan_mode(ESP_BT_NON_CONNECTABLE, ESP_BT_NON_DISCOVERABLE);
+            } else {
+                ESP_LOGE(TAG, "unknown connection status");
+            }
+        } else {
+            ESP_LOGE(TAG, "open failed!");
+        }
+        break;
+    case ESP_HIDD_CLOSE_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_CLOSE_EVT");
+        if (param->close.status == ESP_HIDD_SUCCESS) {
+            if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTING) {
+                ESP_LOGI(TAG, "disconnecting...");
+            } else if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTED) {
+                ESP_LOGI(TAG, "disconnected!");
+                bt_app_task_shut_down();
+                ESP_LOGI(TAG, "making self discoverable and connectable again.");
+                esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            } else {
+                ESP_LOGE(TAG, "unknown connection status");
+            }
+        } else {
+            ESP_LOGE(TAG, "close failed!");
+        }
+        break;
+    case ESP_HIDD_SEND_REPORT_EVT:
+        if (param->send_report.status == ESP_HIDD_SUCCESS) {
+            ESP_LOGI(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d", param->send_report.report_id,
+                     param->send_report.report_type);
+        } else {
+            ESP_LOGE(TAG, "ESP_HIDD_SEND_REPORT_EVT id:0x%02x, type:%d, status:%d, reason:%d",
+                     param->send_report.report_id, param->send_report.report_type, param->send_report.status,
+                     param->send_report.reason);
+        }
+        break;
+    case ESP_HIDD_REPORT_ERR_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_REPORT_ERR_EVT");
+        break;
+    case ESP_HIDD_GET_REPORT_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_GET_REPORT_EVT id:0x%02x, type:%d, size:%d", param->get_report.report_id,
+                 param->get_report.report_type, param->get_report.buffer_size);
+        if (check_report_id_type(param->get_report.report_id, param->get_report.report_type)) {
+            uint8_t report_id;
+            uint16_t report_len;
+            if (s_local_param.protocol_mode == ESP_HIDD_REPORT_MODE) {
+                report_id = 0;
+                report_len = REPORT_PROTOCOL_MOUSE_REPORT_SIZE;
+            } else {
+                // Boot Mode
+                report_id = ESP_HIDD_BOOT_REPORT_ID_MOUSE;
+                report_len = ESP_HIDD_BOOT_REPORT_SIZE_MOUSE - 1;
+            }
+            xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+            esp_bt_hid_device_send_report(param->get_report.report_type, report_id, report_len, s_local_param.buffer);
+            xSemaphoreGive(s_local_param.mouse_mutex);
+        } else {
+            ESP_LOGE(TAG, "check_report_id failed!");
+        }
+        break;
+    case ESP_HIDD_SET_REPORT_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_SET_REPORT_EVT");
+        break;
+    case ESP_HIDD_SET_PROTOCOL_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_SET_PROTOCOL_EVT");
+        if (param->set_protocol.protocol_mode == ESP_HIDD_BOOT_MODE) {
+            ESP_LOGI(TAG, "  - boot protocol");
+            xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+            s_local_param.x_dir = -1;
+            xSemaphoreGive(s_local_param.mouse_mutex);
+        } else if (param->set_protocol.protocol_mode == ESP_HIDD_REPORT_MODE) {
+            ESP_LOGI(TAG, "  - report protocol");
+        }
+        xSemaphoreTake(s_local_param.mouse_mutex, portMAX_DELAY);
+        s_local_param.protocol_mode = param->set_protocol.protocol_mode;
+        xSemaphoreGive(s_local_param.mouse_mutex);
+        break;
+    case ESP_HIDD_INTR_DATA_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_INTR_DATA_EVT");
+        break;
+    case ESP_HIDD_VC_UNPLUG_EVT:
+        ESP_LOGI(TAG, "ESP_HIDD_VC_UNPLUG_EVT");
+        if (param->vc_unplug.status == ESP_HIDD_SUCCESS) {
+            if (param->close.conn_status == ESP_HIDD_CONN_STATE_DISCONNECTED) {
+                ESP_LOGI(TAG, "disconnected!");
+                bt_app_task_shut_down();
+                ESP_LOGI(TAG, "making self discoverable and connectable again.");
+                esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+            } else {
+                ESP_LOGE(TAG, "unknown connection status");
+            }
+        } else {
+            ESP_LOGE(TAG, "close failed!");
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void app_main(void)
+{
+    const char *TAG = "app_main";
+    esp_err_t ret;
+    char bda_str[18] = {0};
+
+    ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+    /* initialize TRANSPORT first */
+    hosted_hci_bluedroid_open();
+
+    /* get HCI driver operations */
+    esp_bluedroid_hci_driver_operations_t operations = {
+        .send = hosted_hci_bluedroid_send,
+        .check_send_available = hosted_hci_bluedroid_check_send_available,
+        .register_host_callback = hosted_hci_bluedroid_register_host_callback,
+    };
+    esp_bluedroid_attach_hci_driver(&operations);
+
+    if ((ret = esp_bluedroid_init()) != ESP_OK) {
+        ESP_LOGE(TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    if ((ret = esp_bluedroid_enable()) != ESP_OK) {
+        ESP_LOGE(TAG, "enable bluedroid failed: %s", esp_err_to_name(ret));
+        return;
+    }
+
+    if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
+        ESP_LOGE(TAG, "gap register failed: %s", esp_err_to_name(ret));
+        return;
+    }
+
+    ESP_LOGI(TAG, "setting device name");
+    esp_bt_gap_set_device_name(local_device_name);
+
+    ESP_LOGI(TAG, "setting cod major, peripheral");
+    esp_bt_cod_t cod = {0};
+    cod.major = ESP_BT_COD_MAJOR_DEV_PERIPHERAL;
+    cod.minor = ESP_BT_COD_MINOR_PERIPHERAL_POINTING;
+    esp_bt_gap_set_cod(cod, ESP_BT_SET_COD_MAJOR_MINOR);
+
+    vTaskDelay(2000 / portTICK_PERIOD_MS);
+
+    // Initialize HID SDP information and L2CAP parameters.
+    // to be used in the call of `esp_bt_hid_device_register_app` after profile initialization finishes
+    do {
+        s_local_param.app_param.name = "Mouse";
+        s_local_param.app_param.description = "Mouse Example";
+        s_local_param.app_param.provider = "ESP32";
+        s_local_param.app_param.subclass = ESP_HID_CLASS_MIC; // keep same with minor class of COD
+        s_local_param.app_param.desc_list = hid_mouse_descriptor;
+        s_local_param.app_param.desc_list_len = hid_mouse_descriptor_len;
+
+        memset(&s_local_param.both_qos, 0, sizeof(esp_hidd_qos_param_t)); // don't set the qos parameters
+    } while (0);
+
+    // Report Protocol Mode is the default mode, according to Bluetooth HID specification
+    s_local_param.protocol_mode = ESP_HIDD_REPORT_MODE;
+
+    ESP_LOGI(TAG, "register hid device callback");
+    esp_bt_hid_device_register_callback(esp_bt_hidd_cb);
+
+    ESP_LOGI(TAG, "starting hid device");
+    esp_bt_hid_device_init();
+
+#if (CONFIG_EXAMPLE_SSP_ENABLED == true)
+    /* Set default parameters for Secure Simple Pairing */
+    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
+    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_NONE;
+    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
+#endif
+
+    /*
+     * Set default parameters for Legacy Pairing
+     * Use variable pin, input pin code when pairing
+     */
+    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
+    esp_bt_pin_code_t pin_code;
+    esp_bt_gap_set_pin(pin_type, 0, pin_code);
+
+    ESP_LOGI(TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
+    ESP_LOGI(TAG, "exiting");
+}

+ 7 - 0
esp-hosted/examples/host_bluedroid_bt_hid_mouse_device/sdkconfig.defaults

@@ -0,0 +1,7 @@
+CONFIG_BT_ENABLED=y
+CONFIG_BTDM_CTRL_MODE_BLE_ONLY=n
+CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=y
+CONFIG_BTDM_CTRL_MODE_BTDM=n
+CONFIG_BT_CLASSIC_ENABLED=y
+CONFIG_BT_HID_ENABLED=y
+CONFIG_BT_HID_DEVICE_ENABLED=y

+ 8 - 0
esp-hosted/examples/host_bluedroid_host_only/CMakeLists.txt

@@ -0,0 +1,8 @@
+# The following lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
+idf_build_set_property(MINIMAL_BUILD ON)
+project(host_hci_uart)

+ 100 - 0
esp-hosted/examples/host_bluedroid_host_only/README.md

@@ -0,0 +1,100 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-S3 | ESP32-P4 | ESP32-H2 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | -------- | -------- | -------- |
+
+ESP-IDF ESP-Hosed VHCI Host
+===========================
+
+This is a Bluetooth Host using ESP-Hosted as HCI IO to the BT Controller.
+
+## Example Layout
+
+This example is modified based on [bt_discovery](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/classic_bt/bt_discovery), and all modifications are listed below:
+
+- Removed all dependencies on controller from `main.c`.
+
+```
+#include "esp_bt.h"
+
+...
+
+ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE));
+
+esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
+    ESP_LOGE(GAP_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
+    return;
+}
+
+if ((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
+    ESP_LOGE(GAP_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
+    return;
+}
+```
+
+- Add support for ESP-Hosted HCI interface: `esp_hosted_bt.h`.
+
+- Open HCI interface in `main.c`.
+
+```
+#include "esp_hosted_bt.h"
+
+...
+
+/* initialize TRANSPORT first */
+hosted_hci_bluedroid_open();
+
+/* get HCI driver operations */
+esp_bluedroid_hci_driver_operations_t operations = {
+    .send = hosted_hci_bluedroid_uart_send,
+    .check_send_available = hosted_hci_bluedroid_check_send_available,
+    .register_host_callback = hosted_hci_bluedroid_register_host_callback,
+};
+esp_bluedroid_attach_hci_driver(&operations);
+```
+
+## How to use example
+
+### Hardware Required
+
+This example runs on the ESP32-P4 Dev Board connected to a ESP32 via the GPIO header, using SPI FD (full duplex) as ESP-Hosted transport (VHCI). The following GPIO settings were used:
+
+| SPI Function | ESP32 GPIO | ESP32-P4 GPIO |
+| :---         |       ---: |          ---: |
+| MOSI         |         13 |             4 |
+| MISO         |         12 |             5 |
+| CLK          |         14 |            26 |
+| CS           |         15 |             6 |
+| Handshake    |         26 |            20 |
+| Data Ready   |          4 |            36 |
+| Reset        |         -1 |             2 |
+
+> [!NOTE]
+> SPI Mode 2 was used on both the ESP32-P4 and ESP32.
+
+Users are free to choose which supported ESP-Hosted transport to use. See the [main ESP-Hosted README](https://github.com/espressif/esp-hosted-mcu/blob/main/README.md#6-decide-the-communication-bus-in-between-host-and-slave) for a list of supported transports.
+
+For standard HCI, configure the co-processor Bluetooth Controller to use UART as the HCI transport, then select appropriate GPIOs on the ESP32-P4 to configure as a UART. In this mode, ESP-Hosted is not involved in transporting the HCI data.
+
+See the ESP-IDF [UART HCI Host example](https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/bluedroid_host_only/bluedroid_host_only_uart) on how to set-up UART for the Bluetooth Host.
+
+### Configure the project
+
+For the ESP32 co-processor, run `idf.py menuconfig` and configure `Example Configuration` for SPI Full-duplex with the correct SPI mode and GPIOs.
+
+For the ESP32-P4 co-processor, run `idf.py menuconfig` and under `Component config ---> ESP-Hosted config`:
+
+* set the transport to be `SPI Full-duplex` with the correct SPI modem GPIOs (see above table) and SPI Clock frequency (10 MHz max).
+* set the Slave chipset used as `ESP32`.
+* set `Bluetooth Support ---> Enable Hosted Bluedroid Bluetooth support` to enable Bluedroid support. Leave the HCI type as `VHCI`.
+
+### Build and Flash
+
+Build and flash the co-processor and host projects, then run monitor tool to view serial output on both the ESP32 and ESP32-P4:
+
+```
+idf.py -p PORT flash monitor
+```
+
+(Replace PORT with the name of the serial port to use.)
+
+(To exit the serial monitor, type ``Ctrl-]``.)

+ 3 - 0
esp-hosted/examples/host_bluedroid_host_only/main/CMakeLists.txt

@@ -0,0 +1,3 @@
+idf_component_register(SRCS "main.c"
+                    PRIV_REQUIRES bt nvs_flash esp_hosted
+                    INCLUDE_DIRS ".")

+ 5 - 0
esp-hosted/examples/host_bluedroid_host_only/main/idf_component.yml

@@ -0,0 +1,5 @@
+dependencies:
+  espressif/esp_wifi_remote:
+    version: "~0.5.1"
+    rules:
+      - if: "target in [esp32p4, esp32h2]"

+ 307 - 0
esp-hosted/examples/host_bluedroid_host_only/main/main.c

@@ -0,0 +1,307 @@
+/*
+ * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Unlicense OR CC0-1.0
+ */
+
+
+
+/****************************************************************************
+*
+* This file is for Classic Bluetooth device and service discovery Demo.
+*
+****************************************************************************/
+
+#include <stdint.h>
+#include <string.h>
+#include <inttypes.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "nvs.h"
+#include "nvs_flash.h"
+#include "esp_system.h"
+#include "esp_log.h"
+#include "esp_bt_main.h"
+#include "esp_bt_device.h"
+#include "esp_gap_bt_api.h"
+#include "esp_bluedroid_hci.h"
+
+#include "esp_hosted_bt.h"
+
+#define GAP_TAG          "GAP"
+
+typedef enum {
+    APP_GAP_STATE_IDLE = 0,
+    APP_GAP_STATE_DEVICE_DISCOVERING,
+    APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE,
+    APP_GAP_STATE_SERVICE_DISCOVERING,
+    APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE,
+} app_gap_state_t;
+
+typedef struct {
+    bool dev_found;
+    uint8_t bdname_len;
+    uint8_t eir_len;
+    uint8_t rssi;
+    uint32_t cod;
+    uint8_t eir[ESP_BT_GAP_EIR_DATA_LEN];
+    uint8_t bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
+    esp_bd_addr_t bda;
+    app_gap_state_t state;
+} app_gap_cb_t;
+
+static app_gap_cb_t m_dev_info;
+
+static char *bda2str(esp_bd_addr_t bda, char *str, size_t size)
+{
+    if (bda == NULL || str == NULL || size < 18) {
+        return NULL;
+    }
+
+    uint8_t *p = bda;
+    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+            p[0], p[1], p[2], p[3], p[4], p[5]);
+    return str;
+}
+
+static char *uuid2str(esp_bt_uuid_t *uuid, char *str, size_t size)
+{
+    if (uuid == NULL || str == NULL) {
+        return NULL;
+    }
+
+    if (uuid->len == 2 && size >= 5) {
+        sprintf(str, "%04x", uuid->uuid.uuid16);
+    } else if (uuid->len == 4 && size >= 9) {
+        sprintf(str, "%08"PRIx32, uuid->uuid.uuid32);
+    } else if (uuid->len == 16 && size >= 37) {
+        uint8_t *p = uuid->uuid.uuid128;
+        sprintf(str, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                p[15], p[14], p[13], p[12], p[11], p[10], p[9], p[8],
+                p[7], p[6], p[5], p[4], p[3], p[2], p[1], p[0]);
+    } else {
+        return NULL;
+    }
+
+    return str;
+}
+
+static bool get_name_from_eir(uint8_t *eir, uint8_t *bdname, uint8_t *bdname_len)
+{
+    uint8_t *rmt_bdname = NULL;
+    uint8_t rmt_bdname_len = 0;
+
+    if (!eir) {
+        return false;
+    }
+
+    rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
+    if (!rmt_bdname) {
+        rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
+    }
+
+    if (rmt_bdname) {
+        if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
+            rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
+        }
+
+        if (bdname) {
+            memcpy(bdname, rmt_bdname, rmt_bdname_len);
+            bdname[rmt_bdname_len] = '\0';
+        }
+        if (bdname_len) {
+            *bdname_len = rmt_bdname_len;
+        }
+        return true;
+    }
+
+    return false;
+}
+
+static void update_device_info(esp_bt_gap_cb_param_t *param)
+{
+    char bda_str[18];
+    uint32_t cod = 0;
+    int32_t rssi = -129; /* invalid value */
+    uint8_t *bdname = NULL;
+    uint8_t bdname_len = 0;
+    uint8_t *eir = NULL;
+    uint8_t eir_len = 0;
+    esp_bt_gap_dev_prop_t *p;
+
+    ESP_LOGI(GAP_TAG, "Device found: %s", bda2str(param->disc_res.bda, bda_str, 18));
+    for (int i = 0; i < param->disc_res.num_prop; i++) {
+        p = param->disc_res.prop + i;
+        switch (p->type) {
+        case ESP_BT_GAP_DEV_PROP_COD:
+            cod = *(uint32_t *)(p->val);
+            ESP_LOGI(GAP_TAG, "--Class of Device: 0x%"PRIx32, cod);
+            break;
+        case ESP_BT_GAP_DEV_PROP_RSSI:
+            rssi = *(int8_t *)(p->val);
+            ESP_LOGI(GAP_TAG, "--RSSI: %"PRId32, rssi);
+            break;
+        case ESP_BT_GAP_DEV_PROP_BDNAME:
+            bdname_len = (p->len > ESP_BT_GAP_MAX_BDNAME_LEN) ? ESP_BT_GAP_MAX_BDNAME_LEN :
+                          (uint8_t)p->len;
+            bdname = (uint8_t *)(p->val);
+            break;
+        case ESP_BT_GAP_DEV_PROP_EIR: {
+            eir_len = p->len;
+            eir = (uint8_t *)(p->val);
+            break;
+        }
+        default:
+            break;
+        }
+    }
+
+    /* search for device with Major device type "PHONE" or "Audio/Video" in COD */
+    app_gap_cb_t *p_dev = &m_dev_info;
+    if (p_dev->dev_found) {
+        return;
+    }
+
+    if (!esp_bt_gap_is_valid_cod(cod) ||
+	    (!(esp_bt_gap_get_cod_major_dev(cod) == ESP_BT_COD_MAJOR_DEV_PHONE) &&
+             !(esp_bt_gap_get_cod_major_dev(cod) == ESP_BT_COD_MAJOR_DEV_AV))) {
+        return;
+    }
+
+    memcpy(p_dev->bda, param->disc_res.bda, ESP_BD_ADDR_LEN);
+    p_dev->dev_found = true;
+
+    p_dev->cod = cod;
+    p_dev->rssi = rssi;
+    if (bdname_len > 0) {
+        memcpy(p_dev->bdname, bdname, bdname_len);
+        p_dev->bdname[bdname_len] = '\0';
+        p_dev->bdname_len = bdname_len;
+    }
+    if (eir_len > 0) {
+        memcpy(p_dev->eir, eir, eir_len);
+        p_dev->eir_len = eir_len;
+    }
+
+    if (p_dev->bdname_len == 0) {
+        get_name_from_eir(p_dev->eir, p_dev->bdname, &p_dev->bdname_len);
+    }
+
+    ESP_LOGI(GAP_TAG, "Found a target device, address %s, name %s", bda_str, p_dev->bdname);
+    p_dev->state = APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE;
+    ESP_LOGI(GAP_TAG, "Cancel device discovery ...");
+    esp_bt_gap_cancel_discovery();
+}
+
+static void bt_app_gap_init(void)
+{
+    app_gap_cb_t *p_dev = &m_dev_info;
+    memset(p_dev, 0, sizeof(app_gap_cb_t));
+
+    p_dev->state = APP_GAP_STATE_IDLE;
+}
+
+static void bt_app_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
+{
+    app_gap_cb_t *p_dev = &m_dev_info;
+    char bda_str[18];
+    char uuid_str[37];
+
+    switch (event) {
+    case ESP_BT_GAP_DISC_RES_EVT: {
+        update_device_info(param);
+        break;
+    }
+    case ESP_BT_GAP_DISC_STATE_CHANGED_EVT: {
+        if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STOPPED) {
+            ESP_LOGI(GAP_TAG, "Device discovery stopped.");
+            if ( (p_dev->state == APP_GAP_STATE_DEVICE_DISCOVER_COMPLETE ||
+                    p_dev->state == APP_GAP_STATE_DEVICE_DISCOVERING)
+                    && p_dev->dev_found) {
+                p_dev->state = APP_GAP_STATE_SERVICE_DISCOVERING;
+                ESP_LOGI(GAP_TAG, "Discover services ...");
+                esp_bt_gap_get_remote_services(p_dev->bda);
+            }
+        } else if (param->disc_st_chg.state == ESP_BT_GAP_DISCOVERY_STARTED) {
+            ESP_LOGI(GAP_TAG, "Discovery started.");
+        }
+        break;
+    }
+    case ESP_BT_GAP_RMT_SRVCS_EVT: {
+        if (memcmp(param->rmt_srvcs.bda, p_dev->bda, ESP_BD_ADDR_LEN) == 0 &&
+                p_dev->state == APP_GAP_STATE_SERVICE_DISCOVERING) {
+            p_dev->state = APP_GAP_STATE_SERVICE_DISCOVER_COMPLETE;
+            if (param->rmt_srvcs.stat == ESP_BT_STATUS_SUCCESS) {
+                ESP_LOGI(GAP_TAG, "Services for device %s found",  bda2str(p_dev->bda, bda_str, 18));
+                for (int i = 0; i < param->rmt_srvcs.num_uuids; i++) {
+                    esp_bt_uuid_t *u = param->rmt_srvcs.uuid_list + i;
+                    ESP_LOGI(GAP_TAG, "--%s", uuid2str(u, uuid_str, 37));
+                }
+            } else {
+                ESP_LOGI(GAP_TAG, "Services for device %s not found",  bda2str(p_dev->bda, bda_str, 18));
+            }
+        }
+        break;
+    }
+    case ESP_BT_GAP_RMT_SRVC_REC_EVT:
+    default: {
+        ESP_LOGI(GAP_TAG, "event: %d", event);
+        break;
+    }
+    }
+    return;
+}
+
+static void bt_app_gap_start_up(void)
+{
+    /* register GAP callback function */
+    esp_bt_gap_register_callback(bt_app_gap_cb);
+
+    char *dev_name = "ESP_GAP_INQRUIY";
+    esp_bt_gap_set_device_name(dev_name);
+
+    /* set discoverable and connectable mode, wait to be connected */
+    esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
+
+    /* initialize device information and status */
+    bt_app_gap_init();
+
+    /* start to discover nearby Bluetooth devices */
+    app_gap_cb_t *p_dev = &m_dev_info;
+    p_dev->state = APP_GAP_STATE_DEVICE_DISCOVERING;
+    esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0);
+}
+
+void app_main(void)
+{
+    /* Initialize NVS — it is used to store PHY calibration data and save key-value pairs in flash memory*/
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK( ret );
+
+    /* initialize TRANSPORT first */
+    hosted_hci_bluedroid_open();
+
+    /* get HCI driver operations */
+    esp_bluedroid_hci_driver_operations_t operations = {
+        .send = hosted_hci_bluedroid_send,
+        .check_send_available = hosted_hci_bluedroid_check_send_available,
+        .register_host_callback = hosted_hci_bluedroid_register_host_callback,
+    };
+    esp_bluedroid_attach_hci_driver(&operations);
+
+    if ((ret = esp_bluedroid_init()) != ESP_OK) {
+        ESP_LOGE(GAP_TAG, "%s initialize bluedroid failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    if ((ret = esp_bluedroid_enable()) != ESP_OK) {
+        ESP_LOGE(GAP_TAG, "%s enable bluedroid failed: %s", __func__, esp_err_to_name(ret));
+        return;
+    }
+
+    bt_app_gap_start_up();
+}

+ 4 - 0
esp-hosted/examples/host_bluedroid_host_only/sdkconfig.defaults

@@ -0,0 +1,4 @@
+CONFIG_BT_CONTROLLER_DISABLED=y
+CONFIG_BT_ENABLED=y
+CONFIG_BT_BLUEDROID_ENABLED=y
+CONFIG_BT_CLASSIC_ENABLED=y

+ 6 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/CMakeLists.txt

@@ -0,0 +1,6 @@
+# The following lines of boilerplate have to be in your project's
+# CMakeLists in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(bleprph_host_only_vhci)

+ 202 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/README.md

@@ -0,0 +1,202 @@
+| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-H2 | ESP32-S3 | ESP32-P4 |
+| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
+
+# BLE Host-Only Peripheral VHCI Example
+
+This example uses the Bluetooth VHCI transport provided by ESP-Hosted.
+
+To use the VHCI transport in the application, the Bluetooth controller
+should be disabled and the default uart-transport should also be
+disabled (when the controller is disabled, by default the
+uart-transport is selected). The Bluetooth VHCI transport in
+ESP-Hosted should also be enabled.
+
+Refer to the `sdkconfig.defaults` file which has the required
+configuration.
+
+To test this demo, any BLE scanner app can be used.
+
+## How to Use This Example
+
+Before project configuration and build, be sure to set the correct
+chip target using:
+
+```bash
+idf.py set-target <chip_name>
+```
+
+### Configure the project
+
+Open the project configuration menu:
+
+```bash
+idf.py menuconfig
+```
+
+In the `Component config-> Bluetooth` menu:
+
+* Select `controller` to Disabled.
+* Disable `Nimble Options-> Host-controller Transport -> Enable Uart Transport`.
+
+In the `Component config-> ESP-Hosted config` menu:
+
+* Enable `Bluetooth Support-> Enable Hosted Bluetooth support`
+
+### Build and Flash
+
+Run `idf.py -p PORT flash monitor` to build, flash and monitor the
+project.
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the [Getting Started Guide](https://idf.espressif.com/) for full
+steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+
+This is the console output when `bleprph_host_only_vhci` is running on
+the ESP32-P4 and using the Bluetooth Controller of the ESP32C6 on the
+ESP32-P4-Function-EV-Board. The data is transferred through SDIO
+between the ESP32-P4 and ESP32-C6:
+
+```
+I (25) boot: ESP-IDF v5.4-dev-2793-g24047f9a04-dirty 2nd stage bootloader
+I (26) boot: compile time Sep  9 2024 16:23:48
+I (27) boot: Multicore bootloader
+I (32) boot: chip revision: v0.1
+I (34) boot: efuse block revision: v0.0
+I (39) boot.esp32p4: SPI Speed      : 80MHz
+I (44) boot.esp32p4: SPI Mode       : DIO
+I (49) boot.esp32p4: SPI Flash Size : 2MB
+I (53) boot: Enabling RNG early entropy source...
+I (59) boot: Partition Table:
+I (62) boot: ## Label            Usage          Type ST Offset   Length
+I (70) boot:  0 nvs              WiFi data        01 02 00009000 00006000
+I (77) boot:  1 phy_init         RF data          01 01 0000f000 00001000
+I (84) boot:  2 factory          factory app      00 00 00010000 00100000
+I (93) boot: End of partition table
+I (96) esp_image: segment 0: paddr=00010020 vaddr=40070020 size=2ae08h (175624) map
+I (135) esp_image: segment 1: paddr=0003ae30 vaddr=30100000 size=0000ch (    12) load
+I (137) esp_image: segment 2: paddr=0003ae44 vaddr=3010000c size=00038h (    56) load
+I (142) esp_image: segment 3: paddr=0003ae84 vaddr=4ff00000 size=05194h ( 20884) load
+I (154) esp_image: segment 4: paddr=00040020 vaddr=40000020 size=638b0h (407728) map
+I (226) esp_image: segment 5: paddr=000a38d8 vaddr=4ff05194 size=0b9a0h ( 47520) load
+I (237) esp_image: segment 6: paddr=000af280 vaddr=4ff10b80 size=02328h (  9000) load
+I (244) boot: Loaded app from partition at offset 0x10000
+I (244) boot: Disabling RNG early entropy source...
+I (258) cpu_start: Multicore app
+W (267) clk: esp_perip_clk_init() has not been implemented yet
+I (274) cpu_start: Pro cpu start user code
+I (274) cpu_start: cpu freq: 360000000 Hz
+I (274) app_init: Application information:
+I (277) app_init: Project name:     bleprph_host_only_vhci
+I (283) app_init: App version:      1c568c9-dirty
+I (288) app_init: Compile time:     Sep  9 2024 16:23:43
+I (294) app_init: ELF file SHA256:  ee5a16527...
+I (299) app_init: ESP-IDF:          v5.4-dev-2793-g24047f9a04-dirty
+I (306) efuse_init: Min chip rev:     v0.1
+I (311) efuse_init: Max chip rev:     v0.99
+I (316) efuse_init: Chip rev:         v0.1
+I (321) heap_init: Initializing. RAM available for dynamic allocation:
+I (328) heap_init: At 4FF160B0 len 00024F10 (147 KiB): RAM
+I (334) heap_init: At 4FF3AFC0 len 00004BF0 (18 KiB): RAM
+I (340) heap_init: At 4FF40000 len 00060000 (384 KiB): RAM
+I (347) heap_init: At 50108080 len 00007F80 (31 KiB): RTCRAM
+I (353) heap_init: At 30100044 len 00001FBC (7 KiB): TCM
+I (360) spi_flash: detected chip: generic
+I (363) spi_flash: flash io: dio
+W (367) spi_flash: Detected size(16384k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
+I (381) host_init: ESP Hosted : Host chip_ip[18]
+I (409) H_API: ESP-Hosted starting. Hosted_Tasks: prio:23, stack: 5120 RPC_task_stack: 5120
+sdio_mempool_create free:181028 min-free:181028 lfb-def:139264 lfb-8bit:139264
+
+I (414) gpio: GPIO[18]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (423) gpio: GPIO[19]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (433) gpio: GPIO[14]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (442) gpio: GPIO[15]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (451) gpio: GPIO[16]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (461) gpio: GPIO[17]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
+I (470) H_API: ** add_esp_wifi_remote_channels **
+I (475) transport: Add ESP-Hosted channel IF[1]: S[0] Tx[0x4000d110] Rx[0x4001b4aa]
+0x4000d110: transport_drv_sta_tx at /home/kysoh/projects/esp_as_mcu_host/examples/bleprph_host_only_vhci/components/esp_hosted/host/drivers/transport/transport_drv.c:208
+0x4001b4aa: esp_wifi_remote_channel_rx at /home/kysoh/projects/esp_as_mcu_host/examples/bleprph_host_only_vhci/managed_components/espressif__esp_wifi_remote/esp_wifi_remote_net.c:19
+
+I (484) transport: Add ESP-Hosted channel IF[2]: S[0] Tx[0x4000d058] Rx[0x4001b4aa]
+0x4000d058: transport_drv_ap_tx at /home/kysoh/projects/esp_as_mcu_host/examples/bleprph_host_only_vhci/components/esp_hosted/host/drivers/transport/transport_drv.c:238
+0x4001b4aa: esp_wifi_remote_channel_rx at /home/kysoh/projects/esp_as_mcu_host/examples/bleprph_host_only_vhci/managed_components/espressif__esp_wifi_remote/esp_wifi_remote_net.c:19
+
+I (493) main_task: Started on CPU0
+I (503) main_task: Calling app_main()
+I (513) transport: Attempt connection with slave: retry[0]
+I (513) transport: Reset slave using GPIO[54]
+I (513) os_wrapper_esp: GPIO [54] configured
+I (513) gpio: GPIO[54]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
+I (1693) sdio_wrapper: SDIO master: Data-Lines: 4-bit Freq(KHz)[40000 KHz]
+I (1693) sdio_wrapper: GPIOs: CLK[18] CMD[19] D0[14] D1[15] D2[16] D3[17] Slave_Reset[54]
+I (1693) H_SDIO_DRV: Starting SDIO process rx task
+I (1693) sdio_wrapper: Queues: Tx[20] Rx[20] SDIO-Rx-Mode[1]
+I (1733) gpio: GPIO[15]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+I (1733) gpio: GPIO[17]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
+Name:
+Type: SDIO
+Speed: 40.00 MHz (limit: 40.00 MHz)
+Size: 0MB
+CSD: ver=1, sector_size=0, capacity=0 read_bl_len=0
+SCR: sd_spec=0, bus_width=0
+TUPLE: DEVICE, size: 3: D9 01 FF
+TUPLE: MANFID, size: 4
+  MANF: 0092, CARD: 6666
+TUPLE: FUNCID, size: 2: 0C 00
+TUPLE: FUNCE, size: 4: 00 00 02 32
+TUPLE: CONFIG, size: 5: 01 01 00 02 07
+TUPLE: CFTABLE_ENTRY, size: 8
+  INDX: C1, Intface: 1, Default: 1, Conf-Entry-Num: 1
+  IF: 41
+  FS: 30, misc: 0, mem_space: 1, irq: 1, io_space: 0, timing: 0, power: 0
+  IR: 30, mask: 1,   IRQ: FF FF
+  LEN: FFFF
+TUPLE: END
+I (1783) sdio_wrapper: Function 0 Blocksize: 512
+I (1793) sdio_wrapper: Function 1 Blocksize: 512
+I (1793) H_SDIO_DRV: SDIO Host operating in STREAMING MODE
+I (1803) H_SDIO_DRV: generate slave intr
+I (1813) transport: Received INIT event from ESP32 peripheral
+I (1813) transport: EVENT: 12
+I (1813) transport: EVENT: 11
+I (1823) transport: capabilities: 0xd
+I (1823) transport: Features supported are:
+I (1833) transport:      * WLAN
+I (1833) transport:        - HCI over SDIO
+I (1843) transport:        - BLE only
+I (1843) transport: EVENT: 13
+I (1843) transport: ESP board type is : 13
+
+I (1853) transport: Base transport is set-up
+
+I (1853) transport: Slave chip Id[12]
+I (1863) vhci_drv: Host BT Support: Enabled
+I (1863) vhci_drv:      BT Transport Type: VHCI
+I (1873) H_SDIO_DRV: Received INIT event
+I (1883) rpc_wrap: Received Slave ESP Init
+I (2623) NimBLE_BLE_PRPH: BLE Host Task Started
+I (2623) uart: queue free spaces: 8
+I (2623) main_task: Returned from app_main()
+I (2623) NimBLE: GAP procedure initiated: stop advertising.
+
+I (2633) NimBLE: Device Address:
+I (2633) NimBLE: 40:4c:ca:5b:9a:e2
+I (2633) NimBLE:
+
+I (2643) NimBLE: GAP procedure initiated: advertise;
+I (2643) NimBLE: disc_mode=2
+I (2653) NimBLE:  adv_channel_map=0 own_addr_type=0 adv_filter_policy=0 adv_itvl_min=0 adv_itvl_max=0
+I (2663) NimBLE:
+```
+
+## Troubleshooting
+
+For any technical queries, please open an [issue](https://github.com/espressif/esp-hosted-mcu/issues) on ESP-Hosted on GitHub. We will get back to you soon.
+
+## References
+
+* Bluetooth Implementation in ESP-Hosted: https://github.com/espressif/esp-hosted-mcu/blob/main/docs/bluetooth_design.md

+ 5 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/CMakeLists.txt

@@ -0,0 +1,5 @@
+set(srcs "main.c"
+         "gatt_svr.c")
+
+idf_component_register(SRCS "${srcs}"
+                       INCLUDE_DIRS ".")

+ 80 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/Kconfig.projbuild

@@ -0,0 +1,80 @@
+menu "Example Configuration"
+
+    choice EXAMPLE_USE_IO_TYPE
+        prompt "I/O Capability"
+        default BLE_SM_IO_CAP_NO_IO
+        help
+            I/O capability of device.
+
+        config BLE_SM_IO_CAP_DISP_ONLY
+            bool "DISPLAY ONLY"
+        config BLE_SM_IO_CAP_DISP_YES_NO
+            bool "DISPLAY YESNO"
+        config BLE_SM_IO_CAP_KEYBOARD_ONLY
+            bool "KEYBOARD ONLY"
+        config BLE_SM_IO_CAP_NO_IO
+            bool "Just works"
+        config BLE_SM_IO_CAP_KEYBOARD_DISP
+            bool "Both KEYBOARD & DISPLAY"
+    endchoice
+
+    config EXAMPLE_IO_TYPE
+        int
+        default 0 if BLE_SM_IO_CAP_DISP_ONLY
+        default 1 if BLE_SM_IO_CAP_DISP_YES_NO
+        default 2 if BLE_SM_IO_CAP_KEYBOARD_ONLY
+        default 3 if BLE_SM_IO_CAP_NO_IO
+        default 4 if BLE_SM_IO_CAP_KEYBOARD_DISP
+
+    config EXAMPLE_BONDING
+        bool
+        default n
+        prompt "Use Bonding"
+        help
+            Use this option to enable/disable bonding.
+
+    config EXAMPLE_MITM
+        bool
+        default n
+        prompt "MITM security"
+        help
+            Use this option to enable/disable MITM security.
+
+    config EXAMPLE_USE_SC
+        bool
+        depends on BT_NIMBLE_SM_SC
+        default n
+        prompt "Use Secure Connection feature"
+        help
+            Use this option to enable/disable Security Manager Secure Connection 4.2 feature.
+
+    config EXAMPLE_EXTENDED_ADV
+        bool
+        depends on SOC_BLE_50_SUPPORTED && BT_NIMBLE_50_FEATURE_SUPPORT
+        default y if SOC_ESP_NIMBLE_CONTROLLER
+        select BT_NIMBLE_EXT_ADV
+        prompt "Enable Extended Adv"
+        help
+            Use this option to enable extended advertising in the example.
+            If this option is disabled, ensure config BT_NIMBLE_EXT_ADV is
+            also disabled from Nimble stack menuconfig
+
+    config EXAMPLE_RANDOM_ADDR
+        bool
+        prompt "Advertise RANDOM Address"
+        help
+            Use this option to advertise a random address instead of public address
+
+    config EXAMPLE_ENCRYPTION
+        bool
+        prompt "Enable Link Encryption"
+        help
+            This adds Encrypted Read and Write permissions in the custom GATT server.
+
+    config EXAMPLE_RESOLVE_PEER_ADDR
+        bool
+        prompt "Enable resolving peer address"
+        help
+            Use this option to enable resolving peer's address.
+
+endmenu

+ 35 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/bleprph.h

@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#ifndef H_BLEPRPH_
+#define H_BLEPRPH_
+
+#include <stdbool.h>
+#include "nimble/ble.h"
+#include "modlog/modlog.h"
+#include "esp_peripheral.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct ble_hs_cfg;
+struct ble_gatt_register_ctxt;
+
+/** GATT server. */
+#define GATT_SVR_SVC_ALERT_UUID               0x1811
+#define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID   0x2A47
+#define GATT_SVR_CHR_NEW_ALERT                0x2A46
+#define GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID   0x2A48
+#define GATT_SVR_CHR_UNR_ALERT_STAT_UUID      0x2A45
+#define GATT_SVR_CHR_ALERT_NOT_CTRL_PT        0x2A44
+
+void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
+int gatt_svr_init(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 247 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/gatt_svr.c

@@ -0,0 +1,247 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+#include "services/gap/ble_svc_gap.h"
+#include "services/gatt/ble_svc_gatt.h"
+#include "bleprph.h"
+#include "services/ans/ble_svc_ans.h"
+
+/*** Maximum number of characteristics with the notify flag ***/
+#define MAX_NOTIFY 5
+
+static const ble_uuid128_t gatt_svr_svc_uuid =
+    BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
+                     0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
+
+/* A characteristic that can be subscribed to */
+static uint8_t gatt_svr_chr_val;
+static uint16_t gatt_svr_chr_val_handle;
+static const ble_uuid128_t gatt_svr_chr_uuid =
+    BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
+                     0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
+
+/* A custom descriptor */
+static uint8_t gatt_svr_dsc_val;
+static const ble_uuid128_t gatt_svr_dsc_uuid =
+    BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12,
+                     0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34);
+
+static int
+gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
+                struct ble_gatt_access_ctxt *ctxt,
+                void *arg);
+
+static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
+    {
+        /*** Service ***/
+        .type = BLE_GATT_SVC_TYPE_PRIMARY,
+        .uuid = &gatt_svr_svc_uuid.u,
+        .characteristics = (struct ble_gatt_chr_def[])
+        { {
+                /*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/
+                .uuid = &gatt_svr_chr_uuid.u,
+                .access_cb = gatt_svc_access,
+#if CONFIG_EXAMPLE_ENCRYPTION
+                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
+                BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
+                BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
+#else
+                .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
+#endif
+                .val_handle = &gatt_svr_chr_val_handle,
+                .descriptors = (struct ble_gatt_dsc_def[])
+                { {
+                      .uuid = &gatt_svr_dsc_uuid.u,
+#if CONFIG_EXAMPLE_ENCRYPTION
+                      .att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC,
+#else
+                      .att_flags = BLE_ATT_F_READ,
+#endif
+                      .access_cb = gatt_svc_access,
+                    }, {
+                      0, /* No more descriptors in this characteristic */
+                    }
+                },
+            }, {
+                0, /* No more characteristics in this service. */
+            }
+        },
+    },
+
+    {
+        0, /* No more services. */
+    },
+};
+
+static int
+gatt_svr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
+               void *dst, uint16_t *len)
+{
+    uint16_t om_len;
+    int rc;
+
+    om_len = OS_MBUF_PKTLEN(om);
+    if (om_len < min_len || om_len > max_len) {
+        return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
+    }
+
+    rc = ble_hs_mbuf_to_flat(om, dst, max_len, len);
+    if (rc != 0) {
+        return BLE_ATT_ERR_UNLIKELY;
+    }
+
+    return 0;
+}
+
+/**
+ * Access callback whenever a characteristic/descriptor is read or written to.
+ * Here reads and writes need to be handled.
+ * ctxt->op tells weather the operation is read or write and
+ * weather it is on a characteristic or descriptor,
+ * ctxt->dsc->uuid tells which characteristic/descriptor is accessed.
+ * attr_handle give the value handle of the attribute being accessed.
+ * Accordingly do:
+ *     Append the value to ctxt->om if the operation is READ
+ *     Write ctxt->om to the value if the operation is WRITE
+ **/
+static int
+gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
+                struct ble_gatt_access_ctxt *ctxt, void *arg)
+{
+    const ble_uuid_t *uuid;
+    int rc;
+
+    switch (ctxt->op) {
+    case BLE_GATT_ACCESS_OP_READ_CHR:
+        if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
+            MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
+                        conn_handle, attr_handle);
+        } else {
+            MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
+                        attr_handle);
+        }
+        uuid = ctxt->chr->uuid;
+        if (attr_handle == gatt_svr_chr_val_handle) {
+            rc = os_mbuf_append(ctxt->om,
+                                &gatt_svr_chr_val,
+                                sizeof(gatt_svr_chr_val));
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        goto unknown;
+
+    case BLE_GATT_ACCESS_OP_WRITE_CHR:
+        if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
+            MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
+                        conn_handle, attr_handle);
+        } else {
+            MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d",
+                        attr_handle);
+        }
+        uuid = ctxt->chr->uuid;
+        if (attr_handle == gatt_svr_chr_val_handle) {
+            rc = gatt_svr_write(ctxt->om,
+                                sizeof(gatt_svr_chr_val),
+                                sizeof(gatt_svr_chr_val),
+                                &gatt_svr_chr_val, NULL);
+            ble_gatts_chr_updated(attr_handle);
+            MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
+                        "all subscribed peers.\n");
+            return rc;
+        }
+        goto unknown;
+
+    case BLE_GATT_ACCESS_OP_READ_DSC:
+        if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
+            MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
+                        conn_handle, attr_handle);
+        } else {
+            MODLOG_DFLT(INFO, "Descriptor read by NimBLE stack; attr_handle=%d\n",
+                        attr_handle);
+        }
+        uuid = ctxt->dsc->uuid;
+        if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) {
+            rc = os_mbuf_append(ctxt->om,
+                                &gatt_svr_dsc_val,
+                                sizeof(gatt_svr_chr_val));
+            return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
+        }
+        goto unknown;
+
+    case BLE_GATT_ACCESS_OP_WRITE_DSC:
+        goto unknown;
+
+    default:
+        goto unknown;
+    }
+
+unknown:
+    /* Unknown characteristic/descriptor;
+     * The NimBLE host should not have called this function;
+     */
+    assert(0);
+    return BLE_ATT_ERR_UNLIKELY;
+}
+
+void
+gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
+{
+    char buf[BLE_UUID_STR_LEN];
+
+    switch (ctxt->op) {
+    case BLE_GATT_REGISTER_OP_SVC:
+        MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
+                    ctxt->svc.handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_CHR:
+        MODLOG_DFLT(DEBUG, "registering characteristic %s with "
+                    "def_handle=%d val_handle=%d\n",
+                    ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
+                    ctxt->chr.def_handle,
+                    ctxt->chr.val_handle);
+        break;
+
+    case BLE_GATT_REGISTER_OP_DSC:
+        MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n",
+                    ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
+                    ctxt->dsc.handle);
+        break;
+
+    default:
+        assert(0);
+        break;
+    }
+}
+
+int
+gatt_svr_init(void)
+{
+    int rc;
+
+    ble_svc_gap_init();
+    ble_svc_gatt_init();
+    ble_svc_ans_init();
+
+    rc = ble_gatts_count_cfg(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_gatts_add_svcs(gatt_svr_svcs);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Setting a value for the read-only descriptor */
+    gatt_svr_dsc_val = 0x99;
+
+    return 0;
+}

+ 7 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/idf_component.yml

@@ -0,0 +1,7 @@
+dependencies:
+  nimble_peripheral_utils:
+    path: ${IDF_PATH}/examples/bluetooth/nimble/common/nimble_peripheral_utils
+  espressif/esp_wifi_remote:
+    version: "~0.5.1"
+    rules:
+      - if: "target in [esp32p4, esp32h2]"

+ 550 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/main/main.c

@@ -0,0 +1,550 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "esp_log.h"
+#include "nvs_flash.h"
+/* BLE */
+#include "nimble/nimble_port.h"
+#include "nimble/nimble_port_freertos.h"
+#include "host/ble_hs.h"
+#include "host/util/util.h"
+#include "console/console.h"
+#include "services/gap/ble_svc_gap.h"
+#include "bleprph.h"
+
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+static uint8_t ext_adv_pattern_1[] = {
+    0x02, 0x01, 0x06,
+    0x03, 0x03, 0xab, 0xcd,
+    0x03, 0x03, 0x18, 0x11,
+    0x11, 0X09, 'n', 'i', 'm', 'b', 'l', 'e', '-', 'b', 'l', 'e', 'p', 'r', 'p', 'h', '-', 'e',
+};
+#endif
+
+static const char *tag = "NimBLE_BLE_PRPH";
+static int bleprph_gap_event(struct ble_gap_event *event, void *arg);
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+static uint8_t own_addr_type = BLE_OWN_ADDR_RANDOM;
+#else
+static uint8_t own_addr_type;
+#endif
+
+void ble_store_config_init(void);
+
+/**
+ * Logs information about a connection to the console.
+ */
+static void
+bleprph_print_conn_desc(struct ble_gap_conn_desc *desc)
+{
+    MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
+                desc->conn_handle, desc->our_ota_addr.type);
+    print_addr(desc->our_ota_addr.val);
+    MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
+                desc->our_id_addr.type);
+    print_addr(desc->our_id_addr.val);
+    MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
+                desc->peer_ota_addr.type);
+    print_addr(desc->peer_ota_addr.val);
+    MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
+                desc->peer_id_addr.type);
+    print_addr(desc->peer_id_addr.val);
+    MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
+                "encrypted=%d authenticated=%d bonded=%d\n",
+                desc->conn_itvl, desc->conn_latency,
+                desc->supervision_timeout,
+                desc->sec_state.encrypted,
+                desc->sec_state.authenticated,
+                desc->sec_state.bonded);
+}
+
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+/**
+ * Enables advertising with the following parameters:
+ *     o General discoverable mode.
+ *     o Undirected connectable mode.
+ */
+static void
+ext_bleprph_advertise(void)
+{
+    struct ble_gap_ext_adv_params params;
+    struct os_mbuf *data;
+    uint8_t instance = 0;
+    int rc;
+
+    /* First check if any instance is already active */
+    if(ble_gap_ext_adv_active(instance)) {
+        return;
+    }
+
+    /* use defaults for non-set params */
+    memset (&params, 0, sizeof(params));
+
+    /* enable connectable advertising */
+    params.connectable = 1;
+
+    /* advertise using random addr */
+    params.own_addr_type = BLE_OWN_ADDR_PUBLIC;
+
+    params.primary_phy = BLE_HCI_LE_PHY_1M;
+    params.secondary_phy = BLE_HCI_LE_PHY_2M;
+    //params.tx_power = 127;
+    params.sid = 1;
+
+    params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
+    params.itvl_max = BLE_GAP_ADV_FAST_INTERVAL1_MIN;
+
+    /* configure instance 0 */
+    rc = ble_gap_ext_adv_configure(instance, &params, NULL,
+                                   bleprph_gap_event, NULL);
+    assert (rc == 0);
+
+    /* in this case only scan response is allowed */
+
+    /* get mbuf for scan rsp data */
+    data = os_msys_get_pkthdr(sizeof(ext_adv_pattern_1), 0);
+    assert(data);
+
+    /* fill mbuf with scan rsp data */
+    rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1));
+    assert(rc == 0);
+
+    rc = ble_gap_ext_adv_set_data(instance, data);
+    assert (rc == 0);
+
+    /* start advertising */
+    rc = ble_gap_ext_adv_start(instance, 0, 0);
+    assert (rc == 0);
+}
+#else
+/**
+ * Enables advertising with the following parameters:
+ *     o General discoverable mode.
+ *     o Undirected connectable mode.
+ */
+static void
+bleprph_advertise(void)
+{
+    struct ble_gap_adv_params adv_params;
+    struct ble_hs_adv_fields fields;
+    const char *name;
+    int rc;
+
+    /**
+     *  Set the advertisement data included in our advertisements:
+     *     o Flags (indicates advertisement type and other general info).
+     *     o Advertising tx power.
+     *     o Device name.
+     *     o 16-bit service UUIDs (alert notifications).
+     */
+
+    memset(&fields, 0, sizeof fields);
+
+    /* Advertise two flags:
+     *     o Discoverability in forthcoming advertisement (general)
+     *     o BLE-only (BR/EDR unsupported).
+     */
+    fields.flags = BLE_HS_ADV_F_DISC_GEN |
+                   BLE_HS_ADV_F_BREDR_UNSUP;
+
+    /* Indicate that the TX power level field should be included; have the
+     * stack fill this value automatically.  This is done by assigning the
+     * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
+     */
+    fields.tx_pwr_lvl_is_present = 1;
+    fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
+
+    name = ble_svc_gap_device_name();
+    fields.name = (uint8_t *)name;
+    fields.name_len = strlen(name);
+    fields.name_is_complete = 1;
+
+    fields.uuids16 = (ble_uuid16_t[]) {
+        BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
+    };
+    fields.num_uuids16 = 1;
+    fields.uuids16_is_complete = 1;
+
+    rc = ble_gap_adv_set_fields(&fields);
+    if (rc != 0) {
+        MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
+        return;
+    }
+
+    /* Begin advertising. */
+    memset(&adv_params, 0, sizeof adv_params);
+    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
+    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
+    rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
+                           &adv_params, bleprph_gap_event, NULL);
+    if (rc != 0) {
+        MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
+        return;
+    }
+}
+#endif
+
+#if MYNEWT_VAL(BLE_POWER_CONTROL)
+static void bleprph_power_control(uint16_t conn_handle)
+{
+    int rc;
+
+    rc = ble_gap_read_remote_transmit_power_level(conn_handle, 0x01 );  // Attempting on LE 1M phy
+    assert (rc == 0);
+
+    rc = ble_gap_set_transmit_power_reporting_enable(conn_handle, 0x1, 0x1);
+    assert (rc == 0);
+}
+#endif
+
+/**
+ * The nimble host executes this callback when a GAP event occurs.  The
+ * application associates a GAP event callback with each connection that forms.
+ * bleprph uses the same callback for all connections.
+ *
+ * @param event                 The type of event being signalled.
+ * @param ctxt                  Various information pertaining to the event.
+ * @param arg                   Application-specified argument; unused by
+ *                                  bleprph.
+ *
+ * @return                      0 if the application successfully handled the
+ *                                  event; nonzero on failure.  The semantics
+ *                                  of the return code is specific to the
+ *                                  particular GAP event being signalled.
+ */
+static int
+bleprph_gap_event(struct ble_gap_event *event, void *arg)
+{
+    struct ble_gap_conn_desc desc;
+    int rc;
+
+    switch (event->type) {
+#if defined(BLE_GAP_EVENT_LINK_ESTAB)
+    case BLE_GAP_EVENT_LINK_ESTAB:
+#else
+    case BLE_GAP_EVENT_CONNECT:
+#endif
+        /* A new connection was established or a connection attempt failed. */
+        MODLOG_DFLT(INFO, "connection %s; status=%d ",
+                    event->connect.status == 0 ? "established" : "failed",
+                    event->connect.status);
+        if (event->connect.status == 0) {
+            rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
+            assert(rc == 0);
+            bleprph_print_conn_desc(&desc);
+        }
+        MODLOG_DFLT(INFO, "\n");
+
+        if (event->connect.status != 0) {
+            /* Connection failed; resume advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+            ext_bleprph_advertise();
+#else
+            bleprph_advertise();
+#endif
+        }
+
+#if MYNEWT_VAL(BLE_POWER_CONTROL)
+	bleprph_power_control(event->connect.conn_handle);
+#endif
+        return 0;
+
+    case BLE_GAP_EVENT_DISCONNECT:
+        MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
+        bleprph_print_conn_desc(&event->disconnect.conn);
+        MODLOG_DFLT(INFO, "\n");
+
+        /* Connection terminated; resume advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+        ext_bleprph_advertise();
+#else
+        bleprph_advertise();
+#endif
+        return 0;
+
+    case BLE_GAP_EVENT_CONN_UPDATE:
+        /* The central has updated the connection parameters. */
+        MODLOG_DFLT(INFO, "connection updated; status=%d ",
+                    event->conn_update.status);
+        rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
+        assert(rc == 0);
+        bleprph_print_conn_desc(&desc);
+        MODLOG_DFLT(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_ADV_COMPLETE:
+        MODLOG_DFLT(INFO, "advertise complete; reason=%d",
+                    event->adv_complete.reason);
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+        ext_bleprph_advertise();
+#else
+        bleprph_advertise();
+#endif
+        return 0;
+
+    case BLE_GAP_EVENT_ENC_CHANGE:
+        /* Encryption has been enabled or disabled for this connection. */
+        MODLOG_DFLT(INFO, "encryption change event; status=%d ",
+                    event->enc_change.status);
+        rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
+        assert(rc == 0);
+        bleprph_print_conn_desc(&desc);
+        MODLOG_DFLT(INFO, "\n");
+        return 0;
+
+    case BLE_GAP_EVENT_NOTIFY_TX:
+        MODLOG_DFLT(INFO, "notify_tx event; conn_handle=%d attr_handle=%d "
+                    "status=%d is_indication=%d",
+                    event->notify_tx.conn_handle,
+                    event->notify_tx.attr_handle,
+                    event->notify_tx.status,
+                    event->notify_tx.indication);
+        return 0;
+
+    case BLE_GAP_EVENT_SUBSCRIBE:
+        MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
+                    "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
+                    event->subscribe.conn_handle,
+                    event->subscribe.attr_handle,
+                    event->subscribe.reason,
+                    event->subscribe.prev_notify,
+                    event->subscribe.cur_notify,
+                    event->subscribe.prev_indicate,
+                    event->subscribe.cur_indicate);
+        return 0;
+
+    case BLE_GAP_EVENT_MTU:
+        MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
+                    event->mtu.conn_handle,
+                    event->mtu.channel_id,
+                    event->mtu.value);
+        return 0;
+
+    case BLE_GAP_EVENT_REPEAT_PAIRING:
+        /* We already have a bond with the peer, but it is attempting to
+         * establish a new secure link.  This app sacrifices security for
+         * convenience: just throw away the old bond and accept the new link.
+         */
+
+        /* Delete the old bond. */
+        rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
+        assert(rc == 0);
+        ble_store_util_delete_peer(&desc.peer_id_addr);
+
+        /* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
+         * continue with the pairing operation.
+         */
+        return BLE_GAP_REPEAT_PAIRING_RETRY;
+
+    case BLE_GAP_EVENT_PASSKEY_ACTION:
+        ESP_LOGI(tag, "PASSKEY_ACTION_EVENT started");
+        struct ble_sm_io pkey = {0};
+        int key = 0;
+
+        if (event->passkey.params.action == BLE_SM_IOACT_DISP) {
+            pkey.action = event->passkey.params.action;
+            pkey.passkey = 123456; // This is the passkey to be entered on peer
+            ESP_LOGI(tag, "Enter passkey %" PRIu32 "on the peer side", pkey.passkey);
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) {
+            ESP_LOGI(tag, "Passkey on device's display: %" PRIu32 , event->passkey.params.numcmp);
+            ESP_LOGI(tag, "Accept or reject the passkey through console in this format -> key Y or key N");
+            pkey.action = event->passkey.params.action;
+            if (scli_receive_key(&key)) {
+                pkey.numcmp_accept = key;
+            } else {
+                pkey.numcmp_accept = 0;
+                ESP_LOGE(tag, "Timeout! Rejecting the key");
+            }
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_OOB) {
+            static uint8_t tem_oob[16] = {0};
+            pkey.action = event->passkey.params.action;
+            for (int i = 0; i < 16; i++) {
+                pkey.oob[i] = tem_oob[i];
+            }
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
+        } else if (event->passkey.params.action == BLE_SM_IOACT_INPUT) {
+            ESP_LOGI(tag, "Enter the passkey through console in this format-> key 123456");
+            pkey.action = event->passkey.params.action;
+            if (scli_receive_key(&key)) {
+                pkey.passkey = key;
+            } else {
+                pkey.passkey = 0;
+                ESP_LOGE(tag, "Timeout! Passing 0 as the key");
+            }
+            rc = ble_sm_inject_io(event->passkey.conn_handle, &pkey);
+            ESP_LOGI(tag, "ble_sm_inject_io result: %d", rc);
+        }
+        return 0;
+
+#if MYNEWT_VAL(BLE_POWER_CONTROL)
+    case BLE_GAP_EVENT_TRANSMIT_POWER:
+        MODLOG_DFLT(INFO, "Transmit power event : status=%d conn_handle=%d reason=%d "
+                           "phy=%d power_level=%x power_level_flag=%d delta=%d",
+                     event->transmit_power.status,
+                     event->transmit_power.conn_handle,
+                     event->transmit_power.reason,
+                     event->transmit_power.phy,
+                     event->transmit_power.transmit_power_level,
+                     event->transmit_power.transmit_power_level_flag,
+                     event->transmit_power.delta);
+        return 0;
+
+     case BLE_GAP_EVENT_PATHLOSS_THRESHOLD:
+        MODLOG_DFLT(INFO, "Pathloss threshold event : conn_handle=%d current path loss=%d "
+                           "zone_entered =%d",
+                     event->pathloss_threshold.conn_handle,
+                     event->pathloss_threshold.current_path_loss,
+                     event->pathloss_threshold.zone_entered);
+        return 0;
+#endif
+    }
+
+    return 0;
+}
+
+static void
+bleprph_on_reset(int reason)
+{
+    MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
+}
+
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+static void
+ble_app_set_addr(void)
+{
+    ble_addr_t addr;
+    int rc;
+
+    /* generate new non-resolvable private address */
+    rc = ble_hs_id_gen_rnd(0, &addr);
+    assert(rc == 0);
+
+    /* set generated address */
+    rc = ble_hs_id_set_rnd(addr.val);
+
+    assert(rc == 0);
+}
+#endif
+
+static void
+bleprph_on_sync(void)
+{
+    int rc;
+
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+    /* Generate a non-resolvable private address. */
+    ble_app_set_addr();
+#endif
+
+    /* Make sure we have proper identity address set (public preferred) */
+#if CONFIG_EXAMPLE_RANDOM_ADDR
+    rc = ble_hs_util_ensure_addr(1);
+#else
+    rc = ble_hs_util_ensure_addr(0);
+#endif
+    assert(rc == 0);
+
+    /* Figure out address to use while advertising (no privacy for now) */
+    rc = ble_hs_id_infer_auto(0, &own_addr_type);
+    if (rc != 0) {
+        MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
+        return;
+    }
+
+    /* Printing ADDR */
+    uint8_t addr_val[6] = {0};
+    rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
+
+    MODLOG_DFLT(INFO, "Device Address: ");
+    print_addr(addr_val);
+    MODLOG_DFLT(INFO, "\n");
+    /* Begin advertising. */
+#if CONFIG_EXAMPLE_EXTENDED_ADV
+    ext_bleprph_advertise();
+#else
+    bleprph_advertise();
+#endif
+}
+
+void bleprph_host_task(void *param)
+{
+    ESP_LOGI(tag, "BLE Host Task Started");
+    /* This function will return only when nimble_port_stop() is executed */
+    nimble_port_run();
+
+    nimble_port_freertos_deinit();
+}
+
+void
+app_main(void)
+{
+    int rc;
+
+    /* Initialize NVS — it is used to store PHY calibration data */
+    esp_err_t ret = nvs_flash_init();
+    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+        ESP_ERROR_CHECK(nvs_flash_erase());
+        ret = nvs_flash_init();
+    }
+    ESP_ERROR_CHECK(ret);
+
+    ret = nimble_port_init();
+    if (ret != ESP_OK) {
+        ESP_LOGE(tag, "Failed to init nimble %d ", ret);
+        return;
+    }
+    /* Initialize the NimBLE host configuration. */
+    ble_hs_cfg.reset_cb = bleprph_on_reset;
+    ble_hs_cfg.sync_cb = bleprph_on_sync;
+    ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
+    ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
+
+    ble_hs_cfg.sm_io_cap = CONFIG_EXAMPLE_IO_TYPE;
+#ifdef CONFIG_EXAMPLE_BONDING
+    ble_hs_cfg.sm_bonding = 1;
+    /* Enable the appropriate bit masks to make sure the keys
+     * that are needed are exchanged
+     */
+    ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
+    ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ENC;
+#endif
+#ifdef CONFIG_EXAMPLE_MITM
+    ble_hs_cfg.sm_mitm = 1;
+#endif
+#ifdef CONFIG_EXAMPLE_USE_SC
+    ble_hs_cfg.sm_sc = 1;
+#else
+    ble_hs_cfg.sm_sc = 0;
+#endif
+#ifdef CONFIG_EXAMPLE_RESOLVE_PEER_ADDR
+    /* Stores the IRK */
+    ble_hs_cfg.sm_our_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
+    ble_hs_cfg.sm_their_key_dist |= BLE_SM_PAIR_KEY_DIST_ID;
+#endif
+
+    rc = gatt_svr_init();
+    assert(rc == 0);
+
+    /* Set the default device name. */
+    rc = ble_svc_gap_device_name_set("nimble-bleprph");
+    assert(rc == 0);
+
+    /* XXX Need to have template for store */
+    ble_store_config_init();
+
+    nimble_port_freertos_init(bleprph_host_task);
+
+    /* Initialize command line interface to accept input from user */
+    rc = scli_init();
+    if (rc != ESP_OK) {
+        ESP_LOGE(tag, "scli_init() failed");
+    }
+}

+ 22 - 0
esp-hosted/examples/host_nimble_bleprph_host_only_vhci/sdkconfig.defaults

@@ -0,0 +1,22 @@
+# Override some defaults so BT stack is enabled
+# in this example
+
+#
+# BT config
+#
+CONFIG_BT_ENABLED=y
+CONFIG_BT_CONTROLLER_DISABLED=y
+CONFIG_BT_BLUEDROID_ENABLED=n
+CONFIG_BT_NIMBLE_ENABLED=y
+CONFIG_BT_NIMBLE_TRANSPORT_UART=n
+
+#
+# Wi-Fi Remote
+#
+CONFIG_ESP_WIFI_REMOTE_LIBRARY_HOSTED=y
+
+#
+# Enable ESP Hosted BT
+# Used as VHCI transport between BT Host and Controller
+#
+CONFIG_ESP_ENABLE_BT_NIMBLE=y

+ 0 - 1
esp-hosted/host/api/include/esp_hosted_api.h

@@ -20,7 +20,6 @@ extern "C" {
 #include "esp_hosted_config.h"
 #include "esp_hosted_wifi_config.h"
 #include "esp_hosted_api_types.h"
-#include "rpc_wrap.h"
 
 /** Exported variables **/
 #define ESP_HOSTED_CHANNEL_CONFIG_DEFAULT()  { \

+ 21 - 0
esp-hosted/host/drivers/bt/esp_hosted_bt.h

@@ -0,0 +1,21 @@
+// Copyright 2015-2024 Espressif Systems (Shanghai) PTE LTD
+/* SPDX-License-Identifier: GPL-2.0 OR Apache-2.0 */
+
+#ifndef __ESP_HOSTED_BT_H
+#define __ESP_HOSTED_BT_H
+
+#include "esp_hosted_bt_config.h"
+
+#if H_BT_HOST_ESP_BLUEDROID
+#include "esp_bluedroid_hci.h"
+
+// BT Bluedroid interface for Host
+void hosted_hci_bluedroid_open(void);
+void hosted_hci_bluedroid_close(void);
+void hosted_hci_bluedroid_send(uint8_t *data, uint16_t len);
+bool hosted_hci_bluedroid_check_send_available(void);
+esp_err_t hosted_hci_bluedroid_register_host_callback(const esp_bluedroid_hci_driver_callbacks_t *callback);
+
+#endif // H_BT_HOST_ESP_BLUEDROID
+
+#endif // __ESP_HOSTED_BT_H

+ 0 - 11
esp-hosted/host/drivers/bt/hci_drv.h

@@ -8,17 +8,6 @@
 
 #include "esp_hosted_bt_config.h"
 
-#if H_BT_ENABLED
-
-#if H_BT_HOST_ESP_NIMBLE
-#include "host/ble_hs_mbuf.h"
-#endif
-
-#endif
-
-#define BLE_HCI_EVENT_HDR_LEN               (2)
-#define BLE_HCI_CMD_HDR_LEN                 (3)
-
 void hci_drv_init(void);
 
 void hci_drv_show_configuration(void);

+ 31 - 6
esp-hosted/host/drivers/bt/hci_stub_drv.c

@@ -7,16 +7,17 @@
 static const char TAG[] = "hci_stub_drv";
 
 #if H_BT_HOST_ESP_NIMBLE
-#include <sysinit/sysinit.h>
-#include <syscfg/syscfg.h>
-#include "os/os_mbuf.h"
 #include "host/ble_hs_mbuf.h"
 #include "nimble/transport.h"
 #endif
 
+#if H_BT_HOST_ESP_BLUEDROID
+#include "esp_hosted_bt.h"
+#endif
+
 #define WEAK __attribute__((weak))
 
-WEAK int hci_rx_handler(interface_buffer_handle_t *buf_handle)
+int hci_rx_handler(interface_buffer_handle_t *buf_handle)
 {
 	/* Hosted transport received BT packets, but Hosted was not
 	 * configured to handle BT packets. Drop them.
@@ -24,11 +25,11 @@ WEAK int hci_rx_handler(interface_buffer_handle_t *buf_handle)
 	return ESP_OK;
 }
 
-WEAK void hci_drv_init(void)
+void hci_drv_init(void)
 {
 }
 
-WEAK void hci_drv_show_configuration(void)
+void hci_drv_show_configuration(void)
 {
 	ESP_LOGI(TAG, "Host BT Support: Disabled");
 }
@@ -66,3 +67,27 @@ WEAK int ble_transport_to_ll_cmd_impl(void *buf)
 	return ESP_FAIL;
 }
 #endif // H_BT_HOST_ESP_NIMBLE
+
+#if H_BT_HOST_ESP_BLUEDROID
+WEAK void hosted_hci_bluedroid_open(void)
+{
+}
+
+WEAK void hosted_hci_bluedroid_close(void)
+{
+}
+
+WEAK void hosted_hci_bluedroid_send(uint8_t *data, uint16_t len)
+{
+}
+
+WEAK bool hosted_hci_bluedroid_check_send_available(void)
+{
+	return false;
+}
+
+WEAK esp_err_t hosted_hci_bluedroid_register_host_callback(const esp_bluedroid_hci_driver_callbacks_t *callback)
+{
+	return ESP_FAIL;
+}
+#endif // H_BT_HOST_ESP_BLUEDROID

+ 165 - 64
esp-hosted/host/drivers/bt/vhci_drv.c

@@ -10,65 +10,114 @@
 #include "hci_drv.h"
 
 #if H_BT_HOST_ESP_NIMBLE
-#include <sysinit/sysinit.h>
-#include <syscfg/syscfg.h>
 #include "host/ble_hs_mbuf.h"
 #include "os/os_mbuf.h"
 #include "nimble/transport.h"
 #include "nimble/transport/hci_h4.h"
+#include "nimble/hci_common.h"
 #endif
 
-#include "esp_hosted_log.h"
+#if H_BT_HOST_ESP_BLUEDROID
+#include "esp_hosted_bt.h"
+#endif
 
-#define TAG "vhci_drv"
+#include "esp_hosted_log.h"
+static const char TAG[] = "vhci_drv";
 
 #if H_BT_HOST_ESP_NIMBLE
-struct hci_h4_sm hci_h4sm;
+#define BLE_HCI_EVENT_HDR_LEN               (2)
+#define BLE_HCI_CMD_HDR_LEN                 (3)
+#endif
+
+void hci_drv_init(void)
+{
+	// do nothing for VHCI: underlying transport should be ready
+}
 
-static int hci_uart_frame_cb(uint8_t pkt_type, void *data)
+void hci_drv_show_configuration(void)
 {
-    switch (pkt_type) {
-    case HCI_H4_EVT:
-        return ble_transport_to_hs_evt(data);
-    case HCI_H4_ACL:
-        return ble_transport_to_hs_acl(data);
-    default:
-        assert(0);
-        break;
-    }
-    return -1;
+	ESP_LOGI(TAG, "Host BT Support: Enabled");
+	ESP_LOGI(TAG, "\tBT Transport Type: VHCI");
 }
-#endif /* H_BT_HOST_ESP_NIMBLE */
 
+#if H_BT_HOST_ESP_NIMBLE
 /**
  * HCI_H4_xxx is the first byte of the received data
  */
 int hci_rx_handler(interface_buffer_handle_t *buf_handle)
 {
-	ESP_LOG_BUFFER_HEXDUMP(TAG " rx", buf_handle->payload, buf_handle->payload_len, ESP_LOG_DEBUG);
-#if H_BT_HOST_ESP_NIMBLE
-	hci_h4_sm_rx(&hci_h4sm, buf_handle->payload, buf_handle->payload_len);
-#endif /* H_BT_HOST_ESP_NIMBLE */
-	return ESP_OK;
-}
+	uint8_t * data = buf_handle->payload;
+	uint32_t len_total_read = buf_handle->payload_len;
 
-void hci_drv_init(void)
-{
-#if H_BT_HOST_ESP_NIMBLE
-	hci_h4_sm_init(&hci_h4sm, &hci_h4_allocs_from_ll, hci_uart_frame_cb);
-#endif /* H_BT_HOST_ESP_NIMBLE */
-}
+	int rc;
 
-void hci_drv_show_configuration(void)
-{
-#if H_BT_HOST_ESP_NIMBLE
-	ESP_LOGI(TAG, "Host BT Support: Enabled");
-	ESP_LOGI(TAG, "\tBT Transport Type: VHCI");
-	ESP_LOGI(TAG, "\tBT Stack Type: NimBLE");
-#endif /* H_BT_HOST_ESP_NIMBLE */
+	if (data[0] == HCI_H4_EVT) {
+		uint8_t *evbuf;
+		int totlen;
+
+		totlen = BLE_HCI_EVENT_HDR_LEN + data[2];
+		if (totlen > UINT8_MAX + BLE_HCI_EVENT_HDR_LEN) {
+			ESP_LOGE(TAG, "Rx: len[%d] > max INT [%d], drop",
+					totlen, UINT8_MAX + BLE_HCI_EVENT_HDR_LEN);
+			return ESP_FAIL;
+		}
+
+		if (totlen > MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) {
+			ESP_LOGE(TAG, "Rx: len[%d] > max BLE [%d], drop",
+					totlen, MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE));
+			return ESP_FAIL;
+		}
+
+		if (data[1] == BLE_HCI_EVCODE_HW_ERROR) {
+			ESP_LOGE(TAG, "Rx: HW_ERROR");
+			return ESP_FAIL;
+		}
+
+		/* Allocate LE Advertising Report Event from lo pool only */
+		if ((data[1] == BLE_HCI_EVCODE_LE_META) &&
+			(data[3] == BLE_HCI_LE_SUBEV_ADV_RPT || data[3] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) {
+			evbuf = ble_transport_alloc_evt(1);
+			/* Skip advertising report if we're out of memory */
+			if (!evbuf) {
+				ESP_LOGE(TAG, "Rx: failed transport_alloc_evt(1)");
+				return ESP_FAIL;
+			}
+		} else {
+			evbuf = ble_transport_alloc_evt(0);
+			if (!evbuf) {
+				ESP_LOGE(TAG, "Rx: failed transport_alloc_evt(0)");
+				return ESP_FAIL;
+			}
+		}
+
+		memset(evbuf, 0, sizeof * evbuf);
+		memcpy(evbuf, &data[1], totlen);
+
+		rc = ble_transport_to_hs_evt(evbuf);
+		if (rc) {
+			ESP_LOGE(TAG, "Rx: transport_to_hs_evt failed");
+			return ESP_FAIL;
+		}
+	} else if (data[0] == HCI_H4_ACL) {
+		struct os_mbuf *m = NULL;
+
+		m = ble_transport_alloc_acl_from_ll();
+		if (!m) {
+			ESP_LOGE(TAG, "Rx: alloc_acl_from_ll failed");
+			return ESP_FAIL;
+		}
+
+		if ((rc = os_mbuf_append(m, &data[1], len_total_read - 1)) != 0) {
+			ESP_LOGE(TAG, "Rx: failed os_mbuf_append; rc = %d", rc);
+			os_mbuf_free_chain(m);
+			return ESP_FAIL;
+		}
+
+		ble_transport_to_hs_acl(m);
+	}
+	return ESP_OK;
 }
 
-#if H_BT_HOST_ESP_NIMBLE
 /**
  * ESP NimBLE expects these interfaces for Tx
  *
@@ -90,35 +139,31 @@ void ble_transport_ll_init(void)
 
 int ble_transport_to_ll_acl_impl(struct os_mbuf *om)
 {
-	int res;
-	struct os_mbuf *x = om;
-
-    while (x != NULL)
-    {
-		uint8_t *data = NULL;
-		int data_len = OS_MBUF_PKTLEN(x) + 1;
-
-		data = g_h.funcs->_h_malloc(data_len);
-		if (!data) {
-			ESP_LOGE(TAG, "Tx %s: malloc failed", __func__);
-			res = ESP_FAIL;
-			goto exit;
-		}
+	// TODO: zerocopy version
 
-		data[0] = HCI_H4_ACL;
-		res = ble_hs_mbuf_to_flat(x, &data[1], OS_MBUF_PKTLEN(x), NULL);
-		if (res) {
-			ESP_LOGE(TAG, "Tx: Error copying HCI_H4_ACL data %d", res);
-			res = ESP_FAIL;
-			goto exit;
-		}
+	// calculate data length from the incoming data
+	int data_len = OS_MBUF_PKTLEN(om) + 1;
 
-		ESP_LOG_BUFFER_HEXDUMP(TAG " tx", data, data_len, ESP_LOG_DEBUG);
+	uint8_t * data = NULL;
+	int res;
 
-		res = esp_hosted_tx(ESP_HCI_IF, 0, data, data_len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
+	data = MEM_ALLOC(data_len);
+	if (!data) {
+		ESP_LOGE(TAG, "Tx %s: malloc failed", __func__);
+		res = ESP_FAIL;
+		goto exit;
+	}
 
-		x = SLIST_NEXT(x, om_next);
+	data[0] = HCI_H4_ACL;
+	res = ble_hs_mbuf_to_flat(om, &data[1], OS_MBUF_PKTLEN(om), NULL);
+	if (res) {
+		ESP_LOGE(TAG, "Tx: Error copying HCI_H4_ACL data %d", res);
+		res = ESP_FAIL;
+		goto exit;
 	}
+
+	res = esp_hosted_tx(ESP_HCI_IF, 0, data, data_len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
+
  exit:
 	os_mbuf_free_chain(om);
 
@@ -135,7 +180,7 @@ int ble_transport_to_ll_cmd_impl(void *buf)
 	uint8_t * data = NULL;
 	int res;
 
-	data = g_h.funcs->_h_malloc(buf_len);
+	data = MEM_ALLOC(buf_len);
 	if (!data) {
 		ESP_LOGE(TAG, "Tx %s: malloc failed", __func__);
 		res =  ESP_FAIL;
@@ -145,8 +190,6 @@ int ble_transport_to_ll_cmd_impl(void *buf)
 	data[0] = HCI_H4_CMD;
 	memcpy(&data[1], buf, buf_len - 1);
 
-	ESP_LOG_BUFFER_HEXDUMP(TAG " tx", data, buf_len, ESP_LOG_DEBUG);
-
 	res = esp_hosted_tx(ESP_HCI_IF, 0, data, buf_len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
 
  exit:
@@ -155,3 +198,61 @@ int ble_transport_to_ll_cmd_impl(void *buf)
 	return res;
 }
 #endif // H_BT_HOST_ESP_NIMBLE
+
+#if H_BT_HOST_ESP_BLUEDROID
+static esp_bluedroid_hci_driver_callbacks_t s_callback = { 0 };
+
+int hci_rx_handler(interface_buffer_handle_t *buf_handle)
+{
+	uint8_t * data = buf_handle->payload;
+	uint32_t len_total_read = buf_handle->payload_len;
+
+	if (s_callback.notify_host_recv) {
+		s_callback.notify_host_recv(data, len_total_read);
+	}
+
+	return ESP_FAIL;
+}
+
+void hosted_hci_bluedroid_open(void)
+{
+	ESP_ERROR_CHECK(transport_drv_reconfigure());
+}
+
+void hosted_hci_bluedroid_close(void)
+{
+}
+
+esp_err_t hosted_hci_bluedroid_register_host_callback(const esp_bluedroid_hci_driver_callbacks_t *callback)
+{
+	s_callback.notify_host_send_available = callback->notify_host_send_available;
+	s_callback.notify_host_recv = callback->notify_host_recv;
+
+	return ESP_OK;
+}
+
+void hosted_hci_bluedroid_send(uint8_t *data, uint16_t len)
+{
+	int res;
+	uint8_t * ptr = NULL;
+
+	ptr = MEM_ALLOC(len);
+	if (!ptr) {
+		ESP_LOGE(TAG, "%s: malloc failed", __func__);
+		return;
+	}
+	memcpy(ptr, data, len);
+
+	res = esp_hosted_tx(ESP_HCI_IF, 0, ptr, len, H_BUFF_NO_ZEROCOPY, H_DEFLT_FREE_FUNC);
+
+	if (res) {
+		ESP_LOGE(TAG, "%s: Tx failed", __func__);
+	}
+}
+
+bool hosted_hci_bluedroid_check_send_available(void)
+{
+	return true;
+}
+
+#endif // H_BT_HOST_ESP_BLUEDROID

+ 2 - 2
esp-hosted/host/drivers/mempool/mempool.c

@@ -16,13 +16,13 @@
 #include "mempool.h"
 #include "esp_hosted_config.h"
 #include "stats.h"
-#include "esp_hosted_log.h"
+#include "esp_log.h"
 #define MEMPOOL_DEBUG 1
 
 
 static char * MEM_TAG = "mpool";
 #if H_MEM_STATS
-#include "esp_hosted_log.h"
+#include "esp_log.h"
 
 
 #endif

+ 7 - 6
esp-hosted/host/drivers/rpc/core/rpc_core.c

@@ -8,8 +8,8 @@
 #include "rpc_common.h"
 #include "serial_if.h"
 #include "serial_drv.h"
+#include <unistd.h>
 #include "esp_log.h"
-#include "esp_hosted_config.h"
 
 DEFINE_LOG_TAG(rpc_core);
 
@@ -26,8 +26,8 @@ struct rpc_lib_context {
 typedef void (*rpc_rx_ind_t)(void);
 typedef void (*rpc_tx_ind_t)(void);
 
-static void * rpc_rx_q = NULL;
-static void * rpc_tx_q = NULL;
+static queue_handle_t rpc_rx_q = NULL;
+static queue_handle_t rpc_tx_q = NULL;
 
 static void * rpc_rx_thread_hdl;
 static void * rpc_tx_thread_hdl;
@@ -74,8 +74,8 @@ typedef struct {
  *    When the response comes, the this registered callback function will be called
  *    with input as response
  */
-#define MAX_SYNC_RPC_TRANSACTIONS  H_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS
-#define MAX_ASYNC_RPC_TRANSACTIONS H_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS
+#define MAX_SYNC_RPC_TRANSACTIONS  CONFIG_ESP_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS
+#define MAX_ASYNC_RPC_TRANSACTIONS CONFIG_ESP_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS
 
 static sync_rsp_t sync_rsp_table[MAX_SYNC_RPC_TRANSACTIONS] = { 0 };
 static async_rsp_t async_rsp_table[MAX_ASYNC_RPC_TRANSACTIONS] = { 0 };
@@ -1003,7 +1003,8 @@ int rpc_core_init(void)
 	int ret = SUCCESS;
 
 	/* semaphore init */
-	rpc_tx_sem = g_h.funcs->_h_create_semaphore(MAX_SYNC_RPC_TRANSACTIONS + MAX_ASYNC_RPC_TRANSACTIONS);
+	rpc_tx_sem = g_h.funcs->_h_create_semaphore(CONFIG_ESP_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS +
+			CONFIG_ESP_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS);
 	if (!rpc_tx_sem) {
 		ESP_LOGE(TAG, "sem init failed, exiting");
 		goto free_bufs;

+ 0 - 3
esp-hosted/host/drivers/rpc/core/rpc_rsp.c

@@ -99,7 +99,6 @@ int rpc_parse_rsp(Rpc *rpc_msg, ctrl_cmd_t *app_resp)
 		RPC_ERR_IN_RESP(resp_ota_begin);
 		if (rpc_msg->resp_ota_begin->resp) {
 			ESP_LOGE(TAG, "OTA Begin Failed");
-			app_resp->resp_event_status = rpc_msg->resp_ota_begin->resp;
 			goto fail_parse_rpc_msg;
 		}
 		break;
@@ -108,7 +107,6 @@ int rpc_parse_rsp(Rpc *rpc_msg, ctrl_cmd_t *app_resp)
 		RPC_ERR_IN_RESP(resp_ota_write);
 		if (rpc_msg->resp_ota_write->resp) {
 			ESP_LOGE(TAG, "OTA write failed");
-			app_resp->resp_event_status = rpc_msg->resp_ota_write->resp;
 			goto fail_parse_rpc_msg;
 		}
 		break;
@@ -116,7 +114,6 @@ int rpc_parse_rsp(Rpc *rpc_msg, ctrl_cmd_t *app_resp)
 		RPC_FAIL_ON_NULL(resp_ota_end);
 		if (rpc_msg->resp_ota_end->resp) {
 			ESP_LOGE(TAG, "OTA end failed");
-			app_resp->resp_event_status = rpc_msg->resp_ota_end->resp;
 			goto fail_parse_rpc_msg;
 		}
 		break;

+ 5 - 5
esp-hosted/host/drivers/rpc/slaveif/rpc_slave_if.c

@@ -358,19 +358,19 @@ ctrl_cmd_t * wifi_sta_get_aid(ctrl_cmd_t *req)
 	RPC_DECODE_RSP_IF_NOT_ASYNC();
 }
 
-ctrl_cmd_t * get_coprocessor_fwversion(ctrl_cmd_t *req)
+ctrl_cmd_t * wifi_set_protocols(ctrl_cmd_t *req)
 {
-	RPC_SEND_REQ(RPC_ID__Req_GetCoprocessorFwVersion);
+	RPC_SEND_REQ(RPC_ID__Req_WifiSetProtocols);
 	RPC_DECODE_RSP_IF_NOT_ASYNC();
 }
 
-#if H_WIFI_DUALBAND_SUPPORT
-ctrl_cmd_t * wifi_set_protocols(ctrl_cmd_t *req)
+ctrl_cmd_t * get_coprocessor_fwversion(ctrl_cmd_t *req)
 {
-	RPC_SEND_REQ(RPC_ID__Req_WifiSetProtocols);
+	RPC_SEND_REQ(RPC_ID__Req_GetCoprocessorFwVersion);
 	RPC_DECODE_RSP_IF_NOT_ASYNC();
 }
 
+#if H_WIFI_DUALBAND_SUPPORT
 ctrl_cmd_t * wifi_get_protocols(ctrl_cmd_t *req)
 {
 	RPC_SEND_REQ(RPC_ID__Req_WifiGetProtocols);

+ 16 - 14
esp-hosted/host/drivers/rpc/wrap/rpc_wrap.c

@@ -40,7 +40,9 @@ DEFINE_LOG_TAG(rpc_wrap);
 #define VENDOR_OUI_1                                      2
 #define VENDOR_OUI_2                                      3
 #define VENDOR_OUI_TYPE                                   22
+#define CHUNK_SIZE                                        1400
 #define OTA_BEGIN_RSP_TIMEOUT_SEC                         15
+#define OTA_FROM_WEB_URL                                  0
 
 
 
@@ -123,10 +125,10 @@ static int rpc_event_callback(ctrl_cmd_t * app_event)
 	switch(app_event->msg_id) {
 
 		case RPC_ID__Event_ESPInit: {
-			ESP_LOGI(TAG, "Received Slave ESP Init");
+			ESP_LOGD(TAG, "Received Slave ESP Init");
 			break;
 		} case RPC_ID__Event_Heartbeat: {
-			ESP_LOGV(TAG, "%s App EVENT: Heartbeat event [%lu]",
+			ESP_LOGV(TAG, "%s ESP EVENT: Heartbeat event [%lu]",
 				rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE),
 					(long unsigned int)app_event->u.e_heartbeat.hb_num);
 			break;
@@ -134,7 +136,7 @@ static int rpc_event_callback(ctrl_cmd_t * app_event)
 			wifi_event_ap_staconnected_t *p_e = &app_event->u.e_wifi_ap_staconnected;
 
 			if (strlen((char*)p_e->mac)) {
-				ESP_LOGV(TAG, "%s App EVENT: SoftAP mode: connected station",
+				ESP_LOGV(TAG, "%s ESP EVENT: SoftAP mode: connected station",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
 				g_h.funcs->_h_event_wifi_post(WIFI_EVENT_AP_STACONNECTED,
 					p_e, sizeof(wifi_event_ap_staconnected_t), HOSTED_BLOCK_MAX);
@@ -143,21 +145,21 @@ static int rpc_event_callback(ctrl_cmd_t * app_event)
 		} case RPC_ID__Event_AP_StaDisconnected: {
 			wifi_event_ap_stadisconnected_t *p_e = &app_event->u.e_wifi_ap_stadisconnected;
 			if (strlen((char*)p_e->mac)) {
-				ESP_LOGV(TAG, "%s App EVENT: SoftAP mode: disconnected MAC",
+				ESP_LOGV(TAG, "%s ESP EVENT: SoftAP mode: disconnected MAC",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
 				g_h.funcs->_h_event_wifi_post(WIFI_EVENT_AP_STADISCONNECTED,
 					p_e, sizeof(wifi_event_ap_stadisconnected_t), HOSTED_BLOCK_MAX);
 			}
 			break;
 		} case RPC_ID__Event_StaConnected: {
-			ESP_LOGV(TAG, "%s App EVENT: Station mode: Connected",
+			ESP_LOGV(TAG, "%s ESP EVENT: Station mode: Connected",
 				rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
 			wifi_event_sta_connected_t *p_e = &app_event->u.e_wifi_sta_connected;
 			g_h.funcs->_h_event_wifi_post(WIFI_EVENT_STA_CONNECTED,
 				p_e, sizeof(wifi_event_sta_connected_t), HOSTED_BLOCK_MAX);
 			break;
 		} case RPC_ID__Event_StaDisconnected: {
-			ESP_LOGV(TAG, "%s App EVENT: Station mode: Disconnected",
+			ESP_LOGV(TAG, "%s ESP EVENT: Station mode: Disconnected",
 				rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
 			wifi_event_sta_disconnected_t *p_e = &app_event->u.e_wifi_sta_disconnected;
 			g_h.funcs->_h_event_wifi_post(WIFI_EVENT_STA_DISCONNECTED,
@@ -169,24 +171,24 @@ static int rpc_event_callback(ctrl_cmd_t * app_event)
 			switch (wifi_event_id) {
 
 			case WIFI_EVENT_STA_START:
-				ESP_LOGV(TAG, "%s App EVENT: WiFi Event[%s]",
+				ESP_LOGV(TAG, "%s ESP EVENT: WiFi Event[%s]",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), "WIFI_EVENT_STA_START");
 				break;
 			case WIFI_EVENT_STA_STOP:
-				ESP_LOGV(TAG, "%s App EVENT: WiFi Event[%s]",
+				ESP_LOGV(TAG, "%s ESP EVENT: WiFi Event[%s]",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), "WIFI_EVENT_STA_STOP");
 				break;
 
 			case WIFI_EVENT_AP_START:
-				ESP_LOGI(TAG,"App Event: softap started");
+				ESP_LOGD(TAG,"ESP EVENT: softap started");
 				break;
 
 			case WIFI_EVENT_AP_STOP:
-				ESP_LOGI(TAG,"App Event: softap stopped");
+				ESP_LOGD(TAG,"ESP EVENT: softap stopped");
 				break;
 
 			default:
-				ESP_LOGV(TAG, "%s App EVENT: WiFi Event[%x]",
+				ESP_LOGV(TAG, "%s ESP EVENT: WiFi Event[%x]",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), wifi_event_id);
 				break;
 			} /* inner switch case */
@@ -195,14 +197,14 @@ static int rpc_event_callback(ctrl_cmd_t * app_event)
 			break;
 		} case RPC_ID__Event_StaScanDone: {
 			wifi_event_sta_scan_done_t *p_e = &app_event->u.e_wifi_sta_scan_done;
-			ESP_LOGV(TAG, "%s App EVENT: StaScanDone",
+			ESP_LOGV(TAG, "%s ESP EVENT: StaScanDone",
 					rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE));
 			ESP_LOGV(TAG, "scan: status: %lu number:%u scan_id:%u", p_e->status, p_e->number, p_e->scan_id);
 			g_h.funcs->_h_event_wifi_post(WIFI_EVENT_SCAN_DONE,
 				p_e, sizeof(wifi_event_sta_scan_done_t), HOSTED_BLOCK_MAX);
 			break;
 		} default: {
-			ESP_LOGW(TAG, "%s Invalid event[0x%x] to parse\n\r",
+			ESP_LOGW(TAG, "%s Invalid event[0x%x] to parse",
 				rpc_get_timestamp(ts, MIN_TIMESTAMP_STR_SIZE), app_event->msg_id);
 			break;
 		}
@@ -313,7 +315,7 @@ int rpc_register_event_callbacks(void)
 
 	for (evt=0; evt<sizeof(events)/sizeof(event_callback_table_t); evt++) {
 		if (CALLBACK_SET_SUCCESS != set_event_callback(events[evt].event, events[evt].fun) ) {
-			ESP_LOGE(TAG, "event callback register failed for event[%u]\n\r", events[evt].event);
+			ESP_LOGE(TAG, "event callback register failed for event[%u]", events[evt].event);
 			ret = FAILURE;
 			break;
 		}

+ 3 - 3
esp-hosted/host/drivers/serial/serial_drv.c

@@ -175,7 +175,7 @@ uint8_t * serial_drv_read(struct serial_drv_handle_t *serial_drv_handle,
 	}
 
 	if (rx_buf_len > (init_read_len + buf_len)) {
-		ESP_LOGE(TAG,"Buf read on serial iface is bigger than expected len\n");
+		ESP_LOGE(TAG,"Buf read on serial iface is smaller than expected len\n");
 	}
 
 	HOSTED_FREE(buf);
@@ -212,8 +212,8 @@ int serial_drv_close(struct serial_drv_handle_t** serial_drv_handle)
 int rpc_platform_init(void)
 {
 	/* rpc semaphore */
-	readSemaphore = g_h.funcs->_h_create_semaphore(ESP_HOSTED_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS +
-			ESP_HOSTED_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS);
+	readSemaphore = g_h.funcs->_h_create_semaphore(CONFIG_ESP_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS +
+			CONFIG_ESP_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS);
 	assert(readSemaphore);
 
 	/* grab the semaphore, so that task will be mandated to wait on semaphore */

+ 5 - 5
esp-hosted/host/drivers/transport/spi/spi_drv.c

@@ -30,7 +30,7 @@
 DEFINE_LOG_TAG(spi);
 
 void * spi_handle = NULL;
-static void * spi_trans_ready_sem;
+semaphore_handle_t spi_trans_ready_sem;
 
 #if DEBUG_HOST_TX_SEMAPHORE
 #define H_DEBUG_GPIO_PIN_Host_Tx_Port NULL
@@ -51,10 +51,10 @@ static struct mempool * buf_mp_g;
 static void * spi_bus_lock;
 
 /* Queue declaration */
-static void * to_slave_queue[MAX_PRIORITY_QUEUES];
-static void * sem_to_slave_queue;
-static void * from_slave_queue[MAX_PRIORITY_QUEUES];
-static void * sem_from_slave_queue;
+static queue_handle_t to_slave_queue[MAX_PRIORITY_QUEUES];
+semaphore_handle_t sem_to_slave_queue;
+static queue_handle_t from_slave_queue[MAX_PRIORITY_QUEUES];
+semaphore_handle_t sem_from_slave_queue;
 
 static void * spi_rx_thread;
 

+ 1 - 1
esp-hosted/host/drivers/transport/transport_drv.h

@@ -43,7 +43,7 @@ extern "C" {
 #define ESP_PRIV_FIRMWARE_CHIP_ESP32C5      (0x17)
 
 
-#ifdef ESP_HOSTED_SPI_HOST_INTERFACE
+#if CONFIG_ESP_SPI_HOST_INTERFACE
 #include "spi_wrapper.h"
 #define SPI_MODE0                           (0)
 #define SPI_MODE1                           (1)

+ 70 - 108
esp-hosted/host/drivers/transport/uart/uart_drv.c

@@ -19,20 +19,21 @@
 
 #include "common.h"
 #include "endian.h"
-#include "esp_hosted_log.h"
+#include "esp_log.h"
 #include "esp_hosted_log.h"
 #include "transport_drv.h"
 #include "stats.h"
 
 static const char TAG[] = "H_UART_DRV";
 
-#define UART_PROCESS_RX_DATA_ERROR (-1)
-#define UART_PROCESS_WAITING_MORE_RX_DATA (0)
-#define UART_PROCESS_RX_DATA_DONE (1)
+// UART is low throughput, so throttling should not be needed
+#define USE_DATA_THROTTLING (0)
 
 static void h_uart_write_task(void const* pvParameters);
 static void h_uart_read_task(void const* pvParameters);
+#if USE_DATA_THROTTLING
 static int update_flow_ctrl(uint8_t *rxbuff);
+#endif
 
 /* TODO to move this in transport drv */
 extern transport_channel_t *chan_arr[ESP_MAX_IF];
@@ -160,7 +161,7 @@ static void h_uart_write_task(void const* pvParameters)
 #endif
 
 		tx_len_to_send = len + sizeof(struct esp_payload_header);
-		tx_len = g_h.funcs->_h_uart_write(sendbuf, tx_len_to_send);
+		tx_len = g_h.funcs->_h_uart_write(uart_handle, sendbuf, tx_len_to_send);
 		if (tx_len != tx_len_to_send) {
 			ESP_LOGE(TAG, "failed to send uart data");
 		}
@@ -174,6 +175,7 @@ done:
 	}
 }
 
+#if USE_DATA_THROTTLING
 static int update_flow_ctrl(uint8_t *rxbuff)
 {
 	struct esp_payload_header * h = (struct esp_payload_header *)rxbuff;
@@ -189,6 +191,7 @@ static int update_flow_ctrl(uint8_t *rxbuff)
 		return 0;
 	}
 }
+#endif
 
 static void h_uart_process_rx_task(void const* pvParameters)
 {
@@ -280,7 +283,7 @@ static void h_uart_process_rx_task(void const* pvParameters)
 }
 
 // pushes received packet data on to rx queue
-static esp_err_t h_uart_push_pkt_to_queue(uint8_t * rxbuff, uint16_t len, uint16_t offset)
+static esp_err_t push_to_rx_queue(uint8_t * rxbuff, uint16_t len, uint16_t offset)
 {
 	uint8_t pkt_prio = PRIO_Q_OTHERS;
 	struct esp_payload_header *h= NULL;
@@ -362,136 +365,95 @@ static int is_valid_uart_rx_packet(uint8_t *rxbuff_a, uint16_t *len_a, uint16_t
 	return 1;
 }
 
-static esp_err_t h_uart_push_data_to_queue(uint8_t * buf, uint32_t buf_len)
-{
-	uint16_t len = 0;
-	uint16_t offset = 0;
-
-	if (update_flow_ctrl(buf)) {
-		// detected and updated flow control
-		// no need to further process the packet
-		h_uart_buffer_free(buf);
-		return ESP_OK;
-	}
-
-	/* Drop packet if no processing needed */
-	if (!is_valid_uart_rx_packet(buf, &len, &offset)) {
-		/* Free up buffer, as one of following -
-		 * 1. no payload to process
-		 * 2. input packet size > driver capacity
-		 * 3. payload header size mismatch,
-		 * wrong header/bit packing?
-		 * */
-		ESP_LOGE(TAG, "Dropping packet");
-		h_uart_buffer_free(buf);
-		return ESP_FAIL;
-	}
-
-	if (h_uart_push_pkt_to_queue(buf, len, offset)) {
-		ESP_LOGE(TAG, "Failed to push Rx packet to queue");
-		h_uart_buffer_free(buf);
-		return ESP_FAIL;
-	}
-
-	return ESP_OK;
-}
-
-// large incoming data may be broken up into several serial packets
-static int current_rx_len = 0;
-static int expected_pkt_len = 0;
 static uint8_t * uart_scratch_buf = NULL;
 
-static int process_uart_rx_data(size_t size)
+static void h_uart_read_task(void const* pvParameters)
 {
+	struct esp_payload_header *header = NULL;
+	uint16_t len = 0, offset = 0;
+#if HOSTED_UART_CHECKSUM
+	uint16_t rx_checksum = 0, checksum = 0;
+#endif
 	int bytes_read;
+	int total_len;
 	uint8_t * rxbuff = NULL;
-	int remaining_len;
+
+	// wait for transport to be in ready
+	while (true) {
+		vTaskDelay(pdMS_TO_TICKS(100));
+		if (is_transport_rx_ready()) {
+			break;
+		}
+	}
+
+	create_debugging_tasks();
 
 	if (!uart_scratch_buf) {
 		uart_scratch_buf = malloc(MAX_UART_BUFFER_SIZE);
 		assert(uart_scratch_buf);
 	}
 
-	bytes_read = g_h.funcs->_h_uart_read(&uart_scratch_buf[current_rx_len], size);
-	current_rx_len += bytes_read;
-	ESP_LOGD(TAG, "current_rx_len %d", current_rx_len);
+	header = (struct esp_payload_header *)uart_scratch_buf;
 
-	// process all data in buffer until there isn't enough to form a packet header
 	while (1) {
-		// get the packet size
-		if (!expected_pkt_len) {
-			if (current_rx_len < sizeof(struct esp_payload_header)) {
-				// not yet enough info in data to decode header
-				ESP_LOGD(TAG, "not enough data to decode header");
-				return UART_PROCESS_WAITING_MORE_RX_DATA;
-			}
-			struct esp_payload_header * h = (struct esp_payload_header *)uart_scratch_buf;
-			expected_pkt_len = le16toh(h->len) + sizeof(struct esp_payload_header);
-			ESP_LOGD(TAG, "expected_pkt_len %d", expected_pkt_len);
+		// get the header
+		bytes_read = g_h.funcs->_h_uart_read(uart_handle, uart_scratch_buf,
+				sizeof(struct esp_payload_header));
+		ESP_LOGD(TAG, "Read %d bytes (header)", bytes_read);
+		if (bytes_read < sizeof(struct esp_payload_header)) {
+			ESP_LOGE(TAG, "Failed to read header");
+			continue;
 		}
-		if (expected_pkt_len > MAX_UART_BUFFER_SIZE) {
-			ESP_LOGE(TAG, "packet size error");
-			current_rx_len = 0;
-			expected_pkt_len = 0;
-			return UART_PROCESS_RX_DATA_ERROR;
+
+		len = le16toh(header->len);
+		offset = le16toh(header->offset);
+		total_len = len + sizeof(struct esp_payload_header);
+		if (total_len > MAX_UART_BUFFER_SIZE) {
+			ESP_LOGE(TAG, "incoming data too big: %d", total_len);
+			continue;
 		}
-		if (current_rx_len < expected_pkt_len) {
-			// still got more data to read
-			return UART_PROCESS_WAITING_MORE_RX_DATA;
+
+		// get the data
+		bytes_read = g_h.funcs->_h_uart_read(uart_handle, &uart_scratch_buf[offset], len);
+		ESP_LOGD(TAG, "Read %d bytes (payload)", bytes_read);
+		if (bytes_read < len) {
+			ESP_LOGE(TAG, "Failed to read payload");
+			continue;
 		}
 
-		// we have enough data to form a complete packet
 		rxbuff = h_uart_buffer_alloc(MEMSET_REQUIRED);
 		assert(rxbuff);
 
 		// copy data to the buffer
-		memcpy(rxbuff, uart_scratch_buf, expected_pkt_len);
-
-		if (h_uart_push_data_to_queue(rxbuff, expected_pkt_len)) {
-			ESP_LOGE(TAG, "Failed to push data to rx queue");
-		}
+		memcpy(rxbuff, uart_scratch_buf, total_len);
 
-		// clean up the scratch buffer
-		if (current_rx_len > expected_pkt_len) {
-			// got part of another packet at the end. Move to the front
-			ESP_LOGD(TAG, "moving remaining data");
-			remaining_len = current_rx_len - expected_pkt_len;
-			memmove(uart_scratch_buf, &uart_scratch_buf[expected_pkt_len], remaining_len);
-
-			current_rx_len = remaining_len;
-			expected_pkt_len = 0;
-		} else {
-			current_rx_len = 0;
-			expected_pkt_len = 0;
-			break;
+#if USE_DATA_THROTTLING
+		if (update_flow_ctrl(rxbuff)) {
+			// detected and updated flow control
+			// no need to further process the packet
+			h_uart_buffer_free(rxbuff);
+			continue;
 		}
-	}
-	return UART_PROCESS_RX_DATA_DONE;
-}
-
-static void h_uart_read_task(void const* pvParameters)
-{
-	int rx_len;
+#endif
 
-	// wait for transport to be in reset state
-	while (true) {
-		vTaskDelay(pdMS_TO_TICKS(100));
-		if (is_transport_rx_ready()) {
-			break;
+		/* Drop packet if no processing needed */
+		if (!is_valid_uart_rx_packet(rxbuff, &len, &offset)) {
+			/* Free up buffer, as one of following -
+			 * 1. no payload to process
+			 * 2. input packet size > driver capacity
+			 * 3. payload header size mismatch,
+			 * wrong header/bit packing?
+			 * */
+			ESP_LOGE(TAG, "Dropping packet");
+			h_uart_buffer_free(rxbuff);
+			continue;
 		}
-	}
 
-	create_debugging_tasks();
-
-	while (1) {
-		// call will block until there is data to read, or an error occurred
-		rx_len = g_h.funcs->_h_uart_wait_rx_data(HOSTED_BLOCK_MAX);
-		if (rx_len < 0) {
-			ESP_LOGE(TAG, "error waiting for uart data");
+		if (push_to_rx_queue(rxbuff, len, offset)) {
+			ESP_LOGE(TAG, "Failed to push Rx packet to queue");
+			h_uart_buffer_free(rxbuff);
 			continue;
 		}
-		if (rx_len)
-			process_uart_rx_data(rx_len);
 	}
 }
 

+ 17 - 0
esp-hosted/host/esp_hosted.h

@@ -0,0 +1,17 @@
+/*
+* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
+*
+* SPDX-License-Identifier: Apache-2.0
+*/
+
+#ifndef __ESP_HOSTED_H__
+#define __ESP_HOSTED_H__
+
+#include "esp_hosted_config.h"
+#include "esp_hosted_transport_config.h"
+
+#include "esp_hosted_api.h"
+
+typedef struct esp_hosted_transport_config esp_hosted_config_t;
+
+#endif /* __ESP_HOSTED_H__ */

+ 26 - 0
esp-hosted/host/esp_hosted_host_init.c

@@ -0,0 +1,26 @@
+/*
+* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
+*
+* SPDX-License-Identifier: Apache-2.0
+*/
+
+#include "os_header.h"
+#include "os_wrapper.h"
+#include "esp_log.h"
+#include "esp_hosted_api.h"
+#include "esp_private/startup_internal.h"
+
+DEFINE_LOG_TAG(host_init);
+
+//ESP_SYSTEM_INIT_FN(esp_hosted_host_init, BIT(0), 120)
+static void __attribute__((constructor)) esp_hosted_host_init(void)
+{
+	ESP_LOGI(TAG, "ESP Hosted : Host chip_ip[%d]", CONFIG_IDF_FIRMWARE_CHIP_ID);
+	ESP_ERROR_CHECK(esp_hosted_init());
+}
+
+static void __attribute__((destructor)) esp_hosted_host_deinit(void)
+{
+	ESP_LOGI(TAG, "ESP Hosted deinit");
+	esp_hosted_deinit();
+}

+ 2 - 6
esp-hosted/host/hosted_os_adapter.h

@@ -5,9 +5,6 @@
 #ifndef __HOSTED_OS_ADAPTER_H__
 #define __HOSTED_OS_ADAPTER_H__
 
-#include <stdint.h>
-#include <stddef.h>
-
 #include "esp_hosted_config.h"
 
 typedef struct {
@@ -103,9 +100,8 @@ typedef struct {
 
 #ifdef CONFIG_ESP_UART_HOST_INTERFACE
           /* Transport - UART */
-/* 51 */ int (*_h_uart_read)(uint8_t *data, uint16_t size);
-/* 52 */ int (*_h_uart_write)(uint8_t *data, uint16_t size);
-/* 53 */ int (*_h_uart_wait_rx_data)(uint32_t ticks_to_wait);
+/* 57 */ int (*_h_uart_read)(void *ctx, uint8_t *data, uint16_t size);
+/* 58 */ int (*_h_uart_write)(void *ctx, uint8_t *data, uint16_t size);
 #endif
 } hosted_osi_funcs_t;
 

+ 47 - 0
esp-hosted/host/port/esp_hosted_bt_config.h

@@ -0,0 +1,47 @@
+/*
+ * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __ESP_HOSTED_BT_CONFIG_H__
+#define __ESP_HOSTED_BT_CONFIG_H__
+
+// Hosted BT defines for NimBLE
+#if CONFIG_ESP_ENABLE_BT_NIMBLE
+#define H_BT_HOST_ESP_NIMBLE 1
+#else
+#define H_BT_HOST_ESP_NIMBLE 0
+#endif
+
+#if CONFIG_ESP_NIMBLE_HCI_VHCI
+#define H_BT_USE_VHCI 1
+#else
+#define H_BT_USE_VHCI 0
+#endif
+
+// Hosted BT defines for BlueDroid
+#if CONFIG_ESP_ENABLE_BT_BLUEDROID
+#define H_BT_HOST_ESP_BLUEDROID 1
+#else
+#define H_BT_HOST_ESP_BLUEDROID 0
+#endif
+
+#if CONFIG_ESP_BLUEDROID_HCI_VHCI
+#define H_BT_BLUEDROID_USE_VHCI 1
+#else
+#define H_BT_BLUEDROID_USE_VHCI 1
+#endif
+
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
+// ll_init required
+#define H_BT_ENABLE_LL_INIT 1
+#else
+#define H_BT_ENABLE_LL_INIT 0
+#endif
+
+// check: only one BT host stack can be enabled at a time
+#if H_BT_HOST_ESP_NIMBLE && H_BT_HOST_ESP_BLUEDROID
+#error "Enable only NimBLE or BlueDroid, not both"
+#endif
+
+#endif

+ 0 - 0
esp-hosted/port/esp32/esp_hosted_config.c → esp-hosted/host/port/esp_hosted_config.c


+ 6 - 10
esp-hosted/port/esp32/esp_hosted_config.h → esp-hosted/host/port/esp_hosted_config.h

@@ -7,13 +7,11 @@
 #ifndef __ESP_HOSTED_CONFIG_H__
 #define __ESP_HOSTED_CONFIG_H__
 
-#include <stdbool.h>
-
 #include "sdkconfig.h"
 #include "esp_task.h"
 #include "hosted_os_adapter.h"
 #include "adapter.h"
-#include "esp_err.h"
+
 
 #define H_TRANSPORT_NONE 0
 #define H_TRANSPORT_SDIO 1
@@ -25,6 +23,10 @@
 #include "driver/sdmmc_host.h"
 #endif
 
+#ifdef CONFIG_ESP_UART_HOST_INTERFACE
+#include "hal/uart_types.h"
+#endif
+
 /* This file is to tune the main ESP-Hosted configurations.
  * In case you are not sure of some value, Let it be default.
  **/
@@ -278,8 +280,6 @@ enum {
 #define H_UART_FLOWCTRL                              UART_HW_FLOWCTRL_DISABLE
 #define H_UART_CLK_SRC                               UART_SCLK_DEFAULT
 
-#define H_UART_EVENT_QUEUE_SIZE                      100
-
 #define H_UART_CHECKSUM                              CONFIG_ESP_UART_CHECKSUM
 #define H_UART_BAUD_RATE                             CONFIG_ESP_UART_BAUDRATE
 #define H_UART_TX_PIN                                CONFIG_ESP_UART_PIN_TX
@@ -330,9 +330,7 @@ enum {
 #endif
 
 /* Raw Throughput Testing */
-#define H_TEST_RAW_TP                                  CONFIG_ESP_RAW_THROUGHPUT_TRANSPORT
-#define H_ESP_RAW_TP_REPORT_INTERVAL                   CONFIG_ESP_RAW_TP_REPORT_INTERVAL
-#define H_ESP_RAW_TP_HOST_TO_ESP_PKT_LEN               CONFIG_ESP_RAW_TP_HOST_TO_ESP_PKT_LEN
+#define H_TEST_RAW_TP     CONFIG_ESP_RAW_THROUGHPUT_TRANSPORT
 
 #if H_TEST_RAW_TP
 #if CONFIG_ESP_RAW_THROUGHPUT_TX_TO_SLAVE
@@ -348,8 +346,6 @@ enum {
 #define H_TEST_RAW_TP_DIR (ESP_TEST_RAW_TP_NONE)
 #endif
 
-#define H_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS           CONFIG_ESP_MAX_SIMULTANEOUS_SYNC_RPC_REQUESTS
-#define H_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS          CONFIG_ESP_MAX_SIMULTANEOUS_ASYNC_RPC_REQUESTS
 
 esp_err_t esp_hosted_set_default_config(void);
 bool esp_hosted_is_config_valid(void);

+ 0 - 0
esp-hosted/port/esp32/esp_hosted_transport_config.c → esp-hosted/host/port/esp_hosted_transport_config.c


+ 0 - 2
esp-hosted/port/esp32/esp_hosted_transport_config.h → esp-hosted/host/port/esp_hosted_transport_config.h

@@ -93,7 +93,6 @@ struct esp_hosted_uart_config {
     uint8_t stop_bits;
     uint8_t flow_ctrl;
     uint8_t clk_src;
-    uint16_t event_queue_size;
     bool checksum_enable;
     uint32_t baud_rate;
     uint16_t tx_queue_size;
@@ -188,7 +187,6 @@ struct esp_hosted_transport_config {
         .stop_bits = H_UART_STOP_BITS, \
         .flow_ctrl = H_UART_FLOWCTRL, \
         .clk_src = H_UART_CLK_SRC, \
-        .event_queue_size = H_UART_EVENT_QUEUE_SIZE, \
         .checksum_enable = H_UART_CHECKSUM, \
         .baud_rate = H_UART_BAUD_RATE, \
         .tx_queue_size = H_UART_TX_QUEUE_SIZE, \

+ 0 - 0
esp-hosted/port/esp32/esp_hosted_wifi_config.h → esp-hosted/host/port/esp_hosted_wifi_config.h


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/CMakeLists.txt → esp-hosted/host/port/examples/wifi/iperf/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/README.md → esp-hosted/host/port/examples/wifi/iperf/README.md


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/CMakeLists.txt → esp-hosted/host/port/examples/wifi/iperf/main/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/Kconfig → esp-hosted/host/port/examples/wifi/iperf/main/Kconfig


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/Kconfig.projbuild → esp-hosted/host/port/examples/wifi/iperf/main/Kconfig.projbuild


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/cmd_decl.h → esp-hosted/host/port/examples/wifi/iperf/main/cmd_decl.h


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/cmd_wifi.c → esp-hosted/host/port/examples/wifi/iperf/main/cmd_wifi.c


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/cmd_wifi.h → esp-hosted/host/port/examples/wifi/iperf/main/cmd_wifi.h


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/main/iperf_example_main.c → esp-hosted/host/port/examples/wifi/iperf/main/iperf_example_main.c


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/pytest_iperf.py → esp-hosted/host/port/examples/wifi/iperf/pytest_iperf.py


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.00 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.00


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.01 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.01


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.02 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.02


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.03 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.03


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.04 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.04


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.05 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.05


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.06 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.06


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.07 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.07


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.ci.99 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.ci.99


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32c2 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c2


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32c3 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c3


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32c6 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32c6


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32s2 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32s2


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/iperf/sdkconfig.defaults.esp32s3 → esp-hosted/host/port/examples/wifi/iperf/sdkconfig.defaults.esp32s3


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/CMakeLists.txt → esp-hosted/host/port/examples/wifi/scan/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/README.md → esp-hosted/host/port/examples/wifi/scan/README.md


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/main/CMakeLists.txt → esp-hosted/host/port/examples/wifi/scan/main/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/main/Kconfig → esp-hosted/host/port/examples/wifi/scan/main/Kconfig


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/main/Kconfig.projbuild → esp-hosted/host/port/examples/wifi/scan/main/Kconfig.projbuild


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/scan/main/scan.c → esp-hosted/host/port/examples/wifi/scan/main/scan.c


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/softAP/CMakeLists.txt → esp-hosted/host/port/examples/wifi/softAP/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/softAP/README.md → esp-hosted/host/port/examples/wifi/softAP/README.md


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/softAP/main/CMakeLists.txt → esp-hosted/host/port/examples/wifi/softAP/main/CMakeLists.txt


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/softAP/main/Kconfig → esp-hosted/host/port/examples/wifi/softAP/main/Kconfig


+ 0 - 0
esp-hosted/port/obsolete-examples/wifi/softAP/main/Kconfig.projbuild → esp-hosted/host/port/examples/wifi/softAP/main/Kconfig.projbuild


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