microbit: Updates to Pairing Mode to improve the user experience

More specifically:

- BLUEZONE mode renamed to PairingMode (by popular request).
- Added timeout of 90 seconds before automatic device reboot.
- Move from a scroll to a print based algorithm to improve the amount of time key is displayed fully.
- Added compulsory 'click to bond' button press.
- Improved response time of tick/cross being displayed.
This commit is contained in:
Joe Finney 2015-12-11 03:43:18 +00:00
parent 5a9f5d42bd
commit 6d610f049a
5 changed files with 89 additions and 28 deletions

View file

@ -56,9 +56,12 @@ Either (1) the client does not possess the flash code and therefore must somehow
Stage 1 - Client Does Not Possess flash code
------------------------------------------
MicroBit has a special mode of operation or state known currently as "Blue Zone". The device enters this state when rebooted by pressing the reset button whilst at the same time holding down both buttons A and B. The device indicates itself to be in the Blue Zone mode by scrolling "BLUEZONE" across the display.
MicroBit has a special mode of operation or state known currently as "Pairing
Mode". The device enters this state when rebooted by pressing the reset button
whilst at the same time holding down both buttons A and B. The device
indicates itself to be in the pairing mode by scrolling "PAIRING MODE!" across the display.
Once in the Blue Zone state, the MicroBit DFU Service also enables another command via the ControlPoint characteristic known as 'REQUEST_FLASHCODE' which is represented by a value of 0x02.
Once in the pairin mode state, the MicroBit DFU Service also enables another command via the ControlPoint characteristic known as 'REQUEST_FLASHCODE' which is represented by a value of 0x02.
To obtain the flash code the client should enable GATT notifications on the FlashCode characteristic and then write 0x02 to the Control characteristic. The micro:bit will respond by displaying "PAIR?" on the LED display.
@ -66,7 +69,12 @@ The user must now press Button A on the micro:bit. This is an "authorization to
Stage 2 - Client in Possession of flash code
-------------------------------------------
If a device already knows the flashcode, it can connect any time and initiate rebooting into "Nordic DFU mode" by writing the FlashCode characteristic with the previously cached value and then writing the 'ENTER NORDIC BOOTLOADER' command (0x01) to the Control characteristic. The device will reboot into the stock nordic bootloader and then the attached device can interact with that to reflash the device. The device does NOT need to be in Blue Zone mode.
If a device already knows the flashcode, it can connect any time and initiate
rebooting into "Nordic DFU mode" by writing the FlashCode characteristic with
the previously cached value and then writing the 'ENTER NORDIC BOOTLOADER'
command (0x01) to the Control characteristic. The device will reboot into the
stock nordic bootloader and then the attached device can interact with that to
reflash the device. The device does NOT need to be in pairing mode.
Issues for Client Application Developers
----------------------------------------
@ -80,14 +88,16 @@ micro:bit human identifiers
---------------------------
In addition to a secret key (flash code) used in the FOTA process as described, micro:bits have a human readable identifier (public name) which is included in BLE advertising packets and can be discovered and used by human users during any process, including FOTA, where there needs to be a confirmation that the device which is to be interacted with is the one the human intends to interact with. In the context of this document, "interact with" means update using the FOTA procedure.
The public name is generated by the run time from the other half of the Nordic serial number. Humans can discover the public name of a device by switching into BLUEZONE mode. The public name is displayed in a coded but simple graphical form on the LED display and can then be entered into (say) a mobile application screen to verify the device to be updated is the one we mean to update.
The public name is generated by the run time from the other half of the Nordic
serial number. Humans can discover the public name of a device by switching
into pairing mode mode. The public name is displayed in a coded but simple graphical form on the LED display and can then be entered into (say) a mobile application screen to verify the device to be updated is the one we mean to update.
Summary of the FOTA Process
---------------------------
Case 1 - Client does not know the flash code
--------------------------------------------
a) User switches micro:bit into BLUEZONE mode - must do this first since it involves a reboot and will therefore disconnect the client
a) User switches micro:bit into pairing mode - must do this first since it involves a reboot and will therefore disconnect the client
b) Client connects to micro:bit
c) Client discovers MicroBit DFU service
d) Client enables notifications on the MicroBit DFU Service::FlashCode characteristic

View file

@ -35,7 +35,8 @@
#define MICROBIT_BLE_PAIR_REQUEST 0x01
#define MICROBIT_BLE_PAIR_COMPLETE 0x02
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x04
#define MICROBIT_BLE_PAIR_PASSCODE 0x04
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x08
/**
* Class definition for the MicroBitBLEManager.
@ -72,12 +73,12 @@ class MicroBitBLEManager
void init(ManagedString deviceName, ManagedString serialNumber);
/**
* Enter BLUEZONE mode. This is mode is called to initiate pairing, and to enable FOTA programming
* Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
* of the micro:bit in cases where BLE is disabled during normal operation.
*
* @param display a MicroBitDisplay to use when displaying pairing information.
*/
void bluezone(MicroBitDisplay &display);
void pairingMode(MicroBitDisplay &display);
/**
* Method that is called whenever a BLE device disconnects from us.
@ -93,13 +94,13 @@ class MicroBitBLEManager
/**
* A request to pair has been received from a BLE device.
* If we're in BLUEZONE mode, display the passkey to the user.
* If we're in pairing mode, display the passkey to the user.
*/
void pairingRequested(ManagedString passKey);
/**
* A pairing request has been sucesfully completed.
* If we're in BLUEZONE mode, display feedback to the user.
* If we're in pairing mode, display feedback to the user.
*/
void pairingComplete(bool success);

View file

@ -123,7 +123,7 @@
// by enabling/disabling the options below.
//
// n.b. The minimum set of services to enable over the air programming of the device will
// still be brought up in 'BLUEZONE' mode regardless of the settings below.
// still be brought up in pairing mode regardless of the settings below.
//
// Enable/Disable BLE during normal operation.
@ -132,10 +132,10 @@
#define MICROBIT_BLE_ENABLED 1
#endif
// Enable/Disable BLUEZONE mode at power up.
// Enable/Disable BLE pairing mode mode at power up.
// Set '1' to enable.
#ifndef MICROBIT_BLE_BLUEZONE
#define MICROBIT_BLE_BLUEZONE 1
#ifndef MICROBIT_BLE_PAIRING_MODE
#define MICROBIT_BLE_PAIRING_MODE 1
#endif
// Enable/Disable the use of private resolvable addresses.

View file

@ -37,7 +37,7 @@ int main()
// Provide time for all threaded initialisers to complete.
uBit.sleep(100);
#if CONFIG_ENABLED(MICROBIT_BLE_BLUEZONE)
#if CONFIG_ENABLED(MICROBIT_BLE_PAIRING_MODE)
// Test if we need to enter BLE pairing mode...
int i=0;
while (uBit.buttonA.isPressed() && uBit.buttonB.isPressed() && i<10)
@ -51,8 +51,8 @@ int main()
if (!uBit.ble)
uBit.bleManager.init(uBit.getName(), uBit.getSerial());
// Enter BLUE ZONE mode, using the LED matrix for any necessary paiing operations
uBit.bleManager.bluezone(uBit.display);
// Enter pairing mode, using the LED matrix for any necessary pairing operations
uBit.bleManager.pairingMode(uBit.display);
}
}

View file

@ -24,6 +24,11 @@
#define MICROBIT_BLE_ENABLE_BONDING true
#define MICROBIT_BLE_REQUIRE_MITM true
#define MICROBIT_PAIRING_MODE_TIMEOUT 90
#define MICROBIT_PAIRING_FADE_SPEED 4
const char* MICROBIT_BLE_MANUFACTURER = "The Cast of W1A";
const char* MICROBIT_BLE_MODEL = "BBC micro:bit";
const char* MICROBIT_BLE_HARDWARE_VERSION = "1.0";
@ -189,7 +194,7 @@ void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumb
/**
* A request to pair has been received from a BLE device.
* If we're in BLUEZONE mode, display the passkey to the user.
* If we're in pairing mode, display the passkey to the user.
*/
void MicroBitBLEManager::pairingRequested(ManagedString passKey)
{
@ -199,29 +204,31 @@ void MicroBitBLEManager::pairingRequested(ManagedString passKey)
/**
* A pairing request has been sucesfully completed.
* If we're in BLUEZONE mode, display feedback to the user.
* If we're in pairing mode, display feedback to the user.
*/
void MicroBitBLEManager::pairingComplete(bool success)
{
this->pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
this->pairingStatus |= MICROBIT_BLE_PAIR_COMPLETE;
this->pairingStatus = MICROBIT_BLE_PAIR_COMPLETE;
if(success)
this->pairingStatus |= MICROBIT_BLE_PAIR_SUCCESSFUL;
}
/**
* Enter BLUEZONE mode. This is mode is called to initiate pairing, and to enable FOTA programming
* Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
* of the micro:bit in cases where BLE is disabled during normal operation.
*/
void MicroBitBLEManager::bluezone(MicroBitDisplay &display)
void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
{
ManagedString namePrefix("BBC micro:bit [");
ManagedString namePostfix("]");
ManagedString BLEName = namePrefix + deviceName + namePostfix;
ManagedString prefix("BLUEZONE:");
ManagedString msg = prefix + deviceName;
ManagedString msg("PAIRING MODE!");
int timeInPairingMode = 0;
int brightness = 255;
int fadeDirection = 0;
// Update the advertised name of this micro:bit to include the device name
ble->clearAdvertisingPayload();
@ -242,8 +249,47 @@ void MicroBitBLEManager::bluezone(MicroBitDisplay &display)
{
if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
{
display.scroll("Pair: ", 90);
display.scroll(passKey, 90);
timeInPairingMode = 0;
MicroBitImage arrow("0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n");
display.print(arrow,0,0,0);
if (fadeDirection == 0)
brightness -= MICROBIT_PAIRING_FADE_SPEED;
else
brightness += MICROBIT_PAIRING_FADE_SPEED;
if (brightness <= 40)
display.clear();
if (brightness <= 0)
fadeDirection = 1;
if (brightness >= 255)
fadeDirection = 0;
if (uBit.buttonA.isPressed())
{
pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
}
}
if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
{
timeInPairingMode = 0;
display.setBrightness(255);
for (int i=0; i<passKey.length(); i++)
{
display.image.print(passKey.charAt(i),0,0);
uBit.sleep(800);
display.clear();
uBit.sleep(200);
if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
break;
}
uBit.sleep(1000);
}
if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
@ -260,7 +306,11 @@ void MicroBitBLEManager::bluezone(MicroBitDisplay &display)
}
}
uBit.sleep(100);
uBit.sleep(30);
timeInPairingMode++;
if (timeInPairingMode >= MICROBIT_PAIRING_MODE_TIMEOUT * 30)
microbit_reset();
}
}