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