Espruino/targets/esp32/BLE/esp32_bluetooth_utils.c
Gordon Williams 891029bfde ESP32: Bluetooth LE tweaks - central mode connects, scans, reads, writes and notifies
Bluetooth: fix for incorrect Bluetooth task strings shown in some errors
Tried to move common code in jsble_exec_pending into jsble_exec_pending_common
2022-10-27 15:28:28 +01:00

327 lines
11 KiB
C

/*
* 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 "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"
#include "freertos/FreeRTOS.h"
#include "jsvariterator.h"
esp_ble_debug_t bleEventDebug = 0;
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("bleuuid_TO_espbtuuid unknown UUID TYPE\n");
}
}
void espbtuuid_TO_bleuuid(esp_bt_uuid_t esp_uuid, ble_uuid_t *ble_uuid) {
switch(esp_uuid.len) {
case ESP_UUID_LEN_16:
ble_uuid->type = BLE_UUID_TYPE_BLE;
ble_uuid->uuid = esp_uuid.uuid.uuid16;
break;
case ESP_UUID_LEN_128:
ble_uuid->type = BLE_UUID_TYPE_128;
for(int i = 0; i < 16; i++)
ble_uuid->uuid128[i] = esp_uuid.uuid.uuid128[i];
break;
default:
jsError("espbtuuid_TO_bleuuid 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");
}
}
bool espbtuuid_equal(esp_bt_uuid_t a, esp_bt_uuid_t b) {
return
(a.len == ESP_UUID_LEN_16 && b.len == ESP_UUID_LEN_16 && a.uuid.uuid16 == b.uuid.uuid16) ||
(a.len == ESP_UUID_LEN_32 && b.len == ESP_UUID_LEN_32 && a.uuid.uuid32 == b.uuid.uuid32) ||
(a.len == ESP_UUID_LEN_128 && b.len == ESP_UUID_LEN_128 && memcmp(a.uuid.uuid128, b.uuid.uuid128, ESP_UUID_LEN_128)==0);
}
void bleaddr_TO_espbtaddr(ble_gap_addr_t ble_addr, esp_bd_addr_t remote_bda, esp_ble_addr_type_t *remote_bda_type) {
memcpy(remote_bda, ble_addr.addr, sizeof(esp_bd_addr_t));
// reverse bytes in address
int x, n = 5;
uint8_t t;
for(x = 0; x < n;) {
t = remote_bda[x];
remote_bda[x] = remote_bda[n];
remote_bda[n] = t;
x++;
n--;
}
// BLE_GAP_ADDR_TYPES and esp_ble_addr_type_t match (no need for conversion)
*remote_bda_type = ble_addr.addr_type;
}