Skip to content

BLE: Generic Access Service and Generic Attribute Service are not available after shutting down and restarting the Cordio BLE stack  #13503

@EmbedEngineer

Description

@EmbedEngineer

Description of defect

After shutting down the Cordio BLE stack and restarting it, the Generic Access Service and Generic Attribute Service are missing when acting as GATT server.
From my understanding by default when starting up the device the Generic Access Service and Generic Attribute Service are created somewhere in the mbed BLE APIs (my guess is void GattServer::initialize() -> add_default_services() in CordioGattServer.h). So after calling BLE::Instance().init(), setting up und starting advertising when having connected to the device, the two services are present.
When calling BLE::Instance().shutdown() BLE shuts down as it should. After calling BLE::Instance().init(), setting up und starting advertising, I can connect to the device but the Generic Access Service and Generic Attribute Service are missing. Since these two services are mandatory according to the standard, I think there is a bug.

Target(s) affected by this defect ?

NRF52840

Toolchain(s) (name and version) displaying this defect ?

gcc-arm-none-eabi-9-2019-q4-major

What version of Mbed-os are you using (tag or sha) ?

mbed-os-6.2.0

What version(s) of tools are you using. List all that apply (E.g. mbed-cli)

mbed-cli

How is this defect reproduced ?

#include <events/mbed_events.h>
#include <mbed.h>

#include "ble/BLE.h"
#include "ble/Gap.h"
#include "ble/services/BatteryService.h"

static DigitalOut led1(LED1, 1);

const static char DEVICE_NAME[] = "BATTERY";

static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE);

class BatteryDemo : ble::Gap::EventHandler
{
public:
    BatteryDemo(BLE &ble, events::EventQueue &event_queue) :
        _ble(ble),
        _event_queue(event_queue),
        _battery_uuid(GattService::UUID_BATTERY_SERVICE),
        _battery_level(50),
        _battery_service(nullptr),
        _adv_data_builder(_adv_buffer)
    {
    }

    void start()
    {
        _ble.gap().setEventHandler(this);

        _ble.init(this, &BatteryDemo::on_init_complete);

        _event_queue.call_in(20000, this, &BatteryDemo::stopAndRestart);

        _event_queue.dispatch_forever();
    }

private:
    /** Callback triggered when the ble initialization process has finished */
    void on_init_complete(BLE::InitializationCompleteCallbackContext *params)
    {
        if (params->error != BLE_ERROR_NONE)
        {
            printf("Ble initialization failed.");
            return;
        }
        _battery_service = new BatteryService(_ble, _battery_level);
        start_advertising();
    }

    void start_advertising()
    {
        /* Create advertising parameters and payload */

        ble::AdvertisingParameters adv_parameters(ble::advertising_type_t::CONNECTABLE_UNDIRECTED,
                                                  ble::adv_interval_t(ble::millisecond_t(1000)));

        _adv_data_builder.setFlags();
        _adv_data_builder.setLocalServiceList(mbed::make_Span(&_battery_uuid, 1));
        _adv_data_builder.setName(DEVICE_NAME);

        /* Setup advertising */

        ble_error_t error = _ble.gap().setAdvertisingParameters(ble::LEGACY_ADVERTISING_HANDLE, adv_parameters);

        if (error)
        {
            printf("_ble.gap().setAdvertisingParameters() failed");
            return;
        }

        error =
            _ble.gap().setAdvertisingPayload(ble::LEGACY_ADVERTISING_HANDLE, _adv_data_builder.getAdvertisingData());

        if (error)
        {
            printf("_ble.gap().setAdvertisingPayload() failed");
            return;
        }

        /* Start advertising */

        error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);

        if (error)
        {
            printf("_ble.gap().startAdvertising() failed");
            return;
        }
    }

    void update_sensor_value()
    {
        _battery_level++;
        if (_battery_level > 100)
        {
            _battery_level = 20;
        }

        _battery_service->updateBatteryLevel(_battery_level);
    }

    void stopAndRestart(void)
    {
        _ble.shutdown();

        delete _battery_service;

        _ble.gap().setEventHandler(this);

        _ble.init(this, &BatteryDemo::on_init_complete);
    }

private:
    /* Event handler */

    void onDisconnectionComplete(const ble::DisconnectionCompleteEvent &)
    {
        _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
        event_queue.cancel(_update_sensor_event);
    }

    void onConnectionComplete(const ble::ConnectionCompleteEvent &)
    {
        _update_sensor_event = _event_queue.call_every(1000, this, &BatteryDemo::update_sensor_value);
    }

private:
    BLE &_ble;
    events::EventQueue &_event_queue;

    UUID _battery_uuid;

    uint8_t _battery_level;
    BatteryService *_battery_service;
    int _update_sensor_event;

    uint8_t _adv_buffer[ble::LEGACY_ADVERTISING_MAX_SIZE];
    ble::AdvertisingDataBuilder _adv_data_builder;
};

/** Schedule processing of events from the BLE middleware in the event queue. */
void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
{
    event_queue.call(Callback<void()>(&context->ble, &BLE::processEvents));
}

int main()
{
    BLE &ble = BLE::Instance();
    ble.onEventsToProcess(schedule_ble_events);

    BatteryDemo demo(ble, event_queue);
    demo.start();

    return 0;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions