• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file hts.c
5  *
6  * @brief Health Thermometer 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 "hts.h"
43 #include "ble_prf_types.h"
44 #include "utility.h"
45 #define EXPONEBT_2 (-2)
46 #define MANTISSA_32 32
47 #define MANTISSA_32_SCALE 100
48 #define OFFSET_24 24
49 #define SCALE_9 9
50 #define DESCALE_5 5
51 /*
52  * ENUMERATIONS
53  *****************************************************************************************
54  */
55 /**@brief Health Thermometer Service Attributes Indexes. */
56 enum {
57     HTS_IDX_SVC,
58 
59     HTS_IDX_TEM_MEAS_CHAR,
60     HTS_IDX_TEM_MEAS_VAL,
61     HTS_IDX_TEM_MEAS_IND_CFG,
62 
63     HTS_IDX_TEM_TYPE_CHAR,
64     HTS_IDX_TEM_TYPE_VAL,
65 
66     HTS_IDX_INTM_TEM_CHAR,
67     HTS_IDX_INTM_TEM_VAL,
68     HTS_IDX_INTM_TEM_NTF_CFG,
69 
70     HTS_IDX_MEAS_INTERVAL_CHAR,
71     HTS_IDX_MEAS_INTERVAL_VAL,
72     HTS_IDX_MEAS_INTERVAL_IND_CFG,
73     HTS_IDX_MEAS_INTERVAL_VRD_CFG,
74 
75     HTS_IDX_NB,
76 };
77 
78 /*
79  * STRUCTURES
80  *****************************************************************************************
81  */
82 /**@brief Health Thermometer Service environment variable. */
83 struct hts_env_t {
84     hts_init_t  hts_init;     /**< Health Thermometer Service initialization variables. */
85     uint16_t    start_hdl;                                  /**< Health Thermometer Service start handle. */
86     uint16_t
87     meas_ind_cfg[HTS_CONNECTION_MAX]; /**< The configuration of Temperature Measurement Indication \
88                                            which is configured by the peer devices. */
89     uint16_t
90     intm_tem_ntf_cfg[HTS_CONNECTION_MAX];       /**< The configuration of Intermediate Temperature Notification \
91                                                      which is configured by the peer devices. */
92     uint16_t
93     meas_interval_ind_cfg[HTS_CONNECTION_MAX];  /**< The configuration of Measurement Interval Indication \
94                                                      which is configured by the peer devices. */
95 };
96 
97 /*
98  * LOCAL FUNCTION DECLARATION
99  *****************************************************************************************
100  */
101 static sdk_err_t   hts_init(void);
102 static void        hts_read_att_cb(uint8_t  conn_idx, const gatts_read_req_cb_t  *p_param);
103 static void        hts_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
104 static void        hts_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
105 /*
106  * LOCAL VARIABLE DEFINITIONS
107  *****************************************************************************************
108  */
109 static struct hts_env_t s_hts_env;
110 
111 /**@brief Full HTS Database Description - Used to add attributes into the database. */
112 static const attm_desc_t hts_attr_tab[HTS_IDX_NB]  = {
113     // Health Thermometer Service Declaration
114     [HTS_IDX_SVC]                   =  {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
115 
116     // Temperature Measurement Characteristic - Declaration
117     [HTS_IDX_TEM_MEAS_CHAR]         =  {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
118     // Temperature Measurement Characteristic - Value
119     [HTS_IDX_TEM_MEAS_VAL]          =  {
120         BLE_ATT_CHAR_TEMPERATURE_MEAS,
121         INDICATE_PERM_UNSEC,
122         ATT_VAL_LOC_USER,
123         HTS_TEM_MEAS_MAX_LEN
124     },
125     // Temperature Measurement Characteristic - Client Characteristic Configuration Descriptor
126     [HTS_IDX_TEM_MEAS_IND_CFG]      =  {
127         BLE_ATT_DESC_CLIENT_CHAR_CFG,
128         READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
129         0,
130         0
131     },
132 
133     // Temperature Type Characteristic - Declaration
134     [HTS_IDX_TEM_TYPE_CHAR]         =  {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
135     // Temperature Measurement Characteristic - Value
136     [HTS_IDX_TEM_TYPE_VAL]          =  {
137         BLE_ATT_CHAR_TEMPERATURE_TYPE,
138         READ_PERM_UNSEC,
139         ATT_VAL_LOC_USER,
140         HTS_TEM_TYPE_MAX_LEN
141     },
142 
143     // Intermediate Temperature Characteristic - Declaration
144     [HTS_IDX_INTM_TEM_CHAR]         =  {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
145     // Intermediate Temperature Characteristic - Value
146     [HTS_IDX_INTM_TEM_VAL]          =  {
147         BLE_ATT_CHAR_INTERMED_TEMPERATURE,
148         NOTIFY_PERM_UNSEC,
149         ATT_VAL_LOC_USER,
150         HTS_INTM_TEM_MAX_LEN
151     },
152     // Intermediate Temperature Characteristic - Client Characteristic Configuration Descriptor
153     [HTS_IDX_INTM_TEM_NTF_CFG]      =  {
154         BLE_ATT_DESC_CLIENT_CHAR_CFG,
155         READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
156         0,
157         0
158     },
159 
160     // Measurement Interval Characteristic - Declaration
161     [HTS_IDX_MEAS_INTERVAL_CHAR]    =  {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
162     // Measurement Interval Characteristic - Value
163     [HTS_IDX_MEAS_INTERVAL_VAL]     =  {
164         BLE_ATT_CHAR_MEAS_INTERVAL,
165         READ_PERM_UNSEC | WRITE_REQ_PERM(AUTH) | INDICATE_PERM_UNSEC,
166         ATT_VAL_LOC_USER,
167         HTS_MEAS_INTERVAL_MAX_LEN
168     },
169     // Measurement Interval Characteristic - Client Characteristic Configuration Descriptor
170     [HTS_IDX_MEAS_INTERVAL_IND_CFG] =  {
171         BLE_ATT_DESC_CLIENT_CHAR_CFG,
172         READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
173         0,
174         0
175     },
176     // Measurement Interval Characteristic - Valid Range Descriptor
177     [HTS_IDX_MEAS_INTERVAL_VRD_CFG] =  {
178         BLE_ATT_DESC_VALID_RANGE,
179         READ_PERM_UNSEC,
180         ATT_VAL_LOC_USER,
181         0
182     },
183 };
184 
185 
186 /**@brief HTS Task interface required by profile manager. */
187 static ble_prf_manager_cbs_t hts_task_cbs = {
188     (prf_init_func_t) hts_init,
189     NULL,
190     NULL
191 
192 };
193 
194 /**@brief HTS Task Callbacks. */
195 static gatts_prf_cbs_t hts_cb_func = {
196     hts_read_att_cb,
197     hts_write_att_cb,
198     NULL,
199     NULL,
200     hts_cccd_set_cb
201 };
202 
203 /**@brief HTS Information. */
204 static const prf_server_info_t hts_prf_info = {
205     .max_connection_nb = HTS_CONNECTION_MAX,
206     .manager_cbs       = &hts_task_cbs,
207     .gatts_prf_cbs     = &hts_cb_func,
208 };
209 
210 /*
211  * LOCAL FUNCTION DEFINITIONS
212  *****************************************************************************************
213  */
214 /**
215  *****************************************************************************************
216  * @brief Initialize health thermometer service  create db in att
217  *
218  * @return Error code to know if profile initialization succeed or not.
219  *****************************************************************************************
220  */
hts_init(void)221 static sdk_err_t hts_init(void)
222 {
223     // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
224     uint16_t          start_hdl      = PRF_INVALID_HANDLE;
225     const uint8_t     hts_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_HEALTH_THERMOM);
226     sdk_err_t         error_code;
227     gatts_create_db_t gatts_db;
228 
229     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
230     if (error_code < 0) {
231         return error_code;
232     }
233 
234     gatts_db.shdl                 = &start_hdl;
235     gatts_db.uuid                 = hts_svc_uuid;
236     gatts_db.attr_tab_cfg         = (uint8_t *)&(s_hts_env.hts_init.char_mask);
237     gatts_db.max_nb_attr          = HTS_IDX_NB;
238     gatts_db.srvc_perm            = 0;
239     gatts_db.attr_tab_type        = SERVICE_TABLE_TYPE_16;
240     gatts_db.attr_tab.attr_tab_16 = hts_attr_tab;
241 
242     error_code = ble_gatts_srvc_db_create(&gatts_db);
243     if (SDK_SUCCESS == error_code) {
244         s_hts_env.start_hdl = *gatts_db.shdl;
245     }
246 
247     return error_code;
248 }
249 
250 /**
251  *****************************************************************************************
252  * @brief Handles reception of the attribute info request message.
253  *
254  * @param[in] conn_idx: Connection index
255  * @param[in] p_param:  The parameters of the read request.
256  *****************************************************************************************
257  */
hts_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)258 static void   hts_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
259 {
260     gatts_read_cfm_t  cfm;
261     uint16_t          meas_interval[2];
262     uint8_t           handle    = p_param->handle;
263     uint8_t           tab_index = prf_find_idx_by_handle(handle,
264                                   s_hts_env.start_hdl,
265                                   HTS_IDX_NB,
266                                   (uint8_t *)&s_hts_env.hts_init.char_mask);
267 
268     cfm.handle = handle;
269     cfm.status = BLE_SUCCESS;
270 
271     switch (tab_index) {
272         case HTS_IDX_TEM_MEAS_IND_CFG:
273             cfm.length = sizeof(uint16_t);
274             cfm.value  = (uint8_t *)&s_hts_env.meas_ind_cfg[conn_idx];
275             break;
276 
277         case HTS_IDX_TEM_TYPE_VAL:
278             if (s_hts_env.hts_init.evt_handler) {
279                 hts_evt_t event;
280                 hts_read_characteristic_t characteristic = HTS_READ_CHAR_TEMP_TYPE;
281 
282                 event.evt_type = HTS_EVT_READ_CHARACTERISTIC;
283                 event.p_data   = (uint8_t *)&characteristic;
284                 event.length   = sizeof(characteristic);
285                 s_hts_env.hts_init.evt_handler(&event);
286             }
287             cfm.length = sizeof(uint8_t);
288             cfm.value  = (uint8_t *)&s_hts_env.hts_init.temp_type;
289             break;
290 
291         case HTS_IDX_INTM_TEM_NTF_CFG:
292             cfm.length = sizeof(uint16_t);
293             cfm.value  = (uint8_t *)&s_hts_env.intm_tem_ntf_cfg[conn_idx];
294             break;
295 
296         case HTS_IDX_MEAS_INTERVAL_VAL:
297             if (s_hts_env.hts_init.evt_handler) {
298                 hts_evt_t event;
299                 hts_read_characteristic_t characteristic = HTS_READ_CHAR_MEAS_INTL;
300 
301                 event.evt_type = HTS_EVT_READ_CHARACTERISTIC;
302                 event.p_data   = (uint8_t *)&characteristic;
303                 event.length   = sizeof(characteristic);
304                 s_hts_env.hts_init.evt_handler(&event);
305             }
306             cfm.length = sizeof(uint16_t);
307             cfm.value  = (uint8_t *)&s_hts_env.hts_init.meas_interval;
308             break;
309 
310         case HTS_IDX_MEAS_INTERVAL_IND_CFG:
311             cfm.length = sizeof(uint16_t);
312             cfm.value  = (uint8_t *)&s_hts_env.meas_interval_ind_cfg[conn_idx];
313             break;
314 
315         case HTS_IDX_MEAS_INTERVAL_VRD_CFG:
316             meas_interval[0] = s_hts_env.hts_init.min_meas_interval_sup;
317             meas_interval[1] = s_hts_env.hts_init.max_meas_interval_sup;
318             cfm.length = sizeof(uint32_t);
319             cfm.value  = (uint8_t *)meas_interval;
320             break;
321 
322         default :
323             cfm.length = 0;
324             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
325             break;
326     }
327 
328     ble_gatts_read_cfm(conn_idx, &cfm);
329 }
330 
331 /**
332  *****************************************************************************************
333  * @brief Handles reception of the write request.
334  *
335  * @param[in]: conn_idx: Connection index
336  * @param[in]: p_param:  The parameters of the write request.
337  *****************************************************************************************
338  */
hts_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)339 static void   hts_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
340 {
341     uint16_t          handle     = p_param->handle;
342     uint16_t          tab_index  = 0;
343     uint16_t          cccd_value = 0;
344     hts_evt_t         event;
345     gatts_write_cfm_t cfm;
346 
347     tab_index  = prf_find_idx_by_handle(handle,
348                                         s_hts_env.start_hdl,
349                                         HTS_IDX_NB,
350                                         (uint8_t *)&s_hts_env.hts_init.char_mask);
351     cfm.handle = handle;
352     cfm.status = BLE_SUCCESS;
353 
354     switch (tab_index) {
355         case HTS_IDX_TEM_MEAS_IND_CFG:
356             cccd_value     = le16toh(&p_param->value[0]);
357             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
358                               HTS_EVT_TEM_MEAS_INDICATION_ENABLE :\
359                               HTS_EVT_TEM_MEAS_INDICATION_DISABLE);
360             event.p_data   = (uint8_t *)&s_hts_env.hts_init.meas_interval;
361             event.length   = sizeof(uint16_t);
362             s_hts_env.meas_ind_cfg[conn_idx] = cccd_value;
363             break;
364 
365         case HTS_IDX_INTM_TEM_NTF_CFG:
366             cccd_value     = le16toh(&p_param->value[0]);
367             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
368                               HTS_EVT_INTM_TEM_NOTIFICATION_ENABLE :\
369                               HTS_EVT_INTM_TEM_NOTIFICATION_DISABLE);
370             s_hts_env.intm_tem_ntf_cfg[conn_idx] = cccd_value;
371             break;
372 
373         case HTS_IDX_MEAS_INTERVAL_VAL:
374             if (((le16toh(p_param->value) >= s_hts_env.hts_init.min_meas_interval_sup) && \
375                 (le16toh(p_param->value) <= s_hts_env.hts_init.max_meas_interval_sup)) || \
376                 (le16toh(p_param->value) == 0)) {
377                     event.evt_type = HTS_EVT_MEAS_INTERVAL_UPDATE;
378                     event.p_data   = p_param->value;
379                     event.length   = sizeof(uint16_t);
380                     s_hts_env.hts_init.meas_interval = le16toh(p_param->value);
381             } else {
382                 cfm.status = 0x80;    // Out of Range
383             }
384             break;
385 
386         case HTS_IDX_MEAS_INTERVAL_IND_CFG:
387             cccd_value     = le16toh(&p_param->value[0]);
388             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
389                               HTS_EVT_MEAS_INTREVAL_INDICATION_ENABLE :\
390                               HTS_EVT_MEAS_INTERVAL_INDICATION_DISABLE);
391             s_hts_env.meas_interval_ind_cfg[conn_idx] = cccd_value;
392             break;
393 
394         default:
395             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
396             break;
397     }
398 
399     if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && HTS_EVT_INVALID != event.evt_type &&
400         s_hts_env.hts_init.evt_handler) {
401         s_hts_env.hts_init.evt_handler(&event);
402     }
403 
404     ble_gatts_write_cfm(conn_idx, &cfm);
405 }
406 
407 /**
408  *****************************************************************************************
409  * @brief Handles reception of the cccd recover request.
410  *
411  * @param[in]: conn_idx:   Connection index
412  * @param[in]: handle:     The handle of cccd attribute.
413  * @param[in]: cccd_value: The value of cccd attribute.
414  *****************************************************************************************
415  */
hts_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)416 static void hts_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
417 {
418     uint16_t          tab_index  = 0;
419     hts_evt_t         event;
420 
421     if (!prf_is_cccd_value_valid(cccd_value)) {
422         return;
423     }
424 
425     tab_index  = prf_find_idx_by_handle(handle,
426                                         s_hts_env.start_hdl,
427                                         HTS_IDX_NB,
428                                         (uint8_t *)&s_hts_env.hts_init.char_mask);
429 
430     switch (tab_index) {
431         case HTS_IDX_TEM_MEAS_IND_CFG:
432             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
433                               HTS_EVT_TEM_MEAS_INDICATION_ENABLE :\
434                               HTS_EVT_TEM_MEAS_INDICATION_DISABLE);
435             s_hts_env.meas_ind_cfg[conn_idx] = cccd_value;
436             break;
437 
438         case HTS_IDX_INTM_TEM_NTF_CFG:
439             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
440                               HTS_EVT_INTM_TEM_NOTIFICATION_ENABLE :\
441                               HTS_EVT_INTM_TEM_NOTIFICATION_DISABLE);
442             s_hts_env.intm_tem_ntf_cfg[conn_idx] = cccd_value;
443             break;
444 
445         case HTS_IDX_MEAS_INTERVAL_IND_CFG:
446             event.evt_type = ((PRF_CLI_START_IND == cccd_value) ?\
447                               HTS_EVT_MEAS_INTREVAL_INDICATION_ENABLE :\
448                               HTS_EVT_MEAS_INTERVAL_INDICATION_DISABLE);
449             s_hts_env.meas_interval_ind_cfg[conn_idx] = cccd_value;
450             break;
451 
452         default:
453             event.evt_type = HTS_EVT_INVALID;
454             break;
455     }
456 
457     if (HTS_EVT_INVALID != event.evt_type && s_hts_env.hts_init.evt_handler) {
458         s_hts_env.hts_init.evt_handler(&event);
459     }
460 }
461 
462 /**
463  *****************************************************************************************
464  * @brief Function for encoding a Temperature Measurement.
465  *
466  * @param[in]  p_meas:           Pointer to temperature measurement value to be encoded.
467  * @param[out] p_encoded_buffer: Buffer where the encoded data will be written.
468  *
469  * @return Length of encoded data.
470   *****************************************************************************************
471  */
hts_htm_encoded(hts_meas_val_t * p_meas,uint8_t * p_encoded_buffer)472 static uint16_t hts_htm_encoded(hts_meas_val_t *p_meas, uint8_t *p_encoded_buffer)
473 {
474     uint8_t flags           = 0;
475     uint16_t length         = 1;
476     uint32_t encoded_sfloat = 0;
477 
478     if (HTS_TEMPERATURE_CELCIUS == s_hts_env.hts_init.temperature_units) {
479         p_meas->temp_convert_value.exponent = EXPONEBT_2;
480         p_meas->temp_convert_value.mantissa = p_meas->temp_original_value;
481     } else {
482         p_meas->temp_convert_value.exponent = EXPONEBT_2;
483         p_meas->temp_convert_value.mantissa = (MANTISSA_32 * MANTISSA_32_SCALE) +
484                                               ((p_meas->temp_original_value * SCALE_9) / DESCALE_5);
485         flags |= HTS_MEAS_FLAG_TEM_UINTS_BIT;
486     }
487 
488     encoded_sfloat             = ((p_meas->temp_convert_value.exponent <<  OFFSET_24) & 0xFF000000) |
489                                  ((p_meas->temp_convert_value.mantissa << 0)  & 0x00FFFFFF);
490     p_encoded_buffer[length++] = LO_UINT32_T(encoded_sfloat);
491     p_encoded_buffer[length++] = L2_UINT32_T(encoded_sfloat);
492     p_encoded_buffer[length++] = L3_UINT32_T(encoded_sfloat);
493     p_encoded_buffer[length++] = HI_UINT32_T(encoded_sfloat);
494 
495     if (s_hts_env.hts_init.time_stamp_present) {
496         flags |= HTS_MEAS_FLAG_TIME_STAMP_BIT;
497         p_encoded_buffer[length++] = LO_U16(p_meas->time_stamp.year);
498         p_encoded_buffer[length++] = HI_U16(p_meas->time_stamp.year);
499         p_encoded_buffer[length++] = p_meas->time_stamp.month;
500         p_encoded_buffer[length++] = p_meas->time_stamp.day;
501         p_encoded_buffer[length++] = p_meas->time_stamp.hour;
502         p_encoded_buffer[length++] = p_meas->time_stamp.min;
503         p_encoded_buffer[length++] = p_meas->time_stamp.sec;
504     }
505 
506     if ((s_hts_env.hts_init.char_mask & HTS_CHAR_TEM_TYPE_SUP) == 0) {
507         flags |= HTS_MEAS_FLAG_TEM_TYPE_BIT;
508         p_encoded_buffer[length++] = p_meas->temp_type;
509     }
510 
511     p_encoded_buffer[0] = flags;
512     return length;
513 }
514 
515 /*
516  * GLOBAL FUNCTION DEFINITIONS
517  ****************************************************************************************
518  */
hts_measurement_send(uint8_t conn_idx,hts_meas_val_t * p_meas)519 sdk_err_t hts_measurement_send(uint8_t conn_idx, hts_meas_val_t *p_meas)
520 {
521     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
522     uint8_t          encoded_hts_meas[HTS_TEM_MEAS_MAX_LEN];
523     uint16_t         length;
524     gatts_noti_ind_t hts_ind;
525 
526     length = hts_htm_encoded(p_meas, encoded_hts_meas);
527     if (HTS_TEMPERATURE_STABLE == p_meas->temp_meas_type) {
528         if (PRF_CLI_START_IND == (s_hts_env.meas_ind_cfg[conn_idx] & PRF_CLI_START_IND)) {
529             hts_ind.type   = BLE_GATT_INDICATION;
530             hts_ind.handle = prf_find_handle_by_idx(HTS_IDX_TEM_MEAS_VAL,
531                                                     s_hts_env.start_hdl,
532                                                     (uint8_t *)&s_hts_env.hts_init.char_mask);
533             hts_ind.length = length;
534             hts_ind.value  = encoded_hts_meas;
535             error_code     = ble_gatts_noti_ind(conn_idx, &hts_ind);
536         }
537     } else {
538         if (PRF_CLI_START_NTF == (s_hts_env.intm_tem_ntf_cfg[conn_idx] & PRF_CLI_START_NTF)) {
539             hts_ind.type   = BLE_GATT_NOTIFICATION;
540             hts_ind.handle = prf_find_handle_by_idx(HTS_IDX_INTM_TEM_VAL,
541                                                     s_hts_env.start_hdl,
542                                                     (uint8_t *)&s_hts_env.hts_init.char_mask);
543             hts_ind.length = length;
544             hts_ind.value  = encoded_hts_meas;
545             error_code     = ble_gatts_noti_ind(conn_idx, &hts_ind);
546         }
547     }
548     return error_code;
549 }
550 
hts_measurement_interval_send(uint8_t conn_idx)551 sdk_err_t hts_measurement_interval_send(uint8_t conn_idx)
552 {
553     sdk_err_t        error_code = SDK_ERR_IND_DISABLED;
554     gatts_noti_ind_t hts_ind;
555 
556     if (PRF_CLI_START_IND == (s_hts_env.meas_interval_ind_cfg[conn_idx] & PRF_CLI_START_IND)) {
557         hts_ind.type   = BLE_GATT_INDICATION;
558         hts_ind.handle = prf_find_handle_by_idx(HTS_IDX_MEAS_INTERVAL_VAL,
559                                                 s_hts_env.start_hdl,
560                                                 (uint8_t *)&s_hts_env.hts_init.char_mask);
561         hts_ind.length = sizeof(uint16_t);
562         hts_ind.value  = (uint8_t *)&s_hts_env.hts_init.meas_interval;
563         error_code     = ble_gatts_noti_ind(conn_idx, &hts_ind);
564     }
565     return error_code;
566 }
567 
hts_service_init(hts_init_t * p_hts_init)568 sdk_err_t hts_service_init(hts_init_t *p_hts_init)
569 {
570     sdk_err_t ret;
571     if (p_hts_init == NULL) {
572         return SDK_ERR_POINTER_NULL;
573     }
574 
575     ret = memcpy_s(&s_hts_env.hts_init, sizeof(hts_init_t), p_hts_init, sizeof(hts_init_t));
576     if (ret < 0) {
577         return ret;
578     }
579 
580     return ble_server_prf_add(&hts_prf_info);
581 }
582 
583