• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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