1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "py/builtin.h"
6 #include "py/mperrno.h"
7 #include "py/obj.h"
8 #include "py/runtime.h"
9 #include "py/stackctrl.h"
10 #include "ulog/ulog.h"
11 #if PY_BUILD_BLE
12 
13 #include "modble.h"
14 
15 #define LOG_TAG "ble"
16 
17 STATIC mp_obj_t cb_ble_event[BLE_EVENT_MAX] = { 0 };
18 
native_bt_host_gatts_handle_write(uint8_t * data,size_t len)19 void native_bt_host_gatts_handle_write(uint8_t *data, size_t len)
20 {
21     mp_obj_t cb_chara_written = cb_ble_event[BLE_EVENT_CHARA_WRITTEN];
22     if (cb_chara_written != mp_const_none && mp_obj_is_callable(cb_chara_written)) {
23         mp_obj_t data_bytes = mp_obj_new_bytes(data, len);
24         callback_to_python(cb_chara_written, data_bytes);
25     }
26 }
27 
py_ble_event_notify(int16_t handle,int32_t state)28 void py_ble_event_notify(int16_t handle, int32_t state)
29 {
30     mp_obj_t cb_net_status = cb_ble_event[BLE_EVENT_NET_STATUS];
31     if (cb_net_status != mp_const_none && mp_obj_is_callable(cb_net_status)) {
32         mp_obj_t data_dict = mp_obj_new_dict(2);
33         mp_obj_dict_store(data_dict, MP_ROM_QSTR(qstr_from_str("handle")), mp_obj_new_int(handle));
34         mp_obj_dict_store(data_dict, MP_ROM_QSTR(qstr_from_str("state")), mp_obj_new_int(state));
35 
36         callback_to_python(cb_net_status, data_dict);
37     }
38 }
39 
40 /**************************************************/
41 /************* For ble host operation *************/
42 /**************************************************/
ble_open(mp_obj_t device_name_in,mp_obj_t conn_num_max_in)43 STATIC mp_obj_t ble_open(mp_obj_t device_name_in, mp_obj_t conn_num_max_in)
44 {
45     amp_bt_host_adapter_init_t init = { 0 };
46     init.dev_name = mp_obj_str_get_str(device_name_in);
47     init.conn_num_max = mp_obj_get_int(conn_num_max_in);
48 
49     mp_int_t ret = py_bt_host_adapter_init(&init);
50     return MP_OBJ_NEW_SMALL_INT(ret);
51 }
52 MP_DEFINE_CONST_FUN_OBJ_2(ble_open_obj, ble_open);
53 
ble_startAdv(mp_obj_t * data)54 STATIC mp_obj_t ble_startAdv(mp_obj_t *data)
55 {
56     if (!mp_obj_is_dict_or_ordereddict(data)) {
57         LOGE(LOG_TAG, "%s  data type error,param type must be dict \r\n",
58                   __func__);
59         return mp_obj_new_int(MP_EINVAL);
60     }
61     amp_bt_host_adapter_adv_start_t adv_param = { 0 };
62 
63     mp_obj_t index = mp_obj_new_str_via_qstr("type", strlen("type"));
64     mp_obj_t value = mp_obj_dict_get(data, index);
65     if (mp_obj_is_int(value)) {
66         adv_param.type = mp_obj_get_int(value);
67     } else {
68         LOGE(LOG_TAG, "%s   key type value must be int \r\n",
69                   __func__);
70         return mp_obj_new_int(MP_EINVAL);
71     }
72 
73     index = mp_obj_new_str_via_qstr("adv_data", strlen("adv_data"));
74     value = mp_obj_dict_get(data, index);
75     if (mp_obj_is_str(value)) {
76         adv_param.adv_data = mp_obj_str_get_str(value);
77     } else {
78         LOGE(LOG_TAG, "%s   key adv_data value must be str \r\n",
79                   __func__);
80         return mp_obj_new_int(MP_EINVAL);
81     }
82 
83     index = mp_obj_new_str_via_qstr("scan_rsp_data", strlen("scan_rsp_data"));
84     value = mp_obj_dict_get(data, index);
85     if (mp_obj_is_str(value)) {
86         adv_param.scan_rsp_data = mp_obj_str_get_str(value);
87     } else {
88         LOGE(LOG_TAG, "%s   key scan_rsp_data value must be str \r\n",
89                   __func__);
90         return mp_obj_new_int(MP_EINVAL);
91     }
92 
93     index = mp_obj_new_str_via_qstr("interval_min", strlen("interval_min"));
94     value = mp_obj_dict_get(data, index);
95     if (mp_obj_is_int(value)) {
96         adv_param.interval_min = mp_obj_get_int(value);
97     } else {
98         LOGE(LOG_TAG, "%s   key interval_min value must be int \r\n",
99                   __func__);
100         return mp_obj_new_int(MP_EINVAL);
101     }
102 
103     index = mp_obj_new_str_via_qstr("interval_max", strlen("interval_max"));
104     value = mp_obj_dict_get(data, index);
105     if (mp_obj_is_int(value)) {
106         adv_param.interval_max = mp_obj_get_int(value);
107     } else {
108         LOGE(LOG_TAG, "%s   key interval_max value must be int \r\n",
109                   __func__);
110         return mp_obj_new_int(MP_EINVAL);
111     }
112 
113     index = mp_obj_new_str_via_qstr("channel_map", strlen("channel_map"));
114     value = mp_obj_dict_get(data, index);
115     if (mp_obj_is_int(value)) {
116         adv_param.channel_map = mp_obj_get_int(value);
117     } else {
118         LOGE(LOG_TAG, "%s   key channel_map value must be int \r\n",
119                   __func__);
120         return mp_obj_new_int(MP_EINVAL);
121     }
122 
123     mp_int_t ret = bt_host_adapter_start_adv(&adv_param);
124     return MP_OBJ_NEW_SMALL_INT(ret);
125 }
126 STATIC MP_DEFINE_CONST_FUN_OBJ_1(ble_startAdv_obj, ble_startAdv);
127 
ble_stopAdv(void)128 STATIC mp_obj_t ble_stopAdv(void)
129 {
130     mp_int_t ret = ble_stack_adv_stop();
131     return MP_OBJ_NEW_SMALL_INT(ret);
132 }
133 STATIC MP_DEFINE_CONST_FUN_OBJ_0(ble_stopAdv_obj, ble_stopAdv);
134 
ble_addService(mp_obj_t srv_in)135 STATIC mp_obj_t ble_addService(mp_obj_t srv_in)
136 {
137     mp_int_t ret = -1;
138     amp_bt_host_adapter_gatts_srvc_t service = { 0 };
139 
140     mp_obj_t s_uuid_obj = mp_obj_dict_get(srv_in, mp_obj_new_strn("uuid"));
141     service.s_uuid = mp_obj_str_get_str(s_uuid_obj);
142     service.attr_cnt += 1;
143 
144     mp_obj_t chara_list_obj = mp_obj_dict_get(srv_in, mp_obj_new_strn("charas"));
145 
146     size_t chara_num;
147     mp_obj_t *chara_items = NULL;
148     mp_obj_list_get(chara_list_obj, &chara_num, &chara_items);
149 
150     /* if we have service to add */
151     if (chara_num != 0) {
152         amp_bt_host_adapter_gatt_chars_t *chara_list = m_new0(amp_bt_host_adapter_gatt_chars_t, chara_num);
153         if (chara_list == NULL) {
154             mp_raise_OSError(MP_ENOMEM);
155             return mp_const_none;
156         } else {
157             service.chars = chara_list;
158         }
159 
160         /* parser chara_list */
161         for (size_t i = 0; i < chara_num; i++) {
162             /* parser each chara item */
163             size_t chara_items_num = 0;
164             mp_obj_t *chara_items_eles = NULL;
165             mp_obj_list_get(chara_items[i], &chara_items_num, &chara_items_eles);
166 
167             bool has_descr = false;
168             if (chara_items_num != 0) {
169                 chara_list->char_uuid = mp_obj_str_get_str(chara_items_eles[0]);
170                 chara_list->permission = mp_obj_str_get_str(chara_items_eles[1]);
171 
172                 if (mp_obj_is_str(chara_items_eles[2])) {
173                     chara_list->descr_uuid = mp_obj_str_get_str(chara_items_eles[2]);
174                     has_descr = true;
175                 } else {
176                     chara_list->descr_uuid = NULL;
177                 }
178 
179                 if (mp_obj_is_str(chara_items_eles[3])) {
180                     chara_list->descr_type = mp_obj_str_get_str(chara_items_eles[3]);
181                     has_descr = true;
182                 } else {
183                     chara_list->descr_type = NULL;
184                 }
185 
186                 if (has_descr == true) {
187                     service.attr_cnt += 3;
188                 } else {
189                     service.attr_cnt += 2;
190                 }
191 
192                 chara_list += 1;
193             } else {
194                 mp_raise_msg(&mp_type_ValueError, MP_ERROR_TEXT("Charas Null"));
195             }
196         }
197 
198         ret = bt_gatts_adapter_add_service(&service);
199         m_del(amp_bt_host_adapter_gatt_chars_t, service.chars, chara_num);
200     }
201 
202     return MP_OBJ_NEW_SMALL_INT(ret);
203 }
204 MP_DEFINE_CONST_FUN_OBJ_1(ble_addService_obj, ble_addService);
205 
ble_updateCharacter(mp_obj_t uuid_in,mp_obj_t data_in)206 STATIC mp_obj_t ble_updateCharacter(mp_obj_t uuid_in, mp_obj_t data_in)
207 {
208     const char *uuid = mp_obj_str_get_str(uuid_in);
209 
210     mp_buffer_info_t data;
211     mp_get_buffer_raise(data_in, &data, MP_BUFFER_READ);
212 
213     mp_int_t ret = bt_gatts_adapter_update_chars(uuid, data.buf, data.len);
214     return MP_OBJ_NEW_SMALL_INT(ret);
215 }
216 STATIC MP_DEFINE_CONST_FUN_OBJ_2(ble_updateCharacter_obj, ble_updateCharacter);
217 
ble_on(mp_obj_t event_in,mp_obj_t cb)218 STATIC mp_obj_t ble_on(mp_obj_t event_in, mp_obj_t cb)
219 {
220     mp_int_t event = mp_obj_get_int(event_in);
221     if (event >= BLE_EVENT_MAX) {
222         return mp_obj_new_int(MP_EINVAL);
223     }
224     cb_ble_event[event] = cb;
225     return mp_obj_new_int(0);
226 }
227 STATIC MP_DEFINE_CONST_FUN_OBJ_2(ble_on_obj, ble_on);
228 
229 STATIC const mp_rom_map_elem_t ble_module_globals_table[] = {
230     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ble) },
231     { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&ble_open_obj) },
232     { MP_ROM_QSTR(MP_QSTR_startAdv), MP_ROM_PTR(&ble_startAdv_obj) },
233     { MP_ROM_QSTR(MP_QSTR_stopAdv), MP_ROM_PTR(&ble_stopAdv_obj) },
234     { MP_ROM_QSTR(MP_QSTR_addService), MP_ROM_PTR(&ble_addService_obj) },
235     { MP_ROM_QSTR(MP_QSTR_updateCharacter), MP_ROM_PTR(&ble_updateCharacter_obj) },
236     { MP_ROM_QSTR(MP_QSTR_on), MP_ROM_PTR(&ble_on_obj) },
237 
238     { MP_ROM_QSTR(MP_QSTR_STATUS), MP_ROM_INT(BLE_EVENT_NET_STATUS) },
239     { MP_ROM_QSTR(MP_QSTR_CHARAWRITE), MP_ROM_INT(BLE_EVENT_CHARA_WRITTEN) },
240 };
241 STATIC MP_DEFINE_CONST_DICT(ble_module_globals, ble_module_globals_table);
242 
243 const mp_obj_module_t mp_module_ble = {
244     .base = { &mp_type_module },
245     .globals = (mp_obj_dict_t *)&ble_module_globals,
246 };
247 
248 MP_REGISTER_MODULE(MP_QSTR_ble, mp_module_ble, PY_BUILD_BLE);
249 
250 #endif
251