1 /**
2 *****************************************************************************************
3 *
4 * @file rscs.c
5 *
6 * @brief Running Speed and Cadence Profile Sensor 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 "rscs.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #define INDEX_2
47 /*
48 * ENUMERATIONS
49 *****************************************************************************************
50 */
51 /**@brief Running Speed and Cadence Service Attributes Indexes. */
52 enum {
53 RSCS_IDX_SVC,
54
55 RSCS_IDX_RSC_MEAS_CHAR,
56 RSCS_IDX_RSC_MEAS_VAL,
57 RSCS_IDX_RSC_MEAS_NTF_CFG,
58
59 RSCS_IDX_RSC_FEAT_CHAR,
60 RSCS_IDX_RSC_FEAT_VAL,
61
62 RSCS_IDX_SENSOR_LOC_CHAR,
63 RSCS_IDX_SENSOR_LOC_VAL,
64
65 RSCS_IDX_CTRL_POINT_CHAR,
66 RSCS_IDX_CTRL_POINT_VAL,
67 RSCS_IDX_CTRL_POINT_IND_CFG,
68
69 RSCS_IDX_NB
70 };
71
72 /*
73 * STRUCTURES
74 *****************************************************************************************
75 */
76 /**@brief Running Speed and Cadence Service environment variable. */
77 struct rscs_env_t {
78 rscs_init_t
79 rscs_init; /**< Running Speed and Cadence Service initialization variables. */
80 uint16_t start_hdl; /**< Running Speed and Cadence Service start handle. */
81 bool
82 ctrl_pt_op_in_progress; /**< A previously triggered SC Control Point operation is still in progress. */
83 bool
84 ctrl_pt_op_rsp_cplt; /**< A previously triggered SC Control Point operation response cplt. */
85 uint16_t
86 meas_ntf_cfg[RSCS_CONNECTION_MAX]; /**< The configuration of RCS Measurement Notification
87 which is configured by the peer devices. */
88 uint16_t
89 ctrl_point_ind_cfg[RSCS_CONNECTION_MAX]; /**< The configuration of SC Control Point Notification
90 which is configured by the peer devices. */
91 };
92
93 /*
94 * LOCAL FUNCTION DECLARATION
95 *****************************************************************************************
96 */
97 static sdk_err_t rscs_init(void);
98 static void rscs_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
99 static void rscs_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
100 static void rscs_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
101 static void rscs_disconnect_cb(uint8_t conn_idx, uint8_t reason);
102 static void rscs_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
103 static void rscs_sc_ctrl_pt_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length);
104
105 /*
106 * LOCAL VARIABLE DEFINITIONS
107 *****************************************************************************************
108 */
109 static struct rscs_env_t s_rscs_env;
110
111 /**@brief Full RSCS Database Description - Used to add attributes into the database. */
112 static const attm_desc_t rscs_attr_tab[RSCS_IDX_NB] = {
113 // Running Speed and Cadence Service Declaration
114 [RSCS_IDX_SVC] = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
115
116 // RSC Measurement Characteristic - Declaration
117 [RSCS_IDX_RSC_MEAS_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
118 // RSC Measurement Characteristic - Value
119 [RSCS_IDX_RSC_MEAS_VAL] = {
120 BLE_ATT_CHAR_RSC_MEAS,
121 NOTIFY_PERM_UNSEC,
122 ATT_VAL_LOC_USER,
123 RSCS_MEAS_VAL_LEN_MAX
124 },
125 // RSC Measurement Characteristic - Client Characteristic Configuration Descriptor
126 [RSCS_IDX_RSC_MEAS_NTF_CFG] = {
127 BLE_ATT_DESC_CLIENT_CHAR_CFG,
128 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
129 0,
130 0
131 },
132
133 // RSC Feature Characteristic - Declaration
134 [RSCS_IDX_RSC_FEAT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
135 // RSC Feature Characteristic - Value
136 [RSCS_IDX_RSC_FEAT_VAL] = {
137 BLE_ATT_CHAR_RSC_FEAT,
138 READ_PERM_UNSEC,
139 ATT_VAL_LOC_USER,
140 RSCS_FEAT_VAL_LEN_MAX
141 },
142
143 // Sensor Location Characteristic - Declaration
144 [RSCS_IDX_SENSOR_LOC_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
145 // Sensor Location Characteristic - Value
146 [RSCS_IDX_SENSOR_LOC_VAL] = {
147 BLE_ATT_CHAR_SENSOR_LOC,
148 READ_PERM_UNSEC,
149 ATT_VAL_LOC_USER,
150 RSCS_SENSOR_LOC_VAL_LEN_MAX
151 },
152
153 // SC Control Point Characteristic - Declaration
154 [RSCS_IDX_CTRL_POINT_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
155 // SC Control Point Characteristic - Value
156 [RSCS_IDX_CTRL_POINT_VAL] = {
157 BLE_ATT_CHAR_SC_CNTL_PT,
158 WRITE_REQ_PERM_UNSEC | INDICATE_PERM_UNSEC,
159 ATT_VAL_LOC_USER,
160 RSCS_CTRL_PT_VAL_LEN_MAX
161 },
162 // SC Control Point Characteristic - Client Characteristic Configuration Descriptor
163 [RSCS_IDX_CTRL_POINT_IND_CFG] = {
164 BLE_ATT_DESC_CLIENT_CHAR_CFG,
165 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
166 0,
167 0
168 },
169 };
170
171 /**@brief RSCS Task interface required by profile manager. */
172 static ble_prf_manager_cbs_t rscs_task_cbs = {
173 (prf_init_func_t) rscs_init,
174 NULL,
175 rscs_disconnect_cb,
176 };
177
178 /**@brief RSCS Task Callbacks. */
179 static gatts_prf_cbs_t rscs_cb_func = {
180 rscs_read_att_cb,
181 rscs_write_att_cb,
182 NULL,
183 rscs_ntf_ind_cb,
184 rscs_cccd_set_cb
185 };
186
187 /**@brief RSCS Information. */
188 static const prf_server_info_t rscs_prf_info = {
189 .max_connection_nb = RSCS_CONNECTION_MAX,
190 .manager_cbs = &rscs_task_cbs,
191 .gatts_prf_cbs = &rscs_cb_func,
192 };
193
194 /*
195 * LOCAL FUNCTION DEFINITIONS
196 *****************************************************************************************
197 */
198 /**
199 *****************************************************************************************
200 * @brief Initialize Running Speed and Cadence service create db in att
201 *
202 * @return Error code to know if profile initialization succeed or not.
203 *****************************************************************************************
204 */
rscs_init(void)205 static sdk_err_t rscs_init(void)
206 {
207 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
208 uint16_t start_hdl = PRF_INVALID_HANDLE;
209 const uint8_t rscs_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_RUNNING_SPEED_CADENCE);
210 sdk_err_t error_code;
211 gatts_create_db_t gatts_db;
212
213 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
214 if (error_code < 0) {
215 return error_code;
216 }
217
218 gatts_db.shdl = &start_hdl;
219 gatts_db.uuid = rscs_svc_uuid;
220 gatts_db.attr_tab_cfg = (uint8_t *)&(s_rscs_env.rscs_init.char_mask);
221 gatts_db.max_nb_attr = RSCS_IDX_NB;
222 gatts_db.srvc_perm = 0;
223 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_16;
224 gatts_db.attr_tab.attr_tab_16 = rscs_attr_tab;
225
226 error_code = ble_gatts_srvc_db_create(&gatts_db);
227 if (SDK_SUCCESS == error_code) {
228 s_rscs_env.start_hdl = *gatts_db.shdl;
229 }
230
231 return error_code;
232 }
233
234 /**
235 *****************************************************************************************
236 * @brief Handles reception of the attribute info request message.
237 *
238 * @param[in] conn_idx: Connection index
239 * @param[in] p_param: The parameters of the read request.
240 *****************************************************************************************
241 */
rscs_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)242 static void rscs_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
243 {
244 gatts_read_cfm_t cfm;
245 uint8_t handle = p_param->handle;
246 uint8_t tab_index = prf_find_idx_by_handle(handle,
247 s_rscs_env.start_hdl,
248 RSCS_IDX_NB,
249 (uint8_t *)&s_rscs_env.rscs_init.char_mask);
250 cfm.handle = handle;
251 cfm.status = BLE_SUCCESS;
252
253 switch (tab_index) {
254 case RSCS_IDX_RSC_MEAS_NTF_CFG:
255 cfm.length = sizeof(uint16_t);
256 cfm.value = (uint8_t *)&s_rscs_env.meas_ntf_cfg[conn_idx];
257 break;
258
259 case RSCS_IDX_RSC_FEAT_VAL:
260 cfm.length = sizeof(uint16_t);
261 cfm.value = (uint8_t *)&s_rscs_env.rscs_init.feature;
262 break;
263
264 case RSCS_IDX_SENSOR_LOC_VAL:
265 cfm.length = sizeof(uint8_t);
266 cfm.value = (uint8_t *)&s_rscs_env.rscs_init.sensor_location;
267 break;
268
269 case RSCS_IDX_CTRL_POINT_IND_CFG:
270 cfm.length = sizeof(uint16_t);
271 cfm.value = (uint8_t *)&s_rscs_env.ctrl_point_ind_cfg[conn_idx];
272 break;
273
274 default:
275 cfm.length = 0;
276 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
277 break;
278 }
279
280 ble_gatts_read_cfm(conn_idx, &cfm);
281 }
282
283 /**
284 *****************************************************************************************
285 * @brief Handles reception of the write request.
286 *
287 * @param[in]: conn_idx: Connection index
288 * @param[in]: p_param: The parameters of the write request.
289 *****************************************************************************************
290 */
rscs_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)291 static void rscs_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
292 {
293 uint16_t handle = p_param->handle;
294 uint16_t tab_index = 0;
295 uint16_t cccd_value = 0;
296 bool ctrl_pt_evt = false;
297 rscs_evt_t event;
298 gatts_write_cfm_t cfm;
299
300 tab_index = prf_find_idx_by_handle(handle,
301 s_rscs_env.start_hdl,
302 RSCS_IDX_NB,
303 (uint8_t *)&s_rscs_env.rscs_init.char_mask);
304 cfm.handle = handle;
305 cfm.status = BLE_SUCCESS;
306 event.evt_type = RSCS_EVT_INVALID;
307 event.conn_idx = conn_idx;
308
309 switch (tab_index) {
310 case RSCS_IDX_RSC_MEAS_NTF_CFG:
311 cccd_value = le16toh(&p_param->value[0]);
312 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
313 RSCS_EVT_RSC_MEAS_NOTIFICATION_ENABLE :\
314 RSCS_EVT_RSC_MEAS_NOTIFICATION_DISABLE);
315 s_rscs_env.meas_ntf_cfg[conn_idx] = cccd_value;
316 break;
317
318 case RSCS_IDX_CTRL_POINT_VAL:
319 if (PRF_CLI_START_IND != s_rscs_env.ctrl_point_ind_cfg[conn_idx]) {
320 cfm.status = RSCS_ERROR_CCCD_INVALID;
321 break;
322 } else if (s_rscs_env.ctrl_pt_op_in_progress) {
323 cfm.status = RSCS_ERROR_PROC_IN_PROGRESS;
324 } else if (PRF_CLI_START_IND == s_rscs_env.ctrl_point_ind_cfg[conn_idx]) {
325 s_rscs_env.ctrl_pt_op_in_progress = true;
326 ctrl_pt_evt = true;
327 }
328 break;
329
330 case RSCS_IDX_CTRL_POINT_IND_CFG:
331 cccd_value = le16toh(&p_param->value[0]);
332 event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
333 RSCS_EVT_CTRL_POINT_INDICATION_ENABLE :\
334 RSCS_EVT_CTRL_POINT_INDICATION_DISABLE);
335 s_rscs_env.ctrl_point_ind_cfg[conn_idx] = cccd_value;
336 break;
337
338 default:
339 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
340 break;
341 }
342
343 ble_gatts_write_cfm(conn_idx, &cfm);
344
345 if (ctrl_pt_evt) {
346 rscs_sc_ctrl_pt_handler(conn_idx, p_param->value, p_param->length);
347 } else if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && RSCS_EVT_INVALID != event.evt_type
348 && s_rscs_env.rscs_init.evt_handler) {
349 s_rscs_env.rscs_init.evt_handler(&event);
350 }
351 }
352
353 /**
354 *****************************************************************************************
355 * @brief Handles reception of the cccd recover request.
356 *
357 * @param[in]: conn_idx: Connection index
358 * @param[in]: handle: The handle of cccd attribute.
359 * @param[in]: cccd_value: The value of cccd attribute.
360 *****************************************************************************************
361 */
rscs_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)362 static void rscs_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
363 {
364 uint16_t tab_index = 0;
365 rscs_evt_t event;
366
367 if (!prf_is_cccd_value_valid(cccd_value)) {
368 return;
369 }
370
371 tab_index = prf_find_idx_by_handle(handle,
372 s_rscs_env.start_hdl,
373 RSCS_IDX_NB,
374 (uint8_t *)&s_rscs_env.rscs_init.char_mask);
375
376 event.evt_type = RSCS_EVT_INVALID;
377 event.conn_idx = conn_idx;
378
379 switch (tab_index) {
380 case RSCS_IDX_RSC_MEAS_NTF_CFG:
381 event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
382 RSCS_EVT_RSC_MEAS_NOTIFICATION_ENABLE :\
383 RSCS_EVT_RSC_MEAS_NOTIFICATION_DISABLE);
384 s_rscs_env.meas_ntf_cfg[conn_idx] = cccd_value;
385 break;
386
387 case RSCS_IDX_CTRL_POINT_IND_CFG:
388 event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
389 RSCS_EVT_CTRL_POINT_INDICATION_ENABLE :\
390 RSCS_EVT_CTRL_POINT_INDICATION_DISABLE);
391 s_rscs_env.ctrl_point_ind_cfg[conn_idx] = cccd_value;
392 break;
393
394 default:
395 break;
396 }
397
398 if (RSCS_EVT_INVALID != event.evt_type && s_rscs_env.rscs_init.evt_handler) {
399 s_rscs_env.rscs_init.evt_handler(&event);
400 }
401 }
402
403 /**
404 *****************************************************************************************
405 * @brief Handles reception of the complete event.
406 *
407 * @param[in] conn_idx: Connection index.
408 * @param[in] status: The status of GATTC operation.
409 * @param[in] p_ntf_ind: Pointer to the parameters of the complete event.
410 *****************************************************************************************
411 */
rscs_ntf_ind_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)412 static void rscs_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
413 {
414 rscs_evt_t event;
415
416 event.evt_type = RSCS_EVT_INVALID;
417 event.conn_idx = conn_idx;
418
419 if (s_rscs_env.rscs_init.evt_handler && SDK_SUCCESS == status) {
420 if (BLE_GATT_NOTIFICATION == p_ntf_ind->type) {
421 event.evt_type = RSCS_EVT_RSC_MEAS_SEND_CPLT;
422 } else if (BLE_GATT_INDICATION == p_ntf_ind->type) {
423 event.evt_type = RSCS_EVT_CTRL_POINT_RSP_CPLT;
424 s_rscs_env.ctrl_pt_op_in_progress = false;
425 }
426 s_rscs_env.rscs_init.evt_handler(&event);
427 }
428 }
429
430 /**
431 *****************************************************************************************
432 * @brief SC Control Point Set Cumulative value handler.
433 *
434 * @param[in] conn_idx: Connection index.
435 * @param[in] p_data: Pointer to data.
436 * @param[in] length: Length of data.
437 *****************************************************************************************
438 */
rscs_op_set_cumulative_handler(uint8_t conn_idx,const uint8_t * p_data,uint16_t length)439 static void rscs_op_set_cumulative_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length)
440 {
441 rscs_evt_t event;
442 uint8_t rsp[RSCS_CTRL_PT_RSP_LEN_MIN];
443
444 rsp[INDEX_0] = RSCS_CTRL_PT_OP_RSP_CODE;
445 rsp[INDEX_1] = RSCS_CTRL_PT_OP_SET_CUMUL_VAL;
446 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_FAILED;
447
448 if ((sizeof(uint32_t) == length) && \
449 (s_rscs_env.rscs_init.feature & RSCS_FEAT_TOTAL_DISTANCE_BIT) && \
450 (s_rscs_env.rscs_init.evt_handler)) {
451 event.conn_idx = conn_idx;
452 event.evt_type = RSCS_EVT_CUMUL_VAL_SET;
453 event.p_data = p_data;
454 event.length = length;
455 s_rscs_env.rscs_init.evt_handler(&event);
456 } else {
457 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
458 }
459 }
460
461 /**
462 *****************************************************************************************
463 * @brief SC Control Point Start Calibration handler.
464 *
465 * @param[in] conn_idx: Connection index.
466 *****************************************************************************************
467 */
rscs_op_start_calibration_handler(uint8_t conn_idx)468 static void rscs_op_start_calibration_handler(uint8_t conn_idx)
469 {
470 rscs_evt_t event;
471 uint8_t rsp[RSCS_CTRL_PT_RSP_LEN_MIN];
472
473 rsp[INDEX_0] = RSCS_CTRL_PT_OP_RSP_CODE;
474 rsp[INDEX_1] = RSCS_CTRL_PT_OP_START_CALIB;
475 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_FAILED;
476
477 if ((s_rscs_env.rscs_init.feature & RSCS_FEAT_CALIBRATION_PROCEDURE_BIT) && s_rscs_env.rscs_init.evt_handler) {
478 event.conn_idx = conn_idx;
479 event.evt_type = RSCS_EVT_SEBSOR_CALIBRATION;
480 s_rscs_env.rscs_init.evt_handler(&event);
481 } else {
482 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
483 }
484 }
485
486 /**
487 *****************************************************************************************
488 * @brief SC Control Point Sensor Location update handler.
489 *
490 * @param[in] conn_idx: Connection index.
491 * @param[in] p_data: Pointer to data.
492 * @param[in] length: Length of data.
493 *****************************************************************************************
494 */
rscs_op_sensor_loc_update_handler(uint8_t conn_idx,const uint8_t * p_data,uint16_t length)495 static void rscs_op_sensor_loc_update_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length)
496 {
497 rscs_evt_t event;
498 uint8_t rsp[RSCS_CTRL_PT_RSP_LEN_MIN];
499
500 rsp[INDEX_0] = RSCS_CTRL_PT_OP_RSP_CODE;
501 rsp[INDEX_1] = RSCS_CTRL_PT_OP_UPD_LOC;
502
503 if (RSCS_SENSOR_LOC_SUP_NB <= p_data[0] || sizeof(uint8_t) != length) {
504 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_INVALID_PARAM;
505 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
506 } else if ((s_rscs_env.rscs_init.feature & RSCS_FEAT_MULTIPLE_SENSORS_BIT) && s_rscs_env.rscs_init.evt_handler) {
507 event.conn_idx = conn_idx;
508 event.evt_type = RSCS_EVT_SEBSOR_LOC_UPD;
509 event.p_data = p_data;
510 event.length = length;
511 s_rscs_env.rscs_init.evt_handler(&event);
512 } else {
513 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_FAILED;
514 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
515 }
516 }
517
518 /**
519 *****************************************************************************************
520 * @brief SC Control Point Suppoted Sensor Location list request handler.
521 *
522 * @param[in] conn_idx: Connection index.
523 *****************************************************************************************
524 */
rscs_op_sup_sensor_loc_req_handler(uint8_t conn_idx)525 static void rscs_op_sup_sensor_loc_req_handler(uint8_t conn_idx)
526 {
527 rscs_evt_t event;
528 uint8_t rsp[RSCS_CTRL_PT_RSP_LEN_MIN + RSCS_SENSOR_LOC_SUP_NB];
529 uint8_t rsp_idx = RSCS_CTRL_PT_RSP_LEN_MIN;
530
531 rsp[INDEX_0] = RSCS_CTRL_PT_OP_RSP_CODE;
532 rsp[INDEX_1] = RSCS_CTRL_PT_OP_REQ_SUP_LOC;
533 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_SUCCESS;
534
535 if (s_rscs_env.rscs_init.feature & RSCS_FEAT_MULTIPLE_SENSORS_BIT) {
536 event.conn_idx = conn_idx;
537 event.evt_type = RSCS_EVT_SUP_SEBSOR_LOC_REQ;
538
539 if (s_rscs_env.rscs_init.evt_handler) {
540 s_rscs_env.rscs_init.evt_handler(&event);
541 }
542
543 for (uint8_t i = 0; i < RSCS_SENSOR_LOC_SUP_NB; i++) {
544 rsp[rsp_idx++] = i;
545 }
546 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN + RSCS_SENSOR_LOC_SUP_NB);
547 } else {
548 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_FAILED;
549 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
550 }
551 }
552
553 /**
554 *****************************************************************************************
555 * @brief Handles reception of the disconnection event.
556 *
557 * @param[in] conn_idx: Connection index.
558 * @param[in] reason: Reason of disconnection.
559 *****************************************************************************************
560 */
rscs_disconnect_cb(uint8_t conn_idx,uint8_t reason)561 static void rscs_disconnect_cb(uint8_t conn_idx, uint8_t reason)
562 {
563 s_rscs_env.ctrl_pt_op_in_progress = false;
564 }
565
566 /**
567 *****************************************************************************************
568 * @brief SC Control Point handler.
569 *
570 * @param[in] conn_idx: Connection index.
571 * @param[in] p_data: Pointer to data.
572 * @param[in] length: Length of data.
573 *****************************************************************************************
574 */
rscs_sc_ctrl_pt_handler(uint8_t conn_idx,const uint8_t * p_data,uint16_t length)575 static void rscs_sc_ctrl_pt_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length)
576 {
577 uint8_t rsp[RSCS_CTRL_PT_RSP_LEN_MIN];
578
579 switch (p_data[0]) {
580 case RSCS_CTRL_PT_OP_SET_CUMUL_VAL:
581 rscs_op_set_cumulative_handler(conn_idx, &p_data[1], length - 1);
582 break;
583
584 case RSCS_CTRL_PT_OP_START_CALIB:
585 rscs_op_start_calibration_handler(conn_idx);
586 break;
587
588 case RSCS_CTRL_PT_OP_UPD_LOC:
589 rscs_op_sensor_loc_update_handler(conn_idx, &p_data[1], length - 1);
590 break;
591
592 case RSCS_CTRL_PT_OP_REQ_SUP_LOC:
593 rscs_op_sup_sensor_loc_req_handler(conn_idx);
594 break;
595
596 default:
597 rsp[INDEX_0] = RSCS_CTRL_PT_OP_RSP_CODE;
598 rsp[INDEX_1] = p_data[0];
599 rsp[INDEX_2] = RSCS_CTRL_PT_RSP_NOT_SUP;
600 rscs_ctrl_pt_rsp_send(conn_idx, rsp, RSCS_CTRL_PT_RSP_LEN_MIN);
601 break;
602 }
603 }
604
605 /**
606 *****************************************************************************************
607 * @brief Encoding a RSC Measurement.
608 *
609 * @param[in] p_meas: Pointer to RSC measurement value to be encoded.
610 * @param[out] p_encoded_buffer: Buffer where the encoded data will be written.
611 *
612 * @return Length of encoded data.
613 *****************************************************************************************
614 */
rsc_meas_value_encoded(rscs_meas_val_t * p_meas,uint8_t * p_encoded_buffer)615 static uint16_t rsc_meas_value_encoded(rscs_meas_val_t *p_meas, uint8_t *p_encoded_buffer)
616 {
617 uint8_t flags = 0;
618 uint16_t length = 1;
619
620 // Instantaneous speed field
621 p_encoded_buffer[length++] = LO_U16(p_meas->inst_speed);
622 p_encoded_buffer[length++] = HI_U16(p_meas->inst_speed);
623
624 // Instantaneous cadence field
625 p_encoded_buffer[length++] = p_meas->inst_cadence;
626
627 // Instantaneous stride length field
628 if (s_rscs_env.rscs_init.feature & RSCS_FEAT_INSTANT_STRIDE_LEN_BIT) {
629 if (p_meas->inst_stride_length_present) {
630 p_encoded_buffer[length++] = LO_U16(p_meas->inst_stride_length);
631 p_encoded_buffer[length++] = HI_U16(p_meas->inst_stride_length);
632 // Flags field
633 flags |= RSCS_MEAS_FLAG_INST_STRIDE_LEN_BIT;
634 }
635 }
636
637 // Total distance field
638 if (s_rscs_env.rscs_init.feature & RSCS_FEAT_TOTAL_DISTANCE_BIT) {
639 if (p_meas->total_distance_present) {
640 p_encoded_buffer[length++] = LO_UINT32_T(p_meas->total_distance);
641 p_encoded_buffer[length++] = L2_UINT32_T(p_meas->total_distance);
642 p_encoded_buffer[length++] = L3_UINT32_T(p_meas->total_distance);
643 p_encoded_buffer[length++] = HI_UINT32_T(p_meas->total_distance);
644 // Flags field
645 flags |= RSCS_MEAS_FLAG_TOTAL_DISTANCE_BIT;
646 }
647 }
648
649 // Flags field
650 if (s_rscs_env.rscs_init.feature & RSCS_FEAT_RUNNING_OR_WALKING_STATUS_BIT) {
651 if (p_meas->is_run_or_walk) {
652 flags |= RSCS_MEAS_FLAG_RUNNING_OR_WALKING_BIT;
653 }
654 }
655
656 p_encoded_buffer[0] = flags;
657
658 return length;
659 }
660
661 /*
662 * GLOBAL FUNCTION DEFINITIONS
663 ****************************************************************************************
664 */
rscs_measurement_send(uint8_t conn_idx,rscs_meas_val_t * p_meas)665 sdk_err_t rscs_measurement_send(uint8_t conn_idx, rscs_meas_val_t *p_meas)
666 {
667 sdk_err_t error_code = SDK_ERR_NTF_DISABLED;
668 uint8_t encoded_rsc_meas[RSCS_MEAS_VAL_LEN_MAX];
669 uint16_t length;
670 gatts_noti_ind_t rsc_ntf;
671
672 length = rsc_meas_value_encoded(p_meas, encoded_rsc_meas);
673
674 if (PRF_CLI_START_NTF == s_rscs_env.meas_ntf_cfg[conn_idx]) {
675 rsc_ntf.type = BLE_GATT_NOTIFICATION;
676 rsc_ntf.handle = prf_find_handle_by_idx(RSCS_IDX_RSC_MEAS_VAL,
677 s_rscs_env.start_hdl,
678 (uint8_t *)&s_rscs_env.rscs_init.char_mask);
679 rsc_ntf.length = length;
680 rsc_ntf.value = encoded_rsc_meas;
681 error_code = ble_gatts_noti_ind(conn_idx, &rsc_ntf);
682 }
683
684 return error_code;
685 }
686
rscs_ctrl_pt_rsp_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)687 sdk_err_t rscs_ctrl_pt_rsp_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
688 {
689 sdk_err_t error_code = SDK_ERR_IND_DISABLED;
690 gatts_noti_ind_t ctrl_pt_rsp;
691
692 if (PRF_CLI_START_IND == s_rscs_env.ctrl_point_ind_cfg[conn_idx]) {
693 ctrl_pt_rsp.type = BLE_GATT_INDICATION;
694 ctrl_pt_rsp.handle = prf_find_handle_by_idx(RSCS_IDX_CTRL_POINT_VAL,
695 s_rscs_env.start_hdl,
696 (uint8_t *)&s_rscs_env.rscs_init.char_mask);
697 ctrl_pt_rsp.length = length;
698 ctrl_pt_rsp.value = p_data;
699 error_code = ble_gatts_noti_ind(conn_idx, &ctrl_pt_rsp);
700 }
701
702 return error_code;
703 }
704
rscs_sensor_loc_update(rscs_sensor_loc_t sensor_loc)705 sdk_err_t rscs_sensor_loc_update(rscs_sensor_loc_t sensor_loc)
706 {
707 sdk_err_t error_code = BLE_SUCCESS;
708
709 if (s_rscs_env.rscs_init.feature & RSCS_FEAT_MULTIPLE_SENSORS_BIT) {
710 s_rscs_env.rscs_init.sensor_location = sensor_loc;
711 } else {
712 error_code = SDK_ERR_DISALLOWED;
713 }
714
715 return error_code;
716 }
717
rscs_service_init(rscs_init_t * p_rscs_init)718 sdk_err_t rscs_service_init(rscs_init_t *p_rscs_init)
719 {
720 sdk_err_t ret;
721 if (p_rscs_init == NULL) {
722 return SDK_ERR_POINTER_NULL;
723 }
724
725 if (p_rscs_init->feature & RSCS_FEAT_MULTIPLE_SENSORS_BIT) {
726 p_rscs_init->char_mask |= RSCS_CHAR_SENSOR_LOC_SUP;
727 } else {
728 p_rscs_init->char_mask &= ~RSCS_CHAR_SENSOR_LOC_SUP;
729 }
730
731 ret = memcpy_s(&s_rscs_env.rscs_init, sizeof(rscs_init_t), p_rscs_init, sizeof(rscs_init_t));
732 if (ret < 0) {
733 return ret;
734 }
735
736 return ble_server_prf_add(&rscs_prf_info);
737 }
738
739