7 years, 11 months ago.

How can I start/stop bluetooth at runtime?

Hi there, I try to find a way to properly start / stop or suspend / activate bluetooth during program runtime by the press on a button. Reason is that I'd like to use FOTA for application updates but don't want to keep it in that state all time for security reasons. I've written a small library that issues a callback function based on the duration of a button press. Ideally I could call an ble activate / suspend method from that callback function. I have put a working implementation together by moving the initialisation code into the callback function.

void startBT(void){
    BLE &ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
    ble.init(bleInitComplete); 
    while (ble.hasInitialized()  == false) { /* spin loop */ }
}

but this looks rather odd to me. Any advise on how to do this properly would be great!

#include "mbed.h"
//#include "LedBlink.h"
#include "PushDuration.h"
#include "ble/BLE.h"
#include "ble/services/DFUService.h"
#include "ble/services/DeviceInformationService.h"

PinName pin(p18);
static const uint16_t uuid16_list[]        = {GattService::UUID_DEVICE_INFORMATION_SERVICE};
const static char DEVICE_NAME[] = "TEST-FOTA";
DigitalOut led1(LED1);
DeviceInformationService *deviceInfo;
DFUService               *dfuService;
Ticker ticker;
volatile int enableDFU = 0;

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    BLE::Instance(BLE::DEFAULT_INSTANCE).gap().startAdvertising(); // restart advertising
}

void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
{
    BLE &ble = params->ble;
    ble_error_t error = params->error; 
    
    if (error != BLE_ERROR_NONE)
    {
        return;
    }
    ble.gap().onDisconnection(disconnectionCallback);
    

    /* Setup primary service. */
    deviceInfo = new DeviceInformationService(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1");
    dfuService = new DFUService(ble);

    //setup advertising
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(1000); /* 1000ms */
    ble.gap().startAdvertising();
}
    

void blink()
{
    led1 = !led1;

}

void startBT(void){
    BLE &ble = BLE::Instance(BLE::DEFAULT_INSTANCE);
    ble.init(bleInitComplete); 
    while (ble.hasInitialized()  == false) { /* spin loop */ }
}

const action action_table[] = 
{
 //   {1, foo},
 //   {2, bar},
    {3, startBT}, //start DFU after 3 seconds 
};

int main(void) {   
    ticker.attach(blink, 1);
    
    ButtonHandler bh(
                    sizeof(action_table)/sizeof(action_table[0]),
                    action_table, 
                    pin,
                    1);
   
    bh.enable();
    
    while (1){    
        BLE::Instance(BLE::DEFAULT_INSTANCE).waitForEvent();
    }
}

Another obvious issue with this implementation is, that it does not allow to have other BLE services running while DFU is off. I've played around with the DFU service but it appears that it doesn't need to be explicitly instantiated in the code "dfuService = new DFUService(ble); " but is always on when an App + Bootloader image is programmed to the nrf51. That seems odd to me.

posted by Jens Strümper 10 Jun 2016
Be the first to answer this question.