diff --git a/.gitmodules b/.gitmodules index 1a0e6b94f1..df40848261 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "components/esptool_py/esptool"] path = components/esptool_py/esptool url = https://github.com/themadinventor/esptool.git +[submodule "components/bt/lib"] + path = components/bt/lib + url = https://github.com/espressif/esp32-bt-lib.git diff --git a/Kconfig b/Kconfig index 58ce77b2b5..73770a79a6 100644 --- a/Kconfig +++ b/Kconfig @@ -19,38 +19,6 @@ config PYTHON help The executable name/path that is used to run python. On some systems Python 2.x may need to be invoked as python2. - -config MEMMAP_BT - bool "Reserve space for Bluetooth stack" - default "n" - help - The Bluetooth stack uses memory that cannot be used as generic memory anymore. This - reserves the space for that within the memory map of the compiled binary. - -config MEMMAP_SMP - bool "Reserve memory for two cores" - default "y" - help - The ESP32 contains two cores. If you plan to only use one, you can disable this item - to save some memory. (ToDo: Make this automatically depend on unicore support) - -config MEMMAP_TRACEMEM - bool "Use TRAX tracing feature" - default "n" - help - The ESP32 contains a feature which allows you to trace the execution path the processor - has taken through the program. This is stored in a chunk of 32K (16K for single-processor) - of memory that can't be used for general purposes anymore. Disable this if you do not know - what this is. - -config MEMMAP_SPISRAM - bool "Use external SPI SRAM chip as main memory" - default "n" - help - The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the - main memory map. Enable this if you have this hardware and want to use it in the same - way as on-chip RAM. - endmenu source "$COMPONENT_KCONFIGS_PROJBUILD" diff --git a/components/bt/Kconfig b/components/bt/Kconfig index 90ef1f3eb6..ab163efc61 100644 --- a/components/bt/Kconfig +++ b/components/bt/Kconfig @@ -3,21 +3,21 @@ visible if MEMMAP_BT config BT_ENABLED - bool "Enable low-level BT stack" - depends on MEMMAP_BT + bool + depends on ESP32_ENABLE_STACK_BT help This compiles in the low-level BT stack. -config BT_BTLE - bool "Enable BTLE" - depends on BT_ENABLED - help - This compiles BTLE support - -config BT_BT - bool "Enable classic BT" - depends on BT_ENABLED - help - This enables classic BT support +#config BT_BTLE +# bool "Enable BTLE" +# depends on BT_ENABLED +# help +# This compiles BTLE support +# +#config BT_BT +# bool "Enable classic BT" +# depends on BT_ENABLED +# help +# This enables classic BT support endmenu diff --git a/components/bt/bt.c b/components/bt/bt.c new file mode 100644 index 0000000000..efb6d34ee3 --- /dev/null +++ b/components/bt/bt.c @@ -0,0 +1,121 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "freertos/xtensa_api.h" +#include "freertos/portmacro.h" +#include "esp_types.h" +#include "esp_system.h" +#include "esp_task.h" +#include "esp_intr.h" +#include "esp_attr.h" +#include "bt.h" + +#if CONFIG_BT_ENABLED + +/* not for user call, so don't put to include file */ +extern void btdm_osi_funcs_register(void *osi_funcs); +extern void btdm_controller_init(void); + + +static bt_app_startup_cb_t app_startup_cb; +static void *app_startup_ctx; + +#define BT_DEBUG(...) +#define BT_API_CALL_CHECK(info, api_call, ret) \ +do{\ + esp_err_t __err = (api_call);\ + if ((ret) != __err) {\ + BT_DEBUG("%s %d %s ret=%d\n", __FUNCTION__, __LINE__, (info), __err);\ + return __err;\ + }\ +} while(0) + +struct osi_funcs_t { + xt_handler (*_set_isr)(int n, xt_handler f, void *arg); + void (*_ints_on)(unsigned int mask); + void (*_interrupt_disable)(void); + void (*_interrupt_restore)(void); + void (*_task_yield)(void); + void *(*_semphr_create)(uint32_t max, uint32_t init); + void *(*_semphr_give_from_isr)(void *semphr, void *hptw); + void *(*_semphr_take)(void *semphr, uint32_t block_time); + esp_err_t (* _read_efuse_mac)(uint8_t mac[6]); +}; + +static portMUX_TYPE global_int_mux = portMUX_INITIALIZER_UNLOCKED; + +static void IRAM_ATTR interrupt_disable(void) +{ + portENTER_CRITICAL(&global_int_mux); +} + +static void IRAM_ATTR interrupt_restore(void) +{ + portEXIT_CRITICAL(&global_int_mux); +} + +static void * IRAM_ATTR semphr_take_wrapper(void *semphr, uint32_t block_time) +{ + return (void *)xSemaphoreTake(semphr, block_time); +} + +static struct osi_funcs_t osi_funcs = { + ._set_isr = xt_set_interrupt_handler, + ._ints_on = xt_ints_on, + ._interrupt_disable = interrupt_disable, + ._interrupt_restore = interrupt_restore, + ._task_yield = vPortYield, + ._semphr_create = xQueueCreateCountingSemaphore, + ._semphr_give_from_isr = (void *)xQueueGiveFromISR, + ._semphr_take = semphr_take_wrapper, + ._read_efuse_mac = system_efuse_read_mac, +}; + +static void bt_controller_task(void *pvParam) +{ + btdm_osi_funcs_register(&osi_funcs); + btdm_controller_init(); +} + + +static void bt_init_task(void *pvParameters) +{ + xTaskCreatePinnedToCore(bt_controller_task, "btControllerTask", ESP_TASK_BT_CONTROLLER_STACK, NULL, ESP_TASK_BT_CONTROLLER_PRIO, NULL, 0); + + if (app_startup_cb) { + app_startup_cb(app_startup_ctx); + } + + vTaskDelete(NULL); +} + + +esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx) +{ + app_startup_cb = cb; + app_startup_ctx = ctx; + + xTaskCreatePinnedToCore(bt_init_task, "btInitTask", ESP_TASK_BT_INIT_STACK, NULL, ESP_TASK_BT_INIT_PRIO, NULL, 0); + + return ESP_OK; +} +#endif diff --git a/components/bt/component.mk b/components/bt/component.mk new file mode 100644 index 0000000000..110d022672 --- /dev/null +++ b/components/bt/component.mk @@ -0,0 +1,25 @@ +# +# Component Makefile +# + +#COMPONENT_ADD_INCLUDEDIRS := + +CURRENT_DIR=$(IDF_PATH)/components/bt + +COMPONENT_ADD_INCLUDEDIRS := ./include + +CFLAGS += -Wno-error=unused-label -Wno-error=return-type -Wno-error=missing-braces -Wno-error=pointer-sign -Wno-error=parentheses + +LIBS := btdm_app + +COMPONENT_ADD_LDFLAGS := -lbt -L$(abspath lib) \ + $(addprefix -l,$(LIBS)) \ + $(LINKER_SCRIPTS) + + +ALL_LIB_FILES := $(patsubst %,$(COMPONENT_PATH)/lib/lib%.a,$(LIBS)) +$(COMPONENT_LIBRARY): $(ALL_LIB_FILES) + +COMPONENT_SRCDIRS := ./ + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h new file mode 100644 index 0000000000..8511aabdf8 --- /dev/null +++ b/components/bt/include/bt.h @@ -0,0 +1,66 @@ +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef __BT_H__ +#define __BT_H__ + +#include "freertos/FreeRTOS.h" +#include "esp_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef void (* bt_app_startup_cb_t)(void *param); + +esp_err_t esp_bt_startup(bt_app_startup_cb_t cb, void *ctx); + +/* @breif: vhci_host_callback + * used for vhci call host function to notify what host need to do + * + * notify_host_send_available: notify host can send packet to controller + * notify_host_recv: notify host that controller has packet send to host + */ +typedef struct vhci_host_callback { + + void (*notify_host_send_available)(void); + int (*notify_host_recv)(uint8_t *data, uint16_t len); +} vhci_host_callback_t; + +/* @breif: API_vhci_host_check_send_available + * used for check actively if the host can send packet to controller or not. + * return true for ready to send, false means cannot send packet + */ +bool API_vhci_host_check_send_available(void); + +/* @breif: API_vhci_host_send_packet + * host send packet to controller + * param data is the packet point, the param len is the packet length + * return void + */ +void API_vhci_host_send_packet(uint8_t *data, uint16_t len); + +/* @breif: API_vhci_host_register_callback + * register the vhci referece callback, the call back + * struct defined by vhci_host_callback structure. + * param is the vhci_host_callback type variable + */ +void API_vhci_host_register_callback(const vhci_host_callback_t *callback); + +#ifdef __cplusplus +} +#endif + +#endif /* __BT_H__ */ diff --git a/components/bt/lib b/components/bt/lib new file mode 160000 index 0000000000..6c9a6de656 --- /dev/null +++ b/components/bt/lib @@ -0,0 +1 @@ +Subproject commit 6c9a6de656262113a0aab63907d6871a64e00fae diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 0ad32756e8..c649a0e317 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -20,13 +20,65 @@ config ESP32_DEFAULT_CPU_FREQ_MHZ default 160 if ESP32_DEFAULT_CPU_FREQ_160 default 240 if ESP32_DEFAULT_CPU_FREQ_240 -config WIFI_ENABLED - bool "Enable low-level WiFi stack" +choice ESP32_WIFI_OR_BT + prompt "Select stack to enable (WiFi or BT)" + default ESP32_ENABLE_WIFI + help + Temporarily, WiFi and BT stacks can not be used at the same time. + Select which stack to enable. + +config ESP32_ENABLE_STACK_WIFI + bool "WiFi" + select WIFI_ENABLED if ESP32_ENABLE_STACK_WIFI +config ESP32_ENABLE_STACK_BT + bool "BT" + select MEMMAP_BT if ESP32_ENABLE_STACK_BT + select BT_ENABLED if ESP32_ENABLE_STACK_BT +config ESP32_ENABLE_STACK_NONE + bool "None" +endchoice + +config MEMMAP_BT + bool + depends on ESP32_ENABLE_STACK_BT + help + The Bluetooth stack uses memory that cannot be used as generic memory anymore. This + reserves the space for that within the memory map of the compiled binary. + This option is required to enable BT stack. + Temporarily, this option is not compatible with WiFi stack. + +config MEMMAP_SMP + bool "Reserve memory for two cores" default "y" + help + The ESP32 contains two cores. If you plan to only use one, you can disable this item + to save some memory. (ToDo: Make this automatically depend on unicore support) + +config MEMMAP_TRACEMEM + bool "Use TRAX tracing feature" + default "n" + help + The ESP32 contains a feature which allows you to trace the execution path the processor + has taken through the program. This is stored in a chunk of 32K (16K for single-processor) + of memory that can't be used for general purposes anymore. Disable this if you do not know + what this is. + +config MEMMAP_SPISRAM + bool "Use external SPI SRAM chip as main memory" + default "n" + help + The ESP32 can control an external SPI SRAM chip, adding the memory it contains to the + main memory map. Enable this if you have this hardware and want to use it in the same + way as on-chip RAM. + +config WIFI_ENABLED + bool + default "y" + depends on ESP32_ENABLE_STACK_WIFI help This compiles in the low-level WiFi stack. - Temporarily, this option requires that FreeRTOS runs in single core mode. + Temporarily, this option is not compatible with BT stack. config WIFI_AUTO_STARTUP bool "Start WiFi with system startup" diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 85f4ace512..45a4bcec3c 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -48,6 +48,9 @@ static void IRAM_ATTR call_user_start_cpu1(); static void IRAM_ATTR user_start_cpu1(void); extern void ets_setup_syscalls(void); extern esp_err_t app_main(void *ctx); +#if CONFIG_BT_ENABLED +extern void bt_app_main(void *param); +#endif extern int _bss_start; extern int _bss_end; @@ -161,7 +164,10 @@ void user_start_cpu0(void) #if CONFIG_WIFI_ENABLED && CONFIG_WIFI_AUTO_STARTUP #include "esp_wifi.h" - esp_wifi_startup(app_main, NULL); + esp_wifi_startup(app_main, NULL); +#elif CONFIG_BT_ENABLED +#include "bt.h" + esp_bt_startup(bt_app_main, NULL); #else app_main(NULL); #endif diff --git a/components/esp32/include/esp_task.h b/components/esp32/include/esp_task.h index 6d98bf1983..58458106fa 100644 --- a/components/esp32/include/esp_task.h +++ b/components/esp32/include/esp_task.h @@ -43,6 +43,11 @@ #define ESP_TASK_WPS_PRIO (ESP_TASK_PRIO_MIN + 2) #define ESP_TASK_WPS_STACK 2048 +/* Bt contoller Task */ +/* controller */ +#define ESP_TASK_BT_CONTROLLER_PRIO (ESP_TASK_PRIO_MAX - 1) +#define ESP_TASK_BT_CONTROLLER_STACK 4096 + /* idf task */ #define ESP_TASKD_EVENT_PRIO (ESP_TASK_PRIO_MAX - 5) #define ESP_TASKD_EVENT_STACK CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE @@ -50,5 +55,6 @@ #define ESP_TASK_WIFI_STARTUP_STACK 4096 #define ESP_TASK_TCPIP_PRIO (ESP_TASK_PRIO_MAX - 7) #define ESP_TASK_TCPIP_STACK 2048 - +#define ESP_TASK_BT_INIT_PRIO (ESP_TASK_PRIO_MAX - 7) +#define ESP_TASK_BT_INIT_STACK 2048 #endif diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 0b8cdfecba..4ffdfb069e 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -260,14 +260,14 @@ /************************************************************************************************************* * Intr num Level Type PRO CPU usage APP CPU uasge * 0 1 extern level WMAC Reserved - * 1 1 extern level BT/BLE Host Reserved + * 1 1 extern level BT/BLE Host VHCI Reserved * 2 1 extern level FROM_CPU FROM_CPU * 3 1 extern level TG0_WDT Reserved * 4 1 extern level WBB - * 5 1 extern level Reserved + * 5 1 extern level BT Controller * 6 1 timer FreeRTOS Tick(L1) FreeRTOS Tick(L1) * 7 1 software Reserved Reserved - * 8 1 extern level Reserved + * 8 1 extern level BLE Controller * 9 1 extern level * 10 1 extern edge Internal Timer * 11 3 profiling diff --git a/examples/04_ble_adv/Makefile b/examples/04_ble_adv/Makefile new file mode 100644 index 0000000000..cea72c6f02 --- /dev/null +++ b/examples/04_ble_adv/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := ble_adv + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/04_ble_adv/README.rst b/examples/04_ble_adv/README.rst new file mode 100644 index 0000000000..5e9ff15c5c --- /dev/null +++ b/examples/04_ble_adv/README.rst @@ -0,0 +1,6 @@ +ESP-IDF ble_advertising app +==================== + +This is a BLE advertising demo with virtual HCI interface. Send Reset/ADV_PARAM/ADV_DATA/ADV_ENABLE HCI command for BLE advertising. + + diff --git a/examples/04_ble_adv/main/app_bt.c b/examples/04_ble_adv/main/app_bt.c new file mode 100755 index 0000000000..011cf0c715 --- /dev/null +++ b/examples/04_ble_adv/main/app_bt.c @@ -0,0 +1,204 @@ +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "bt.h" +#include + +#define HCI_H4_CMD_PREAMBLE_SIZE (4) + +/* HCI Command opcode group field(OGF) */ +#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10) /* 0x0C00 */ +#define HCI_GRP_BLE_CMDS (0x08 << 10) + +#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS) +#define HCI_BLE_WRITE_ADV_ENABLE (0x000A | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_PARAMS (0x0006 | HCI_GRP_BLE_CMDS) +#define HCI_BLE_WRITE_ADV_DATA (0x0008 | HCI_GRP_BLE_CMDS) + +#define HCIC_PARAM_SIZE_WRITE_ADV_ENABLE (1) +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_PARAMS (15) +#define HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA (31) + +#define BD_ADDR_LEN (6) /* Device address length */ +typedef uint8_t bd_addr_t[BD_ADDR_LEN]; /* Device address */ + +#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);} +#define UINT8_TO_STREAM(p, u8) {*(p)++ = (uint8_t)(u8);} +#define BDADDR_TO_STREAM(p, a) {int ijk; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *(p)++ = (uint8_t) a[BD_ADDR_LEN - 1 - ijk];} +#define ARRAY_TO_STREAM(p, a, len) {int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (uint8_t) a[ijk];} + +enum { + H4_TYPE_COMMAND = 1, + H4_TYPE_ACL = 2, + H4_TYPE_SCO = 3, + H4_TYPE_EVENT = 4 +}; + +static uint8_t hci_cmd_buf[128]; + +/* + * @brief: BT controller callback function, used to notify the upper layer that + * controller is ready to receive command + */ +static void controller_rcv_pkt_ready(void) +{ + printf("controller rcv pkt ready\n"); +} + +/* + * @brief: BT controller callback function, to transfer data packet to upper + * controller is ready to receive command + */ +static int host_rcv_pkt(uint8_t *data, uint16_t len) +{ + printf("host rcv pkt: "); + for (uint16_t i=0; i 0) { + if (data_len > HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA) { + data_len = HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA; + } + + UINT8_TO_STREAM (buf, data_len); + + ARRAY_TO_STREAM (buf, p_data, data_len); + } + return HCI_H4_CMD_PREAMBLE_SIZE + HCIC_PARAM_SIZE_BLE_WRITE_ADV_DATA + 1; +} + +static void hci_cmd_send_reset(void) +{ + uint16_t sz = make_cmd_reset (hci_cmd_buf); + API_vhci_host_send_packet(hci_cmd_buf, sz); +} + +static void hci_cmd_send_ble_adv_start(void) +{ + uint16_t sz = make_cmd_ble_set_adv_enable (hci_cmd_buf, 1); + API_vhci_host_send_packet(hci_cmd_buf, sz); +} + +static void hci_cmd_send_ble_set_adv_param(void) +{ + uint16_t adv_intv_min = 256; // 160ms + uint16_t adv_intv_max = 256; // 160ms + uint8_t adv_type = 0; // connectable undirected advertising (ADV_IND) + uint8_t own_addr_type = 0; // Public Device Address + uint8_t peer_addr_type = 0; // Public Device Address + uint8_t peer_addr[6] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85}; + uint8_t adv_chn_map = 0x07; // 37, 38, 39 + uint8_t adv_filter_policy = 0; // Process All Conn and Scan + + uint16_t sz = make_cmd_ble_set_adv_param(hci_cmd_buf, + adv_intv_min, + adv_intv_max, + adv_type, + own_addr_type, + peer_addr_type, + peer_addr, + adv_chn_map, + adv_filter_policy); + API_vhci_host_send_packet(hci_cmd_buf, sz); +} + +static void hci_cmd_send_ble_set_adv_data(void) +{ + char *adv_name = "ESP-BLE-HELLO"; + uint8_t name_len = (uint8_t)strlen(adv_name); + uint8_t adv_data[31] = {0x02, 0x01, 0x06, 0x0, 0x09}; + uint8_t adv_data_len; + + adv_data[3] = name_len + 1; + for (int i=0; i