1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 //#include <aos/osal_debug.h>
5 #include <aos/ble.h>
6 #include <yoc/bas.h>
7 
8 #define TAG "BAS"
9 
10 enum {
11     BAS_IDX_SVC,
12     BAS_IDX_LEVEL_CHAR,
13     BAS_IDX_LEVEL_VAL,
14     BAS_IDX_LEVEL_CCC,
15 
16     BAS_IDX_MAX,
17 };
18 
19 static slist_t bas_list = {NULL};
20 
21 gatt_service bas_service;
22 
23 static gatt_attr_t bas_attrs[BAS_IDX_MAX] = {
24     [BAS_IDX_SVC] = GATT_PRIMARY_SERVICE_DEFINE(UUID_BAS),
25     [BAS_IDX_LEVEL_CHAR] = GATT_CHAR_DEFINE(UUID_BAS_BATTERY_LEVEL,  GATT_CHRC_PROP_READ | GATT_CHRC_PROP_NOTIFY),
26     [BAS_IDX_LEVEL_VAL] = GATT_CHAR_VAL_DEFINE(UUID_BAS_BATTERY_LEVEL, GATT_PERM_READ),
27     [BAS_IDX_LEVEL_CCC] = GATT_CHAR_CCC_DEFINE(),
28 };
29 
get_bas(uint16_t bas_svc_handle)30 static inline bas_t *get_bas(uint16_t bas_svc_handle)
31 {
32     slist_t *tmp;
33     bas_t *node;
34 
35     slist_for_each_entry_safe(&bas_list, tmp, node, bas_t, next) {
36         if (node->bas_svc_handle == bas_svc_handle) {
37             return node;
38         }
39     }
40 
41     return NULL;
42 }
43 
event_char_read(ble_event_en event,void * event_data)44 static void event_char_read(ble_event_en event, void *event_data)
45 {
46     evt_data_gatt_char_read_t *e = (evt_data_gatt_char_read_t *)event_data;
47 
48     bas_t *bas = get_bas(e->char_handle - BAS_IDX_LEVEL_VAL);
49 
50     if (bas == NULL) {
51         return;
52     }
53 
54     e->data = &bas->battery_level;
55     e->len = 1;
56 }
57 
conn_change(ble_event_en event,void * event_data)58 static void conn_change(ble_event_en event, void *event_data)
59 {
60     evt_data_gap_conn_change_t *e = (evt_data_gap_conn_change_t *)event_data;
61 
62     slist_t *tmp;
63     bas_t *node;
64     slist_for_each_entry_safe(&bas_list, tmp, node, bas_t, next) {
65         if (e->connected == CONNECTED) {
66             node->conn_handle = e->conn_handle;
67         } else {
68             node->conn_handle = 0xFFFF;
69         }
70     }
71 }
72 
event_char_ccc_change(ble_event_en event,void * event_data)73 static void event_char_ccc_change(ble_event_en event, void *event_data)
74 {
75     evt_data_gatt_char_ccc_change_t *e = (evt_data_gatt_char_ccc_change_t *)event_data;
76     bas_t *bas = get_bas(e->char_handle - BAS_IDX_LEVEL_CCC);
77 
78     if (bas == NULL) {
79         return;
80     }
81 
82     bas->ccc = e->ccc_value;
83 }
84 
bas_event_callback(ble_event_en event,void * event_data)85 static int bas_event_callback(ble_event_en event, void *event_data)
86 {
87     switch (event) {
88         case EVENT_GAP_CONN_CHANGE:
89             conn_change(event, event_data);
90             break;
91 
92         case EVENT_GATT_CHAR_READ:
93             event_char_read(event, event_data);
94             break;
95 
96         case EVENT_GATT_CHAR_CCC_CHANGE:
97             event_char_ccc_change(event, event_data);
98             break;
99 
100         default:
101             break;
102     }
103 
104     return 0;
105 }
106 
107 static ble_event_cb_t ble_cb = {
108     .callback = bas_event_callback,
109 };
110 
111 
bas_init(bas_t * bas)112 bas_handle_t bas_init(bas_t *bas)
113 {
114     int ret = 0;
115 
116     if (bas == NULL) {
117         return NULL;
118     }
119 
120     ret = ble_stack_event_register(&ble_cb);
121 
122     if (ret) {
123         goto err;
124     }
125 
126     ret = ble_stack_gatt_registe_service(&bas_service, bas_attrs, BLE_ARRAY_NUM(bas_attrs));
127 
128     if (ret < 0) {
129         goto err;
130     }
131 
132     bas->conn_handle = 0xFFFF;
133     bas->bas_svc_handle = ret;
134     bas->battery_level = 0xFF;
135     bas->ccc = 0;
136 
137     slist_add(&bas->next, &bas_list);
138     return bas;
139 
140 err:
141     ///free(bas);
142     return NULL;
143 }
144 
bas_level_update(bas_handle_t handle,uint8_t level)145 int bas_level_update(bas_handle_t handle, uint8_t level)
146 {
147     if (handle == NULL) {
148         return -BLE_STACK_ERR_NULL;
149     }
150 
151     bas_t *bas = handle;
152 
153     if (level != bas->battery_level) {
154         bas->battery_level = level;
155 
156         if (bas->conn_handle != 0xFFFF && bas->ccc == CCC_VALUE_NOTIFY) {
157             return ble_stack_gatt_notificate(bas->conn_handle,
158                                              bas->bas_svc_handle + BAS_IDX_LEVEL_VAL,
159                                              &level, 1);
160         }
161     }
162 
163     return 0;
164 }
165 
166