1 /*
2  * Copyright (C) 2019-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8 //#include <aos/osal_debug.h>
9 #include <aos/ble.h>
10 #include <yoc/hrs.h>
11 
12 #define TAG "HRS"
13 
14 enum {
15     HRS_IDX_SVC,
16     HRS_IDX_MEA_CHAR,
17     HRS_IDX_MEA_VAL,
18     HRS_IDX_MEA_CCC,
19     HRS_IDX_BODY_CHAR,
20     HRS_IDX_BODY_VAL,
21     HRS_IDX_CONTROL_CHAR,
22     HRS_IDX_CONTROL_VAL,
23 
24     HRS_IDX_MAX,
25 };
26 
27 static slist_t hrs_list = {NULL};
28 gatt_service hrs_service;
29 
30 //static struct bt_gatt_ccc_cfg_t ccc_data[2] = {};
31 
32 static gatt_attr_t hrs_attrs[HRS_IDX_MAX] = {
33     [HRS_IDX_SVC] = GATT_PRIMARY_SERVICE_DEFINE(UUID_HRS),
34     [HRS_IDX_MEA_CHAR] = GATT_CHAR_DEFINE(UUID_HRS_MEASUREMENT, GATT_CHRC_PROP_NOTIFY),
35     [HRS_IDX_MEA_VAL] = GATT_CHAR_VAL_DEFINE(UUID_HRS_MEASUREMENT, GATT_PERM_NONE),
36     [HRS_IDX_MEA_CCC] = GATT_CHAR_CCC_DEFINE(),
37     [HRS_IDX_BODY_CHAR] = GATT_CHAR_DEFINE(UUID_HRS_BODY_SENSOR, GATT_CHRC_PROP_READ),
38     [HRS_IDX_BODY_VAL]  = GATT_CHAR_VAL_DEFINE(UUID_HRS_BODY_SENSOR, GATT_PERM_NONE),
39     [HRS_IDX_CONTROL_CHAR] = GATT_CHAR_DEFINE(UUID_HRS_CONTROL_POINT, GATT_CHRC_PROP_WRITE),
40     [HRS_IDX_CONTROL_VAL] = GATT_CHAR_VAL_DEFINE(UUID_HRS_CONTROL_POINT, GATT_PERM_NONE),
41 };
42 
get_hrs(uint16_t hrs_svc_handle)43 static inline hrs_t *get_hrs(uint16_t hrs_svc_handle)
44 {
45     slist_t *tmp;
46     hrs_t *node;
47 
48     slist_for_each_entry_safe(&hrs_list, tmp, node, hrs_t, next) {
49         if (node->hrs_svc_handle == hrs_svc_handle) {
50             return node;
51         }
52     }
53 
54     return NULL;
55 }
56 
57 
58 
event_char_read(ble_event_en event,void * event_data)59 static void event_char_read(ble_event_en event, void *event_data)
60 {
61     evt_data_gatt_char_read_t *e = (evt_data_gatt_char_read_t *)event_data;
62 
63     hrs_t *hrs = get_hrs(e->char_handle - HRS_IDX_MEA_VAL);
64 
65     if (hrs == NULL) {
66         return;
67     }
68 
69     LOGD(TAG, "event_char_read conn handle %d char handle 0x%04x, len %d, offset %d",
70          e->conn_handle, e->char_handle, e->len, e->offset);
71 
72     e->data = &hrs->hrs_mea_level;
73     e->len = 1;
74 }
75 
76 
conn_change(ble_event_en event,void * event_data)77 static void conn_change(ble_event_en event, void *event_data)
78 {
79     evt_data_gap_conn_change_t *e = (evt_data_gap_conn_change_t *)event_data;
80 
81     slist_t *tmp;
82     hrs_t *node;
83     slist_for_each_entry_safe(&hrs_list, tmp, node, hrs_t, next) {
84         if (e->connected == CONNECTED) {
85             node->conn_handle = e->conn_handle;
86         } else {
87             node->conn_handle = 0xFFFF;
88         }
89     }
90 }
91 
92 
93 
event_char_ccc_change(ble_event_en event,void * event_data)94 static void event_char_ccc_change(ble_event_en event, void *event_data)
95 {
96     evt_data_gatt_char_ccc_change_t *e = (evt_data_gatt_char_ccc_change_t *)event_data;
97     hrs_t *hrs = get_hrs(e->char_handle - HRS_IDX_MEA_CCC);
98 
99     if (hrs == NULL) {
100         return;
101     }
102 
103     hrs->mea_ccc = e->ccc_value;
104 }
105 
106 
107 
hrs_event_callback(ble_event_en event,void * event_data)108 static int hrs_event_callback(ble_event_en event, void *event_data)
109 {
110     switch (event) {
111         case EVENT_GAP_CONN_CHANGE:
112             conn_change(event, event_data);
113             break;
114 
115         case EVENT_GATT_CHAR_READ:
116             event_char_read(event, event_data);
117             break;
118 
119         case EVENT_GATT_CHAR_CCC_CHANGE:
120             event_char_ccc_change(event, event_data);
121             break;
122 
123         default:
124             break;
125     }
126 
127     return 0;
128 }
129 
130 static ble_event_cb_t ble_cb = {
131     .callback = hrs_event_callback,
132 };
133 
hrs_init(hrs_t * hrs)134 hrs_handle_t hrs_init(hrs_t *hrs)
135 {
136     int ret = 0;
137 
138     if (hrs == NULL) {
139         return NULL;
140     }
141 
142     ret = ble_stack_event_register(&ble_cb);
143 
144     if (ret) {
145         goto err;
146     }
147 
148     ret = ble_stack_gatt_registe_service(&hrs_service,hrs_attrs, BLE_ARRAY_NUM(hrs_attrs));
149 
150     if (ret < 0) {
151         goto err;
152     }
153 
154     hrs->conn_handle = 0xFFFF;
155     hrs->hrs_svc_handle = ret;
156     hrs->hrs_mea_level = 0xFF;
157     hrs->mea_ccc = 0;
158 
159     slist_add(&hrs->next, &hrs_list);
160     return hrs;
161 
162 err:
163     return NULL;
164 }
165 
166 
hrs_measure_level_update(hrs_handle_t handle,uint8_t * data,uint8_t length)167 int hrs_measure_level_update(hrs_handle_t handle, uint8_t *data, uint8_t length)
168 {
169     if (handle == NULL) {
170         return -BLE_STACK_ERR_NULL;
171     }
172 
173     hrs_t *hrs = handle;
174 
175     if (data[1] != hrs->hrs_mea_level) {
176         hrs->hrs_mea_level = data[1];
177 
178         if (hrs->conn_handle != 0xFFFF && hrs->mea_ccc == CCC_VALUE_NOTIFY) {
179             LOGD(TAG, "data:%x", data[1]);
180             return ble_stack_gatt_notificate(hrs->conn_handle,
181                                              hrs->hrs_svc_handle + HRS_IDX_MEA_VAL,
182                                              data, length);
183         }
184     }
185 
186     return 0;
187 }
188 
189 
190 
191 
192