2020-02-01 16:30:53 +00:00
# include "BluetoothUtil.h"
# include "BluetoothSoftwareUpdate.h"
# include <esp_gatt_defs.h>
# include <BLE2902.h>
# include <Arduino.h>
# include <Update.h>
2020-02-04 16:17:44 +00:00
# include "configuration.h"
2020-02-08 04:59:21 +00:00
# include "screen.h"
2020-02-01 16:30:53 +00:00
2020-02-23 18:49:37 +00:00
SimpleAllocator btPool ;
2020-02-01 16:30:53 +00:00
/**
* Create standard device info service
* */
2020-02-19 00:18:01 +00:00
BLEService * createDeviceInfomationService ( BLEServer * server , std : : string hwVendor , std : : string swVersion , std : : string hwVersion = " " )
2020-02-08 04:59:21 +00:00
{
BLEService * deviceInfoService = server - > createService ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_DEVICE_INFO_SVC ) ) ;
2020-02-01 16:30:53 +00:00
2020-02-24 00:41:27 +00:00
BLECharacteristic * swC = new BLECharacteristic ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_SW_VERSION_STR ) , BLECharacteristic : : PROPERTY_READ ) ;
BLECharacteristic * mfC = new BLECharacteristic ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_MANU_NAME ) , BLECharacteristic : : PROPERTY_READ ) ;
2020-02-23 19:05:55 +00:00
// BLECharacteristic SerialNumberCharacteristic(BLEUUID((uint16_t) ESP_GATT_UUID_SERIAL_NUMBER_STR), BLECharacteristic::PROPERTY_READ);
2020-02-08 04:59:21 +00:00
/*
2020-02-01 16:30:53 +00:00
* Mandatory characteristic for device info service ?
BLECharacteristic * m_pnpCharacteristic = m_deviceInfoService - > createCharacteristic ( ESP_GATT_UUID_PNP_ID , BLECharacteristic : : PROPERTY_READ ) ;
uint8_t sig , uint16_t vid , uint16_t pid , uint16_t version ;
uint8_t pnp [ ] = { sig , ( uint8_t ) ( vid > > 8 ) , ( uint8_t ) vid , ( uint8_t ) ( pid > > 8 ) , ( uint8_t ) pid , ( uint8_t ) ( version > > 8 ) , ( uint8_t ) version } ;
m_pnpCharacteristic - > setValue ( pnp , sizeof ( pnp ) ) ;
*/
2020-02-23 19:05:55 +00:00
swC - > setValue ( swVersion ) ;
2020-02-24 00:41:27 +00:00
deviceInfoService - > addCharacteristic ( addBLECharacteristic ( swC ) ) ;
2020-02-23 19:05:55 +00:00
mfC - > setValue ( hwVendor ) ;
2020-02-24 00:41:27 +00:00
deviceInfoService - > addCharacteristic ( addBLECharacteristic ( mfC ) ) ;
2020-02-19 00:18:01 +00:00
if ( ! hwVersion . empty ( ) )
{
2020-02-24 00:41:27 +00:00
BLECharacteristic * hwvC = new BLECharacteristic ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_HW_VERSION_STR ) , BLECharacteristic : : PROPERTY_READ ) ;
2020-02-23 19:05:55 +00:00
hwvC - > setValue ( hwVersion ) ;
2020-02-24 00:41:27 +00:00
deviceInfoService - > addCharacteristic ( addBLECharacteristic ( hwvC ) ) ;
2020-02-19 00:18:01 +00:00
}
2020-02-08 04:59:21 +00:00
//SerialNumberCharacteristic.setValue("FIXME");
//deviceInfoService->addCharacteristic(&SerialNumberCharacteristic);
// m_manufacturerCharacteristic = m_deviceInfoService->createCharacteristic((uint16_t) 0x2a29, BLECharacteristic::PROPERTY_READ);
// m_manufacturerCharacteristic->setValue(name);
/* add these later?
2020-02-01 16:30:53 +00:00
ESP_GATT_UUID_SYSTEM_ID
*/
2020-02-08 04:59:21 +00:00
// caller must call service->start();
return deviceInfoService ;
2020-02-01 16:30:53 +00:00
}
bool _BLEClientConnected = false ;
2020-02-08 04:59:21 +00:00
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect ( BLEServer * pServer )
{
_BLEClientConnected = true ;
} ;
void onDisconnect ( BLEServer * pServer )
{
_BLEClientConnected = false ;
}
2020-02-01 16:30:53 +00:00
} ;
2020-02-24 00:41:27 +00:00
# define MAX_DESCRIPTORS 32
# define MAX_CHARACTERISTICS 32
static BLECharacteristic * chars [ MAX_CHARACTERISTICS ] ;
static size_t numChars ;
static BLEDescriptor * descs [ MAX_DESCRIPTORS ] ;
static size_t numDescs ;
/// Add a characteristic that we will delete when we restart
BLECharacteristic * addBLECharacteristic ( BLECharacteristic * c )
{
assert ( numChars < MAX_CHARACTERISTICS ) ;
chars [ numChars + + ] = c ;
return c ;
}
/// Add a characteristic that we will delete when we restart
BLEDescriptor * addBLEDescriptor ( BLEDescriptor * c )
{
assert ( numDescs < MAX_DESCRIPTORS ) ;
descs [ numDescs + + ] = c ;
return c ;
}
2020-02-01 16:30:53 +00:00
// Help routine to add a description to any BLECharacteristic and add it to the service
2020-02-08 04:59:21 +00:00
// We default to require an encrypted BOND for all these these characterstics
void addWithDesc ( BLEService * service , BLECharacteristic * c , const char * description )
{
c - > setAccessPermissions ( ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED ) ;
2020-02-24 00:41:27 +00:00
BLEDescriptor * desc = new BLEDescriptor ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_CHAR_DESCRIPTION ) , strlen ( description ) + 1 ) ;
2020-02-04 01:13:41 +00:00
assert ( desc ) ;
2020-02-08 04:59:21 +00:00
desc - > setAccessPermissions ( ESP_GATT_PERM_READ_ENCRYPTED | ESP_GATT_PERM_WRITE_ENCRYPTED ) ;
2020-02-01 16:30:53 +00:00
desc - > setValue ( description ) ;
c - > addDescriptor ( desc ) ;
service - > addCharacteristic ( c ) ;
2020-02-24 00:41:27 +00:00
addBLECharacteristic ( c ) ;
addBLEDescriptor ( desc ) ;
2020-02-01 16:30:53 +00:00
}
2020-02-23 19:05:55 +00:00
static BLECharacteristic * batteryLevelC ;
2020-02-23 18:49:37 +00:00
2020-02-01 16:30:53 +00:00
/**
* Create a battery level service
*/
2020-02-08 04:59:21 +00:00
BLEService * createBatteryService ( BLEServer * server )
{
// Create the BLE Service
BLEService * pBattery = server - > createService ( BLEUUID ( ( uint16_t ) 0x180F ) ) ;
2020-02-01 16:30:53 +00:00
2020-02-24 00:41:27 +00:00
batteryLevelC = new BLECharacteristic ( BLEUUID ( ( uint16_t ) ESP_GATT_UUID_BATTERY_LEVEL ) , BLECharacteristic : : PROPERTY_READ | BLECharacteristic : : PROPERTY_NOTIFY ) ;
2020-02-23 19:05:55 +00:00
addWithDesc ( pBattery , batteryLevelC , " Percentage 0 - 100 " ) ;
2020-02-24 00:41:27 +00:00
batteryLevelC - > addDescriptor ( addBLEDescriptor ( new BLE2902 ( ) ) ) ; // Needed so clients can request notification
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
// I don't think we need to advertise this
// server->getAdvertising()->addServiceUUID(pBattery->getUUID());
pBattery - > start ( ) ;
2020-02-02 21:37:02 +00:00
2020-02-08 04:59:21 +00:00
return pBattery ;
2020-02-01 16:30:53 +00:00
}
2020-02-02 21:37:02 +00:00
/**
* Update the battery level we are currently telling clients .
* level should be a pct between 0 and 100
*/
2020-02-08 04:59:21 +00:00
void updateBatteryLevel ( uint8_t level )
{
// Pretend to update battery levels - fixme do elsewhere
2020-02-23 19:05:55 +00:00
if ( batteryLevelC )
{
batteryLevelC - > setValue ( & level , 1 ) ;
batteryLevelC - > notify ( ) ;
}
2020-02-02 21:37:02 +00:00
}
2020-02-08 04:59:21 +00:00
void dumpCharacteristic ( BLECharacteristic * c )
{
std : : string value = c - > getValue ( ) ;
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
if ( value . length ( ) > 0 )
{
DEBUG_MSG ( " New value: " ) ;
for ( int i = 0 ; i < value . length ( ) ; i + + )
DEBUG_MSG ( " %c " , value [ i ] ) ;
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
DEBUG_MSG ( " \n " ) ;
}
2020-02-01 16:30:53 +00:00
}
/** converting endianness pull out a 32 bit value */
2020-02-08 04:59:21 +00:00
uint32_t getValue32 ( BLECharacteristic * c , uint32_t defaultValue )
{
std : : string value = c - > getValue ( ) ;
uint32_t r = defaultValue ;
if ( value . length ( ) = = 4 )
r = value [ 0 ] | ( value [ 1 ] < < 8UL ) | ( value [ 2 ] < < 16UL ) | ( value [ 3 ] < < 24UL ) ;
return r ;
2020-02-01 16:30:53 +00:00
}
2020-02-08 04:59:21 +00:00
class MySecurity : public BLESecurityCallbacks
{
bool onConfirmPIN ( uint32_t pin )
{
Serial . printf ( " onConfirmPIN %u \n " , pin ) ;
return false ;
}
uint32_t onPassKeyRequest ( )
{
Serial . println ( " onPassKeyRequest " ) ;
return 123511 ; // not used
}
void onPassKeyNotify ( uint32_t pass_key )
{
Serial . printf ( " onPassKeyNotify %u \n " , pass_key ) ;
screen_start_bluetooth ( pass_key ) ;
}
bool onSecurityRequest ( )
{
Serial . println ( " onSecurityRequest " ) ;
return true ;
}
void onAuthenticationComplete ( esp_ble_auth_cmpl_t cmpl )
{
if ( cmpl . success )
{
uint16_t length ;
esp_ble_gap_get_whitelist_size ( & length ) ;
Serial . printf ( " onAuthenticationComplete -> success size: %d \n " , length ) ;
}
else
{
Serial . printf ( " onAuthenticationComplete -> fail %d \n " , cmpl . fail_reason ) ;
}
// Remove our custom screen
2020-03-05 00:46:57 +00:00
screen . setFrames ( ) ;
2020-02-08 04:59:21 +00:00
}
} ;
2020-02-23 21:54:40 +00:00
BLEServer * pServer ;
BLEService * pDevInfo , * pUpdate ;
2020-02-23 19:05:55 +00:00
void deinitBLE ( )
{
2020-02-23 21:54:40 +00:00
assert ( pServer ) ;
2020-02-24 02:09:40 +00:00
pServer - > getAdvertising ( ) - > stop ( ) ;
destroyUpdateService ( ) ;
pUpdate - > stop ( ) ;
pDevInfo - > stop ( ) ;
pUpdate - > stop ( ) ; // we delete them below
2020-02-23 21:54:40 +00:00
// First shutdown bluetooth
BLEDevice : : deinit ( false ) ;
// do not delete this - it is dynamically allocated, but only once - statically in BLEDevice
// delete pServer->getAdvertising();
delete pUpdate ;
delete pDevInfo ;
delete pServer ;
2020-02-23 19:05:55 +00:00
batteryLevelC = NULL ; // Don't let anyone generate bogus notifies
2020-02-23 21:54:40 +00:00
2020-02-24 00:41:27 +00:00
for ( int i = 0 ; i < numChars ; i + + )
delete chars [ i ] ;
numChars = 0 ;
for ( int i = 0 ; i < numDescs ; i + + )
delete descs [ i ] ;
numDescs = 0 ;
2020-02-23 19:05:55 +00:00
btPool . reset ( ) ;
}
2020-02-14 22:00:08 +00:00
BLEServer * initBLE ( std : : string deviceName , std : : string hwVendor , std : : string swVersion , std : : string hwVersion )
2020-02-08 04:59:21 +00:00
{
BLEDevice : : init ( deviceName ) ;
BLEDevice : : setEncryptionLevel ( ESP_BLE_SEC_ENCRYPT ) ;
/*
* Required in authentication process to provide displaying and / or input passkey or yes / no butttons confirmation
*/
2020-02-23 18:49:37 +00:00
static MySecurity mySecurity ;
BLEDevice : : setSecurityCallbacks ( & mySecurity ) ;
2020-02-08 04:59:21 +00:00
// Create the BLE Server
2020-02-23 21:54:40 +00:00
pServer = BLEDevice : : createServer ( ) ;
2020-02-23 18:49:37 +00:00
static MyServerCallbacks myCallbacks ;
pServer - > setCallbacks ( & myCallbacks ) ;
2020-02-01 16:30:53 +00:00
2020-02-23 21:54:40 +00:00
pDevInfo = createDeviceInfomationService ( pServer , hwVendor , swVersion , hwVersion ) ;
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
// We now let users create the battery service only if they really want (not all devices have a battery)
// BLEService *pBattery = createBatteryService(pServer);
2020-02-01 16:30:53 +00:00
2020-02-24 18:24:21 +00:00
pUpdate = createUpdateService ( pServer , hwVendor , swVersion , hwVersion ) ; // We need to advertise this so our android ble scan operation can see it
2020-02-19 00:18:01 +00:00
2020-02-13 19:53:46 +00:00
// It seems only one service can be advertised - so for now don't advertise our updater
// pServer->getAdvertising()->addServiceUUID(pUpdate->getUUID());
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
// start all our services (do this after creating all of them)
pDevInfo - > start ( ) ;
pUpdate - > start ( ) ;
2020-02-01 16:30:53 +00:00
2020-02-09 00:17:31 +00:00
// FIXME turn on this restriction only after the device is paired with a phone
// advert->setScanFilter(false, true); // We let anyone scan for us (FIXME, perhaps only allow that until we are paired with a phone and configured) but only let whitelist phones connect
2020-02-13 19:53:46 +00:00
2020-02-23 18:49:37 +00:00
static BLESecurity security ; // static to avoid allocs
BLESecurity * pSecurity = & security ;
2020-02-08 04:59:21 +00:00
pSecurity - > setCapability ( ESP_IO_CAP_OUT ) ;
pSecurity - > setAuthenticationMode ( ESP_LE_AUTH_REQ_SC_BOND ) ;
pSecurity - > setInitEncryptionKey ( ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK ) ;
2020-02-01 16:30:53 +00:00
2020-02-08 04:59:21 +00:00
return pServer ;
2020-02-01 16:30:53 +00:00
}
// Called from loop
2020-02-08 04:59:21 +00:00
void loopBLE ( )
{
bluetoothRebootCheck ( ) ;
2020-02-01 16:30:53 +00:00
}