mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
314 lines
10 KiB
C
314 lines
10 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 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");
|
|
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 connection 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;
|
|
}
|
|
case ESP_GAP_BLE_SEC_REQ_EVT:{
|
|
esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true);
|
|
break;
|
|
}
|
|
default:{
|
|
gap_event_scan_handler(event,param);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void bluetooth_gap_setScan(bool 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);
|
|
if(deviceName){
|
|
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];
|
|
nameLen += 2;
|
|
}
|
|
jsvUnLock(deviceName);
|
|
return nameLen + 2;
|
|
}
|
|
else return 0;
|
|
}
|
|
|
|
int addAdvertisingUart(uint8_t *advData,int pnt){
|
|
uint8_t *uart_adv;
|
|
uart_adv = getUartAdvice();
|
|
for(int i = 0; i < 18; i++){ advData[pnt + i] = uart_adv[i];}
|
|
return 18;
|
|
}
|
|
|
|
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);
|
|
if (jsvGetBoolAndUnLock(jsvObjectGetChild(options, "uart", 0))){
|
|
i = i + addAdvertisingUart(&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_efuse_mac_get_default(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));
|
|
}
|
|
|
|
void gap_init_security(){
|
|
/* set the security iocap & auth_req & key size & init key response key parameters to the stack*/
|
|
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_BOND; //bonding with peer device after authentication
|
|
esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; //set the IO capability to No output No input
|
|
uint8_t key_size = 16; //the key size should be 7~16 bytes
|
|
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
|
|
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
|
|
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
|
|
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
|
|
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
|
|
/* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribut to you,
|
|
and the response key means which key you can distribut to the Master;
|
|
If your BLE device act as a master, the response key means you hope which types of key of the slave should distribut to you,
|
|
and the init key means which key you can distribut to the slave. */
|
|
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
|
|
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
|
|
}
|