1 /** @file
2 * @brief HTS Service sample
3 */
4
5 /*
6 * Copyright (c) 2020 SixOctets Systems
7 * Copyright (c) 2019 Aaron Tsui <aaron.tsui@outlook.com>
8 *
9 * SPDX-License-Identifier: Apache-2.0
10 */
11
12 #include <stdio.h>
13 #include <stddef.h>
14 #include <string.h>
15 #include <errno.h>
16
17 #include <zephyr/kernel.h>
18 #include <zephyr/drivers/sensor.h>
19 #include <zephyr/sys/printk.h>
20 #include <zephyr/sys/byteorder.h>
21
22 #include <zephyr/bluetooth/bluetooth.h>
23 #include <zephyr/bluetooth/hci.h>
24 #include <zephyr/bluetooth/conn.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/bluetooth/gatt.h>
27
28 #ifdef CONFIG_TEMP_NRF5
29 static const struct device *temp_dev = DEVICE_DT_GET_ANY(nordic_nrf_temp);
30 #else
31 static const struct device *temp_dev;
32 #endif
33
34 static uint8_t simulate_htm;
35 static uint8_t indicating;
36 static struct bt_gatt_indicate_params ind_params;
37
htmc_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)38 static void htmc_ccc_cfg_changed(const struct bt_gatt_attr *attr,
39 uint16_t value)
40 {
41 simulate_htm = (value == BT_GATT_CCC_INDICATE) ? 1 : 0;
42 }
43
indicate_cb(struct bt_conn * conn,struct bt_gatt_indicate_params * params,uint8_t err)44 static void indicate_cb(struct bt_conn *conn,
45 struct bt_gatt_indicate_params *params, uint8_t err)
46 {
47 printk("Indication %s\n", err != 0U ? "fail" : "success");
48 }
49
indicate_destroy(struct bt_gatt_indicate_params * params)50 static void indicate_destroy(struct bt_gatt_indicate_params *params)
51 {
52 printk("Indication complete\n");
53 indicating = 0U;
54 }
55
56 /* Health Thermometer Service Declaration */
57 BT_GATT_SERVICE_DEFINE(hts_svc,
58 BT_GATT_PRIMARY_SERVICE(BT_UUID_HTS),
59 BT_GATT_CHARACTERISTIC(BT_UUID_HTS_MEASUREMENT, BT_GATT_CHRC_INDICATE,
60 BT_GATT_PERM_NONE, NULL, NULL, NULL),
61 BT_GATT_CCC(htmc_ccc_cfg_changed,
62 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
63 /* more optional Characteristics */
64 );
65
hts_init(void)66 void hts_init(void)
67 {
68 if (temp_dev == NULL || !device_is_ready(temp_dev)) {
69 printk("no temperature device; using simulated data\n");
70 temp_dev = NULL;
71 } else {
72 printk("temp device is %p, name is %s\n", temp_dev,
73 temp_dev->name);
74 }
75 }
76
hts_indicate(void)77 void hts_indicate(void)
78 {
79 /* Temperature measurements simulation */
80 struct sensor_value temp_value;
81
82 if (simulate_htm) {
83 static uint8_t htm[5];
84 static double temperature = 20U;
85 uint32_t mantissa;
86 uint8_t exponent;
87 int r;
88
89 if (indicating) {
90 return;
91 }
92
93 if (!temp_dev) {
94 temperature++;
95 if (temperature == 30U) {
96 temperature = 20U;
97 }
98
99 goto gatt_indicate;
100 }
101
102 r = sensor_sample_fetch(temp_dev);
103 if (r) {
104 printk("sensor_sample_fetch failed return: %d\n", r);
105 }
106
107 r = sensor_channel_get(temp_dev, SENSOR_CHAN_DIE_TEMP,
108 &temp_value);
109 if (r) {
110 printk("sensor_channel_get failed return: %d\n", r);
111 }
112
113 temperature = sensor_value_to_double(&temp_value);
114
115 gatt_indicate:
116 printf("temperature is %gC\n", temperature);
117
118 mantissa = (uint32_t)(temperature * 100);
119 exponent = (uint8_t)-2;
120
121 htm[0] = 0; /* temperature in celsius */
122 sys_put_le24(mantissa, (uint8_t *)&htm[1]);
123 htm[4] = exponent;
124
125 ind_params.attr = &hts_svc.attrs[2];
126 ind_params.func = indicate_cb;
127 ind_params.destroy = indicate_destroy;
128 ind_params.data = &htm;
129 ind_params.len = sizeof(htm);
130
131 if (bt_gatt_indicate(NULL, &ind_params) == 0) {
132 indicating = 1U;
133 }
134 }
135 }
136