Added non-functional ANCS interface. Needs to be refactored to be a class.

This commit is contained in:
James Hudson 2019-12-17 13:17:51 +01:00
parent 60d8063232
commit 40035b5d18
6 changed files with 300 additions and 50 deletions

View File

@ -3,9 +3,11 @@
#include "esp32notifications.h"
// Different hardware presets; feel free to add your own board layout.
// You will need to add these hardware buttons to your dev board.
// See the ESP32 pinout to choose a free GPIO pin.
// Different hardware presets; uncomment the correct device.
// Or feel free to add your own board layout for your specific hardware.
// See the ESP32 pinout to choose a free GPIO pin on your hardware.
// An inexpensive and easy-to build open-source smartwatch platform https://github.com/jhud/hackwatch
#define HARDWARE_HACKWATCH
#ifdef HARDWARE_HACKWATCH
@ -19,6 +21,8 @@
BLENotifications notifications;
// This callback will be called when a Bluetooth LE connection is made or broken.
// You can update the device's UI or take other action here.
void onBLEStateChanged(BLENotifications::State state) {
switch(state) {
case BLENotifications::StateConnected:
@ -32,11 +36,13 @@ void onBLEStateChanged(BLENotifications::State state) {
}
// A notification arrived from the mobile device, ie a social media notification or incoming call.
void onNotificationArrived() {
Serial.println("Got notification.");
}
// Called once when the device first starts up
void setup() {
// Button configuration
pinMode(BUTTON_A, INPUT_PULLUP);
@ -51,14 +57,14 @@ void setup() {
Serial.println("BLENotifications BLE ANCS on ESP32 Example");
Serial.println("------------------------------------------");
notifications.begin("deviceName");
// Set up the BLENotification library
notifications.begin("BLEConnection device name");
notifications.setConnectionStateChangedCallback(onBLEStateChanged);
notifications.setNotificationCallback(onNotificationArrived);
}
void checkButtons() {
if (digitalRead(BUTTON_A) == LOW) {
Serial.println("Positive action.");
notifications.actionPositive();

192
src/ancs_ble_client.cpp Normal file
View File

@ -0,0 +1,192 @@
// Based on the ANCS work of https://github.com/S-March
#include "ble_security.h"
#include "ancs_ble_client.h"
#include "BLEAddress.h"
#include "BLEDevice.h"
#include "BLEClient.h"
#include "BLEUtils.h"
#include "BLE2902.h"
#include "esp_log.h"
#include <Arduino.h> // Only for development
static char LOG_TAG[] = "ancs_ble_client";
// Fixed service IDs for the Apple ANCS service
const BLEUUID notificationSourceCharacteristicUUID("9FBF120D-6301-42D9-8C58-25E699A21DBD");
const BLEUUID controlPointCharacteristicUUID("69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9");
const BLEUUID dataSourceCharacteristicUUID("22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB");
const BLEUUID ancsServiceUUID("7905F431-B5CE-4E99-A40F-4B1E122D00D0");
// @todo - make into class or remove global data
uint8_t latestMessageID[4];
boolean pendingNotification = false;
BLERemoteCharacteristic* pControlPointCharacteristic;
#define MESSAGE_TITLE 1
#define MESSAGE_BODY 3
static void dataSourceNotifyCallback(
BLERemoteCharacteristic* pDataSourceCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify) {
Serial.print("Notify callback for characteristic ");
Serial.print(pDataSourceCharacteristic->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
for(int i = 0; i < length; i++){
if(i > 7){
Serial.write(pData[i]);
}
else{
Serial.print(pData[i], HEX);
Serial.print(" ");
}
}
Serial.println();
if ((pData[5] == MESSAGE_BODY || pData[5] == MESSAGE_TITLE) /*&& onMsgReceived*/) {
pData[length]=0;
//onMsgReceived(pData[5], (char*)pData+8); // @todo send msg received cb
}
}
static void notificationSourceNotifyCallback(
BLERemoteCharacteristic* pNotificationSourceCharacteristic,
uint8_t* pData,
size_t length,
bool isNotify)
{
if(pData[0]==0)
{
Serial.println("New notification!");
//Serial.println(pNotificationSourceCharacteristic->getUUID().toString().c_str());
latestMessageID[0] = pData[4];
latestMessageID[1] = pData[5];
latestMessageID[2] = pData[6];
latestMessageID[3] = pData[7];
switch(pData[2])
{
case 0:
Serial.println("Category: Other");
break;
case 1:
Serial.println("Category: Incoming call");
break;
case 2:
Serial.println("Category: Missed call");
break;
case 3:
Serial.println("Category: Voicemail");
break;
case 4:
Serial.println("Category: Social");
break;
case 5:
Serial.println("Category: Schedule");
break;
case 6:
Serial.println("Category: Email");
break;
case 7:
Serial.println("Category: News");
break;
case 8:
Serial.println("Category: Health");
break;
case 9:
Serial.println("Category: Business");
break;
case 10:
Serial.println("Category: Location");
break;
case 11:
Serial.println("Category: Entertainment");
break;
default:
break;
}
}
pendingNotification = true;
}
/**
* Become a BLE client to a remote BLE server. We are passed in the address of the BLE server
* as the input parameter when the task is created.
*/
void ancs_ble_client_init(const BLEAddress* address) {
BLEClient* pClient = BLEDevice::createClient();
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
BLEDevice::setSecurityCallbacks(new NotificationSecurityCallbacks()); // @todo memory leak?
BLESecurity *pSecurity = new BLESecurity();
pSecurity->setAuthenticationMode(ESP_LE_AUTH_REQ_SC_BOND);
pSecurity->setCapability(ESP_IO_CAP_IO);
pSecurity->setRespEncryptionKey(ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK);
// Connect to the remove BLE Server.
pClient->connect(*address);
/** BEGIN ANCS SERVICE **/
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pAncsService = pClient->getService(ancsServiceUUID);
if (pAncsService == nullptr) {
ESP_LOGD(LOG_TAG, "Failed to find service UUID ancsServiceUUID.");
return;
}
// Obtain a reference to the characteristic in the service of the remote BLE server.
BLERemoteCharacteristic* pNotificationSourceCharacteristic = pAncsService->getCharacteristic(notificationSourceCharacteristicUUID);
if (pNotificationSourceCharacteristic == nullptr) {
ESP_LOGD(LOG_TAG, "Failed to find characteristic UUID notificationSourceCharacteristicUUID");
return;
}
// Obtain a reference to the characteristic in the service of the remote BLE server.
pControlPointCharacteristic = pAncsService->getCharacteristic(controlPointCharacteristicUUID);
if (pControlPointCharacteristic == nullptr) {
ESP_LOGD(LOG_TAG, "Failed to find characteristic UUID: controlPointCharacteristicUUID");
return;
}
// Obtain a reference to the characteristic in the service of the remote BLE server.
BLERemoteCharacteristic* pDataSourceCharacteristic = pAncsService->getCharacteristic(dataSourceCharacteristicUUID);
if (pDataSourceCharacteristic == nullptr) {
ESP_LOGD(LOG_TAG, "Failed to find characteristic UUID dataSourceCharacteristicUUID");
return;
}
const uint8_t v[]={0x1,0x0};
pDataSourceCharacteristic->registerForNotify(dataSourceNotifyCallback);
pDataSourceCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,true);
pNotificationSourceCharacteristic->registerForNotify(notificationSourceNotifyCallback);
pNotificationSourceCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)v,2,true);
/** END ANCS SERVICE **/
}
BLEUUID getAncsServiceUUID() {
return ancsServiceUUID;
}
void ancs_ble_client_update() {
if(pendingNotification == true){
// CommandID: CommandIDGetNotificationAttributes
// 32bit uid
// AttributeID
ESP_LOGD(LOG_TAG, "Requesting details...");
const uint8_t vIdentifier[]={0x0, latestMessageID[0],latestMessageID[1],latestMessageID[2],latestMessageID[3], 0x0};
pControlPointCharacteristic->writeValue((uint8_t*)vIdentifier,6,true);
const uint8_t vTitle[]={0x0, latestMessageID[0],latestMessageID[1],latestMessageID[2],latestMessageID[3], 0x1, 0x0, 0x10};
pControlPointCharacteristic->writeValue((uint8_t*)vTitle,8,true);
const uint8_t vMessage[]={0x0, latestMessageID[0],latestMessageID[1],latestMessageID[2],latestMessageID[3], 0x3, 0x0, 0x10};
pControlPointCharacteristic->writeValue((uint8_t*)vMessage,8,true);
const uint8_t vDate[]={0x0, latestMessageID[0],latestMessageID[1],latestMessageID[2],latestMessageID[3], 0x5};
pControlPointCharacteristic->writeValue((uint8_t*)vDate,6,true);
pendingNotification = false;
}
delay(100); //does not work without small delay
}

18
src/ancs_ble_client.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef ANCS_BLE_CLIENT_H_
#define ANCS_BLE_CLIENT_H_
class BLEAddress;
class BLERemoteCharacteristic;
#include "BLEUUID.h"
/**
* Internal module for creating and managing an ANCS client connection.
*/
// @todo - should definitely be a class
void ancs_ble_client_init(const BLEAddress* address);
void ancs_ble_client_update();
BLEUUID getAncsServiceUUID();
#endif // ANCS_BLE_CLIENT_H_

36
src/ble_security.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "ble_security.h"
#include "esp_log.h"
static char LOG_TAG[] = "NotificationSecurityCallbacks";
uint32_t NotificationSecurityCallbacks::onPassKeyRequest(){
ESP_LOGI(LOG_TAG, "PassKeyRequest");
return 123456;
}
void NotificationSecurityCallbacks::onPassKeyNotify(uint32_t pass_key){
ESP_LOGI(LOG_TAG, "On passkey Notify number:%d", pass_key);
}
bool NotificationSecurityCallbacks::onSecurityRequest(){
ESP_LOGI(LOG_TAG, "On Security Request");
return true;
}
bool NotificationSecurityCallbacks::onConfirmPIN(unsigned int){
ESP_LOGI(LOG_TAG, "On Confrimed Pin Request");
return true;
}
void NotificationSecurityCallbacks::onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
ESP_LOGI(LOG_TAG, "Starting BLE work!");
if(cmpl.success){
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
ESP_LOGD(LOG_TAG, "size: %d", length);
}
}

19
src/ble_security.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef BLE_SECURITY_H_
#define BLE_SECURITY_H_
#include "BLESecurity.h"
class NotificationSecurityCallbacks : public BLESecurityCallbacks {
uint32_t onPassKeyRequest();
void onPassKeyNotify(uint32_t pass_key);
bool onSecurityRequest();
bool onConfirmPIN(unsigned int);
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl);
};
#endif // BLE_SECURITY_H_

View File

@ -1,6 +1,8 @@
// Based on https://github.com/espressif/esp-idf/tree/master/examples/bluetooth/bluedroid/ble/ble_ancs
#include "esp32notifications.h"
#include "ancs_ble_client.h"
#include "ble_security.h"
#include "BLEAddress.h"
#include "BLEDevice.h"
@ -13,37 +15,7 @@
static char LOG_TAG[] = "BLENotifications";
class MySecurity : public BLESecurityCallbacks {
uint32_t onPassKeyRequest(){
ESP_LOGI(LOG_TAG, "PassKeyRequest");
return 123456;
}
void onPassKeyNotify(uint32_t pass_key){
ESP_LOGI(LOG_TAG, "On passkey Notify number:%d", pass_key);
}
bool onSecurityRequest(){
ESP_LOGI(LOG_TAG, "On Security Request");
return true;
}
bool onConfirmPIN(unsigned int){
ESP_LOGI(LOG_TAG, "On Confrimed Pin Request");
return true;
}
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl){
ESP_LOGI(LOG_TAG, "Starting BLE work!");
if(cmpl.success){
uint16_t length;
esp_ble_gap_get_whitelist_size(&length);
ESP_LOGD(LOG_TAG, "size: %d", length);
}
}
};
extern const BLEUUID ancsServiceUUID;
class MyServerCallbacks: public BLEServerCallbacks {
private:
@ -64,22 +36,28 @@ public:
Serial.println("**Device connected**");
gatts_connect_evt_param * connectEventParam = (gatts_connect_evt_param *) param;
Serial.println(BLEAddress(connectEventParam->remote_bda).toString().c_str());
/*MyClient* pMyClient = new MyClient();
pMyClient->setStackSize(18000);
pMyClient->start(new BLEAddress(BLEDevice::m_remoteBda));*/ // @todo - memory leak?
//ANCSBLEClient* pMyClient = new ANCSBLEClient(); // @todo memory leak?
//pMyClient->setStackSize(18000); // @todo not needed?
ancs_ble_client_init(new BLEAddress(connectEventParam->remote_bda)); // @todo - memory leak?
delay(1000);
// Grab any pending notifications as a test
ancs_ble_client_update();
if (instance->cbStateChanged) {
instance->cbStateChanged(BLENotifications::StateConnected);
}
};
void onDisconnect(BLEServer* pServer) {
ESP_LOGI(LOG_TAG, "Device disconnected");
Serial.println("**Device disconnected**");
if (instance->cbStateChanged) {
instance->cbStateChanged(BLENotifications::StateDisconnected);
}
// @todo, disconnect, free stack?
}
void onDisconnect(BLEServer* pServer) {
ESP_LOGI(LOG_TAG, "Device disconnected");
Serial.println("**Device disconnected**");
if (instance->cbStateChanged) {
instance->cbStateChanged(BLENotifications::StateDisconnected);
}
// @todo, disconnect, free stack?
}
};
@ -96,7 +74,6 @@ bool BLENotifications::begin(const char * name) {
server = BLEDevice::createServer();
server->setCallbacks(new MyServerCallbacks(this));
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
BLEDevice::setSecurityCallbacks(new MySecurity());
startAdvertising();
}
@ -122,11 +99,13 @@ void BLENotifications::actionNegative() {
}
void BLENotifications::startAdvertising() {
// Start soliciting ANCS
BLEDevice::setSecurityCallbacks(new NotificationSecurityCallbacks()); // @todo memory leak?
// Start soliciting the Apple ANCS service and make the device visible to searches on iOS (from Apple ANCS documentation)
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
oAdvertisementData.setFlags(0x01);
oAdvertisementData.setServiceSolicitation(BLEUUID("7905F431-B5CE-4E99-A40F-4B1E122D00D0"));
oAdvertisementData.setServiceSolicitation(getAncsServiceUUID());
pAdvertising->setAdvertisementData(oAdvertisementData);
// Set security