update esp-idf to v3.0. BLE support - thanks to @jumjum. 2500 vars. Erase flash before flashing

This commit is contained in:
wilberforce 2018-05-13 13:54:02 +12:00
parent c5921bd803
commit 883000cf81
22 changed files with 1984 additions and 56 deletions

View File

@ -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()

View File

@ -19,7 +19,7 @@ info = {
'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',

View File

@ -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
}

View File

@ -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 @@ https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
"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 @@ https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
"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;

View File

@ -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);

View File

@ -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

View File

@ -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")

View File

@ -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
)

View File

@ -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
)

View File

@ -0,0 +1,292 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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");
}
}

View File

@ -0,0 +1,57 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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_ */

View File

@ -0,0 +1,279 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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 <stdio.h>
#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));
}

View File

@ -0,0 +1,36 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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_ */

View File

@ -0,0 +1,247 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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 <stdio.h>
#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);
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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_ */

View File

@ -0,0 +1,554 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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 <stdio.h>
#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);
}
}
}
}

View File

@ -0,0 +1,80 @@
/*
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2017 Gordon Williams <gw@pur3.co.uk>
*
* 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_ */

203
targets/esp32/bluetooth.c Normal file
View File

@ -0,0 +1,203 @@
/**
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
*
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
*
* 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 <stdio.h>
#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;
}

View File

@ -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);
}
}

View File

@ -12,13 +12,24 @@
* ----------------------------------------------------------------------------
*/
#include <stdio.h>
#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

View File

@ -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_ */

View File

@ -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();