Skip to content

Fix timing issue during pairing, add pairing control/status methods #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
#include <ArduinoBLE.h>


#define PAIR_BUTTON D3 // button for pairing
#define PAIR_LED 24 // LED used to signal pairing
#define PAIR_LED_ON LOW // Blue LED on Nano BLE has inverted logic
#define PAIR_INTERVAL 30000 // interval for pairing after button press in ms

#define CTRL_LED LED_BUILTIN


// BLE Battery Service
BLEService batteryService("180F");

Expand All @@ -31,13 +39,17 @@ BLEStringCharacteristic stringcharacteristic("183E", BLERead | BLEWrite, 31);
BLEUnsignedCharCharacteristic secretValue("2a3F", BLERead | BLEWrite | BLEEncryption);

int oldBatteryLevel = 0; // last battery level reading from analog input
long previousMillis = 0; // last time the battery level was checked, in ms
unsigned long previousMillis = 0; // last time the battery level was checked, in ms
unsigned long pairingStarted = 0; // pairing start time when button is pressed
bool wasConnected = 0;

void setup() {
Serial.begin(9600); // initialize serial communication
while (!Serial);

pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
pinMode(CTRL_LED, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected
pinMode(PAIR_LED, OUTPUT);
pinMode(PAIR_BUTTON, INPUT_PULLUP);


Serial.println("Serial connected");
Expand Down Expand Up @@ -145,6 +157,9 @@ void setup() {
secretValue.writeValue(0);

delay(1000);

// prevent pairing until button is pressed (will show a pairing rejected message)
BLE.setPairable(false);

/* Start advertising BLE. It will start continuously transmitting BLE
advertising packets and will be visible to remote BLE central devices
Expand All @@ -169,30 +184,44 @@ void loop() {
// wait for a BLE central
BLEDevice central = BLE.central();


// If button is pressed, allow pairing for 30 sec
if (!BLE.pairable() && digitalRead(PAIR_BUTTON) == LOW){
pairingStarted = millis();
BLE.setPairable(Pairable::ONCE);
Serial.println("Accepting pairing for 30s");
} else if (BLE.pairable() && millis() > pairingStarted + PAIR_INTERVAL){
BLE.setPairable(false);
Serial.println("No longer accepting pairing");
}
// Make LED blink while pairing is allowed
digitalWrite(PAIR_LED, (BLE.pairable() ? (millis()%400)<200 : BLE.paired()) ? PAIR_LED_ON : !PAIR_LED_ON);


// if a central is connected to the peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's BT address:
Serial.println(central.address());
if (central && central.connected()) {
if (!wasConnected){
wasConnected = true;
Serial.print("Connected to central: ");
// print the central's BT address:
Serial.println(central.address());
}

// check the battery level every 200ms
// while the central is connected:
while (central.connected()) {
long currentMillis = millis();
// if 200ms have passed, check the battery level:
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
updateBatteryLevel();
if(secretValue.value()>0){
digitalWrite(13,HIGH);
}else{
digitalWrite(13,LOW);
}
}
long currentMillis = millis();
// if 200ms have passed, check the battery level:
if (currentMillis - previousMillis >= 1000) {
previousMillis = currentMillis;
updateBatteryLevel();
digitalWrite(CTRL_LED, secretValue.value()>0 ? HIGH : LOW);
}
} else if (wasConnected){
wasConnected = false;
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}

}

void updateBatteryLevel() {
Expand All @@ -208,4 +237,4 @@ void updateBatteryLevel() {
batteryLevelChar.writeValue(batteryLevel); // and update the battery level characteristic
oldBatteryLevel = batteryLevel; // save the level for next comparison
}
}
}
3 changes: 3 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,12 @@ setEventHandler KEYWORD2
setAdvertisingInterval KEYWORD2
setConnectionInterval KEYWORD2
setConnectable KEYWORD2
setPairable KEYWORD2
setTimeout KEYWORD2
debug KEYWORD2
noDebug KEYWORD2
pairable KEYWORD2
paired KEYWORD2

properties KEYWORD2
valueSize KEYWORD2
Expand Down
26 changes: 26 additions & 0 deletions src/local/BLELocalDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,16 @@ bool BLELocalDevice::connected() const
return ATT.connected();
}

/*
* Whether there is at least one paired device
*/
bool BLELocalDevice::paired()
{
HCI.poll();

return ATT.paired();
}

bool BLELocalDevice::disconnect()
{
return ATT.disconnect();
Expand Down Expand Up @@ -395,6 +405,22 @@ void BLELocalDevice::setTimeout(unsigned long timeout)
ATT.setTimeout(timeout);
}

/*
* Control whether pairing is allowed or rejected
* Use true/false or the Pairable enum
*/
void BLELocalDevice::setPairable(uint8_t pairable)
{
L2CAPSignaling.setPairingEnabled(pairable);
}

/*
* Whether pairing is currently allowed
*/
bool BLELocalDevice::pairable()
{
return L2CAPSignaling.isPairingEnabled();
}

void BLELocalDevice::setGetIRKs(int (*getIRKs)(uint8_t* nIRKs, uint8_t** BADDR_type, uint8_t*** BADDRs, uint8_t*** IRKs)){
HCI._getIRKs = getIRKs;
Expand Down
10 changes: 10 additions & 0 deletions src/local/BLELocalDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@
#include "BLEService.h"
#include "BLEAdvertisingData.h"

enum Pairable {
NO = 0,
YES = 1,
ONCE = 2,
};

class BLELocalDevice {
public:
BLELocalDevice();
Expand Down Expand Up @@ -80,6 +86,10 @@ class BLELocalDevice {

virtual void debug(Stream& stream);
virtual void noDebug();

virtual void setPairable(uint8_t pairable);
virtual bool pairable();
virtual bool paired();

/// TODO: Put in actual variable names
virtual void setStoreIRK(int (*storeIRK)(uint8_t*, uint8_t*));
Expand Down
26 changes: 26 additions & 0 deletions src/utility/ATT.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,32 @@ bool ATTClass::connected(uint16_t handle) const
return false;
}

/*
* Return true if any of the known devices is paired (peer encrypted)
* Does not check if the paired device is also connected
*/
bool ATTClass::paired() const
{
for(int i=0; i<ATT_MAX_PEERS; i++){
if((_peers[i].encryption & PEER_ENCRYPTION::ENCRYPTED_AES) > 0){
return true;
}
}
return false;
}

/*
* Return true if the specified device is paired (peer encrypted)
*/
bool ATTClass::paired(uint16_t handle) const
{
for(int i=0; i<ATT_MAX_PEERS; i++){
if(_peers[i].connectionHandle != handle){continue;}
return (_peers[i].encryption & PEER_ENCRYPTION::ENCRYPTED_AES) > 0;
}
return false; // unknown handle
}

uint16_t ATTClass::mtu(uint16_t handle) const
{
for (int i = 0; i < ATT_MAX_PEERS; i++) {
Expand Down
2 changes: 2 additions & 0 deletions src/utility/ATT.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class ATTClass {
virtual bool connected() const;
virtual bool connected(uint8_t addressType, const uint8_t address[6]) const;
virtual bool connected(uint16_t handle) const;
virtual bool paired() const;
virtual bool paired(uint16_t handle) const;
virtual uint16_t mtu(uint16_t handle) const;

virtual bool disconnect();
Expand Down
16 changes: 12 additions & 4 deletions src/utility/HCI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "btct.h"
#include "HCI.h"

//#define _BLE_TRACE_

#define HCI_COMMAND_PKT 0x01
#define HCI_ACLDATA_PKT 0x02
#define HCI_EVENT_PKT 0x04
Expand Down Expand Up @@ -1335,23 +1337,29 @@ void HCIClass::handleEventPkt(uint8_t /*plen*/, uint8_t pdata[])
break;
}

uint8_t encryption = ATT.getPeerEncryption(connectionHandle);

for(int i=0; i<32; i++) DHKey[31-i] = evtLeDHKeyComplete->DHKey[i];

#ifdef _BLE_TRACE_
Serial.println("Stored our DHKey:");
btct.printBytes(DHKey,32);
#endif
encryption |= PEER_ENCRYPTION::DH_KEY_CALULATED;
uint8_t encryption = ATT.getPeerEncryption(connectionHandle) | PEER_ENCRYPTION::DH_KEY_CALULATED;
ATT.setPeerEncryption(connectionHandle, encryption);

if((encryption & PEER_ENCRYPTION::RECEIVED_DH_CHECK) > 0){
#ifdef _BLE_TRACE_
if(encryption | PEER_ENCRYPTION::RECEIVED_DH_CHECK){
Serial.println("Recieved DHKey check already so calculate f5, f6.");
Serial.println("Recieved DHKey check already so calculate f5, f6 now.");
#endif
L2CAPSignaling.smCalculateLTKandConfirm(connectionHandle, HCI.remoteDHKeyCheckBuffer);

}else{
#ifdef _BLE_TRACE_
Serial.println("Waiting on other DHKey check before calculating.");
#endif
}
}else{
#ifdef _BLE_TRACE_
Serial.print("Key generation error: 0x");
Serial.println(evtLeDHKeyComplete->status, HEX);
#endif
Expand Down
3 changes: 3 additions & 0 deletions src/utility/HCI.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

#include <Arduino.h>

#include "L2CAPSignaling.h"

#define OGF_LINK_CTL 0x01
#define OGF_HOST_CTL 0x03
#define OGF_INFO_PARAM 0x04
Expand Down Expand Up @@ -111,6 +113,7 @@ class HCIClass {
// TODO: Send command be private again & use ATT implementation within ATT.
virtual int sendCommand(uint16_t opcode, uint8_t plen = 0, void* parameters = NULL);
uint8_t remotePublicKeyBuffer[64];
uint8_t remoteDHKeyCheckBuffer[16];
uint8_t Na[16];
uint8_t Nb[16];
uint8_t DHKey[32];
Expand Down
Loading