diff --git a/inc/MicroBitBLEService.h b/inc/MicroBitBLEService.h index 219800ba..14708681 100644 --- a/inc/MicroBitBLEService.h +++ b/inc/MicroBitBLEService.h @@ -60,6 +60,7 @@ class MicroBitBLEService ~MicroBitBLEService(); + ble_uuid_t getServiceUUID(); protected: @@ -137,6 +138,7 @@ class MicroBitBLEService uint8_t bs_uuid_type; microbit_servicehandle_t bs_service_handle; + ble_uuid_t bs_service_uuid; static const uint8_t bs_base_uuid[16]; }; diff --git a/inc/MicroBitConfig.h b/inc/MicroBitConfig.h index 588e0966..7b420769 100644 --- a/inc/MicroBitConfig.h +++ b/inc/MicroBitConfig.h @@ -250,7 +250,7 @@ #endif // Enable/Disable Nordic Firmware style BLE based UART implimentation. -// The default codal implimentation reverses the TX/RX ids +// The default codal implementation reverses the TX/RX ids // Set to '1' to enable #ifndef MICROBIT_BLE_NORDIC_STYLE_UART #define MICROBIT_BLE_NORDIC_STYLE_UART 0 @@ -272,4 +272,8 @@ #define MICROBIT_USB_SERIAL_WAKE 0 #endif +#ifndef MICROBIT_SW_VERSION +#define MICROBIT_SW_VERSION "unknown" +#endif + #endif diff --git a/inc/bluetooth/MicroBitBLEManager.h b/inc/bluetooth/MicroBitBLEManager.h index fc402ad7..74e3d9e3 100644 --- a/inc/bluetooth/MicroBitBLEManager.h +++ b/inc/bluetooth/MicroBitBLEManager.h @@ -159,6 +159,19 @@ class MicroBitBLEManager : public CodalComponent */ void advertise(); + /** + * When called, the micro:bit will begin advertising the supplied service's complete UUID. + * + * @param serviceUUIDs Pointer to an array of service UUID structures to insert into the advertising data. + * @param service_count Count of service UUID structures to insert into the advertising data. + * @param service_list_complete Flag to indicate whether the service UUID array contains all available services. + * @param manufacturer_id Manufacturer ID to insert into Manfacturer Data value in the advertising data. + * @param manufacturer_data Array of Manfacturer Data bytes to insert into the advertising data. + * @param manufacturer_data_size Size of Manfacturer Data array. + */ + void advertise(ble_uuid_t *serviceUUIDs, uint16_t service_count = 1, bool service_list_complete = true, + uint16_t manufacturer_id = 0, uint8_t *manufacturer_data = nullptr, uint16_t manufacturer_data_size = 0); + /** * Determines the number of devices currently bonded with this micro:bit. * @return The number of active bonds. diff --git a/source/bluetooth/MicroBitBLEManager.cpp b/source/bluetooth/MicroBitBLEManager.cpp index f45e0640..7df2321f 100644 --- a/source/bluetooth/MicroBitBLEManager.cpp +++ b/source/bluetooth/MicroBitBLEManager.cpp @@ -111,9 +111,10 @@ DEALINGS IN THE SOFTWARE. const char *MICROBIT_BLE_MANUFACTURER = NULL; const char *MICROBIT_BLE_MODEL = "BBC micro:bit"; +const char *MICROBIT_BLE_VERSION[2] = { "2.0", "2.X" }; const char *MICROBIT_BLE_HARDWARE_VERSION = NULL; const char *MICROBIT_BLE_FIRMWARE_VERSION = MICROBIT_DAL_VERSION; -const char *MICROBIT_BLE_SOFTWARE_VERSION = NULL; +const char *MICROBIT_BLE_SOFTWARE_VERSION = MICROBIT_SW_VERSION; const int8_t MICROBIT_BLE_POWER_LEVEL[] = { -40, -20, -16, -12, -8, -4, 0, 4}; @@ -131,6 +132,7 @@ MicroBitBLEManager *MicroBitBLEManager::manager = NULL; // Singleton reference t static int m_power = MICROBIT_BLE_DEFAULT_TX_POWER; static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; static uint8_t m_enc_advdata[ BLE_GAP_ADV_SET_DATA_SIZE_MAX]; +static uint8_t m_enc_scan_rsp_data[ BLE_GAP_ADV_SET_DATA_SIZE_MAX]; static volatile int m_pending; @@ -149,10 +151,21 @@ static void microbit_ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_conte static void microbit_ble_pm_evt_handler(pm_evt_t const * p_evt); static void microbit_ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context); +#if CONFIG_ENABLED(MICROBIT_BLE_DFU_SERVICE) static void microbit_dfu_init(void); +#endif + +static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, + uint16_t interval_ms, int timeout_seconds, + ble_advdata_t *p_advdata, ble_advdata_t *p_scndata = nullptr); static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, uint16_t interval_ms, int timeout_seconds); +static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, + uint16_t interval_ms, int timeout_seconds, + ble_advdata_uuid_list_t *services, bool service_list_complete = true, + ble_advdata_manuf_data_t *manufacturer_data = nullptr); + #if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL) || CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID) static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, uint16_t interval_ms, int timeout_seconds, uint8_t *frameData, uint16_t frameSize); @@ -446,7 +459,7 @@ void MicroBitBLEManager::init( ManagedString deviceName, ManagedString serialNum const_ascii_to_utf8( &disi.manufact_name_str, MICROBIT_BLE_MANUFACTURER); const_ascii_to_utf8( &disi.model_num_str, disName.toCharArray()); const_ascii_to_utf8( &disi.serial_num_str, serialNumber.toCharArray()); - const_ascii_to_utf8( &disi.hw_rev_str, MICROBIT_BLE_HARDWARE_VERSION); + const_ascii_to_utf8( &disi.hw_rev_str, modelVersion.toCharArray()); const_ascii_to_utf8( &disi.fw_rev_str, MICROBIT_BLE_FIRMWARE_VERSION); const_ascii_to_utf8( &disi.sw_rev_str, MICROBIT_BLE_SOFTWARE_VERSION); //ble_dis_sys_id_t * p_sys_id; /**< System ID. */ @@ -657,6 +670,40 @@ void MicroBitBLEManager::advertise() } +/** + * When called, the micro:bit will begin advertising for a predefined period, + * MICROBIT_BLE_ADVERTISING_TIMEOUT seconds to bonded devices. + * + * @param serviceUUID The service UUID to insert into advertising data. + */ +void MicroBitBLEManager::advertise(ble_uuid_t *serviceUUIDs, uint16_t service_count, bool service_list_complete, uint16_t manufacturer_id, uint8_t *manufacturer_data, uint16_t manufacturer_data_size) +{ + MICROBIT_DEBUG_DMESG( "advertise service"); + + ble_advdata_uuid_list_t services; + services.p_uuids = serviceUUIDs; + services.uuid_cnt = service_count; + + if(manufacturer_data != nullptr) + { + ble_advdata_manuf_data_t manuf_data; + manuf_data.company_identifier = manufacturer_id; + manuf_data.data.p_data = manufacturer_data; + manuf_data.data.size = manufacturer_data_size; + + microbit_ble_configureAdvertising(true, true, false, MICROBIT_BLE_ADVERTISING_INTERVAL, + MICROBIT_BLE_ADVERTISING_TIMEOUT, &services, service_list_complete, &manuf_data); + } + else + { + microbit_ble_configureAdvertising(true, true, false, MICROBIT_BLE_ADVERTISING_INTERVAL, + MICROBIT_BLE_ADVERTISING_TIMEOUT, &services, service_list_complete); + } + + advertise(); +} + + /** * Stops any currently running BLE advertisements */ @@ -1177,7 +1224,7 @@ void MicroBitBLEManager::servicesChanged() */ static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, uint16_t interval_ms, int timeout_seconds, - ble_advdata_t *p_advdata) + ble_advdata_t *p_advdata, ble_advdata_t *p_scandata) { MICROBIT_DEBUG_DMESG( "configureAdvertising connectable %d, discoverable %d", (int) connectable, (int) discoverable); MICROBIT_DEBUG_DMESG( "whitelist %d, interval_ms %d, timeout_seconds %d", (int) whitelist, (int) interval_ms, (int) timeout_seconds); @@ -1198,10 +1245,22 @@ static void microbit_ble_configureAdvertising( bool connectable, bool discoverab ble_gap_adv_data_t gap_adv_data; memset( &gap_adv_data, 0, sizeof( gap_adv_data)); + + // encode advertising data gap_adv_data.adv_data.p_data = m_enc_advdata; gap_adv_data.adv_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX; MICROBIT_BLE_ECHK( ble_advdata_encode( p_advdata, gap_adv_data.adv_data.p_data, &gap_adv_data.adv_data.len)); NRF_LOG_HEXDUMP_INFO( gap_adv_data.adv_data.p_data, gap_adv_data.adv_data.len); + + // encode scan response data if supplied + if(p_scandata != nullptr) + { + gap_adv_data.scan_rsp_data.p_data = m_enc_scan_rsp_data; + gap_adv_data.scan_rsp_data.len = BLE_GAP_ADV_SET_DATA_SIZE_MAX; + MICROBIT_BLE_ECHK( ble_advdata_encode( p_scandata, gap_adv_data.scan_rsp_data.p_data, &gap_adv_data.scan_rsp_data.len)); + NRF_LOG_HEXDUMP_INFO( gap_adv_data.scan_rsp_data.p_data, gap_adv_data.scan_rsp_data.len); + } + MICROBIT_BLE_ECHK( sd_ble_gap_adv_set_configure( &m_adv_handle, &gap_adv_data, &gap_adv_params)); } @@ -1220,6 +1279,36 @@ static void microbit_ble_configureAdvertising( bool connectable, bool discoverab } +static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, + uint16_t interval_ms, int timeout_seconds, + ble_advdata_uuid_list_t *services, bool service_list_complete, + ble_advdata_manuf_data_t *manufacturer_data) +{ + ble_advdata_t advdata; + memset( &advdata, 0, sizeof( advdata)); + advdata.name_type = BLE_ADVDATA_FULL_NAME; + advdata.flags = !whitelist && discoverable + ? BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED | BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE + : BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; + + ble_advdata_t scandata; + memset( &scandata, 0, sizeof( scandata)); + if(service_list_complete) + { + scandata.uuids_complete = *services; + } + else + { + scandata.uuids_more_available = *services; + } + if(manufacturer_data != nullptr) { + scandata.p_manuf_specific_data = manufacturer_data; + } + + microbit_ble_configureAdvertising( connectable, discoverable, whitelist, interval_ms, timeout_seconds, &advdata, &scandata); +} + + #if CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_URL) || CONFIG_ENABLED(MICROBIT_BLE_EDDYSTONE_UID) static void microbit_ble_configureAdvertising( bool connectable, bool discoverable, bool whitelist, diff --git a/source/bluetooth/MicroBitBLEService.cpp b/source/bluetooth/MicroBitBLEService.cpp index cb314dc7..722a7893 100644 --- a/source/bluetooth/MicroBitBLEService.cpp +++ b/source/bluetooth/MicroBitBLEService.cpp @@ -53,6 +53,8 @@ MicroBitBLEService::MicroBitBLEService() : bs_uuid_type(0), bs_service_handle(0) { + bs_service_uuid.type = 0; + bs_service_uuid.uuid = 0; MicroBitBLEServices::getShared()->AddService( this); } @@ -66,9 +68,10 @@ MicroBitBLEService::~MicroBitBLEService() void MicroBitBLEService::RegisterBaseUUID( const uint8_t *bytes16UUID) { ble_uuid128_t uuid128; - for ( int i = 0; i < 16; i++) + for ( int i = 0; i < 16; i++) { uuid128.uuid128[i] = bytes16UUID[ 15 - i]; - + } + MICROBIT_BLE_ECHK( sd_ble_uuid_vs_add( &uuid128, &bs_uuid_type)); MICROBIT_DEBUG_DMESG( "MicroBitBLEService::RegisterBaseUUID bs_uuid_type = %d", (int) bs_uuid_type); @@ -77,12 +80,10 @@ void MicroBitBLEService::RegisterBaseUUID( const uint8_t *bytes16UUID) void MicroBitBLEService::CreateService( uint16_t uuid) { - ble_uuid_t serviceUUID; + bs_service_uuid.uuid = uuid; + bs_service_uuid.type = bs_uuid_type; - serviceUUID.uuid = uuid; - serviceUUID.type = bs_uuid_type; - - MICROBIT_BLE_ECHK( sd_ble_gatts_service_add( BLE_GATTS_SRVC_TYPE_PRIMARY, &serviceUUID, &bs_service_handle)); + MICROBIT_BLE_ECHK( sd_ble_gatts_service_add( BLE_GATTS_SRVC_TYPE_PRIMARY, &bs_service_uuid, &bs_service_handle)); MICROBIT_DEBUG_DMESG( "MicroBitBLEService::CreateService( %x) = %d", (unsigned int) uuid, (int) bs_service_handle); } @@ -140,6 +141,10 @@ void MicroBitBLEService::CreateCharacteristic( (int) charHandles( idx)->sccd); } +ble_uuid_t MicroBitBLEService::getServiceUUID() +{ + return bs_service_uuid; +} microbit_gaphandle_t MicroBitBLEService::getConnectionHandle() {