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