• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file hids.c
5  *
6  * @brief THe Implementation of Human Input Device Service.
7  *
8  *****************************************************************************************
9  * @attention
10   #####Copyright (c) 2019 GOODIX
11   All rights reserved.
12 
13     Redistribution and use in source and binary forms, with or without
14     modification, are permitted provided that the following conditions are met:
15   * Redistributions of source code must retain the above copyright
16     notice, this list of conditions and the following disclaimer.
17   * Redistributions in binary form must reproduce the above copyright
18     notice, this list of conditions and the following disclaimer in the
19     documentation and/or other materials provided with the distribution.
20   * Neither the name of GOODIX nor the names of its contributors may be used
21     to endorse or promote products derived from this software without
22     specific prior written permission.
23 
24   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27   ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34   POSSIBILITY OF SUCH DAMAGE.
35  *****************************************************************************************
36  */
37 
38 /*
39  * INCLUDE FILES
40  *****************************************************************************************
41  */
42 #include "hids.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #define INDEX_0 0
47 #define INDEX_1 1
48 #define INDEX_2 2
49 #define INDEX_3 3
50 #define INDEX_4 4
51 /*
52  * DEFINES
53  *******************************************************************************
54  */
55 #define IN_REPORT_MAX_COUNT                       3                  /**< Maximum support input report count. */
56 /**< Maximum size of a Boot Keyboard Input Report (as per Appendix B in Device Class Definition
57  * for Human Interface Devices (HID), Version 1.11). */
58 #define HIDS_BOOT_KB_IN_REPORT_MAX_SIZE           8
59 /**< Maximum size of a Boot Keyboard Output Report (as per Appendix B in Device Class Definition
60  * for Human Interface Devices (HID), Version 1.11). */
61 #define HIDS_BOOT_KB_OUT_REPORT_MAX_SIZE          1
62 /**< Minimum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition
63  * for Human Interface Devices (HID), Version 1.11). */
64 #define HIDS_BOOT_MOUSE_IN_REPORT_MIN_SIZE        3
65 /**< Maximum size of a Boot Mouse Input Report (as per Appendix B in Device Class Definition
66  * for Human Interface Devices (HID), Version 1.11). */
67 #define HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE        8
68 
69 
70 // Protocol Mode values
71 #define PROTOCOL_MODE_BOOT                        0x00               /**< Boot Protocol Mode. */
72 #define PROTOCOL_MODE_REPORT                      0x01               /**< Report Protocol Mode. */
73 
74 // HID Control Point values
75 #define HIDS_CONTROL_POINT_SUSPEND                0x00               /**< Suspend command. */
76 #define HIDS_CONTROL_POINT_EXIT_SUSPEND           0x01               /**< Exit Suspend command. */
77 /**< Default value for the Protocol Mode characteristic. */
78 #define DEFAULT_PROTOCOL_MODE            PROTOCOL_MODE_REPORT
79 /**< Initial value for the HID Control Point characteristic. */
80 #define INITIAL_VALUE_HID_CONTROL_POINT  HIDS_CONTROL_POINT_SUSPEND
81 #define REPORT_CNT_0 0
82 #define REPORT_CNT_1 1
83 #define REPORT_CNT_2 2
84 /*
85  * ENUMERATIONS
86  *****************************************************************************************
87  */
88 /**@brief HIDS Attributes database index list. */
89 enum hids_attr_idx_tag {
90     // Service
91     HIDS_IDX_SVC,
92 
93     // Protocol Mode characteristic
94     HIDS_IDX_PROTOCOL_MODE_CHAR,
95     HIDS_IDX_PROTOCOL_MODE_VAL,
96 
97     // Input Report1 characteristics
98     HIDS_IDX_INPUT1_REPORT_CHAR,
99     HIDS_IDX_INPUT1_REPORT_VAL,
100     HIDS_IDX_INPUT1_REPORT_CCCD,
101     HIDS_IDX_INPUT1_REPORT_REF,
102 
103     // Input Report2 characteristics
104     HIDS_IDX_INPUT2_REPORT_CHAR,
105     HIDS_IDX_INPUT2_REPORT_VAL,
106     HIDS_IDX_INPUT2_REPORT_CCCD,
107     HIDS_IDX_INPUT2_REPORT_REF,
108 
109     // Input Report3 characteristics
110     HIDS_IDX_INPUT3_REPORT_CHAR,
111     HIDS_IDX_INPUT3_REPORT_VAL,
112     HIDS_IDX_INPUT3_REPORT_CCCD,
113     HIDS_IDX_INPUT3_REPORT_REF,
114 
115     // Output Report characteristics
116     HIDS_IDX_OUTPUT_REPORT_CHAR,
117     HIDS_IDX_OUTPUT_REPORT_VAL,
118     HIDS_IDX_OUTPUT_REPORT_REF,
119 
120     // Feature Report characteristic
121     HIDS_IDX_FEATURE_REPORT_CHAR,
122     HIDS_IDX_FEATURE_REPORT_VAL,
123     HIDS_IDX_FEATURE_REPORT_REF,
124 
125     // Report Map characteristic
126     HIDS_IDX_REPORT_MAP_CHAR,
127     HIDS_IDX_REPORT_MAP_VAL,
128 
129     // Boot Keyboard Input Report characteristic
130     HIDS_IDX_BOOT_KB_IN_RPT_CHAR,
131     HIDS_IDX_BOOT_KB_IN_RPT_VAL,
132     HIDS_IDX_BOOT_KB_IN_RPT_CCCD,
133 
134     // Boot Keyboard Output Report characteristic
135     HIDS_IDX_BOOT_KB_OUT_RPT_CHAR,
136     HIDS_IDX_BOOT_KB_OUT_RPT_VAL,
137 
138     // Boot Mouse Input Report characteristic.
139     HIDS_IDX_BOOT_MS_IN_RPT_CHAR,
140     HIDS_IDX_BOOT_MS_IN_RPT_VAL,
141     HIDS_IDX_BOOT_MS_IN_RPT_CCCD,
142 
143     // HID Information characteristic
144     HIDS_IDX_HID_INFO_CHAR,
145     HIDS_IDX_HID_INFO_VAL,
146 
147     // HID Control Point characteristic
148     HIDS_IDX_CTRL_POINT_CHAR,
149     HIDS_IDX_CTRL_POINT_VAL,
150 
151     HIDS_IDX_NB,
152 };
153 
154 /*
155  * STRUCT DEFINE
156  *******************************************************************************
157  */
158 /**@brief Heart Rate Service environment variable. */
159 struct hids_env_t {
160     hids_init_t               hids_init;                         /**< HID Service Init Value. */
161     uint16_t                  start_hdl;                         /**< HID Service start handle. */
162     uint8_t
163     char_mask[5];                                                /**< Mask of Supported characteristics*/
164     uint16_t
165     input_cccd[IN_REPORT_MAX_COUNT][HIDS_CONNECTION_MAX];        /**< Input report characteristics cccd value*/
166     uint16_t
167     kb_input_cccd[HIDS_CONNECTION_MAX];            /**< Boot keyboard input report characteristics cccd value*/
168     uint16_t
169     mouse_input_cccd[HIDS_CONNECTION_MAX];         /**< Boot mouse input report characteristics cccd value*/
170     uint8_t                   protocol_mode;                                               /**< Protocol mode. */
171     uint8_t                   ctrl_pt;                                                     /**< HID Control Point. */
172     uint8_t
173     input_report_val[IN_REPORT_MAX_COUNT][HIDS_REPORT_MAX_SIZE]; /**< Input report characteristics value*/
174     uint8_t
175     output_report_val[HIDS_REPORT_MAX_SIZE];                     /**< Output report characteristic value*/
176     uint8_t
177     feature_report_val[HIDS_REPORT_MAX_SIZE];                    /**< Feature report characteristic value*/
178     uint8_t
179     kb_input_report_val[HIDS_BOOT_KB_IN_REPORT_MAX_SIZE];  /**< Boot keyboard input report characteristics value*/
180     uint8_t
181     kb_output_report_val[HIDS_BOOT_KB_OUT_REPORT_MAX_SIZE];  /**< Boot keyboard output report characteristics value*/
182     uint8_t
183     mouse_input_report_val[HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE];  /**< Boot mouse input report characteristics value*/
184 };
185 
186 
187 /*
188  * LOCAL FUNCTION DECLARATIONS
189  *****************************************************************************************
190  */
191 static sdk_err_t hids_init(void);
192 static void      hids_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
193 static void      hids_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
194 static void      hids_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
195 
196 /*
197  * LOCAL VARIABLE DEFINITIONS
198  *******************************************************************************
199  */
200 static struct hids_env_t s_hids_env;
201 
202 
203 /**@brief Full HID Service Database Description - Used to add attributes into the database. */
204 static const attm_desc_t hids_attr_tab[HIDS_IDX_NB] = {
205     // HID Service Declaration
206     [HIDS_IDX_SVC] = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
207 
208     // Protocol Mode Characteristic - Declaration
209     [HIDS_IDX_PROTOCOL_MODE_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
210     // Protocol Mode Characteristic - Value
211     [HIDS_IDX_PROTOCOL_MODE_VAL]  = {
212         BLE_ATT_CHAR_PROTOCOL_MODE, READ_PERM(UNAUTH) | WRITE_CMD_PERM(UNAUTH),
213         ATT_VAL_LOC_USER, sizeof(uint8_t)
214     },
215 
216     // Input Report1 Characteristic - Declaration
217     [HIDS_IDX_INPUT1_REPORT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
218     // Input Report1 Characteristic - Value
219     [HIDS_IDX_INPUT1_REPORT_VAL]  = {
220         BLE_ATT_CHAR_REPORT, READ_PERM(UNAUTH) | NOTIFY_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
221         ATT_VAL_LOC_USER, HIDS_REPORT_MAX_SIZE
222     },
223     // Input Report1 Characteristic - Descriptor: CCCD
224     [HIDS_IDX_INPUT1_REPORT_CCCD] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH), 0, 0},
225     // Input Report1 Characteristic - Descriptor: Report Reference
226     [HIDS_IDX_INPUT1_REPORT_REF]  = {
227         BLE_ATT_DESC_REPORT_REF, READ_PERM(UNAUTH),
228         ATT_VAL_LOC_USER, sizeof(hids_report_ref_t)
229     },
230 
231     // Input Report2 Characteristic - Declaration
232     [HIDS_IDX_INPUT2_REPORT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
233     // Input Report2 Characteristic - Value
234     [HIDS_IDX_INPUT2_REPORT_VAL]  = {
235         BLE_ATT_CHAR_REPORT, READ_PERM(UNAUTH) | NOTIFY_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
236         ATT_VAL_LOC_USER, HIDS_REPORT_MAX_SIZE
237     },
238     // Input Report2 Characteristic - Descriptor: CCCD
239     [HIDS_IDX_INPUT2_REPORT_CCCD] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH), 0, 0},
240     // Input Report2 Characteristic - Descriptor: Report Reference
241     [HIDS_IDX_INPUT2_REPORT_REF]  = {
242         BLE_ATT_DESC_REPORT_REF, READ_PERM(UNAUTH),
243         ATT_VAL_LOC_USER, sizeof(hids_report_ref_t)
244     },
245 
246     // Input Report3 Characteristic - Declaration
247     [HIDS_IDX_INPUT3_REPORT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
248     // Input Report3 Characteristic - Value
249     [HIDS_IDX_INPUT3_REPORT_VAL]  = {
250         BLE_ATT_CHAR_REPORT, READ_PERM(UNAUTH) | NOTIFY_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
251         ATT_VAL_LOC_USER, HIDS_REPORT_MAX_SIZE
252     },
253     // Input Report3 Characteristic - Descriptor: CCCD
254     [HIDS_IDX_INPUT3_REPORT_CCCD] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH), 0, 0},
255     // Input Report3 Characteristic - Descriptor: Report Reference
256     [HIDS_IDX_INPUT3_REPORT_REF]  = {
257         BLE_ATT_DESC_REPORT_REF, READ_PERM(UNAUTH),
258         ATT_VAL_LOC_USER, sizeof(hids_report_ref_t)
259     },
260 
261     // Output Report Characteristic - Declaration
262     [HIDS_IDX_OUTPUT_REPORT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
263     // Output Report Characteristic - Value
264     [HIDS_IDX_OUTPUT_REPORT_VAL]  = {
265         BLE_ATT_CHAR_REPORT, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH) | WRITE_CMD_PERM(UNAUTH),
266         ATT_VAL_LOC_USER, HIDS_REPORT_MAX_SIZE
267     },
268     // Output Report Characteristic - Descriptor: Report Reference
269     [HIDS_IDX_OUTPUT_REPORT_REF]  = {
270         BLE_ATT_DESC_REPORT_REF, READ_PERM(UNAUTH),
271         ATT_VAL_LOC_USER, sizeof(hids_report_ref_t)
272     },
273 
274     // Feature Report Characteristic - Declaration
275     [HIDS_IDX_FEATURE_REPORT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
276     // Feature Report Characteristic - Value
277     [HIDS_IDX_FEATURE_REPORT_VAL]  = {
278         BLE_ATT_CHAR_REPORT, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
279         ATT_VAL_LOC_USER, HIDS_REPORT_MAX_SIZE
280     },
281     // Feature Report Characteristic - Descriptor: Report Reference
282     [HIDS_IDX_FEATURE_REPORT_REF]  = {
283         BLE_ATT_DESC_REPORT_REF, READ_PERM(UNAUTH),
284         ATT_VAL_LOC_USER, sizeof(hids_report_ref_t)
285     },
286 
287     // Report Map Characteristic - Declaration
288     [HIDS_IDX_REPORT_MAP_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
289     // Report Map Characteristic - Value
290     [HIDS_IDX_REPORT_MAP_VAL]  = {
291         BLE_ATT_CHAR_REPORT_MAP,     READ_PERM(UNAUTH),
292         ATT_VAL_LOC_USER, HIDS_REPORT_MAP_MAX_SIZE
293     },
294 
295     // Boot Keyboard Input Report Characteristic - Declaration
296     [HIDS_IDX_BOOT_KB_IN_RPT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
297     // Boot Keyboard Input Report Characteristic - Value
298     [HIDS_IDX_BOOT_KB_IN_RPT_VAL]  = {
299         BLE_ATT_CHAR_BOOT_KB_IN_REPORT,
300         READ_PERM(UNAUTH) | NOTIFY_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
301         ATT_VAL_LOC_USER, HIDS_BOOT_KB_IN_REPORT_MAX_SIZE
302     },
303     // Boot Keyboard Input Report Characteristic - Descriptor: CCCD
304     [HIDS_IDX_BOOT_KB_IN_RPT_CCCD] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH), 0, 0},
305 
306     // Boot Keyboard Output Report Characteristic - Declaration
307     [HIDS_IDX_BOOT_KB_OUT_RPT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
308     // Boot Keyboard Output Report Characteristic - Value
309     [HIDS_IDX_BOOT_KB_OUT_RPT_VAL]  = {
310         BLE_ATT_CHAR_BOOT_KB_OUT_REPORT,
311         READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH) | WRITE_CMD_PERM(UNAUTH),
312         ATT_VAL_LOC_USER, HIDS_BOOT_KB_OUT_REPORT_MAX_SIZE
313     },
314 
315     // Boot Mouse Input Report Characteristic - Declaration
316     [HIDS_IDX_BOOT_MS_IN_RPT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
317     // Boot Mouse Input Report Characteristic - Value
318     [HIDS_IDX_BOOT_MS_IN_RPT_VAL]  = {
319         BLE_ATT_CHAR_BOOT_MOUSE_IN_REPORT,
320         READ_PERM(UNAUTH) | NOTIFY_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
321         ATT_VAL_LOC_USER, HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE
322     },
323     // Boot Mouse Input Report Characteristic - Descriptor: CCCD
324     [HIDS_IDX_BOOT_MS_IN_RPT_CCCD] = {BLE_ATT_DESC_CLIENT_CHAR_CFG, READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH), 0, 0},
325 
326     // HID Information Characteristic - Declaration
327     [HIDS_IDX_HID_INFO_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
328     // HID Information Characteristic - Value
329     [HIDS_IDX_HID_INFO_VAL]  = {
330         BLE_ATT_CHAR_HID_INFO,       READ_PERM(UNAUTH),
331         ATT_VAL_LOC_USER, sizeof(hids_hid_info_t)
332     },
333 
334     // HID Control Point Characteristic - Declaration
335     [HIDS_IDX_CTRL_POINT_CHAR] = {
336         BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC,
337         0, 0
338     },
339     // HID Control Point Characteristic - Value
340     [HIDS_IDX_CTRL_POINT_VAL]  = {
341         BLE_ATT_CHAR_HID_CTNL_PT,    WRITE_CMD_PERM(UNAUTH),
342         ATT_VAL_LOC_USER, sizeof(uint8_t)
343     },
344 };
345 
346 /**@brief HIDS interface required by profile manager. */
347 static ble_prf_manager_cbs_t hids_mgr_cbs = {
348     (prf_init_func_t)hids_init,
349     NULL,
350     NULL
351 };
352 
353 /**@brief HIDS GATT server Callbacks. */
354 static gatts_prf_cbs_t hids_gatts_cbs = {
355     hids_read_att_cb,
356     hids_write_att_cb,
357     NULL,
358     NULL,
359     hids_cccd_set_cb
360 };
361 
362 /**@brief HIDS Information. */
363 static const prf_server_info_t hids_prf_info = {
364     .max_connection_nb = HIDS_CONNECTION_MAX,
365     .manager_cbs       = &hids_mgr_cbs,
366     .gatts_prf_cbs     = &hids_gatts_cbs
367 };
368 
369 /*
370  * LOCAL FUNCTION DEFINITIONS
371  *******************************************************************************
372  */
373 
374 /**
375  *****************************************************************************************
376  * @brief Initialize HID service and create db in att.
377  *
378  * @return BLE_ATT_ERR_NO_ERROR on success, otherwise error code.
379  *****************************************************************************************
380  */
hids_init(void)381 static sdk_err_t hids_init(void)
382 {
383     const uint8_t     hids_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_HID);
384     gatts_create_db_t gatts_db;
385     uint16_t          start_hdl       = PRF_INVALID_HANDLE; /* The start hanlde is an in/out
386                                                              * parameter of ble_gatts_srvc_db_create().
387                                                              * It must be set with PRF_INVALID_HANDLE
388                                                              * to be allocated automatically by BLE Stack. */
389     sdk_err_t ret;
390     ret = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
391     if (ret < 0) {
392         return ret;
393     }
394 
395     gatts_db.shdl                 = &start_hdl;
396     gatts_db.uuid                 = (uint8_t*)hids_svc_uuid;
397     gatts_db.attr_tab_cfg         = (uint8_t*)&s_hids_env.char_mask;
398     gatts_db.max_nb_attr          = HIDS_IDX_NB;
399     gatts_db.srvc_perm            = 0;
400     gatts_db.attr_tab_type        = SERVICE_TABLE_TYPE_16;
401     gatts_db.attr_tab.attr_tab_16 = hids_attr_tab;
402 
403     sdk_err_t   status = ble_gatts_srvc_db_create(&gatts_db);
404     if (SDK_SUCCESS == status) {
405         s_hids_env.start_hdl = *gatts_db.shdl;
406     }
407     return status;
408 }
409 
410 /**
411  *****************************************************************************************
412  * @brief Handles reception of the read request.
413  *
414  * @param[in] conn_idx: Connection index.
415  * @param[in] p_param:  Pointer to the parameters of the read request.
416  *****************************************************************************************
417  */
hids_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)418 static void hids_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
419 {
420     uint8_t handle = p_param->handle;
421     uint8_t tab_index = prf_find_idx_by_handle(handle, s_hids_env.start_hdl,
422                         HIDS_IDX_NB,
423                         (uint8_t *)&s_hids_env.char_mask);
424     gatts_read_cfm_t cfm;
425 
426     cfm.handle = handle;
427     cfm.status = BLE_SUCCESS;
428 
429     switch (tab_index) {
430         case HIDS_IDX_PROTOCOL_MODE_VAL:
431             cfm.length = sizeof(uint8_t);
432             cfm.value  = (uint8_t *)(&s_hids_env.protocol_mode);
433             break;
434         /*----------------------------------------------------------------------------------*/
435         case HIDS_IDX_INPUT1_REPORT_VAL:
436             cfm.length = s_hids_env.hids_init.input_report_array[INDEX_0].value_len;
437             cfm.value  = (uint8_t *)(&s_hids_env.input_report_val[INDEX_0]);
438             break;
439 
440         case HIDS_IDX_INPUT1_REPORT_CCCD:
441             cfm.length = sizeof(uint16_t);
442             cfm.value  = (uint8_t *)(&s_hids_env.input_cccd[INDEX_0][conn_idx]);
443             break;
444 
445         case HIDS_IDX_INPUT1_REPORT_REF:
446             cfm.length = sizeof(hids_report_ref_t);
447             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.input_report_array[INDEX_0].ref);
448             break;
449         /*----------------------------------------------------------------------------------*/
450         case HIDS_IDX_INPUT2_REPORT_VAL:
451             cfm.length = s_hids_env.hids_init.input_report_array[INDEX_1].value_len;
452             cfm.value  = (uint8_t *)(&s_hids_env.input_report_val[INDEX_1]);
453             break;
454 
455         case HIDS_IDX_INPUT2_REPORT_CCCD:
456             cfm.length = sizeof(uint16_t);
457             cfm.value  = (uint8_t *)(&s_hids_env.input_cccd[INDEX_1][conn_idx]);
458             break;
459 
460         case HIDS_IDX_INPUT2_REPORT_REF:
461             cfm.length = sizeof(hids_report_ref_t);
462             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.input_report_array[INDEX_1].ref);
463             break;
464         /*----------------------------------------------------------------------------------*/
465         case HIDS_IDX_INPUT3_REPORT_VAL:
466             cfm.length = s_hids_env.hids_init.input_report_array[INDEX_2].value_len;
467             cfm.value  = (uint8_t *)(&s_hids_env.input_report_val[INDEX_2]);
468             break;
469 
470         case HIDS_IDX_INPUT3_REPORT_CCCD:
471             cfm.length = sizeof(uint16_t);
472             cfm.value  = (uint8_t *)(&s_hids_env.input_cccd[INDEX_2][conn_idx]);
473             break;
474 
475         case HIDS_IDX_INPUT3_REPORT_REF:
476             cfm.length = sizeof(hids_report_ref_t);
477             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.input_report_array[INDEX_2].ref);
478             break;
479         /*----------------------------------------------------------------------------------*/
480         case HIDS_IDX_OUTPUT_REPORT_VAL:
481             cfm.length = s_hids_env.hids_init.output_report.value_len;
482             cfm.value  = (uint8_t *)(&s_hids_env.output_report_val);
483             break;
484 
485         case HIDS_IDX_OUTPUT_REPORT_REF:
486             cfm.length = sizeof(hids_report_ref_t);
487             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.output_report.ref);
488             break;
489         /*----------------------------------------------------------------------------------*/
490         case HIDS_IDX_FEATURE_REPORT_VAL:
491             cfm.length = s_hids_env.hids_init.feature_report.value_len;
492             cfm.value  = (uint8_t *)(&s_hids_env.feature_report_val);
493             break;
494 
495         case HIDS_IDX_FEATURE_REPORT_REF:
496             cfm.length = sizeof(hids_report_ref_t);
497             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.feature_report.ref);
498             break;
499         /*----------------------------------------------------------------------------------*/
500         case HIDS_IDX_REPORT_MAP_VAL:
501             cfm.length = s_hids_env.hids_init.report_map.len;
502             cfm.value  = (uint8_t *)(s_hids_env.hids_init.report_map.p_map);
503             break;
504         /*----------------------------------------------------------------------------------*/
505         case HIDS_IDX_BOOT_KB_IN_RPT_VAL:
506             cfm.length = HIDS_BOOT_KB_IN_REPORT_MAX_SIZE;
507             cfm.value  = (uint8_t *)(&s_hids_env.kb_input_report_val);
508             break;
509 
510         case HIDS_IDX_BOOT_KB_IN_RPT_CCCD:
511             cfm.length = sizeof(uint16_t);
512             cfm.value  = (uint8_t *)(&s_hids_env.kb_input_cccd[conn_idx]);
513             break;
514         /*----------------------------------------------------------------------------------*/
515         case HIDS_IDX_BOOT_KB_OUT_RPT_VAL:
516             cfm.length = HIDS_IDX_BOOT_KB_IN_RPT_VAL;
517             cfm.value  = (uint8_t *)(&s_hids_env.kb_output_report_val);
518             break;
519         /*----------------------------------------------------------------------------------*/
520         case HIDS_IDX_BOOT_MS_IN_RPT_VAL:
521             cfm.length = HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE;
522             cfm.value  = (uint8_t *)(&s_hids_env.mouse_input_report_val);
523             break;
524         /*----------------------------------------------------------------------------------*/
525         case HIDS_IDX_BOOT_MS_IN_RPT_CCCD:
526             cfm.length = sizeof(uint16_t);
527             cfm.value  = (uint8_t *)&s_hids_env.mouse_input_cccd[conn_idx];
528             break;
529         /*----------------------------------------------------------------------------------*/
530 
531         case HIDS_IDX_HID_INFO_VAL:
532             cfm.length = sizeof(hids_hid_info_t);
533             cfm.value  = (uint8_t *)(&s_hids_env.hids_init.hid_info);
534             break;
535         /*----------------------------------------------------------------------------------*/
536         case HIDS_IDX_CTRL_POINT_VAL:
537             cfm.length = sizeof(uint16_t);
538             cfm.value  = (uint8_t *)(&s_hids_env.ctrl_pt);
539             break;
540         /*----------------------------------------------------------------------------------*/
541         default:
542             cfm.length = 0;
543             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
544             break;
545     }
546     ble_gatts_read_cfm(conn_idx, &cfm);
547 }
548 
549 /**
550  *****************************************************************************************
551  * @brief Check Input Report Characteristic cccd value.
552  *
553  * @param[in] p_evt: Pointer of HID Service event.
554  * @param[in] cccd_value: Cccd value.
555  *****************************************************************************************
556  */
hids_cccd_check(hids_evt_t * p_evt,uint16_t cccd_value)557 static void hids_cccd_check(hids_evt_t *p_evt, uint16_t cccd_value)
558 {
559     p_evt->evt_type = ((cccd_value == PRF_CLI_START_NTF) ?
560                        HIDS_EVT_IN_REP_NOTIFY_ENABLED :
561                        HIDS_EVT_IN_REP_NOTIFY_DISABLED);
562 }
563 
564 /**
565  *****************************************************************************************
566  * @brief Function for handling write events to a cccd value.
567  *
568  * @param[in]   tab_index      CCCD index in DB.
569  * @param[in]   conn_idx       Connect index.
570  * @param[in]   p_evt          Pointer of HID Service event.
571  * @param[in]   cccd_value     CCCD Value.
572  *****************************************************************************************
573  */
hids_on_cccd_write(uint8_t tab_index,uint8_t conn_idx,hids_evt_t * p_evt,uint16_t cccd_value)574 static void hids_on_cccd_write(uint8_t tab_index, uint8_t conn_idx, hids_evt_t *p_evt, uint16_t cccd_value)
575 {
576     switch (tab_index) {
577         case HIDS_IDX_INPUT1_REPORT_CCCD:
578             s_hids_env.input_cccd[INDEX_0][conn_idx] = cccd_value;
579             p_evt->report_type = HIDS_REPORT_TYPE_IN1;
580             hids_cccd_check(p_evt, cccd_value);
581             break;
582 
583         case HIDS_IDX_INPUT2_REPORT_CCCD:
584             s_hids_env.input_cccd[INDEX_1][conn_idx] = cccd_value;
585             p_evt->report_type = HIDS_REPORT_TYPE_IN2;
586             hids_cccd_check(p_evt, cccd_value);
587             break;
588 
589         case HIDS_IDX_INPUT3_REPORT_CCCD:
590             s_hids_env.input_cccd[INDEX_2][conn_idx] = cccd_value;
591             p_evt->report_type = HIDS_REPORT_TYPE_IN3;
592             hids_cccd_check(p_evt, cccd_value);
593             break;
594 
595         case HIDS_IDX_BOOT_KB_IN_RPT_CCCD:
596             s_hids_env.kb_input_cccd[conn_idx] = cccd_value;
597             p_evt->report_type = HIDS_REPORT_TYPE_KB_IN;
598             hids_cccd_check(p_evt, cccd_value);
599             break;
600 
601         case HIDS_IDX_BOOT_MS_IN_RPT_CCCD:
602             s_hids_env.mouse_input_cccd[conn_idx] = cccd_value;
603             p_evt->report_type = HIDS_REPORT_TYPE_MOUSE_IN;
604             hids_cccd_check(p_evt, cccd_value);
605             break;
606 
607         default:
608             break;
609     }
610 }
611 
612 /**
613  *****************************************************************************************
614  * @brief Function for handling write events to the Protocol Mode value.
615  *
616  * @param[in]   p_evt       Pointer of HID Service event.
617  * @param[in]   p_param     Pointer to the parameters of the write request.
618  *****************************************************************************************
619  */
hids_on_protocol_mode_write(hids_evt_t * p_evt,const gatts_write_req_cb_t * p_param)620 static void hids_on_protocol_mode_write(hids_evt_t *p_evt, const gatts_write_req_cb_t *p_param)
621 {
622     if (p_param->length == 1) {
623         switch (p_param->value[INDEX_0]) {
624             case PROTOCOL_MODE_BOOT:
625                 p_evt->evt_type = HIDS_EVT_BOOT_MODE_ENTERED;
626                 break;
627 
628             case PROTOCOL_MODE_REPORT:
629                 p_evt->evt_type = HIDS_EVT_REPORT_MODE_ENTERED;
630                 break;
631 
632             default:
633                 break;
634         }
635         s_hids_env.protocol_mode = p_param->value[INDEX_0];
636     }
637 }
638 
639 /**
640  *****************************************************************************************
641  * @brief Function for handling write events to the HID Control Point value..
642  *
643  * @param[in]   p_evt       Pointer of HID Service event.
644  * @param[in]   p_param     Pointer to the parameters of the write request.
645  *****************************************************************************************
646  */
hids_on_control_point_write(hids_evt_t * p_evt,const gatts_write_req_cb_t * p_param)647 static void hids_on_control_point_write(hids_evt_t *p_evt, const gatts_write_req_cb_t *p_param)
648 {
649     if (p_param->length == 1) {
650         switch (p_param->value[INDEX_0]) {
651             case HIDS_CONTROL_POINT_SUSPEND:
652                 p_evt->evt_type = HIDS_EVT_HOST_SUSP;
653                 break;
654 
655             case HIDS_CONTROL_POINT_EXIT_SUSPEND:
656                 p_evt->evt_type = HIDS_EVT_HOST_EXIT_SUSP;
657                 break;
658 
659             default:
660                 break;
661         }
662         s_hids_env.ctrl_pt = p_param->value[INDEX_0];
663     }
664 }
665 
666 
667 /**
668  *****************************************************************************************
669  * @brief Handles reception of the write request.
670  *
671  * @param[in] conn_idx: Connection index.
672  * @param[in] p_param:  Pointer to the parameters of the write request.
673  *****************************************************************************************
674  */
hids_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)675 static void hids_write_att_cb(uint8_t conn_idx,
676                               const gatts_write_req_cb_t *p_param)
677 {
678     uint16_t handle = p_param->handle;
679     uint8_t tab_index = prf_find_idx_by_handle(handle,
680                         s_hids_env.start_hdl,
681                         HIDS_IDX_NB,
682                         (uint8_t *)&s_hids_env.char_mask);
683     uint16_t          cccd_value;
684     gatts_write_cfm_t cfm;
685     hids_evt_t         evt;
686     uint8_t ret;
687 
688     evt.evt_type = HIDS_EVT_INVALID;
689     evt.offset = p_param->offset;
690     evt.len = p_param->length;
691     evt.data = p_param->value;
692     cfm.handle = handle;
693     cfm.status = BLE_SUCCESS;
694 
695     switch (tab_index) {
696         case HIDS_IDX_PROTOCOL_MODE_VAL:
697             hids_on_protocol_mode_write(&evt, p_param);
698             break;
699 
700         case HIDS_IDX_INPUT1_REPORT_CCCD:
701         case HIDS_IDX_INPUT2_REPORT_CCCD:
702         case HIDS_IDX_INPUT3_REPORT_CCCD:
703         case HIDS_IDX_BOOT_KB_IN_RPT_CCCD:
704         case HIDS_IDX_BOOT_MS_IN_RPT_CCCD:
705             cccd_value = le16toh(&p_param->value[INDEX_0]);
706             hids_on_cccd_write(tab_index, conn_idx, &evt, cccd_value);
707             break;
708 
709         case HIDS_IDX_INPUT1_REPORT_VAL:
710             if ((p_param->offset + p_param->length) <= s_hids_env.hids_init.input_report_array[INDEX_0].value_len) {
711                 ret = memcp_s(&s_hids_env.input_report_val[INDEX_0][p_param->offset], p_param->length,
712                               p_param->value, p_param->length);
713                 if (ret < 0) {
714                     return ret;
715                 }
716                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
717                 evt.report_type = HIDS_REPORT_TYPE_IN1;
718             }
719             break;
720 
721         case HIDS_IDX_INPUT2_REPORT_VAL:
722             if ((p_param->offset + p_param->length) <= s_hids_env.hids_init.input_report_array[INDEX_1].value_len) {
723                 ret = memcpy_s(&s_hids_env.input_report_val[INDEX_1][p_param->offset], p_param->length,
724                                p_param->value, p_param->length);
725                 if (ret < 0) {
726                     return ret;
727                 }
728                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
729                 evt.report_type = HIDS_REPORT_TYPE_IN2;
730             }
731             break;
732 
733         case HIDS_IDX_INPUT3_REPORT_VAL:
734             if ((p_param->offset + p_param->length) <= s_hids_env.hids_init.input_report_array[INDEX_2].value_len) {
735                 ret = memcpy_s(&s_hids_env.input_report_val[INDEX_2][p_param->offset], p_param->length,
736                                p_param->value, p_param->length);
737                 if (ret < 0) {
738                     return ret;
739                 }
740                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
741                 evt.report_type = HIDS_REPORT_TYPE_IN3;
742             }
743             break;
744 
745         case HIDS_IDX_OUTPUT_REPORT_VAL:
746             if ((p_param->offset + p_param->length) <= s_hids_env.hids_init.output_report.value_len) {
747                 ret = memcpy_s(&s_hids_env.output_report_val[p_param->offset], p_param->length,
748                                p_param->value, p_param->length);
749                 if (ret < 0) {
750                     return ret;
751                 }
752                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
753                 evt.report_type = HIDS_REPORT_TYPE_OUT;
754             }
755             break;
756 
757         case HIDS_IDX_FEATURE_REPORT_VAL:
758             if ((p_param->offset + p_param->length) <= s_hids_env.hids_init.feature_report.value_len) {
759                 ret = memcpy_s(&s_hids_env.feature_report_val[p_param->offset], p_param->length,
760                                p_param->value, p_param->length);
761                 if (ret < 0) {
762                     return ret;
763                 }
764                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
765                 evt.report_type = HIDS_REPORT_TYPE_FEATURE;
766             }
767             break;
768 
769         case HIDS_IDX_BOOT_KB_IN_RPT_VAL:
770             if ((p_param->offset + p_param->length) <= HIDS_BOOT_KB_IN_REPORT_MAX_SIZE) {
771                 ret = memcpy_s(&s_hids_env.kb_input_report_val[p_param->offset], p_param->length,
772                                p_param->value, p_param->length);
773                 if (ret < 0) {
774                     return ret;
775                 }
776                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
777                 evt.report_type = HIDS_REPORT_TYPE_KB_IN;
778             }
779             break;
780         case HIDS_IDX_BOOT_KB_OUT_RPT_VAL:
781             if ((p_param->offset + p_param->length) <= HIDS_BOOT_KB_OUT_REPORT_MAX_SIZE) {
782                 ret = memcpy_s(&s_hids_env.kb_output_report_val[p_param->offset], p_param->length,
783                                p_param->value, p_param->length);
784                 if (ret < 0) {
785                     return ret;
786                 }
787                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
788                 evt.report_type = HIDS_REPORT_TYPE_KB_OUT;
789             }
790             break;
791         case HIDS_IDX_BOOT_MS_IN_RPT_VAL:
792             if ((p_param->offset + p_param->length) <= HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE) {
793                 ret = memcpy_s(&s_hids_env.mouse_input_report_val[p_param->offset], p_param->length,
794                                p_param->value, p_param->length);
795                 if (ret < 0) {
796                     return ret;
797                 }
798                 evt.evt_type = HIDS_EVT_REP_CHAR_WRITE;
799                 evt.report_type = HIDS_REPORT_TYPE_MOUSE_IN;
800             }
801             break;
802 
803         case HIDS_IDX_CTRL_POINT_VAL:
804             hids_on_control_point_write(&evt, p_param);
805             break;
806 
807         default:
808             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
809             break;
810     }
811 
812     if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && \
813             HIDS_EVT_INVALID != evt.evt_type && \
814             s_hids_env.hids_init.evt_handler) {
815         evt.conn_idx = conn_idx;
816         s_hids_env.hids_init.evt_handler(&evt);
817     }
818 
819     ble_gatts_write_cfm(conn_idx, &cfm);
820 }
821 
822 
823 /**
824  *****************************************************************************************
825  * @brief Handles reception of the cccd recover request.
826  *
827  * @param[in]: conn_idx:   Connection index
828  * @param[in]: handle:     The handle of cccd attribute.
829  * @param[in]: cccd_value: The value of cccd attribute.
830  *****************************************************************************************
831  */
hids_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)832 static void hids_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
833 {
834     hids_evt_t  evt;
835     evt.evt_type = HIDS_EVT_INVALID;
836     if (!prf_is_cccd_value_valid(cccd_value)) {
837         return;
838     }
839 
840     uint8_t   tab_index = prf_find_idx_by_handle(handle,
841                           s_hids_env.start_hdl,
842                           HIDS_IDX_NB,
843                           (uint8_t *)&s_hids_env.char_mask);
844     hids_on_cccd_write(tab_index, conn_idx, &evt, cccd_value);
845     if (HIDS_EVT_INVALID != evt.evt_type && \
846             s_hids_env.hids_init.evt_handler) {
847         evt.conn_idx = conn_idx;
848         s_hids_env.hids_init.evt_handler(&evt);
849     }
850 }
851 
852 /**
853  *****************************************************************************************
854  * @brief HIDS Characteristic mask init.
855  *
856  * @param[in]: p_hids_init:   Pointer to the hids init.
857  *****************************************************************************************
858  */
hids_char_mask_init(hids_init_t * p_hids_init)859 static void hids_char_mask_init(hids_init_t *p_hids_init)
860 {
861     s_hids_env.char_mask[INDEX_0] = 0x01;
862     s_hids_env.char_mask[INDEX_1] = 0x00;
863     s_hids_env.char_mask[INDEX_2] = 0x60;
864     s_hids_env.char_mask[INDEX_3] = 0x80;
865     s_hids_env.char_mask[INDEX_4] = 0x07;
866     if (p_hids_init->is_kb || p_hids_init->is_mouse) {
867         s_hids_env.char_mask[INDEX_0] |= 0x06;
868         if (p_hids_init->is_kb) {
869             s_hids_env.char_mask[INDEX_2] |= 0x80;
870             s_hids_env.char_mask[INDEX_3] |= 0x0f;
871         }
872         if (p_hids_init->is_mouse) {
873             s_hids_env.char_mask[INDEX_3] |= 0x70;
874         }
875     }
876     switch (p_hids_init->input_report_count) {
877         case REPORT_CNT_0: // do noting
878             break;
879         case REPORT_CNT_1:
880             s_hids_env.char_mask[INDEX_0] |= 0x78;
881             break;
882         case REPORT_CNT_2:
883             s_hids_env.char_mask[INDEX_0] |= 0xf8;
884             s_hids_env.char_mask[INDEX_1] |= 0x07;
885             break;
886         default: // max count is 3
887             s_hids_env.char_mask[INDEX_0] |= 0xf8;
888             s_hids_env.char_mask[INDEX_1] |= 0x7f;
889             break;
890     }
891 
892     if (p_hids_init->out_report_sup) {
893         s_hids_env.char_mask[INDEX_1] |= 0x80;
894         s_hids_env.char_mask[INDEX_2] |= 0x03;
895     }
896 
897     if (p_hids_init->feature_report_sup) {
898         s_hids_env.char_mask[INDEX_2] |= 0x1c;
899     }
900 }
901 
902 /**
903  *****************************************************************************************
904  * @brief Send an input report.
905  *
906  * @param[in] conn_idx: Connection index.
907  * @param[in] char_idx: Input report Characteristic inedx.
908  * @param[in] p_data: Pointer to data to be sent.
909  * @param[in] length: Length of data to be sent.
910  *
911  * @return BLE_SDK_SUCCESS on success, otherwise an error code.
912  *****************************************************************************************
913  */
hids_in_rep_notify(uint8_t conn_idx,uint8_t char_idx,uint8_t * p_data,uint16_t length)914 static sdk_err_t hids_in_rep_notify(uint8_t conn_idx, uint8_t char_idx, uint8_t *p_data, uint16_t length)
915 {
916     sdk_err_t   error_code;
917     gatts_noti_ind_t hids_noti;
918     hids_noti.type   = BLE_GATT_NOTIFICATION;
919     hids_noti.handle = prf_find_handle_by_idx(char_idx,
920                                               s_hids_env.start_hdl,
921                                               (uint8_t *)&s_hids_env.char_mask);
922     hids_noti.length = length;
923     hids_noti.value  = p_data;
924 
925     error_code = ble_gatts_noti_ind(conn_idx, &hids_noti);
926     return error_code;
927 }
928 
929 /*
930  * GLOBAL FUNCTION DEFINITIONS
931  *******************************************************************************
932  */
hids_service_init(hids_init_t * p_hids_init)933 sdk_err_t hids_service_init(hids_init_t *p_hids_init)
934 {
935     sdk_err_t ret;
936     if (p_hids_init == NULL) {
937         return SDK_ERR_POINTER_NULL;
938     }
939     ret = memcpy_s(&s_hids_env.hids_init, sizeof(hids_init_t), p_hids_init, sizeof(hids_init_t));
940     if (ret < 0) {
941         return ret;
942     }
943     hids_char_mask_init(p_hids_init);
944     s_hids_env.protocol_mode = DEFAULT_PROTOCOL_MODE;
945     s_hids_env.ctrl_pt = INITIAL_VALUE_HID_CONTROL_POINT;
946     return ble_server_prf_add(&hids_prf_info);
947 }
948 
949 
hids_input_rep_send(uint8_t conn_idx,uint8_t rep_idx,uint8_t * p_data,uint16_t uint16_t length)950 sdk_err_t hids_input_rep_send(uint8_t conn_idx, uint8_t rep_idx, uint8_t *p_data, uint16_t uint16_t length)
951 {
952     uint16_t len = length;
953     sdk_err_t ret;
954     static const uint8_t char_idx[] = {HIDS_IDX_INPUT1_REPORT_VAL,
955                                        HIDS_IDX_INPUT2_REPORT_VAL, HIDS_IDX_INPUT3_REPORT_VAL};
956     sdk_err_t   error_code = SDK_ERR_NTF_DISABLED;
957     if (rep_idx >= IN_REPORT_MAX_COUNT || p_data == NULL || len == 0) {
958         return SDK_ERR_INVALID_PARAM;
959     }
960     len = ((length > HIDS_REPORT_MAX_SIZE) ? HIDS_REPORT_MAX_SIZE : len);
961     ret = memcpy_s(&s_hids_env.input_report_val[rep_idx], len, p_data, len);
962     if (ret < 0) {
963         return ret;
964     }
965     if (s_hids_env.input_cccd[rep_idx][conn_idx] == PRF_CLI_START_NTF) {
966         error_code = hids_in_rep_notify(conn_idx, char_idx[rep_idx], p_data, len);
967     }
968     return error_code;
969 }
970 
hids_boot_kb_in_rep_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)971 sdk_err_t hids_boot_kb_in_rep_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
972 {
973     sdk_err_t   error_code = SDK_ERR_NTF_DISABLED;
974     uint16_t len = length;
975     if (p_data == NULL || len == 0) {
976         return SDK_ERR_INVALID_PARAM;
977     }
978     len = ((len > HIDS_BOOT_KB_IN_REPORT_MAX_SIZE) ? HIDS_BOOT_KB_IN_REPORT_MAX_SIZE : len);
979     error_code = memcpy_s(&s_hids_env.kb_input_report_val, len, p_data, len);
980     iferror_code < 0) {
981         return error_code;
982     }
983     if (s_hids_env.kb_input_cccd[conn_idx] == PRF_CLI_START_NTF) {
984         error_code = hids_in_rep_notify(conn_idx, HIDS_IDX_BOOT_KB_IN_RPT_VAL, p_data, len);
985     }
986     return error_code;
987 }
988 
989 sdk_err_t hids_boot_mouse_in_rep_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
990 {
991     sdk_err_t   error_code = SDK_ERR_NTF_DISABLED;
992     uint16_t len = length;
993     if (p_data == NULL || length < HIDS_BOOT_MOUSE_IN_REPORT_MIN_SIZE) {
994         return SDK_ERR_INVALID_PARAM;
995     }
996     len = ((len > HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE) ? HIDS_BOOT_MOUSE_IN_REPORT_MAX_SIZE : len);
997     error_code = memcpy_s(&s_hids_env.mouse_input_report_val, len, p_data, len);
998     iferror_code < 0) {
999         return error_code;
1000     }
1001     if (s_hids_env.mouse_input_cccd[conn_idx] == PRF_CLI_START_NTF) {
1002         error_code = hids_in_rep_notify(conn_idx, HIDS_IDX_BOOT_MS_IN_RPT_VAL, p_data, len);
1003     }
1004     return error_code;
1005 }
1006