From 761d8cebee17014bf51c83f169f96e697431fbe7 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Mon, 30 Apr 2018 21:44:19 +1200 Subject: [PATCH 01/15] intial esp-idf 3.0 build --- boards/ESP32.py | 2 +- libs/network/network.c | 3 ++- make/family/ESP32.make | 16 ++++++++++++- scripts/provision.sh | 8 ++++--- targets/esp32/jswrap_esp32.c | 44 ++---------------------------------- 5 files changed, 25 insertions(+), 48 deletions(-) diff --git a/boards/ESP32.py b/boards/ESP32.py index c41a064b5..e48b38e8d 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -19,7 +19,7 @@ 'espruino_page_link' : 'ESP32', 'default_console' : "EV_SERIAL1", 'default_console_baudrate' : "115200", - 'variables' : 5000, + 'variables' : 3000, 'binary_name' : 'espruino_%v_esp32.bin', 'build' : { 'optimizeflags' : '-Og', diff --git a/libs/network/network.c b/libs/network/network.c index 7cf59d26a..201f6553b 100644 --- a/libs/network/network.c +++ b/libs/network/network.c @@ -672,7 +672,8 @@ int netCreateSocket(JsNetwork *net, SocketType socketType, uint32_t host, unsign if (sckt<0) return sckt; #ifdef USE_TLS - assert(sckt>=0 && sckt<32); + // NEED TO FIX - as socket is assumed to be < 32 + //assert(sckt>=0 && sckt<32); if (socketType & ST_TLS) { if (ssl_newSocketData(sckt, options)) { } else { diff --git a/make/family/ESP32.make b/make/family/ESP32.make index a1f07b03b..e45d3f169 100755 --- a/make/family/ESP32.make +++ b/make/family/ESP32.make @@ -6,7 +6,7 @@ ESP32=1 CFLAGS+=-Og -Wpointer-arith -Wno-error=unused-function -Wno-error=unused-but-set-variable \ -Wno-error=unused-variable -Wall -ffunction-sections -fdata-sections -mlongcalls -nostdlib \ --MMD -MP -std=gnu99 -fstrict-volatile-bitfields -fgnu89-inline +-MMD -MP -std=gnu99 -fstrict-volatile-bitfields -fgnu89-inline -mfix-esp32-psram-cache-issue SOURCES += targets/esp32/jshardware.c SOURCES += targets/esp32/esp32_neopixel.c INCLUDE += -I$(ROOT)/targets/esp32 @@ -38,6 +38,8 @@ LDFLAGS += -L$(ESP_IDF_PATH)/ld \ -L$(ESP_APP_TEMPLATE_PATH)/build/nghttp \ -L$(ESP_APP_TEMPLATE_PATH)/build/nvs_flash \ -L$(ESP_APP_TEMPLATE_PATH)/build/partition_table \ +-L$(ESP_APP_TEMPLATE_PATH)/build/pthread \ +-L$(ESP_APP_TEMPLATE_PATH)/build/heap \ -L$(ESP_APP_TEMPLATE_PATH)/build/soc \ -L$(ESP_APP_TEMPLATE_PATH)/build/spi_flash \ -L$(ESP_APP_TEMPLATE_PATH)/build/tcpip_adapter \ @@ -46,12 +48,14 @@ LDFLAGS += -L$(ESP_IDF_PATH)/ld \ -L$(ESP_APP_TEMPLATE_PATH)/build/wpa_supplicant \ -L$(ESP_APP_TEMPLATE_PATH)/build/ethernet \ -L$(ESP_APP_TEMPLATE_PATH)/build/app_update \ +-L$(ESP_IDF_PATH)/components/esp32/ld \ -lgcc ESPTOOL?= INCLUDE+=\ -I$(ESP_APP_TEMPLATE_PATH)/build/include \ -I$(ESP_IDF_PATH)/components \ -I$(ESP_IDF_PATH)/components/newlib/include \ +-I$(ESP_IDF_PATH)/components/pthread/include \ -I$(ESP_IDF_PATH)/components/bt/include \ -I$(ESP_IDF_PATH)/components/driver/include \ -I$(ESP_IDF_PATH)/components/esp32/include \ @@ -66,6 +70,8 @@ INCLUDE+=\ -I$(ESP_IDF_PATH)/components/nvs_flash/include \ -I$(ESP_IDF_PATH)/components/tcpip_adapter/include \ -I$(ESP_IDF_PATH)/components/vfs/include \ +-I$(ESP_IDF_PATH)/components/heap/include \ +-I$(ESP_IDF_PATH)/components/soc/include \ -I$(ESP_IDF_PATH)/components/soc/esp32/include \ -I$(ESP_IDF_PATH)/components/soc/esp32/include/soc \ -Itargets/esp32/include @@ -75,8 +81,14 @@ LIBS+=-T esp32_out.ld \ -T$(ESP_IDF_PATH)/components/esp32/ld/esp32.rom.ld \ -T$(ESP_IDF_PATH)/components/esp32/ld/esp32.peripherals.ld \ $(ESP_IDF_PATH)/components/esp32/lib/librtc.a \ +$(ESP_IDF_PATH)/components/esp32/lib/libnet80211.a \ $(ESP_IDF_PATH)/components/newlib/lib/libc.a \ $(ESP_IDF_PATH)/components/newlib/lib/libm.a \ +$(ESP_IDF_PATH)/components/esp32/lib/libwpa2.a \ +$(ESP_IDF_PATH)/components/esp32/lib/libwps.a \ +$(ESP_IDF_PATH)/components/newlib/lib/libc-psram-workaround.a \ +$(ESP_IDF_PATH)/components/newlib/lib/libm-psram-workaround.a \ +$(ESP_IDF_PATH)/components/esp32/lib/libcore.a \ -lbt \ -lbtdm_app \ -ldriver \ @@ -97,6 +109,8 @@ $(ESP_IDF_PATH)/components/esp32/libhal.a \ -lmbedtls \ -lnghttp \ -lnvs_flash \ +-lheap \ +-lpthread \ -lsoc \ -lspi_flash \ -ltcpip_adapter \ diff --git a/scripts/provision.sh b/scripts/provision.sh index 9dcff3e04..e67314d81 100755 --- a/scripts/provision.sh +++ b/scripts/provision.sh @@ -38,16 +38,18 @@ if [ "$FAMILY" = "ESP32" ]; then # SDK if [ ! -d "app" ]; then echo installing app folder - curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/master/esp32/deploy/app.tgz | tar xfz - --no-same-owner + #curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/master/esp32/deploy/app.tgz | tar xfz - --no-same-owner + curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/ESP32-v3.0/esp32/deploy/app.tgz | tar xfz - --no-same-owner fi if [ ! -d "esp-idf" ]; then echo installing esp-idf folder - curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/master/esp32/deploy/esp-idf.tgz | tar xfz - --no-same-owner + #curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/master/esp32/deploy/esp-idf.tgz | tar xfz - --no-same-owner + curl -Ls https://github.com/espruino/EspruinoBuildTools/raw/ESP32-v3.0/esp32/deploy/esp-idf.tgz | tar xfz - --no-same-owner fi if ! type xtensa-esp32-elf-gcc 2> /dev/null > /dev/null; then echo installing xtensa-esp32-elf-gcc if [ ! -d "xtensa-esp32-elf" ]; then - curl -Ls https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz | tar xfz - --no-same-owner + curl -Ls https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz | tar xfz - --no-same-owner else echo "Folder found" fi diff --git a/targets/esp32/jswrap_esp32.c b/targets/esp32/jswrap_esp32.c index 167726a88..895c32ca0 100644 --- a/targets/esp32/jswrap_esp32.c +++ b/targets/esp32/jswrap_esp32.c @@ -17,7 +17,7 @@ #include "jshardwareAnalog.h" #include "esp_system.h" -#include "app_update/include/esp_ota_ops.h" +#include "esp_sleep.h" /*JSON{ "type" : "staticmethod", @@ -57,7 +57,7 @@ void jswrap_ESP32_reboot() { Put device in deepsleep state for "us" microseconds. */ void jswrap_ESP32_deepSleep(int us) { - esp_deep_sleep_enable_timer_wakeup((uint64_t)(us)); + esp_sleep_enable_timer_wakeup((uint64_t)(us)); esp_deep_sleep_start(); // This function does not return. } // End of jswrap_ESP32_deepSleep @@ -81,45 +81,5 @@ JsVar *jswrap_ESP32_getState() { JsVar *esp32State = jsvNewObject(); jsvObjectSetChildAndUnLock(esp32State, "sdkVersion", jsvNewFromString(esp_get_idf_version())); jsvObjectSetChildAndUnLock(esp32State, "freeHeap", jsvNewFromInteger(esp_get_free_heap_size())); - esp_partition_t * partition=esp_ota_get_boot_partition(); - jsvObjectSetChildAndUnLock(esp32State, "addr", jsvNewFromInteger(partition->address)); - jsvObjectSetChildAndUnLock(esp32State, "partitionBoot", jsvNewFromString( partition->label)); - //jsvObjectSetChildAndUnLock(esp32State, "partitionRunning", jsvNewFromString( esp_ota_get_running_partition()->label)); - //jsvObjectSetChildAndUnLock(esp32State, "partitionNext", jsvNewFromString( esp_ota_get_next_update_partition(NULL)->label)); return esp32State; } // End of jswrap_ESP32_getState - -/*JSON{ - "type" : "staticmethod", - "class" : "ESP32", - "name" : "setBoot", - "generate" : "jswrap_ESP32_setBoot", - "params" : [ - ["jsPartitionName", "JsVar", "Name of ota partition to boot into next boot"] - ], - "return" : ["JsVar", "Change boot partition after ota update"] -} -*/ -JsVar *jswrap_ESP32_setBoot(JsVar *jsPartitionName) { - JsVar *esp32State = jsvNewObject(); - esp_err_t err; - char partitionNameStr[20]; - - jsvGetString(jsPartitionName, partitionNameStr, sizeof(partitionNameStr)); - esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, partitionNameStr); - if (it==0) { - jsError("Couldn't find partition with name %s\n", partitionNameStr); - } - else { - const esp_partition_t *p = esp_partition_get(it); - err= ESP_OK; //esp_ota_set_boot_partition(p); - if (err!=ESP_OK) { - jsError("Couldn't set boot partition %d!\n",err); - } else { - jsvObjectSetChildAndUnLock(esp32State, "addr", jsvNewFromInteger(p->address)); - jsvObjectSetChildAndUnLock(esp32State, "nextPartitionBoot", jsvNewFromString( p->label)); - } - } - esp_partition_iterator_release(it); - return esp32State; -} // End of jswrap_ESP32_setBoot From eb1f01e981ae4bca01fd669b967419b2e9341bb6 Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Sun, 6 May 2018 17:16:00 +1200 Subject: [PATCH 02/15] update constant to #define --- targets/esp32/jshardware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/esp32/jshardware.c b/targets/esp32/jshardware.c index f5edcf752..4b52b5dde 100644 --- a/targets/esp32/jshardware.c +++ b/targets/esp32/jshardware.c @@ -727,7 +727,7 @@ size_t jshFlashGetMemMapAddress(size_t ptr) { return 0; } // Flash memory access is offset to 0, so remove starting location as already accounted for - return &romdata_jscode[ptr - 0x100000 ]; + return &romdata_jscode[ptr - FLASH_SAVED_CODE_START ]; } unsigned int jshSetSystemClock(JsVar *options) { From cfc72335906f0fb612597c8b19fd41f9e4233737 Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Sun, 6 May 2018 21:05:54 +1200 Subject: [PATCH 03/15] check build with debug off in esp-idf libs --- targets/esp32/jshardware.c | 1 + 1 file changed, 1 insertion(+) diff --git a/targets/esp32/jshardware.c b/targets/esp32/jshardware.c index 4b52b5dde..b203b5085 100644 --- a/targets/esp32/jshardware.c +++ b/targets/esp32/jshardware.c @@ -702,6 +702,7 @@ JsVar *jshFlashGetFree() { if (!jsFreeFlash) return 0; // Space should be reserved here in the parition table - assume 4Mb EEPROM // Set just after programme save area + // This should be read from the partition table - need to define area addFlashArea(jsFreeFlash, 0x100000 + FLASH_PAGE * 16, 0x300000-FLASH_PAGE * 16-1); return jsFreeFlash; From c01485b175343d8613f1918bfe1ddf98bbce8d1a Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Fri, 11 May 2018 20:58:48 +1200 Subject: [PATCH 04/15] New partition table and layout - partitions_espruino.bin needs to be flashed --- boards/ESP32.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/boards/ESP32.py b/boards/ESP32.py index e48b38e8d..905a9070f 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -55,8 +55,8 @@ 'saved_code' : { 'address' : 0x100000, 'page_size' : 4096, - 'pages' : 16, - 'flash_available' : 960, # firmware can be up to this size + 'pages' : 64, + 'flash_available' : 91344, # firmware can be up to this size - see paritions_espruino.csv }, }; devices = { From 4f930f0271c22a92220b250442106e7e21b5c24c Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Fri, 11 May 2018 21:02:30 +1200 Subject: [PATCH 05/15] sync network.c --- libs/network/network.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/libs/network/network.c b/libs/network/network.c index 201f6553b..3cddde148 100644 --- a/libs/network/network.c +++ b/libs/network/network.c @@ -508,7 +508,6 @@ bool ssl_newSocketData(int sckt, JsVar *options) { * Also see https://tls.mbed.org/kb/how-to/reduce-mbedtls-memory-and-storage-footprint * */ - assert(sckt>=0 && sckt<32); // Create a new socketData using the variable JsVar *ssl = jsvObjectGetChild(execInfo.root, "ssl", JSV_OBJECT); if (!ssl) return false; // out of memory? @@ -672,8 +671,6 @@ int netCreateSocket(JsNetwork *net, SocketType socketType, uint32_t host, unsign if (sckt<0) return sckt; #ifdef USE_TLS - // NEED TO FIX - as socket is assumed to be < 32 - //assert(sckt>=0 && sckt<32); if (socketType & ST_TLS) { if (ssl_newSocketData(sckt, options)) { } else { From c33d1102dd887c1b92e87e9e7af04daa15baa086 Mon Sep 17 00:00:00 2001 From: Rhys Williams Date: Fri, 11 May 2018 21:09:41 +1200 Subject: [PATCH 06/15] correct firmware size --- boards/ESP32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/ESP32.py b/boards/ESP32.py index 905a9070f..cb4479567 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -56,7 +56,7 @@ 'address' : 0x100000, 'page_size' : 4096, 'pages' : 64, - 'flash_available' : 91344, # firmware can be up to this size - see paritions_espruino.csv + 'flash_available' : 1344, # firmware can be up to this size - see paritions_espruino.csv }, }; devices = { From 3f99ffe89627b16fd9f33bab3df54bd06a169760 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Sat, 12 May 2018 00:21:32 +1200 Subject: [PATCH 07/15] Correct saved code location 0x2C0000 --- boards/ESP32.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/ESP32.py b/boards/ESP32.py index cb4479567..20ecc51bc 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -53,7 +53,7 @@ 'adc' : 2, 'dac' : 0, 'saved_code' : { - 'address' : 0x100000, + 'address' : 0x2C0000, 'page_size' : 4096, 'pages' : 64, 'flash_available' : 1344, # firmware can be up to this size - see paritions_espruino.csv From c5921bd803559ba8ab3170f0e23dd2d7d262a834 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Sat, 12 May 2018 09:51:43 +1200 Subject: [PATCH 08/15] update require("Flash").getFree(); addresses --- libs/bluetooth/bluetooth.h | 8 +++++++- targets/esp32/jshardware.c | 14 +++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/libs/bluetooth/bluetooth.h b/libs/bluetooth/bluetooth.h index 4f0c22cff..8a6b249f9 100644 --- a/libs/bluetooth/bluetooth.h +++ b/libs/bluetooth/bluetooth.h @@ -23,7 +23,8 @@ #else typedef struct { uint16_t uuid; - uint8_t type; + uint8_t type; //see BLE_UUID_TYPE_... definitions + uint8_t uuid128[16]; //BLE knows 16/32/128 bit uuids. Espruino supports 16/128. } PACKED_FLAGS ble_uuid_t; typedef struct { //uint8_t addr_id_peer; @@ -44,6 +45,7 @@ typedef struct { #define BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA 0xFF #define BLE_UUID_TYPE_UNKNOWN (0) #define BLE_UUID_TYPE_BLE (1) +#define BLE_UUID_TYPE_128 2 #define MSEC_TO_UNITS(MS,MEH) MS #endif @@ -56,6 +58,10 @@ typedef struct { #define PERIPHERAL_LINK_COUNT 1 /** Date: Sun, 13 May 2018 13:54:02 +1200 Subject: [PATCH 09/15] update esp-idf to v3.0. BLE support - thanks to @jumjum. 2500 vars. Erase flash before flashing --- ChangeLog | 11 + boards/ESP32.py | 2 +- libs/bluetooth/bluetooth_utils.c | 23 +- libs/bluetooth/jswrap_bluetooth.c | 75 ++- libs/bluetooth/jswrap_bluetooth.h | 1 + make/family/ESP32.make | 20 + scripts/common.py | 19 +- scripts/esp32/flash-blank-js.bat | 3 +- scripts/esp32/flash-erase.bat | 2 +- targets/esp32/BLE/esp32_bluetooth_utils.c | 292 ++++++++++++ targets/esp32/BLE/esp32_bluetooth_utils.h | 57 +++ targets/esp32/BLE/esp32_gap_func.c | 279 +++++++++++ targets/esp32/BLE/esp32_gap_func.h | 36 ++ targets/esp32/BLE/esp32_gattc_func.c | 247 ++++++++++ targets/esp32/BLE/esp32_gattc_func.h | 46 ++ targets/esp32/BLE/esp32_gatts_func.c | 554 ++++++++++++++++++++++ targets/esp32/BLE/esp32_gatts_func.h | 80 ++++ targets/esp32/bluetooth.c | 203 ++++++++ targets/esp32/jshardware.c | 37 +- targets/esp32/jswrap_esp32.c | 34 +- targets/esp32/jswrap_esp32.h | 4 + targets/esp32/main.c | 15 +- 22 files changed, 1984 insertions(+), 56 deletions(-) create mode 100644 targets/esp32/BLE/esp32_bluetooth_utils.c create mode 100644 targets/esp32/BLE/esp32_bluetooth_utils.h create mode 100644 targets/esp32/BLE/esp32_gap_func.c create mode 100644 targets/esp32/BLE/esp32_gap_func.h create mode 100644 targets/esp32/BLE/esp32_gattc_func.c create mode 100644 targets/esp32/BLE/esp32_gattc_func.h create mode 100644 targets/esp32/BLE/esp32_gatts_func.c create mode 100644 targets/esp32/BLE/esp32_gatts_func.h create mode 100644 targets/esp32/bluetooth.c diff --git a/ChangeLog b/ChangeLog index 632c92767..c6e406f7b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,15 @@ + ESP32: update esp-idf to v3.0. BLE support - thanks to @jumjum. Erase flash before flashing Allow Crypto SHA1 without SHA256/512 (for Original & ESP8266 where flash is scarce) + Add better docs for the form of Wifi callback functions + Modify ESP8266/ESP32 callbacks to match the node.js style used elsewhere + nRF52: fix pin.toggle() on software-negated pins + Pixl.js: Reorder pins so 0..13 are also D0..13 for better Arduino compatibility + Fix dump() when used with code written using E.setBootCode(..), (fix #1398) + Allow parseInt/parseFloat to be used on very large strings if the number doesn't extend right to the end (fix #1397) + nRF5x: Fix memory leak on NRF.connect + Fix memory leak if an exception is thrown within a rejected promise + ESP8266: rewrite wifi.save and restore to use the storage lib (imp #1380) + ESP8266: Add missing option ssid_hidden for Wifi.startAP() (imp #1358) 1v97 : nRF52: fix NRF.on('connect',...) issue STM32: Fix setDeviceClockCmd error for USB.setConsole() diff --git a/boards/ESP32.py b/boards/ESP32.py index 20ecc51bc..f33eb0af9 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -19,7 +19,7 @@ 'espruino_page_link' : 'ESP32', 'default_console' : "EV_SERIAL1", 'default_console_baudrate' : "115200", - 'variables' : 3000, + 'variables' : 2500, 'binary_name' : 'espruino_%v_esp32.bin', 'build' : { 'optimizeflags' : '-Og', diff --git a/libs/bluetooth/bluetooth_utils.c b/libs/bluetooth/bluetooth_utils.c index d8c2f9d99..b8a47080f 100644 --- a/libs/bluetooth/bluetooth_utils.c +++ b/libs/bluetooth/bluetooth_utils.c @@ -24,7 +24,20 @@ /// Return true if two UUIDs are equal bool bleUUIDEqual(ble_uuid_t a, ble_uuid_t b) { - return a.type==b.type && a.uuid==b.uuid; +#ifdef NRF5X + return a.type==b.type && a.uuid==b.uuid; +#else + switch(a.type){ + case BLE_UUID_TYPE_UNKNOWN: + return a.type == b.type; + case BLE_UUID_TYPE_BLE: + return a.type == b.type && a.uuid == b.uuid; + case BLE_UUID_TYPE_128: + return a.type == b.type && a.uuid128 == b.uuid128; + default: + return false; + } +#endif } JsVar *bleUUID128ToStr(const uint8_t *data) { @@ -52,8 +65,7 @@ JsVar *bleUUIDToStr(ble_uuid_t uuid) { assert(dataLen==16); // it should always be 16 as we checked above return bleUUID128ToStr(&data[0]); #else - jsiConsolePrintf("FIXME\n"); - return 0; + return bleUUID128ToStr(&uuid.uuid128); #endif } @@ -163,7 +175,10 @@ const char *bleVarToUUID(ble_uuid_t *uuid, JsVar *v) { } return err_code ? "BLE device error adding UUID" : 0; #else - jsiConsolePrintf("FIXME\n"); + uuid->uuid = ((data[13]<<8) | data[12]); + for(int i = 0; i < 16; i++){ + uuid->uuid128[i] = data[i]; + } return 0; #endif } diff --git a/libs/bluetooth/jswrap_bluetooth.c b/libs/bluetooth/jswrap_bluetooth.c index 132d1c661..05cfd7f62 100644 --- a/libs/bluetooth/jswrap_bluetooth.c +++ b/libs/bluetooth/jswrap_bluetooth.c @@ -44,6 +44,12 @@ #endif #endif +#ifdef ESP32 +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_gatts_func.h" +#include "BLE/esp32_gattc_func.h" +#define BLE_CONN_HANDLE_INVALID -1 +#endif // ------------------------------------------------------------------------------ // ------------------------------------------------------------------------------ @@ -141,14 +147,16 @@ void jswrap_nrf_init() { if (jsiStatus & JSIS_COMPLETELY_RESET) { -#if defined(USE_NFC) && defined(NFC_DEFAULT_URL) +#ifdef USE_NFC +#ifdef PUCKJS // By default Puck.js's NFC will send you to the PuckJS website // address is included so Web Bluetooth can connect to the correct one JsVar *addr = jswrap_nrf_bluetooth_getAddress(); - JsVar *uri = jsvVarPrintf(NFC_DEFAULT_URL"?a=%v", addr); + JsVar *uri = jsvVarPrintf("https://puck-js.com/go?a=%v", addr); jsvUnLock(addr); jswrap_nrf_nfcURL(uri); jsvUnLock(uri); +#endif #endif } else { #ifdef USE_NFC @@ -288,7 +296,7 @@ Called when a host device disconnects from Espruino. "type" : "event", "class" : "NRF", "name" : "servicesDiscover", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Called with discovered services when discovery is finished */ @@ -296,7 +304,7 @@ Called with discovered services when discovery is finished "type" : "event", "class" : "NRF", "name" : "characteristicsDiscover", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Called with discovered characteristics when discovery is finished */ @@ -644,9 +652,12 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) { err_code = sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *)namePtr, nameLen); -#else - err_code = 0xDEAD; - jsiConsolePrintf("FIXME\n"); +//#else +// err_code = 0xDEAD; +// jsiConsolePrintf("FIXME\n"); +#endif +#ifdef ESP32 + bluetooth_setDeviceName(v); #endif jsble_check_error(err_code); bleChanged = true; @@ -728,9 +739,12 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) { jsble_advertising_stop(); #ifdef NRF5X err_code = sd_ble_gap_adv_data_set((uint8_t *)dPtr, dLen, NULL, 0); -#else - err_code = 0xDEAD; - jsiConsolePrintf("FIXME\n"); +//#else +// err_code = 0xDEAD; +// jsiConsolePrintf("FIXME\n"); +#endif +#ifdef ESP32 + err_code = bluetooth_gap_setAdvertizing(advArray); #endif jsvUnLock(initialArray); jsble_check_error(err_code); @@ -754,6 +768,11 @@ the data, it returns the packet that would be advertised as an array. */ JsVar *jswrap_nrf_bluetooth_getAdvertisingData(JsVar *data, JsVar *options) { uint32_t err_code; +#ifdef ESP32 + JsVar *r; + r = bluetooth_gap_getAdvertisingData(data,options); + return r; +#endif #ifdef NRF5X ble_advdata_t advdata; jsble_setup_advdata(&advdata); @@ -1922,7 +1941,7 @@ void jswrap_nrf_sendHIDReport(JsVar *data, JsVar *callback) { "type" : "staticmethod", "class" : "NRF", "name" : "requestDevice", - "ifdef" : "NRF52", + "ifdef" : "NRF52,ESP32", "generate" : "jswrap_nrf_bluetooth_requestDevice", "params" : [ ["options","JsVar","Options used to filter the device to use"] @@ -2110,7 +2129,7 @@ JsVar *jswrap_nrf_bluetooth_requestDevice(JsVar *options) { "type" : "staticmethod", "class" : "NRF", "name" : "connect", - "ifdef" : "NRF52", + "ifdef" : "NRF52,ESP32", "generate" : "jswrap_nrf_bluetooth_connect", "params" : [ ["mac","JsVar","The MAC address to connect to"] @@ -2213,7 +2232,7 @@ NRF.requestDevice({ filters: [{ name: 'Puck.js abcd' }] }).then(function(device) "type" : "property", "class" : "BluetoothDevice", "name" : "gatt", - "ifdef" : "NRF52", + "ifdef" : "NRF52,ESP32", "generate" : "jswrap_BluetoothDevice_gatt", "return" : ["JsVar", "A `BluetoothRemoteGATTServer` for this device" ] } @@ -2238,7 +2257,7 @@ JsVar *jswrap_BluetoothDevice_gatt(JsVar *parent) { "type" : "method", "class" : "BluetoothRemoteGATTServer", "name" : "connect", - "ifdef" : "NRF52", + "ifdef" : "NRF52,ESP32", "generate" : "jswrap_nrf_BluetoothRemoteGATTServer_connect", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the connection is complete" ] } @@ -2292,7 +2311,7 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTServer_connect(JsVar *parent) { /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTServer", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Web Bluetooth-style GATT server - get this using `NRF.connect(address)` or `NRF.requestDevice(options)` and `response.gatt.connect` @@ -2304,7 +2323,7 @@ or `NRF.requestDevice(options)` and `response.gatt.connect` "class" : "BluetoothRemoteGATTServer", "name" : "disconnect", "generate" : "jswrap_BluetoothRemoteGATTServer_disconnect", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Disconnect from a previously connected BLE device connected with `NRF.connect` - this does not disconnect from something that has @@ -2320,7 +2339,12 @@ void jswrap_BluetoothRemoteGATTServer_disconnect(JsVar *parent) { jsble_check_error(err_code); } else { // no connection - try and cancel the connect attempt (assume we have one) +#ifdef NRF52 err_code = sd_ble_gap_connect_cancel(); +#endif +#ifdef ESP32 + jsWarn("connect cancel not implemented yet\n"); +#endif // maybe we don't, in which case we don't care about the error code } #else @@ -2420,7 +2444,7 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTServer_getSecurityStatus(JsVar *parent) { "generate" : "jswrap_BluetoothRemoteGATTServer_getPrimaryService", "params" : [ ["service","JsVar","The service UUID"] ], "return" : ["JsVar", "A Promise that is resolved (or rejected) when the primary service is found (the argument contains a `BluetoothRemoteGATTService`)" ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } See `NRF.connect` for usage examples. */ @@ -2452,7 +2476,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryService(JsVar *parent, JsVar * "name" : "getPrimaryServices", "generate" : "jswrap_BluetoothRemoteGATTServer_getPrimaryServices", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the primary services are found (the argument contains an array of `BluetoothRemoteGATTService`)" ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } */ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) { @@ -2479,7 +2503,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) { "params" : [ ["callback","JsVar","The callback to call with the RSSI value, or undefined to stop"] ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Start/stop listening for RSSI values on the active GATT connection @@ -2513,7 +2537,7 @@ void jswrap_BluetoothRemoteGATTServer_setRSSIHandler(JsVar *parent, JsVar *callb /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTService", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.getPrimaryService(s)` @@ -2526,7 +2550,7 @@ Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.get "generate" : "jswrap_BluetoothRemoteGATTService_getCharacteristic", "params" : [ ["characteristic","JsVar","The characteristic UUID"] ], "return" : ["JsVar", "A Promise that is resolved (or rejected) when the characteristic is found (the argument contains a `BluetoothRemoteGATTCharacteristic`)" ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } See `NRF.connect` for usage examples. */ @@ -2558,7 +2582,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristic(JsVar *parent, JsVar "name" : "getCharacteristics", "generate" : "jswrap_BluetoothRemoteGATTService_getCharacteristics", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the characteristic is found (the argument contains an array of `BluetoothRemoteGATTCharacteristic`)" ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } */ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) { @@ -2581,7 +2605,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) { /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTCharacteristic", - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } Web Bluetooth-style GATT characteristic - get this using `BluetoothRemoteGATTService.getCharacteristic(s)` @@ -2639,11 +2663,10 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_writeValue(JsVar *characteri "name" : "readValue", "generate" : "jswrap_nrf_BluetoothRemoteGATTCharacteristic_readValue", "return" : ["JsVar", "A Promise that is resolved (or rejected) with a `DataView` when the characteristic is read" ], - "ifdef" : "NRF52" + "ifdef" : "NRF52,ESP32" } -Read a characteristic's value, return a promise containing a `DataView` with the data in it - +Read a characteristic's value, return a promise containing a `DataView` ``` var device; diff --git a/libs/bluetooth/jswrap_bluetooth.h b/libs/bluetooth/jswrap_bluetooth.h index de1e98132..b96a6e39f 100644 --- a/libs/bluetooth/jswrap_bluetooth.h +++ b/libs/bluetooth/jswrap_bluetooth.h @@ -33,6 +33,7 @@ typedef enum { #define BLETASK_IS_CENTRAL(x) ((x)>=BLETASK_CENTRAL_START && ((x)<=BLETASK_CENTRAL_END)) extern JsVar *bleTaskInfo; // info related to the current task +extern JsVar *blePromise; //defined here, used in jswrap_bluetooth.c and in ESP32 relevant bluetooth bool bleInTask(BleTask task); BleTask bleGetCurrentTask(); bool bleNewTask(BleTask task, JsVar *taskInfo); diff --git a/make/family/ESP32.make b/make/family/ESP32.make index e45d3f169..b794af717 100755 --- a/make/family/ESP32.make +++ b/make/family/ESP32.make @@ -121,3 +121,23 @@ $(ESP_IDF_PATH)/components/esp32/libhal.a \ -lapp_update \ -lstdc++ \ -lgcc + +#needed for using ifdef in wrapper JSON +DEFINES += -DESP32 + +ifdef USE_BLUETOOTH +SOURCES+= targets/esp32/bluetooth.c \ +targets/esp32/BLE/esp32_bluetooth_utils.c \ +targets/esp32/BLE/esp32_gap_func.c \ +targets/esp32/BLE/esp32_gatts_func.c \ +targets/esp32/BLE/esp32_gattc_func.c +INCLUDE+= -I$(ESP_IDF_PATH)/components/bt/bluedroid/include \ +-I$(ESP_IDF_PATH)/components/bt/bluedroid/api/include \ +-I$(ESP_IDF_PATH)/components/bt/bluedroid/bta/include \ +-I$(ESP_IDF_PATH)/components/bt/bluedroid/stack/include \ +-I$(ESP_IDF_PATH)/components/bt/bluedroid/stack/gatt/include \ +-I$(ESP_IDF_PATH)/components/bt/bluedroid/osi/include +LDFLAGS+= -L$(ESP_APP_TEMPLATE_PATH)/build/components/bt/bluedroid/api \ +-L$(ESP_APP_TEMPLATE_PATH)/build/components/bt/bluedroid/bta +endif + diff --git a/scripts/common.py b/scripts/common.py index 0b5658194..56ab20567 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -176,15 +176,14 @@ def get_jsondata(is_for_document, parseArgs = True, board = False): if ("ifndef" in jsondata) and (jsondata["ifndef"] in defines): print(dropped_prefix+" because of #ifndef "+jsondata["ifndef"]) drop = True - if ("ifdef" in jsondata) and not (jsondata["ifdef"] in defines): - print(dropped_prefix+" because of #ifdef "+jsondata["ifdef"]) - drop = True + if ("ifdef" in jsondata): + ifdefs = jsondata["ifdef"].encode('ascii','ignore').split(",") + if(not [val for val in defines if val in ifdefs]): + print(dropped_prefix+" because of #ifdef "+jsondata["ifdef"]) + drop = True if ("#ifdef" in jsondata) or ("#ifndef" in jsondata): sys.stderr.write( "'#ifdef' where 'ifdef' should be used in " + jsonstring + " - "+str(sys.exc_info()[0]) + "\n" ) exit(1) - if ("if" in jsondata): - sys.stderr.write( "'if' where '#if' should be used in " + jsonstring + " - "+str(sys.exc_info()[0]) + "\n" ) - exit(1) if ("#if" in jsondata): expr = jsondata["#if"] for defn in defines: @@ -371,8 +370,7 @@ def get_ifdef_description(d): if d=="SAVE_ON_FLASH_EXTREME": return "devices with extremely low flash memory (eg. HYSTM32_28)" if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)" if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)" - if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js and MDBT42Q)" - if d=="PIXLJS": return "Pixl.js boards" + if d=="NRF52": return "NRF52 devices (like Puck.js and Pixl.js)" if d=="ESPRUINOWIFI": return "Espruino WiFi boards" if d=="ESP8266": return "ESP8266 devices running Espruino" if d=="ESP32": return "ESP32 devices" @@ -380,15 +378,12 @@ def get_ifdef_description(d): if d=="USE_LCD_SDL": return "Linux with SDL support compiled in" if d=="USE_TLS": return "devices with TLS and SSL support (Espruino Pico and Espruino WiFi only)" if d=="RELEASE": return "release builds" - if d=="DEBUG": return "debug builds" if d=="LINUX": return "Linux-based builds" if d=="BLUETOOTH": return "devices with Bluetooth LE capability" if d=="USB": return "devices with USB" if d=="USE_USB_HID": return "devices that support USB HID (Espruino Pico and Espruino WiFi)" if d=="USE_AES": return "devices that support AES (Espruino Pico, Espruino WiFi or Linux)" - if d=="USE_SHA256": return "devices that support SHA256 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux)" - if d=="USE_SHA512": return "devices that support SHA512 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux)" - if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Original, Espruino WiFi, Espruino BLE devices, Linux or ESP8266)" + if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Espruino WiFi, Linux or ESP8266)" if d=="USE_FLASHFS": return "devices with filesystem in Flash support enabled (ESP32 only)" if d=="USE_TERMINAL": return "devices with VT100 terminal emulation enabled (Pixl.js only)" print("WARNING: Unknown ifdef '"+d+"' in common.get_ifdef_description") diff --git a/scripts/esp32/flash-blank-js.bat b/scripts/esp32/flash-blank-js.bat index 122288bde..1b74409f7 100644 --- a/scripts/esp32/flash-blank-js.bat +++ b/scripts/esp32/flash-blank-js.bat @@ -1,4 +1,5 @@ -..\..\..\esp-idf\components\esptool_py\esptool\esptool.py --chip esp32 --port COM3 --baud 921600 --before esp32r0 --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x100000 blank.bin +REM ..\..\..\esp-idf\components\esptool_py\esptool\esptool.py --chip esp32 --port COM3 --baud 921600 --after soft_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x100000 blank.bin +..\..\..\esp-idf\components\esptool_py\esptool\esptool.py --chip esp32 --port COM3 --baud 921600 erase_region 0x100000 0x10000 if %ERRORLEVEL% NEQ 0 ( pause ) diff --git a/scripts/esp32/flash-erase.bat b/scripts/esp32/flash-erase.bat index 97353549f..4892ee23d 100644 --- a/scripts/esp32/flash-erase.bat +++ b/scripts/esp32/flash-erase.bat @@ -1,4 +1,4 @@ -..\..\..\esp-idf\components\esptool_py\esptool\esptool.py --chip esp32 --baud 921600 --before esp32r0 --after hard_reset --port COM3 --baud 921600 erase_flash +..\..\..\esp-idf\components\esptool_py\esptool\esptool.py --chip esp32 --baud 921600 --after hard_reset --port COM3 --baud 921600 erase_flash if %ERRORLEVEL% NEQ 0 ( pause ) diff --git a/targets/esp32/BLE/esp32_bluetooth_utils.c b/targets/esp32/BLE/esp32_bluetooth_utils.c new file mode 100644 index 000000000..3cd5b1fd7 --- /dev/null +++ b/targets/esp32/BLE/esp32_bluetooth_utils.c @@ -0,0 +1,292 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific Bluetooth utils + * ---------------------------------------------------------------------------- + */ + + +#include "BLE/esp32_bluetooth_utils.h" +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_gatts_func.h" +#include "BLE/esp32_gattc_func.h" +#include "bt.h" +#include "esp_bt_main.h" +#include "esp_gatt_common_api.h" +#include "freertos/FreeRTOS.h" +#include "jsvariterator.h" + +int bleEventDebug = 0; + +typedef enum{ + ESP_BLE_DEBUG_GAP = 1, + ESP_BLE_DEBUG_GATTS = 2, + ESP_BLE_DEBUG_GATTC = 4 +} esp_ble_debug_t; + +esp_err_t initController(){ + esp_err_t ret; + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + ret = esp_bt_controller_init(&bt_cfg);if(ret) {jsWarn("init controller failed:%x\n",ret); return ret;} + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);if(ret) {jsWarn("enable controller failed:%x\n",ret); return ret;} + return ret; +} +esp_err_t initBluedroid(){ + esp_err_t ret; + ret = esp_bluedroid_init();if (ret) {jsWarn("init bluedroid failed:%x\n",ret);return ret;} + ret = esp_bluedroid_enable();if (ret) {jsWarn("enable bluedroid failed:%x\n",ret);return ret;} + return ret; +} +esp_err_t deinitController(){ + esp_err_t ret; + ret = esp_bt_controller_disable(); if (ret) {jsWarn("disable bluetooth failed:%x\n"); return ret;} + ret = esp_bt_controller_deinit(); if (ret) {jsWarn("deinit bluetooth failed:%x\n"); return ret;} + return ret; +} +esp_err_t deinitBluedroid(){ + esp_err_t ret; + ret = esp_bluedroid_disable();if (ret) {jsWarn("disable bluedroid failed:%x\n",ret);return ret;} + ret = esp_bluedroid_deinit();if (ret) {jsWarn("deinit bluedroid failed:%x\n",ret);return ret;} + return ret; +} +esp_err_t registerCallbacks(){ + esp_err_t ret; + ret = esp_ble_gap_register_callback(gap_event_handler);if (ret){jsWarn("gap register error:%x\n", ret);return ret;} + ret = esp_ble_gatts_register_callback(gatts_event_handler);if(ret){jsWarn("gatts register error:%x\n", ret);return ret;} + ret = esp_ble_gattc_register_callback(gattc_event_handler);if(ret){jsWarn("gattc regigister error:%x\n",ret);return ret;} + return ret; +} +esp_err_t setMtu(){ + esp_err_t ret; + ret = esp_ble_gatt_set_local_mtu(500);if(ret)jsWarn("set local MTU failed:%x\n",ret); + return ret; +} + +JsVar *bda2JsVarString(esp_bd_addr_t bda){ + JsVar *s = jsvVarPrintf("%02x:%02x:%02x:%02x:%02x:%02x",bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]); + return s; +} + +void ESP32_setBLE_Debug(int level){ + bleEventDebug = level; +} +static char *gattsEvent2String(esp_gatts_cb_event_t event){ + switch(event){ + case 0: return "REG"; + case 1: return "READ"; + case 2: return "WRITE"; + case 3: return "EXEC_WRITE"; + case 4: return "MTU"; + case 5: return "CONF"; + case 6: return "UNREG"; + case 7: return "CREATE"; + case 8: return "ADD_INCL_SRVC"; + case 9: return "ADD_CHAR"; + case 10: return "ADD_CHAR_DESCR"; + case 11: return "DELETE"; + case 12: return "START"; + case 13: return "STOP"; + case 14: return "CONNECT"; + case 15: return "DISCONNECT"; + case 16: return "OPEN"; + case 17: return "CANCEL_OPEN"; + case 18: return "CLOSE"; + case 19: return "LISTEN"; + case 20: return "CONGEST"; + case 21: return "RESPONSE"; + case 22: return "CREAT_ATTR_TAB"; + case 23: return "CREAT_ATTR_TAB"; + } + return "unknown GattsEvent"; +} +static char *gattcEvent2String(esp_gattc_cb_event_t event){ + switch(event){ + case 0: return "REG"; + case 1: return "UNREG"; + case 2: return "OPEN"; + case 3: return "READ_CHAR"; + case 4: return "WRITE_CHAR"; + case 5: return "CLOSE"; + case 6: return "SEARCH_CMPL"; + case 7: return "SEARCH_RES"; + case 8: return "READ_DESCR"; + case 9: return "WRITE_DESCR"; + case 10: return "NOTIFY"; + case 11: return "PREP_WRITE"; + case 12: return "EXEC"; + case 13: return "ACL"; + case 14: return "CANCEL_OPEN"; + case 15: return "SRVC_CHG"; + case 17: return "ENC_CMPL_CB"; + case 18: return "CFG_MTU"; + case 19: return "ADV_DATA"; + case 20: return "MULT_ADV_ENB"; + case 21: return "ADV_ADV_UPD"; + case 22: return "MULT_ADV_DATA"; + case 23: return "MULT_ADV_DIS"; + case 24: return "CONGEST"; + case 25: return "BTH_SCAN_ENB"; + case 26: return "BTH_SCAN_CFG"; + case 27: return "BTH_SCAN_RD"; + case 28: return "BTH_SCAN_THR"; + case 29: return "BTH_SCAN_PARAM"; + case 30: return "BTH_SCAN_DIS"; + case 31: return "SCAN_FLT_CFG"; + case 32: return "SCAN_FLT_PARAM"; + case 33: return "SCAN_FLT_STATUS"; + case 34: return "ADV_VSC"; + case 38: return "REG_FOR_NOTIFY"; + case 39: return "UNREG_FOR_NOTIFY"; + case 40: return "CONNECT"; + case 41: return "DISCONNECT"; + case 42: return "READ_MUTIPLE"; + case 43: return "QUEUE_FULL"; + } + return "unknown GattcEvent"; +} +static char *gapEvent2String(esp_gap_ble_cb_event_t event){ + switch(event){ + case 0: return "ADV_DATA_SET_COMPLETE"; + case 1: return "SCAN_RSP_DATA_SET_COMPLETE"; + case 2: return "SCAN_PARAM_SET_COMPLETE"; + case 3: return "SCAN_RESULT"; + case 4: return "ADV_DATA_RAW_SET_COMPLETE"; + case 5: return "SCAN_RSP_DATA_RAW_SET_COMPLETE"; + case 6: return "ADV_START_COMPLETE"; + case 7: return "SCAN_START_COMPLETE"; + case 8: return "AUTH_CMPL"; + case 9: return "KEY"; + case 10: return "SEC_REQ"; + case 11: return "PASSKEY_NOTIF"; + case 12: return "PASSKEY_REQ"; + case 13: return "OOB_REQ"; + case 14: return "LOCAL_IR"; + case 15: return "LOCAL_ER"; + case 16: return "NC_REQ"; + case 17: return "ADV_STOP_COMPLETE"; + case 18: return "SCAN_STOP_COMPLETE"; + case 19: return "SET_STATIC_RAND_ADDR"; + case 20: return "UPDATE_CONN_PARAMS"; + case 21: return "SET_PKT_LENGTH_COMPLETE"; + case 22: return "SET_LOCAL_PRIVACY_COMPLETE"; + case 23: return "REMOVE_BOND_DEV_COMPLETE"; + case 24: return "CLEAR_BOND_DEV_COMPLETE"; + case 25: return "GET_BOND_DEV_COMPLETE_EVT"; + case 26: return "READ_RSSI_COMPLETE"; + case 27: return "UPDATE_WHITELIST_COMPLETE"; + } + return "unknown GapEvent"; +} + +void jsWarnGattsEvent(esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if){ + if(bleEventDebug & ESP_BLE_DEBUG_GATTS) + jsWarn("Event:ESP_GATTS_%s_EVT gatts_if:%d\n",gattsEvent2String(event), gatts_if); +} +void jsWarnGattcEvent(esp_gattc_cb_event_t event,esp_gatt_if_t gattc_if){ + if(bleEventDebug & ESP_BLE_DEBUG_GATTC) + jsWarn("Event:ESP_GATTC_%s_EVT gattc_if:%d\n",gattcEvent2String(event), gattc_if); +} +void jsWarnGapEvent(esp_gap_ble_cb_event_t event){ + if(bleEventDebug & ESP_BLE_DEBUG_GAP) + jsWarn("Event:ESP_GAP_BLE_%s_EVT\n",gapEvent2String(event)); +} + +void jsWarnUUID(esp_bt_uuid_t char_uuid){ + if (char_uuid.len == ESP_UUID_LEN_16) { + jsWarn("- - - Char UUID16: %x", char_uuid.uuid.uuid16); + } else if (char_uuid.len == ESP_UUID_LEN_32) { + jsWarn("- - - Char UUID32: %x", char_uuid.uuid.uuid32); + } else if (char_uuid.len == ESP_UUID_LEN_128) { + jsWarn("- - - Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_uuid.uuid.uuid128[0], + char_uuid.uuid.uuid128[1], char_uuid.uuid.uuid128[2], char_uuid.uuid.uuid128[3], + char_uuid.uuid.uuid128[4], char_uuid.uuid.uuid128[5], char_uuid.uuid.uuid128[6], + char_uuid.uuid.uuid128[7], char_uuid.uuid.uuid128[8], char_uuid.uuid.uuid128[9], + char_uuid.uuid.uuid128[10], char_uuid.uuid.uuid128[11], char_uuid.uuid.uuid128[12], + char_uuid.uuid.uuid128[13], char_uuid.uuid.uuid128[14], char_uuid.uuid.uuid128[15]); + } else { + jsWarn("- - - Char UNKNOWN LEN %d\n", char_uuid.len); + } +} +void jsWarnBDA(uint8_t *bda){ + jsWarn("bda %02x:%02x:%02x:%02x:%02x:%02x\n",bda[0],bda[1],bda[2],bda[3],bda[4],bda[5]); +} +void jsWarnHeap(char * whereAmI){ + jsWarn("%s Heap:%d, jsVars:%d\n",whereAmI,esp_get_free_heap_size(),jsvGetMemoryUsage()); +} + +void bleGetHiddenName(char *eventName, char *hiddenName, uint16_t pos){ + strcpy(eventName,hiddenName); + itostr(pos,&eventName[strlen(eventName)],16); +} +bool bleRemoveChild(JsVar *parent, JsVar *blevar){ + bool ret = false; + JsvObjectIterator it; + jsvObjectIteratorNew(&it, parent); + while (jsvObjectIteratorHasValue(&it)) { + JsVar *child = jsvObjectIteratorGetKey(&it); + JsVar *name = jsvNewFromStringVar(child, 0, 10); + if(jsvIsEqual(name,blevar)){ + jsvRemoveChild(parent,child); + ret = true; + } + jsvUnLock(child); + jsvUnLock(name); + jsvObjectIteratorNext(&it); + } + jsvObjectIteratorFree(&it); + return ret; +} +void bleRemoveChilds(JsVar *parent){ + JsVar *blevar = jsvNewFromString(BLE_CHAR_VALUE); + while(bleRemoveChild(parent,blevar)){} + jsvUnLock(blevar); +} + +void bleuuid_TO_espbtuuid(ble_uuid_t ble_uuid,esp_bt_uuid_t *esp_uuid){ + switch(ble_uuid.type){ + case BLE_UUID_TYPE_UNKNOWN: + jsError("empty UUID type\n"); + break; + case BLE_UUID_TYPE_BLE: + esp_uuid->len = ESP_UUID_LEN_16; + esp_uuid->uuid.uuid16 = ble_uuid.uuid; + break; + case BLE_UUID_TYPE_128: + esp_uuid->len = ESP_UUID_LEN_128; + for(int i = 0; i < 16; i++){ + esp_uuid->uuid.uuid128[i] = ble_uuid.uuid128[i]; + } + break; + default: + jsError("unknown UUID TYPE\n"); + } +} +void bleuuid_To_uuid128(ble_uuid_t ble_uuid,uint8_t *ble128){ + uint8_t tmp[] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00}; + switch (ble_uuid.type){ + case BLE_UUID_TYPE_UNKNOWN: + jsError("empty UUID type\n"); + break; + case BLE_UUID_TYPE_BLE: + for(int i = 0; i < 16; i++){ + ble128[i] = tmp[i]; + } + ble128[12] = ble_uuid.uuid & 0xff; + ble128[13] = ble_uuid.uuid >> 8; + break; + case BLE_UUID_TYPE_128: + for(int i = 0; i < 16; i++){ + ble128[i] = ble_uuid.uuid128[i]; + } + break; + default: + jsError("unknown UUID type\n"); + } +} diff --git a/targets/esp32/BLE/esp32_bluetooth_utils.h b/targets/esp32/BLE/esp32_bluetooth_utils.h new file mode 100644 index 000000000..6bf515cb1 --- /dev/null +++ b/targets/esp32/BLE/esp32_bluetooth_utils.h @@ -0,0 +1,57 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific Bluetooth utils + * ---------------------------------------------------------------------------- + */ +#ifndef ESP32_BLUETOOTH_UTILS_H_ +#define ESP32_BLUETOOTH_UTILS_H_ + +#include "jsvar.h" + +#include "esp_bt_defs.h" +#include "esp_gatts_api.h" +#include "esp_gattc_api.h" +#include "esp_gap_ble_api.h" + +#include "bluetooth.h" + +#define BLE_WRITE_EVENT JS_EVENT_PREFIX"blewv" +#define BLE_READ_EVENT JS_EVENT_PREFIX"blerv" +#define BLE_CONNECT_EVENT JS_EVENT_PREFIX"connect" +#define BLE_DISCONNECT_EVENT JS_EVENT_PREFIX"disconnect" + +#define BLE_CHAR_VALUE "BLE_CHAR_V" + +esp_err_t initController(); +esp_err_t initBluedroid(); +esp_err_t deinitController(); +esp_err_t deinitBluedroid(); +esp_err_t registerCallbacks(); +esp_err_t setMtu(); + +JsVar *bda2JsVarString(uint8_t *ble_adv); + +void ESP32_setBLE_Debug(int level); +void jsWarnGattsEvent(esp_gatts_cb_event_t event,esp_gatt_if_t gatts_if); +void jsWarnGattcEvent(esp_gattc_cb_event_t event,esp_gatt_if_t gatts_if); +void jsWarnGapEvent(esp_gap_ble_cb_event_t event); + +void jsWarnBDA(uint8_t *bda); +void jsWarnUUID(esp_bt_uuid_t char_uuid); +void jsWarnHeap(char * whereAmI); + +void bleGetHiddenName(char *eventName, char *hiddenName, uint16_t pos); +void bleRemoveChilds(JsVar *parent); + +void bleuuid_TO_espbtuuid(ble_uuid_t ble_uuid,esp_bt_uuid_t *esp_uuid); +void bleuuid_To_uuid128(ble_uuid_t ble_uuid,uint8_t *ble128); + +#endif /* ESP32_BLUETOOTH_UTILS_H_ */ diff --git a/targets/esp32/BLE/esp32_gap_func.c b/targets/esp32/BLE/esp32_gap_func.c new file mode 100644 index 000000000..ac2a16106 --- /dev/null +++ b/targets/esp32/BLE/esp32_gap_func.c @@ -0,0 +1,279 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GAP functions + * ---------------------------------------------------------------------------- + */ + +#include + +#include "esp_wifi.h" +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_gatts_func.h" +#include "BLE/esp32_bluetooth_utils.h" + +#include "jsutils.h" +#include "jsparse.h" +#include "jsinteractive.h" +#include "jshardware.h" +#include "bluetooth_utils.h" + +#define adv_config_flag (1 << 0) +#define scan_rsp_config_flag (1 << 1) +#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] +#define GAP_SCAN_FUNC "gap_scan_func" + +static uint8_t adv_config_done = 0; + +static esp_ble_adv_params_t adv_params = { + .adv_int_min = 0x20, + .adv_int_max = 0x40, + .adv_type = ADV_TYPE_IND, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + //.peer_addr = + //.peer_addr_type = + .channel_map = ADV_CHNL_ALL, + .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, +}; + +static esp_ble_scan_params_t ble_scan_params = { + .scan_type = BLE_SCAN_TYPE_ACTIVE, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + .scan_interval = 0x50, + .scan_window = 0x30 +}; + +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[0], + .service_data_len = 0, + .p_service_data = NULL, + .service_uuid_len = 0, //needs to be set before used + .p_service_uuid = &adv_service_uuid128, + .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), +}; + +static void execScanFunc(esp_ble_gap_cb_param_t *p){ + JsVar *evt = jsvNewObject(); + jsvObjectSetChildAndUnLock(evt, "id", bda2JsVarString(p->scan_rst.bda)); + jsvObjectSetChildAndUnLock(evt, "rssi",jsvNewFromInteger(p->scan_rst.rssi)); + JsVar *data = jsvNewStringOfLength(p->scan_rst.adv_data_len, (char*)p->scan_rst.ble_adv); + if(data){ + JsVar *ab = jsvNewArrayBufferFromString(data,p->scan_rst.adv_data_len); + jsvUnLock(data); + jsvObjectSetChildAndUnLock(evt,"data",ab); + } + jsiQueueObjectCallbacks(execInfo.root, BLE_SCAN_EVENT, &evt,1); + jsvUnLock(evt); + jshHadEvent(); +} + +void gap_event_scan_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){ + uint8_t *adv_name = NULL; + uint8_t adv_name_len = 0; + esp_ble_gap_cb_param_t *p = (esp_ble_gap_cb_param_t *)param; + switch(event){ + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { + break; + } + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:{ + if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {jsWarn("Scan start failed:d\n",param->scan_start_cmpl.status);} + break; + } + case ESP_GAP_BLE_SCAN_RESULT_EVT:{ + execScanFunc(param); + break; + } + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:{ + if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){jsWarn("Scan stop failed");} + else {jsWarn("Stop scan successfully");} + break; + } + default: break; + } +} + +void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param){ + jsWarnGapEvent(event); + switch (event) { + 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; + } + case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:{ + if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { + jsWarn("Advertising start failed\n"); + } + break; + } + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:{ + if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) { + jsWarn("Advertising stop failed\n"); + } + else { + jsWarn("Stop adv successfully\n"); + } + break; + } + case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:{ + jsWarn("update connetion params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d", + param->update_conn_params.status, + param->update_conn_params.min_int, + param->update_conn_params.max_int, + param->update_conn_params.conn_int, + param->update_conn_params.latency, + param->update_conn_params.timeout); + break; + } + default:{ + gap_event_scan_handler(event,param); + break; + } + } +} + +void bluetooth_gap_setScan(bool enable){ +jsWarn("--- gap_setScan %x\n",enable); + esp_err_t status; + status = esp_ble_gap_set_scan_params(&ble_scan_params); + if (status){ jsWarn("gap set scan error code = %x", status);return;} + if(enable == true){ + status = esp_ble_gap_start_scanning(30); + if (status != ESP_OK) jsWarn("esp_ble_gap_start_scanning: rc=%d", status); + } + else{ + status = esp_ble_gap_stop_scanning(); + } +} + +esp_err_t bluetooth_gap_startAdvertizing(bool enable){ + if(enable){ + return esp_ble_gap_start_advertising(&adv_params); + } + else{ + return esp_ble_gap_stop_advertising(); + } +} + +int addAdvertisingData(uint8_t *advData,int pnt,int idx,JsVar *value){ + int len = 0; + JSV_GET_AS_CHAR_ARRAY(dPtr,dLen,value); + len = 4 + dLen; + advData[pnt++] = 3 + dLen; + advData[pnt++] = 22; + advData[pnt++] = idx & 255; + advData[pnt++] = idx >> 8; + for(int i = 0; i < dLen; i++){ advData[pnt++] = dPtr[i];} + return len; +} + +int addAdvertisingDeviceName(uint8_t *advData,int pnt){ + JsVar *deviceName; + deviceName = jsvObjectGetChild(execInfo.hiddenRoot, BLE_DEVICE_NAME, 0); + JSV_GET_AS_CHAR_ARRAY(namePtr, nameLen, deviceName); + if(nameLen > 0){ + if((nameLen + pnt + 2) > BLE_GAP_ADV_MAX_SIZE){ + nameLen = BLE_GAP_ADV_MAX_SIZE - 2 - pnt; + advData[pnt] = nameLen + 1; + advData[pnt + 1] = 8; + } + else{ + advData[pnt] = nameLen + 1; + advData[pnt + 1] = 9; + } + for(int i = 0; i < nameLen; i++) advData[pnt + i + 2] = namePtr[i]; + } + jsvUnLock(deviceName); + return nameLen + 2; +} + +JsVar *bluetooth_gap_getAdvertisingData(JsVar *data, JsVar *options){ + uint8_t encoded_advdata[BLE_GAP_ADV_MAX_SIZE]; + int i = 0; + if(jsvIsArray(data) || jsvIsArrayBuffer(data)){ + return jsvLockAgain(data); + } else if(jsvIsObject(data)){ + encoded_advdata[i++] = 2; + encoded_advdata[i++] = 1; + encoded_advdata[i++] = 6; //todo add support of showName == false + JsvObjectIterator it; + jsvObjectIteratorNew(&it, data); + while(jsvObjectIteratorHasValue(&it)){ + JsVar *value = jsvObjectIteratorGetValue(&it); + int idx = jsvGetIntegerAndUnLock(jsvObjectIteratorGetKey(&it)); + i = i + addAdvertisingData(&encoded_advdata,i,idx,value); + jsvUnLock(value); + jsvObjectIteratorNext(&it); + } + jsvObjectIteratorFree(&it); + //todo add support of manufacturerData + i = i + addAdvertisingDeviceName(&encoded_advdata,i); + } + else if (!jsvIsUndefined(data)){ + jsExceptionHere(JSET_TYPEERROR, "Expecting object array or undefined, got %t",data); + return 0; + } + return jsvNewArrayBufferWithData(i,encoded_advdata); +} + +esp_err_t bluetooth_gap_setAdvertizing(JsVar *advArray){ + esp_err_t ret; + if(!advArray){ + adv_data.service_uuid_len = ble_service_cnt * 16; + ret = esp_ble_gap_config_adv_data(&adv_data); + } + else{ + JSV_GET_AS_CHAR_ARRAY(advPtr, advLen, advArray); + ret = esp_ble_gap_config_adv_data_raw(advPtr, advLen); + } + if (ret){ + jsWarn("config adv data failed, error code = %x", ret); + } + return ret; +} + +esp_err_t bluetooth_setDeviceName(JsVar *deviceName){ + esp_err_t r; + jsvObjectSetOrRemoveChild(execInfo.hiddenRoot, BLE_DEVICE_NAME, deviceName); + JSV_GET_AS_CHAR_ARRAY(namePtr, nameLen, deviceName); + r = esp_ble_gap_set_device_name((uint8_t *)namePtr); + return r; +} + +void bluetooth_initDeviceName(){ + char deviceName[14]; + strcpy(deviceName,"ESP32.js 0123"); + uint8_t macnr[6]; + esp_wifi_get_mac(WIFI_IF_STA, macnr); + deviceName[9] = itoch((macnr[4]>>4)&15); + deviceName[10] = itoch(macnr[4]&15); + deviceName[11] = itoch((macnr[5]>>4)&15); + deviceName[12] = itoch(macnr[5]&15); + deviceName[13] = '\0'; + jsvObjectSetChild(execInfo.hiddenRoot, BLE_DEVICE_NAME,jsvNewFromString(deviceName)); +} + diff --git a/targets/esp32/BLE/esp32_gap_func.h b/targets/esp32/BLE/esp32_gap_func.h new file mode 100644 index 000000000..d09f05a77 --- /dev/null +++ b/targets/esp32/BLE/esp32_gap_func.h @@ -0,0 +1,36 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GAP functions + * ---------------------------------------------------------------------------- + */ +#ifndef GAP_FUNC_H_ +#define GAP_FUNC_H_ + +#include "esp_gap_ble_api.h" + +#include "jsvar.h" + +#define BLE_DEVICE_NAME "BLE_DEV_N" + +void bluetooth_gap_setScan(bool enabled); + +//esp_err_t bluetooth_setDeviceName(uint8_t *deviceName); +esp_err_t bluetooth_setDeviceName(JsVar *deviceName); +void bluetooth_initDeviceName(); + +esp_err_t bluetooth_gap_startAdvertizing(bool enable); +esp_err_t bluetooth_gap_setAdvertizing(JsVar *advArray); + +JsVar *bluetooth_gap_getAdvertisingData(JsVar *data, JsVar *options); + +void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param); + +#endif /* GAP_FUNC_H_ */ diff --git a/targets/esp32/BLE/esp32_gattc_func.c b/targets/esp32/BLE/esp32_gattc_func.c new file mode 100644 index 000000000..5240447af --- /dev/null +++ b/targets/esp32/BLE/esp32_gattc_func.c @@ -0,0 +1,247 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GATT client functions + * ---------------------------------------------------------------------------- + */ + +#include +#include "esp_log.h" + +#include "BLE/esp32_gattc_func.h" +#include "BLE/esp32_bluetooth_utils.h" + +#include "bluetooth_utils.h" +#include "jswrap_bluetooth.h" + +#include "jsvar.h" +#include "jsutils.h" +#include "jsparse.h" +#include "jsinteractive.h" + +#define GATTC_PROFILE 0 +#define INVALID_HANDLE 0 + +static struct gattc_profile_inst gattc_apps[1] = { + [GATTC_PROFILE] = { + .gattc_cb = gattc_event_handler, + .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + } +}; +static esp_bt_uuid_t serviceFilter = { + .len = ESP_UUID_LEN_16, + .uuid = {.uuid16 = 0,}, +}; +static esp_bt_uuid_t charFilter = { + .len = ESP_UUID_LEN_16, + .uuid = {.uuid16 = 0} +}; +static bool get_server = false; +static esp_gattc_char_elem_t *char_elem_result = NULL; +static esp_gattc_descr_elem_t *descr_elem_result = NULL; + +void gattc_evt_reg(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + gattc_apps[param->reg.app_id].gattc_if = gattc_if; +} +void gattc_evt_connect(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + gattc_apps[GATTC_PROFILE].conn_id = p_data->connect.conn_id; + m_central_conn_handle = 0x01; + memcpy(gattc_apps[GATTC_PROFILE].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t)); + esp_err_t mtu_ret = esp_ble_gattc_send_mtu_req (gattc_if, p_data->connect.conn_id); + if (mtu_ret){jsWarn("config MTU error, error code = %x", mtu_ret);} +} +void gattc_evt_disconnect(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + m_central_conn_handle = BLE_GATT_HANDLE_INVALID; +} +void gattc_evt_cfg_mtu(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + if (!bleTaskInfo) bleTaskInfo = jsvNewEmptyArray(); + jsvObjectSetChildAndUnLock(bleTaskInfo,"connected", jsvNewFromBool(true)); + bleCompleteTaskSuccess(BLETASK_CONNECT, bleTaskInfo); +} +void gattc_evt_search_cmpl(){ + if(get_server){ + if (!bleTaskInfo) bleTaskInfo = jsvNewEmptyArray(); + JsVar *o = jspNewObject(0,"BluetoothRemoteGATTService"); + jsvObjectSetChildAndUnLock(o,"uuid",jsvVarPrintf("0x%04x",serviceFilter.uuid.uuid16)); + jsvObjectSetChildAndUnLock(o,"isPrimary",jsvNewFromBool(true)); + jsvObjectSetChildAndUnLock(o,"start_handle",jsvNewFromInteger(gattc_apps[GATTC_PROFILE].service_start_handle)); + jsvObjectSetChildAndUnLock(o,"end_handle",jsvNewFromInteger(gattc_apps[GATTC_PROFILE].service_end_handle)); + jsvArrayPushAndUnLock(bleTaskInfo,o); + JsVar *t = jsvSkipNameAndUnLock(jsvArrayPopFirst(bleTaskInfo)); + jsvUnLock(bleTaskInfo); + bleTaskInfo = t; + if(bleTaskInfo) bleCompleteTaskSuccess(BLETASK_PRIMARYSERVICE,bleTaskInfo); + else bleCompleteTaskFailAndUnLock(BLETASK_PRIMARYSERVICE,jsvNewFromString("No Services found")); + } +} +void gattc_evt_search_res(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + esp_gatt_srvc_id_t *srvc_id =(esp_gatt_srvc_id_t *)&p_data->search_res.srvc_id; + if (srvc_id->id.uuid.len == ESP_UUID_LEN_16 && srvc_id->id.uuid.uuid.uuid16 == serviceFilter.uuid.uuid16) { + get_server = true; + gattc_apps[GATTC_PROFILE].service_start_handle = p_data->search_res.start_handle; + gattc_apps[GATTC_PROFILE].service_end_handle = p_data->search_res.end_handle; + } +} +void gattc_evt_read_char(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + JsVar *data = jsvNewDataViewWithData(p_data->read.value_len,(unsigned char*)p_data->read.value); + jsvObjectSetChild(bleTaskInfo,"value",data); + bleCompleteTaskSuccessAndUnLock(BLETASK_CHARACTERISTIC_READ,data); +} +void gattc_evt_write_char(esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param){ + bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC_WRITE,0); +} + +void gattc_init(){ + esp_err_t ret; + ret = esp_ble_gattc_app_register(GATTC_PROFILE);if(ret){jsWarn("gattc register app error:%x\n",ret);return;} +} +void gattc_reset(){ + esp_err_t ret; + if(gattc_apps[GATTC_PROFILE].gattc_if != ESP_GATT_IF_NONE){ + ret = esp_ble_gattc_app_unregister(gattc_apps[GATTC_PROFILE].gattc_if); + if(ret) jsWarn("could not unregister GATTC(%d)\n",ret); + } + m_central_conn_handle = BLE_GATT_HANDLE_INVALID; +} + +void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) { + jsWarnGattcEvent(event,gattc_if); + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + JsVar *args[1]; + switch (event) { + case ESP_GATTC_REG_EVT: gattc_evt_reg(gattc_if,param);break; + case ESP_GATTC_CONNECT_EVT: gattc_evt_connect(gattc_if,param);break; + case ESP_GATTC_CFG_MTU_EVT: gattc_evt_cfg_mtu(gattc_if,param);break; + case ESP_GATTC_SEARCH_CMPL_EVT: gattc_evt_search_cmpl(gattc_if,param);break; + case ESP_GATTC_SEARCH_RES_EVT: gattc_evt_search_res(gattc_if,param);break; + case ESP_GATTC_READ_CHAR_EVT: gattc_evt_read_char(gattc_if,param);break; + case ESP_GATTC_WRITE_CHAR_EVT: gattc_evt_write_char(gattc_if,param);break; + + case ESP_GATTC_UNREG_EVT: break; + case ESP_GATTC_OPEN_EVT: break; + case ESP_GATTC_CLOSE_EVT: break; + case ESP_GATTC_READ_DESCR_EVT: break; + case ESP_GATTC_WRITE_DESCR_EVT: break; + case ESP_GATTC_NOTIFY_EVT: break; + case ESP_GATTC_PREP_WRITE_EVT: break; + case ESP_GATTC_EXEC_EVT: break; + case ESP_GATTC_ACL_EVT: break; + case ESP_GATTC_CANCEL_OPEN_EVT: break; + case ESP_GATTC_SRVC_CHG_EVT: break; + case ESP_GATTC_ENC_CMPL_CB_EVT: break; + case ESP_GATTC_ADV_DATA_EVT: break; + case ESP_GATTC_MULT_ADV_ENB_EVT: break; + case ESP_GATTC_MULT_ADV_UPD_EVT: break; + case ESP_GATTC_MULT_ADV_DATA_EVT: break; + case ESP_GATTC_MULT_ADV_DIS_EVT: break; + case ESP_GATTC_CONGEST_EVT: break; + case ESP_GATTC_BTH_SCAN_ENB_EVT: break; + case ESP_GATTC_BTH_SCAN_CFG_EVT: break; + case ESP_GATTC_BTH_SCAN_RD_EVT: break; + case ESP_GATTC_BTH_SCAN_THR_EVT: break; + case ESP_GATTC_BTH_SCAN_PARAM_EVT: break; + case ESP_GATTC_BTH_SCAN_DIS_EVT: break; + case ESP_GATTC_SCAN_FLT_CFG_EVT: break; + case ESP_GATTC_SCAN_FLT_PARAM_EVT: break; + case ESP_GATTC_SCAN_FLT_STATUS_EVT: break; + case ESP_GATTC_ADV_VSC_EVT: break; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: break; + case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: break; + case ESP_GATTC_DISCONNECT_EVT: break; + default: break; + } +} + +void reverseBDA(uint8_t *bda){ + int x,t,n; + n = 5; + for(x = 0; x < n;) { + t = bda[x]; + bda[x] = bda[n]; + bda[n] = t; + x++; + n--; + } +} +void gattc_connect(uint8_t *addr){ + esp_err_t ret; + reverseBDA(addr); +jsError("new parameter in esp_ble_gattc_open ???\n"); + //ret = esp_ble_gattc_open(gattc_apps[GATTC_PROFILE].gattc_if,addr,true); +} +uint32_t gattc_disconnect(uint16_t conn_handle){ + esp_err_t ret; + ret = esp_ble_gattc_close(gattc_apps[GATTC_PROFILE].gattc_if,gattc_apps[GATTC_PROFILE].conn_id); + return ret; +} +void gattc_searchService(ble_uuid_t uuid){ + bleuuid_TO_espbtuuid(uuid,&serviceFilter); + esp_ble_gattc_search_service(gattc_apps[GATTC_PROFILE].gattc_if, gattc_apps[GATTC_PROFILE].conn_id, &serviceFilter); +} +void gattc_getCharacteristic(ble_uuid_t char_uuid){ + uint16_t count = 0; + bleuuid_TO_espbtuuid(char_uuid,&charFilter); + esp_ble_gattc_get_attr_count( + gattc_apps[GATTC_PROFILE].gattc_if, gattc_apps[GATTC_PROFILE].conn_id,ESP_GATT_DB_CHARACTERISTIC, + gattc_apps[GATTC_PROFILE].service_start_handle,gattc_apps[GATTC_PROFILE].service_end_handle, + INVALID_HANDLE,&count); + if(count > 0) { + if (!bleTaskInfo) bleTaskInfo = jsvNewEmptyArray(); + char_elem_result = (esp_gattc_char_elem_t *)malloc(sizeof(esp_gattc_char_elem_t) * count); + esp_ble_gattc_get_char_by_uuid( + gattc_apps[GATTC_PROFILE].gattc_if, gattc_apps[GATTC_PROFILE].conn_id, + gattc_apps[GATTC_PROFILE].service_start_handle,gattc_apps[GATTC_PROFILE].service_end_handle, + charFilter,char_elem_result,&count); + if(count > 0){ +//check with more than one character in service + gattc_apps[GATTC_PROFILE].char_handle = char_elem_result[0].char_handle; + JsVar *o = jspNewObject(0,"BluetoothRemoteGATTCharacteristic"); + if(o) { + jsvObjectSetChildAndUnLock(o,"uuid",jsvVarPrintf("%04x",char_elem_result[0].uuid.uuid.uuid16)); + jsvObjectSetChildAndUnLock(o,"handle_value",jsvNewFromInteger(char_elem_result[0].char_handle)); + JsVar *p = jsvNewObject(); + if(p){ + jsvObjectSetChildAndUnLock(p,"broadcast",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_BROADCAST)); + jsvObjectSetChildAndUnLock(p,"read",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_READ)); + jsvObjectSetChildAndUnLock(p,"writeWithoutResponse",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_WRITE_NR)); + jsvObjectSetChildAndUnLock(p,"write",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_WRITE)); + jsvObjectSetChildAndUnLock(p,"notify",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_NOTIFY)); + jsvObjectSetChildAndUnLock(p,"indicate",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_INDICATE)); + jsvObjectSetChildAndUnLock(p,"authenticatedSignedWrites",jsvNewFromBool(char_elem_result[0].properties & ESP_GATT_CHAR_PROP_BIT_AUTH)); + jsvObjectSetChildAndUnLock(o,"properties",p); + } + } + jsvArrayPushAndUnLock(bleTaskInfo,o); + } + free(char_elem_result); + } + JsVar *t = jsvSkipNameAndUnLock(jsvArrayPopFirst(bleTaskInfo)); + jsvUnLock(bleTaskInfo); + bleTaskInfo = t; + if (bleTaskInfo) bleCompleteTaskSuccess(BLETASK_CHARACTERISTIC, bleTaskInfo); + else bleCompleteTaskFailAndUnLock(BLETASK_CHARACTERISTIC, jsvNewFromString("No Characteristics found")); +} +void gattc_readValue(uint16_t charHandle){ +// check for connected + esp_ble_gattc_read_char(gattc_apps[GATTC_PROFILE].gattc_if,gattc_apps[GATTC_PROFILE].conn_id, + charHandle,ESP_GATT_AUTH_REQ_NONE); +} +void gattc_writeValue(uint16_t charHandle,char *data,size_t dataLen){ + esp_ble_gattc_write_char(gattc_apps[GATTC_PROFILE].gattc_if,gattc_apps[GATTC_PROFILE].conn_id, + charHandle,dataLen,data,ESP_GATT_WRITE_TYPE_RSP,ESP_GATT_AUTH_REQ_NONE); +} +void gattc_readDesc(uint16_t charHandle){ + esp_ble_gattc_read_char_descr (gattc_apps[GATTC_PROFILE].gattc_if,gattc_apps[GATTC_PROFILE].conn_id, + charHandle,ESP_GATT_AUTH_REQ_NONE); +} + diff --git a/targets/esp32/BLE/esp32_gattc_func.h b/targets/esp32/BLE/esp32_gattc_func.h new file mode 100644 index 000000000..eecd2bb9a --- /dev/null +++ b/targets/esp32/BLE/esp32_gattc_func.h @@ -0,0 +1,46 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GATT Client functions + * ---------------------------------------------------------------------------- + */ +#ifndef GATTC_FUNC_H_ +#define GATTC_FUNC_H_ + +#include "esp_gattc_api.h" + +#include "jsvar.h" + +#include "bluetooth.h" + +struct gattc_profile_inst { + esp_gattc_cb_t gattc_cb; + uint16_t gattc_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_start_handle; + uint16_t service_end_handle; + uint16_t char_handle; + esp_bd_addr_t remote_bda; +}; + +void gattc_init(); +void gattc_reset(); +void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gattc_cb_param_t *param); +void gattc_connect(uint8_t *addr); +uint32_t gattc_disconnect(uint16_t conn_handle); +//void gattc_searchService(uint16_t service_uuid); +void gattc_searchService(ble_uuid_t uuid); +void gattc_getCharacteristic(ble_uuid_t char_uuid); +void gattc_readValue(uint16_t charHandle); +void gattc_writeValue(uint16_t charHandle,char *data,size_t dataLen); +void gattc_readDesc(uint16_t charHandle); + +#endif /* GATTC_FUNC_H_ */ diff --git a/targets/esp32/BLE/esp32_gatts_func.c b/targets/esp32/BLE/esp32_gatts_func.c new file mode 100644 index 000000000..1ecd82f79 --- /dev/null +++ b/targets/esp32/BLE/esp32_gatts_func.c @@ -0,0 +1,554 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GATT functions + * ---------------------------------------------------------------------------- + */ + +#include + +#include "esp_system.h" +#include "esp_heap_caps.h" +#include "esp_log.h" + +#include "BLE/esp32_gatts_func.h" +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_bluetooth_utils.h" + +#include "bluetooth.h" +#include "bluetooth_utils.h" + +#include "jsutils.h" +#include "jsparse.h" +#include "jsinteractive.h" + +ble_uuid_t uart_service_uuid = { + .type = BLE_UUID_TYPE_128, + .uuid128 = {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,0x01,0x00,0x40,0x6e} +}; +esp_bt_uuid_t uart_char_rx_uuid = { + .len = ESP_UUID_LEN_128, + .uuid.uuid128 = {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,0x02,0x00,0x40,0x6e} +}; +esp_bt_uuid_t uart_char_tx_uuid = { + .len = ESP_UUID_LEN_128, + .uuid.uuid128 = {0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,0x03,0x00,0x40,0x6e} +}; +esp_bt_uuid_t uart_tx_descr = { + .len = ESP_UUID_LEN_16, + .uuid.uuid16 = 0x2902 +}; +uint8_t uart_advice[18] = {0x11,0x07,0x9e,0xca,0xdc,0x24,0x0e,0xe5,0xa9,0xe0,0x93,0xf3,0xa3,0xb5,0x01,0x00,0x40,0x6e,}; + +JsVar *gatts_services; +uint16_t ble_service_pos = -1;JsvObjectIterator ble_service_it;//ble_service_cnt is defined in .h +uint16_t ble_char_pos = -1;JsvObjectIterator ble_char_it;uint16_t ble_char_cnt = 0; +uint16_t ble_descr_pos = -1;JsvObjectIterator ble_descr_it;uint16_t ble_descr_cnt = 0; + +struct gatts_service_inst *gatts_service = NULL; +struct gatts_char_inst *gatts_char = NULL; +struct gatts_descr_inst *gatts_descr = NULL; + +bool _removeValues; + +void jshSetDeviceInitialised(IOEventFlags device, bool isInit); + +esp_gatt_if_t uart_gatts_if; +uint16_t uart_tx_handle; +bool uart_gatts_connected = false; + +uint8_t *getUartAdvice(){ + return uart_advice; +} +void gatts_sendNotification(int c){ + uint8_t data[2]; + data[0] = (uint8_t)c; + data[1] = 0; + if(uart_gatts_if != ESP_GATT_IF_NONE){ + esp_ble_gatts_send_indicate(uart_gatts_if, 0, uart_tx_handle, 1, data, false); + } +} + +void emitNRFEvent(char *event,JsVar *args,int argCnt){ + JsVar *nrf = jsvObjectGetChild(execInfo.root, "NRF", 0); + if(nrf){ + JsVar *eventName = jsvNewFromString(event); + JsVar *callback = jsvSkipNameAndUnLock(jsvFindChildFromVar(nrf,eventName,0)); + jsvUnLock(eventName); + if(callback) jsiQueueEvents(nrf,callback,args,argCnt); + jsvUnLock(nrf); + jsvUnLock(callback); + if(args) jsvUnLockMany(argCnt,args); + } + else {jsWarn("sorry, no NRF Object found"); } +} + +int getIndexFromGatts_if(esp_gatt_if_t gatts_if){ + for(int i = 0; i < ble_service_cnt;i++){ + if(gatts_service[i].gatts_if == gatts_if) return i; + } + return -1; +} + +static void gatts_read_value_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + esp_gatt_rsp_t rsp; JsVar *charValue; + memset(&rsp, 0, sizeof(esp_gatt_rsp_t)); + rsp.attr_value.handle = param->read.handle; + for (uint32_t pos=0;pos < ble_char_cnt;pos++) { + if (gatts_char[pos].char_handle==param->read.handle) { + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_READ_EVENT,pos); + JsVar *readCB = jsvObjectGetChild(execInfo.hiddenRoot,hiddenName,0); + if(readCB){ + charValue = jspExecuteFunction(readCB,0,0,0); + jsvUnLock(readCB); + } + else { + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_CHAR_VALUE,pos); + charValue = jsvObjectGetChild(execInfo.hiddenRoot,hiddenName,0); + } + if(charValue){ + JSV_GET_AS_CHAR_ARRAY(vPtr,vLen,charValue); + for(uint16_t valpos = 0; valpos < vLen; valpos++){ + rsp.attr_value.value[valpos] = vPtr[valpos]; + } + rsp.attr_value.len = vLen; + jsvUnLock(charValue); + } + break; + } + } + for (uint32_t pos=0;pos < ble_descr_cnt;pos++) { + if (gatts_descr[pos].descr_handle==param->read.handle) { + if(gatts_descr[pos].descrVal){ + JSV_GET_AS_CHAR_ARRAY(vPtr,vLen,gatts_descr[pos].descrVal); + for(uint16_t descrpos = 0; descrpos < vLen; descrpos++){rsp.attr_value.value[descrpos] = vPtr[descrpos];} + rsp.attr_value.len = vLen; + } + break; + } + } + esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp); +} +static void gatts_write_value_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + for(uint16_t pos = 0; pos < ble_char_cnt; pos++){ + if(gatts_char[pos].char_handle == param->write.handle){ + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_CHAR_VALUE,pos); + jsvObjectSetChildAndUnLock(execInfo.hiddenRoot,hiddenName, + jsvNewStringOfLength(param->write.len,param->write.value)); + bleGetHiddenName(hiddenName,BLE_WRITE_EVENT,pos); + JsVar *writeCB = jsvObjectGetChild(execInfo.hiddenRoot,hiddenName,0); + if(writeCB){ + JsVar *tmp = jspExecuteFunction(writeCB,0,0,0); + if(tmp) jsvUnLock(tmp); + } + break; + } + } + for(uint16_t pos = 0; pos < ble_descr_cnt; pos++){ + if(gatts_descr[pos].descr_handle == param->write.handle){ + gatts_descr[pos].descrVal = jsvNewStringOfLength(param->write.len,param->write.value); + break; + } + } + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); +} +static void gatts_write_nus_value_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + jshPushIOCharEvents(EV_BLUETOOTH, (char*)param->write.value, param->write.len); + jshHadEvent(); + esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL); +} +static void gatts_connect_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + int g = getIndexFromGatts_if(gatts_if); + if(g >= 0){ + JsVar *args[1]; + gatts_service[g].conn_id = param->connect.conn_id; + args[0] = bda2JsVarString(param->connect.remote_bda); + m_conn_handle = 0x01; + emitNRFEvent(BLE_CONNECT_EVENT,args,1); + if(gatts_service[g].serviceFlag == BLE_SERVICE_NUS) uart_gatts_connected = true; + } +} +static void gatts_disconnect_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + int g = getIndexFromGatts_if(gatts_if); + if(g >= 0){ + JsVar *args[1]; + gatts_service[g].gatts_if = ESP_GATT_IF_NONE; + bluetooth_gap_startAdvertizing(true); + args[0] = bda2JsVarString(param->disconnect.remote_bda); + m_conn_handle = BLE_GATT_HANDLE_INVALID; + emitNRFEvent(BLE_DISCONNECT_EVENT,args,1); + if(gatts_service[g].serviceFlag == BLE_SERVICE_NUS) uart_gatts_connected = true; + } +} +void gatts_reg_app(){ + esp_err_t r; + if(ble_service_pos < ble_service_cnt){ + r = esp_ble_gatts_app_register(ble_service_pos); + if(r) jsWarn("app_register error:%d\n",r); + } + else{ + bluetooth_gap_startAdvertizing(true); + jshSetDeviceInitialised(EV_BLUETOOTH, true); + } +} +void gatts_createService(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param){ + esp_err_t r; + gatts_service[param->reg.app_id].service_id.is_primary = true; + gatts_service[param->reg.app_id].service_id.id.inst_id = 0x00; + gatts_service[param->reg.app_id].gatts_if = gatts_if; + bleuuid_TO_espbtuuid(gatts_service[param->reg.app_id].ble_uuid,&gatts_service[param->reg.app_id].service_id.id); + r = esp_ble_gatts_create_service(gatts_if, &gatts_service[param->reg.app_id].service_id, gatts_service[param->reg.app_id].num_handles); + if(r) jsWarn("createService error:%d\n",r); +} +void gatts_add_char(){ + esp_err_t r; + for(uint16_t pos=0; pos < ble_char_cnt; pos++){ + if(gatts_char[pos].service_pos == ble_service_pos && gatts_char[pos].char_handle == 0){ + ble_char_pos = pos; + r = esp_ble_gatts_add_char(gatts_service[ble_service_pos].service_handle,&gatts_char[pos].char_uuid, + gatts_char[pos].char_perm,gatts_char[pos].char_property, + NULL,gatts_char[pos].char_control); + if(r) jsWarn("add char error:%d\n",r); + return; + } + } + ble_service_pos++; + gatts_reg_app(); +} +void gatts_add_descr(){ + esp_err_t r; + for(uint16_t pos = 0;pos < ble_descr_cnt; pos++){ + if(gatts_descr[pos].descr_handle == 0 && gatts_descr[pos].char_pos == ble_char_pos){ + ble_descr_pos = pos; + r = esp_ble_gatts_add_char_descr(gatts_service[ble_service_pos].service_handle, + &gatts_descr[pos].descr_uuid,gatts_descr[pos].descr_perm, + NULL,gatts_descr[pos].descr_control); + if(r) jsWarn("add descr error:%d\n",r); + return; + } + } + ble_char_pos++; + gatts_add_char(); +} +void gatts_check_add_descr(esp_bt_uuid_t descr_uuid, uint16_t attr_handle){ + if(attr_handle != 0){ + gatts_descr[ble_descr_pos].descr_handle=attr_handle; + } + gatts_add_descr(); // try to add more descriptors +} +static void gatts_check_add_char(esp_bt_uuid_t char_uuid, uint16_t attr_handle) { + if (attr_handle != 0) { + gatts_char[ble_char_pos].char_handle=attr_handle; + gatts_add_descr(); // try to add descriptors to this characteristic + } +} +static void gatts_delete_service(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if){ + esp_err_t r; + r = esp_ble_gatts_app_unregister(gatts_service[getIndexFromGatts_if(gatts_if)].gatts_if); + if(r) jsWarn("error in app_unregister:%d\n",r); +} +static void gatts_unreg_app(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if){ + gatts_service[getIndexFromGatts_if(gatts_if)].gatts_if = ESP_GATT_IF_NONE; + for(int i = 0; i < ble_service_cnt; i++){ + if(gatts_service[i].gatts_if != ESP_GATT_IF_NONE) return; + } + free(adv_service_uuid128);adv_service_uuid128 = NULL; + free(gatts_char);gatts_char = NULL; + free(gatts_descr);gatts_descr = NULL; + free(gatts_service);gatts_service = NULL; + ble_service_cnt = 0; + ble_char_cnt = 0; + ble_descr_cnt = 0; + if(_removeValues) bleRemoveChilds(execInfo.hiddenRoot); +} +void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) { + jsWarnGattsEvent(event,gatts_if); + JsVar *args[1]; + switch (event) { + case ESP_GATTS_REG_EVT:{gatts_createService(event,gatts_if,param);break;} + case ESP_GATTS_CREATE_EVT:{ + gatts_service[ble_service_pos].service_handle = param->create.service_handle; + esp_ble_gatts_start_service(gatts_service[ble_service_pos].service_handle); + break; + } + case ESP_GATTS_ADD_CHAR_EVT: { + if (param->add_char.status==ESP_GATT_OK) { + gatts_check_add_char(param->add_char.char_uuid,param->add_char.attr_handle); + } + else{ + jsWarn("add char failed:%d\n",param->add_char.status); + gatts_char[ble_char_pos].char_handle = -1; + ble_char_pos++; + gatts_add_char(); + } + break; + } + case ESP_GATTS_START_EVT: {gatts_add_char();break;} + case ESP_GATTS_DISCONNECT_EVT:{gatts_disconnect_handler(event,gatts_if,param); break;} + case ESP_GATTS_ADD_CHAR_DESCR_EVT:{ + if (param->add_char_descr.status==ESP_GATT_OK) { + gatts_check_add_descr(param->add_char.char_uuid,param->add_char.attr_handle); + } + else{jsWarn("add descr failed:%d\n",param->add_char_descr.status);} + break; + } + case ESP_GATTS_CONNECT_EVT: {gatts_connect_handler(event,gatts_if,param); break;} + case ESP_GATTS_READ_EVT: {gatts_read_value_handler(event, gatts_if, param);break;} + case ESP_GATTS_WRITE_EVT:{ + if(gatts_service[getIndexFromGatts_if(gatts_if)].serviceFlag == BLE_SERVICE_NUS){ + gatts_write_nus_value_handler(event,gatts_if,param); + } + else{ + gatts_write_value_handler(event,gatts_if,param); + } + break; + } + case ESP_GATTS_DELETE_EVT:{gatts_delete_service(event,gatts_if);break;} + case ESP_GATTS_UNREG_EVT:{gatts_unreg_app(event,gatts_if);break;} + + case ESP_GATTS_EXEC_WRITE_EVT:break; + case ESP_GATTS_MTU_EVT:break; + case ESP_GATTS_CONF_EVT:break; + case ESP_GATTS_ADD_INCL_SRVC_EVT:break; + case ESP_GATTS_STOP_EVT:break; + case ESP_GATTS_OPEN_EVT:break; + case ESP_GATTS_CANCEL_OPEN_EVT:break; + case ESP_GATTS_CLOSE_EVT:break; + case ESP_GATTS_LISTEN_EVT:break; + case ESP_GATTS_CONGEST_EVT:break; + default: + break; + } +} + +void add_ble_uart(){ + uint16_t handles = 1; + ble_service_pos++; + gatts_service[ble_service_pos].ble_uuid = uart_service_uuid; + bleuuid_To_uuid128(gatts_service[ble_service_pos].ble_uuid,&adv_service_uuid128[ble_service_pos * 16]); + gatts_service[ble_service_pos].uuid16 = gatts_service[ble_service_pos].ble_uuid.uuid; + gatts_service[ble_service_pos].serviceFlag = BLE_SERVICE_NUS; + ble_char_pos++; + gatts_char[ble_char_pos].char_perm = 0; + gatts_char[ble_char_pos].service_pos = ble_service_pos; + gatts_char[ble_char_pos].char_uuid = uart_char_rx_uuid; + gatts_char[ble_char_pos].char_perm += ESP_GATT_PERM_WRITE; + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_WRITE_NR; + gatts_char[ble_char_pos].char_control = NULL; + gatts_char[ble_char_pos].char_handle = 0; + gatts_char[ble_char_pos].charFlag = BLE_CHAR_UART_RX; + handles +=2; + ble_char_pos++; + gatts_char[ble_char_pos].char_perm = 0; + gatts_char[ble_char_pos].service_pos = ble_service_pos; + gatts_char[ble_char_pos].char_uuid = uart_char_tx_uuid; + gatts_char[ble_char_pos].char_perm += ESP_GATT_PERM_READ; + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_NOTIFY; + gatts_char[ble_char_pos].char_control = NULL; + gatts_char[ble_char_pos].char_handle = 0; + gatts_char[ble_char_pos].charFlag = BLE_CHAR_UART_TX; + handles +=2; + ble_descr_pos++; + gatts_descr[ble_descr_pos].char_pos = ble_char_pos; + gatts_descr[ble_descr_pos].descr_uuid = uart_tx_descr; + gatts_descr[ble_descr_pos].descr_handle = 0; + handles +=2; + gatts_service[ble_service_pos].gatts_if = ESP_GATT_IF_NONE; + gatts_service[ble_service_pos].num_handles = handles; +} +void setBleUart(){ + uart_gatts_if = ESP_GATT_IF_NONE; + for(int i = 0; i < ble_service_cnt; i++){ + if(gatts_service[i].serviceFlag == BLE_SERVICE_NUS){ + uart_gatts_if = gatts_service[i].gatts_if; + for(int j = 0; j < ble_char_cnt; j++){ + if(gatts_char[j].charFlag == BLE_CHAR_UART_TX){ + uart_tx_handle = gatts_char[j].char_handle; + } + } + } + } +} + +void gatts_char_init(){ + const char *errorStr; + ble_uuid_t ble_uuid; + gatts_char[ble_char_pos].service_pos = ble_service_pos; + if((errorStr = bleVarToUUIDAndUnLock(&ble_uuid,jsvObjectIteratorGetKey(&ble_char_it)))){ + jsExceptionHere(JSET_ERROR,"invalid Char UUID:%s",errorStr); + } + JsVar *charVar = jsvObjectIteratorGetValue(&ble_char_it); + gatts_char[ble_char_pos].char_uuid.len = ESP_UUID_LEN_16; + gatts_char[ble_char_pos].char_uuid.uuid.uuid16 = ble_uuid.uuid; + gatts_char[ble_char_pos].char_perm = 0; + if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "broadcast", 0))) + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_BROADCAST; + if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "notify", 0))) + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_NOTIFY; + if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "indicate", 0))) + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_INDICATE; + if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "readable", 0))){ + gatts_char[ble_char_pos].char_perm += ESP_GATT_PERM_READ; + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_READ; + } + if (jsvGetBoolAndUnLock(jsvObjectGetChild(charVar, "writable", 0))){ + gatts_char[ble_char_pos].char_perm += ESP_GATT_PERM_WRITE; + gatts_char[ble_char_pos].char_property += ESP_GATT_CHAR_PROP_BIT_WRITE|ESP_GATT_CHAR_PROP_BIT_WRITE_NR; + } + gatts_char[ble_char_pos].char_control = NULL; + gatts_char[ble_char_pos].char_handle = 0; + JsVar *readCB = jsvObjectGetChild(charVar, "onRead", 0); + if(readCB){ + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_READ_EVENT,ble_char_pos); + jsvObjectSetChildAndUnLock(execInfo.hiddenRoot,hiddenName,readCB); + } + JsVar *writeCB = jsvObjectGetChild(charVar, "onWrite", 0); + if(writeCB){ + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_WRITE_EVENT,ble_char_pos); + jsvObjectSetChildAndUnLock(execInfo.hiddenRoot,hiddenName,writeCB); + } + JsVar *charDescriptionVar = jsvObjectGetChild(charVar, "description", 0); + if (charDescriptionVar && jsvHasCharacterData(charDescriptionVar)) { + ble_descr_pos++; + gatts_descr[ble_descr_pos].char_pos = ble_char_pos; + gatts_descr[ble_descr_pos].descr_uuid.len = ESP_UUID_LEN_16; + gatts_descr[ble_descr_pos].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_DESCRIPTION; + gatts_descr[ble_descr_pos].descr_perm = ESP_GATT_PERM_READ; + gatts_descr[ble_descr_pos].descrVal = charDescriptionVar; + gatts_descr[ble_descr_pos].descr_control = NULL; + gatts_descr[ble_descr_pos].descr_handle = 0; + } + jsvUnLock(charDescriptionVar); + JsVar *charValue = jsvObjectGetChild(charVar,"value",0); + if(charValue){ + char hiddenName[12]; + bleGetHiddenName(hiddenName,BLE_CHAR_VALUE,ble_char_pos); + jsvObjectSetChildAndUnLock(execInfo.hiddenRoot,hiddenName,charValue); + } + jsvUnLock(charVar); +} +void gatts_service_struct_init(){ + ble_uuid_t ble_uuid;uint16_t handles; + const char *errorStr; + if((errorStr = bleVarToUUIDAndUnLock(&gatts_service[ble_service_pos].ble_uuid, jsvObjectIteratorGetKey(&ble_service_it)))){ + jsExceptionHere(JSET_ERROR,"invalid Service UUID:%s",errorStr); + } + handles = 1; //for service + bleuuid_To_uuid128(gatts_service[ble_service_pos].ble_uuid,&adv_service_uuid128[ble_service_pos * 16]); + gatts_service[ble_service_pos].uuid16 = gatts_service[ble_service_pos].ble_uuid.uuid; + JsVar *serviceVar = jsvObjectIteratorGetValue(&ble_service_it); + jsvObjectIteratorNew(&ble_char_it,serviceVar); + while(jsvObjectIteratorHasValue(&ble_char_it)){ + ble_char_pos++; + gatts_char_init(); + handles +=2; //2 for each char + handles +=2; //placeholder for 2 descr + jsvObjectIteratorNext(&ble_char_it); + } + gatts_service[ble_service_pos].num_handles = handles; + jsvObjectIteratorFree(&ble_char_it); + jsvUnLock(serviceVar); +} +void gatts_structs_init(JsVar *options){ + for(int i = 0; i < ble_service_cnt; i++){ + gatts_service[i].gatts_if = ESP_GATT_IF_NONE; + gatts_service[i].num_handles = 0; + gatts_service[i].serviceFlag = BLE_SERVICE_GENERAL; + } + for(int i = 0; i < ble_char_cnt;i++){ + gatts_char[i].service_pos = -1; + gatts_char[i].charFlag = BLE_CHAR_GENERAL; + } + for(int i = 0; i < ble_descr_cnt;i++){ + gatts_descr[i].char_pos = -1; + } + jsvObjectIteratorNew(&ble_service_it,gatts_services); + while(jsvObjectIteratorHasValue(&ble_service_it)){ + ble_service_pos++; + gatts_service_struct_init(); + jsvObjectIteratorNext(&ble_service_it); + } + jsvObjectIteratorFree(&ble_service_it); + if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "uart", 0))){ + add_ble_uart(); + } +} +void gatts_getAdvServiceUUID(uint8_t *p_service_uuid, uint16_t service_len){ + p_service_uuid = adv_service_uuid128; + service_len = 16 * ble_service_cnt - 16; +} + +void gatts_create_structs(JsVar *options){ + ble_service_cnt = 0; ble_char_cnt = 0; ble_descr_cnt = 0; + ble_service_pos = -1; ble_char_pos = -1; ble_descr_pos = -1; + jsvObjectIteratorNew(&ble_service_it,gatts_services); + while(jsvObjectIteratorHasValue(&ble_service_it)){ + JsVar *serviceVar = jsvObjectIteratorGetValue(&ble_service_it); + jsvObjectIteratorNew(&ble_char_it,serviceVar); + while(jsvObjectIteratorHasValue(&ble_char_it)){ + JsVar *charVar = jsvObjectIteratorGetValue(&ble_char_it); + JsVar *charDescriptionVar = jsvObjectGetChild(charVar, "description", 0); + if (charDescriptionVar && jsvHasCharacterData(charDescriptionVar)) ble_descr_cnt++; + jsvUnLock(charDescriptionVar); + jsvUnLock(charVar); + jsvObjectIteratorNext(&ble_char_it); + ble_char_cnt++; + } + jsvUnLock(serviceVar); + jsvObjectIteratorFree(&ble_char_it); + jsvObjectIteratorNext(&ble_service_it); + ble_service_cnt++; + } + if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "uart", 0))){ + ble_service_cnt++; + ble_char_cnt += 2; + ble_descr_cnt += 2; + } + jsvObjectIteratorFree(&ble_service_it); + adv_service_uuid128 = calloc(sizeof(uint8_t),(ble_service_cnt * 16)); + gatts_service = calloc(sizeof(struct gatts_service_inst),ble_service_cnt); + gatts_char = calloc(sizeof(struct gatts_char_inst),ble_char_cnt); + gatts_descr = calloc(sizeof(struct gatts_descr_inst),ble_descr_cnt); +} + +void gatts_set_services(JsVar *data){ + JsVar *options = jsvObjectGetChild(execInfo.hiddenRoot, BLE_NAME_SERVICE_OPTIONS,0); + gatts_reset(true); + gatts_services = data; + if (jsvIsObject(gatts_services)) { + gatts_create_structs(options); + gatts_structs_init(options); + ble_service_pos = 0; + ble_char_pos = 0; + ble_descr_pos = 0; + gatts_reg_app(); //this starts tons of api calls creating gatts-events. Ends in gatts_reg_app + if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "uart", 0))){ + setBleUart(); + } + } + jsvUnLock(options); +} +void gatts_reset(bool removeValues){ + esp_err_t r; + _removeValues = removeValues; + if(ble_service_cnt > 0){ + for(int i = 0; i < ble_service_cnt;i++){ + if(gatts_service[i].gatts_if != ESP_GATT_IF_NONE){ + r = esp_ble_gatts_delete_service(gatts_service[i].service_handle); + if(r) jsWarn("delete service error:%d\n",r); + } + } + } +} diff --git a/targets/esp32/BLE/esp32_gatts_func.h b/targets/esp32/BLE/esp32_gatts_func.h new file mode 100644 index 000000000..d72627f23 --- /dev/null +++ b/targets/esp32/BLE/esp32_gatts_func.h @@ -0,0 +1,80 @@ +/* + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2017 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * ESP32 specific GATT functions + * ---------------------------------------------------------------------------- + */ +#ifndef GATTS_FUNC_H_ +#define GATTS_FUNC_H_ + +#include "esp_gatts_api.h" +#include "jsvar.h" +#include "bluetooth.h" + +#define GATTS_CHAR_VAL_LEN_MAX 22 // maximum length in bytes of a characteristic's value. TODO: find out how to determine this value? + +typedef enum { + BLE_SERVICE_GENERAL = 0, + BLE_SERVICE_NUS = 1 +} BLEServiceFlags; + +typedef enum { + BLE_CHAR_GENERAL = 0, + BLE_CHAR_UART_RX = 1, + BLE_CHAR_UART_TX = 2 +} BLECharFlags; + +struct gatts_service_inst { + 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 num_handles; + ble_uuid_t ble_uuid; + uint16_t uuid16; + BLEServiceFlags serviceFlag; +}; + +struct gatts_char_inst { + uint32_t service_pos; + esp_bt_uuid_t char_uuid; + esp_gatt_perm_t char_perm; + esp_gatt_char_prop_t char_property; + esp_attr_control_t *char_control; + uint16_t char_handle; + char char_nvs[16]; + BLECharFlags charFlag; +}; + +struct gatts_descr_inst { + uint32_t char_pos; + esp_bt_uuid_t descr_uuid; + esp_gatt_perm_t descr_perm; + JsVar *descrVal; + esp_attr_control_t *descr_control; + uint16_t descr_handle; +}; + +static uint8_t *adv_service_uuid128 = NULL; + +static uint16_t ble_service_cnt = 0; + +void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param); +void gatts_register_app(uint16_t id); +void gatts_set_services(JsVar *data); +void gatts_reset(bool removeValues); + +uint8_t *getUartAdvice(); +void gatts_sendNotification(int c); + +void gatts_test(); + +#endif /* GATTS_FUNC_H_ */ diff --git a/targets/esp32/bluetooth.c b/targets/esp32/bluetooth.c new file mode 100644 index 000000000..d96c54599 --- /dev/null +++ b/targets/esp32/bluetooth.c @@ -0,0 +1,203 @@ +/** + * This file is part of Espruino, a JavaScript interpreter for Microcontrollers + * + * Copyright (C) 2013 Gordon Williams + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ---------------------------------------------------------------------------- + * Utilities for converting Nordic datastructures to Espruino and vice versa + * ---------------------------------------------------------------------------- + */ +#include + +#include "bt.h" +#include "esp_bt_main.h" +#include "esp_gatt_common_api.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" + +#include "jswrap_bluetooth.h" +#include "bluetooth.h" +#include "jsutils.h" + +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_gatts_func.h" +#include "BLE/esp32_gattc_func.h" +#include "BLE/esp32_bluetooth_utils.h" + +#define UNUSED(x) (void)(x) + +volatile BLEStatus bleStatus; +uint16_t bleAdvertisingInterval; /**< The advertising interval (in units of 0.625 ms). */ +volatile uint16_t m_conn_handle; /**< Handle of the current connection. */ +volatile uint16_t m_central_conn_handle; /**< Handle of central mode connection */ + +/** Initialise the BLE stack */ +void jsble_init(){ + esp_err_t ret; + ret = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); + if(ret) {jsWarn("mem release failed:%x\n",ret); return;} + + if(initController()) return; + if(initBluedroid()) return; + if(registerCallbacks()) return; + setMtu(); +} +/** Completely deinitialise the BLE stack */ +void jsble_kill(){ + jsWarn("kill not implemented yet\n"); +} + +void jsble_queue_pending_buf(BLEPending blep, uint16_t data, char *ptr, size_t len){ + jsWarn("queue_pending_buf not implemented yet"); + UNUSED(blep); + UNUSED(data); + UNUSED(ptr); + UNUSED(len); +} + +void jsble_queue_pending(BLEPending blep, uint16_t data){ + jsWarn("queue_pending not implemented yet"); + UNUSED(blep); + UNUSED(data); +} + +int jsble_exec_pending(IOEvent *event){ + jsWarn("exec_pending not implemented yet"); + UNUSED(event); + return 0; +} + +void jsble_restart_softdevice(){ + bleStatus &= ~(BLE_NEEDS_SOFTDEVICE_RESTART | BLE_SERVICES_WERE_SET); + if (bleStatus & BLE_IS_SCANNING) { + bluetooth_gap_setScan(false); + } + jswrap_nrf_reconfigure_softdevice(); +} + +void jsble_advertising_start(){ +//jsWarn("advertising start\n"); + esp_err_t status; + if (bleStatus & BLE_IS_ADVERTISING) return; + status = bluetooth_gap_startAdvertizing(true); + if(status) jsWarn("advertizing start problem:0X%x\n",status); +} +void jsble_advertising_stop(){ + esp_err_t status; + status = bluetooth_gap_startAdvertizing(false); + if(status) jsWarn("error in stop advertising:0X%x\n",status); +} +/** Is BLE connected to any device at all? */ +bool jsble_has_connection(){ + jsWarn("has connected not implemented yet\n"); + return false; +} + +/** Is BLE connected to a central device at all? */ +bool jsble_has_central_connection(){ + jsWarn("has central connection not implemented yet\n"); + return false; +} +/** Is BLE connected to a server device at all (eg, the simple, 'slave' mode)? */ +bool jsble_has_simple_connection(){ + jsWarn("has simple connection not implemented yet\n"); + return false; +} + +/// Checks for error and reports an exception if there was one. Return true on error +bool jsble_check_error(uint32_t err_code){ + jsWarn("check error not implemented yet:%x\n",err_code); + UNUSED(err_code); + return false; +} +/// Scanning for advertisign packets +uint32_t jsble_set_scanning(bool enabled){ + bluetooth_gap_setScan(enabled); + return 0; +} + +/// returning RSSI values for current connection +uint32_t jsble_set_rssi_scan(bool enabled){ + jsWarn("set rssi scan not implemeted yet\n"); + UNUSED(enabled); + return 0; +} + +/** Actually set the services defined in the 'data' object. Note: we can + * only do this *once* - so to change it we must reset the softdevice and + * then call this again */ +void jsble_set_services(JsVar *data){ + gatts_set_services(data); +} + +/// Disconnect from the given connection +uint32_t jsble_disconnect(uint16_t conn_handle){ + return gattc_disconnect(conn_handle); + return 0; +} + +/// For BLE HID, send an input report to the receiver. Must be <= HID_KEYS_MAX_LEN +void jsble_send_hid_input_report(uint8_t *data, int length){ + jsWarn("send hid input report not implemented yet\n"); + UNUSED(data); + UNUSED(length); +} + +/// Connect to the given peer address. When done call bleCompleteTask +void jsble_central_connect(ble_gap_addr_t peer_addr){ + gattc_connect(peer_addr.addr); +} +/// Get primary services. Filter by UUID unless UUID is invalid, in which case return all. When done call bleCompleteTask +void jsble_central_getPrimaryServices(ble_uuid_t uuid){ + gattc_searchService(uuid); +} +/// Get characteristics. Filter by UUID unless UUID is invalid, in which case return all. When done call bleCompleteTask +void jsble_central_getCharacteristics(JsVar *service, ble_uuid_t uuid){ + gattc_getCharacteristic(uuid); + UNUSED(service); +} +// Write data to the given characteristic. When done call bleCompleteTask +void jsble_central_characteristicWrite(JsVar *characteristic, char *dataPtr, size_t dataLen){ + uint16_t handle = jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0)); + gattc_writeValue(handle,dataPtr,dataLen); +} +// Read data from the given characteristic. When done call bleCompleteTask +void jsble_central_characteristicRead(JsVar *characteristic){ + uint16_t handle = jsvGetIntegerAndUnLock(jsvObjectGetChild(characteristic, "handle_value", 0)); + gattc_readValue(handle); +} +// Discover descriptors of characteristic +void jsble_central_characteristicDescDiscover(JsVar *characteristic){ + jsWarn("Central characteristicDescDiscover not implemented yet\n"); + UNUSED(characteristic); +} +// Set whether to notify on the given characteristic. When done call bleCompleteTask +void jsble_central_characteristicNotify(JsVar *characteristic, bool enable){ + jsWarn("central characteristic notify not implemented yet\n"); + UNUSED(characteristic); + UNUSED(enable); +} +/// Start bonding on the current central connection +void jsble_central_startBonding(bool forceRePair){ + jsWarn("central start bonding not implemented yet\n"); + UNUSED(forceRePair); +} +/// Get the security status of the current link +JsVar *jsble_central_getSecurityStatus(){ + jsWarn("central getSecurityStatus not implemented yet\n"); + return 0; +} +/// RSSI monitoring in central mode +uint32_t jsble_set_central_rssi_scan(bool enabled){ + jsWarn("central set rssi scan not implemented yet\n"); + return 0; +} +// Set whether or not the whitelist is enabled +void jsble_central_setWhitelist(bool whitelist){ + jsWarn("central set Whitelist not implemented yet\n"); + return 0; +} diff --git a/targets/esp32/jshardware.c b/targets/esp32/jshardware.c index 107b4fcf8..9afe828c6 100644 --- a/targets/esp32/jshardware.c +++ b/targets/esp32/jshardware.c @@ -32,6 +32,12 @@ #include "jshardwarePWM.h" #include "jshardwarePulse.h" +#ifdef BLUETOOTH +#include "BLE/esp32_gap_func.h" +#include "BLE/esp32_gattc_func.h" +#include "BLE/esp32_gatts_func.h" +#endif + #include "jsutils.h" #include "jstimer.h" #include "jsparse.h" @@ -126,6 +132,9 @@ void jshPinDefaultPullup() { */ void jshInit() { esp32_wifi_init(); +#ifdef BLUETOOTH + gattc_init(); +#endif jshInitDevices(); BITFIELD_CLEAR(jshPinSoftPWM); if (JSHPINSTATE_I2C != 13 || JSHPINSTATE_GPIO_IN_PULLDOWN != 6 || JSHPINSTATE_MASK != 15) { @@ -147,11 +156,14 @@ void jshInit() { void jshReset() { jshResetDevices(); jshPinDefaultPullup() ; - UartReset(); +// UartReset(); RMTReset(); ADCReset(); SPIReset(); I2CReset(); +#ifdef BLUETOOTH + gatts_reset(false); +#endif } /** @@ -505,12 +517,12 @@ bool jshIsEventForPin( void jshUSARTSetup(IOEventFlags device, JshUSARTInfo *inf) { - + if (inf->errorHandling) { jsExceptionHere(JSET_ERROR, "ESP32 Espruino builds can't handle framing/parity errors (errors:true)"); return; - } - + } + initSerial(device,inf); } @@ -527,8 +539,21 @@ void jshUSARTKick( ) { int c = jshGetCharToTransmit(device); while(c >= 0) { - if(device == EV_SERIAL1) uart_tx_one_char((uint8_t)c); - else writeSerial(device,(uint8_t)c); + switch(device){ +#ifdef BLUETOOTH + case EV_BLUETOOTH: + gatts_sendNotification(c); + break; +#endif + case EV_SERIAL1: + uart_tx_one_char((uint8_t)c); + break; + default: + writeSerial(device,(uint8_t)c); + break; + //if(device == EV_SERIAL1) uart_tx_one_char((uint8_t)c); + //else writeSerial(device,(uint8_t)c); + } c = jshGetCharToTransmit(device); } } diff --git a/targets/esp32/jswrap_esp32.c b/targets/esp32/jswrap_esp32.c index 895c32ca0..0c11645bf 100644 --- a/targets/esp32/jswrap_esp32.c +++ b/targets/esp32/jswrap_esp32.c @@ -12,13 +12,24 @@ * ---------------------------------------------------------------------------- */ #include - + #include "jswrap_esp32.h" #include "jshardwareAnalog.h" +#include "jsutils.h" +#include "jsinteractive.h" +#include "jsparse.h" #include "esp_system.h" #include "esp_sleep.h" +#ifdef BLUETOOTH +#include "BLE/esp32_bluetooth_utils.h" +#endif + +#include "jsutils.h" +#include "jsinteractive.h" +#include "jsparse.h" + /*JSON{ "type" : "staticmethod", "class" : "ESP32", @@ -27,7 +38,7 @@ "params" : [ ["pin", "pin", "Pin for Analog read"], ["atten", "int", "Attenuate factor"] - ] + ] }*/ void jswrap_ESP32_setAtten(Pin pin,int atten){ printf("Atten:%d\n",atten); @@ -52,7 +63,7 @@ void jswrap_ESP32_reboot() { "class" : "ESP32", "name" : "deepSleep", "generate" : "jswrap_ESP32_deepSleep", - "params" : [ ["us", "int", "Sleeptime in us"] ] + "params" : [ ["us", "int", "Sleeptime in us"] ] } Put device in deepsleep state for "us" microseconds. */ @@ -83,3 +94,20 @@ JsVar *jswrap_ESP32_getState() { jsvObjectSetChildAndUnLock(esp32State, "freeHeap", jsvNewFromInteger(esp_get_free_heap_size())); return esp32State; } // End of jswrap_ESP32_getState + +#ifdef BLUETOOTH +/*JSON{ + "type" : "staticmethod", + "class" : "ESP32", + "name" : "setBLE_Debug", + "generate" : "jswrap_ESP32_setBLE_Debug", + "params" : [ + ["level", "int", "which events should be shown (GATTS, GATTC, GAP)"] + ], + "ifdef" : "BLUETOOTH" +} +*/ +void jswrap_ESP32_setBLE_Debug(int level){ + ESP32_setBLE_Debug(level); +} +#endif diff --git a/targets/esp32/jswrap_esp32.h b/targets/esp32/jswrap_esp32.h index 597f02466..db78801aa 100644 --- a/targets/esp32/jswrap_esp32.h +++ b/targets/esp32/jswrap_esp32.h @@ -24,4 +24,8 @@ JsVar *jswrap_ESP32_setBoot(JsVar *jsPartitionName); void jswrap_ESP32_reboot(); void jswrap_ESP32_deepSleep(int us); void jswrap_ESP32_setAtten(Pin pin,int atten); + +#ifdef BLUETOOTH +void jswrap_ESP32_setBLE_Debug(int level); +#endif #endif /* TARGETS_ESP32_JSWRAP_ESP32_H_ */ diff --git a/targets/esp32/main.c b/targets/esp32/main.c index 463d2e4a8..bd8a6dc4d 100644 --- a/targets/esp32/main.c +++ b/targets/esp32/main.c @@ -18,6 +18,11 @@ #include "jshardwareSpi.h" #include "jswrap_wifi.h" // jswrap_wifi_restore +#ifdef BLUETOOTH +#include "libs/bluetooth/bluetooth.h" +#include "BLE/esp32_gap_func.h" +#endif + #include "esp_spi_flash.h" #include "spi_flash/include/esp_partition.h" #include "esp_log.h" @@ -27,8 +32,8 @@ extern void initialise_wifi(void); static void uartTask(void *data) { initConsole(); while(1) { - consoleToEspruino(); - serialToEspruino(); + consoleToEspruino(); + serialToEspruino(); } } @@ -43,6 +48,9 @@ static void espruinoTask(void *data) { // not sure why this delay is needed? vTaskDelay(200 / portTICK_PERIOD_MS); jsiInit(true); // Initialize the interactive subsystem +#ifdef BLUETOOTH + bluetooth_initDeviceName(); +#endif while(1) { jsiLoop(); // Perform the primary loop processing } @@ -58,6 +66,9 @@ int app_main(void) { esp_log_level_set("*", ESP_LOG_ERROR); // set all components to ERROR level - suppress Wifi Info nvs_flash_init(); +#ifdef BLUETOOTH + jsble_init(); +#endif spi_flash_init(); tcpip_adapter_init(); timers_Init(); From 15c3a9ae9343ba9f4bc99d266fd3b0179498b680 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Sun, 13 May 2018 14:24:17 +1200 Subject: [PATCH 10/15] update esp-idf to v3.0. BLE support - thanks to @jumjum. 2500 vars. Erase flash before flashing --- ChangeLog | 3 +++ boards/ESP32.py | 3 ++- libs/bluetooth/bluetooth.h | 6 +----- scripts/common.py | 4 +++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index c6e406f7b..cb20653e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,9 @@ Fix memory leak if an exception is thrown within a rejected promise ESP8266: rewrite wifi.save and restore to use the storage lib (imp #1380) ESP8266: Add missing option ssid_hidden for Wifi.startAP() (imp #1358) + Fixed double-connect issue for TCP sockets + Pixl.js: Ensure Pixl.menu changes to bitmap fonts + Pixl.js: tweaked bias/contrast to improve display quality 1v97 : nRF52: fix NRF.on('connect',...) issue STM32: Fix setDeviceClockCmd error for USB.setConsole() diff --git a/boards/ESP32.py b/boards/ESP32.py index f33eb0af9..6b407c8c5 100755 --- a/boards/ESP32.py +++ b/boards/ESP32.py @@ -32,7 +32,8 @@ 'TELNET', 'NEOPIXEL', 'FILESYSTEM', - 'FLASHFS' + 'FLASHFS', + 'BLUETOOTH' ], 'makefile' : [ 'DEFINES+=-DESP_PLATFORM -DESP32=1' diff --git a/libs/bluetooth/bluetooth.h b/libs/bluetooth/bluetooth.h index 8a6b249f9..edc126067 100644 --- a/libs/bluetooth/bluetooth.h +++ b/libs/bluetooth/bluetooth.h @@ -49,7 +49,7 @@ typedef struct { #define MSEC_TO_UNITS(MS,MEH) MS #endif -#ifdef NRF52 +#if defined(NRF52) || defined(ESP32) // nRF52 gets the ability to connect to other #define CENTRAL_LINK_COUNT 1 /** Date: Sun, 13 May 2018 14:52:58 +1200 Subject: [PATCH 11/15] update esp-idf to v3.0. BLE support - thanks to @jumjum. 2500 vars. Erase flash before flashing --- libs/bluetooth/jswrap_bluetooth.c | 8 ++++---- scripts/common.py | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/bluetooth/jswrap_bluetooth.c b/libs/bluetooth/jswrap_bluetooth.c index 05cfd7f62..7addd4b66 100644 --- a/libs/bluetooth/jswrap_bluetooth.c +++ b/libs/bluetooth/jswrap_bluetooth.c @@ -152,7 +152,7 @@ void jswrap_nrf_init() { // By default Puck.js's NFC will send you to the PuckJS website // address is included so Web Bluetooth can connect to the correct one JsVar *addr = jswrap_nrf_bluetooth_getAddress(); - JsVar *uri = jsvVarPrintf("https://puck-js.com/go?a=%v", addr); + JsVar *uri = jsvVarPrintf(NFC_DEFAULT_URL"?a=%v", addr); jsvUnLock(addr); jswrap_nrf_nfcURL(uri); jsvUnLock(uri); @@ -739,9 +739,9 @@ void jswrap_nrf_bluetooth_setAdvertising(JsVar *data, JsVar *options) { jsble_advertising_stop(); #ifdef NRF5X err_code = sd_ble_gap_adv_data_set((uint8_t *)dPtr, dLen, NULL, 0); -//#else -// err_code = 0xDEAD; -// jsiConsolePrintf("FIXME\n"); +#else + err_code = 0xDEAD; + jsiConsolePrintf("FIXME\n"); #endif #ifdef ESP32 err_code = bluetooth_gap_setAdvertizing(advArray); diff --git a/scripts/common.py b/scripts/common.py index f40130f22..740148070 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -371,7 +371,6 @@ def get_ifdef_description(d): if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)" if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)" if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js and MDBT42Q)" - if d=="PUCKJS": return "Puck.js devices" if d=="PIXLJS": return "Pixl.js boards" if d=="ESPRUINOWIFI": return "Espruino WiFi boards" if d=="ESP8266": return "ESP8266 devices running Espruino" @@ -381,11 +380,14 @@ def get_ifdef_description(d): if d=="USE_TLS": return "devices with TLS and SSL support (Espruino Pico and Espruino WiFi only)" if d=="RELEASE": return "release builds" if d=="LINUX": return "Linux-based builds" + if d=="DEBUG": return "debug builds" if d=="BLUETOOTH": return "devices with Bluetooth LE capability" if d=="USB": return "devices with USB" if d=="USE_USB_HID": return "devices that support USB HID (Espruino Pico and Espruino WiFi)" - if d=="USE_AES": return "devices that support AES (Espruino Pico, Espruino WiFi or Linux)" - if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Espruino WiFi, Linux or ESP8266)" + if d=="USE_AES": return "devices that support AES (Espruino Pico, Espruino WiFi or Linux, EPS32)" + if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Espruino WiFi, Linux or ESP8266, ESP32)" + if d=="USE_SHA256": return "devices that support SHA256 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux, ESP32)" + if d=="USE_SHA512": return "devices that support SHA512 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux, ESP32)" if d=="USE_FLASHFS": return "devices with filesystem in Flash support enabled (ESP32 only)" if d=="USE_TERMINAL": return "devices with VT100 terminal emulation enabled (Pixl.js only)" print("WARNING: Unknown ifdef '"+d+"' in common.get_ifdef_description") From 0181ed9bf52475a519975816dbf97c74bbfbb470 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Sun, 13 May 2018 15:27:22 +1200 Subject: [PATCH 12/15] update esp-idf to v3.0. BLE support - thanks to @jumjum. 2500 vars. Erase flash before flashing --- libs/bluetooth/jswrap_bluetooth.c | 4 +--- scripts/common.py | 19 ++++++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/libs/bluetooth/jswrap_bluetooth.c b/libs/bluetooth/jswrap_bluetooth.c index 7addd4b66..8d5cd324b 100644 --- a/libs/bluetooth/jswrap_bluetooth.c +++ b/libs/bluetooth/jswrap_bluetooth.c @@ -147,8 +147,7 @@ void jswrap_nrf_init() { if (jsiStatus & JSIS_COMPLETELY_RESET) { -#ifdef USE_NFC -#ifdef PUCKJS +#if defined(USE_NFC) && defined(NFC_DEFAULT_URL) // By default Puck.js's NFC will send you to the PuckJS website // address is included so Web Bluetooth can connect to the correct one JsVar *addr = jswrap_nrf_bluetooth_getAddress(); @@ -156,7 +155,6 @@ void jswrap_nrf_init() { jsvUnLock(addr); jswrap_nrf_nfcURL(uri); jsvUnLock(uri); -#endif #endif } else { #ifdef USE_NFC diff --git a/scripts/common.py b/scripts/common.py index 740148070..28cfe2ef6 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -184,6 +184,9 @@ def get_jsondata(is_for_document, parseArgs = True, board = False): if ("#ifdef" in jsondata) or ("#ifndef" in jsondata): sys.stderr.write( "'#ifdef' where 'ifdef' should be used in " + jsonstring + " - "+str(sys.exc_info()[0]) + "\n" ) exit(1) + if ("if" in jsondata): + sys.stderr.write( "'if' where '#if' should be used in " + jsonstring + " - "+str(sys.exc_info()[0]) + "\n" ) + exit(1) if ("#if" in jsondata): expr = jsondata["#if"] for defn in defines: @@ -371,25 +374,27 @@ def get_ifdef_description(d): if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)" if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)" if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js and MDBT42Q)" + if d=="PUCKJS": return "Puck.js devices" if d=="PIXLJS": return "Pixl.js boards" if d=="ESPRUINOWIFI": return "Espruino WiFi boards" - if d=="ESP8266": return "ESP8266 devices running Espruino" - if d=="ESP32": return "ESP32 devices" + if d=="ESP8266": return "ESP8266 boards running Espruino" + if d=="ESP32": return "ESP32 boards" if d=="EFM32": return "EFM32 devices" if d=="USE_LCD_SDL": return "Linux with SDL support compiled in" if d=="USE_TLS": return "devices with TLS and SSL support (Espruino Pico and Espruino WiFi only)" if d=="RELEASE": return "release builds" - if d=="LINUX": return "Linux-based builds" if d=="DEBUG": return "debug builds" + if d=="LINUX": return "Linux-based builds" if d=="BLUETOOTH": return "devices with Bluetooth LE capability" if d=="USB": return "devices with USB" if d=="USE_USB_HID": return "devices that support USB HID (Espruino Pico and Espruino WiFi)" - if d=="USE_AES": return "devices that support AES (Espruino Pico, Espruino WiFi or Linux, EPS32)" - if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Espruino WiFi, Linux or ESP8266, ESP32)" - if d=="USE_SHA256": return "devices that support SHA256 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux, ESP32)" - if d=="USE_SHA512": return "devices that support SHA512 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux, ESP32)" + if d=="USE_AES": return "devices that support AES (Espruino Pico, Espruino WiFi or Linux)" + if d=="USE_SHA256": return "devices that support SHA256 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux)" + if d=="USE_SHA512": return "devices that support SHA512 (Espruino Pico, Espruino WiFi, Espruino BLE devices or Linux)" + if d=="USE_CRYPTO": return "devices that support Crypto Functionality (Espruino Pico, Original, Espruino WiFi, Espruino BLE devices, Linux or ESP8266)" if d=="USE_FLASHFS": return "devices with filesystem in Flash support enabled (ESP32 only)" if d=="USE_TERMINAL": return "devices with VT100 terminal emulation enabled (Pixl.js only)" + if d=="USE_TELNET": return "devices with Telnet enabled (Linux, ESP8266 and ESP32)" print("WARNING: Unknown ifdef '"+d+"' in common.get_ifdef_description") return d From cdc1f4f92568bd8efd9333bb3f1b219802ee5a55 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Mon, 14 May 2018 11:33:44 +1200 Subject: [PATCH 13/15] Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cb20653e9..4e3c69c43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ - ESP32: update esp-idf to v3.0. BLE support - thanks to @jumjum. Erase flash before flashing + ESP32: update esp-idf to v3.0. BLE support - thanks to @jumjum. Erase flash before flashing. vars now 2500 Allow Crypto SHA1 without SHA256/512 (for Original & ESP8266 where flash is scarce) Add better docs for the form of Wifi callback functions Modify ESP8266/ESP32 callbacks to match the node.js style used elsewhere From 664fe948cbd2503da4754f19fbb65425dbc42407 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Mon, 14 May 2018 21:26:44 +1200 Subject: [PATCH 14/15] clean up conditions --- libs/bluetooth/jswrap_bluetooth.c | 32 +++++++++++++++---------------- libs/bluetooth/jswrap_bluetooth.h | 2 +- scripts/common.py | 11 +++++------ 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/libs/bluetooth/jswrap_bluetooth.c b/libs/bluetooth/jswrap_bluetooth.c index 8d5cd324b..e9e57aa35 100644 --- a/libs/bluetooth/jswrap_bluetooth.c +++ b/libs/bluetooth/jswrap_bluetooth.c @@ -294,7 +294,7 @@ Called when a host device disconnects from Espruino. "type" : "event", "class" : "NRF", "name" : "servicesDiscover", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Called with discovered services when discovery is finished */ @@ -302,7 +302,7 @@ Called with discovered services when discovery is finished "type" : "event", "class" : "NRF", "name" : "characteristicsDiscover", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Called with discovered characteristics when discovery is finished */ @@ -1939,7 +1939,7 @@ void jswrap_nrf_sendHIDReport(JsVar *data, JsVar *callback) { "type" : "staticmethod", "class" : "NRF", "name" : "requestDevice", - "ifdef" : "NRF52,ESP32", + "#if" : "defined(NRF52) || defined(ESP32)", "generate" : "jswrap_nrf_bluetooth_requestDevice", "params" : [ ["options","JsVar","Options used to filter the device to use"] @@ -2127,7 +2127,7 @@ JsVar *jswrap_nrf_bluetooth_requestDevice(JsVar *options) { "type" : "staticmethod", "class" : "NRF", "name" : "connect", - "ifdef" : "NRF52,ESP32", + "#if" : "defined(NRF52) || defined(ESP32)", "generate" : "jswrap_nrf_bluetooth_connect", "params" : [ ["mac","JsVar","The MAC address to connect to"] @@ -2230,7 +2230,7 @@ NRF.requestDevice({ filters: [{ name: 'Puck.js abcd' }] }).then(function(device) "type" : "property", "class" : "BluetoothDevice", "name" : "gatt", - "ifdef" : "NRF52,ESP32", + "#if" : "defined(NRF52) || defined(ESP32)", "generate" : "jswrap_BluetoothDevice_gatt", "return" : ["JsVar", "A `BluetoothRemoteGATTServer` for this device" ] } @@ -2255,7 +2255,7 @@ JsVar *jswrap_BluetoothDevice_gatt(JsVar *parent) { "type" : "method", "class" : "BluetoothRemoteGATTServer", "name" : "connect", - "ifdef" : "NRF52,ESP32", + "#if" : "defined(NRF52) || defined(ESP32)", "generate" : "jswrap_nrf_BluetoothRemoteGATTServer_connect", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the connection is complete" ] } @@ -2309,7 +2309,7 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTServer_connect(JsVar *parent) { /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTServer", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Web Bluetooth-style GATT server - get this using `NRF.connect(address)` or `NRF.requestDevice(options)` and `response.gatt.connect` @@ -2321,7 +2321,7 @@ or `NRF.requestDevice(options)` and `response.gatt.connect` "class" : "BluetoothRemoteGATTServer", "name" : "disconnect", "generate" : "jswrap_BluetoothRemoteGATTServer_disconnect", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Disconnect from a previously connected BLE device connected with `NRF.connect` - this does not disconnect from something that has @@ -2442,7 +2442,7 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTServer_getSecurityStatus(JsVar *parent) { "generate" : "jswrap_BluetoothRemoteGATTServer_getPrimaryService", "params" : [ ["service","JsVar","The service UUID"] ], "return" : ["JsVar", "A Promise that is resolved (or rejected) when the primary service is found (the argument contains a `BluetoothRemoteGATTService`)" ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } See `NRF.connect` for usage examples. */ @@ -2474,7 +2474,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryService(JsVar *parent, JsVar * "name" : "getPrimaryServices", "generate" : "jswrap_BluetoothRemoteGATTServer_getPrimaryServices", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the primary services are found (the argument contains an array of `BluetoothRemoteGATTService`)" ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } */ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) { @@ -2501,7 +2501,7 @@ JsVar *jswrap_BluetoothRemoteGATTServer_getPrimaryServices(JsVar *parent) { "params" : [ ["callback","JsVar","The callback to call with the RSSI value, or undefined to stop"] ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Start/stop listening for RSSI values on the active GATT connection @@ -2535,7 +2535,7 @@ void jswrap_BluetoothRemoteGATTServer_setRSSIHandler(JsVar *parent, JsVar *callb /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTService", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.getPrimaryService(s)` @@ -2548,7 +2548,7 @@ Web Bluetooth-style GATT service - get this using `BluetoothRemoteGATTServer.get "generate" : "jswrap_BluetoothRemoteGATTService_getCharacteristic", "params" : [ ["characteristic","JsVar","The characteristic UUID"] ], "return" : ["JsVar", "A Promise that is resolved (or rejected) when the characteristic is found (the argument contains a `BluetoothRemoteGATTCharacteristic`)" ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } See `NRF.connect` for usage examples. */ @@ -2580,7 +2580,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristic(JsVar *parent, JsVar "name" : "getCharacteristics", "generate" : "jswrap_BluetoothRemoteGATTService_getCharacteristics", "return" : ["JsVar", "A Promise that is resolved (or rejected) when the characteristic is found (the argument contains an array of `BluetoothRemoteGATTCharacteristic`)" ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } */ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) { @@ -2603,7 +2603,7 @@ JsVar *jswrap_BluetoothRemoteGATTService_getCharacteristics(JsVar *parent) { /*JSON{ "type" : "class", "class" : "BluetoothRemoteGATTCharacteristic", - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Web Bluetooth-style GATT characteristic - get this using `BluetoothRemoteGATTService.getCharacteristic(s)` @@ -2661,7 +2661,7 @@ JsVar *jswrap_nrf_BluetoothRemoteGATTCharacteristic_writeValue(JsVar *characteri "name" : "readValue", "generate" : "jswrap_nrf_BluetoothRemoteGATTCharacteristic_readValue", "return" : ["JsVar", "A Promise that is resolved (or rejected) with a `DataView` when the characteristic is read" ], - "ifdef" : "NRF52,ESP32" + "#if" : "defined(NRF52) || defined(ESP32)" } Read a characteristic's value, return a promise containing a `DataView` diff --git a/libs/bluetooth/jswrap_bluetooth.h b/libs/bluetooth/jswrap_bluetooth.h index b96a6e39f..b96e84528 100644 --- a/libs/bluetooth/jswrap_bluetooth.h +++ b/libs/bluetooth/jswrap_bluetooth.h @@ -33,7 +33,7 @@ typedef enum { #define BLETASK_IS_CENTRAL(x) ((x)>=BLETASK_CENTRAL_START && ((x)<=BLETASK_CENTRAL_END)) extern JsVar *bleTaskInfo; // info related to the current task -extern JsVar *blePromise; //defined here, used in jswrap_bluetooth.c and in ESP32 relevant bluetooth + bool bleInTask(BleTask task); BleTask bleGetCurrentTask(); bool bleNewTask(BleTask task, JsVar *taskInfo); diff --git a/scripts/common.py b/scripts/common.py index 28cfe2ef6..dccbf7fdb 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -173,9 +173,9 @@ def get_jsondata(is_for_document, parseArgs = True, board = False): elif "class" in jsondata: dropped_prefix += jsondata["class"]+" " drop = False if not is_for_document: - if ("ifndef" in jsondata) and (jsondata["ifndef"] in defines): - print(dropped_prefix+" because of #ifndef "+jsondata["ifndef"]) - drop = True + if ("ifdef" in jsondata) and not (jsondata["ifdef"] in defines): + print(dropped_prefix+" because of #ifdef "+jsondata["ifdef"]) + drop = True if ("ifdef" in jsondata): ifdefs = jsondata["ifdef"].encode('ascii','ignore').split(",") if(not [val for val in defines if val in ifdefs]): @@ -374,11 +374,10 @@ def get_ifdef_description(d): if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)" if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)" if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js and MDBT42Q)" - if d=="PUCKJS": return "Puck.js devices" if d=="PIXLJS": return "Pixl.js boards" if d=="ESPRUINOWIFI": return "Espruino WiFi boards" - if d=="ESP8266": return "ESP8266 boards running Espruino" - if d=="ESP32": return "ESP32 boards" + if d=="ESP8266": return "ESP8266 devices running Espruino" + if d=="ESP32": return "ESP32 devices" if d=="EFM32": return "EFM32 devices" if d=="USE_LCD_SDL": return "Linux with SDL support compiled in" if d=="USE_TLS": return "devices with TLS and SSL support (Espruino Pico and Espruino WiFi only)" From c9ae999afb9e4d33a205f7b620b0c92ae2cd8e29 Mon Sep 17 00:00:00 2001 From: wilberforce Date: Mon, 14 May 2018 21:41:42 +1200 Subject: [PATCH 15/15] clean up conditions --- ChangeLog | 2 +- scripts/common.py | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4e3c69c43..6e8fa88a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,3 @@ - ESP32: update esp-idf to v3.0. BLE support - thanks to @jumjum. Erase flash before flashing. vars now 2500 Allow Crypto SHA1 without SHA256/512 (for Original & ESP8266 where flash is scarce) Add better docs for the form of Wifi callback functions Modify ESP8266/ESP32 callbacks to match the node.js style used elsewhere @@ -13,6 +12,7 @@ Fixed double-connect issue for TCP sockets Pixl.js: Ensure Pixl.menu changes to bitmap fonts Pixl.js: tweaked bias/contrast to improve display quality + ESP32: update esp-idf to v3.0. BLE support - thanks to @jumjum. Erase flash before flashing. vars now 2500 1v97 : nRF52: fix NRF.on('connect',...) issue STM32: Fix setDeviceClockCmd error for USB.setConsole() diff --git a/scripts/common.py b/scripts/common.py index dccbf7fdb..48911dbce 100644 --- a/scripts/common.py +++ b/scripts/common.py @@ -173,14 +173,12 @@ def get_jsondata(is_for_document, parseArgs = True, board = False): elif "class" in jsondata: dropped_prefix += jsondata["class"]+" " drop = False if not is_for_document: + if ("ifndef" in jsondata) and (jsondata["ifndef"] in defines): + print(dropped_prefix+" because of #ifndef "+jsondata["ifndef"]) + drop = True if ("ifdef" in jsondata) and not (jsondata["ifdef"] in defines): print(dropped_prefix+" because of #ifdef "+jsondata["ifdef"]) - drop = True - if ("ifdef" in jsondata): - ifdefs = jsondata["ifdef"].encode('ascii','ignore').split(",") - if(not [val for val in defines if val in ifdefs]): - print(dropped_prefix+" because of #ifdef "+jsondata["ifdef"]) - drop = True + drop = True if ("#ifdef" in jsondata) or ("#ifndef" in jsondata): sys.stderr.write( "'#ifdef' where 'ifdef' should be used in " + jsonstring + " - "+str(sys.exc_info()[0]) + "\n" ) exit(1) @@ -374,10 +372,11 @@ def get_ifdef_description(d): if d=="STM32": return "STM32 devices (including Espruino Original, Pico and WiFi)" if d=="STM32F1": return "STM32F1 devices (including Original Espruino Board)" if d=="NRF52": return "NRF52 devices (like Puck.js, Pixl.js and MDBT42Q)" + if d=="PUCKJS": return "Puck.js devices" if d=="PIXLJS": return "Pixl.js boards" if d=="ESPRUINOWIFI": return "Espruino WiFi boards" - if d=="ESP8266": return "ESP8266 devices running Espruino" - if d=="ESP32": return "ESP32 devices" + if d=="ESP8266": return "ESP8266 boards running Espruino" + if d=="ESP32": return "ESP32 boards" if d=="EFM32": return "EFM32 devices" if d=="USE_LCD_SDL": return "Linux with SDL support compiled in" if d=="USE_TLS": return "devices with TLS and SSL support (Espruino Pico and Espruino WiFi only)"