LoginSignup
0

More than 1 year has passed since last update.

BLEモジュールnRF52シリーズにおけるCentralサービスを実装する仕組み

Last updated at Posted at 2021-09-13

記事の概要

Nordic社製のBLEモジュールのCentralサービスを作成します。
サービス名はorange_cとします。

実際に作成したプロジェクトは以下を参照ください。
https://github.com/matsuikosuke/nRF52_Central_and_Peripheral

サービスの実体

instance定義用のマクロを作成します。

orange_service_c.h
#define BLE_ORANGE_C_DEF(_name)                                                                        \
static ble_orange_c_t _name;                                                                           \
NRF_SDH_BLE_OBSERVER(_name ## _obs,                                                                 \
                     BLE_ORANGE_C_BLE_OBSERVER_PRIO,                                                   \
                     ble_orange_c_on_ble_evt, &_name)

複数のCentralサービスを使用する場合のマクロも作成しておきます。

orange_service_c.h
#define BLE_ORANGE_C_ARRAY_DEF(_name, _cnt)                                                            \
static ble_orange_c_t _name[_cnt];                                                                     \
NRF_SDH_BLE_OBSERVERS(_name ## _obs,                                                                \
                      BLE_ORANGE_C_BLE_OBSERVER_PRIO,                                                  \
                      ble_orange_c_on_ble_evt, &_name, _cnt)

UUID

UUIDを定義します。
ベースになるUUID、サービスUUID、サービスに付随するCharacteristicのUUIDを作成します。
例えばCharacteristicのUUIDはNotify用、Write用、read用などそれぞれの目的に合わせて使い分けます。

ベースUUIDのxxxxの部分にサービスUUIDやCharacteristicのUUIDを代入したものが使用されます。

orange_service_c.h
//BASE-UUID:4ab4xxxx-65bc-126e-3b8c-8345de91b0d3
#define ORANGE_UUID_BASE {0xd3, 0xb0, 0x91, 0xde, 0x45, 0x83, 0x8c, 0x3b, \
                              0x6e, 0x12, 0xbc, 0x65, 0x00, 0x00, 0xb4, 0x4a}
#define ORANGE_UUID_SERVICE               0xABC0
#define ORANGE_READ_UUID_CHAR            0xABC1  //Read
#define ORANGE_INDICATION_UUID_CHAR       0xABC2  //Indication
#define ORANGE_NOTIFICATION_UUID_CHAR     0xABC3  //Notification
#define ORANGE_WRITE_UUID_CHAR            0xABC4  //Write

BLEイベントタイプの構造体

サービスに関するイベントを定義します。
BLE接続確立時のイベント、Peripheral側からデータ受信時(Notification、Indicationなど)のイベントの構造体を作成しておく必要があります。

orange_service_c.h
typedef enum
{
    BLE_ORANGE_C_EVT_DISCOVERY_COMPLETE = 1,  /**< Event indicating that the ORANGE Service was discovered at the peer. */
    BLE_ORANGE_C_EVT_BUTTON_NOTIFICATION,      /**< Event indicating that a notification of the LED Button Button characteristic was received from the peer. */
    BLE_ORANGE_C_EVT_NOTIFICATION,       /**< Event indicating that a notification of the ORANGE characteristic has been received from the peer. */
    BLE_ORANGE_C_EVT_INDICATION,          /**< Event indicating that a indication of the ORANGE characteristic has been received from the peer. */
    BLE_ORANGE_C_EVT_READ
} ble_orange_c_evt_type_t;

サービスに関するハンドラの構造体

notification、notificationのCCCDコールバック、indication、notifyのCCCDコールバック、writeのようなCentralサービスに関するハンドラの構造体を作成します。

orange_service_c.h
typedef struct
{
    uint16_t orange_notify_cccd_handle;  /**< Handle of the CCCD of the Notify characteristic. */
    uint16_t orange_notify_handle;       /**< Handle of the Notify characteristic as provided by the SoftDevice. */
    uint16_t orange_write_handle;          /**< Handle of the Write characteristic as provided by the SoftDevice. */
    uint16_t orange_indicate_cccd_handle;  /**< Handle of the CCCD of the Indicate characteristic. */
    uint16_t orange_indicate_handle;       /**< Handle of the Indicate characteristic as provided by the SoftDevice. */
    uint16_t orange_read_handle;
} orange_db_t;

CCCDコールバックについては以下を参照してください。
CCCDコールバック関数の設定

BLEイベントの構造体

BLEイベントの構造体を作成します。
イベントタイプ、接続ハンドラ、イベントハンドラから成る構造体を作成します。

orange_service_c.h
typedef struct
{
    ble_orange_c_evt_type_t evt_type;    /**< Type of the event. */
    uint16_t             conn_handle; /**< Connection handle on which the event occured.*/
    union
    {
        ble_button_t button;          /**< Button value received. This is filled if the evt_type is @ref BLE_ORANGE_C_EVT_BUTTON_NOTIFICATION. */
        orange_db_t     peer_db;         /**< Handles related to the ORANGE Service found on the peer device. This is filled if the evt_type is @ref BLE_ORANGE_C_EVT_DISCOVERY_COMPLETE.*/
    } params;
} ble_orange_c_evt_t;

BLEベントに対する割り込み関数の定義

BLEイベントによる割り込み処理の関数を定義します。

orange_service_c.h
/**@brief   Event handler type.
 *
 * @details This is the type of the event handler that is to be provided by the application
 *          of this module in order to receive events.
 */
typedef void (* ble_orange_c_evt_handler_t) (ble_orange_c_t * p_ble_orange_c, ble_orange_c_evt_t * p_evt);

Centralサービスの構造体

Centralサービスに関する構造体を作成します。

orange_service_c.h
// Forward declaration of the ble_orange_c_t type.
typedef struct ble_orange_c_s ble_orange_c_t;

/**@brief Orange Client structure. */
struct ble_orange_c_s
{
    uint16_t                     conn_handle;     /**< Connection handle as provided by the SoftDevice. */
    orange_db_t                  peer_orange_db;  /**< Handles related to ORANGE on the peer. */
    ble_orange_c_evt_handler_t   evt_handler;     /**< Application event handler to be called when there is an event related to the Orange service. */
    ble_srv_error_handler_t      error_handler;   /**< Function to be called in case of an error. */
    uint8_t                      uuid_type;       /**< UUID type. */
    nrf_ble_gq_t                 * p_gatt_queue;  /**< Pointer to the BLE GATT Queue instance. */
};

Centralサービス初期化の構造体

Centralサービス初期設定の構造体を作成します。

orange_service_c.h
/**@brief Orange Client initialization structure. */
typedef struct
{
    ble_orange_c_evt_handler_t   evt_handler;   /**< Event handler to be called by the Orange Client module when there is an event related to the ORANGE Service. */
    nrf_ble_gq_t            * p_gatt_queue;  /**< Pointer to the BLE GATT Queue instance. */
    ble_srv_error_handler_t   error_handler; /**< Function to be called in case of an error. */
} ble_orange_c_init_t;

Centaralサービス初期化処理

各種ハンドラの設定、UUIDの設定を行います

orange_service_c.c
uint32_t ble_orange_c_init(ble_orange_c_t * p_ble_orange_c, ble_orange_c_init_t * p_ble_orange_c_init)
{
    uint32_t      err_code;
    ble_uuid_t    orange_uuid;
    ble_uuid128_t orange_base_uuid = {ORANGE_UUID_BASE};

    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c_init);
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c_init->evt_handler);
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c_init->p_gatt_queue);

    p_ble_orange_c->conn_handle                    = BLE_CONN_HANDLE_INVALID;
    p_ble_orange_c->evt_handler                    = p_ble_orange_c_init->evt_handler;
    p_ble_orange_c->p_gatt_queue                   = p_ble_orange_c_init->p_gatt_queue;
    p_ble_orange_c->error_handler                  = p_ble_orange_c_init->error_handler;

    err_code = sd_ble_uuid_vs_add(&orange_base_uuid, &p_ble_orange_c->uuid_type);
    if (err_code != NRF_SUCCESS)
    {
        return err_code;
    }
    VERIFY_SUCCESS(err_code);

    orange_uuid.type = p_ble_orange_c->uuid_type;
    orange_uuid.uuid = ORANGE_UUID_SERVICE;

    return ble_db_discovery_evt_register(&orange_uuid);
}

GATTエラー割り込み処理

orange_service_c.c
static void gatt_error_handler(uint32_t   nrf_error,
                               void     * p_ctx,
                               uint16_t   conn_handle)
{
    ble_orange_c_t * p_ble_orange_c = (ble_orange_c_t *)p_ctx;

    NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);

    if (p_ble_orange_c->error_handler != NULL)
    {
        p_ble_orange_c->error_handler(nrf_error);
    }
}

BLEイベント処理

BLEイベント処理です。
BLEイベント割り込み処理ble_evt_handlerから呼び出されます。
p_ble_evt->header.evt_idがBLEデータ受信イベントBLE_GATTC_EVT_HVXかBLE切断イベントBLE_GAP_EVT_DISCONNECTEDBLE_GATTC_EVT_READ_RSPかを判定して分岐し、イベントに対応する処理を実行します。

orange_service_c.c
void ble_orange_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    if ((p_context == NULL) || (p_ble_evt == NULL))
    {
        return;
    }

    ble_orange_c_t * p_ble_orange_c = (ble_orange_c_t *)p_context;

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GATTC_EVT_HVX:
            on_hvx(p_ble_orange_c, p_ble_evt);
            break;

        case BLE_GATTC_EVT_READ_RSP:
            on_read_rsp(p_ble_orange_c, p_ble_evt);
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnected(p_ble_orange_c, p_ble_evt);
            break;

        default:
            break;
    }
}

BLE_GATTC_EVT_HVX:BLEデータ受信イベント処理

Notification、Indicationを受信した時に行う処理です。
必須の処理に加えて、アプリケーションの仕様に基づいて処理を追加ください。

orange_service_c.c
static void on_hvx(ble_orange_c_t * p_ble_orange_c, ble_evt_t const * p_ble_evt)
{
    // Check if the event is on the link for this instance.
    if (p_ble_orange_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
    {
        return;
    }
    // Check if this is a SmartAgri notification.
    if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_orange_c->peer_orange_db.orange_notify_handle)
    {
            ble_orange_c_evt_t ble_orange_c_evt;
            uint32_t        index = 0;

            ble_orange_c_evt.evt_type                   = BLE_ORANGE_C_EVT_NOTIFICATION;
            ble_orange_c_evt.conn_handle                = p_ble_orange_c->conn_handle;  //By seeing this information, it is determined which device the transmission is from.

            for (int i = 0; i < BLE_NOTIFICATION_DATA_LENGTH; i ++)
            {
                if (index >= p_ble_evt->evt.gattc_evt.params.hvx.len)
                {
                    break;
                }
                notification_buf[i] = p_ble_evt->evt.gattc_evt.params.hvx.data[index];
                index += 1;
            }

            p_ble_orange_c->evt_handler(p_ble_orange_c, &ble_orange_c_evt);
    }
    // Check if this is a SmartAgri indication.
    if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_orange_c->peer_orange_db.orange_indicate_handle)
    {
            ble_orange_c_evt_t ble_orange_c_evt;
            uint32_t        index = 0;

            ble_orange_c_evt.evt_type                   = BLE_ORANGE_C_EVT_INDICATION;
            ble_orange_c_evt.conn_handle                = p_ble_orange_c->conn_handle;  //By seeing this information, it is determined which device the transmission is from.

            for (int i = 0; i < BLE_INDICATION_DATA_LENGTH; i ++)
            {
                if (index >= p_ble_evt->evt.gattc_evt.params.hvx.len)
                {
                    break;
                }
                indication_buf[i] = p_ble_evt->evt.gattc_evt.params.hvx.data[index];
                index += 1;
            }

            // In case of Indicate, you have to add the following function that returns an ACK response
            sd_ble_gattc_hv_confirm(ble_orange_c_evt.conn_handle,  p_ble_orange_c->peer_orange_db.orange_indicate_handle);

            p_ble_orange_c->evt_handler(p_ble_orange_c, &ble_orange_c_evt);
    }
}

この処理の内容について以下に説明します。

接続ハンドラの確認

    // Check if the event is on the link for this instance.
    if (p_ble_orange_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
    {
        return;
    }

p_ble_evt->evt.gattc_evt.conn_handlep_ble_orange_c->conn_handleと一致しているか確認します。
複数のCentralサービスを実装している場合、p_ble_evt->evt.gattc_evt.conn_handleには他のサービスの接続ハンドラが格納されているかもしれません。
その場合はOrangeサービスを適用していはいけないので処理を終了します。

p_ble_evt->evt.gattc_evt.params.hvx.handleの確認

p_ble_evt->evt.gattc_evt.params.hvx.handleがサービスハンドラ構造体orange_db_tのどれに対応するか確認します。
ただしhvx.handleには受信に関するイベントしかないので、今回はNotificationもしくはIndicationに関するイベントであるorange_notify_handleorange_indicate_handle`のどちらかになります。

受信データの確認

p_ble_evt->evt.gattc_evt.params.hvx.lenには受信データのサイズが格納されています。
p_ble_evt->evt.gattc_evt.params.hvx.data[]には受信データが格納されています。

割り込み処理はなるべく短時間で済ませたいので、データをバッファに一時退避させてから、mainループ内で受信データの解析処理をした方がいいと考えて、受信データをindication_bufに格納しています。

受信タイプの保存と受信割り込み処理の実行

ble_orange_c_evt.evt_typeにイベントタイプを保存します。
ble_orange_c_evt.conn_handleにはp_ble_orange_c->conn_handleを保存します。

これらを用いてイベントに対応する割り込み処理を呼び出します。

p_ble_orange_c->evt_handler(p_ble_orange_c, &ble_orange_c_evt);

これにより割り込み処理orange_c_evt_handlerにおいて、BLEイベントble_orange_c_evt_type_tに対応する処理が実行されます。
今回の場合はBLEイベントBLE_ORANGE_C_EVT_NOTIFICATIONもしくはBLE_ORANGE_C_EVT_INDICATIONが使用されます。

Indication ACK応答

Indication受信時には、CentralからPeripheralに対してACK応答を送信しないといけません。
以下の処理をそれを実行しています。

// In case of Indicate, you have to add the following function that returns an ACK response
sd_ble_gattc_hv_confirm(ble_orange_c_evt.conn_handle,  p_ble_orange_c->peer_orange_db.orange_indicate_handle);

BLE_GAP_EVT_DISCONNECTED:BLE切断イベント処理

BLE切断時に行う処理です。
各種ハンドラを初期化します。

orange_service_c.c
static void on_disconnected(ble_orange_c_t * p_ble_orange_c, ble_evt_t const * p_ble_evt)
{
    if (p_ble_orange_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
    {
        p_ble_orange_c->conn_handle                    = BLE_CONN_HANDLE_INVALID;
        p_ble_orange_c->peer_orange_db.orange_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_orange_c->peer_orange_db.orange_notify_handle      = BLE_GATT_HANDLE_INVALID;
        p_ble_orange_c->peer_orange_db.orange_write_handle         = BLE_GATT_HANDLE_INVALID;
        p_ble_orange_c->peer_orange_db.orange_indicate_cccd_handle = BLE_GATT_HANDLE_INVALID;
        p_ble_orange_c->peer_orange_db.orange_indicate_handle      = BLE_GATT_HANDLE_INVALID;
    }
}

BLE_GATTC_EVT_READ_RSP:Read受信処理

Read要求を実行することでPeripheralからReadデータが送信されます。
BLE_GATTC_EVT_READ_RSPは、そのデータを受信時に発生するイベントです。

orange_service_c.c
static void on_read_rsp(ble_orange_c_t *p_ble_orange_c, ble_evt_t const *p_ble_evt)
{
    ble_gattc_evt_read_rsp_t const *p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
    ble_orange_c_evt_t ble_orange_c_evt;

    // Check if the event is on the link for this instance and the event handler is present.
    if ((p_ble_orange_c->evt_handler == NULL) ||
        (p_ble_orange_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle))
    {
        return;
    }

    if (p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_SUCCESS)
    {
        if (p_response->handle == p_ble_orange_c->peer_orange_db.orange_read_handle)
        {
            ble_orange_c_evt.evt_type = BLE_ORANGE_C_EVT_READ;
            ble_orange_c_evt.conn_handle = p_ble_orange_c->conn_handle;
            NRF_LOG_INFO("Received read data %lu of length %u", * (uint32_t *) p_response->data, p_response->len);

            for(int i=0; i<p_response->len; i++)
            {
                central_read_buf[i] = p_response->data[i];
            }

            p_ble_orange_c->evt_handler(p_ble_orange_c, &ble_orange_c_evt);
        }
    }
}

Write送信処理

CentralからPeripheralへデータをWrite送信する処理です。
この関数はstatusに格納したデータを送信します。

orange_service_c.c
uint32_t ble_orange_status_send(ble_orange_c_t * p_ble_orange_c, uint8_t status)
{
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);

    if (p_ble_orange_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    NRF_LOG_DEBUG("Writing orange status 0x%x", status);

    nrf_ble_gq_req_t write_req;

    memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));

    write_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    write_req.error_handler.cb            = gatt_error_handler;
    write_req.error_handler.p_ctx         = p_ble_orange_c;
    write_req.params.gattc_write.handle   = p_ble_orange_c->peer_orange_db.orange_write_handle;
    write_req.params.gattc_write.len      = sizeof(status);
    write_req.params.gattc_write.p_value  = &status;
    write_req.params.gattc_write.offset   = 0;
    write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD; 

    return nrf_ble_gq_item_add(p_ble_orange_c->p_gatt_queue, &write_req, p_ble_orange_c->conn_handle);
}

Read要求

Read要求ble_orange_read_requestを実行することで、PeripheralからReadデータが返ってきます。
Readデータ受信時にはble_orange_c_on_ble_evt割り込み処理においてイベントBLE_GATTC_EVT_READ_RSPが呼び出されます。

orange_service_c.c
uint32_t ble_orange_read_request(ble_orange_c_t * p_ble_orange_c)
{
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);

    if (p_ble_orange_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    NRF_LOG_DEBUG("Read orange");

    nrf_ble_gq_req_t read_req;

    memset(&read_req, 0, sizeof(nrf_ble_gq_req_t));

    read_req.type                        = NRF_BLE_GQ_REQ_GATTC_READ;
    read_req.error_handler.cb            = gatt_error_handler;
    read_req.error_handler.p_ctx         = p_ble_orange_c;
    read_req.params.gattc_read.handle   = p_ble_orange_c->peer_orange_db.orange_read_handle;

    return nrf_ble_gq_item_add(p_ble_orange_c->p_gatt_queue, &read_req, p_ble_orange_c->conn_handle);
}

Discoveryイベント処理

Discoveryイベント処理においては、CentralサービスとのBLE接続確立後、Characteristicに対応するハンドラを設定します。

p_evt->params.discovered_db.char_countにはCentralサービスに含まれるCharacteristic数が格納されています。
それらのCharacteristicのUUIDp_char->characteristic.uuid.uuidを1つずつ確認し、Characteristicに対応するハンドルを設定します。

またconn_handle以外のハンドラが既に設定済みでないかを確認し、設定済みなら既存の設定evt.params.peer_dbを代入します。

orange_service_c.c
void ble_orange_on_db_disc_evt(ble_orange_c_t * p_ble_orange_c, ble_db_discovery_evt_t const * p_evt)
{
    // Check if the Test Service was discovered.
    if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
        p_evt->params.discovered_db.srv_uuid.uuid == ORANGE_UUID_SERVICE &&
        p_evt->params.discovered_db.srv_uuid.type == p_ble_orange_c->uuid_type)
    {
        ble_orange_c_evt_t evt;

        evt.evt_type    = BLE_ORANGE_C_EVT_DISCOVERY_COMPLETE;
        evt.conn_handle = p_evt->conn_handle;

        for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
        {
            const ble_gatt_db_char_t * p_char = &(p_evt->params.discovered_db.charateristics[i]);
            switch (p_char->characteristic.uuid.uuid)
            {
                case ORANGE_WRITE_UUID_CHAR:
                    evt.params.peer_db.orange_write_handle = p_char->characteristic.handle_value;
                    break;

                case ORANGE_NOTIFICATION_UUID_CHAR:
                    evt.params.peer_db.orange_notify_handle      = p_char->characteristic.handle_value;
                    evt.params.peer_db.orange_notify_cccd_handle = p_char->cccd_handle;
                    break;

                case ORANGE_INDICATION_UUID_CHAR:
                    evt.params.peer_db.orange_indicate_handle      = p_char->characteristic.handle_value;
                    evt.params.peer_db.orange_indicate_cccd_handle = p_char->cccd_handle;
                    break;

                default:
                    break;
            }
        }

        NRF_LOG_DEBUG("Orange Service discovered at peer.");
        //If the instance was assigned prior to db_discovery, assign the db_handles
        if (p_ble_orange_c->conn_handle != BLE_CONN_HANDLE_INVALID)
        {
            if ((p_ble_orange_c->peer_orange_db.orange_write_handle         == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_orange_c->peer_orange_db.orange_notify_handle      == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_orange_c->peer_orange_db.orange_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_orange_c->peer_orange_db.orange_indicate_handle      == BLE_GATT_HANDLE_INVALID)&&
                (p_ble_orange_c->peer_orange_db.orange_indicate_cccd_handle == BLE_GATT_HANDLE_INVALID))
            {
                p_ble_orange_c->peer_orange_db = evt.params.peer_db;
            }
        }

        p_ble_orange_c->evt_handler(p_ble_orange_c, &evt);

    }
}

CCCDコールバック設定処理

CCCDコールバック設定処理です。
BLEイベント割り込み処理orange_c_evt_handlerBLE_ORANGE_C_EVT_DISCOVERY_COMPLETEイベント発生時に実行します。

orange_service_c.c
static uint32_t cccd_configure_notify(ble_orange_c_t * p_ble_orange_c, bool enable)
{
    NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
                  p_ble_orange_c->peer_orange_db.orange_notify_cccd_handle,
                  p_ble_orange_c->conn_handle);

    nrf_ble_gq_req_t cccd_req;
    uint16_t         cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
    uint8_t          cccd[WRITE_MESSAGE_LENGTH];

    cccd[0] = LSB_16(cccd_val);
    cccd[1] = MSB_16(cccd_val);

    cccd_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    cccd_req.error_handler.cb            = gatt_error_handler;
    cccd_req.error_handler.p_ctx         = p_ble_orange_c;
    cccd_req.params.gattc_write.handle   = p_ble_orange_c->peer_orange_db.orange_notify_cccd_handle;
    cccd_req.params.gattc_write.len      = WRITE_MESSAGE_LENGTH;
    cccd_req.params.gattc_write.offset   = 0;
    cccd_req.params.gattc_write.p_value  = cccd;
    cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;

    return nrf_ble_gq_item_add(p_ble_orange_c->p_gatt_queue, &cccd_req, p_ble_orange_c->conn_handle);
}

static uint32_t cccd_configure_indicate(ble_orange_c_t * p_ble_orange_c, bool enable)
{
    NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
                  p_ble_orange_c->peer_orange_db.orange_indicate_cccd_handle,
                  p_ble_orange_c->conn_handle);

    nrf_ble_gq_req_t cccd_req;
    uint16_t         cccd_val = enable ? BLE_GATT_HVX_INDICATION : 0;
    uint8_t          cccd[WRITE_MESSAGE_LENGTH];

    cccd[0] = LSB_16(cccd_val);
    cccd[1] = MSB_16(cccd_val);

    cccd_req.type                        = NRF_BLE_GQ_REQ_GATTC_WRITE;
    cccd_req.error_handler.cb            = gatt_error_handler;
    cccd_req.error_handler.p_ctx         = p_ble_orange_c;
    cccd_req.params.gattc_write.handle   = p_ble_orange_c->peer_orange_db.orange_indicate_cccd_handle;
    cccd_req.params.gattc_write.len      = WRITE_MESSAGE_LENGTH;
    cccd_req.params.gattc_write.offset   = 0;
    cccd_req.params.gattc_write.p_value  = cccd;
    cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;

    return nrf_ble_gq_item_add(p_ble_orange_c->p_gatt_queue, &cccd_req, p_ble_orange_c->conn_handle);
}

uint32_t ble_orange_c_orange_notification_enable(ble_orange_c_t * p_ble_orange_c)
{
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);

    if (p_ble_orange_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    return cccd_configure_notify(p_ble_orange_c, true);
}

uint32_t ble_orange_c_orange_indication_enable(ble_orange_c_t * p_ble_orange_c)
{
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);

    if (p_ble_orange_c->conn_handle == BLE_CONN_HANDLE_INVALID)
    {
        return NRF_ERROR_INVALID_STATE;
    }

    return cccd_configure_indicate(p_ble_orange_c, true);
}

BLEハンドラ登録処理

BLEハンドラ登録処理です。BLEイベント割り込み処理orange_c_evt_handlerBLE_ORANGE_C_EVT_DISCOVERY_COMPLETEイベント発生時に実行します。

orange_service_c.c
uint32_t ble_orange_c_handles_assign(ble_orange_c_t    * p_ble_orange_c,
                                  uint16_t         conn_handle,
                                  const orange_db_t * p_peer_handles)
{
    VERIFY_PARAM_NOT_NULL(p_ble_orange_c);

    p_ble_orange_c->conn_handle = conn_handle;
    if (p_peer_handles != NULL)
    {
        p_ble_orange_c->peer_orange_db = *p_peer_handles;
    }
    return nrf_ble_gq_conn_handle_register(p_ble_orange_c->p_gatt_queue, conn_handle);
}

参照

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
0