263 lines
7.5 KiB
C++
263 lines
7.5 KiB
C++
#ifndef BLUETOOTH_h
|
|
#define BLUETOOTH_h
|
|
|
|
#include <NimBLEDevice.h>
|
|
#include "logger.h"
|
|
|
|
|
|
|
|
static bool doConnect = false;
|
|
static uint32_t scanTime = 0;
|
|
|
|
static NimBLEAdvertisedDevice* advDevice;
|
|
|
|
static void scanEndedCB(NimBLEScanResults results){
|
|
logger.log(5, "Scan Ended" );
|
|
} // END SCANENDEDCB
|
|
|
|
|
|
|
|
|
|
class ClientCallbacks : public NimBLEClientCallbacks {
|
|
void onConnect(NimBLEClient* pClient) {
|
|
logger.log(5, "Connected");
|
|
};
|
|
|
|
void onDisconnect(NimBLEClient* pClient) {
|
|
logger.log(5, "Disconnected - Starting Scan" );
|
|
NimBLEDevice::getScan()->start(scanTime, scanEndedCB);
|
|
};
|
|
bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params) {
|
|
if(params->itvl_min < 24) { /** 1.25ms units */
|
|
return false;
|
|
} else if(params->itvl_max > 40) { /** 1.25ms units */
|
|
return false;
|
|
} else if(params->latency > 2) { /** Number of intervals allowed to skip */
|
|
return false;
|
|
} else if(params->supervision_timeout > 100) { /** 10ms units */
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
uint32_t onPassKeyRequest(){
|
|
return 123456;
|
|
};
|
|
|
|
bool onConfirmPIN(uint32_t pass_key){
|
|
return true;
|
|
};
|
|
void onAuthenticationComplete(ble_gap_conn_desc* desc){
|
|
|
|
if(!desc->sec_state.encrypted) {
|
|
logger.log(5, "Encrypt connection failed.");
|
|
NimBLEDevice::getClientByID(desc->conn_handle)->disconnect();
|
|
return;
|
|
}
|
|
};
|
|
};// END CLIENTCALLBACK
|
|
|
|
class AdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
|
|
private:
|
|
LOGGER logger;
|
|
|
|
|
|
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
|
|
|
|
logger.log(5, advertisedDevice->toString().c_str() );
|
|
if(advertisedDevice->isAdvertisingService(NimBLEUUID::fromString("0x180F") ))
|
|
{
|
|
logger.log(5, "Service Found");
|
|
NimBLEDevice::getScan()->stop();
|
|
advDevice = advertisedDevice;
|
|
doConnect = true;
|
|
}
|
|
};
|
|
}; // END ADVERTISED CALLBACK
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BLUETOOTH
|
|
{
|
|
private:
|
|
|
|
ClientCallbacks clientCB;
|
|
|
|
|
|
|
|
static void notifyCB(NimBLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify){
|
|
std::string str = (isNotify == true) ? "Notification" : "Indication";
|
|
str += " from ";
|
|
/** NimBLEAddress and NimBLEUUID have std::string operators */
|
|
str += std::string(pRemoteCharacteristic->getRemoteService()->getClient()->getPeerAddress());
|
|
str += ": Service = " + std::string(pRemoteCharacteristic->getRemoteService()->getUUID());
|
|
str += ", Characteristic = " + std::string(pRemoteCharacteristic->getUUID());
|
|
str += ", Value = " + std::string((char*)pData, length);
|
|
logger.log(5,"NOTIFY CALLBACK ");
|
|
logger.log(5,str.c_str());
|
|
} // END NOTIFYCB
|
|
|
|
|
|
|
|
|
|
|
|
bool connectToServer() {
|
|
logger.log(5,"Connected To Server");
|
|
NimBLEClient* pClient = nullptr;
|
|
if(NimBLEDevice::getClientListSize()) {
|
|
pClient = NimBLEDevice::getClientByPeerAddress(advDevice->getAddress());
|
|
|
|
if(pClient){
|
|
|
|
if(!pClient->connect(advDevice, false)) {
|
|
logger.log(5,"Reconnect Failed");
|
|
return false;
|
|
}
|
|
logger.log(5,"Reconnected Client");
|
|
}
|
|
else {
|
|
|
|
pClient = NimBLEDevice::getDisconnectedClient();
|
|
}
|
|
}
|
|
|
|
if(!pClient) {
|
|
if(NimBLEDevice::getClientListSize() >= NIMBLE_MAX_CONNECTIONS) {
|
|
logger.log(5,"Max clients reached");
|
|
return false;
|
|
}
|
|
|
|
pClient = NimBLEDevice::createClient();
|
|
pClient->setClientCallbacks(&clientCB, false);
|
|
|
|
pClient->setConnectionParams(12,12,0,51);
|
|
|
|
/** Set how long we are willing to wait for the connection to complete (seconds), default is 30. */
|
|
pClient->setConnectTimeout(5);
|
|
logger.log(5,advDevice->toString().c_str());
|
|
if (!pClient->connect(advDevice)) {
|
|
|
|
NimBLEDevice::deleteClient(pClient);
|
|
logger.log(5,"Failed to connect, deleted client");
|
|
Serial.println("Failed to connect, deleted client");
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
if(!pClient->isConnected()) {
|
|
if (!pClient->connect(advDevice)) {
|
|
logger.log(5,"Failed to connect");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
logger.log(5,"Connected to");
|
|
logger.log(5,pClient->getPeerAddress().toString().c_str());
|
|
|
|
/** Now we can read/write/subscribe the charateristics of the services we are interested in */
|
|
NimBLERemoteService* pSvc = nullptr;
|
|
NimBLERemoteCharacteristic* pChr = nullptr;
|
|
NimBLERemoteDescriptor* pDsc = nullptr;
|
|
|
|
pSvc = pClient->getService(NimBLEUUID::fromString("0x181D"));
|
|
if(pSvc) { /** make sure it's not null */
|
|
logger.log(5,"Service found");
|
|
|
|
|
|
pChr = pSvc->getCharacteristic(NimBLEUUID::fromString("0x2A9D"));
|
|
|
|
if(pChr) { /** make sure it's not null */
|
|
logger.log(5,"Charactheristic found");
|
|
|
|
if(pChr->canRead()) {
|
|
logger.log(5,"Can read");
|
|
|
|
|
|
Serial.print(pChr->getUUID().toString().c_str());
|
|
Serial.print(" Value: ");
|
|
Serial.println(pChr->readValue().c_str());
|
|
}
|
|
|
|
|
|
/** registerForNotify() has been deprecated and replaced with subscribe() / unsubscribe().
|
|
* Subscribe parameter defaults are: notifications=true, notifyCallback=nullptr, response=false.
|
|
* Unsubscribe parameter defaults are: response=false.
|
|
*/
|
|
if(pChr->canNotify()) {
|
|
logger.log(5,"Can Notify");
|
|
|
|
//if(!pChr->registerForNotify(notifyCB)) {
|
|
if(!pChr->subscribe(true, notifyCB)) {
|
|
/** Disconnect if subscribe failed */
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
}
|
|
else if(pChr->canIndicate()) {
|
|
logger.log(5,"Can indicate");
|
|
|
|
|
|
/** Send false as first argument to subscribe to indications instead of notifications */
|
|
//if(!pChr->registerForNotify(notifyCB, false)) {
|
|
if(!pChr->subscribe(false, notifyCB)) {
|
|
/** Disconnect if subscribe failed */
|
|
pClient->disconnect();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
} else {
|
|
logger.log(5,"Service not found");
|
|
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
BLUETOOTH () {} // CONSTRUCTOR
|
|
|
|
void setup (){
|
|
|
|
NimBLEDevice::init("");
|
|
NimBLEDevice::setSecurityAuth(/*BLE_SM_PAIR_AUTHREQ_BOND | BLE_SM_PAIR_AUTHREQ_MITM |*/ BLE_SM_PAIR_AUTHREQ_SC);
|
|
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
|
|
NimBLEScan* pScan = NimBLEDevice::getScan();
|
|
pScan->setAdvertisedDeviceCallbacks(new AdvertisedDeviceCallbacks());
|
|
pScan->setInterval(45);
|
|
pScan->setWindow(15);
|
|
pScan->setActiveScan(true);
|
|
pScan->start(scanTime, scanEndedCB);
|
|
} // setup()
|
|
|
|
void loop (){
|
|
if(doConnect){
|
|
Serial.println("doCOnnect=true");
|
|
if(connectToServer()) {
|
|
logger.log(1, "Connected to BLE");
|
|
|
|
Serial.println("Success! we should now be getting notifications, scanning for more!");
|
|
} else {
|
|
Serial.println("Failed to connect, starting scan");
|
|
}
|
|
NimBLEDevice::getScan()->start(scanTime,scanEndedCB);
|
|
|
|
}
|
|
doConnect = false;
|
|
|
|
|
|
} // loop()
|
|
};
|
|
#endif
|