区荣杰 4 жил өмнө
parent
commit
01e77a212f

+ 79 - 0
profiles/service/bsal_hid/README.md

@@ -0,0 +1,79 @@
+# 关于未完成的 HOGP
+
+## 一、简介
+
+HID over GATT Profile(HOGP),利用 LE 的基本协议 GATT 实现 HID Host 与 Device 的交互。
+
+本项目目标是基于 BSAL 实现 HOGP,完成一个鼠标的 sample。
+
+本项目目前开发使用的开发板是 PCA10056,BSAL 使用的协议栈是 Nimble。
+
+
+
+## 二、参考
+
+以 Nordic 官方 [nRF5_SDK_17.1.0](https://www.nordicsemi.com/Products/Development-software/nrf5-sdk/download) 中 \examples\ble_peripheral\ble_app_hids_mouse\pca10056\s140\arm5_no_packs 作参考。
+
+相关文件已放在 Softdevice 文件夹内。
+
+### 2.1 测试方法
+
+打开官方 sdk 的 hid sample 工程,板子连接上之后,首先将板子完全擦除一遍。使用 sde 规则擦除芯片:
+
+<img src="images/2021-10-12135211.jpg" alt="2021-10-12135211" style="zoom:33%;" />
+
+擦除完芯片后,将工程切换至 Softdevice 目标,并下载(不需要编译):
+
+<img src="images/2021-10-12135502.jpg" alt="2021-10-12135502" style="zoom:33%;" />
+
+下载完 Softdevice 后,再将工程目标切换为 nrf52840_xxaa ,编译并下载。此时,打开串口工具,按下板子的复位键,就能看到有打印信息出来。
+
+打开电脑的蓝牙,搜索设备,连接板子(此时板子是一个鼠标设备)。连接成功后,按下板子的按键,电脑的鼠标就能上下左右移动了。
+
+手机(安卓)同理,打开蓝牙,搜索设备,连接板子。连接成功后,按下板子上的按键,手机屏幕上便会出现一个鼠标,这个鼠标也会移动。
+
+需要注意的是,有时候会出现怎么也连不上板子蓝牙的情况。这时候需要将板子擦除一次,并重新烧录文件。有可能是程序对上一次连接的设备做了记录,导致下一次就不能连接其他设备了。
+
+### 2.2 抓包
+
+利用手机进行了一次抓包,抓包文件在当前目录下的 btsnoop_hci_hid.cfa 文件。可以使用 Frontline 查看文件。具体抓包与查看文件[教程链接](https://supperthomas-wiki.readthedocs.io/en/latest/03_xupenghu/04_btsnoop_hci/android_hci.html)。
+
+抓包的操作过程:首先擦除芯片,重新烧录文件。然后手机开启抓包模式,在设置->蓝牙里,连接上板子。逐一按下板子的四个按键,鼠标向上下左右四个方向移动了一点距离,抓包操作结束。
+
+
+
+## 三、目前进度
+
+### 3.1 sample 需要的各种 Service 的注册已实现
+
+按照参考的工程,各种 Service 的注册已实现,包括 HID,BAS,DIS 等等。即目前手机连接上后,用 nRF Connect 看到的 Service 与参考工程的一致。但 Service 里的功能尚未实现。比如说 hid上传到 bsal 层的各种中断还没处理。
+
+### 3.2 目前卡在发送数组(Report Map 特性)
+
+#### 3.2.1 抓包的分析与结论
+
+官方 sdk 中,有一个很长的配置用的数组(Report Map),用以告诉 host 一些配置信息。但是不是很清楚这个数组是何时、怎么发送过去的。分析抓包数据:
+
+<img src="images/2021-10-12145729.jpg" alt="2021-10-12145729" style="zoom:33%;" />
+
+可以看到,第2004帧,host 端发送一个读请求,请求读取 Report Map 数据。之后,设备分七次将 Report Map 数据发送过去。
+
+因此,这个数组是 hid 下的 Report Map 特性的一个值,当 host 请求读取 Report Map 特性值时,便要将数组发送过去。要实现的就是这个发送过程。
+
+#### 3.2.2 手机请求读取 Report Map 数据时,没有中断传上来
+
+手机用 nRF Connect 连接上设备后,读取 Report Map 特性无反应,调试发现读请求中断没有上传到 BSAL。
+
+为了排除是服务、特性之间的影响,我只保留一个 Service 和一个特性,将其他全部注释掉(现在 bsal_srv_hid.c 便是如此)。发现 hid 服务下,除了几个特性以外,其他的特性的读、写请求中断均无法上传到 BSAL 层。
+
+一开始怀疑是 BSAL 层某些部分未实现,尝试 debug 后发现,原来在 nimble 就已经没有中断上传上来了。不是 BSAL 的问题,便没有继续往 nimble 去 debug 了。
+
+目前怀疑两个地方:一个是 nimble 的 rt-thread 接口部分会不会有 bug;一个是手机连接会不会有问题。
+
+- 第一个,nimble 的 ops 函数会不会有问题,特别是注册 Service 的那条函数,以及 nimble 的读写中断向 BSAL 传时会不会有 bug。
+
+- 第二个,在猜测有没有可能在连接时需要一些加密,或者验证等,才能继续后面读取 Report Map 操作。
+
+
+
+项目未完,待续……

+ 1576 - 0
profiles/service/bsal_hid/Softdevice/ble_hids.c

@@ -0,0 +1,1576 @@
+/**
+ * Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ *    Semiconductor ASA integrated circuit in a product or a software update for
+ *    such product, must reproduce the above copyright notice, this list of
+ *    conditions and the following disclaimer in the documentation and/or other
+ *    materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ *    Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ *    engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/* Attention!
+ * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
+ * qualification listings, this section of source code must not be modified.
+ */
+#include "sdk_common.h"
+#if NRF_MODULE_ENABLED(BLE_HIDS)
+#include "ble_hids.h"
+#include <string.h>
+#include "app_error.h"
+#include "ble_srv_common.h"
+
+
+// Protocol Mode values
+#define PROTOCOL_MODE_BOOT               0x00                        /**< Boot Protocol Mode. */
+#define PROTOCOL_MODE_REPORT             0x01                        /**< Report Protocol Mode. */
+
+// HID Control Point values
+#define HIDS_CONTROL_POINT_SUSPEND       0                           /**< Suspend command. */
+#define HIDS_CONTROL_POINT_EXIT_SUSPEND  1                           /**< Exit Suspend command. */
+
+#define DEFAULT_PROTOCOL_MODE            PROTOCOL_MODE_REPORT        /**< Default value for the Protocol Mode characteristic. */
+#define INITIAL_VALUE_HID_CONTROL_POINT  HIDS_CONTROL_POINT_SUSPEND  /**< Initial value for the HID Control Point characteristic. */
+
+#define ENCODED_HID_INFORMATION_LEN      4                           /**< Maximum size of an encoded HID Information characteristic. */
+
+/**@brief Handles errors for HID service module.
+ *
+ * @param[in]   _p_hids   HID Service structure.
+ * @param[in]   _err_code Maximum number of HID hosts connected at a time.
+ *
+ */
+#define BLE_HIDS_ERROR_HANDLE(_p_hids, _err_code)                               \
+    do                                                                          \
+    {                                                                           \
+        if (((_err_code) != NRF_SUCCESS) && ((_p_hids)->error_handler != NULL)) \
+        {                                                                       \
+            (_p_hids)->error_handler((_err_code));                              \
+        }                                                                       \
+    } while (0)
+
+
+/**@brief Function for calculating the link context size for the HID service.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ *
+ * @return      Link context size.
+ */
+static size_t ble_hids_client_context_size_calc(ble_hids_t * p_hids)
+{
+    size_t client_size = sizeof(ble_hids_client_context_t) + (BOOT_KB_INPUT_REPORT_MAX_SIZE) +
+                         (BOOT_KB_OUTPUT_REPORT_MAX_SIZE) + (BOOT_MOUSE_INPUT_REPORT_MAX_SIZE);
+
+    if (p_hids->p_inp_rep_init_array != NULL)
+    {
+        for (uint32_t i = 0; i < p_hids->inp_rep_count; i++)
+        {
+            client_size += p_hids->p_inp_rep_init_array[i].max_len;
+        }
+    }
+    if (p_hids->p_outp_rep_init_array != NULL)
+    {
+        for (uint32_t i = 0; i < p_hids->outp_rep_count; i++)
+        {
+            client_size += p_hids->p_outp_rep_init_array[i].max_len;
+        }
+    }
+    if (p_hids->p_feature_rep_init_array != NULL)
+    {
+        for (uint32_t i = 0; i < p_hids->feature_rep_count; i++)
+        {
+            client_size += p_hids->p_feature_rep_init_array[i].max_len;
+        }
+    }
+
+    return client_size;
+}
+
+
+/**@brief Function for making a HID Service characteristic id.
+ *
+ * @param[in]   uuid        UUID of characteristic.
+ * @param[in]   rep_type    Type of report.
+ * @param[in]   rep_index   Index of the characteristic.
+ *
+ * @return      HID Service characteristic id structure.
+ */
+static ble_hids_char_id_t make_char_id(uint16_t uuid, uint8_t rep_type, uint8_t rep_index)
+{
+    ble_hids_char_id_t char_id = {0};
+
+    char_id.uuid      = uuid;
+    char_id.rep_type  = rep_type;
+    char_id.rep_index = rep_index;
+
+    return char_id;
+}
+
+
+/**@brief Function for handling the Connect event.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   p_ble_evt   Event received from the BLE stack.
+ */
+static void on_connect(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    uint32_t                    err_code;
+    ble_gatts_value_t           gatts_value;
+    ble_hids_client_context_t * p_client = NULL;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gap_evt.conn_handle,
+                                 (void *) &p_client);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+    if (p_client == NULL)
+    {
+        return;
+    }
+
+    memset(p_client, 0, ble_hids_client_context_size_calc(p_hids));
+
+    if (p_hids->protocol_mode_handles.value_handle)
+    {
+        // Set Protocol Mode characteristic value to default value
+        p_client->protocol_mode = DEFAULT_PROTOCOL_MODE;
+
+        // Initialize value struct.
+        memset(&gatts_value, 0, sizeof(gatts_value));
+
+        gatts_value.len     = sizeof(uint8_t);
+        gatts_value.offset  = 0;
+        gatts_value.p_value = &p_client->protocol_mode;
+
+        err_code = sd_ble_gatts_value_set(p_ble_evt->evt.gap_evt.conn_handle,
+                                          p_hids->protocol_mode_handles.value_handle,
+                                          &gatts_value);
+        BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+    }
+}
+
+
+/**@brief Function for handling write events to the HID Control Point value.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_evt_write   Write event received from the BLE stack.
+ */
+static void on_control_point_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    ret_code_t                        err_code;
+    ble_hids_client_context_t       * p_host;
+    ble_gatts_evt_write_t     const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gatts_evt.conn_handle,
+                                 (void *) &p_host);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+    if (p_host == NULL)
+    {
+        return;
+    }
+
+    if (p_evt_write->len == 1)
+    {
+        ble_hids_evt_t evt;
+
+        switch (p_evt_write->data[0])
+        {
+            case HIDS_CONTROL_POINT_SUSPEND:
+                evt.evt_type = BLE_HIDS_EVT_HOST_SUSP;
+                break;
+
+            case HIDS_CONTROL_POINT_EXIT_SUSPEND:
+                evt.evt_type = BLE_HIDS_EVT_HOST_EXIT_SUSP;
+                break;
+
+            default:
+                // Illegal Control Point value, ignore
+                return;
+        }
+
+        // Store the new Control Point value for the host
+        p_host->ctrl_pt = p_evt_write->data[0];
+
+        // HID Control Point written, propagate event to application
+        if (p_hids->evt_handler != NULL)
+        {
+            evt.p_ble_evt = p_ble_evt;
+            p_hids->evt_handler(p_hids, &evt);
+        }
+    }
+}
+
+
+/**@brief Function for handling write events to the Protocol Mode value.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_ble_evt     BLE event received from the BLE stack.
+ */
+static void on_protocol_mode_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    ret_code_t                        err_code;
+    ble_hids_client_context_t       * p_host;
+    ble_gatts_evt_write_t     const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gatts_evt.conn_handle,
+                                 (void *) &p_host);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+
+    if (p_host == NULL)
+    {
+        return;
+    }
+
+    if (p_evt_write->len == 1)
+    {
+        ble_hids_evt_t evt;
+
+        switch (p_evt_write->data[0])
+        {
+            case PROTOCOL_MODE_BOOT:
+                evt.evt_type = BLE_HIDS_EVT_BOOT_MODE_ENTERED;
+                break;
+
+            case PROTOCOL_MODE_REPORT:
+                evt.evt_type = BLE_HIDS_EVT_REPORT_MODE_ENTERED;
+                break;
+
+            default:
+                // Illegal Protocol Mode value, ignore
+                return;
+        }
+
+        // Store Protocol Mode of the host
+        p_host->protocol_mode = p_evt_write->data[0];
+
+        // HID Protocol Mode written, propagate event to application
+        if (p_hids->evt_handler != NULL)
+        {
+            evt.p_ble_evt = p_ble_evt;
+            p_hids->evt_handler(p_hids, &evt);
+        }
+    }
+}
+
+
+/**@brief Function for handling authorize read events to the Protocol Mode value.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_ble_evt     BLE event received from the BLE stack.
+ */
+void on_protocol_mode_read_auth(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    ret_code_t                                   err_code;
+    ble_gatts_rw_authorize_reply_params_t        auth_read_params;
+    ble_hids_client_context_t                  * p_host;
+    ble_gatts_evt_rw_authorize_request_t const * p_read_auth =
+        &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gatts_evt.conn_handle,
+                                 (void *) &p_host);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+    // Update GATTS table with this host's Protocol Mode value and authorize Read
+    if (p_host != NULL)
+    {
+        memset(&auth_read_params, 0, sizeof(auth_read_params));
+
+        auth_read_params.type                    = BLE_GATTS_AUTHORIZE_TYPE_READ;
+        auth_read_params.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+        auth_read_params.params.read.offset      = p_read_auth->request.read.offset;
+        auth_read_params.params.read.len         = sizeof(uint8_t);
+        auth_read_params.params.read.p_data      = &p_host->protocol_mode;
+        auth_read_params.params.read.update      = 1;
+
+        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle,
+                                                   &auth_read_params);
+        BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+    }
+}
+
+
+/**@brief Function for handling write events to a report CCCD.
+ *
+ * @param[in]   p_hids          HID Service structure.
+ * @param[in]   p_char_id       Id of report characteristic.
+ * @param[in]   p_ble_evt       BLE event received from the BLE stack.
+ */
+static void on_report_cccd_write(ble_hids_t         * p_hids,
+                                 ble_hids_char_id_t * p_char_id,
+                                 ble_evt_t    const * p_ble_evt)
+{
+    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+    if (p_evt_write->len == 2)
+    {
+        // CCCD written, update notification state
+        if (p_hids->evt_handler != NULL)
+        {
+            ble_hids_evt_t evt;
+
+            if (ble_srv_is_notification_enabled(p_evt_write->data))
+            {
+                evt.evt_type = BLE_HIDS_EVT_NOTIF_ENABLED;
+            }
+            else
+            {
+                evt.evt_type = BLE_HIDS_EVT_NOTIF_DISABLED;
+            }
+            evt.params.notification.char_id = *p_char_id;
+            evt.p_ble_evt                   = p_ble_evt;
+
+            p_hids->evt_handler(p_hids, &evt);
+        }
+    }
+}
+
+
+/**@brief Function for handling write events to a report value.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   p_ble_evt   Pointer to BLE event structure.
+ * @param[in]   p_char_id   Id of report characteristic.
+ * @param[in]   rep_offset  Offset to the affected HID report data.
+ * @param[in]   rep_max_len Maximum HID report length.
+ */
+static void on_report_value_write(ble_hids_t         * p_hids,
+                                  ble_evt_t    const * p_ble_evt,
+                                  ble_hids_char_id_t * p_char_id,
+                                  uint16_t             rep_offset,
+                                  uint16_t             rep_max_len)
+{
+    // Update host's Output Report data
+    ret_code_t                        err_code;
+    uint8_t                         * p_report;
+    ble_hids_client_context_t       * p_host;
+    ble_gatts_evt_write_t     const * p_write = &p_ble_evt->evt.gatts_evt.params.write;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gatts_evt.conn_handle,
+                                 (void *) &p_host);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+    // Store the written values in host's report data
+    if ((p_host != NULL) && (p_write->len + p_write->offset <= rep_max_len))
+    {
+        p_report = (uint8_t *) p_host + rep_offset;
+        memcpy(p_report, p_write->data, p_write->len);
+    }
+    else
+    {
+        return;
+    }
+
+    // Notify the applicartion
+    if (p_hids->evt_handler != NULL)
+    {
+        ble_hids_evt_t evt;
+
+        evt.evt_type                  = BLE_HIDS_EVT_REP_CHAR_WRITE;
+        evt.params.char_write.char_id = *p_char_id;
+        evt.params.char_write.offset  = p_ble_evt->evt.gatts_evt.params.write.offset;
+        evt.params.char_write.len     = p_ble_evt->evt.gatts_evt.params.write.len;
+        evt.params.char_write.data    = p_ble_evt->evt.gatts_evt.params.write.data;
+        evt.p_ble_evt                 = p_ble_evt;
+
+        p_hids->evt_handler(p_hids, &evt);
+    }
+}
+
+
+/**@brief Handle authorize read events to a report value.
+ *
+ * @param[in]   p_hids              HID Service structure.
+ * @param[in]   p_char_id           Id of report characteristic.
+ * @param[in]   p_ble_evt           Pointer to BLE event structure.
+ * @param[in]   rep_offset          Report data offset.
+ * @param[in]   rep_max_len         Report maximum length.
+ */
+static void on_report_value_read_auth(ble_hids_t         * p_hids,
+                                      ble_hids_char_id_t * p_char_id,
+                                      ble_evt_t    const * p_ble_evt,
+                                      uint16_t             rep_offset,
+                                      uint16_t             rep_max_len)
+{
+    ble_gatts_rw_authorize_reply_params_t auth_read_params;
+    ble_hids_client_context_t           * p_host;
+    uint8_t                             * p_report;
+    uint16_t                              read_offset;
+    uint32_t                              err_code = NRF_SUCCESS;
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 p_ble_evt->evt.gatts_evt.conn_handle,
+                                 (void *) &p_host);
+    BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+
+    // Update Report GATTS table with host's current report data
+    if (p_host != NULL)
+    {
+        read_offset = p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.offset;
+        p_report    = (uint8_t *) p_host + rep_offset;
+        memset(&auth_read_params, 0, sizeof(auth_read_params));
+
+        auth_read_params.type                    = BLE_GATTS_AUTHORIZE_TYPE_READ;
+        auth_read_params.params.read.gatt_status = BLE_GATT_STATUS_SUCCESS;
+        auth_read_params.params.read.offset      = read_offset;
+        auth_read_params.params.read.len         = rep_max_len - read_offset;
+        auth_read_params.params.read.p_data      = p_report + read_offset;
+        auth_read_params.params.read.update      = 1;
+
+        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gap_evt.conn_handle,
+                                                   &auth_read_params);
+
+        BLE_HIDS_ERROR_HANDLE(p_hids, err_code);
+    }
+    else
+    {
+        return;
+    }
+
+    if (p_hids->evt_handler != NULL)
+    {
+        ble_hids_evt_t evt;
+
+        evt.evt_type                      = BLE_HIDS_EVT_REPORT_READ;
+        evt.params.char_auth_read.char_id = *p_char_id;
+        evt.p_ble_evt                     = p_ble_evt;
+
+        p_hids->evt_handler(p_hids, &evt);
+    }
+}
+
+
+/**@brief Function for finding the Characteristic Id of a characteristic corresponding to a CCCD handle.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   handle      Handle to search for.
+ * @param[out]  p_char_id   Id of report characteristic.
+ *
+ * @return      TRUE if CCCD handle was found, FALSE otherwise.
+ */
+static bool inp_rep_cccd_identify(ble_hids_t         * p_hids,
+                                  uint16_t             handle,
+                                  ble_hids_char_id_t * p_char_id)
+{
+    uint8_t i;
+
+    for (i = 0; i < p_hids->inp_rep_count; i++)
+    {
+        if (handle == p_hids->inp_rep_array[i].char_handles.cccd_handle)
+        {
+            *p_char_id = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_INPUT, i);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+
+/**@brief Function for finding the Characteristic Id of a characteristic corresponding to a value handle.
+ *
+ * @param[in]   p_hids           HID Service structure.
+ * @param[in]   handle           Handle to search for.
+ * @param[out]  p_char_id        Id of report characteristic.
+ * @param[out]  p_context_offset Pointer to offset to the report data within the host data.
+ * @param[out]  p_rep_max_len    Pointer to maximum report length.
+ *
+ * @return      TRUE if value handle was found, FALSE otherwise.
+ */
+static bool rep_value_identify(ble_hids_t         * p_hids,
+                               uint16_t             handle,
+                               ble_hids_char_id_t * p_char_id,
+                               uint16_t           * p_context_offset,
+                               uint16_t           * p_rep_max_len)
+{
+    uint8_t i;
+
+    /* Initialize the offset with size of non-report-related data */
+    *p_context_offset = sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+                        BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+
+    if (p_hids->p_inp_rep_init_array != NULL)
+    {
+        for (i = 0; i < p_hids->inp_rep_count; i++)
+        {
+            if (handle == p_hids->inp_rep_array[i].char_handles.value_handle)
+            {
+                *p_char_id     = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_INPUT, i);
+                *p_rep_max_len = p_hids->p_inp_rep_init_array[i].max_len;
+                return true;
+            }
+            *p_context_offset += p_hids->p_inp_rep_init_array[i].max_len;
+        }
+    }
+    if (p_hids->p_outp_rep_init_array != NULL)
+    {
+        for (i = 0; i < p_hids->outp_rep_count; i++)
+        {
+            if (handle == p_hids->outp_rep_array[i].char_handles.value_handle)
+            {
+                *p_char_id     = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_OUTPUT, i);
+                *p_rep_max_len = p_hids->p_outp_rep_init_array[i].max_len;
+                return true;
+            }
+            *p_context_offset += p_hids->p_outp_rep_init_array[i].max_len;
+        }
+    }
+    if (p_hids->p_feature_rep_init_array != NULL)
+    {
+        for (i = 0; i < p_hids->feature_rep_count; i++)
+        {
+            if (handle == p_hids->feature_rep_array[i].char_handles.value_handle)
+            {
+                *p_char_id     = make_char_id(BLE_UUID_REPORT_CHAR, BLE_HIDS_REP_TYPE_FEATURE, i);
+                *p_rep_max_len = p_hids->p_feature_rep_init_array[i].max_len;
+                return true;
+            }
+            *p_context_offset += p_hids->p_feature_rep_init_array[i].max_len;
+        }
+    }
+
+    return false;
+}
+
+
+/**@brief Function for handling the Write event.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   p_ble_evt   Event received from the BLE stack.
+ */
+static void on_write(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    ble_hids_char_id_t            char_id;
+    ble_gatts_evt_write_t const * p_evt_write     = &p_ble_evt->evt.gatts_evt.params.write;
+    uint16_t                      rep_data_offset = sizeof(ble_hids_client_context_t);
+    uint16_t                      max_rep_len     = 0;
+
+    if (p_evt_write->handle == p_hids->hid_control_point_handles.value_handle)
+    {
+        on_control_point_write(p_hids, p_ble_evt);
+    }
+    else if (p_evt_write->handle == p_hids->protocol_mode_handles.value_handle)
+    {
+        on_protocol_mode_write(p_hids, p_ble_evt);
+    }
+    else if (p_evt_write->handle == p_hids->boot_kb_inp_rep_handles.cccd_handle)
+    {
+        char_id = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+        on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+    }
+    else if (p_evt_write->handle == p_hids->boot_kb_inp_rep_handles.value_handle)
+    {
+        char_id     = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+        max_rep_len = BOOT_KB_INPUT_REPORT_MAX_SIZE;
+        on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+    }
+    else if (p_evt_write->handle == p_hids->boot_kb_outp_rep_handles.value_handle)
+    {
+        char_id          = make_char_id(BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR, 0, 0);
+        rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE;
+        max_rep_len      = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+        on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+    }
+    else if (p_evt_write->handle == p_hids->boot_mouse_inp_rep_handles.cccd_handle)
+    {
+        char_id = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+        on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+    }
+    else if (p_evt_write->handle == p_hids->boot_mouse_inp_rep_handles.value_handle)
+    {
+        char_id          = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+        rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE + BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+        max_rep_len      = BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+        on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+    }
+    else if (inp_rep_cccd_identify(p_hids, p_evt_write->handle, &char_id))
+    {
+        on_report_cccd_write(p_hids, &char_id, p_ble_evt);
+    }
+    else if (rep_value_identify(p_hids,
+                                p_evt_write->handle,
+                                &char_id,
+                                &rep_data_offset,
+                                &max_rep_len))
+    {
+        on_report_value_write(p_hids, p_ble_evt, &char_id, rep_data_offset, max_rep_len);
+    }
+    else
+    {
+        // No implementation needed.
+    }
+}
+
+
+/**@brief Read/write authorize request event handler.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   p_ble_evt   Event received from the BLE stack.
+ */
+static void on_rw_authorize_request(ble_hids_t * p_hids, ble_evt_t const * p_ble_evt)
+{
+    ble_gatts_evt_rw_authorize_request_t const * evt_rw_auth =
+        &p_ble_evt->evt.gatts_evt.params.authorize_request;
+
+    ble_hids_char_id_t char_id;
+    uint16_t           rep_data_offset = sizeof(ble_hids_client_context_t);
+    uint16_t           max_rep_len     = 0;
+
+    if (evt_rw_auth->type != BLE_GATTS_AUTHORIZE_TYPE_READ)
+    {
+        // Unexpected operation
+        return;
+    }
+
+    /* Update SD GATTS values of appropriate host before SD sends the Read Response */
+    if (evt_rw_auth->request.read.handle == p_hids->protocol_mode_handles.value_handle)
+    {
+        on_protocol_mode_read_auth(p_hids, p_ble_evt);
+    }
+    else if (evt_rw_auth->request.read.handle == p_hids->boot_kb_inp_rep_handles.value_handle)
+    {
+        char_id     = make_char_id(BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR, 0, 0);
+        max_rep_len = BOOT_KB_INPUT_REPORT_MAX_SIZE;
+        on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+    }
+    else if (evt_rw_auth->request.read.handle == p_hids->boot_kb_outp_rep_handles.value_handle)
+    {
+        char_id          = make_char_id(BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR, 0, 0);
+        rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE;
+        max_rep_len      = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+        on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+    }
+    else if (evt_rw_auth->request.read.handle == p_hids->boot_mouse_inp_rep_handles.value_handle)
+    {
+        char_id          = make_char_id(BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR, 0, 0);
+        rep_data_offset += BOOT_KB_INPUT_REPORT_MAX_SIZE + BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+        max_rep_len      = BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+        on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+    }
+    else if (rep_value_identify(p_hids,
+                                evt_rw_auth->request.read.handle,
+                                &char_id,
+                                &rep_data_offset,
+                                &max_rep_len))
+    {
+        on_report_value_read_auth(p_hids, &char_id, p_ble_evt, rep_data_offset, max_rep_len);
+    }
+    else
+    {
+        // Do nothing.
+    }
+}
+
+
+void ble_hids_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
+{
+    ble_hids_t * p_hids = (ble_hids_t *) p_context;
+
+    switch (p_ble_evt->header.evt_id)
+    {
+        case BLE_GAP_EVT_CONNECTED:
+            on_connect(p_hids, p_ble_evt);
+            break;
+
+        case BLE_GATTS_EVT_WRITE:
+            on_write(p_hids, p_ble_evt);
+            break;
+
+        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+            on_rw_authorize_request(p_hids, p_ble_evt);
+            break;
+
+        default:
+            // No implementation needed.
+            break;
+    }
+}
+
+
+/**@brief Function for adding Protocol Mode characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   read_access   Security requirement for reading characteristic value.
+ * @param[in]   write_access  Security requirement for writing characteristic value.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t protocol_mode_char_add(ble_hids_t   * p_hids,
+                                       security_req_t read_access,
+                                       security_req_t write_access)
+{
+    ble_add_char_params_t add_char_params;
+    uint8_t               initial_protocol_mode;
+
+    initial_protocol_mode = DEFAULT_PROTOCOL_MODE;
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid                     = BLE_UUID_PROTOCOL_MODE_CHAR;
+    add_char_params.max_len                  = sizeof(uint8_t);
+    add_char_params.init_len                 = sizeof(uint8_t);
+    add_char_params.p_init_value             = &initial_protocol_mode;
+    add_char_params.char_props.read          = 1;
+    add_char_params.char_props.write_wo_resp = 1;
+    add_char_params.read_access              = read_access;
+    add_char_params.write_access             = write_access;
+    add_char_params.is_defered_read          = true;
+
+    return characteristic_add(p_hids->service_handle,
+                              &add_char_params,
+                              &p_hids->protocol_mode_handles);
+}
+
+
+/**@brief Function for adding report characteristics.
+ *
+ * @param[in]   p_hids              HID Service structure.
+ * @param[in]   p_properties        Report characteristic properties.
+ * @param[in]   max_len             Maximum length of report value.
+ * @param[in]   p_rep_ref           Report Reference descriptor.
+ * @param[in]   p_char_sec          Characteristic security settings.
+ * @param[out]  p_rep_char          Handles of new characteristic.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rep_char_add(ble_hids_t                      * p_hids,
+                             ble_gatt_char_props_t           * p_properties,
+                             uint16_t                          max_len,
+                             ble_srv_report_ref_t const      * p_rep_ref,
+                             ble_hids_char_sec_t const * const p_char_sec,
+                             ble_hids_rep_char_t             * p_rep_char)
+{
+    uint32_t               err_code;
+    ble_add_char_params_t  add_char_params;
+    ble_add_descr_params_t add_descr_params;
+    uint8_t                encoded_rep_ref[BLE_SRV_ENCODED_REPORT_REF_LEN];
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid              = BLE_UUID_REPORT_CHAR;
+    add_char_params.max_len           = max_len;
+    add_char_params.char_props        = *p_properties;
+    add_char_params.read_access       = p_char_sec->rd;
+    add_char_params.write_access      = p_char_sec->wr;
+    add_char_params.cccd_write_access = p_char_sec->cccd_wr;
+    add_char_params.is_var_len        = true;
+    add_char_params.is_defered_read   = true;
+
+    err_code = characteristic_add(p_hids->service_handle,
+                                  &add_char_params,
+                                  &p_rep_char->char_handles);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add Report Reference descriptor
+    memset(&add_descr_params, 0, sizeof(add_descr_params));
+    add_descr_params.uuid         = BLE_UUID_REPORT_REF_DESCR;
+    add_descr_params.read_access  = p_char_sec->rd;
+    add_descr_params.write_access = p_char_sec->wr;
+    add_descr_params.init_len     = ble_srv_report_ref_encode(encoded_rep_ref, p_rep_ref);
+    add_descr_params.max_len      = add_descr_params.init_len;
+    add_descr_params.p_value      = encoded_rep_ref;
+
+    return descriptor_add(p_rep_char->char_handles.value_handle,
+                          &add_descr_params,
+                          &p_rep_char->ref_handle);
+}
+
+
+/**@brief Function for adding Report Map characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t rep_map_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+    uint32_t               err_code;
+    ble_add_char_params_t  add_char_params;
+    ble_add_descr_params_t add_descr_params;
+
+    // Add Report Map characteristic
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid            = BLE_UUID_REPORT_MAP_CHAR;
+    add_char_params.max_len         = p_hids_init->rep_map.data_len;
+    add_char_params.init_len        = p_hids_init->rep_map.data_len;
+    add_char_params.p_init_value    = p_hids_init->rep_map.p_data;
+    add_char_params.char_props.read = 1;
+    add_char_params.read_access     = p_hids_init->rep_map.rd_sec;
+    add_char_params.is_var_len      = true;
+
+    err_code = characteristic_add(p_hids->service_handle,
+                                  &add_char_params,
+                                  &p_hids->rep_map_handles);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    if (p_hids_init->rep_map.ext_rep_ref_num != 0 && p_hids_init->rep_map.p_ext_rep_ref == NULL)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    for (int i = 0; i < p_hids_init->rep_map.ext_rep_ref_num; ++i)
+    {
+        uint8_t encoded_rep_ref[sizeof(ble_uuid128_t)];
+        uint8_t encoded_rep_ref_len;
+
+        // Add External Report Reference descriptor
+        err_code = sd_ble_uuid_encode(&p_hids_init->rep_map.p_ext_rep_ref[i],
+                                      &encoded_rep_ref_len,
+                                      encoded_rep_ref);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+
+        memset(&add_descr_params, 0, sizeof(add_descr_params));
+        add_descr_params.uuid        = BLE_UUID_EXTERNAL_REPORT_REF_DESCR;
+        add_descr_params.read_access = p_hids_init->rep_map.rd_sec;
+        add_descr_params.init_len    = encoded_rep_ref_len;
+        add_descr_params.max_len     = add_descr_params.init_len;
+        add_descr_params.p_value     = encoded_rep_ref;
+
+        err_code = descriptor_add(p_hids->rep_map_handles.value_handle,
+                                  &add_descr_params,
+                                  &p_hids->rep_map_ext_rep_ref_handle);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding Input Report characteristics.
+ *
+ * @param[in]   p_hids           HID Service structure.
+ * @param[in]   uuid             UUID of report characteristic to be added.
+ * @param[in]   max_data_len     Maximum length of report value.
+ * @param[in]   p_char_sec       Characteristic security settings.
+ * @param[out]  p_char_handles   Handles of new characteristic.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t boot_inp_rep_char_add(ble_hids_t                      * p_hids,
+                                      uint16_t                          uuid,
+                                      uint16_t                          max_data_len,
+                                      ble_hids_char_sec_t const * const p_char_sec,
+                                      ble_gatts_char_handles_t        * p_char_handles)
+{
+    ble_add_char_params_t add_char_params;
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid              = uuid;
+    add_char_params.max_len           = max_data_len;
+    add_char_params.char_props.read   = 1;
+    add_char_params.char_props.write  = (p_char_sec->wr != SEC_NO_ACCESS) ? 1 : 0;
+    add_char_params.char_props.notify = 1;
+    add_char_params.read_access       = p_char_sec->rd;
+    add_char_params.write_access      = p_char_sec->wr;
+    add_char_params.cccd_write_access = p_char_sec->cccd_wr;
+    add_char_params.is_defered_read   = true;
+
+    return characteristic_add(p_hids->service_handle,
+                              &add_char_params,
+                              p_char_handles);
+}
+
+
+/**@brief Function for adding Boot Keyboard Output Report characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t boot_kb_outp_rep_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+    ble_add_char_params_t add_char_params;
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid                     = BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR;
+    add_char_params.max_len                  = BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+    add_char_params.char_props.read          = 1;
+    add_char_params.char_props.write         = 1;
+    add_char_params.char_props.write_wo_resp = 1;
+    add_char_params.read_access              = p_hids_init->boot_kb_outp_rep_sec.rd;
+    add_char_params.write_access             = p_hids_init->boot_kb_outp_rep_sec.wr;
+    add_char_params.is_defered_read          = true;
+
+    return characteristic_add(p_hids->service_handle,
+                              &add_char_params,
+                              &p_hids->boot_kb_outp_rep_handles);
+}
+
+
+/**@brief Function for encoding a HID Information characteristic value.
+ *
+ * @param[out]  p_encoded_buffer    Buffer where the encoded data will be written.
+ * @param[in]   p_hid_information   Measurement to be encoded.
+ *
+ * @return      Size of encoded data.
+ */
+static uint8_t encode_hid_information(uint8_t                          * p_encoded_buffer,
+                                      const ble_hids_hid_information_t * p_hid_information)
+{
+    uint8_t len = uint16_encode(p_hid_information->bcd_hid, p_encoded_buffer);
+
+    p_encoded_buffer[len++] = p_hid_information->b_country_code;
+    p_encoded_buffer[len++] = p_hid_information->flags;
+
+    APP_ERROR_CHECK_BOOL(len == ENCODED_HID_INFORMATION_LEN);
+
+    return len;
+}
+
+
+/**@brief Function for adding HID Information characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hid_information_char_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+    uint8_t               encoded_hid_information[ENCODED_HID_INFORMATION_LEN];
+    uint8_t               hid_info_len;
+    ble_add_char_params_t add_char_params;
+
+    hid_info_len = encode_hid_information(encoded_hid_information, &p_hids_init->hid_information);
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid            = BLE_UUID_HID_INFORMATION_CHAR;
+    add_char_params.max_len         = hid_info_len;
+    add_char_params.char_props.read = 1;
+    add_char_params.read_access     = p_hids_init->hid_information.rd_sec;
+    add_char_params.init_len        = hid_info_len;
+    add_char_params.p_init_value    = encoded_hid_information;
+    
+    return characteristic_add(p_hids->service_handle,
+                              &add_char_params,
+                              &p_hids->hid_information_handles);
+}
+
+
+/**@brief Function for adding HID Control Point characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   write_access  Security requirement for writing characteristic value.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t hid_control_point_char_add(ble_hids_t * p_hids, security_req_t write_access)
+{
+    uint8_t               initial_hid_control_point;
+    ble_add_char_params_t add_char_params;
+
+    initial_hid_control_point = INITIAL_VALUE_HID_CONTROL_POINT;
+
+    memset(&add_char_params, 0, sizeof(add_char_params));
+    add_char_params.uuid                     = BLE_UUID_HID_CONTROL_POINT_CHAR;
+    add_char_params.max_len                  = sizeof(uint8_t);
+    add_char_params.char_props.write_wo_resp = 1;
+    add_char_params.write_access             = write_access;
+    add_char_params.init_len                 = sizeof(uint8_t);
+    add_char_params.p_init_value             = &initial_hid_control_point;
+
+    return characteristic_add(p_hids->service_handle, 
+                              &add_char_params, 
+                              &p_hids->hid_control_point_handles);
+}
+
+
+/**@brief Function for adding input report characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t inp_rep_characteristics_add(ble_hids_t            * p_hids,
+                                            const ble_hids_init_t * p_hids_init)
+{
+    if ((p_hids_init->inp_rep_count != 0) && (p_hids_init->p_inp_rep_array != NULL))
+    {
+        uint8_t i;
+
+        for (i = 0; i < p_hids_init->inp_rep_count; i++)
+        {
+            uint32_t                        err_code;
+            ble_hids_inp_rep_init_t const * p_rep_init = &p_hids_init->p_inp_rep_array[i];
+            ble_gatt_char_props_t           properties;
+
+            memset(&properties, 0, sizeof(properties));
+
+            properties.read   = true;
+            properties.write  = (p_rep_init->sec.wr != SEC_NO_ACCESS) ? 1 : 0;
+            properties.notify = true;
+
+            err_code = rep_char_add(p_hids,
+                                    &properties,
+                                    p_rep_init->max_len,
+                                    &p_rep_init->rep_ref,
+                                    &p_rep_init->sec,
+                                    &p_hids->inp_rep_array[i]);
+            if (err_code != NRF_SUCCESS)
+            {
+                return err_code;
+            }
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding output report characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t outp_rep_characteristics_add(ble_hids_t            * p_hids,
+                                             const ble_hids_init_t * p_hids_init)
+{
+    if ((p_hids_init->outp_rep_count != 0) && (p_hids_init->p_outp_rep_array != NULL))
+    {
+        uint8_t i;
+
+        for (i = 0; i < p_hids_init->outp_rep_count; i++)
+        {
+            uint32_t                         err_code;
+            ble_hids_outp_rep_init_t const * p_rep_init = &p_hids_init->p_outp_rep_array[i];
+            ble_gatt_char_props_t            properties;
+
+            memset(&properties, 0, sizeof(properties));
+
+            properties.read          = true;
+            properties.write         = true;
+            properties.write_wo_resp = true;
+
+            err_code = rep_char_add(p_hids,
+                                    &properties,
+                                    p_rep_init->max_len,
+                                    &p_rep_init->rep_ref,
+                                    &p_rep_init->sec,
+                                    &p_hids->outp_rep_array[i]);
+            if (err_code != NRF_SUCCESS)
+            {
+                return err_code;
+            }
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding feature report characteristics.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t feature_rep_characteristics_add(ble_hids_t            * p_hids,
+                                                const ble_hids_init_t * p_hids_init)
+{
+    if ((p_hids_init->feature_rep_count != 0) && (p_hids_init->p_feature_rep_array != NULL))
+    {
+        uint8_t i;
+
+        for (i = 0; i < p_hids_init->feature_rep_count; i++)
+        {
+            uint32_t                            err_code;
+            ble_hids_feature_rep_init_t const * p_rep_init = &p_hids_init->p_feature_rep_array[i];
+            ble_gatt_char_props_t               properties;
+
+            memset(&properties, 0, sizeof(properties));
+
+            properties.read  = true;
+            properties.write = true;
+
+            err_code = rep_char_add(p_hids,
+                                    &properties,
+                                    p_rep_init->max_len,
+                                    &p_rep_init->rep_ref,
+                                    &p_rep_init->sec,
+                                    &p_hids->feature_rep_array[i]);
+            if (err_code != NRF_SUCCESS)
+            {
+                return err_code;
+            }
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**@brief Function for adding included services.
+ *
+ * @param[in]   p_hids        HID Service structure.
+ * @param[in]   p_hids_init   Service initialization structure.
+ *
+ * @return      NRF_SUCCESS on success, otherwise an error code.
+ */
+static uint32_t includes_add(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+    uint32_t err_code;
+    uint8_t  i;
+    uint16_t unused_include_handle;
+
+    for (i = 0; i < p_hids_init->included_services_count; i++)
+    {
+        err_code = sd_ble_gatts_include_add(p_hids->service_handle,
+                                            p_hids_init->p_included_services_array[i],
+                                            &unused_include_handle);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init)
+{
+    VERIFY_PARAM_NOT_NULL(p_hids);
+    VERIFY_PARAM_NOT_NULL(p_hids_init);
+
+    uint32_t   err_code;
+    ble_uuid_t ble_uuid;
+
+    if ((p_hids_init->inp_rep_count > BLE_HIDS_MAX_INPUT_REP) ||
+        (p_hids_init->outp_rep_count > BLE_HIDS_MAX_OUTPUT_REP) ||
+        (p_hids_init->feature_rep_count > BLE_HIDS_MAX_FEATURE_REP)
+       )
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Initialize service structure.
+    p_hids->evt_handler       = p_hids_init->evt_handler;
+    p_hids->error_handler     = p_hids_init->error_handler;
+    p_hids->inp_rep_count     = p_hids_init->inp_rep_count;
+    p_hids->outp_rep_count    = p_hids_init->outp_rep_count;
+    p_hids->feature_rep_count = p_hids_init->feature_rep_count;
+
+    // Add service.
+    BLE_UUID_BLE_ASSIGN(ble_uuid, BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE);
+
+    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
+                                        &ble_uuid,
+                                        &p_hids->service_handle);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add includes.
+    err_code = includes_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    if (p_hids_init->is_kb || p_hids_init->is_mouse)
+    {
+        // Add Protocol Mode characteristic.
+        err_code = protocol_mode_char_add(p_hids,
+                                          p_hids_init->protocol_mode_rd_sec,
+                                          p_hids_init->protocol_mode_wr_sec);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+    }
+
+    // Add Input Report characteristics (if any).
+    err_code = inp_rep_characteristics_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add Output Report characteristics (if any).
+    err_code = outp_rep_characteristics_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add Feature Report characteristic (if any).
+    err_code = feature_rep_characteristics_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add Report Map characteristic.
+    err_code = rep_map_char_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    if (p_hids_init->is_kb)
+    {
+        // Add Boot Keyboard Input Report characteristic.
+        err_code = boot_inp_rep_char_add(p_hids,
+                                         BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR,
+                                         BOOT_KB_INPUT_REPORT_MAX_SIZE,
+                                         &p_hids_init->boot_kb_inp_rep_sec,
+                                         &p_hids->boot_kb_inp_rep_handles);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+
+        // Add Boot Keyboard Output Report characteristic.
+        err_code = boot_kb_outp_rep_char_add(p_hids, p_hids_init);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+    }
+
+    if (p_hids_init->is_mouse)
+    {
+        // Add Boot Mouse Input Report characteristic.
+        err_code = boot_inp_rep_char_add(p_hids,
+                                         BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR,
+                                         BOOT_MOUSE_INPUT_REPORT_MAX_SIZE,
+                                         &p_hids_init->boot_mouse_inp_rep_sec,
+                                         &p_hids->boot_mouse_inp_rep_handles);
+        if (err_code != NRF_SUCCESS)
+        {
+            return err_code;
+        }
+    }
+
+    // Add HID Information characteristic.
+    err_code = hid_information_char_add(p_hids, p_hids_init);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Add HID Control Point characteristic.
+    err_code = hid_control_point_char_add(p_hids, p_hids_init->ctrl_point_wr_sec);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Set pointers to user-defined report arrays
+    p_hids->p_inp_rep_init_array     = p_hids_init->p_inp_rep_array;
+    p_hids->p_outp_rep_init_array    = p_hids_init->p_outp_rep_array;
+    p_hids->p_feature_rep_init_array = p_hids_init->p_feature_rep_array;
+
+    return err_code;
+}
+
+
+uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
+                               uint8_t      rep_index,
+                               uint16_t     len,
+                               uint8_t    * p_data,
+                               uint16_t     conn_handle)
+{
+    VERIFY_PARAM_NOT_NULL(p_hids);
+    VERIFY_PARAM_NOT_NULL(p_data);
+
+    uint32_t err_code;
+
+    if (rep_index < p_hids->inp_rep_count)
+    {
+        ble_hids_rep_char_t * p_rep_char = &p_hids->inp_rep_array[rep_index];
+
+        if (conn_handle != BLE_CONN_HANDLE_INVALID)
+        {
+            ble_gatts_hvx_params_t hvx_params;
+            uint8_t                index   = 0;
+            uint16_t               hvx_len = len;
+            uint8_t              * p_host_rep_data;
+
+            err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                         conn_handle,
+                                         (void *) &p_host_rep_data);
+            VERIFY_SUCCESS(err_code);
+
+            p_host_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+                               BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+
+            // Store the new report data in host's context
+            while (index < rep_index)
+            {
+                p_host_rep_data += p_hids->p_inp_rep_init_array[index].max_len;
+                ++index;
+            }
+
+            if (len <= p_hids->p_inp_rep_init_array[rep_index].max_len)
+            {
+                memcpy(p_host_rep_data, p_data, len);
+            }
+            else
+            {
+                return NRF_ERROR_DATA_SIZE;
+            }
+
+            // Notify host
+            memset(&hvx_params, 0, sizeof(hvx_params));
+
+            hvx_params.handle = p_rep_char->char_handles.value_handle;
+            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
+            hvx_params.offset = 0;
+            hvx_params.p_len  = &hvx_len;
+            hvx_params.p_data = p_data;
+
+            err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+            if ((err_code == NRF_SUCCESS) && (*hvx_params.p_len != len))
+            {
+                err_code = NRF_ERROR_DATA_SIZE;
+            }
+        }
+        else
+        {
+            err_code = NRF_ERROR_INVALID_STATE;
+        }
+    }
+    else
+    {
+        err_code = NRF_ERROR_INVALID_PARAM;
+    }
+
+    return err_code;
+}
+
+
+uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
+                                       uint16_t     len,
+                                       uint8_t    * p_data,
+                                       uint16_t     conn_handle)
+{
+    VERIFY_PARAM_NOT_NULL(p_hids);
+    VERIFY_PARAM_NOT_NULL(p_data);
+
+    uint32_t err_code;
+
+    if (conn_handle != BLE_CONN_HANDLE_INVALID)
+    {
+        ble_gatts_hvx_params_t hvx_params;
+        uint16_t               hvx_len = len;
+        uint8_t              * p_host_rep_data;
+
+        err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                     conn_handle,
+                                     (void *) &p_host_rep_data);
+        VERIFY_SUCCESS(err_code);
+
+        p_host_rep_data += sizeof(ble_hids_client_context_t);
+
+        // Store the new value in the host's context
+        if (len <= BOOT_KB_INPUT_REPORT_MAX_SIZE)
+        {
+            memcpy(p_host_rep_data, p_data, len);
+        }
+
+        // Notify host
+        memset(&hvx_params, 0, sizeof(hvx_params));
+
+        hvx_params.handle = p_hids->boot_kb_inp_rep_handles.value_handle;
+        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
+        hvx_params.offset = 0;
+        hvx_params.p_len  = &hvx_len;
+        hvx_params.p_data = p_data;
+
+        err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+        if ((err_code == NRF_SUCCESS) && (*hvx_params.p_len != len))
+        {
+            err_code = NRF_ERROR_DATA_SIZE;
+        }
+    }
+    else
+    {
+        err_code = NRF_ERROR_INVALID_STATE;
+    }
+
+    return err_code;
+}
+
+
+uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
+                                          uint8_t      buttons,
+                                          int8_t       x_delta,
+                                          int8_t       y_delta,
+                                          uint16_t     optional_data_len,
+                                          uint8_t    * p_optional_data,
+                                          uint16_t     conn_handle)
+{
+    VERIFY_PARAM_NOT_NULL(p_hids);
+
+    uint32_t err_code;
+
+    if (conn_handle != BLE_CONN_HANDLE_INVALID)
+    {
+        uint16_t hvx_len = BOOT_MOUSE_INPUT_REPORT_MIN_SIZE + optional_data_len;
+
+        if (hvx_len <= BOOT_MOUSE_INPUT_REPORT_MAX_SIZE)
+        {
+            uint8_t                buffer[BOOT_MOUSE_INPUT_REPORT_MAX_SIZE];
+            ble_gatts_hvx_params_t hvx_params;
+            uint8_t              * p_host_rep_data;
+
+            err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                         conn_handle,
+                                         (void *) &p_host_rep_data);
+            VERIFY_SUCCESS(err_code);
+
+            p_host_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+                               BOOT_KB_OUTPUT_REPORT_MAX_SIZE;
+
+            APP_ERROR_CHECK_BOOL(BOOT_MOUSE_INPUT_REPORT_MIN_SIZE == 3);
+
+            // Build buffer
+            buffer[0] = buttons;
+            buffer[1] = (uint8_t)x_delta;
+            buffer[2] = (uint8_t)y_delta;
+
+            if (optional_data_len > 0)
+            {
+                memcpy(&buffer[3], p_optional_data, optional_data_len);
+            }
+
+            // Store the new value in the host's context
+            memcpy(p_host_rep_data, buffer, hvx_len);
+
+            // Pass buffer to stack
+            memset(&hvx_params, 0, sizeof(hvx_params));
+
+            hvx_params.handle = p_hids->boot_mouse_inp_rep_handles.value_handle;
+            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
+            hvx_params.offset = 0;
+            hvx_params.p_len  = &hvx_len;
+            hvx_params.p_data = buffer;
+
+            err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
+            if ((err_code == NRF_SUCCESS) &&
+                (*hvx_params.p_len != BOOT_MOUSE_INPUT_REPORT_MIN_SIZE + optional_data_len)
+               )
+            {
+                err_code = NRF_ERROR_DATA_SIZE;
+            }
+        }
+        else
+        {
+            err_code = NRF_ERROR_DATA_SIZE;
+        }
+    }
+    else
+    {
+        err_code = NRF_ERROR_INVALID_STATE;
+    }
+
+    return err_code;
+}
+
+
+uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
+                               uint8_t      rep_index,
+                               uint16_t     len,
+                               uint8_t      offset,
+                               uint16_t     conn_handle,
+                               uint8_t    * p_outp_rep)
+{
+    VERIFY_PARAM_NOT_NULL(p_hids);
+    VERIFY_PARAM_NOT_NULL(p_outp_rep);
+
+    ret_code_t err_code;
+    uint8_t  * p_rep_data;
+    uint8_t    index;
+
+    if (rep_index >= p_hids->outp_rep_count)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    err_code = blcm_link_ctx_get(p_hids->p_link_ctx_storage,
+                                 conn_handle,
+                                 (void *) &p_rep_data);
+    VERIFY_SUCCESS(err_code);
+
+    p_rep_data += sizeof(ble_hids_client_context_t) + BOOT_KB_INPUT_REPORT_MAX_SIZE +
+                  BOOT_KB_OUTPUT_REPORT_MAX_SIZE + BOOT_MOUSE_INPUT_REPORT_MAX_SIZE;
+
+    for (index = 0; index < p_hids->inp_rep_count; index++)
+    {
+        p_rep_data += p_hids->p_inp_rep_init_array[index].max_len;
+    }
+
+    for (index = 0; index < rep_index; index++)
+    {
+        p_rep_data += p_hids->p_outp_rep_init_array[index].max_len;
+    }
+
+    // Copy the requested output report data
+    if (len + offset <= p_hids->p_outp_rep_init_array[rep_index].max_len)
+    {
+        memcpy(p_outp_rep, p_rep_data + offset, len);
+    }
+    else
+    {
+        return NRF_ERROR_INVALID_LENGTH;
+    }
+
+    return NRF_SUCCESS;
+}
+
+
+/**
+   @}
+ */
+#endif // NRF_MODULE_ENABLED(BLE_HIDS)

+ 439 - 0
profiles/service/bsal_hid/Softdevice/ble_hids.h

@@ -0,0 +1,439 @@
+/**
+ * Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ *    Semiconductor ASA integrated circuit in a product or a software update for
+ *    such product, must reproduce the above copyright notice, this list of
+ *    conditions and the following disclaimer in the documentation and/or other
+ *    materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ *    Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ *    engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_hids Human Interface Device Service
+ * @{
+ * @ingroup ble_sdk_srv
+ * @brief Human Interface Device Service module.
+ *
+ * @details This module implements the Human Interface Device Service with the corresponding set of
+ *          characteristics. During initialization it adds the Human Interface Device Service and
+ *          a set of characteristics as per the Human Interface Device Service specification and
+ *          the user requirements to the BLE stack database.
+ *
+ *          If enabled, notification of Input Report characteristics is performed when the
+ *          application calls the corresponding ble_hids_xx_input_report_send() function.
+ *
+ *          If an event handler is supplied by the application, the Human Interface Device Service
+ *          will generate Human Interface Device Service events to the application.
+ *
+ * @note    The application must register this module as BLE event observer using the
+ *          NRF_SDH_BLE_OBSERVER macro. Example:
+ *          @code
+ *              ble_hids_t instance;
+ *              NRF_SDH_BLE_OBSERVER(anything, BLE_HIDS_BLE_OBSERVER_PRIO,
+ *                                   ble_hids_on_ble_evt, &instance);
+ *          @endcode
+ *
+ * @note Attention!
+ *  To maintain compliance with Nordic Semiconductor ASA Bluetooth profile
+ *  qualification listings, this section of source code must not be modified.
+ */
+
+#ifndef BLE_HIDS_H__
+#define BLE_HIDS_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "ble.h"
+#include "ble_srv_common.h"
+#include "ble_link_ctx_manager.h"
+#include "nrf_sdh_ble.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**@brief Allocate static data for keeping host connection contexts.
+ *
+ * @param       _name             Name of BLE HIDS instance.
+ * @param[in]   _hids_max_clients Maximum number of HIDS clients connected at a time.
+ * @param[in]   ...               Lengths of HIDS reports.
+ *
+ * @details
+ * Mapping of HIDS reports in the HIDS report context:
+ * - Structure of type @ref ble_hids_client_context_t
+ * - Boot keyboard input report
+ * - Boot keyboard output report
+ * - Boot mouse input report
+ * - Input reports
+ * - Output reports
+ * - Feature reports
+ * @hideinitializer
+ */
+#define BLE_HIDS_DEF(_name,                                              \
+                     _hids_max_clients,                                  \
+                     ...)                                                \
+    BLE_LINK_CTX_MANAGER_DEF(CONCAT_2(_name, _link_ctx_storage),         \
+                             (_hids_max_clients),                        \
+                             BLE_HIDS_LINK_CTX_SIZE_CALC(__VA_ARGS__));  \
+    static ble_hids_t _name =                                            \
+    {                                                                    \
+        .p_link_ctx_storage = &CONCAT_2(_name, _link_ctx_storage)        \
+    };                                                                   \
+    NRF_SDH_BLE_OBSERVER(_name ## _obs,                                  \
+                         BLE_HIDS_BLE_OBSERVER_PRIO,                     \
+                         ble_hids_on_ble_evt,                            \
+                         &_name)
+
+/**@brief Helping macro for @ref BLE_HIDS_DEF, that calculates the link context size for BLE HIDS
+ *        instance.
+ *
+ * @param[in]   ... Lengths of HIDS reports
+ * @hideinitializer
+ */
+#define BLE_HIDS_LINK_CTX_SIZE_CALC(...)            \
+    (sizeof(ble_hids_client_context_t) +            \
+    MACRO_MAP_REC(BLE_HIDS_REPORT_ADD, __VA_ARGS__) \
+    (BOOT_KB_INPUT_REPORT_MAX_SIZE) +               \
+    (BOOT_KB_OUTPUT_REPORT_MAX_SIZE) +              \
+    (BOOT_MOUSE_INPUT_REPORT_MAX_SIZE))             \
+
+/**@brief Helping macro for @ref BLE_HIDS_LINK_CTX_SIZE_CALC, that adds Input/Output/Feature report
+ *        lengths.
+ *
+ * @param[in]   _report_size   Length of the specific report.
+ * @hideinitializer
+ */
+#define BLE_HIDS_REPORT_ADD(_report_size) (_report_size) +
+
+/** @name Report Type values
+ * @anchor BLE_HIDS_REPORT_TYPE @{
+ */
+// Report Type values
+#define BLE_HIDS_REP_TYPE_INPUT                 1
+#define BLE_HIDS_REP_TYPE_OUTPUT                2
+#define BLE_HIDS_REP_TYPE_FEATURE               3
+/** @} */
+
+// Maximum number of the various Report Types
+#define BLE_HIDS_MAX_INPUT_REP                  10
+#define BLE_HIDS_MAX_OUTPUT_REP                 10
+#define BLE_HIDS_MAX_FEATURE_REP                10
+
+// Information Flags
+#define HID_INFO_FLAG_REMOTE_WAKE_MSK           0x01
+#define HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK  0x02
+
+#define BOOT_KB_INPUT_REPORT_MAX_SIZE           8       /**< Maximum size of a Boot Keyboard Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_KB_OUTPUT_REPORT_MAX_SIZE          1       /**< Maximum size of a Boot Keyboard Output Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_MOUSE_INPUT_REPORT_MIN_SIZE        3       /**< Minimum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+#define BOOT_MOUSE_INPUT_REPORT_MAX_SIZE        8       /**< Maximum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition for Human Interface Devices (HID), Version 1.11). */
+
+/**@brief HID Service characteristic id. */
+typedef struct
+{
+    uint16_t uuid;                                  /**< UUID of characteristic. */
+    uint8_t  rep_type;                              /**< Type of report (only used for BLE_UUID_REPORT_CHAR, see @ref BLE_HIDS_REPORT_TYPE). */
+    uint8_t  rep_index;                             /**< Index of the characteristic (only used for BLE_UUID_REPORT_CHAR). */
+} ble_hids_char_id_t;
+
+/**@brief HID Service event type. */
+typedef enum
+{
+    BLE_HIDS_EVT_HOST_SUSP,                         /**< Suspend command received. */
+    BLE_HIDS_EVT_HOST_EXIT_SUSP,                    /**< Exit suspend command received. */
+    BLE_HIDS_EVT_NOTIF_ENABLED,                     /**< Notification enabled event. */
+    BLE_HIDS_EVT_NOTIF_DISABLED,                    /**< Notification disabled event. */
+    BLE_HIDS_EVT_REP_CHAR_WRITE,                    /**< A new value has been written to an Report characteristic. */
+    BLE_HIDS_EVT_BOOT_MODE_ENTERED,                 /**< Boot mode entered. */
+    BLE_HIDS_EVT_REPORT_MODE_ENTERED,               /**< Report mode entered. */
+    BLE_HIDS_EVT_REPORT_READ                        /**< Read with response */
+} ble_hids_evt_type_t;
+
+/**@brief HID Service event. */
+typedef struct
+{
+    ble_hids_evt_type_t evt_type;                   /**< Type of event. */
+    union
+    {
+        struct
+        {
+            ble_hids_char_id_t char_id;             /**< Id of characteristic for which notification has been started. */
+        } notification;
+        struct
+        {
+            ble_hids_char_id_t char_id;             /**< Id of characteristic having been written. */
+            uint16_t           offset;              /**< Offset for the write operation. */
+            uint16_t           len;                 /**< Length of the incoming data. */
+            uint8_t    const * data;                /**< Incoming data, variable length */
+        } char_write;
+        struct
+        {
+            ble_hids_char_id_t char_id;             /**< Id of characteristic being read. */
+        } char_auth_read;
+    } params;
+    ble_evt_t const * p_ble_evt;                    /**< corresponding received ble event, NULL if not relevant */
+} ble_hids_evt_t;
+
+// Forward declaration of the ble_hids_t type.
+typedef struct ble_hids_s ble_hids_t;
+
+/**@brief HID Service event handler type. */
+typedef void (*ble_hids_evt_handler_t) (ble_hids_t * p_hids, ble_hids_evt_t * p_evt);
+
+/**@brief Security requirements for HID Service characteristic. */
+typedef struct
+{
+    security_req_t                rd;               /**< Security requirement for reading HID Service characteristic value. */
+    security_req_t                wr;               /**< Security requirement for writing HID Service characteristic value. */
+    security_req_t                cccd_wr;          /**< Security requirement for writing HID Service characteristic CCCD. */
+} ble_hids_char_sec_t;
+
+/**@brief HID Information characteristic value. */
+typedef struct
+{
+    uint16_t                      bcd_hid;          /**< 16-bit unsigned integer representing version number of base USB HID Specification implemented by HID Device */
+    uint8_t                       b_country_code;   /**< Identifies which country the hardware is localized for. Most hardware is not localized and thus this value would be zero (0). */
+    uint8_t                       flags;            /**< See http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.hid_information.xml */
+    security_req_t                rd_sec;           /**< Security requirement for reading HID Information characteristic value. */
+} ble_hids_hid_information_t;
+
+/**@brief HID Service Input Report characteristic init structure. This contains all options and
+ *        data needed for initialization of one Input Report characteristic. */
+typedef struct
+{
+    uint16_t                      max_len;          /**< Maximum length of characteristic value. */
+    ble_srv_report_ref_t          rep_ref;          /**< Value of the Report Reference descriptor. */
+    ble_hids_char_sec_t           sec;              /**< Security requirements for HID Service Input Report characteristic. */
+} ble_hids_inp_rep_init_t;
+
+/**@brief HID Service Output Report characteristic init structure. This contains all options and
+ *        data needed for initialization of one Output Report characteristic. */
+typedef struct
+{
+    uint16_t                      max_len;          /**< Maximum length of characteristic value. */
+    ble_srv_report_ref_t          rep_ref;          /**< Value of the Report Reference descriptor. */
+    ble_hids_char_sec_t           sec;              /**< Security requirements for HID Service Output Report characteristic. */
+} ble_hids_outp_rep_init_t;
+
+/**@brief HID Service Feature Report characteristic init structure. This contains all options and
+ *        data needed for initialization of one Feature Report characteristic. */
+typedef struct
+{
+    uint16_t                      max_len;          /**< Maximum length of characteristic value. */
+    ble_srv_report_ref_t          rep_ref;          /**< Value of the Report Reference descriptor. */
+    ble_hids_char_sec_t           sec;              /**< Security requirements for HID Service Feature Report characteristic. */
+} ble_hids_feature_rep_init_t;
+
+/**@brief HID Service Report Map characteristic init structure. This contains all options and data
+ *        needed for initialization of the Report Map characteristic. */
+typedef struct
+{
+    uint8_t *                     p_data;           /**< Report map data. */
+    uint16_t                      data_len;         /**< Length of report map data. */
+    uint8_t                       ext_rep_ref_num;  /**< Number of Optional External Report Reference descriptors. */
+    ble_uuid_t const *            p_ext_rep_ref;    /**< Optional External Report Reference descriptor (will be added if != NULL). */
+    security_req_t                rd_sec;           /**< Security requirement for HID Service Report Map characteristic. */
+} ble_hids_rep_map_init_t;
+
+/**@brief HID Report characteristic structure. */
+typedef struct
+{
+    ble_gatts_char_handles_t      char_handles;     /**< Handles related to the Report characteristic. */
+    uint16_t                      ref_handle;       /**< Handle of the Report Reference descriptor. */
+} ble_hids_rep_char_t;
+
+/**@brief HID Host context structure. It keeps information relevant to a single host. */
+typedef struct
+{
+    uint8_t   protocol_mode;  /**< Protocol mode. */
+    uint8_t   ctrl_pt;        /**< HID Control Point. */
+} ble_hids_client_context_t;
+
+/**@brief HID Service init structure. This contains all options and data needed for initialization
+ *        of the service. */
+typedef struct
+{
+    ble_hids_evt_handler_t              evt_handler;                                  /**< Event handler to be called for handling events in the HID Service. */
+    ble_srv_error_handler_t             error_handler;                                /**< Function to be called in case of an error. */
+    bool                                is_kb;                                        /**< TRUE if device is operating as a keyboard, FALSE if it is not. */
+    bool                                is_mouse;                                     /**< TRUE if device is operating as a mouse, FALSE if it is not. */
+    uint8_t                             inp_rep_count;                                /**< Number of Input Report characteristics. */
+    ble_hids_inp_rep_init_t const *     p_inp_rep_array;                              /**< Information about the Input Report characteristics. */
+    uint8_t                             outp_rep_count;                               /**< Number of Output Report characteristics. */
+    ble_hids_outp_rep_init_t const *    p_outp_rep_array;                             /**< Information about the Output Report characteristics. */
+    uint8_t                             feature_rep_count;                            /**< Number of Feature Report characteristics. */
+    ble_hids_feature_rep_init_t const * p_feature_rep_array;                          /**< Information about the Feature Report characteristics. */
+    ble_hids_rep_map_init_t             rep_map;                                      /**< Information nedeed for initialization of the Report Map characteristic. */
+    ble_hids_hid_information_t          hid_information;                              /**< Value of the HID Information characteristic. */
+    uint8_t                             included_services_count;                      /**< Number of services to include in HID service. */
+    uint16_t *                          p_included_services_array;                    /**< Array of services to include in HID service. */
+    security_req_t                      protocol_mode_rd_sec;                         /**< Security requirement for reading HID service Protocol Mode characteristic. */
+    security_req_t                      protocol_mode_wr_sec;                         /**< Security requirement for writing HID service Protocol Mode characteristic. */
+    security_req_t                      ctrl_point_wr_sec;                            /**< Security requirement for writing HID service Control Point characteristic. */
+    ble_hids_char_sec_t                 boot_mouse_inp_rep_sec;                       /**< Security requirements for HID Boot Keyboard Input Report characteristic. */
+    ble_hids_char_sec_t                 boot_kb_inp_rep_sec;                          /**< Security requirements for HID Boot Keyboard Input Report characteristic. */
+    ble_hids_char_sec_t                 boot_kb_outp_rep_sec;                         /**< Security requirements for HID Boot Keyboard Output Report characteristic. */
+} ble_hids_init_t;
+
+/**@brief HID Service structure. This contains various status information for the service. */
+struct ble_hids_s
+{
+    ble_hids_evt_handler_t              evt_handler;                                  /**< Event handler to be called for handling events in the HID Service. */
+    ble_srv_error_handler_t             error_handler;                                /**< Function to be called in case of an error. */
+    uint16_t                            service_handle;                               /**< Handle of HID Service (as provided by the BLE stack). */
+    ble_gatts_char_handles_t            protocol_mode_handles;                        /**< Handles related to the Protocol Mode characteristic (will only be created if ble_hids_init_t.is_kb or ble_hids_init_t.is_mouse is set). */
+    uint8_t                             inp_rep_count;                                /**< Number of Input Report characteristics. */
+    ble_hids_rep_char_t                 inp_rep_array[BLE_HIDS_MAX_INPUT_REP];        /**< Information about the Input Report characteristics. */
+    uint8_t                             outp_rep_count;                               /**< Number of Output Report characteristics. */
+    ble_hids_rep_char_t                 outp_rep_array[BLE_HIDS_MAX_OUTPUT_REP];      /**< Information about the Output Report characteristics. */
+    uint8_t                             feature_rep_count;                            /**< Number of Feature Report characteristics. */
+    ble_hids_rep_char_t                 feature_rep_array[BLE_HIDS_MAX_FEATURE_REP];  /**< Information about the Feature Report characteristics. */
+    ble_gatts_char_handles_t            rep_map_handles;                              /**< Handles related to the Report Map characteristic. */
+    uint16_t                            rep_map_ext_rep_ref_handle;                   /**< Handle of the Report Map External Report Reference descriptor. */
+    ble_gatts_char_handles_t            boot_kb_inp_rep_handles;                      /**< Handles related to the Boot Keyboard Input Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
+    ble_gatts_char_handles_t            boot_kb_outp_rep_handles;                     /**< Handles related to the Boot Keyboard Output Report characteristic (will only be created if ble_hids_init_t.is_kb is set). */
+    ble_gatts_char_handles_t            boot_mouse_inp_rep_handles;                   /**< Handles related to the Boot Mouse Input Report characteristic (will only be created if ble_hids_init_t.is_mouse is set). */
+    ble_gatts_char_handles_t            hid_information_handles;                      /**< Handles related to the Report Map characteristic. */
+    ble_gatts_char_handles_t            hid_control_point_handles;                    /**< Handles related to the Report Map characteristic. */
+    blcm_link_ctx_storage_t     * const p_link_ctx_storage;                           /**< Link context storage with handles of all current connections and its data context. */
+    ble_hids_inp_rep_init_t     const * p_inp_rep_init_array;                         /**< Pointer to information about the Input Report characteristics. */
+    ble_hids_outp_rep_init_t    const * p_outp_rep_init_array;                        /**< Pointer to information about the Output Report characteristics. */
+    ble_hids_feature_rep_init_t const * p_feature_rep_init_array;                     /**< Pointer to information about the Feature Report characteristics. */
+};
+
+/**@brief Function for initializing the HID Service.
+ *
+ * @param[out]  p_hids       HID Service structure. This structure will have to be supplied by the
+ *                           application. It will be initialized by this function, and will later be
+ *                           used to identify this particular service instance.
+ * @param[in]   p_hids_init  Information needed to initialize the service.
+ *
+ * @return      NRF_SUCCESS on successful initialization of service, otherwise an error code.
+ */
+uint32_t ble_hids_init(ble_hids_t * p_hids, const ble_hids_init_t * p_hids_init);
+
+/**@brief Function for handling the Application's BLE Stack events.
+ *
+ * @details Handles all events from the BLE stack of interest to the HID Service.
+ *
+ * @param[in]   p_ble_evt   Event received from the BLE stack.
+ * @param[in]   p_context   HID Service structure.
+ */
+void ble_hids_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
+
+/**@brief Function for sending Input Report.
+ *
+ * @details Sends data on an Input Report characteristic.
+ *
+ * @param[in]   p_hids       HID Service structure.
+ * @param[in]   rep_index    Index of the characteristic (corresponding to the index in
+ *                           ble_hids_t.inp_rep_array as passed to ble_hids_init()).
+ * @param[in]   len          Length of data to be sent.
+ * @param[in]   p_data       Pointer to data to be sent.
+ * @param[in]   conn_handle  Connection handle, where the notification will be sent.
+ *
+ * @return      NRF_SUCCESS on successful sending of input report, otherwise an error code.
+ */
+uint32_t ble_hids_inp_rep_send(ble_hids_t * p_hids,
+                               uint8_t      rep_index,
+                               uint16_t     len,
+                               uint8_t    * p_data,
+                               uint16_t     conn_handle);
+
+/**@brief Function for sending Boot Keyboard Input Report.
+ *
+ * @details Sends data on an Boot Keyboard Input Report characteristic.
+ *
+ * @param[in]   p_hids       HID Service structure.
+ * @param[in]   len          Length of data to be sent.
+ * @param[in]   p_data       Pointer to data to be sent.
+ * @param[in]   conn_handle  Connection handle, where the notification will be sent.
+ *
+ * @return      NRF_SUCCESS on successful sending of the report, otherwise an error code.
+ */
+uint32_t ble_hids_boot_kb_inp_rep_send(ble_hids_t * p_hids,
+                                       uint16_t     len,
+                                       uint8_t    * p_data,
+                                       uint16_t     conn_handle);
+
+/**@brief Function for sending Boot Mouse Input Report.
+ *
+ * @details Sends data on an Boot Mouse Input Report characteristic.
+ *
+ * @param[in]   p_hids              HID Service structure.
+ * @param[in]   buttons             State of mouse buttons.
+ * @param[in]   x_delta             Horizontal movement.
+ * @param[in]   y_delta             Vertical movement.
+ * @param[in]   optional_data_len   Length of optional part of Boot Mouse Input Report.
+ * @param[in]   p_optional_data     Optional part of Boot Mouse Input Report.
+ * @param[in]   conn_handle         Connection handle.
+ *
+ * @return      NRF_SUCCESS on successful sending of the report, otherwise an error code.
+ */
+uint32_t ble_hids_boot_mouse_inp_rep_send(ble_hids_t * p_hids,
+                                          uint8_t      buttons,
+                                          int8_t       x_delta,
+                                          int8_t       y_delta,
+                                          uint16_t     optional_data_len,
+                                          uint8_t    * p_optional_data,
+                                          uint16_t     conn_handle);
+
+/**@brief Function for getting the current value of Output Report from the stack.
+ *
+ * @details Fetches the current value of the output report characteristic from the stack.
+ *
+ * @param[in]   p_hids      HID Service structure.
+ * @param[in]   rep_index   Index of the characteristic (corresponding to the index in
+ *                          ble_hids_t.outp_rep_array as passed to ble_hids_init()).
+ * @param[in]   len         Length of output report needed.
+ * @param[in]   offset      Offset in bytes to read from.
+ * @param[in]   conn_handle Connection handle.
+ * @param[out]  p_outp_rep  Pointer to the output report.
+ *
+ * @return      NRF_SUCCESS on successful read of the report, otherwise an error code.
+ */
+uint32_t ble_hids_outp_rep_get(ble_hids_t * p_hids,
+                               uint8_t      rep_index,
+                               uint16_t     len,
+                               uint8_t      offset,
+                               uint16_t     conn_handle,
+                               uint8_t    * p_outp_rep);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // BLE_HIDS_H__
+
+/** @} */

+ 1303 - 0
profiles/service/bsal_hid/Softdevice/main.c

@@ -0,0 +1,1303 @@
+/**
+ * Copyright (c) 2014 - 2021, Nordic Semiconductor ASA
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form, except as embedded into a Nordic
+ *    Semiconductor ASA integrated circuit in a product or a software update for
+ *    such product, must reproduce the above copyright notice, this list of
+ *    conditions and the following disclaimer in the documentation and/or other
+ *    materials provided with the distribution.
+ *
+ * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
+ *    contributors may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * 4. This software, with or without modification, must only be used with a
+ *    Nordic Semiconductor ASA integrated circuit.
+ *
+ * 5. Any software provided in binary form under this license must not be reverse
+ *    engineered, decompiled, modified and/or disassembled.
+ *
+ * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/** @file
+ *
+ * @defgroup ble_sdk_app_hids_mouse_main main.c
+ * @{
+ * @ingroup ble_sdk_app_hids_mouse
+ * @brief HID Mouse Sample Application main file.
+ *
+ * This file contains is the source code for a sample application using the HID, Battery and Device
+ * Information Service for implementing a simple mouse functionality. This application uses the
+ * @ref app_scheduler.
+ *
+ * Also it would accept pairing requests from any peer device. This implementation of the
+ * application will not know whether a connected central is a known device or not.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "nordic_common.h"
+#include "nrf.h"
+#include "nrf_sdm.h"
+#include "app_error.h"
+#include "ble.h"
+#include "ble_err.h"
+#include "ble_hci.h"
+#include "ble_srv_common.h"
+#include "ble_advdata.h"
+#include "ble_hids.h"
+#include "ble_bas.h"
+#include "ble_dis.h"
+#include "ble_conn_params.h"
+#include "sensorsim.h"
+#include "bsp_btn_ble.h"
+#include "app_scheduler.h"
+#include "nrf_sdh.h"
+#include "nrf_sdh_soc.h"
+#include "nrf_sdh_ble.h"
+#include "app_timer.h"
+#include "peer_manager.h"
+#include "ble_advertising.h"
+#include "fds.h"
+#include "ble_conn_state.h"
+#include "nrf_ble_gatt.h"
+#include "nrf_ble_qwr.h"
+#include "nrf_pwr_mgmt.h"
+#include "peer_manager_handler.h"
+
+#include "nrf_log.h"
+#include "nrf_log_ctrl.h"
+#include "nrf_log_default_backends.h"
+
+
+#define DEVICE_NAME                     "nRF5_Mouse"                                /**< Name of device. Will be included in the advertising data. */
+#define MANUFACTURER_NAME               "NordicSemiconductor"                       /**< Manufacturer. Will be passed to Device Information Service. */
+
+#define APP_BLE_OBSERVER_PRIO           3                                           /**< Application's BLE observer priority. You shouldn't need to modify this value. */
+#define APP_BLE_CONN_CFG_TAG            1                                           /**< A tag identifying the SoftDevice BLE configuration. */
+
+#define BATTERY_LEVEL_MEAS_INTERVAL     APP_TIMER_TICKS(2000)                       /**< Battery level measurement interval (ticks). */
+#define MIN_BATTERY_LEVEL               81                                          /**< Minimum simulated battery level. */
+#define MAX_BATTERY_LEVEL               100                                         /**< Maximum simulated battery level. */
+#define BATTERY_LEVEL_INCREMENT         1                                           /**< Increment between each simulated battery level measurement. */
+
+#define PNP_ID_VENDOR_ID_SOURCE         0x02                                        /**< Vendor ID Source. */
+#define PNP_ID_VENDOR_ID                0x1915                                      /**< Vendor ID. */
+#define PNP_ID_PRODUCT_ID               0xEEEE                                      /**< Product ID. */
+#define PNP_ID_PRODUCT_VERSION          0x0001                                      /**< Product Version. */
+
+/*lint -emacro(524, MIN_CONN_INTERVAL) // Loss of precision */
+#define MIN_CONN_INTERVAL               MSEC_TO_UNITS(7.5, UNIT_1_25_MS)            /**< Minimum connection interval (7.5 ms). */
+#define MAX_CONN_INTERVAL               MSEC_TO_UNITS(15, UNIT_1_25_MS)             /**< Maximum connection interval (15 ms). */
+#define SLAVE_LATENCY                   20                                          /**< Slave latency. */
+#define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(3000, UNIT_10_MS)             /**< Connection supervisory timeout (3000 ms). */
+
+#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000)                       /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
+#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000)                      /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
+#define MAX_CONN_PARAM_UPDATE_COUNT     3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
+
+#define SEC_PARAM_BOND                  1                                           /**< Perform bonding. */
+#define SEC_PARAM_MITM                  0                                           /**< Man In The Middle protection not required. */
+#define SEC_PARAM_LESC                  0                                           /**< LE Secure Connections not enabled. */
+#define SEC_PARAM_KEYPRESS              0                                           /**< Keypress notifications not enabled. */
+#define SEC_PARAM_IO_CAPABILITIES       BLE_GAP_IO_CAPS_NONE                        /**< No I/O capabilities. */
+#define SEC_PARAM_OOB                   0                                           /**< Out Of Band data not available. */
+#define SEC_PARAM_MIN_KEY_SIZE          7                                           /**< Minimum encryption key size. */
+#define SEC_PARAM_MAX_KEY_SIZE          16                                          /**< Maximum encryption key size. */
+
+#define SWIFT_PAIR_SUPPORTED            1                                           /**< Swift Pair feature is supported. */
+#if SWIFT_PAIR_SUPPORTED == 1
+#define MICROSOFT_VENDOR_ID             0x0006                                      /**< Microsoft Vendor ID.*/
+#define MICROSOFT_BEACON_ID             0x03                                        /**< Microsoft Beacon ID, used to indicate that Swift Pair feature is supported. */
+#define MICROSOFT_BEACON_SUB_SCENARIO   0x00                                        /**< Microsoft Beacon Sub Scenario, used to indicate how the peripheral will pair using Swift Pair feature. */
+#define RESERVED_RSSI_BYTE              0x80                                        /**< Reserved RSSI byte, used to maintain forwards and backwards compatibility. */
+#endif
+
+#define MOVEMENT_SPEED                  5                                           /**< Number of pixels by which the cursor is moved each time a button is pushed. */
+#define INPUT_REPORT_COUNT              3                                           /**< Number of input reports in this application. */
+#define INPUT_REP_BUTTONS_LEN           3                                           /**< Length of Mouse Input Report containing button data. */
+#define INPUT_REP_MOVEMENT_LEN          3                                           /**< Length of Mouse Input Report containing movement data. */
+#define INPUT_REP_MEDIA_PLAYER_LEN      1                                           /**< Length of Mouse Input Report containing media player data. */
+#define INPUT_REP_BUTTONS_INDEX         0                                           /**< Index of Mouse Input Report containing button data. */
+#define INPUT_REP_MOVEMENT_INDEX        1                                           /**< Index of Mouse Input Report containing movement data. */
+#define INPUT_REP_MPLAYER_INDEX         2                                           /**< Index of Mouse Input Report containing media player data. */
+#define INPUT_REP_REF_BUTTONS_ID        1                                           /**< Id of reference to Mouse Input Report containing button data. */
+#define INPUT_REP_REF_MOVEMENT_ID       2                                           /**< Id of reference to Mouse Input Report containing movement data. */
+#define INPUT_REP_REF_MPLAYER_ID        3                                           /**< Id of reference to Mouse Input Report containing media player data. */
+
+#define BASE_USB_HID_SPEC_VERSION       0x0101                                      /**< Version number of base USB HID Specification implemented by this application. */
+
+#define SCHED_MAX_EVENT_DATA_SIZE       APP_TIMER_SCHED_EVENT_DATA_SIZE             /**< Maximum size of scheduler events. */
+#ifdef SVCALL_AS_NORMAL_FUNCTION
+#define SCHED_QUEUE_SIZE                20                                          /**< Maximum number of events in the scheduler queue. More is needed in case of Serialization. */
+#else
+#define SCHED_QUEUE_SIZE                10                                          /**< Maximum number of events in the scheduler queue. */
+#endif
+
+#define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
+
+#define APP_ADV_FAST_INTERVAL           0x0028                                      /**< Fast advertising interval (in units of 0.625 ms. This value corresponds to 25 ms.). */
+#define APP_ADV_SLOW_INTERVAL           0x00A0                                      /**< Slow advertising interval (in units of 0.625 ms. This value corresponds to 100 ms.). */
+
+#define APP_ADV_FAST_DURATION           3000                                        /**< The advertising duration of fast advertising in units of 10 milliseconds. */
+#define APP_ADV_SLOW_DURATION           18000                                       /**< The advertising duration of slow advertising in units of 10 milliseconds. */
+
+
+APP_TIMER_DEF(m_battery_timer_id);                                                  /**< Battery timer. */
+BLE_BAS_DEF(m_bas);                                                                 /**< Battery service instance. */
+BLE_HIDS_DEF(m_hids,                                                                /**< HID service instance. */
+             NRF_SDH_BLE_TOTAL_LINK_COUNT,
+             INPUT_REP_BUTTONS_LEN,
+             INPUT_REP_MOVEMENT_LEN,
+             INPUT_REP_MEDIA_PLAYER_LEN);
+NRF_BLE_GATT_DEF(m_gatt);                                                           /**< GATT module instance. */
+NRF_BLE_QWR_DEF(m_qwr);                                                             /**< Context for the Queued Write module.*/
+BLE_ADVERTISING_DEF(m_advertising);                                                 /**< Advertising module instance. */
+
+static bool              m_in_boot_mode = false;                                    /**< Current protocol mode. */
+static uint16_t          m_conn_handle  = BLE_CONN_HANDLE_INVALID;                  /**< Handle of the current connection. */
+static pm_peer_id_t      m_peer_id;                                                 /**< Device reference handle to the current bonded central. */
+static sensorsim_cfg_t   m_battery_sim_cfg;                                         /**< Battery Level sensor simulator configuration. */
+static sensorsim_state_t m_battery_sim_state;                                       /**< Battery Level sensor simulator state. */
+static ble_uuid_t        m_adv_uuids[] =                                            /**< Universally unique service identifiers. */
+{
+    {BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE, BLE_UUID_TYPE_BLE}
+};
+
+#if SWIFT_PAIR_SUPPORTED == 1
+static uint8_t m_sp_payload[] =                                                     /**< Payload of advertising data structure for Microsoft Swift Pair feature. */
+{
+    MICROSOFT_BEACON_ID,
+    MICROSOFT_BEACON_SUB_SCENARIO,
+    RESERVED_RSSI_BYTE
+};
+static ble_advdata_manuf_data_t m_sp_manuf_advdata =                                /**< Advertising data structure for Microsoft Swift Pair feature. */
+{
+    .company_identifier = MICROSOFT_VENDOR_ID,
+    .data               =
+    {
+        .size   = sizeof(m_sp_payload),
+        .p_data = &m_sp_payload[0]
+    }
+};
+static ble_advdata_t m_sp_advdata;
+#endif
+
+static void on_hids_evt(ble_hids_t * p_hids, ble_hids_evt_t * p_evt);
+
+
+/**@brief Callback function for asserts in the SoftDevice.
+ *
+ * @details This function will be called in case of an assert in the SoftDevice.
+ *
+ * @warning This handler is an example only and does not fit a final product. You need to analyze
+ *          how your product is supposed to react in case of Assert.
+ * @warning On assert from the SoftDevice, the system can only recover on reset.
+ *
+ * @param[in]   line_num   Line number of the failing ASSERT call.
+ * @param[in]   file_name  File name of the failing ASSERT call.
+ */
+void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
+{
+    app_error_handler(DEAD_BEEF, line_num, p_file_name);
+}
+
+
+/**@brief Function for setting filtered whitelist.
+ *
+ * @param[in] skip  Filter passed to @ref pm_peer_id_list.
+ */
+static void whitelist_set(pm_peer_id_list_skip_t skip)
+{
+    pm_peer_id_t peer_ids[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+    uint32_t     peer_id_count = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
+
+    ret_code_t err_code = pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
+    APP_ERROR_CHECK(err_code);
+
+    NRF_LOG_INFO("\tm_whitelist_peer_cnt %d, MAX_PEERS_WLIST %d",
+                   peer_id_count + 1,
+                   BLE_GAP_WHITELIST_ADDR_MAX_COUNT);
+
+    err_code = pm_whitelist_set(peer_ids, peer_id_count);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for setting filtered device identities.
+ *
+ * @param[in] skip  Filter passed to @ref pm_peer_id_list.
+ */
+static void identities_set(pm_peer_id_list_skip_t skip)
+{
+    pm_peer_id_t peer_ids[BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT];
+    uint32_t     peer_id_count = BLE_GAP_DEVICE_IDENTITIES_MAX_COUNT;
+
+    ret_code_t err_code = pm_peer_id_list(peer_ids, &peer_id_count, PM_PEER_ID_INVALID, skip);
+    APP_ERROR_CHECK(err_code);
+
+    err_code = pm_device_identities_list_set(peer_ids, peer_id_count);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Clear bond information from persistent storage.
+ */
+static void delete_bonds(void)
+{
+    ret_code_t err_code;
+
+    NRF_LOG_INFO("Erase bonds!");
+
+    err_code = pm_peers_delete();
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for starting advertising.
+ */
+static void advertising_start(bool erase_bonds)
+{
+    if (erase_bonds == true)
+    {
+        delete_bonds();
+        // Advertising is started by PM_EVT_PEERS_DELETE_SUCCEEDED event.
+    }
+    else
+    {
+        whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
+
+        ret_code_t ret = ble_advertising_start(&m_advertising, BLE_ADV_MODE_FAST);
+        APP_ERROR_CHECK(ret);
+    }
+}
+
+
+/**@brief Function for handling Peer Manager events.
+ *
+ * @param[in] p_evt  Peer Manager event.
+ */
+static void pm_evt_handler(pm_evt_t const * p_evt)
+{
+    pm_handler_on_pm_evt(p_evt);
+    pm_handler_disconnect_on_sec_failure(p_evt);
+    pm_handler_flash_clean(p_evt);
+
+    switch (p_evt->evt_id)
+    {
+        case PM_EVT_CONN_SEC_SUCCEEDED:
+            m_peer_id = p_evt->peer_id;
+            break;
+
+        case PM_EVT_PEERS_DELETE_SUCCEEDED:
+            advertising_start(false);
+            break;
+
+        case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
+            if (     p_evt->params.peer_data_update_succeeded.flash_changed
+                 && (p_evt->params.peer_data_update_succeeded.data_id == PM_PEER_DATA_ID_BONDING))
+            {
+                NRF_LOG_INFO("New Bond, add the peer to the whitelist if possible");
+                // Note: You should check on what kind of white list policy your application should use.
+
+                whitelist_set(PM_PEER_ID_LIST_SKIP_NO_ID_ADDR);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+/**@brief Function for handling Service errors.
+ *
+ * @details A pointer to this function will be passed to each service which may need to inform the
+ *          application about an error.
+ *
+ * @param[in]   nrf_error   Error code containing information about what went wrong.
+ */
+static void service_error_handler(uint32_t nrf_error)
+{
+    APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for handling advertising errors.
+ *
+ * @param[in] nrf_error  Error code containing information about what went wrong.
+ */
+static void ble_advertising_error_handler(uint32_t nrf_error)
+{
+    APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for performing a battery measurement, and update the Battery Level characteristic in the Battery Service.
+ */
+static void battery_level_update(void)
+{
+    ret_code_t err_code;
+    uint8_t  battery_level;
+
+    battery_level = (uint8_t)sensorsim_measure(&m_battery_sim_state, &m_battery_sim_cfg);
+
+    err_code = ble_bas_battery_level_update(&m_bas, battery_level, BLE_CONN_HANDLE_ALL);
+    if ((err_code != NRF_SUCCESS) &&
+        (err_code != NRF_ERROR_BUSY) &&
+        (err_code != NRF_ERROR_RESOURCES) &&
+        (err_code != NRF_ERROR_FORBIDDEN) &&
+        (err_code != NRF_ERROR_INVALID_STATE) &&
+        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
+       )
+    {
+        APP_ERROR_HANDLER(err_code);
+    }
+}
+
+
+/**@brief Function for handling the Battery measurement timer timeout.
+ *
+ * @details This function will be called each time the battery level measurement timer expires.
+ *
+ * @param[in]   p_context   Pointer used for passing some arbitrary information (context) from the
+ *                          app_start_timer() call to the timeout handler.
+ */
+static void battery_level_meas_timeout_handler(void * p_context)
+{
+    UNUSED_PARAMETER(p_context);
+    battery_level_update();
+}
+
+
+/**@brief Function for the Timer initialization.
+ *
+ * @details Initializes the timer module.
+ */
+static void timers_init(void)
+{
+    ret_code_t err_code;
+
+    err_code = app_timer_init();
+    APP_ERROR_CHECK(err_code);
+
+    // Create battery timer.
+    err_code = app_timer_create(&m_battery_timer_id,
+                                APP_TIMER_MODE_REPEATED,
+                                battery_level_meas_timeout_handler);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for the GAP initialization.
+ *
+ * @details This function sets up all the necessary GAP (Generic Access Profile) parameters of the
+ *          device including the device name, appearance, and the preferred connection parameters.
+ */
+static void gap_params_init(void)
+{
+    ret_code_t              err_code;
+    ble_gap_conn_params_t   gap_conn_params;
+    ble_gap_conn_sec_mode_t sec_mode;
+
+    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
+
+    err_code = sd_ble_gap_device_name_set(&sec_mode,
+                                          (const uint8_t *)DEVICE_NAME,
+                                          strlen(DEVICE_NAME));
+    APP_ERROR_CHECK(err_code);
+
+    err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HID_MOUSE);
+    APP_ERROR_CHECK(err_code);
+
+    memset(&gap_conn_params, 0, sizeof(gap_conn_params));
+
+    gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
+    gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
+    gap_conn_params.slave_latency     = SLAVE_LATENCY;
+    gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
+
+    err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing the GATT module.
+ */
+static void gatt_init(void)
+{
+    ret_code_t err_code = nrf_ble_gatt_init(&m_gatt, NULL);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling Queued Write Module errors.
+ *
+ * @details A pointer to this function will be passed to each service which may need to inform the
+ *          application about an error.
+ *
+ * @param[in]   nrf_error   Error code containing information about what went wrong.
+ */
+static void nrf_qwr_error_handler(uint32_t nrf_error)
+{
+    APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for initializing the Queued Write Module.
+ */
+static void qwr_init(void)
+{
+    ret_code_t         err_code;
+    nrf_ble_qwr_init_t qwr_init_obj = {0};
+
+    qwr_init_obj.error_handler = nrf_qwr_error_handler;
+
+    err_code = nrf_ble_qwr_init(&m_qwr, &qwr_init_obj);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing Device Information Service.
+ */
+static void dis_init(void)
+{
+    ret_code_t       err_code;
+    ble_dis_init_t   dis_init_obj;
+    ble_dis_pnp_id_t pnp_id;
+
+    pnp_id.vendor_id_source = PNP_ID_VENDOR_ID_SOURCE;
+    pnp_id.vendor_id        = PNP_ID_VENDOR_ID;
+    pnp_id.product_id       = PNP_ID_PRODUCT_ID;
+    pnp_id.product_version  = PNP_ID_PRODUCT_VERSION;
+
+    memset(&dis_init_obj, 0, sizeof(dis_init_obj));
+
+    ble_srv_ascii_to_utf8(&dis_init_obj.manufact_name_str, MANUFACTURER_NAME);
+    dis_init_obj.p_pnp_id = &pnp_id;
+
+    dis_init_obj.dis_char_rd_sec = SEC_JUST_WORKS;
+
+    err_code = ble_dis_init(&dis_init_obj);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing Battery Service.
+ */
+static void bas_init(void)
+{
+    ret_code_t     err_code;
+    ble_bas_init_t bas_init_obj;
+
+    memset(&bas_init_obj, 0, sizeof(bas_init_obj));
+
+    bas_init_obj.evt_handler          = NULL;
+    bas_init_obj.support_notification = true;
+    bas_init_obj.p_report_ref         = NULL;
+    bas_init_obj.initial_batt_level   = 100;
+
+    bas_init_obj.bl_rd_sec        = SEC_JUST_WORKS;
+    bas_init_obj.bl_cccd_wr_sec   = SEC_JUST_WORKS;
+    bas_init_obj.bl_report_rd_sec = SEC_JUST_WORKS;
+
+    err_code = ble_bas_init(&m_bas, &bas_init_obj);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing HID Service.
+ */
+static void hids_init(void)
+{
+    ret_code_t                err_code;
+    ble_hids_init_t           hids_init_obj;
+    ble_hids_inp_rep_init_t * p_input_report;
+    uint8_t                   hid_info_flags;
+
+    static ble_hids_inp_rep_init_t inp_rep_array[INPUT_REPORT_COUNT];
+    static uint8_t rep_map_data[] =
+    {
+        0x05, 0x01, // Usage Page (Generic Desktop)
+        0x09, 0x02, // Usage (Mouse)
+
+        0xA1, 0x01, // Collection (Application)
+
+        // Report ID 1: Mouse buttons + scroll/pan
+        0x85, 0x01,       // Report Id 1
+        0x09, 0x01,       // Usage (Pointer)
+        0xA1, 0x00,       // Collection (Physical)
+        0x95, 0x05,       // Report Count (3)
+        0x75, 0x01,       // Report Size (1)
+        0x05, 0x09,       // Usage Page (Buttons)
+        0x19, 0x01,       // Usage Minimum (01)
+        0x29, 0x05,       // Usage Maximum (05)
+        0x15, 0x00,       // Logical Minimum (0)
+        0x25, 0x01,       // Logical Maximum (1)
+        0x81, 0x02,       // Input (Data, Variable, Absolute)
+        0x95, 0x01,       // Report Count (1)
+        0x75, 0x03,       // Report Size (3)
+        0x81, 0x01,       // Input (Constant) for padding
+        0x75, 0x08,       // Report Size (8)
+        0x95, 0x01,       // Report Count (1)
+        0x05, 0x01,       // Usage Page (Generic Desktop)
+        0x09, 0x38,       // Usage (Wheel)
+        0x15, 0x81,       // Logical Minimum (-127)
+        0x25, 0x7F,       // Logical Maximum (127)
+        0x81, 0x06,       // Input (Data, Variable, Relative)
+        0x05, 0x0C,       // Usage Page (Consumer)
+        0x0A, 0x38, 0x02, // Usage (AC Pan)
+        0x95, 0x01,       // Report Count (1)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0xC0,             // End Collection (Physical)
+
+        // Report ID 2: Mouse motion
+        0x85, 0x02,       // Report Id 2
+        0x09, 0x01,       // Usage (Pointer)
+        0xA1, 0x00,       // Collection (Physical)
+        0x75, 0x0C,       // Report Size (12)
+        0x95, 0x02,       // Report Count (2)
+        0x05, 0x01,       // Usage Page (Generic Desktop)
+        0x09, 0x30,       // Usage (X)
+        0x09, 0x31,       // Usage (Y)
+        0x16, 0x01, 0xF8, // Logical maximum (2047)
+        0x26, 0xFF, 0x07, // Logical minimum (-2047)
+        0x81, 0x06,       // Input (Data, Variable, Relative)
+        0xC0,             // End Collection (Physical)
+        0xC0,             // End Collection (Application)
+
+        // Report ID 3: Advanced buttons
+        0x05, 0x0C,       // Usage Page (Consumer)
+        0x09, 0x01,       // Usage (Consumer Control)
+        0xA1, 0x01,       // Collection (Application)
+        0x85, 0x03,       // Report Id (3)
+        0x15, 0x00,       // Logical minimum (0)
+        0x25, 0x01,       // Logical maximum (1)
+        0x75, 0x01,       // Report Size (1)
+        0x95, 0x01,       // Report Count (1)
+
+        0x09, 0xCD,       // Usage (Play/Pause)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x09, 0xB5,       // Usage (Scan Next Track)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x09, 0xB6,       // Usage (Scan Previous Track)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+
+        0x09, 0xEA,       // Usage (Volume Down)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x09, 0xE9,       // Usage (Volume Up)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x0A, 0x25, 0x02, // Usage (AC Forward)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0x0A, 0x24, 0x02, // Usage (AC Back)
+        0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+        0xC0              // End Collection
+    };
+
+    memset(inp_rep_array, 0, sizeof(inp_rep_array));
+    // Initialize HID Service.
+    p_input_report                      = &inp_rep_array[INPUT_REP_BUTTONS_INDEX];
+    p_input_report->max_len             = INPUT_REP_BUTTONS_LEN;
+    p_input_report->rep_ref.report_id   = INPUT_REP_REF_BUTTONS_ID;
+    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
+
+    p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
+    p_input_report->sec.wr      = SEC_JUST_WORKS;
+    p_input_report->sec.rd      = SEC_JUST_WORKS;
+
+    p_input_report                      = &inp_rep_array[INPUT_REP_MOVEMENT_INDEX];
+    p_input_report->max_len             = INPUT_REP_MOVEMENT_LEN;
+    p_input_report->rep_ref.report_id   = INPUT_REP_REF_MOVEMENT_ID;
+    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
+
+    p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
+    p_input_report->sec.wr      = SEC_JUST_WORKS;
+    p_input_report->sec.rd      = SEC_JUST_WORKS;
+
+    p_input_report                      = &inp_rep_array[INPUT_REP_MPLAYER_INDEX];
+    p_input_report->max_len             = INPUT_REP_MEDIA_PLAYER_LEN;
+    p_input_report->rep_ref.report_id   = INPUT_REP_REF_MPLAYER_ID;
+    p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;
+
+    p_input_report->sec.cccd_wr = SEC_JUST_WORKS;
+    p_input_report->sec.wr      = SEC_JUST_WORKS;
+    p_input_report->sec.rd      = SEC_JUST_WORKS;
+
+    hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;
+
+    memset(&hids_init_obj, 0, sizeof(hids_init_obj));
+
+    hids_init_obj.evt_handler                    = on_hids_evt;
+    hids_init_obj.error_handler                  = service_error_handler;
+    hids_init_obj.is_kb                          = false;
+    hids_init_obj.is_mouse                       = true;
+    hids_init_obj.inp_rep_count                  = INPUT_REPORT_COUNT;
+    hids_init_obj.p_inp_rep_array                = inp_rep_array;
+    hids_init_obj.outp_rep_count                 = 0;
+    hids_init_obj.p_outp_rep_array               = NULL;
+    hids_init_obj.feature_rep_count              = 0;
+    hids_init_obj.p_feature_rep_array            = NULL;
+    hids_init_obj.rep_map.data_len               = sizeof(rep_map_data);
+    hids_init_obj.rep_map.p_data                 = rep_map_data;
+    hids_init_obj.hid_information.bcd_hid        = BASE_USB_HID_SPEC_VERSION;
+    hids_init_obj.hid_information.b_country_code = 0;
+    hids_init_obj.hid_information.flags          = hid_info_flags;
+    hids_init_obj.included_services_count        = 0;
+    hids_init_obj.p_included_services_array      = NULL;
+
+    hids_init_obj.rep_map.rd_sec         = SEC_JUST_WORKS;
+    hids_init_obj.hid_information.rd_sec = SEC_JUST_WORKS;
+
+    hids_init_obj.boot_mouse_inp_rep_sec.cccd_wr = SEC_JUST_WORKS;
+    hids_init_obj.boot_mouse_inp_rep_sec.wr      = SEC_JUST_WORKS;
+    hids_init_obj.boot_mouse_inp_rep_sec.rd      = SEC_JUST_WORKS;
+
+    hids_init_obj.protocol_mode_rd_sec = SEC_JUST_WORKS;
+    hids_init_obj.protocol_mode_wr_sec = SEC_JUST_WORKS;
+    hids_init_obj.ctrl_point_wr_sec    = SEC_JUST_WORKS;
+
+    err_code = ble_hids_init(&m_hids, &hids_init_obj);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing services that will be used by the application.
+ */
+static void services_init(void)
+{
+    qwr_init();
+    dis_init();
+    bas_init();
+    hids_init();
+}
+
+
+/**@brief Function for initializing the battery sensor simulator.
+ */
+static void sensor_simulator_init(void)
+{
+    m_battery_sim_cfg.min          = MIN_BATTERY_LEVEL;
+    m_battery_sim_cfg.max          = MAX_BATTERY_LEVEL;
+    m_battery_sim_cfg.incr         = BATTERY_LEVEL_INCREMENT;
+    m_battery_sim_cfg.start_at_max = true;
+
+    sensorsim_init(&m_battery_sim_state, &m_battery_sim_cfg);
+}
+
+
+/**@brief Function for handling a Connection Parameters error.
+ *
+ * @param[in]   nrf_error   Error code containing information about what went wrong.
+ */
+static void conn_params_error_handler(uint32_t nrf_error)
+{
+    APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for initializing the Connection Parameters module.
+ */
+static void conn_params_init(void)
+{
+    ret_code_t             err_code;
+    ble_conn_params_init_t cp_init;
+
+    memset(&cp_init, 0, sizeof(cp_init));
+
+    cp_init.p_conn_params                  = NULL;
+    cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
+    cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
+    cp_init.max_conn_params_update_count   = MAX_CONN_PARAM_UPDATE_COUNT;
+    cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
+    cp_init.disconnect_on_fail             = false;
+    cp_init.evt_handler                    = NULL;
+    cp_init.error_handler                  = conn_params_error_handler;
+
+    err_code = ble_conn_params_init(&cp_init);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for starting timers.
+ */
+static void timers_start(void)
+{
+    ret_code_t err_code;
+
+    err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for putting the chip into sleep mode.
+ *
+ * @note This function will not return.
+ */
+static void sleep_mode_enter(void)
+{
+    ret_code_t err_code;
+
+    err_code = bsp_indication_set(BSP_INDICATE_IDLE);
+    APP_ERROR_CHECK(err_code);
+
+    // Prepare wakeup buttons.
+    err_code = bsp_btn_ble_sleep_mode_prepare();
+    APP_ERROR_CHECK(err_code);
+
+    // Go to system-off mode (this function will not return; wakeup will cause a reset).
+    err_code = sd_power_system_off();
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling HID events.
+ *
+ * @details This function will be called for all HID events which are passed to the application.
+ *
+ * @param[in]   p_hids  HID service structure.
+ * @param[in]   p_evt   Event received from the HID service.
+ */
+static void on_hids_evt(ble_hids_t * p_hids, ble_hids_evt_t * p_evt)
+{
+    switch (p_evt->evt_type)
+    {
+        case BLE_HIDS_EVT_BOOT_MODE_ENTERED:
+            m_in_boot_mode = true;
+            break;
+
+        case BLE_HIDS_EVT_REPORT_MODE_ENTERED:
+            m_in_boot_mode = false;
+            break;
+
+        case BLE_HIDS_EVT_NOTIF_ENABLED:
+            break;
+
+        default:
+            // No implementation needed.
+            break;
+    }
+}
+
+
+/**@brief Function for handling advertising events.
+ *
+ * @details This function will be called for advertising events which are passed to the application.
+ *
+ * @param[in] ble_adv_evt  Advertising event.
+ */
+static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
+{
+    ret_code_t err_code;
+
+    switch (ble_adv_evt)
+    {
+        case BLE_ADV_EVT_DIRECTED_HIGH_DUTY:
+            NRF_LOG_INFO("Directed advertising.");
+            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_DIRECTED);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_ADV_EVT_FAST:
+            NRF_LOG_INFO("Fast advertising.");
+            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_ADV_EVT_SLOW:
+            NRF_LOG_INFO("Slow advertising.");
+#if SWIFT_PAIR_SUPPORTED == 1
+            m_sp_advdata.p_manuf_specific_data = NULL;
+            err_code = ble_advertising_advdata_update(&m_advertising, &m_sp_advdata, NULL);
+            APP_ERROR_CHECK(err_code);
+#endif
+            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_SLOW);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_ADV_EVT_FAST_WHITELIST:
+            NRF_LOG_INFO("Fast advertising with whitelist.");
+            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_ADV_EVT_SLOW_WHITELIST:
+            NRF_LOG_INFO("Slow advertising with whitelist.");
+            err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING_WHITELIST);
+            APP_ERROR_CHECK(err_code);
+            err_code = ble_advertising_restart_without_whitelist(&m_advertising);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_ADV_EVT_IDLE:
+            err_code = bsp_indication_set(BSP_INDICATE_IDLE);
+            APP_ERROR_CHECK(err_code);
+            sleep_mode_enter();
+            break;
+
+        case BLE_ADV_EVT_WHITELIST_REQUEST:
+        {
+            ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+            ble_gap_irk_t  whitelist_irks[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
+            uint32_t       addr_cnt = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
+            uint32_t       irk_cnt  = BLE_GAP_WHITELIST_ADDR_MAX_COUNT;
+
+            err_code = pm_whitelist_get(whitelist_addrs, &addr_cnt,
+                                        whitelist_irks,  &irk_cnt);
+            APP_ERROR_CHECK(err_code);
+            NRF_LOG_DEBUG("pm_whitelist_get returns %d addr in whitelist and %d irk whitelist",
+                           addr_cnt,
+                           irk_cnt);
+
+            // Set the correct identities list (no excluding peers with no Central Address Resolution).
+            identities_set(PM_PEER_ID_LIST_SKIP_NO_IRK);
+
+            // Apply the whitelist.
+            err_code = ble_advertising_whitelist_reply(&m_advertising,
+                                                       whitelist_addrs,
+                                                       addr_cnt,
+                                                       whitelist_irks,
+                                                       irk_cnt);
+            APP_ERROR_CHECK(err_code);
+        }
+        break;
+
+        case BLE_ADV_EVT_PEER_ADDR_REQUEST:
+        {
+            pm_peer_data_bonding_t peer_bonding_data;
+
+            // Only Give peer address if we have a handle to the bonded peer.
+            if (m_peer_id != PM_PEER_ID_INVALID)
+            {
+
+                err_code = pm_peer_data_bonding_load(m_peer_id, &peer_bonding_data);
+                if (err_code != NRF_ERROR_NOT_FOUND)
+                {
+                    APP_ERROR_CHECK(err_code);
+
+                    // Manipulate identities to exclude peers with no Central Address Resolution.
+                    identities_set(PM_PEER_ID_LIST_SKIP_ALL);
+
+                    ble_gap_addr_t * p_peer_addr = &(peer_bonding_data.peer_ble_id.id_addr_info);
+                    err_code = ble_advertising_peer_addr_reply(&m_advertising, p_peer_addr);
+                    APP_ERROR_CHECK(err_code);
+                }
+
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+}
+
+
+/**@brief Function for handling BLE events.
+ *
+ * @param[in]   p_ble_evt   Bluetooth stack event.
+ * @param[in]   p_context   Unused.
+ */
+static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
+{
+    ret_code_t err_code;
+
+    switch (p_ble_evt->header.evt_id)
+    {
+        case BLE_GAP_EVT_CONNECTED:
+            NRF_LOG_INFO("Connected");
+            err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
+            APP_ERROR_CHECK(err_code);
+
+            m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+
+            err_code = nrf_ble_qwr_conn_handle_assign(&m_qwr, m_conn_handle);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_GAP_EVT_DISCONNECTED:
+            NRF_LOG_INFO("Disconnected");
+            // LED indication will be changed when advertising starts.
+
+            m_conn_handle = BLE_CONN_HANDLE_INVALID;
+            break;
+
+        case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
+        {
+            NRF_LOG_DEBUG("PHY update request.");
+            ble_gap_phys_t const phys =
+            {
+                .rx_phys = BLE_GAP_PHY_AUTO,
+                .tx_phys = BLE_GAP_PHY_AUTO,
+            };
+            err_code = sd_ble_gap_phy_update(p_ble_evt->evt.gap_evt.conn_handle, &phys);
+            APP_ERROR_CHECK(err_code);
+        } break;
+
+        case BLE_GATTC_EVT_TIMEOUT:
+            // Disconnect on GATT Client timeout event.
+            NRF_LOG_DEBUG("GATT Client Timeout.");
+            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gattc_evt.conn_handle,
+                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        case BLE_GATTS_EVT_TIMEOUT:
+            // Disconnect on GATT Server timeout event.
+            NRF_LOG_DEBUG("GATT Server Timeout.");
+            err_code = sd_ble_gap_disconnect(p_ble_evt->evt.gatts_evt.conn_handle,
+                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+            APP_ERROR_CHECK(err_code);
+            break;
+
+        default:
+            // No implementation needed.
+            break;
+    }
+}
+
+
+/**@brief Function for initializing the BLE stack.
+ *
+ * @details Initializes the SoftDevice and the BLE event interrupt.
+ */
+static void ble_stack_init(void)
+{
+    ret_code_t err_code;
+
+    err_code = nrf_sdh_enable_request();
+    APP_ERROR_CHECK(err_code);
+
+    // Configure the BLE stack using the default settings.
+    // Fetch the start address of the application RAM.
+    uint32_t ram_start = 0;
+    err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
+    APP_ERROR_CHECK(err_code);
+
+    // Enable BLE stack.
+    err_code = nrf_sdh_ble_enable(&ram_start);
+    APP_ERROR_CHECK(err_code);
+
+    // Register a handler for BLE events.
+    NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
+}
+
+
+/**@brief Function for the Peer Manager initialization.
+ */
+static void peer_manager_init(void)
+{
+    ble_gap_sec_params_t sec_param;
+    ret_code_t           err_code;
+
+    err_code = pm_init();
+    APP_ERROR_CHECK(err_code);
+
+    memset(&sec_param, 0, sizeof(ble_gap_sec_params_t));
+
+    // Security parameters to be used for all security procedures.
+    sec_param.bond           = SEC_PARAM_BOND;
+    sec_param.mitm           = SEC_PARAM_MITM;
+    sec_param.lesc           = SEC_PARAM_LESC;
+    sec_param.keypress       = SEC_PARAM_KEYPRESS;
+    sec_param.io_caps        = SEC_PARAM_IO_CAPABILITIES;
+    sec_param.oob            = SEC_PARAM_OOB;
+    sec_param.min_key_size   = SEC_PARAM_MIN_KEY_SIZE;
+    sec_param.max_key_size   = SEC_PARAM_MAX_KEY_SIZE;
+    sec_param.kdist_own.enc  = 1;
+    sec_param.kdist_own.id   = 1;
+    sec_param.kdist_peer.enc = 1;
+    sec_param.kdist_peer.id  = 1;
+
+    err_code = pm_sec_params_set(&sec_param);
+    APP_ERROR_CHECK(err_code);
+
+    err_code = pm_register(pm_evt_handler);
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing the Advertising functionality.
+ */
+static void advertising_init(void)
+{
+    ret_code_t             err_code;
+    uint8_t                adv_flags;
+    ble_advertising_init_t init;
+
+    memset(&init, 0, sizeof(init));
+
+    adv_flags                            = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
+    init.advdata.name_type               = BLE_ADVDATA_FULL_NAME;
+    init.advdata.include_appearance      = true;
+    init.advdata.flags                   = adv_flags;
+    init.advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
+    init.advdata.uuids_complete.p_uuids  = m_adv_uuids;
+#if SWIFT_PAIR_SUPPORTED == 1
+    init.advdata.p_manuf_specific_data = &m_sp_manuf_advdata;
+    memcpy(&m_sp_advdata, &init.advdata, sizeof(m_sp_advdata));
+#endif
+
+    init.config.ble_adv_whitelist_enabled          = true;
+    init.config.ble_adv_directed_high_duty_enabled = true;
+    init.config.ble_adv_directed_enabled           = false;
+    init.config.ble_adv_directed_interval          = 0;
+    init.config.ble_adv_directed_timeout           = 0;
+    init.config.ble_adv_fast_enabled               = true;
+    init.config.ble_adv_fast_interval              = APP_ADV_FAST_INTERVAL;
+    init.config.ble_adv_fast_timeout               = APP_ADV_FAST_DURATION;
+    init.config.ble_adv_slow_enabled               = true;
+    init.config.ble_adv_slow_interval              = APP_ADV_SLOW_INTERVAL;
+    init.config.ble_adv_slow_timeout               = APP_ADV_SLOW_DURATION;
+
+    init.evt_handler   = on_adv_evt;
+    init.error_handler = ble_advertising_error_handler;
+
+    err_code = ble_advertising_init(&m_advertising, &init);
+    APP_ERROR_CHECK(err_code);
+
+    ble_advertising_conn_cfg_tag_set(&m_advertising, APP_BLE_CONN_CFG_TAG);
+}
+
+
+/**@brief Function for the Event Scheduler initialization.
+ */
+static void scheduler_init(void)
+{
+    APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
+}
+
+
+/**@brief Function for sending a Mouse Movement.
+ *
+ * @param[in]   x_delta   Horizontal movement.
+ * @param[in]   y_delta   Vertical movement.
+ */
+static void mouse_movement_send(int16_t x_delta, int16_t y_delta)
+{
+    ret_code_t err_code;
+
+    if (m_in_boot_mode)
+    {
+        x_delta = MIN(x_delta, 0x00ff);
+        y_delta = MIN(y_delta, 0x00ff);
+
+        err_code = ble_hids_boot_mouse_inp_rep_send(&m_hids,
+                                                    0x00,
+                                                    (int8_t)x_delta,
+                                                    (int8_t)y_delta,
+                                                    0,
+                                                    NULL,
+                                                    m_conn_handle);
+    }
+    else
+    {
+        uint8_t buffer[INPUT_REP_MOVEMENT_LEN];
+
+        APP_ERROR_CHECK_BOOL(INPUT_REP_MOVEMENT_LEN == 3);
+
+        x_delta = MIN(x_delta, 0x0fff);
+        y_delta = MIN(y_delta, 0x0fff);
+
+        buffer[0] = x_delta & 0x00ff;
+        buffer[1] = ((y_delta & 0x000f) << 4) | ((x_delta & 0x0f00) >> 8);
+        buffer[2] = (y_delta & 0x0ff0) >> 4;
+
+        err_code = ble_hids_inp_rep_send(&m_hids,
+                                         INPUT_REP_MOVEMENT_INDEX,
+                                         INPUT_REP_MOVEMENT_LEN,
+                                         buffer,
+                                         m_conn_handle);
+    }
+
+    if ((err_code != NRF_SUCCESS) &&
+        (err_code != NRF_ERROR_INVALID_STATE) &&
+        (err_code != NRF_ERROR_RESOURCES) &&
+        (err_code != NRF_ERROR_BUSY) &&
+        (err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING)
+       )
+    {
+        APP_ERROR_HANDLER(err_code);
+    }
+}
+
+
+/**@brief Function for handling events from the BSP module.
+ *
+ * @param[in]   event   Event generated by button press.
+ */
+static void bsp_event_handler(bsp_event_t event)
+{
+    ret_code_t err_code;
+
+    switch (event)
+    {
+        case BSP_EVENT_SLEEP:
+            sleep_mode_enter();
+            break;
+
+        case BSP_EVENT_DISCONNECT:
+            err_code = sd_ble_gap_disconnect(m_conn_handle,
+                                             BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+            if (err_code != NRF_ERROR_INVALID_STATE)
+            {
+                APP_ERROR_CHECK(err_code);
+            }
+            break;
+
+        case BSP_EVENT_WHITELIST_OFF:
+            if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
+            {
+                err_code = ble_advertising_restart_without_whitelist(&m_advertising);
+                if (err_code != NRF_ERROR_INVALID_STATE)
+                {
+                    APP_ERROR_CHECK(err_code);
+                }
+            }
+            break;
+
+        case BSP_EVENT_KEY_0:
+            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+            {
+                mouse_movement_send(-MOVEMENT_SPEED, 0);
+            }
+            break;
+
+        case BSP_EVENT_KEY_1:
+            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+            {
+                mouse_movement_send(0, -MOVEMENT_SPEED);
+            }
+            break;
+
+        case BSP_EVENT_KEY_2:
+            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+            {
+                mouse_movement_send(MOVEMENT_SPEED, 0);
+            }
+            break;
+
+        case BSP_EVENT_KEY_3:
+            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
+            {
+                mouse_movement_send(0, MOVEMENT_SPEED);
+            }
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+/**@brief Function for initializing buttons and leds.
+ *
+ * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
+ */
+static void buttons_leds_init(bool * p_erase_bonds)
+{
+    ret_code_t err_code;
+    bsp_event_t startup_event;
+
+    err_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
+
+    APP_ERROR_CHECK(err_code);
+
+    err_code = bsp_btn_ble_init(NULL, &startup_event);
+    APP_ERROR_CHECK(err_code);
+
+    *p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
+}
+
+
+/**@brief Function for initializing the nrf log module.
+ */
+static void log_init(void)
+{
+    ret_code_t err_code = NRF_LOG_INIT(NULL);
+    APP_ERROR_CHECK(err_code);
+
+    NRF_LOG_DEFAULT_BACKENDS_INIT();
+}
+
+
+/**@brief Function for initializing power management.
+ */
+static void power_management_init(void)
+{
+    ret_code_t err_code;
+    err_code = nrf_pwr_mgmt_init();
+    APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling the idle state (main loop).
+ *
+ * @details If there is no pending log operation, then sleep until next the next event occurs.
+ */
+static void idle_state_handle(void)
+{
+    app_sched_execute();
+    if (NRF_LOG_PROCESS() == false)
+    {
+        nrf_pwr_mgmt_run();
+    }
+}
+
+
+/**@brief Function for application main entry.
+ */
+int main(void)
+{
+    bool erase_bonds;
+
+    // Initialize.
+    log_init();
+    timers_init();
+    buttons_leds_init(&erase_bonds);
+    power_management_init();
+    ble_stack_init();
+    scheduler_init();
+    gap_params_init();
+    gatt_init();
+    advertising_init();
+    services_init();
+    sensor_simulator_init();
+    conn_params_init();
+    peer_manager_init();
+
+    // Start execution.
+    NRF_LOG_INFO("HID Mouse example started.");
+    timers_start();
+    advertising_start(erase_bonds);
+
+    // Enter main loop.
+    for (;;)
+    {
+        idle_state_handle();
+    }
+}
+
+
+/**
+ * @}
+ */

+ 297 - 0
profiles/service/bsal_hid/bsal_srv_hid.c

@@ -0,0 +1,297 @@
+
+
+
+
+
+
+#include <rtthread.h>
+#include <rtdevice.h>
+#include <rthw.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include "bsal.h"
+#include "bsal_osif.h"
+#include "bsal_srv_hid.h"
+
+
+static P_SRV_GENERAL_CB pfn_bas_cb = NULL;
+
+
+static uint8_t rep_map_data[] =
+{
+    0x05, 0x01, // Usage Page (Generic Desktop)
+    0x09, 0x02, // Usage (Mouse)
+
+    0xA1, 0x01, // Collection (Application)
+
+    // Report ID 1: Mouse buttons + scroll/pan
+    0x85, 0x01,       // Report Id 1
+    0x09, 0x01,       // Usage (Pointer)
+    0xA1, 0x00,       // Collection (Physical)
+    0x95, 0x05,       // Report Count (3)
+    0x75, 0x01,       // Report Size (1)
+    0x05, 0x09,       // Usage Page (Buttons)
+    0x19, 0x01,       // Usage Minimum (01)
+    0x29, 0x05,       // Usage Maximum (05)
+    0x15, 0x00,       // Logical Minimum (0)
+    0x25, 0x01,       // Logical Maximum (1)
+    0x81, 0x02,       // Input (Data, Variable, Absolute)
+    0x95, 0x01,       // Report Count (1)
+    0x75, 0x03,       // Report Size (3)
+    0x81, 0x01,       // Input (Constant) for padding
+    0x75, 0x08,       // Report Size (8)
+    0x95, 0x01,       // Report Count (1)
+    0x05, 0x01,       // Usage Page (Generic Desktop)
+    0x09, 0x38,       // Usage (Wheel)
+    0x15, 0x81,       // Logical Minimum (-127)
+    0x25, 0x7F,       // Logical Maximum (127)
+    0x81, 0x06,       // Input (Data, Variable, Relative)
+    0x05, 0x0C,       // Usage Page (Consumer)
+    0x0A, 0x38, 0x02, // Usage (AC Pan)
+    0x95, 0x01,       // Report Count (1)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0xC0,             // End Collection (Physical)
+
+    // Report ID 2: Mouse motion
+    0x85, 0x02,       // Report Id 2
+    0x09, 0x01,       // Usage (Pointer)
+    0xA1, 0x00,       // Collection (Physical)
+    0x75, 0x0C,       // Report Size (12)
+    0x95, 0x02,       // Report Count (2)
+    0x05, 0x01,       // Usage Page (Generic Desktop)
+    0x09, 0x30,       // Usage (X)
+    0x09, 0x31,       // Usage (Y)
+    0x16, 0x01, 0xF8, // Logical maximum (2047)
+    0x26, 0xFF, 0x07, // Logical minimum (-2047)
+    0x81, 0x06,       // Input (Data, Variable, Relative)
+    0xC0,             // End Collection (Physical)
+    0xC0,             // End Collection (Application)
+
+    // Report ID 3: Advanced buttons
+    0x05, 0x0C,       // Usage Page (Consumer)
+    0x09, 0x01,       // Usage (Consumer Control)
+    0xA1, 0x01,       // Collection (Application)
+    0x85, 0x03,       // Report Id (3)
+    0x15, 0x00,       // Logical minimum (0)
+    0x25, 0x01,       // Logical maximum (1)
+    0x75, 0x01,       // Report Size (1)
+    0x95, 0x01,       // Report Count (1)
+
+    0x09, 0xCD,       // Usage (Play/Pause)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x09, 0xB5,       // Usage (Scan Next Track)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x09, 0xB6,       // Usage (Scan Previous Track)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+
+    0x09, 0xEA,       // Usage (Volume Down)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x09, 0xE9,       // Usage (Volume Up)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x0A, 0x25, 0x02, // Usage (AC Forward)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0x0A, 0x24, 0x02, // Usage (AC Back)
+    0x81, 0x06,       // Input (Data,Value,Relative,Bit Field)
+    0xC0              // End Collection
+};
+
+
+static void hid_profile_callback(void *p)
+{
+    bsal_callbak_data_t *p_param = (bsal_callbak_data_t *)p;
+    bool is_app_cb = false;
+    rt_kprintf("msg_type = %d\n", p_param->msg_type);
+    if (p_param->msg_type == BSAL_CALLBACK_TYPE_READ_CHAR_VALUE)
+    {
+        rt_kprintf("off_handle = %d\n", p_param->off_handle);
+        if (GATT_SVC_HID_REPORT_MAP_INDEX == p_param->off_handle)
+        {
+            is_app_cb = true;
+            rt_kprintf("report map\n");
+//            bsal_srv_write_data(p_param->stack_ptr, p_param->start_handle, p_param->off_handle, sizeof(rep_map_data), rep_map_data);
+        }
+    }
+    if (is_app_cb && (pfn_bas_cb != NULL))
+    {
+        pfn_bas_cb(p_param);
+    }
+}
+
+
+void bsal_le_hid_svr_init(void *stack_ptr, void *app_callback)
+{
+    struct bsal_gatt_app_srv_def ble_svc_hid_defs[] =
+    {
+        {
+            /*** Hid Service. */
+            .type = BSAL_GATT_UUID_PRIMARY_SERVICE,
+            .uuid = BSAL_UUID16_DECLARE(GATT_UUID_HID),
+            .characteristics = (bsal_gatt_chr_def_t[])
+            {
+//                {
+//                    /*** Protocol Mode characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_PROTOCOL_MODE),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE_WITHOUT_RESPONSE,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+                {
+                    /*** Input Report characteristics */
+                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_INPUT_REPORT),
+                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE | BSAL_ATT_P_NOTIFY,
+                    .permission = BSAL_GATT_PERM_READ_NONE,
+                    .value_length = 1,
+                },
+//                {
+//                    /*** Output Report characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_INPUT_REPORT),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE | BSAL_ATT_P_NOTIFY,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** Feature Report characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_INPUT_REPORT),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE | BSAL_ATT_P_NOTIFY,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** Report Map characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_REPORT_MAP),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+////                    .value_length = sizeof(rep_map_data),
+////                    .val_handle = rep_map_data,
+//                },
+//                {
+//                    /*** Boot Mouse Input Report characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_BOOT_MOUSE_INPUT_REPORT),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE | BSAL_ATT_P_NOTIFY,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** HID Information characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_HID_INFORMATION),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** HID Control Point characteristics */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_HID_CONTROL_POINT),
+//                    .properties = BSAL_ATT_P_WRITE_WITHOUT_RESPONSE,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+                {
+                    0, /* No more characteristics in this service. */
+                }
+            },
+        },
+//        {
+//            /*** Battery Service. */
+//            .type = BSAL_GATT_UUID_PRIMARY_SERVICE,
+//            .uuid = BSAL_UUID16_DECLARE(GATT_UUID_BATTERY),
+//            .characteristics = (bsal_gatt_chr_def_t[])
+//            {
+//                {
+//                    /*** Battery Level characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_BAS_LEVEL),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_NOTIFY,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    0, /* No more characteristics in this service. */
+//                }
+//            },
+//        },
+//        {
+//            /*** Device Information Service. */
+//            .type = BSAL_GATT_UUID_PRIMARY_SERVICE,
+//            .uuid = BSAL_UUID16_DECLARE(GATT_UUID_DEVICE_INFORMATION),
+//            .characteristics = (bsal_gatt_chr_def_t[])
+//            {
+//                {
+//                    /*** Manufacturer Name String characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_MANUFACTURER_NAME_STRING),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** PnP ID characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_PNP_ID),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    0, /* No more characteristics in this service. */
+//                }
+//            },
+//        },
+//        {
+//            /*** Generic Attribute Service. */
+//            .type = BSAL_GATT_UUID_PRIMARY_SERVICE,
+//            .uuid = BSAL_UUID16_DECLARE(GATT_UUID_GENERIC_ATTRIBUTE),
+//            /* This service is empty */
+//        },
+//        {
+//            /*** Generic Access Service. */
+//            .type = BSAL_GATT_UUID_PRIMARY_SERVICE,
+//            .uuid = BSAL_UUID16_DECLARE(GATT_UUID_GENERIC_ACCESS),
+//            .characteristics = (bsal_gatt_chr_def_t[])
+//            {
+//                {
+//                    /*** Device Name characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_DEVICE_NAME),
+//                    .properties = BSAL_ATT_P_READ | BSAL_ATT_P_WRITE,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** Appearance characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_GAP_APPEARANCE),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** Peripheral Preferred Connection Parameters characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_PPCP),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    /*** Central Address Resolution characteristic */
+//                    .uuid = BSAL_UUID16_DECLARE(GATT_UUID_CHAR_CENTRAL_ADDRESS_RESOLUTION),
+//                    .properties = BSAL_ATT_P_READ,
+//                    .permission = BSAL_GATT_PERM_READ_NONE,
+//                    .value_length = 1,
+//                },
+//                {
+//                    0, /* No more characteristics in this service. */
+//                }
+//            },
+//        },
+        {
+            0, /* No more services. */
+        },
+    };
+    bsal_stack_le_srv_reg_func(stack_ptr, &ble_svc_hid_defs, (P_SRV_GENERAL_CB *)hid_profile_callback);
+    pfn_bas_cb = (P_SRV_GENERAL_CB)app_callback;
+}
+
+
+
+
+
+

+ 45 - 0
profiles/service/bsal_hid/bsal_srv_hid.h

@@ -0,0 +1,45 @@
+#ifndef __BSAL_SRV_HID_H__
+#define __BSAL_SRV_HID_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdint.h>
+#include <stdbool.h>
+#include "bsal.h"
+
+
+
+#define GATT_UUID_HID                              BSAL_GATT_SERVICE_HUMAN_INTERFACE_DEVICE
+#define GATT_UUID_CHAR_PROTOCOL_MODE               BSAL_UUID_CHAR_PROTOCOL_MODE
+#define GATT_UUID_CHAR_INPUT_REPORT                BSAL_UUID_CHAR_REPORT
+#define GATT_UUID_CHAR_OUTPUT_REPORT               BSAL_UUID_CHAR_REPORT
+#define GATT_UUID_CHAR_FEATURE_REPORT              BSAL_UUID_CHAR_REPORT
+#define GATT_UUID_CHAR_REPORT_MAP                  BSAL_UUID_CHAR_REPORT_MAP
+#define GATT_UUID_CHAR_BOOT_MOUSE_INPUT_REPORT     BSAL_UUID_CHAR_BOOT_MOUSE_INPUT_REPORT
+#define GATT_UUID_CHAR_HID_INFORMATION             BSAL_UUID_CHAR_HID_INFORMATION
+#define GATT_UUID_CHAR_HID_CONTROL_POINT           BSAL_UUID_CHAR_HID_CONTROL_POINT
+
+#define GATT_UUID_BATTERY                          BSAL_GATT_SERVICE_BATTERY_SERVICE
+#define GATT_UUID_CHAR_BAS_LEVEL                   BSAL_UUID_CHAR_BATTERY_LEVEL
+
+#define GATT_UUID_DEVICE_INFORMATION               BSAL_GATT_SERVICE_DEVICE_INFORMATION
+#define GATT_UUID_CHAR_MANUFACTURER_NAME_STRING    BSAL_UUID_CHAR_MANUFACTURER_NAME_STRING
+#define GATT_UUID_CHAR_PNP_ID                      BSAL_UUID_CHAR_PNP_ID
+
+#define GATT_UUID_GENERIC_ATTRIBUTE                BSAL_GATT_SERVICE_GENERIC_ATTRIBUTE
+
+#define GATT_UUID_GENERIC_ACCESS                   BSAL_GATT_SERVICE_GENERIC_ACCESS
+#define GATT_UUID_CHAR_DEVICE_NAME                 BSAL_UUID_CHAR_GAP_DEVICE_NAME
+#define GATT_UUID_CHAR_GAP_APPEARANCE              BSAL_UUID_CHAR_GAP_APPEARANCE
+#define GATT_UUID_CHAR_PPCP                        BSAL_UUID_CHAR_GAP_PERIPHERAL_PREFERRED_CONNECTION_PARAMETERS
+#define GATT_UUID_CHAR_CENTRAL_ADDRESS_RESOLUTION  BSAL_UUID_CHAR_GAP_CENTRAL_ADDRESS_RESOLUTION
+
+
+#define GATT_SVC_HID_REPORT_MAP_INDEX              35
+
+void bsal_le_hid_svr_init(void *stack_ptr, void *app_callback);
+#endif 
+
+

BIN
profiles/service/bsal_hid/btsnoop_hci_hid.cfa


BIN
profiles/service/bsal_hid/images/2021-10-12135211.jpg


BIN
profiles/service/bsal_hid/images/2021-10-12135502.jpg


BIN
profiles/service/bsal_hid/images/2021-10-12145729.jpg


+ 169 - 0
samples/ble_hogp_app.c

@@ -0,0 +1,169 @@
+
+
+
+
+
+#include "bsal.h"
+#include <stdio.h>
+#include <string.h>
+#include "bsal_osif.h"
+#include "bsal_srv_hid.h"
+#include "bsal_srv_dis.h"
+
+
+#define BSAL_STACK_NAME PKG_BSAL_STACK_NAME
+
+static void *bsal_stack_ptr = NULL;
+static uint16_t bsal_app_conn_handle;
+static rt_uint8_t gap_conn_state = BSAL_GAP_CONN_STATE_CONNECTED;
+
+static void bsa_app_set_adv_data(void *stack_ptr)
+{
+    uint8_t tmp_data[32] = {0} ; //must be zero
+    bsal_le_adv_data_add_flag(tmp_data, BSAL_GAP_ADTYPE_FLAGS_LIMITED | BSAL_GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED);
+
+    char *adv_name = (char *)bsal_get_device_name(stack_ptr);
+    bsal_adv_data_add_name(tmp_data, strlen(adv_name), adv_name);
+    //bsal_adv_data_add_uuid16(tmp_data, BSAL_GATT_SERVICE_BATTERY_SERVICE);
+    bsal_set_le_adv_data_user(stack_ptr, tmp_data);
+}
+
+static void bsal_app_all_callback(void *stack_ptr, uint8_t cb_layer, uint16_t cb_sub_event, uint8_t value_length, void *value)
+{
+    T_BSAL_GAP_MSG_DATA  *bsal_gap_msg_data = (T_BSAL_GAP_MSG_DATA *)value;
+    uint8_t bd_addr[6];
+    switch (cb_layer)
+    {
+    case BSAL_CB_LAYER_GAP:
+        switch (cb_sub_event)
+        {
+        case BSAL_CB_STACK_READY:
+            //get mac address
+
+            bsal_osif_printf_info("============stack ready===========\r\n");
+            bsa_app_set_adv_data(stack_ptr);
+            bsal_stack_start_adv(stack_ptr);
+            break;
+        case BSAL_CB_CONNECT_STATUS:
+            bsal_osif_printf_info("============stack connect id %d===========\r\n", bsal_gap_msg_data->gap_conn_state_change.conn_id);
+            if (bsal_gap_msg_data->gap_conn_state_change.new_state == BSAL_GAP_CONN_STATE_CONNECTED)
+            {
+                bsal_app_conn_handle = bsal_gap_msg_data->gap_conn_state_change.conn_id;
+            }
+            else if (bsal_gap_msg_data->gap_conn_state_change.new_state == BSAL_GAP_CONN_STATE_DISCONNECTED)
+            {
+                bsal_stack_start_adv(stack_ptr);
+            }
+            bsal_osif_printf_info("BSAL: conn_id %d old_state %d new_state %d, disc_cause 0x%x",
+                                  bsal_gap_msg_data->gap_conn_state_change.conn_id, gap_conn_state, bsal_gap_msg_data->gap_conn_state_change.new_state, bsal_gap_msg_data->gap_conn_state_change.disc_cause);
+
+            break;
+        default:
+            break;
+        }
+
+        if (cb_sub_event == BSAL_CB_STACK_READY)
+        {
+            //stack ready
+        }
+
+        break;
+    case BSAL_CB_LAYER_GATT_PROFILE:
+        switch (cb_sub_event)
+        {
+            //save the service start_handle
+            //case uuid profile save start_handle
+            //case SRV_CALLBACK66
+            //save the identity
+        }
+        break;
+    case BSAL_CB_LAYER_SM:
+        break;
+    case BSAL_CB_LAYER_COMMON:
+        //connected save the connect id
+
+        break;
+    case BSAL_CB_LAYER_UNKNOWN:
+        break;
+    default:
+        break;
+    }
+
+}
+
+static void bsal_app_profile_callback(void *p)
+{
+    bsal_callbak_data_t *bsal_param = (bsal_callbak_data_t *)p;
+
+    if (bsal_param->msg_type == BSAL_CALLBACK_TYPE_READ_CHAR_VALUE)
+    {
+        bsal_osif_printf_info("========callback read from %x====%x=======\r\n", bsal_param->off_handle, bsal_param->srv_uuid.u16.value);
+    }
+    else if (bsal_param->msg_type == BSAL_CALLBACK_TYPE_INDIFICATION_NOTIFICATION)
+    {
+        uint16_t  cccbits = bsal_param->value;
+        bsal_osif_printf_info("======callback notify from %x===data cccd %x====%x=====\r\n", bsal_param->off_handle, cccbits, bsal_param->srv_uuid.u16.value);
+//        if (nus_is_uuid(&(bsal_param->srv_uuid), BSAL_UUID128_DECLARE(0x9e, 0xca, 0xdc, 0x24, 0x0e, 0xe5, 0xa9, 0xe0,
+//                        0x93, 0xf3, 0xa3, 0xb5, 0x01, 0x00, 0x40, 0x6e)))//uart_uuid
+//        {
+//            if (cccbits & BSAL_GATT_CCC_NOTIFY)
+//            {
+//                bsal_osif_printf_info("=========NOTIFY ENABLE from %x===data cccd %x====%x=====\r\n", bsal_param->off_handle, cccbits, bsal_param->srv_uuid.u16.value);
+//            }
+//            else
+//            {
+//                bsal_osif_printf_info("========NOTIFY DISABLE from %x===data cccd %x====%x=====\r\n", bsal_param->off_handle, cccbits, bsal_param->srv_uuid.u16.value);
+//            }
+//        }
+    }
+    else if (bsal_param->msg_type == BSAL_CALLBACK_TYPE_WRITE_CHAR_VALUE)
+    {
+        bsal_osif_printf_info("\r\n BSAL: THE DATA IS :%s\r\n", bsal_param->data);
+    }
+}
+
+int bsal_hogp_app(void)
+{
+    void *stack_ptr = bsal_find_stack_ptr(BSAL_STACK_NAME);
+    if (stack_ptr == NULL)
+    {
+        //print error;
+        return 1;
+    }
+    //set iocapability
+
+
+    bsal_stack_ptr  = stack_ptr;
+    //1. init stack
+    bsal_stack_init(stack_ptr, bsal_app_all_callback);  // init param not start stack
+    // set device name
+    char *device_name = "ble_rtt_hogp";
+    bsal_set_device_name(stack_ptr, strlen(device_name), (uint8_t *)device_name);
+    //2. bond type
+    bsal_set_device_le_bond_type(stack_ptr, false, BSAL_NO_INPUT, BSAL_NO_OUTPUT, BSAL_GAP_AUTHEN_BIT_NO_BONDING, false);
+    //set the bond flag:
+
+    //3. service begin
+    bsal_stack_le_srv_begin(stack_ptr, 1, bsal_app_profile_callback);  //will add 1 service
+
+    //4. uart init
+    bsal_le_hid_svr_init(stack_ptr, bsal_app_profile_callback);
+    
+    
+//    bsal_le_dis_svr_init(stack_ptr, bsal_app_profile_callback);
+
+    //5. srv_end
+    bsal_stack_le_srv_end(stack_ptr);    //end srv add
+
+    //6. start stack
+    bsal_stack_startup(stack_ptr);    //start she
+
+//    bsal_bleuart_init(stack_ptr, &bsal_app_conn_handle);
+
+    return 0;
+}
+MSH_CMD_EXPORT_ALIAS(bsal_hogp_app, bsal_hogp_app, "bluetoooth hogp sample");
+
+
+
+