From 79c739674c23f7865e383f1c06246d5a95f242b7 Mon Sep 17 00:00:00 2001 From: Joe Finney Date: Sun, 15 Nov 2015 14:31:44 +0000 Subject: [PATCH] first compiling build. --- inc/MicroBit.h | 40 +-------- inc/MicroBitBLEManager.h | 88 +++++++++++++++++++ source/CMakeLists.txt | 1 + source/MicroBit.cpp | 78 +--------------- source/MicroBitSuperMain.cpp | 25 ++---- ...MicroBitBLE.cpp => MicroBitBLEManager.cpp} | 62 ++++++------- 6 files changed, 133 insertions(+), 161 deletions(-) create mode 100644 inc/MicroBitBLEManager.h rename source/ble-services/{MicroBitBLE.cpp => MicroBitBLEManager.cpp} (78%) diff --git a/inc/MicroBit.h b/inc/MicroBit.h index 417b300..4741b41 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -32,35 +32,7 @@ #include "MicroBitFiber.h" #include "MicroBitMessageBus.h" -/* - * The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ - * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL) - * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this - * as a compatability option, but does not support the options used... - */ -#if !defined (__arm) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif -#include "ble/BLE.h" - -/* - * Return to our predefined compiler settings. - */ -#if !defined (__arm) -#pragma GCC diagnostic pop -#endif - -#include "ble/services/DeviceInformationService.h" -#include "MicroBitDFUService.h" -#include "MicroBitEventService.h" -#include "MicroBitLEDService.h" -#include "MicroBitAccelerometerService.h" -#include "MicroBitMagnetometerService.h" -#include "MicroBitButtonService.h" -#include "MicroBitIOPinService.h" -#include "MicroBitTemperatureService.h" -#include "ExternalEvents.h" +#include "MicroBitBLEManager.h" // MicroBit::flags values #define MICROBIT_FLAG_SCHEDULER_RUNNING 0x00000001 @@ -128,8 +100,8 @@ class MicroBit MicroBitIO io; // Bluetooth related member variables. - BLEDevice *ble; - MicroBitDFUService *ble_firmware_update_service; + MicroBitBLEManager bleManager; + BLEDevice *ble; /** * Constructor. @@ -298,12 +270,6 @@ class MicroBit // code integration a little bit easier for third parties. extern MicroBit uBit; -// -// BLE callback when an active GATT session with another device is terminated. -// Used to reset state and restart advertising ourselves. -// -void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason); - // Entry point for application programs. Called after the super-main function // has initialized the device and runtime environment. extern "C" void app_main(); diff --git a/inc/MicroBitBLEManager.h b/inc/MicroBitBLEManager.h new file mode 100644 index 0000000..dcea8ce --- /dev/null +++ b/inc/MicroBitBLEManager.h @@ -0,0 +1,88 @@ +#ifndef MICROBIT_BLE_MANAGER_H +#define MICROBIT_BLE_MANAGER_H + +#include "mbed.h" + +/* + * The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ + * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL) + * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this + * as a compatability option, but does not support the options used... + */ +#if !defined (__arm) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#include "ble/BLE.h" + +/* + * Return to our predefined compiler settings. + */ +#if !defined (__arm) +#pragma GCC diagnostic pop +#endif + +#include "ble/services/DeviceInformationService.h" +#include "MicroBitDFUService.h" +#include "MicroBitEventService.h" +#include "MicroBitLEDService.h" +#include "MicroBitAccelerometerService.h" +#include "MicroBitMagnetometerService.h" +#include "MicroBitButtonService.h" +#include "MicroBitIOPinService.h" +#include "MicroBitTemperatureService.h" +#include "ExternalEvents.h" + +/** + * Class definition for the MicroBitBLEManager. + * + */ +class MicroBitBLEManager +{ + public: + + // The mbed abstraction of the BlueTooth Low Energy (BLE) hardware + BLEDevice *ble; + + /** + * Constructor. + * + * Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack. + * Note that the BLE stack *cannot* be brought up in a static context. + * (the software simply hangs or corrupts itself). + * Hence, we bring it up in an explicit init() method, rather than in the constructor. + */ + MicroBitBLEManager(); + + /** + * Post constructor initialisation method. + * After *MUCH* pain, it's noted that the BLE stack can't be brought up in a + * static context, so we bring it up here rather than in the constructor. + * n.b. This method *must* be called in main() or later, not before. + * + * Example: + * @code + * uBit.init(); + * @endcode + */ + void init(ManagedString deviceName, ManagedString serialNumber); + + /** + * Enter BLUEZOE 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); + + /** + * Method that is called whenever a BLE device disconnects from us. + * The nordic stack stops dvertising whenever a device connects, so we use + * this callback to restart advertising. + */ + void onDisconnectionCallback(); +}; + + +#endif + diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 8d16619..4e2ad95 100755 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -29,6 +29,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES "MicroBitHeapAllocator.cpp" "MicroBitListener.cpp" "MemberFunctionCallback.cpp" + "ble-services/MicroBitBLEManager.cpp" "ble-services/MicroBitDFUService.cpp" "ble-services/MicroBitEventService.cpp" "ble-services/MicroBitLEDService.cpp" diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index ed8d38d..fad8d19 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -2,13 +2,6 @@ char MICROBIT_BLE_DEVICE_NAME[] = "BBC micro:bit [xxxxx]"; -#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) && CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) -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"; -const char* MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION; -const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL; -#endif /** * custom function for panic for malloc & new due to scoping issue. @@ -28,17 +21,6 @@ microbit_reset() } -/** - * Callback when a BLE GATT disconnect occurs. - */ -void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) -{ - (void) handle; /* -Wunused-param */ - (void) reason; /* -Wunused-param */ - - uBit.ble->startAdvertising(); -} - /** * Constructor. * Create a representation of a MicroBit device as a global singleton. @@ -76,7 +58,8 @@ MicroBit::MicroBit() : MICROBIT_ID_IO_P9,MICROBIT_ID_IO_P10,MICROBIT_ID_IO_P11, MICROBIT_ID_IO_P12,MICROBIT_ID_IO_P13,MICROBIT_ID_IO_P14, MICROBIT_ID_IO_P15,MICROBIT_ID_IO_P16,MICROBIT_ID_IO_P19, - MICROBIT_ID_IO_P20) + MICROBIT_ID_IO_P20), + bleManager() { } @@ -112,63 +95,10 @@ void MicroBit::init() #if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) // Start the BLE stack. - ble = new BLEDevice(); - ble->init(); - ble->onDisconnection(bleDisconnectionCallback); - - // Bring up any configured auxiliary services. -#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE) - ble_firmware_update_service = new MicroBitDFUService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) - DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, getSerial().toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE) - new MicroBitEventService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_LED_SERVICE) - new MicroBitLEDService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE) - new MicroBitAccelerometerService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE) - new MicroBitMagnetometerService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE) - new MicroBitButtonService(*ble); -#endif - -#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE) - new MicroBitIOPinService(*ble); + bleManager.init(this->getName(), this->getSerial()); + ble = bleManager.ble; #endif -#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE) - new MicroBitTemperatureService(*ble); -#endif - - // Configure for high speed mode where possible. - Gap::ConnectionParams_t fast; - ble->getPreferredConnectionParams(&fast); - fast.minConnectionInterval = 8; // 10 ms - fast.maxConnectionInterval = 16; // 20 ms - fast.slaveLatency = 0; - ble->setPreferredConnectionParams(&fast); - - // Setup advertising. - ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME)); - ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(200)); - ble->startAdvertising(); -#endif - // Start refreshing the Matrix Display systemTicker.attach(this, &MicroBit::systemTick, MICROBIT_DISPLAY_REFRESH_PERIOD); } diff --git a/source/MicroBitSuperMain.cpp b/source/MicroBitSuperMain.cpp index ed1a790..e8f1e9b 100644 --- a/source/MicroBitSuperMain.cpp +++ b/source/MicroBitSuperMain.cpp @@ -47,28 +47,13 @@ int main() if (i == 10) { - // OK - we need to enter BLUE ZONE mode. - // Test to see if BLE and the necessary services have been brought up already. - // If not, start them. - if (!uBit.ble) - { - uBit.ble = new BLEDevice(); - uBit.ble->init(); - uBit.ble->onDisconnection(bleDisconnectionCallback); + // Bring up the BLE stack if it isn't alredy done. + if (!uBit.ble) + uBit.bleManager.init(uBit.getName(), uBit.getSerial()); - // Ensure we're advertising. - uBit.ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - uBit.ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME)); - uBit.ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); - uBit.ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(200)); - uBit.ble->startAdvertising(); - } + // Enter BLUE ZONE mode, using the LED matrix for any necessary paiing operations + uBit.bleManager.bluezone(uBit.display); - if (!uBit.ble_firmware_update_service) - uBit.ble_firmware_update_service = new MicroBitDFUService(*uBit.ble); - - // enter BLUE ZONE mode. - uBit.ble_firmware_update_service->pair(); } } #endif diff --git a/source/ble-services/MicroBitBLE.cpp b/source/ble-services/MicroBitBLEManager.cpp similarity index 78% rename from source/ble-services/MicroBitBLE.cpp rename to source/ble-services/MicroBitBLEManager.cpp index 831cced..9c00347 100644 --- a/source/ble-services/MicroBitBLE.cpp +++ b/source/ble-services/MicroBitBLEManager.cpp @@ -1,9 +1,8 @@ #include "MicroBit.h" #define MICROBIT_BLE_ENABLE_BONDING true -#define MICROBIT_BLE_REQUIRE_MITM true +#define MICROBIT_BLE_REQUIRE_MITM true -#if CONFIG_ENABLED(MICROBIT_BLE_ENABLED) && CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) 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"; @@ -13,7 +12,7 @@ const char* MICROBIT_BLE_SOFTWARE_VERSION = NULL; /* * Many of the mbed interfaces we need to use only support callbacks to plain C functions, rather than C++ methods. * So, we maintain a pointer to the MicroBitBLEManager that's in use. Ths way, we can still access resources on the micro:bit - * whilst keeping the code modular. + * whilst keeping the code modular. */ static MicroBitBLEManager *manager = NULL; @@ -26,7 +25,7 @@ static void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionRea (void) reason; /* -Wunused-param */ if (manager) - manager->bleDisconnectionCallback(); + manager->onDisconnectionCallback(); } @@ -54,31 +53,14 @@ static void securitySetupCompletedCallback(Gap::Handle_t handle, SecurityManager static void securitySetupInitiatedCallback(Gap::Handle_t handle, bool allowBonding, bool requireMITM, SecurityManager::SecurityIOCapabilities_t iocaps) { - (void) handle; /* -Wunused-param */ + (void) handle; /* -Wunused-param */ (void) allowBonding; /* -Wunused-param */ (void) requireMITM; /* -Wunused-param */ - (void) iocaps; /* -Wunused-param */ + (void) iocaps; /* -Wunused-param */ printf("Security setup initiated\r\n"); } -void initializeSecurity(BLE &ble) -{ - bool enableBonding = true; - bool requireMITM = HID_SECURITY_REQUIRE_MITM; - - ble.securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); - ble.securityManager().onPasskeyDisplay(passkeyDisplayCallback); - ble.securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); - - ble.securityManager().init(enableBonding, requireMITM, HID_SECURITY_IOCAPS); -} - - -void MicroBitBLEManager::bleDisconnectionCallback() -{ - ble.startAdvertising(); -} /** * Constructor. @@ -90,6 +72,18 @@ void MicroBitBLEManager::bleDisconnectionCallback() */ MicroBitBLEManager::MicroBitBLEManager() { + this->ble = NULL; +} + +/** + * Method that is called whenever a BLE device disconnects from us. + * The nordic stack stops dvertising whenever a device connects, so we use + * this callback to restart advertising. + */ +void MicroBitBLEManager::onDisconnectionCallback() +{ + if(ble) + ble->startAdvertising(); } /** @@ -103,7 +97,7 @@ MicroBitBLEManager::MicroBitBLEManager() * uBit.init(); * @endcode */ -void MicroBitBLEManager::init() +void MicroBitBLEManager::init(ManagedString deviceName, ManagedString serialNumber) { // Start the BLE stack. ble = new BLEDevice(); @@ -116,16 +110,15 @@ void MicroBitBLEManager::init() ble->securityManager().onSecuritySetupInitiated(securitySetupInitiatedCallback); ble->securityManager().onPasskeyDisplay(passkeyDisplayCallback); ble->securityManager().onSecuritySetupCompleted(securitySetupCompletedCallback); - - ble.securityManager().init(MICROBIT_BLE_ENABLE_BONDING, MICROBIT_BLE_REQUIRE_MITM, HID_SECURITY_IOCAPS); + ble->securityManager().init(MICROBIT_BLE_ENABLE_BONDING, MICROBIT_BLE_REQUIRE_MITM, SecurityManager::IO_CAPS_DISPLAY_ONLY); // Bring up any configured auxiliary services. #if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE) - ble_firmware_update_service = new MicroBitDFUService(*ble); + new MicroBitDFUService(*ble); #endif #if CONFIG_ENABLED(MICROBIT_BLE_DEVICE_INFORMATION_SERVICE) - DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, getSerial().toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION); + DeviceInformationService ble_device_information_service (*ble, MICROBIT_BLE_MANUFACTURER, MICROBIT_BLE_MODEL, serialNumber.toCharArray(), MICROBIT_BLE_HARDWARE_VERSION, MICROBIT_BLE_FIRMWARE_VERSION, MICROBIT_BLE_SOFTWARE_VERSION); #endif #if CONFIG_ENABLED(MICROBIT_BLE_EVENT_SERVICE) @@ -166,11 +159,20 @@ void MicroBitBLEManager::init() // Setup advertising. ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); - ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME)); + ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)deviceName.toCharArray(), deviceName.length()); ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble->setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(200)); ble->startAdvertising(); -#endif +} +/** + * Enter BLUEZONE 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) +{ + // TODO: + while(1); } +