LoginSignup
3
1

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);
}

参照

3
1
0

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
  3. You can use dark theme
What you can do with signing up
3
1