• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file thscps.c
5  *
6  * @brief Throughput Control Point Service Implementation.
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 <string.h>
43 #include "ble_prf_utils.h"
44 #include "utility.h"
45 #include "app_log.h"
46 #include "thscps.h"
47 
48 #define INDEX_0 0
49 #define INDEX_1 1
50 #define INDEX_2 2
51 #define INDEX_4 4
52 #define INDEX_6 6
53 #define INDEX_7 7
54 #define LEN_3 3
55 /*
56 * DEFINES
57 *****************************************************************************************
58 */
59 #define THSCPS_CTRL_PT_CHARACTERISTIC_UUID        {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
60                                                    0x0A, 0x46, 0x44, 0xD3, 0x02, 0x07, 0xED, 0xA6}
61 #define THSCPS_TEST_SETTING_CHARACTERISTIC_UUID   {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
62                                                    0x0A, 0x46, 0x44, 0xD3, 0x03, 0x07, 0xED, 0xA6}
63 #define THSCPS_TEST_INFO_CHARACTERISTIC_UUID      {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
64                                                    0x0A, 0x46, 0x44, 0xD3, 0x04, 0x07, 0xED, 0xA6}
65 #define THSCPS_CONN_INFO_CHARACTERISTIC_UUID      {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, \
66                                                    0x0A, 0x46, 0x44, 0xD3, 0x05, 0x07, 0xED, 0xA6}
67 
68 /**@brief Macros for conversion of 128bit to 16bit UUID. */
69 #define ATT_128_PRIMARY_SERVICE     BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
70 #define ATT_128_CHARACTERISTIC      BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
71 #define ATT_128_CLIENT_CHAR_CFG     BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
72 
73 /*
74  * ENUMERATIONS
75  *****************************************************************************************
76  */
77 /**@brief THS Control Point Service Attributes Indexes. */
78 enum {
79     // THS Control Point Service
80     THSCPS_IDX_SVC,
81 
82     // THS Control Point
83     THSCPS_IDX_THS_CTRL_PT_CHAR,
84     THSCPS_IDX_THS_CTRL_PT_VAL,
85     THSCPS_IDX_THS_CTRL_PT_CFG,
86 
87     // THS throughput Test Setting
88     THSCPS_IDX_TEST_SETTING_CHAR,
89     THSCPS_IDX_TEST_SETTING_VAL,
90     THSCPS_IDX_TEST_SETTING_CFG,
91 
92     // THS throughput Test Information
93     THSCPS_IDX_TEST_INFO_CHAR,
94     THSCPS_IDX_TEST_INFO_VAL,
95     THSCPS_IDX_TEST_INFO_CFG,
96 
97     // THS throughput Conn Information
98     THSCPS_IDX_CONN_INFO_CHAR,
99     THSCPS_IDX_CONN_INFO_VAL,
100     THSCPS_IDX_CONN_INFO_CFG,
101 
102     THSCPS_IDX_NB
103 };
104 
105 /*
106  * STRUCTURES
107  *****************************************************************************************
108  */
109 /**@brief THS Control Point Service environment variable. */
110 struct thscps_env_t {
111     thscps_evt_handler_t   evt_handler;         /**< THS Control Point Service event handler. */
112     uint16_t               start_hdl;           /**< THS Control Point Service start handle. */
113     thscps_test_role_t     curr_role;           /**< Current test role. */
114     thscps_test_state_t    test_state;          /**< Test is on going or not. */
115     uint16_t
116     ctrl_pt_ind_cfg[THSCPS_CONNECTION_MAX];      /**< The configuration of Control Point Response \
117                                                  which is configured by the peer devices. */
118     uint16_t
119     test_setting_ntf_cfg[THSCPS_CONNECTION_MAX]; /**< The configuration of Test Setting \
120                                                  which is configured by the peer devices. */
121     uint16_t
122     conn_info_ntf_cfg[THSCPS_CONNECTION_MAX];    /**< The configuration of Connection Information \
123                                                  which is configured by the peer devices. */
124     uint16_t
125     test_info_ntf_cfg[THSCPS_CONNECTION_MAX];    /**< The configuration of Test Information \
126                                                  which is configured by the peer devices. */
127 };
128 
129 /*
130  * LOCAL FUNCTION DECLARATION
131  *****************************************************************************************
132  */
133 static sdk_err_t   thscps_init(void);
134 static void        thscps_read_att_cb(uint8_t  conn_idx, const gatts_read_req_cb_t  *p_param);
135 static void        thscps_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
136 static void        thscps_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
137 static void        thscps_ctrl_pt_handler(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
138 static sdk_err_t   thscps_ctrl_pt_fail_rsp_send(uint8_t conn_idx, thscps_ctrl_pt_id_t cmd_id,
139                                                 thscps_status_rsp_t status);
140 
141 /*
142  * LOCAL VARIABLE DEFINITIONS
143  *****************************************************************************************
144  */
145 static struct thscps_env_t s_thscps_env;
146 static uint16_t            s_thscps_char_mask = 0x1fff;
147 /**@brief Full THSCPS Database Description - Used to add attributes into the database. */
148 static const attm_desc_128_t thscps_attr_tab[THSCPS_IDX_NB] = {
149     // THS Control Point Service
150     [THSCPS_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
151 
152     // THS Control Point Characteristic - Declaration
153     [THSCPS_IDX_THS_CTRL_PT_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
154     // THS Control Point Characteristic - Value
155     [THSCPS_IDX_THS_CTRL_PT_VAL]  = {
156         THSCPS_CTRL_PT_CHARACTERISTIC_UUID,
157         WRITE_REQ_PERM_UNSEC | INDICATE_PERM_UNSEC,
158         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
159         THSCPS_CTRL_PT_VAL_LEN
160     },
161     // THS Control Point Characteristic - Client Characteristic Configuration Descriptor
162     [THSCPS_IDX_THS_CTRL_PT_CFG]  = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
163 
164     // THS Test Setting Characteristic - Declaration
165     [THSCPS_IDX_TEST_SETTING_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
166     // THS Test Setting Characteristic - Value
167     [THSCPS_IDX_TEST_SETTING_VAL]  = {
168         THSCPS_TEST_SETTING_CHARACTERISTIC_UUID,
169         WRITE_REQ_PERM_UNSEC | NOTIFY_PERM_UNSEC,
170         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
171         THSCPS_TEST_SETTING_VAL_LEN
172     },
173     // THS Test Setting Characteristic - Client Characteristic Configuration Descriptor
174     [THSCPS_IDX_TEST_SETTING_CFG]  = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
175 
176     // THS Test Information Characteristic - Declaration
177     [THSCPS_IDX_TEST_INFO_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
178     // THS Test Information Characteristic - Value
179     [THSCPS_IDX_TEST_INFO_VAL]  = {
180         THSCPS_TEST_INFO_CHARACTERISTIC_UUID,
181         NOTIFY_PERM_UNSEC,
182         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
183         THSCPS_TEST_INFO_VAL_LEN
184     },
185     // THS Test Information Characteristic - Client Characteristic Configuration Descriptor
186     [THSCPS_IDX_TEST_INFO_CFG]  = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0},
187 
188     // THS Test Connection Characteristic - Declaration
189     [THSCPS_IDX_CONN_INFO_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
190     // THS Test Connection Characteristic - Value
191     [THSCPS_IDX_CONN_INFO_VAL]  = {
192         THSCPS_CONN_INFO_CHARACTERISTIC_UUID,
193         NOTIFY_PERM_UNSEC,
194         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
195         THSCPS_CONN_INFO_VAL_LEN
196     },
197     // THS Test Connection Characteristic - Client Characteristic Configuration Descriptor
198     [THSCPS_IDX_CONN_INFO_CFG]  = {ATT_128_CLIENT_CHAR_CFG, READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC, 0, 0}
199 };
200 
201 /**@brief THSCPS Service interface required by profile manager. */
202 static ble_prf_manager_cbs_t thscps_mgr_cbs = {
203     (prf_init_func_t)thscps_init,
204     NULL,
205     NULL
206 };
207 
208 /**@brief THSCPS GATT Server Callbacks. */
209 static gatts_prf_cbs_t thscps_gatts_cbs = {
210     thscps_read_att_cb,
211     thscps_write_att_cb,
212     NULL,
213     NULL,
214     thscps_cccd_set_cb
215 };
216 
217 /**@brief THSCPS Service Information. */
218 static const prf_server_info_t thscps_prf_info = {
219     .max_connection_nb = THSCPS_CONNECTION_MAX,
220     .manager_cbs       = &thscps_mgr_cbs,
221     .gatts_prf_cbs     = &thscps_gatts_cbs
222 };
223 
224 /*
225  * LOCAL FUNCTION DEFINITIONS
226  *****************************************************************************************
227  */
228 /**
229  *****************************************************************************************
230  * @brief Initialize THS Control Point service and create database in ATT.
231  *
232  * @return Error code to know if profile initialization succeed or not.
233  *****************************************************************************************
234  */
thscps_init(void)235 static sdk_err_t thscps_init(void)
236 {
237     const uint8_t     thscps_svc_uuid[] = {THSCPS_SERVICE_UUID};
238     uint16_t          start_hdl         = PRF_INVALID_HANDLE;
239     sdk_err_t         error_code;
240     gatts_create_db_t gatts_db;
241 
242     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
243     if (error_code < 0) {
244         return error_code;
245     }
246 
247     gatts_db.shdl                  = &start_hdl;
248     gatts_db.uuid                  = thscps_svc_uuid;
249     gatts_db.attr_tab_cfg          = NULL;
250     gatts_db.max_nb_attr           = THSCPS_IDX_NB;
251     gatts_db.srvc_perm             = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
252     gatts_db.attr_tab_type         = SERVICE_TABLE_TYPE_128;
253     gatts_db.attr_tab.attr_tab_128 = thscps_attr_tab;
254 
255     error_code = ble_gatts_srvc_db_create(&gatts_db);
256     if (SDK_SUCCESS == error_code) {
257         s_thscps_env.start_hdl = *gatts_db.shdl;
258     }
259 
260     return error_code;
261 }
262 
263 /**
264  *****************************************************************************************
265  * @brief Handles reception of the attribute info request message.
266  *
267  * @param[in] conn_idx: Connection index.
268  * @param[in] p_param:  Pointer to the parameters of the read request.
269  *****************************************************************************************
270  */
thscps_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)271 static void  thscps_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
272 {
273     gatts_read_cfm_t cfm;
274     uint8_t          handle    = p_param->handle;
275     uint8_t          tab_index = 0;
276 
277     tab_index  = prf_find_idx_by_handle(handle, s_thscps_env.start_hdl, THSCPS_IDX_NB, (uint8_t *)&s_thscps_char_mask);
278     cfm.handle = handle;
279     cfm.status = BLE_SUCCESS;
280 
281     switch (tab_index) {
282         case THSCPS_IDX_THS_CTRL_PT_CFG:
283             cfm.length = sizeof(uint16_t);
284             cfm.value  = (uint8_t *)&s_thscps_env.ctrl_pt_ind_cfg[conn_idx];
285             break;
286 
287         case THSCPS_IDX_TEST_SETTING_CFG:
288             cfm.length = sizeof(uint16_t);
289             cfm.value  = (uint8_t *)&s_thscps_env.test_setting_ntf_cfg[conn_idx];
290             break;
291 
292         case THSCPS_IDX_TEST_INFO_CFG:
293             cfm.length = sizeof(uint16_t);
294             cfm.value  = (uint8_t *)&s_thscps_env.test_info_ntf_cfg[conn_idx];
295             break;
296 
297         case THSCPS_IDX_CONN_INFO_CFG:
298             cfm.length = sizeof(uint16_t);
299             cfm.value  = (uint8_t *)&s_thscps_env.conn_info_ntf_cfg[conn_idx];
300             break;
301 
302         default:
303             cfm.length = 0;
304             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
305             break;
306     }
307 
308     ble_gatts_read_cfm(conn_idx, &cfm);
309 }
310 
311 /**
312  *****************************************************************************************
313  * @brief Handles reception of the write request.
314  *
315  * @param[in] conn_idx: Connection index.
316  * @param[in] p_param:  Pointer to the parameters of the write request.
317  *****************************************************************************************
318  */
thscps_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)319 static void thscps_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
320 {
321     uint8_t              handle           = p_param->handle;
322     uint8_t              tab_index        = 0;
323     uint16_t             cccd_value       = 0;
324     bool                 is_ctrl_pt_wr    = false;
325     thscps_rsp_val_t     rsp_val;
326     thscps_evt_t         event;
327     gatts_write_cfm_t    cfm;
328 
329     tab_index      = prf_find_idx_by_handle(handle, s_thscps_env.start_hdl,
330                                             THSCPS_IDX_NB, (uint8_t *)&s_thscps_char_mask);
331     cfm.handle     = handle;
332     cfm.status     = BLE_SUCCESS;
333     event.conn_idx = conn_idx;
334     event.evt_type = THSCPS_EVT_INVALID;
335 
336     switch (tab_index) {
337         case THSCPS_IDX_THS_CTRL_PT_VAL:
338             is_ctrl_pt_wr = true;
339             break;
340 
341         case THSCPS_IDX_THS_CTRL_PT_CFG:
342             cccd_value = le16toh(&p_param->value[0]);
343             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
344                               THSCPS_EVT_CTRL_PT_IND_ENABLE : \
345                               THSCPS_EVT_CTRL_PT_IND_DISABLE);
346             s_thscps_env.ctrl_pt_ind_cfg[conn_idx] = cccd_value;
347             break;
348 
349         case THSCPS_IDX_TEST_SETTING_VAL:
350             event.evt_type = THSCPS_EVT_SETTING_SET;
351             event.param.setting_info.length = p_param->length;
352             event.param.setting_info.p_data = p_param->value;
353             break;
354 
355         case THSCPS_IDX_TEST_SETTING_CFG:
356             cccd_value = le16toh(&p_param->value[0]);
357             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
358                               THSCPS_EVT_TSET_SET_NTF_ENABLE : \
359                               THSCPS_EVT_TSET_SET_NTF_DISABLE);
360             s_thscps_env.test_setting_ntf_cfg[conn_idx] = cccd_value;
361             break;
362 
363         case THSCPS_IDX_TEST_INFO_CFG:
364             cccd_value = le16toh(&p_param->value[0]);
365             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
366                               THSCPS_EVT_TSET_INFO_NTF_ENABLE : \
367                               THSCPS_EVT_TSET_INFO_NTF_DISABLE);
368             s_thscps_env.test_info_ntf_cfg[conn_idx] = cccd_value;
369             break;
370 
371         case THSCPS_IDX_CONN_INFO_CFG:
372             cccd_value = le16toh(&p_param->value[0]);
373             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
374                               THSCPS_EVT_CONN_INFO_NTF_ENABLE : \
375                               THSCPS_EVT_CONN_INFO_NTF_DISABLE);
376             s_thscps_env.conn_info_ntf_cfg[conn_idx] = cccd_value;
377             break;
378 
379         default:
380             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
381             break;
382     }
383 
384     ble_gatts_write_cfm(conn_idx, &cfm);
385 
386     if (is_ctrl_pt_wr) {
387         thscps_ctrl_pt_handler(conn_idx, p_param);
388     } else if (THSCPS_EVT_SETTING_SET == event.evt_type &&
389                THSCPS_TEST_STARTED == s_thscps_env.test_state &&
390                p_param->value[0] != THSCPS_SETTINGS_TYPE_TOGGLE) {
391         rsp_val.cmd_id       = p_param->value[0];
392         rsp_val.conn_idx     = p_param->value[1];
393         rsp_val.status       = THSCPS_RSP_ID_STATUS_ERR;
394 
395         thscps_test_setting_rsp_send(conn_idx, &rsp_val);
396     } else if (THSCPS_EVT_INVALID != event.evt_type && s_thscps_env.evt_handler) {
397         s_thscps_env.evt_handler(&event);
398     }
399 }
400 
401 /**
402  *****************************************************************************************
403  * @brief Handles reception of the cccd recover request.
404  *
405  * @param[in]: conn_idx:   Connection index
406  * @param[in]: handle:     The handle of cccd attribute.
407  * @param[in]: cccd_value: The value of cccd attribute.
408  *****************************************************************************************
409  */
thscps_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)410 static void thscps_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
411 {
412     uint8_t       tab_index = 0;
413     thscps_evt_t  event;
414 
415     event.conn_idx = conn_idx;
416     event.evt_type = THSCPS_EVT_INVALID;
417 
418     if (!prf_is_cccd_value_valid(cccd_value)) {
419         return;
420     }
421 
422     tab_index  = prf_find_idx_by_handle(handle, s_thscps_env.start_hdl, THSCPS_IDX_NB, (uint8_t *)&s_thscps_char_mask);
423 
424     switch (tab_index) {
425         case THSCPS_IDX_THS_CTRL_PT_CFG:
426             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
427                               THSCPS_EVT_CTRL_PT_IND_ENABLE : \
428                               THSCPS_EVT_CTRL_PT_IND_DISABLE);
429             s_thscps_env.ctrl_pt_ind_cfg[conn_idx] = cccd_value;
430             break;
431 
432         case THSCPS_IDX_TEST_SETTING_CFG:
433             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
434                               THSCPS_EVT_TSET_SET_NTF_ENABLE : \
435                               THSCPS_EVT_TSET_SET_NTF_DISABLE);
436             s_thscps_env.test_setting_ntf_cfg[conn_idx] = cccd_value;
437             break;
438 
439         case THSCPS_IDX_TEST_INFO_CFG:
440             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
441                               THSCPS_EVT_TSET_INFO_NTF_ENABLE : \
442                               THSCPS_EVT_TSET_INFO_NTF_DISABLE);
443             s_thscps_env.test_info_ntf_cfg[conn_idx] = cccd_value;
444             break;
445 
446         case THSCPS_IDX_CONN_INFO_CFG:
447             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
448                               THSCPS_EVT_CONN_INFO_NTF_ENABLE : \
449                               THSCPS_EVT_CONN_INFO_NTF_DISABLE);
450             s_thscps_env.conn_info_ntf_cfg[conn_idx] = cccd_value;
451             break;
452 
453         default:
454             break;
455     }
456 
457     if (s_thscps_env.evt_handler) {
458         s_thscps_env.evt_handler(&event);
459     }
460 }
461 
462 /**
463  *****************************************************************************************
464  * @brief Handle THS Control Point.
465  *
466  * @param[in] conn_idx Connection index.
467  * @param[in] p_param: Pointer to the parameters of the write request.
468  *****************************************************************************************
469  */
thscps_ctrl_pt_handler(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)470 static void thscps_ctrl_pt_handler(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
471 {
472     thscps_evt_t        event;
473     thscps_ctrl_pt_id_t ctrl_pt_id;
474 
475     ctrl_pt_id = (thscps_ctrl_pt_id_t)p_param->value[0];
476 
477     if (THSCPS_TEST_STARTED == s_thscps_env.test_state) {
478         thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_STATUS_ERR);
479         return;
480     }
481 
482     event.conn_idx = conn_idx;
483     event.evt_type = THSCPS_EVT_INVALID;
484 
485     switch (ctrl_pt_id) {
486         case THSCPS_CTRL_PT_TEST_ROLE:
487             if (p_param->value[1] != THSCPS_TEST_ROLE_SLAVE && p_param->value[1] != THSCPS_TEST_ROLE_MASTER) {
488                 thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_PARAM_ERR);
489             } else {
490                 s_thscps_env.curr_role = (thscps_test_role_t)p_param->value[1];
491                 event.evt_type       = THSCPS_EVT_TEST_ROLE_SET;
492                 event.param.test_role = (thscps_test_role_t)p_param->value[1];
493             }
494             break;
495 
496         case THSCPS_CTRL_PT_ADV_PARAM:
497             if (THSCPS_TEST_ROLE_SLAVE == s_thscps_env.curr_role) {
498                 event.evt_type                 = THSCPS_EVT_ADV_PRAM_SET;
499                 event.param.adv_param.phy      = (thscps_adv_phy_t)(p_param->value[1]);
500                 event.param.adv_param.interval = le16toh(&p_param->value[INDEX_2]);
501                 event.param.adv_param.duration = le16toh(&p_param->value[INDEX_4]);
502                 event.param.adv_param.tx_power = p_param->value[INDEX_6] == 1 ? \
503                                                  0 - p_param->value[INDEX_7] : p_param->value[INDEX_7];
504             } else {
505                 thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_TEST_ROLE_ERR);
506             }
507             break;
508 
509         case THSCPS_CTRL_PT_ADV_ACTION:
510             if (THSCPS_TEST_ROLE_SLAVE == s_thscps_env.curr_role) {
511                 event.evt_type         = THSCPS_EVT_ADV_ACTION;
512                 event.param.action_set = p_param->value[1];
513             } else {
514                 thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_TEST_ROLE_ERR);
515             }
516             break;
517 
518         case THSCPS_CTRL_PT_SCAN_ACTION:
519             if (THSCPS_TEST_ROLE_MASTER == s_thscps_env.curr_role) {
520                 event.evt_type         = THSCPS_EVT_SCAN_ACTION;
521                 event.param.action_set = p_param->value[1];
522             } else {
523                 thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_TEST_ROLE_ERR);
524             }
525             break;
526 
527         default:
528             thscps_ctrl_pt_fail_rsp_send(conn_idx, ctrl_pt_id, THSCPS_RSP_ID_UNSUPPORT);
529             break;
530     }
531 
532     if (THSCPS_EVT_INVALID != event.evt_type && s_thscps_env.evt_handler) {
533         s_thscps_env.evt_handler(&event);
534     }
535 }
536 
537 /**
538  *****************************************************************************************
539  * @brief Encode THS Control Point Response value.
540  *
541  * @param[in]  p_rsp_val:      Pointer to Control Point Response value.
542  * @param[out] p_encoded_buff: Pointer to buffer encoded.
543  *
544  * @return Length of encoded
545  *****************************************************************************************
546  */
thscps_ctrl_pt_rsp_encode(thscps_rsp_val_t * p_rsp_val,uint8_t * p_encoded_buff)547 static uint16_t thscps_ctrl_pt_rsp_encode(thscps_rsp_val_t *p_rsp_val, uint8_t *p_encoded_buff)
548 {
549     uint16_t length = 0;
550 
551     p_encoded_buff[length++] = THSCPS_CTRL_PT_RSP_CODE;
552     p_encoded_buff[length++] = p_rsp_val->cmd_id;
553     p_encoded_buff[length++] = p_rsp_val->status;
554 
555     return length;
556 }
557 
558 /**
559  *****************************************************************************************
560  * @brief Encode THS Settings Response value.
561  *
562  * @param[in]  p_rsp_val:      Pointer to Settings Response value.
563  * @param[out] p_encoded_buff: Pointer to buffer encoded.
564  *
565  * @return Length of encoded
566  *****************************************************************************************
567  */
thscps_settings_rsp_encode(thscps_rsp_val_t * p_rsp_val,uint8_t * p_encoded_buff)568 static uint16_t thscps_settings_rsp_encode(thscps_rsp_val_t *p_rsp_val, uint8_t *p_encoded_buff)
569 {
570     uint16_t length = 0;
571 
572     p_encoded_buff[length++] = THSCPS_CTRL_PT_RSP_CODE;
573     p_encoded_buff[length++] = p_rsp_val->cmd_id;
574     p_encoded_buff[length++] = p_rsp_val->conn_idx;
575     p_encoded_buff[length++] = p_rsp_val->status;
576 
577     return length;
578 }
579 
580 /**
581  *****************************************************************************************
582  * @brief Encode THS test information.
583  *
584  * @param[in]  p_ctrl_val_pt:  Pointer to test information.
585  * @param[out] p_encoded_buff: Pointer to buffer encoded.
586  *
587  * @return Length of encoded
588  *****************************************************************************************
589  */
thscps_test_info_encode(thscps_test_info_t * p_test_info,uint8_t * p_encoded_buff)590 static uint16_t thscps_test_info_encode(thscps_test_info_t *p_test_info, uint8_t *p_encoded_buff)
591 {
592     uint16_t length = 0;
593 
594     // RSSI
595     if (p_test_info->rssi > 0) {
596         p_encoded_buff[length++] = 0;
597         p_encoded_buff[length++] = p_test_info->rssi;
598     } else {
599         p_encoded_buff[length++] = 1;
600         p_encoded_buff[length++] = 0 - p_test_info->rssi;
601     }
602 
603     // Right rate
604     p_encoded_buff[length++] = p_test_info->right_rate;
605 
606     // Throughput instant value
607     p_encoded_buff[length++] = LO_U16(p_test_info->instant_val);
608     p_encoded_buff[length++] = HI_U16(p_test_info->instant_val);
609 
610     // Throughput average value
611     p_encoded_buff[length++] = LO_U16(p_test_info->average_val);
612     p_encoded_buff[length++] = HI_U16(p_test_info->average_val);
613 
614     // Total recieved packets value in one second
615     p_encoded_buff[length++] = LO_U16(p_test_info->packets_val);
616     p_encoded_buff[length++] = HI_U16(p_test_info->packets_val);
617 
618     return length;
619 }
620 
621 /**
622  *****************************************************************************************
623  * @brief Encode THS conn information.
624  *
625  * @param[in]  p_ctrl_val_pt:  Pointer to test information.
626  * @param[out] p_encoded_buff: Pointer to buffer encoded.
627  *
628  * @return Length of encoded
629  *****************************************************************************************
630  */
thscps_conn_info_encode(thscps_test_conn_info_t * p_conn_info,uint8_t * p_encoded_buff)631 static uint16_t thscps_conn_info_encode(thscps_test_conn_info_t *p_conn_info, uint8_t *p_encoded_buff)
632 {
633     uint16_t length = 0;
634 
635     // CI
636     p_encoded_buff[length++] = LO_U16(p_conn_info->ci);
637     p_encoded_buff[length++] = HI_U16(p_conn_info->ci);
638 
639     // PDU
640     p_encoded_buff[length++] = LO_U16(p_conn_info->pdu);
641     p_encoded_buff[length++] = HI_U16(p_conn_info->pdu);
642 
643     // MTU
644     p_encoded_buff[length++] = LO_U16(p_conn_info->mtu);
645     p_encoded_buff[length++] = HI_U16(p_conn_info->mtu);
646 
647     // PHY
648     p_encoded_buff[length++] = p_conn_info->tx_phy;
649     p_encoded_buff[length++] = p_conn_info->rx_phy;
650 
651     // TX POWER
652     if (p_conn_info->tx_power > 0) {
653         p_encoded_buff[length++] = 0;
654         p_encoded_buff[length++] = p_conn_info->tx_power;
655     } else {
656         p_encoded_buff[length++] = 1;
657         p_encoded_buff[length++] = 0 - p_conn_info->tx_power;
658     }
659 
660     // THS Mode
661     p_encoded_buff[length++] = p_conn_info->ths_mode;
662 
663     return length;
664 }
665 
666 /**
667  *****************************************************************************************
668  * @brief Send Control Point Fail Response if its indicaiton has been enabled.
669  *
670  * @param[in] conn_idx:  Connnection index.
671 * @param[in] cmd_id:     Control Point ID.
672  * @param[in] status:    Status response ID.
673  *
674  * @return Result of indicate value
675  *****************************************************************************************
676  */
thscps_ctrl_pt_fail_rsp_send(uint8_t conn_idx,thscps_ctrl_pt_id_t cmd_id,thscps_status_rsp_t status)677 static sdk_err_t thscps_ctrl_pt_fail_rsp_send(uint8_t conn_idx, thscps_ctrl_pt_id_t cmd_id, thscps_status_rsp_t status)
678 {
679     uint8_t          encoded_ctrl_pt_rsp[3];
680     gatts_noti_ind_t ctrl_pt_rsp_ind;
681 
682     encoded_ctrl_pt_rsp[INDEX_0] = THSCPS_CTRL_PT_RSP_CODE;
683     encoded_ctrl_pt_rsp[INDEX_1] = cmd_id;
684     encoded_ctrl_pt_rsp[INDEX_2] = status;
685 
686     if (PRF_CLI_START_IND == s_thscps_env.ctrl_pt_ind_cfg[conn_idx]) {
687         ctrl_pt_rsp_ind.type    = BLE_GATT_INDICATION;
688         ctrl_pt_rsp_ind.handle  = prf_find_handle_by_idx(THSCPS_IDX_THS_CTRL_PT_VAL,
689                                                          s_thscps_env.start_hdl,
690                                                          (uint8_t *)&s_thscps_char_mask);
691         ctrl_pt_rsp_ind.length  = LEN_3;
692         ctrl_pt_rsp_ind.value   = encoded_ctrl_pt_rsp;
693 
694         return ble_gatts_noti_ind(conn_idx, &ctrl_pt_rsp_ind);
695     }
696 
697     return SDK_ERR_IND_DISABLED;
698 }
699 
700 /*
701  * GLOBAL FUNCTION DEFINITIONS
702  *****************************************************************************************
703  */
thscps_ctrl_pt_rsp_send(uint8_t conn_idx,thscps_rsp_val_t * p_rsp_val)704 sdk_err_t thscps_ctrl_pt_rsp_send(uint8_t conn_idx, thscps_rsp_val_t *p_rsp_val)
705 {
706     uint8_t          encoded_ctrl_pt_rsp[THSCPS_CTRL_PT_VAL_LEN];
707     gatts_noti_ind_t ctrl_pt_rsp_ind;
708     uint16_t         encoded_length;
709 
710     encoded_length =thscps_ctrl_pt_rsp_encode(p_rsp_val, encoded_ctrl_pt_rsp);
711 
712     if (PRF_CLI_START_IND == s_thscps_env.ctrl_pt_ind_cfg[conn_idx]) {
713         ctrl_pt_rsp_ind.type    = BLE_GATT_INDICATION;
714         ctrl_pt_rsp_ind.handle  = prf_find_handle_by_idx(THSCPS_IDX_THS_CTRL_PT_VAL,
715                                                          s_thscps_env.start_hdl,
716                                                          (uint8_t *)&s_thscps_char_mask);
717         ctrl_pt_rsp_ind.length  = encoded_length;
718         ctrl_pt_rsp_ind.value   = encoded_ctrl_pt_rsp;
719 
720         return ble_gatts_noti_ind(conn_idx, &ctrl_pt_rsp_ind);
721     }
722 
723     return SDK_ERR_IND_DISABLED;
724 }
725 
thscps_test_setting_rsp_send(uint8_t conn_idx,thscps_rsp_val_t * p_rsp_val)726 sdk_err_t thscps_test_setting_rsp_send(uint8_t conn_idx, thscps_rsp_val_t *p_rsp_val)
727 {
728     uint8_t          encoded_rsp[THSCPS_CTRL_PT_VAL_LEN];
729     gatts_noti_ind_t test_setting_rsp_ntf;
730     uint16_t         encoded_length;
731 
732     encoded_length =thscps_settings_rsp_encode(p_rsp_val, encoded_rsp);
733 
734     if (PRF_CLI_START_NTF == s_thscps_env.test_setting_ntf_cfg[conn_idx]) {
735         test_setting_rsp_ntf.type    = BLE_GATT_NOTIFICATION;
736         test_setting_rsp_ntf.handle  = prf_find_handle_by_idx(THSCPS_IDX_TEST_SETTING_VAL,
737                                                               s_thscps_env.start_hdl,
738                                                               (uint8_t *)&s_thscps_char_mask);
739         test_setting_rsp_ntf.length  = encoded_length;
740         test_setting_rsp_ntf.value   = encoded_rsp;
741 
742         return ble_gatts_noti_ind(conn_idx, &test_setting_rsp_ntf);
743     }
744 
745     return SDK_ERR_NTF_DISABLED;
746 }
747 
thscps_test_info_send(uint8_t conn_idx,thscps_test_info_t * p_test_info)748 sdk_err_t thscps_test_info_send(uint8_t conn_idx, thscps_test_info_t *p_test_info)
749 {
750     uint8_t          encoded_test_info[THSCPS_TEST_INFO_VAL_LEN];
751     gatts_noti_ind_t test_info_ntf;
752     uint16_t         encoded_length;
753 
754     encoded_length = thscps_test_info_encode(p_test_info, encoded_test_info);
755 
756     if (PRF_CLI_START_NTF == s_thscps_env.test_info_ntf_cfg[conn_idx]) {
757         test_info_ntf.type    = BLE_GATT_NOTIFICATION;
758         test_info_ntf.handle  = prf_find_handle_by_idx(THSCPS_IDX_TEST_INFO_VAL,
759                                                        s_thscps_env.start_hdl,
760                                                        (uint8_t *)&s_thscps_char_mask);
761         test_info_ntf.length  = encoded_length;
762         test_info_ntf.value   = encoded_test_info;
763 
764         return ble_gatts_noti_ind(conn_idx, &test_info_ntf);
765     }
766 
767     return SDK_ERR_NTF_DISABLED;
768 }
769 
thscps_conn_info_send(uint8_t conn_idx,thscps_test_conn_info_t * p_conn_info)770 sdk_err_t thscps_conn_info_send(uint8_t conn_idx, thscps_test_conn_info_t *p_conn_info)
771 {
772     uint8_t          encoded_conn_info[THSCPS_CONN_INFO_VAL_LEN];
773     gatts_noti_ind_t test_info_ntf;
774     uint16_t         encoded_length;
775 
776     encoded_length = thscps_conn_info_encode(p_conn_info, encoded_conn_info);
777 
778     if (PRF_CLI_START_NTF == s_thscps_env.conn_info_ntf_cfg[conn_idx]) {
779         test_info_ntf.type    = BLE_GATT_NOTIFICATION;
780         test_info_ntf.handle  = prf_find_handle_by_idx(THSCPS_IDX_CONN_INFO_VAL,
781                                                        s_thscps_env.start_hdl,
782                                                        (uint8_t *)&s_thscps_char_mask);
783         test_info_ntf.length  = encoded_length;
784         test_info_ntf.value   = encoded_conn_info;
785 
786         return ble_gatts_noti_ind(conn_idx, &test_info_ntf);
787     }
788 
789     return SDK_ERR_NTF_DISABLED;
790 }
791 
thscps_service_init(thscps_evt_handler_t evt_handler)792 sdk_err_t thscps_service_init(thscps_evt_handler_t evt_handler)
793 {
794     s_thscps_env.evt_handler = evt_handler;
795 
796     return ble_server_prf_add(&thscps_prf_info);
797 }
798 
thscps_test_state_set(thscps_test_state_t test_state)799 void thscps_test_state_set(thscps_test_state_t test_state)
800 {
801     s_thscps_env.test_state = test_state;
802 }
803 
804