• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  ****************************************************************************************
3  *
4  * @file gls.c
5  *
6  * @brief Glucose 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 "gls.h"
43 #include "gls_db.h"
44 #include "gls_racp.h"
45 #include "ble_prf_types.h"
46 #include "ble_prf_utils.h"
47 #include "utility.h"
48 #include "app_log.h"
49 
50 #define XPONENT_OFFSET 12
51 #define ENCODE_OFFSET 8
52 #define LOCATION_OFFSET 4
53 /*
54  * ENUMERATIONS
55  ****************************************************************************************
56  */
57 /**@brief Glucose Service Attributes Indexes. */
58 enum {
59     // Glucose Service
60     GLS_IDX_SVC,
61 
62     // Glucose Measurement
63     GLS_IDX_MEAS_CHAR,
64     GLS_IDX_MEAS_VAL,
65     GLS_IDX_MEAS_NTF_CFG,
66 
67     // Glucose Measurement Context
68     GLS_IDX_MEAS_CTX_CHAR,
69     GLS_IDX_MEAS_CTX_VAL,
70     GLS_IDX_MEAS_CTX_NTF_CFG,
71 
72     // Glucose Feature
73     GLS_IDX_FEATURE_CHAR,
74     GLS_IDX_FEATURE_VAL,
75 
76     // Record Access Control Point
77     GLS_IDX_REC_ACCESS_CTRL_CHAR,
78     GLS_IDX_REC_ACCESS_CTRL_VAL,
79     GLS_IDX_REC_ACCESS_CTRL_IND_CFG,
80 
81     GLS_IDX_NB,
82 };
83 
84 /*
85  * STRUCTURES
86  *****************************************************************************************
87  */
88 /**@brief Glucose Service environment variable. */
89 struct gls_env_t {
90     gls_init_t      gls_init;                               /**< Glucose Service initialization variables. */
91     uint16_t        start_hdl;                              /**< Glucose Service start handle. */
92     uint16_t        next_seq_num;                           /**< Sequence number of the next database record. */
93     uint8_t         proc_record_idx;                        /**< Current record index. */
94     uint16_t        proc_record_seq_num;                    /**< Sequence number of current request. */
95     uint16_t        proc_records_reported;                  /**< Number of reported records. */
96     bool            is_record_continue_send;                /**< State for continue send record. */
97     bool
98     racp_in_progress;                       /**< A previously triggered Control Point operation is still in progress. */
99     uint8_t
100     ntf_mask;                               /**< Mask for measurement notify or measurement context notify. */
101     gls_racp_req_t  racp_req;                               /**< Buffer saved current RACP request decode result. */
102     uint16_t
103     meas_ntf_cfg[GLS_CONNECTION_MAX];       /**< The configuration of Glucose Measurement Notification
104                                             which is configured by the peer devices. */
105     uint16_t
106     meas_ctx_ntf_cfg[GLS_CONNECTION_MAX];   /**< The configuration of Glucose Measurement
107                                             Context Notification which is configured by the peer devices. */
108     uint16_t
109     racp_ind_cfg[GLS_CONNECTION_MAX];       /**< The configuration of Record Access Control Point Indication
110                                             which is configured by the peer devices. */
111 };
112 
113 /*
114 * LOCAL FUNCTION DECLARATION
115 ****************************************************************************************
116 */
117 static sdk_err_t   gls_init(void);
118 static void        gls_read_att_cb(uint8_t conidx, const gatts_read_req_cb_t *p_param);
119 static void        gls_write_att_cb(uint8_t conidx, const gatts_write_req_cb_t *p_param);
120 static void        gls_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
121 static void        gls_disconnect_cb(uint8_t conn_idx, uint8_t reason);
122 static void        gls_gatts_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
123 static void        gls_receive_racp_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length);
124 static bool        gls_are_meas_racp_cccd_configured(uint8_t conn_idx);
125 static sdk_err_t   gls_meas_val_send(uint8_t conn_idx, gls_rec_t *p_rec);
126 
127 /*
128  * LOCAL VARIABLE DEFINITIONS
129  ****************************************************************************************
130  */
131 static struct gls_env_t s_gls_env;
132 
133 /**@brief Full GLS Database Description - Used to add attributes into the database. */
134 static const attm_desc_t gls_attr_tab[GLS_IDX_NB] = {
135     // Glucose Service Declaration
136     [GLS_IDX_SVC]          = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
137 
138     // Glucose Measurement Characteristic Declaration
139     [GLS_IDX_MEAS_CHAR]    = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
140     // Glucose Measurement Characteristic Value
141     [GLS_IDX_MEAS_VAL]     = {
142         BLE_ATT_CHAR_GLUCOSE_MEAS, NOTIFY_PERM(AUTH),
143         ATT_VAL_LOC_USER, GLS_MEAS_VAL_LEN_MAX
144     },
145     // Glucose Measurement Characteristic - Client Characteristic Configuration Descriptor
146     [GLS_IDX_MEAS_NTF_CFG] = {
147         BLE_ATT_DESC_CLIENT_CHAR_CFG,
148         READ_PERM(AUTH) | WRITE_REQ_PERM(AUTH),
149         0, 0
150     },
151 
152     // Glucose Measurement Context Characteristic Declaration
153     [GLS_IDX_MEAS_CTX_CHAR]    = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
154     // Glucose Measurement Context Characteristic Value
155     [GLS_IDX_MEAS_CTX_VAL]     = {
156         BLE_ATT_CHAR_GLUCOSE_MEAS_CTX, NOTIFY_PERM(AUTH),
157         ATT_VAL_LOC_USER, GLS_MEAS_CTX_LEN_MAX
158     },
159     // Glucose Measurement Context Characteristic - Client Characteristic Configuration Descriptor
160     [GLS_IDX_MEAS_CTX_NTF_CFG] = {
161         BLE_ATT_DESC_CLIENT_CHAR_CFG,
162         READ_PERM(AUTH) | WRITE_REQ_PERM(AUTH),
163         0, 0
164     },
165 
166     // Glucose Features Characteristic Declaration
167     [GLS_IDX_FEATURE_CHAR]     = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
168     // Glucose Features Characteristic Value
169 #if defined(PTS_AUTO_TEST)
170     [GLS_IDX_FEATURE_VAL]      = {
171         BLE_ATT_CHAR_GLUCOSE_FEATURE, READ_PERM_UNSEC,
172         ATT_VAL_LOC_USER, sizeof(uint16_t)
173     },
174 #else
175     [GLS_IDX_FEATURE_VAL]      = {
176         BLE_ATT_CHAR_GLUCOSE_FEATURE, READ_PERM(AUTH),
177         ATT_VAL_LOC_USER, sizeof(uint16_t)
178     },
179 #endif
180 
181     // Record Access Control Point characteristic Declaration
182     [GLS_IDX_REC_ACCESS_CTRL_CHAR]     = {BLE_ATT_DECL_CHARACTERISTIC,  READ_PERM_UNSEC, 0, 0},
183     // Record Access Control Point characteristic Value
184     [GLS_IDX_REC_ACCESS_CTRL_VAL]      = {
185         BLE_ATT_CHAR_REC_ACCESS_CTRL_PT,
186         INDICATE_PERM_UNSEC | WRITE_REQ_PERM(AUTH),
187         ATT_VAL_LOC_USER,
188         GLS_REC_ACCESS_CTRL_LEN_MAX
189     },
190     // Record Access Control Point characteristic - Client Characteristic Configuration Descriptor
191     [GLS_IDX_REC_ACCESS_CTRL_IND_CFG]  = {
192         BLE_ATT_DESC_CLIENT_CHAR_CFG,
193         READ_PERM(AUTH) | WRITE_REQ_PERM(AUTH),
194         0, 0
195     },
196 
197 };
198 
199 /**@brief GLS Task interface required by profile manager. */
200 static ble_prf_manager_cbs_t gls_tack_cbs = {
201     (prf_init_func_t) gls_init,
202     NULL,
203     gls_disconnect_cb
204 };
205 
206 /**@brief GLS Task Callbacks. */
207 static gatts_prf_cbs_t gls_cb_func = {
208     gls_read_att_cb,
209     gls_write_att_cb,
210     NULL,
211     gls_gatts_ntf_ind_cb,
212     gls_cccd_set_cb
213 };
214 
215 /**@brief GLS Information. */
216 static const prf_server_info_t gls_prf_info = {
217     .max_connection_nb = GLS_CONNECTION_MAX,
218     .manager_cbs       = &gls_tack_cbs,
219     .gatts_prf_cbs     = &gls_cb_func
220 };
221 
222 /*
223  * LOCAL FUNCTION DEFINITIONS
224  ****************************************************************************************
225  */
226 /**
227  *****************************************************************************************
228  * @brief Initialize Glucose Service and create db in att
229  *
230  * @return Error code to know if profile initialization succeed or not.
231  *****************************************************************************************
232  */
gls_init(void)233 static sdk_err_t gls_init(void)
234 {
235     // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
236     uint16_t          start_hdl      = PRF_INVALID_HANDLE;
237     const uint8_t     gls_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_GLUCOSE);
238     sdk_err_t         error_code;
239     gatts_create_db_t gatts_db;
240     sdk_err_t         error_code;
241 
242     error_code = memset_s(&gatts_db, sizeof(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                 = gls_svc_uuid;
249     gatts_db.attr_tab_cfg         = (uint8_t *)&(s_gls_env.gls_init.char_mask);
250     gatts_db.max_nb_attr          = GLS_IDX_NB;
251     gatts_db.srvc_perm            = 0;
252     gatts_db.attr_tab_type        = SERVICE_TABLE_TYPE_16;
253     gatts_db.attr_tab.attr_tab_16 = gls_attr_tab;
254 
255     error_code = ble_gatts_srvc_db_create(&gatts_db);
256     if (SDK_SUCCESS == error_code) {
257         s_gls_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:  The parameters of the read request.
269  *****************************************************************************************
270  */
gls_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)271 static void gls_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 = prf_find_idx_by_handle(handle,
276                                   s_gls_env.start_hdl,
277                                   GLS_IDX_NB,
278                                   (uint8_t *)&s_gls_env.gls_init.char_mask);
279     cfm.handle = handle;
280     cfm.status = BLE_SUCCESS;
281 
282     switch (tab_index) {
283         case GLS_IDX_MEAS_NTF_CFG:
284             cfm.length = sizeof(uint16_t);
285             cfm.value  = (uint8_t *)&s_gls_env.meas_ntf_cfg[conn_idx];
286             break;
287 
288         case GLS_IDX_MEAS_CTX_NTF_CFG:
289             cfm.length = sizeof(uint16_t);
290             cfm.value  = (uint8_t *)&s_gls_env.meas_ctx_ntf_cfg[conn_idx];
291             break;
292 
293         case GLS_IDX_FEATURE_VAL:
294             cfm.length = sizeof(uint16_t);
295             cfm.value  = (uint8_t *)&s_gls_env.gls_init.feature;
296             break;
297 
298         case GLS_IDX_REC_ACCESS_CTRL_IND_CFG:
299             cfm.length = sizeof(uint16_t);
300             cfm.value  = (uint8_t *)&s_gls_env.racp_ind_cfg[conn_idx];
301             break;
302 
303         default:
304             cfm.length = 0;
305             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
306             break;
307     }
308 
309     ble_gatts_read_cfm(conn_idx, &cfm);
310 }
311 
312 /**
313  *****************************************************************************************
314  * @brief Handles reception of the write request.
315  *
316  * @param[in]: conn_idx: Connection index
317  * @param[in]: p_param:  The parameters of the write request.
318  *****************************************************************************************
319  */
gls_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)320 static void gls_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
321 {
322     uint16_t          handle      = p_param->handle;
323     uint16_t          tab_index   = 0;
324     uint16_t          cccd_value  = 0;
325     bool              racp_evt    = false;
326     gls_evt_t         event;
327     gatts_write_cfm_t cfm;
328 
329     tab_index  = prf_find_idx_by_handle(handle, s_gls_env.start_hdl,
330                                         GLS_IDX_NB, (uint8_t *)&s_gls_env.gls_init.char_mask);
331     cfm.handle     = handle;
332     cfm.status     = BLE_SUCCESS;
333     event.evt_type = GLS_EVT_INVALID;
334     event.conn_idx = conn_idx;
335 
336     switch (tab_index) {
337         case GLS_IDX_MEAS_NTF_CFG:
338             cccd_value     = le16toh(&p_param->value[0]);
339             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
340                               GLS_EVT_MEAS_NOTIFICATION_ENABLED : GLS_EVT_MEAS_NOTIFICATION_DISABLED);
341             s_gls_env.meas_ntf_cfg[conn_idx] = cccd_value;
342             break;
343 
344         case GLS_IDX_MEAS_CTX_NTF_CFG:
345             cccd_value     = le16toh(&p_param->value[0]);
346             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
347                               GLS_EVT_CTX_NOTIFICATION_ENABLED : GLS_EVT_CTX_NOTIFICATION_DISABLED);
348             s_gls_env.meas_ctx_ntf_cfg[conn_idx] = cccd_value;
349             break;
350 
351         case GLS_IDX_REC_ACCESS_CTRL_IND_CFG:
352             cccd_value     = le16toh(&p_param->value[0]);
353             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
354                               GLS_EVT_CTRL_INDICATION_ENABLED : GLS_EVT_CTRL_INDICATION_DISABLED);
355             s_gls_env.racp_ind_cfg[conn_idx] = cccd_value;
356             break;
357 
358         case GLS_IDX_REC_ACCESS_CTRL_VAL:
359             if (!gls_are_meas_racp_cccd_configured(conn_idx)) {
360                 cfm.status = GLS_ERROR_CCCD_INVALID;
361             } else if (s_gls_env.racp_in_progress && GLS_RACP_OP_ABORT_OP != p_param->value[0]) {
362                 cfm.status = GLS_ERROR_PROC_IN_PROCESS;
363             } else {
364                 racp_evt = true;
365             }
366             break;
367         default:
368             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
369             break;
370     }
371 
372     ble_gatts_write_cfm(conn_idx, &cfm);
373     if (racp_evt) {
374         gls_receive_racp_handler(conn_idx, p_param->value, p_param->length);
375     }
376     if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status &&
377         GLS_EVT_INVALID != event.evt_type && s_gls_env.gls_init.evt_handler) {
378         s_gls_env.gls_init.evt_handler(&event);
379     }
380 }
381 
382 /**
383  *****************************************************************************************
384  * @brief Handles reception of the cccd recover request.
385  *
386  * @param[in]: conn_idx:   Connection index
387  * @param[in]: handle:     The handle of cccd attribute.
388  * @param[in]: cccd_value: The value of cccd attribute.
389  *****************************************************************************************
390  */
gls_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)391 static void gls_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
392 {
393     uint16_t          tab_index   = 0;
394     gls_evt_t         event;
395 
396     if (!prf_is_cccd_value_valid(cccd_value)) {
397         return;
398     }
399 
400     tab_index  = prf_find_idx_by_handle(handle,
401                                         s_gls_env.start_hdl,
402                                         GLS_IDX_NB,
403                                         (uint8_t *)&s_gls_env.gls_init.char_mask);
404 
405     event.evt_type = GLS_EVT_INVALID;
406     event.conn_idx = conn_idx;
407 
408     switch (tab_index) {
409         case GLS_IDX_MEAS_NTF_CFG:
410             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
411                               GLS_EVT_MEAS_NOTIFICATION_ENABLED : \
412                               GLS_EVT_MEAS_NOTIFICATION_DISABLED);
413             s_gls_env.meas_ntf_cfg[conn_idx] = cccd_value;
414             break;
415 
416         case GLS_IDX_MEAS_CTX_NTF_CFG:
417             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ? \
418                               GLS_EVT_CTX_NOTIFICATION_ENABLED : \
419                               GLS_EVT_CTX_NOTIFICATION_DISABLED);
420             s_gls_env.meas_ctx_ntf_cfg[conn_idx] = cccd_value;
421             break;
422 
423         case GLS_IDX_REC_ACCESS_CTRL_IND_CFG:
424             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ? \
425                               GLS_EVT_CTRL_INDICATION_ENABLED : \
426                               GLS_EVT_CTRL_INDICATION_DISABLED);
427             s_gls_env.racp_ind_cfg[conn_idx] = cccd_value;
428             break;
429 
430         default:
431             break;
432     }
433 
434     if (GLS_EVT_INVALID != event.evt_type && s_gls_env.gls_init.evt_handler) {
435         s_gls_env.gls_init.evt_handler(&event);
436     }
437 }
438 
439 /**
440  *****************************************************************************************
441  * @brief Handles reception of the disconnection event.
442  *
443  * @param[in] conn_idx: Connection index.
444  * @param[in] reason:   Reason of disconnection.
445  *****************************************************************************************
446  */
gls_disconnect_cb(uint8_t conn_idx,uint8_t reason)447 static void gls_disconnect_cb(uint8_t conn_idx, uint8_t reason)
448 {
449     s_gls_env.racp_in_progress = false;
450 }
451 
452 /**
453  *****************************************************************************************
454  * @brief Check glucose measurement notification and record access control point indication are both configured.
455  *
456  * @param[in] conn_idx: Connection index.
457  *
458  * @return Result of checking.
459  *****************************************************************************************
460  */
gls_are_meas_racp_cccd_configured(uint8_t conn_idx)461 static bool gls_are_meas_racp_cccd_configured(uint8_t conn_idx)
462 {
463     if ((PRF_CLI_STOP_NTFIND == s_gls_env.meas_ntf_cfg[conn_idx]) || \
464             (PRF_CLI_STOP_NTFIND == s_gls_env.racp_ind_cfg[conn_idx])) {
465         return false;
466     } else {
467         return true;
468     }
469 }
470 
471 /**
472  *****************************************************************************************
473  * @brief Set the next sequence number by reading the last record in the data base.
474  *
475  * @return If set successfully or not.
476  *****************************************************************************************
477  */
gls_next_sequence_num_set(void)478 static bool gls_next_sequence_num_set(void)
479 {
480     uint16_t  records_num;
481     gls_rec_t gls_res;
482 
483     records_num = gls_db_records_num_get();
484     if (records_num > 0) {
485         if (gls_db_record_get(records_num - 1, &gls_res)) {
486             s_gls_env.next_seq_num = gls_res.meas_val.sequence_number + 1;
487         } else {
488             return false;
489         }
490     } else {
491         s_gls_env.next_seq_num = 0;
492     }
493 
494     return true;
495 }
496 
497 /**
498  *****************************************************************************************
499  * @brief Informing that the REPORT RECORDS procedure is completed.
500  *
501  * @param[in] conn_idx: Connection index.
502  *****************************************************************************************
503  */
gls_report_records_completed(uint8_t conn_idx)504 static void gls_report_records_completed(uint8_t conn_idx)
505 {
506     gls_racp_rsp_t  racp_rsp;
507     uint8_t         encoded_racp_rsp[GLS_REC_ACCESS_CTRL_LEN_MAX];
508     uint16_t        encode_length;
509     uint8_t ret;
510 
511     ret = memset_s(&racp_rsp, sizeof(gls_racp_rsp_t), 0, sizeof(gls_racp_rsp_t));
512     if (ret < 0) {
513         return;
514     }
515 
516     racp_rsp.op_code                 = GLS_RACP_OP_RSP_CODE;
517     racp_rsp.operand.rsp.op_code_req = GLS_RACP_OP_REP_STRD_RECS;
518 
519     if (s_gls_env.proc_records_reported) {
520         racp_rsp.operand.rsp.status = GLS_RACP_RSP_SUCCESS;
521     } else {
522         racp_rsp.operand.rsp.status = GLS_RACP_RSP_NO_RECS_FOUND;
523     }
524 
525     encode_length = gls_racp_rsp_encode(&racp_rsp, encoded_racp_rsp);
526     gls_racp_rsp_send(conn_idx, encoded_racp_rsp, encode_length);
527 }
528 
529 /**
530  *****************************************************************************************
531  * @brief Report all records handler.
532  *
533  * @param[in] conn_idx:   Connection index.
534  * @param[in] p_racp_rsp: Pointer to buffer saved response.
535  *****************************************************************************************
536  */
gls_all_records_report(uint8_t conn_idx,gls_racp_req_t * p_racp_req)537 static void gls_all_records_report(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
538 {
539     uint16_t  records_num;
540     gls_rec_t gls_res;
541 
542     records_num = gls_db_records_num_get();
543     if (s_gls_env.proc_record_idx >= records_num) {
544         s_gls_env.is_record_continue_send = false;
545         s_gls_env.racp_in_progress        = false;
546         gls_report_records_completed(conn_idx);
547     } else if (gls_db_record_get(s_gls_env.proc_record_idx, &gls_res)) {
548         s_gls_env.is_record_continue_send = true;
549         gls_meas_val_send(conn_idx, &gls_res);
550     }
551 }
552 
553 /**
554  *****************************************************************************************
555  * @brief Report less or equal setting value records handler.
556  *
557  * @param[in] conn_idx:   Connection index.
558  * @param[in] p_racp_rsp: Pointer to buffer saved response.
559  *****************************************************************************************
560  */
gls_less_or_equal_records_report(uint8_t conn_idx,gls_racp_req_t * p_racp_req)561 static void gls_less_or_equal_records_report(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
562 {
563     uint16_t  records_num;
564     gls_rec_t gls_res;
565 
566     records_num = gls_db_records_num_get();
567 
568     while (s_gls_env.proc_record_idx < records_num) {
569         if (gls_db_record_get(s_gls_env.proc_record_idx, &gls_res)) {
570             if (s_gls_env.proc_record_seq_num >= gls_res.meas_val.sequence_number) {
571                 s_gls_env.is_record_continue_send = true;
572                 gls_meas_val_send(conn_idx, &gls_res);
573                 return;
574             }
575 
576             s_gls_env.proc_record_idx++;
577         } else {
578             break;
579         }
580     };
581 
582     s_gls_env.is_record_continue_send = false;
583     s_gls_env.racp_in_progress        = false;
584     gls_report_records_completed(conn_idx);
585 }
586 
587 /**
588  *****************************************************************************************
589  * @brief Report greater or equal setting value records handler.
590  *
591  * @param[in] conn_idx:   Connection index.
592  * @param[in] p_racp_rsp: Pointer to buffer saved response.
593  *****************************************************************************************
594  */
gls_greater_or_equal_records_report(uint8_t conn_idx,gls_racp_req_t * p_racp_req)595 static void gls_greater_or_equal_records_report(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
596 {
597     uint16_t  records_num;
598     gls_rec_t gls_res;
599 
600     records_num = gls_db_records_num_get();
601 
602     while (s_gls_env.proc_record_idx < records_num) {
603         if (gls_db_record_get(s_gls_env.proc_record_idx, &gls_res)) {
604             if (s_gls_env.proc_record_seq_num <= gls_res.meas_val.sequence_number) {
605                 s_gls_env.is_record_continue_send = true;
606                 gls_meas_val_send(conn_idx, &gls_res);
607                 return;
608             }
609 
610             s_gls_env.proc_record_idx++;
611         } else {
612             break;
613         }
614     };
615 
616     s_gls_env.is_record_continue_send = false;
617     s_gls_env.racp_in_progress        = false;
618     gls_report_records_completed(conn_idx);
619 }
620 
621 /**
622  *****************************************************************************************
623  * @brief Report within range of setting value records handler.
624  *
625  * @param[in] conn_idx:   Connection index.
626  * @param[in] p_racp_rsp: Pointer to buffer saved response.
627  *****************************************************************************************
628  */
gls_within_range_of_records_report(uint8_t conn_idx,gls_racp_req_t * p_racp_req)629 static void gls_within_range_of_records_report(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
630 {
631     uint16_t  records_num;
632     gls_rec_t gls_res;
633 
634     records_num = gls_db_records_num_get();
635 
636     while (s_gls_env.proc_record_idx < records_num) {
637         if (!gls_db_record_get(s_gls_env.proc_record_idx, &gls_res)) {
638             break;
639         }
640 
641         if (GLS_RACP_FILTER_SEQ_NUMBER == p_racp_req->filter.racp_filter_type) {
642             if ((gls_res.meas_val.sequence_number >= s_gls_env.racp_req.filter.val.seq_num.min) && \
643                     (gls_res.meas_val.sequence_number <= s_gls_env.racp_req.filter.val.seq_num.max)) {
644                 s_gls_env.is_record_continue_send = true;
645                 gls_meas_val_send(conn_idx, &gls_res);
646                 return;
647             }
648         } else if (GLS_RACP_FILTER_USER_FACING_TIME == p_racp_req->filter.racp_filter_type) {
649             if (!(-1 == gls_racp_user_time_compare(&gls_res.meas_val.base_time, \
650                                                    &s_gls_env.racp_req.filter.val.time.min)) && \
651                 !(-1 == gls_racp_user_time_compare(&s_gls_env.racp_req.filter.val.time.max, \
652                                                    &gls_res.meas_val.base_time))) {
653                 s_gls_env.is_record_continue_send = true;
654                 gls_meas_val_send(conn_idx, &gls_res);
655                 break;
656             }
657         }
658         s_gls_env.proc_record_idx++;
659     };
660 
661     s_gls_env.is_record_continue_send = false;
662     s_gls_env.racp_in_progress        = false;
663     gls_report_records_completed(conn_idx);
664 }
665 
666 /**
667  *****************************************************************************************
668  * @brief Report first or last records handler.
669  *
670  * @param[in] conn_idx:   Connection index.
671  * @param[in] p_racp_rsp: Pointer to buffer saved response.
672  *****************************************************************************************
673  */
gls_first_or_last_records_report(uint8_t conn_idx,gls_racp_req_t * p_racp_req)674 static void gls_first_or_last_records_report(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
675 {
676     uint16_t  records_num;
677     gls_rec_t gls_res;
678     bool      is_get_rec;
679 
680     records_num = gls_db_records_num_get();
681 
682     if (0 < s_gls_env.proc_records_reported) {
683         s_gls_env.is_record_continue_send = false;
684         s_gls_env.racp_in_progress        = false;
685         gls_report_records_completed(conn_idx);
686     } else {
687         s_gls_env.is_record_continue_send = true;
688         is_get_rec                        = false;
689 
690         if (GLS_RACP_OPERATOR_FIRST_REC == p_racp_req->filter.racp_operator) {
691             is_get_rec = gls_db_record_get(0, &gls_res);
692         } else if (GLS_RACP_OPERATOR_LAST_REC == p_racp_req->filter.racp_operator) {
693             is_get_rec = gls_db_record_get(records_num - 1, &gls_res);
694         }
695 
696         if (is_get_rec) {
697             gls_meas_val_send(conn_idx, &gls_res);
698         }
699     }
700 }
701 
702 /**
703  *****************************************************************************************
704  * @brief Report records request handler.
705  *
706  * @param[in] conn_idx:   Connection index.
707  * @param[in] p_racp_rsp: Pointer to buffer saved response.
708  *****************************************************************************************
709  */
gls_report_records_req_handler(uint8_t conn_idx,gls_racp_req_t * p_racp_req)710 static void gls_report_records_req_handler(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
711 {
712     switch (p_racp_req->filter.racp_operator) {
713         case GLS_RACP_OPERATOR_ALL_RECS:
714             gls_all_records_report(conn_idx, p_racp_req);
715             break;
716 
717         case GLS_RACP_OPERATOR_LE_OR_EQ:
718             s_gls_env.proc_record_seq_num = p_racp_req->filter.val.seq_num.max;
719             gls_less_or_equal_records_report(conn_idx, p_racp_req);
720             break;
721 
722         case GLS_RACP_OPERATOR_GT_OR_EQ:
723             s_gls_env.proc_record_seq_num = p_racp_req->filter.val.seq_num.min;
724             gls_greater_or_equal_records_report(conn_idx, p_racp_req);
725             break;
726 
727         case GLS_RACP_OPERATOR_WITHIN_RANGE_OF:
728             gls_within_range_of_records_report(conn_idx, p_racp_req);
729             break;
730 
731         case GLS_RACP_OPERATOR_FIRST_REC:
732         case GLS_RACP_OPERATOR_LAST_REC:
733             gls_first_or_last_records_report(conn_idx, p_racp_req);
734             break;
735 
736         default:
737             break;
738     }
739 }
740 
741 /**
742  *****************************************************************************************
743  * @brief Report number of records request handler.
744  *
745  * @param[in] conn_idx:   Connection index.
746  * @param[in] p_racp_rsp: Pointer to buffer saved response.
747  *****************************************************************************************
748  */
gls_report_records_num_req_handler(uint8_t conn_idx,gls_racp_req_t * p_racp_req)749 static void gls_report_records_num_req_handler(uint8_t conn_idx, gls_racp_req_t *p_racp_req)
750 {
751     gls_racp_rsp_t  racp_rsp;
752     uint8_t         encoded_racp_rsp[GLS_REC_ACCESS_CTRL_LEN_MAX];
753     uint16_t        encode_length;
754     uint16_t        req_num;
755 
756     req_num = gls_db_filter_records_num_get(&p_racp_req->filter);
757 
758     racp_rsp.op_code               = GLS_RACP_OP_NB_OF_STRD_RECS_RSP;
759     racp_rsp.racp_operator         = GLS_RACP_OPERATOR_NULL;
760     racp_rsp.operand.num_of_record = req_num;
761 
762     encode_length = gls_racp_rsp_encode(&racp_rsp, encoded_racp_rsp);
763     gls_racp_rsp_send(conn_idx, encoded_racp_rsp, encode_length);
764 }
765 
766 /**
767  *****************************************************************************************
768  * @brief Abort operation request handler.
769  *
770  * @param[in] conn_idx:   Connection index.
771  *****************************************************************************************
772  */
gls_abort_operation_handler(uint8_t conn_idx)773 static void gls_abort_operation_handler(uint8_t conn_idx)
774 {
775     gls_racp_rsp_t      racp_rsp;
776     uint8_t             encoded_racp_rsp[GLS_REC_ACCESS_CTRL_LEN_MAX];
777     uint16_t            encode_length;
778     uint8_t ret;
779 
780     ret = memset_s(&racp_rsp, sizeof(gls_racp_rsp_t), 0, sizeof(gls_racp_rsp_t));
781     if (ret <0) {
782         return;
783     }
784 
785     if (s_gls_env.racp_in_progress) {
786         s_gls_env.racp_in_progress = false;
787     }
788 
789     racp_rsp.operand.rsp.status = GLS_RACP_RSP_SUCCESS;
790 
791     racp_rsp.op_code                 = GLS_RACP_OP_RSP_CODE;
792     racp_rsp.racp_operator           = GLS_RACP_OPERATOR_NULL;
793     racp_rsp.operand.rsp.op_code_req = GLS_RACP_OP_ABORT_OP;
794     encode_length = gls_racp_rsp_encode(&racp_rsp, encoded_racp_rsp);
795     gls_racp_rsp_send(conn_idx, encoded_racp_rsp, encode_length);
796 }
797 
798 /**
799  *****************************************************************************************
800  * @brief Record Access Control Point receive handler.
801  *
802  * @param[in] conn_idx: Connection index.
803  * @param[in] p_data:   Pointer to data.
804  * @param[in] length:   Length of data.
805  *****************************************************************************************
806  */
gls_receive_racp_handler(uint8_t conn_idx,const uint8_t * p_data,uint16_t length)807 static void gls_receive_racp_handler(uint8_t conn_idx, const uint8_t *p_data, uint16_t length)
808 {
809     gls_racp_rsp_t      racp_rsp;
810     gls_racp_operand_t  status;
811     uint8_t             encoded_racp_rsp[GLS_REC_ACCESS_CTRL_LEN_MAX];
812     uint16_t            encode_length;
813     uint8_t   ret;
814 
815     ret  = memset_S(&s_gls_env.racp_req, sizeof(gls_racp_req_t), 0, sizeof(gls_racp_req_t));
816     if (ret < 0) {
817         return;
818     }
819     ret = memset_S(&racp_rsp, sizeof(gls_racp_rsp_t), 0, sizeof(gls_racp_rsp_t));
820     if (ret < 0) {
821         return;
822     }
823 
824     if (GLS_REC_ACCESS_CTRL_LEN_MIN <= length) {
825         status = gls_racp_req_decode(p_data, length, &s_gls_env.racp_req);
826         if ((GLS_RACP_RSP_VALID_DECODE == status) && \
827             (GLS_RACP_OP_REP_STRD_RECS <= s_gls_env.racp_req.op_code) && \
828             (GLS_RACP_OP_REP_NB_OF_STRD_RECS >= s_gls_env.racp_req.op_code)) {
829             if (GLS_RACP_OP_REP_STRD_RECS == s_gls_env.racp_req.op_code) {
830                 s_gls_env.racp_in_progress      = true;
831                 s_gls_env.proc_records_reported = 0;
832                 s_gls_env.proc_record_idx       = 0;
833                 gls_report_records_req_handler(conn_idx, &s_gls_env.racp_req);
834             } else if (GLS_RACP_OP_REP_NB_OF_STRD_RECS == s_gls_env.racp_req.op_code) {
835                 s_gls_env.racp_in_progress = true;
836                 gls_report_records_num_req_handler(conn_idx, &s_gls_env.racp_req);
837             } else if (GLS_RACP_OP_ABORT_OP == s_gls_env.racp_req.op_code) {
838                 gls_abort_operation_handler(conn_idx);
839             }
840         } else {
841             if (GLS_RACP_RSP_VALID_DECODE != status) {
842                 racp_rsp.operand.rsp.status = status;
843             }
844 
845             if ((GLS_RACP_OP_REP_STRD_RECS > s_gls_env.racp_req.op_code) || \
846                     (GLS_RACP_OP_REP_NB_OF_STRD_RECS < s_gls_env.racp_req.op_code)) {
847                 racp_rsp.operand.rsp.status = GLS_RACP_RSP_OP_CODE_NOT_SUP;
848             }
849 
850             racp_rsp.op_code                 = GLS_RACP_OP_RSP_CODE;
851             racp_rsp.operand.rsp.op_code_req = s_gls_env.racp_req.op_code;
852             encode_length = gls_racp_rsp_encode(&racp_rsp, encoded_racp_rsp);
853             gls_racp_rsp_send(conn_idx, encoded_racp_rsp, encode_length);
854         }
855     }
856 }
857 
858 /**
859  *****************************************************************************************
860  * @brief Encode a Glucose measurement.
861  *
862  * @param[in]  p_meas:           Pointer to GLS measurement value to be encoded.
863  * @param[out] p_encoded_buffer: Buffer where the encoded data will be written.
864  *
865  * @return Length of encoded data.
866  *****************************************************************************************
867  */
gls_meas_value_encode(const gls_meas_val_t * p_meas,uint8_t * p_encoded_buffer)868 static uint8_t gls_meas_value_encode(const gls_meas_val_t *p_meas, uint8_t *p_encoded_buffer)
869 {
870     uint8_t length = 0;
871 
872     p_encoded_buffer[length++] = p_meas->flags;
873 
874     p_encoded_buffer[length++] = LO_U16(p_meas->sequence_number);
875     p_encoded_buffer[length++] = HI_U16(p_meas->sequence_number);
876 
877     p_encoded_buffer[length++] = LO_U16(p_meas->base_time.year);
878     p_encoded_buffer[length++] = HI_U16(p_meas->base_time.year);
879     p_encoded_buffer[length++] = LO_U16(p_meas->base_time.month);
880     p_encoded_buffer[length++] = HI_U16(p_meas->base_time.day);
881     p_encoded_buffer[length++] = LO_U16(p_meas->base_time.hour);
882     p_encoded_buffer[length++] = HI_U16(p_meas->base_time.min);
883     p_encoded_buffer[length++] = LO_U16(p_meas->base_time.sec);
884 
885     if (p_meas->flags & GLS_MEAS_FLAG_TIME_OFFSET) {
886         p_encoded_buffer[length++] = LO_U16(p_meas->time_offset);
887         p_encoded_buffer[length++] = HI_U16(p_meas->time_offset);
888     }
889 
890     if (p_meas->flags & GLS_MEAS_FLAG_CONC_TYPE_LOC) {
891         uint16_t encoded_concentration;
892 
893         encoded_concentration = ((p_meas->glucose_concentration.exponent << XPONENT_OFFSET) & 0xF000) |
894                                 ((p_meas->glucose_concentration.mantissa <<  0) & 0x0FFF);
895 
896         p_encoded_buffer[length++] = (uint8_t)(encoded_concentration);
897         p_encoded_buffer[length++] = (uint8_t)(encoded_concentration >> ENCODE_OFFSET);
898         p_encoded_buffer[length++] = (p_meas->sample_location << LOCATION_OFFSET) | (p_meas->type & 0x0F);
899     }
900 
901     if (p_meas->flags & GLS_MEAS_FLAG_SENSOR_STATUS) {
902         p_encoded_buffer[length++] = LO_U16(p_meas->sensor_status_annunciation);
903         p_encoded_buffer[length++] = HI_U16(p_meas->sensor_status_annunciation);
904     }
905 
906     return length;
907 }
908 
909 /**
910  *****************************************************************************************
911  * @brief Send a glucose measurement/context.
912  *
913  * @param[in] conn_idx: Connnection index.
914  * @param[in] p_rec: Pointer to measurement to be sent.
915  *
916  * @return Result of notify value
917  *****************************************************************************************
918  */
gls_meas_val_send(uint8_t conn_idx,gls_rec_t * p_rec)919 static sdk_err_t gls_meas_val_send(uint8_t conn_idx, gls_rec_t *p_rec)
920 {
921     sdk_err_t        error_code = BLE_SUCCESS;
922     uint8_t          encoded_glc_meas[GLS_MEAS_VAL_LEN_MAX];
923     uint16_t         length;
924     gatts_noti_ind_t gls_ntf;
925     sdk_err_t ret;
926 
927     length  = gls_meas_value_encode(&p_rec->meas_val, encoded_glc_meas);
928 
929     ret = memset_s(&gls_ntf, sizeof(gatts_noti_ind_t), 0, sizeof(gatts_noti_ind_t));
930     if (ret < 0) {
931         return ret;
932     }
933 
934     if (PRF_CLI_START_NTF == s_gls_env.meas_ntf_cfg[conn_idx]) {
935         gls_ntf.type   = BLE_GATT_NOTIFICATION;
936         gls_ntf.handle = prf_find_handle_by_idx(GLS_IDX_MEAS_VAL,
937                                                 s_gls_env.start_hdl,
938                                                 (uint8_t *)&s_gls_env.gls_init.char_mask);
939         gls_ntf.length = length;
940         gls_ntf.value  = encoded_glc_meas;
941         error_code     = ble_gatts_noti_ind(conn_idx, &gls_ntf);
942         if (BLE_SUCCESS == error_code) {
943             s_gls_env.ntf_mask = GLS_NTF_OF_MEAS;
944         }
945     }
946 
947     return error_code;
948 }
949 
950 /**
951  *****************************************************************************************
952  * @brief Handles reception of the complete event.
953  *
954  * @param[in] conn_idx: Connection index.
955  * @param[in] p_param:  Pointer to the parameters of the complete event.
956  *****************************************************************************************
957  */
gls_gatts_ntf_ind_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)958 static void gls_gatts_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
959 {
960     if (SDK_SUCCESS != status) {
961         return;
962     }
963 
964     if (BLE_GATT_INDICATION == p_ntf_ind->type) {
965         s_gls_env.racp_in_progress = false;
966     } else if (BLE_GATT_NOTIFICATION == p_ntf_ind->type) {
967         if (s_gls_env.ntf_mask & GLS_NTF_OF_MEAS) {
968             s_gls_env.ntf_mask = GLS_NTF_OF_NULL;
969 
970             if (s_gls_env.is_record_continue_send) {
971                 s_gls_env.proc_record_idx++;
972                 s_gls_env.proc_records_reported++;
973                 gls_report_records_req_handler(conn_idx, &s_gls_env.racp_req);
974             } else {
975                 s_gls_env.racp_in_progress = false;
976             }
977         }
978     }
979 }
980 
981 /*
982  * GLOBAL FUNCTION DEFINITIONS
983  ****************************************************************************************
984  */
gls_new_meas_record(gls_rec_t * p_rec)985 bool gls_new_meas_record(gls_rec_t *p_rec)
986 {
987     p_rec->meas_val.sequence_number = s_gls_env.next_seq_num++;
988     return gls_db_record_add(p_rec);
989 }
990 
gls_racp_rsp_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)991 sdk_err_t   gls_racp_rsp_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
992 {
993     sdk_err_t        error_code = SDK_ERR_IND_DISABLED;
994     gatts_noti_ind_t racp_rsp;
995 
996     if (PRF_CLI_START_IND == s_gls_env.racp_ind_cfg[conn_idx]) {
997         racp_rsp.type     = BLE_GATT_INDICATION;
998         racp_rsp.handle   = prf_find_handle_by_idx(GLS_IDX_REC_ACCESS_CTRL_VAL,
999             s_gls_env.start_hdl,
1000             (uint8_t *)&s_gls_env.gls_init.char_mask);
1001         racp_rsp.length = length;
1002         racp_rsp.value  = p_data;
1003         error_code      = ble_gatts_noti_ind(conn_idx, &racp_rsp);
1004     }
1005 
1006     return error_code;
1007 }
1008 
gls_service_init(gls_init_t * p_gls_init)1009 sdk_err_t gls_service_init(gls_init_t *p_gls_init)
1010 {
1011     sdk_err_t ret;
1012     if (p_gls_init == NULL) {
1013         return SDK_ERR_POINTER_NULL;
1014     }
1015 
1016     ret = memset_s(&s_gls_env, sizeof(s_gls_env), 0, sizeof(s_gls_env));
1017     if (ret < 0) {
1018         return ret;
1019     }
1020     ret = memcpy_s(&s_gls_env.gls_init, sizeof(gls_init_t), p_gls_init, sizeof(gls_init_t));
1021     if (ret < 0) {
1022         return ret;
1023     }
1024     gls_next_sequence_num_set();
1025     gls_db_init();
1026 
1027     return ble_server_prf_add(&gls_prf_info);
1028 }
1029