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 #define TEMP_SENSOR_CHAN SENSOR_CHAN_DIE_TEMP
31 #elif DT_HAS_ALIAS(dht0)
32 static const struct device *temp_dev = DEVICE_DT_GET(DT_ALIAS(dht0));
33 #define TEMP_SENSOR_CHAN SENSOR_CHAN_AMBIENT_TEMP
34 #else
35 static const struct device *temp_dev;
36 #define TEMP_SENSOR_CHAN SENSOR_CHAN_AMBIENT_TEMP
37 #endif
38 
39 static uint8_t simulate_htm;
40 static uint8_t indicating;
41 static struct bt_gatt_indicate_params ind_params;
42 
htmc_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)43 static void htmc_ccc_cfg_changed(const struct bt_gatt_attr *attr,
44 				 uint16_t value)
45 {
46 	simulate_htm = (value == BT_GATT_CCC_INDICATE) ? 1 : 0;
47 }
48 
indicate_cb(struct bt_conn * conn,struct bt_gatt_indicate_params * params,uint8_t err)49 static void indicate_cb(struct bt_conn *conn,
50 			struct bt_gatt_indicate_params *params, uint8_t err)
51 {
52 	printk("Indication %s\n", err != 0U ? "fail" : "success");
53 }
54 
indicate_destroy(struct bt_gatt_indicate_params * params)55 static void indicate_destroy(struct bt_gatt_indicate_params *params)
56 {
57 	printk("Indication complete\n");
58 	indicating = 0U;
59 }
60 
61 /* Health Thermometer Service Declaration */
62 BT_GATT_SERVICE_DEFINE(hts_svc,
63 	BT_GATT_PRIMARY_SERVICE(BT_UUID_HTS),
64 	BT_GATT_CHARACTERISTIC(BT_UUID_HTS_MEASUREMENT, BT_GATT_CHRC_INDICATE,
65 			       BT_GATT_PERM_NONE, NULL, NULL, NULL),
66 	BT_GATT_CCC(htmc_ccc_cfg_changed,
67 		    BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
68 	/* more optional Characteristics */
69 );
70 
hts_init(void)71 void hts_init(void)
72 {
73 	if (temp_dev == NULL || !device_is_ready(temp_dev)) {
74 		printk("no temperature device; using simulated data\n");
75 		temp_dev = NULL;
76 	} else {
77 		printk("temp device is %p, name is %s\n", temp_dev,
78 		       temp_dev->name);
79 	}
80 }
81 
hts_indicate(void)82 void hts_indicate(void)
83 {
84 	/* Temperature measurements simulation */
85 	struct sensor_value temp_value;
86 
87 	if (simulate_htm) {
88 		static uint8_t htm[5];
89 		static double temperature = 20U;
90 		uint32_t mantissa;
91 		uint8_t exponent;
92 		int r;
93 
94 		if (indicating) {
95 			return;
96 		}
97 
98 		if (!temp_dev) {
99 			temperature++;
100 			if (temperature == 30U) {
101 				temperature = 20U;
102 			}
103 
104 			goto gatt_indicate;
105 		}
106 
107 		r = sensor_sample_fetch(temp_dev);
108 		if (r) {
109 			printk("sensor_sample_fetch failed return: %d\n", r);
110 		}
111 
112 		r = sensor_channel_get(temp_dev, TEMP_SENSOR_CHAN, &temp_value);
113 		if (r) {
114 			printk("sensor_channel_get failed return: %d\n", r);
115 		}
116 
117 		temperature = sensor_value_to_double(&temp_value);
118 
119 gatt_indicate:
120 		printf("temperature is %gC\n", temperature);
121 
122 		mantissa = (uint32_t)(temperature * 100);
123 		exponent = (uint8_t)-2;
124 
125 		htm[0] = 0; /* temperature in celsius */
126 		sys_put_le24(mantissa, (uint8_t *)&htm[1]);
127 		htm[4] = exponent;
128 
129 		ind_params.attr = &hts_svc.attrs[2];
130 		ind_params.func = indicate_cb;
131 		ind_params.destroy = indicate_destroy;
132 		ind_params.data = &htm;
133 		ind_params.len = sizeof(htm);
134 
135 		if (bt_gatt_indicate(NULL, &ind_params) == 0) {
136 			indicating = 1U;
137 		}
138 	}
139 }
140