Newer
Older
mbed-os / connectivity / FEATURE_BLE / include / ble / BLE.h
/* mbed Microcontroller Library
 * Copyright (c) 2006-2020 ARM Limited
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef MBED_BLE_H__
#define MBED_BLE_H__

#include "platform/mbed_error.h"
#include "platform/mbed_assert.h"
#include "platform/mbed_toolchain.h"

#include "ble/Gap.h"
#include "ble/GattClient.h"
#include "ble/GattServer.h"
#include "ble/SecurityManager.h"

#include "ble/common/BLERoles.h"
#include "ble/common/BLETypes.h"
#include "ble/common/blecommon.h"
#include "ble/common/FunctionPointerWithContext.h"

/* Forward declaration for the implementation class */

namespace ble {
class BLEInstanceBase;

/**
 * @addtogroup ble
 * @{
 */

/**
 * Abstract away BLE-capable radio transceivers or SOCs.
 *
 * Instances of this class have three responsibilities:
 *   - Initialize the inner BLE subsystem.
 *   - Signal user code that BLE events are available and an API to process them.
 *   - Manage access to the instances abstracting each BLE layer:
 *        + GAP: Handle advertising and scan, as well as connection and
 *          disconnection.
 *        + GATTServer: API to construct and manage a GATT server, which connected peers can
 *          access.
 *        + GATTClient: API to interact with a peer GATT server.
 *        + SecurityManager: API to manage security.
 *
 * The user should not create BLE instances directly but rather access to the
 * singleton(s) holding the BLE interfaces present in the system by using the
 * static function Instance().
 *
 * @code
 * #include "ble/BLE.h"
 *
 * BLE& ble_interface = BLE::Instance();
 * @endcode
 *
 * Next, the signal handling/process mechanism should be set up. By design,
 * Mbed BLE does not impose to the user an event handling/processing mechanism;
 * however, it exposes APIs, which allows an application to compose its own:
 *   - onEventsToProcess(), which registers a callback that
 *     the BLE subsystem will call when there is an event ready to be processed.
 *   - processEvents(), which processes all the events present in the BLE subsystem.
 *
 * It is common to bind BLE event mechanism with Mbed EventQueue:
 *
 * @code
 * #include <events/mbed_events.h>
 * #include "ble/BLE.h"
 *
 * // declare the event queue, which the whole application will share.
 * static EventQueue event_queue(4 * EVENTS_EVENT_SIZE);
 *
 * // Function invoked when there is a BLE event available.
 * // Event processing is put into the event queue.
 * void schedule_ble_processing(BLE::OnEventsToProcessCallbackContext* context) {
 *   event_queue.call(callback(&(context->ble), &BLE::processEvents));
 * }
 *
 * int main()
 * {
 *   BLE &ble_interface = BLE::Instance();
 *
 *   // Bind event signaling to schedule_ble_processing
 *   ble_interface.onEventsToProcess(schedule_ble_processing);
 *
 *   // Launch BLE initialisation
 *
 *   // Dispatch events in the event queue
 *   event_queue.dispatch_forever();
 *   return 0;
 * }
 * @endcode
 *
 * Once the event processing mechanism is in place, the Bluetooth subsystem can
 * be initialized with the init() function. That function accepts in input a
 * callback, which will be invoked once the initialization process has finished.
 *
 * @code
 * void on_ble_init_complete(BLE::InitializationCompleteCallbackContext *context)
 * {
 *   BLE& ble_interface = context->ble;
 *   ble_error_t initialization_error = context->error;
 *
 *   if (initialization_error) {
 *     // handle error
 *     return;
 *   }
 *
 *   // The BLE interface can be accessed now.
 * }
 *
 * int main() {
 *   BLE &ble_interface = BLE::Instance();
 *   ble_interface.onEventsToProcess(schedule_ble_processing);
 *
 *   // Initialize the BLE interface
 *   ble_interface.init(on_ble_init_complete);
 *
 *   event_queue.dispatch_forever();
 *   return 0;
 * }
 * @endcode
 */
class BLE {
public:
    /**
     * Opaque type used to store the ID of a BLE instance.
     * @deprecated BLE singleton supports one instance. You may create multiple instances by using the constructor.
     */
    typedef unsigned InstanceID_t;

    /**
     * The value of the BLE::InstanceID_t for the default BLE instance.
     * @deprecated BLE singleton supports one instance. You may create multiple instances by using the constructor.
     */
    static const InstanceID_t DEFAULT_INSTANCE = 0;

    /**
     * The number of permitted BLE instances for the application.
     * @deprecated BLE singleton supports one instance. You may create multiple instances by using the constructor.
     */
    static const InstanceID_t NUM_INSTANCES = 1;

    // Prevent copy construction and copy assignment of BLE.
    BLE(const BLE &) = delete;
    BLE &operator=(const BLE &) = delete;

    /**
     * Get a reference to the BLE singleton.
     *
     * @note Calling Instance() is preferred over constructing a BLE object
     * directly because it returns a reference to singleton.
     *
     * @return A reference to a single object.
     */
    static BLE &Instance();

    /**
     * Get a reference to the BLE singleton corresponding to a given interface.
     *
     * There is a static array of BLE singletons.
     *
     * @note Calling Instance() is preferred over constructing a BLE object
     * directly because it returns references to singletons.
     *
     * @param[in] id BLE Instance ID to get.
     *
     * @return A reference to a single object.
     *
     * @pre id shall be less than NUM_INSTANCES.
     *
     */
    MBED_DEPRECATED_SINCE("mbed-os-6.3.0", "BLE singleton supports one instance. You may create multiple"
                          "instances by using the constructor. Please use BLE::Instance().")
    static BLE &Instance(InstanceID_t id)
    {
        return Instance();
    }

    /**
     * Fetch the ID of a BLE instance.
     *
     * @return Instance id of this BLE instance.
     */
    MBED_DEPRECATED_SINCE("mbed-os-6.3.0", "BLE singleton supports one instance. You may create multiple"
                          "instances by using the constructor.")
    InstanceID_t getInstanceID() const
    {
        return DEFAULT_INSTANCE;
    }

    /**
     * Events to process event.
     *
     * Instances of OnEventsToProcessCallbackContext are passed to the event
     * handler registered with onEventsToProcess().
     */
    struct OnEventsToProcessCallbackContext {
        /**
         * The ble instance which have events to process.
         */
        BLE &ble;
    };

    /**
     * Events to process event handler
     */
    typedef FunctionPointerWithContext<OnEventsToProcessCallbackContext *>
        OnEventsToProcessCallback_t;

    /**
     * Register a callback called when the BLE stack has pending work.
     *
     * By registering a callback, application code can know when event processing
     * has to be scheduled.
     *
     * @param on_event_cb Callback invoked when there are new events to process.
     */
    void onEventsToProcess(const OnEventsToProcessCallback_t &on_event_cb);

    /**
     * Process ALL pending events living in the BLE stack and return once all
     * events have been consumed.
     *
     * @see onEventsToProcess()
     */
    void processEvents();

    /**
     * Initialization complete event.
     *
     * This event is generated at the end of the init() procedure and is passed
     * to the completion callback passed to init().
     */
    struct InitializationCompleteCallbackContext {
        /**
         * Reference to the BLE object that has been initialized
         */
        BLE &ble;

        /**
         * Error status of the initialization.
         *
         * That value is set to BLE_ERROR_NONE if initialization completed
         * successfully or the appropriate error code otherwise.
         * */
        ble_error_t error;
    };

    /**
     * Initialization complete event handler.
     *
     * @note There are two versions of init(). In addition to the
     * function-pointer, init() can also take an <Object, member> tuple as its
     * callback target. In case of the latter, the following declaration doesn't
     * apply.
     */
    typedef void (*InitializationCompleteCallback_t)(
        InitializationCompleteCallbackContext *context
    );

    /**
     * Initialize the BLE controller/stack.
     *
     * init() hands control to the underlying BLE module to accomplish
     * initialization. This initialization may tacitly depend on other hardware
     * setup (such as clocks or power-modes) that happens early on during system
     * startup. It may not be safe to call init() from a global static context
     * where ordering is compiler-specific and can't be guaranteed - it is safe
     * to call BLE::init() from within main().
     *
     * @param[in] completion_cb A callback for when initialization completes for
     * a BLE instance. This is an optional parameter; if no callback is set up,
     * the application can still determine the status of initialization using
     * BLE::hasInitialized() (see below).
     *
     * @return BLE_ERROR_NONE if the initialization procedure started
     * successfully.
     *
     * @note If init() returns BLE_ERROR_NONE, the underlying stack must invoke
     * the initialization completion callback at some point.
     *
     * @note Nearly all BLE APIs would return BLE_ERROR_INITIALIZATION_INCOMPLETE
     * if used on an instance before the corresponding transport is initialized.
     *
     * @note There are two versions of init(). In addition to the
     * function-pointer, init() can also take an <Object, member> pair as its
     * callback target.
     *
     * @attention This should be called before using anything else in the BLE
     * API.
     */
    ble_error_t init(InitializationCompleteCallback_t completion_cb = nullptr)
    {
        FunctionPointerWithContext<InitializationCompleteCallbackContext *> callback(completion_cb);
        return initImplementation(callback);
    }

    /**
     * Initialize the BLE controller/stack.
     *
     * This is an alternate declaration for init(). This one takes an
     * <Object, member> pair as its callback target.
     *
     * @param[in] object Object, which will be used to invoke the completion callback.
     * @param[in] completion_cb Member function pointer, which will be invoked when
     * initialization is complete.
     */
    template<typename T>
    ble_error_t init(T *object, void (T::*completion_cb)(InitializationCompleteCallbackContext *context))
    {
        FunctionPointerWithContext<InitializationCompleteCallbackContext *> callback(object, completion_cb);
        return initImplementation(callback);
    }

    /**
     * Indicate if the BLE instance has been initialized.
     *
     * @return true if initialization has completed for the underlying BLE
     * transport.
     *
     * @note The application should set up a callback to signal completion of
     * initialization when using init().
     */
    bool hasInitialized() const;

    /**
     * Shut down the underlying stack, and reset state of this BLE instance.
     *
     * @return BLE_ERROR_NONE if the instance was shut down without error or the
     * appropriate error code.
     *
     * @attention init() must be called afterward to reinstate services and
     * GAP state. This API offers a way to repopulate the GATT database with new
     * services and characteristics.
     */
    ble_error_t shutdown();

    /**
     * This call allows the application to get the BLE stack version information.
     *
     * @return A pointer to a const string representing the version.
     *
     * @note The BLE API owns the string returned.
     */
    const char *getVersion();

    /**
     * Accessor to Gap. All Gap-related functionality requires going through
     * this accessor.
     *
     * @return A reference to a Gap object associated to this BLE instance.
     */
    ble::Gap &gap();

    /**
     * A const alternative to gap().
     *
     * @return A const reference to a Gap object associated to this BLE instance.
     */
    const ble::Gap &gap() const;

#if BLE_FEATURE_GATT_SERVER
    /**
     * Accessor to GattServer. All GattServer related functionality requires
     * going through this accessor.
     *
     * @return A reference to a GattServer object associated to this BLE instance.
     */
    ble::GattServer &gattServer();

    /**
     * A const alternative to gattServer().
     *
     * @return A const reference to a GattServer object associated to this BLE
     * instance.
     */
    const ble::GattServer &gattServer() const;
#endif // BLE_FEATURE_GATT_SERVER

#if BLE_FEATURE_GATT_CLIENT
    /**
     * Accessors to GattClient. All GattClient related functionality requires
     * going through this accessor.
     *
     * @return A reference to a GattClient object associated to this BLE instance.
     */
    ble::GattClient &gattClient();

    /**
     * A const alternative to gattClient().
     *
     * @return A const reference to a GattClient object associated to this BLE
     * instance.
     */
    const ble::GattClient &gattClient() const;
#endif // BLE_FEATURE_GATT_CLIENT

#if BLE_FEATURE_SECURITY
    /**
     * Accessors to SecurityManager. All SecurityManager-related functionality
     * requires going through this accessor.
     *
     * @return A reference to a SecurityManager object associated to this BLE
     * instance.
     */
    ble::SecurityManager &securityManager();

    /**
     * A const alternative to securityManager().
     *
     * @return A const reference to a SecurityManager object associated to this
     * BLE instance.
     */
    const ble::SecurityManager &securityManager() const;
#endif // BLE_FEATURE_SECURITY

    /**
     * Translate error code into a printable string.
     *
     * @param[in] error Error code returned by BLE functions.
     *
     * @return A pointer to a const string describing the error.
     */
    static const char *errorToString(ble_error_t error);

    /**
     * This function allows the BLE stack to signal that there is work to do and
     * event processing should be done (BLE::processEvent()).
     *
     * @note This function should be called by the port of BLE_API. It is not
     * meant to be used by end users.
     */
    void signalEventsToProcess();

private:
    friend class ble::BLEInstanceBase;

    /**
     * Constructor for a handle to a BLE instance (the BLE stack). BLE handles
     * are thin wrappers around a transport object (that is, ptr. to
     * ble::BLEInstanceBase).
     *
     * @param[in] transport Ble transport used for the BLE instance.
     * @note Cordio supports only one instance.
     */
    BLE(ble::BLEInstanceBase &transport);

    /**
     * Implementation of init() [internal to BLE_API].
     *
     * The implementation is separated into a private method because it isn't
     * suitable to be included in the header.
     */
    ble_error_t initImplementation(
        FunctionPointerWithContext<InitializationCompleteCallbackContext *> callback
    );

private:
    ble::BLEInstanceBase &transport; /* The device-specific backend */
    OnEventsToProcessCallback_t whenEventsToProcess;
    bool event_signaled;
};


/**
 * @}
 */

}

using ble::BLE;
/**
 * @namespace ble Entry namespace for all BLE API definitions.
 */

#endif /* ifndef MBED_BLE_H__ */