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