diff --git "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/README.md" "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/README.md" index 9ea8865d7222711c18be7d86252565e15038926f..93cb48befa413deb1581c7d47bd0c281e645b8a8 100644 --- "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/README.md" +++ "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/README.md" @@ -28,5 +28,7 @@ - [quecgnss - 内置GNSS相关功能](./quecgnss.md) - [gnss - GNSS相关功能](./gnss.md) - [securedata - 安全数据区相关功能](./securedata.md) +- [ble- 低功耗蓝牙相关功能](./ble.md) +- [bt- 经典蓝牙相关功能](./bt.md) diff --git "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/app_fota.md" "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/app_fota.md" index e1bb5cdf95cc84aa7294bdb221d16739b01f8db4..e2ca42dc23a381b98788320a5b3ec50412d05779 100644 --- "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/app_fota.md" +++ "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/app_fota.md" @@ -69,7 +69,7 @@ fota.bulk_download(info=[]) **返回值描述**: -- 返回下载失败的列表,类型为list。 +- 下载失败时返回下载失败的列表,类型为list。下载成功时返回空。 **示例**: diff --git "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/ble.md" "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/ble.md" new file mode 100644 index 0000000000000000000000000000000000000000..9104a6430acd074bc1778d13c922d4bd2d5028c0 --- /dev/null +++ "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/ble.md" @@ -0,0 +1,2328 @@ +# ble-低功耗蓝牙相关功能 + +`ble`模块用于提供BLE GATT Server (从机)与 Client (主机)功能,基于BLE 4.2协议。 + +**示例**: + +```python +#BLE Server + +import ble +import utime + + +BLE_GATT_SYS_SERVICE = 0 # 0-删除系统默认的GAP和GATT服务 1-保留系统默认的GAP和GATT服务 +BLE_SERVER_HANDLE = 0 +_BLE_NAME = "Quectel_ble" + + +event_dict = { + 'BLE_START_STATUS_IND': 0, # ble start + 'BLE_STOP_STATUS_IND': 1, # ble stop + 'BLE_CONNECT_IND': 16, # ble connect + 'BLE_DISCONNECT_IND': 17, # ble disconnect + 'BLE_UPDATE_CONN_PARAM_IND': 18, # ble update connection parameter + 'BLE_SCAN_REPORT_IND': 19, # ble gatt client scan and report other devices + 'BLE_GATT_MTU': 20, # ble connection mtu + 'BLE_GATT_RECV_WRITE_IND': 21, # when ble client write characteristic value or descriptor,server get the notice + 'BLE_GATT_RECV_READ_IND': 22, # when ble client read characteristic value or descriptor,server get the notice + 'BLE_GATT_RECV_NOTIFICATION_IND': 23, # client receive notification + 'BLE_GATT_RECV_INDICATION_IND': 24, # client receive indication + 'BLE_GATT_SEND_END': 25, # server send notification,and receive send end notice +} + +class EVENT(dict): + def __getattr__(self, item): + return self[item] + + def __setattr__(self, key, value): + raise ValueError("{} is read-only.".format(key)) + + +event = EVENT(event_dict) + + +def ble_callback(args): + global BLE_GATT_SYS_SERVICE + global BLE_SERVER_HANDLE + event_id = args[0] + status = args[1] + print('[ble_callback]: event_id={}, status={}'.format(event_id, status)) + + if event_id == event.BLE_START_STATUS_IND: # ble start + if status == 0: + print('[callback] BLE start success.') + mac = ble.getPublicAddr() + if mac != -1 and len(mac) == 6: + addr = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]) + print('BLE public addr : {}'.format(addr)) + ret = ble_gatt_set_name() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_set_param() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_set_data() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_set_rsp_data() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_add_service() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_add_characteristic() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_add_characteristic_value() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_add_characteristic_desc() + if ret != 0: + ble_gatt_close() + return + ret = ble_gatt_add_service_complete() + if ret != 0: + ble_gatt_close() + return + if BLE_GATT_SYS_SERVICE == 0: + BLE_SERVER_HANDLE = 1 + else: + BLE_SERVER_HANDLE = 16 + ret = ble_adv_start() + if ret != 0: + ble_gatt_close() + return + else: + print('[callback] BLE start failed.') + elif event_id == event.BLE_STOP_STATUS_IND: # ble stop + if status == 0: + print('[callback] ble stop successful.') + ble_status = ble.getStatus() + print('ble status is {}'.format(ble_status)) + ble_gatt_server_release() + else: + print('[callback] ble stop failed.') + elif event_id == event.BLE_CONNECT_IND: # ble connect + if status == 0: + print('[callback] ble connect successful.') + connect_id = args[2] + addr = args[3] + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('[callback] connect_id = {}, addr = {}'.format(connect_id, addr_str)) + + ret = ble_gatt_send_notification() + if ret == 0: + print('[callback] ble_gatt_send_notification successful.') + else: + print('[callback] ble_gatt_send_notification failed.') + ble_gatt_close() + return + else: + print('[callback] ble connect failed.') + elif event_id == event.BLE_DISCONNECT_IND: # ble disconnect + if status == 0: + print('[callback] ble disconnect successful.') + connect_id = args[2] + addr = args[3] + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + ble_gatt_close() + print('[callback] connect_id = {}, addr = {}'.format(connect_id, addr_str)) + else: + print('[callback] ble disconnect failed.') + ble_gatt_close() + return + elif event_id == event.BLE_UPDATE_CONN_PARAM_IND: # ble update connection parameter + if status == 0: + print('[callback] ble update parameter successful.') + connect_id = args[2] + max_interval = args[3] + min_interval = args[4] + latency = args[5] + timeout = args[6] + print('[callback] connect_id={},max_interval={},min_interval={},latency={},timeout={}'.format(connect_id, max_interval, min_interval, latency, timeout)) + else: + print('[callback] ble update parameter failed.') + ble_gatt_close() + return + elif event_id == event.BLE_GATT_MTU: # ble connection mtu + if status == 0: + print('[callback] ble connect mtu successful.') + handle = args[2] + ble_mtu = args[3] + print('[callback] handle = {:#06x}, ble_mtu = {}'.format(handle, ble_mtu)) + else: + print('[callback] ble connect mtu failed.') + ble_gatt_close() + return + elif event_id == event.BLE_GATT_RECV_WRITE_IND: + if status == 0: + print('[callback] ble recv successful.') + data_len = args[2] + data = args[3] # 这是一个bytearray + attr_handle = args[4] + short_uuid = args[5] + long_uuid = args[6] # 这是一个bytearray + print('len={}, data:{}'.format(data_len, data)) + print('attr_handle = {:#06x}'.format(attr_handle)) + print('short uuid = {:#06x}'.format(short_uuid)) + print('long uuid = {}'.format(long_uuid)) + else: + print('[callback] ble recv failed.') + ble_gatt_close() + return + elif event_id == event.BLE_GATT_RECV_READ_IND: + if status == 0: + print('[callback] ble recv read successful.') + data_len = args[2] + data = args[3] # 这是一个bytearray + attr_handle = args[4] + short_uuid = args[5] + long_uuid = args[6] # 这是一个bytearray + print('len={}, data:{}'.format(data_len, data)) + print('attr_handle = {:#06x}'.format(attr_handle)) + print('short uuid = {:#06x}'.format(short_uuid)) + print('long uuid = {}'.format(long_uuid)) + else: + print('[callback] ble recv read failed.') + ble_gatt_close() + return + elif event_id == event.BLE_GATT_SEND_END: + if status == 0: + print('[callback] ble send data successful.') + else: + print('[callback] ble send data failed.') + else: + print('unknown event id.') + + +def ble_gatt_server_init(cb): + ret = ble.serverInit(cb) + if ret != 0: + print('ble_gatt_server_init failed.') + return -1 + print('ble_gatt_server_init success.') + return 0 + + +def ble_gatt_server_release(): + ret = ble.serverRelease() + if ret != 0: + print('ble_gatt_server_release failed.') + return -1 + print('ble_gatt_server_release success.') + return 0 + + +def ble_gatt_open(): + ret = ble.gattStart() + if ret != 0: + print('ble_gatt_open failed.') + return -1 + print('ble_gatt_open success.') + return 0 + + +def ble_gatt_close(): + ret = ble.gattStop() + if ret != 0: + print('ble_gatt_close failed.') + return -1 + print('ble_gatt_close success.') + return 0 + + +def ble_gatt_set_name(): + code = 0 # utf8 + name = _BLE_NAME + ret = ble.setLocalName(code, name) + if ret != 0: + print('ble_gatt_set_name failed.') + return -1 + print('ble_gatt_set_name success.') + return 0 + + +def ble_gatt_set_param(): + min_adv = 0x300 + max_adv = 0x320 + adv_type = 0 # 可连接的非定向广播,默认选择 + addr_type = 0 # 公共地址 + channel = 0x07 + filter_strategy = 0 # 处理所有设备的扫描和连接请求 + discov_mode = 2 + no_br_edr = 1 + enable_adv = 1 + ret = ble.setAdvParam(min_adv, max_adv, adv_type, addr_type, channel, filter_strategy, discov_mode, no_br_edr, enable_adv) + if ret != 0: + print('ble_gatt_set_param failed.') + return -1 + print('ble_gatt_set_param success.') + return 0 + + +def ble_gatt_set_data(): + adv_data = [0x02, 0x01, 0x05] + ble_name = _BLE_NAME + length = len(ble_name) + 1 + adv_data.append(length) + adv_data.append(0x09) + name_encode = ble_name.encode('UTF-8') + for i in range(0, len(name_encode)): + adv_data.append(name_encode[i]) + print('set adv_data:{}'.format(adv_data)) + data = bytearray(adv_data) + ret = ble.setAdvData(data) + if ret != 0: + print('ble_gatt_set_data failed.') + return -1 + print('ble_gatt_set_data success.') + return 0 + + +def ble_gatt_set_rsp_data(): + adv_data = [] + ble_name = _BLE_NAME + length = len(ble_name) + 1 + adv_data.append(length) + adv_data.append(0x09) + name_encode = ble_name.encode('UTF-8') + for i in range(0, len(name_encode)): + adv_data.append(name_encode[i]) + print('set adv_rsp_data:{}'.format(adv_data)) + data = bytearray(adv_data) + ret = ble.setAdvRspData(data) + if ret != 0: + print('ble_gatt_set_rsp_data failed.') + return -1 + print('ble_gatt_set_rsp_data success.') + return 0 + + +def ble_gatt_add_service(): + primary = 1 + server_id = 0x01 + uuid_type = 1 # 短UUID + uuid_s = 0x180F + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + ret = ble.addService(primary, server_id, uuid_type, uuid_s, uuid_l) + if ret != 0: + print('ble_gatt_add_service failed.') + return -1 + print('ble_gatt_add_service success.') + return 0 + + +def ble_gatt_add_characteristic(): + server_id = 0x01 + chara_id = 0x01 + chara_prop = 0x02 | 0x10 | 0x20 # 0x02-可读 0x10-通知 0x20-指示 + uuid_type = 1 # 短UUID + uuid_s = 0x2A19 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + ret = ble.addChara(server_id, chara_id, chara_prop, uuid_type, uuid_s, uuid_l) + if ret != 0: + print('ble_gatt_add_characteristic failed.') + return -1 + print('ble_gatt_add_characteristic success.') + return 0 + + +def ble_gatt_add_characteristic_value(): + data = [] + server_id = 0x01 + chara_id = 0x01 + permission = 0x0001 | 0x0002 + uuid_type = 1 # 短UUID + uuid_s = 0x2A19 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + for i in range(0, 244): + data.append(0x00) + value = bytearray(data) + ret = ble.addCharaValue(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) + if ret != 0: + print('ble_gatt_add_characteristic_value failed.') + return -1 + print('ble_gatt_add_characteristic_value success.') + return 0 + + +def ble_gatt_add_characteristic_desc(): + data = [0x00, 0x00] + server_id = 0x01 + chara_id = 0x01 + permission = 0x0001 | 0x0002 + uuid_type = 1 # 短UUID + uuid_s = 0x2902 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + value = bytearray(data) + ret = ble.addCharaDesc(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) + if ret != 0: + print('ble_gatt_add_characteristic_desc failed.') + return -1 + print('ble_gatt_add_characteristic_desc success.') + return 0 + + +def ble_gatt_send_notification(): + global BLE_SERVER_HANDLE + data = [0x39, 0x39, 0x39, 0x39, 0x39] # 测试数据 + conn_id = 0 + attr_handle = BLE_SERVER_HANDLE + 2 + value = bytearray(data) + ret = ble.sendNotification(conn_id, attr_handle, value) + if ret != 0: + print('ble_gatt_send_notification failed.') + return -1 + print('ble_gatt_send_notification success.') + return 0 + + +def ble_gatt_add_service_complete(): + global BLE_GATT_SYS_SERVICE + ret = ble.addOrClearService(1, BLE_GATT_SYS_SERVICE) + if ret != 0: + print('ble_gatt_add_service_complete failed.') + return -1 + print('ble_gatt_add_service_complete success.') + return 0 + + +def ble_gatt_clear_service_complete(): + global BLE_GATT_SYS_SERVICE + ret = ble.addOrClearService(0, BLE_GATT_SYS_SERVICE) + if ret != 0: + print('ble_gatt_clear_service_complete failed.') + return -1 + print('ble_gatt_clear_service_complete success.') + return 0 + + +def ble_adv_start(): + ret = ble.advStart() + if ret != 0: + print('ble_adv_start failed.') + return -1 + print('ble_adv_start success.') + return 0 + + +def ble_adv_stop(): + ret = ble.advStop() + if ret != 0: + print('ble_adv_stop failed.') + return -1 + print('ble_adv_stop success.') + return 0 + + +def main(): + ret = ble_gatt_server_init(ble_callback) + if ret == 0: + ret = ble_gatt_open() + if ret != 0: + return -1 + else: + return -1 + count = 0 + while True: + utime.sleep(1) + count += 1 + if count % 5 == 0: + print('##### BLE running, count = {}......'.format(count)) + if count > 120: + count = 0 + print('!!!!! stop BLE now !!!!!') + ble_gatt_close() + return 0 + + +if __name__ == '__main__': + main() + +``` + +```python +#BLE Client + +import ble +import utime +import _thread +import checkNet +from queue import Queue + +PROJECT_NAME = "QuecPython_BLE_Client_Example" +PROJECT_VERSION = "1.0.0" +checknet = checkNet.CheckNetwork(PROJECT_NAME, PROJECT_VERSION) + +event_dict = { + 'BLE_START_STATUS_IND': 0, # ble start + 'BLE_STOP_STATUS_IND': 1, # ble stop + 'BLE_CONNECT_IND': 16, # ble connect + 'BLE_DISCONNECT_IND': 17, # ble disconnect + 'BLE_UPDATE_CONN_PARAM_IND': 18, # ble update connection parameter + 'BLE_SCAN_REPORT_IND': 19, # ble gatt client scan and report other devices + 'BLE_GATT_MTU': 20, # ble connection mtu + 'BLE_GATT_RECV_NOTIFICATION_IND': 23, # client receive notification + 'BLE_GATT_RECV_INDICATION_IND': 24, # client receive indication + 'BLE_GATT_START_DISCOVER_SERVICE_IND': 26, # start discover service + 'BLE_GATT_DISCOVER_SERVICE_IND': 27, # discover service + 'BLE_GATT_DISCOVER_CHARACTERISTIC_DATA_IND': 28, # discover characteristic + 'BLE_GATT_DISCOVER_CHARA_DESC_IND': 29, # discover characteristic descriptor + 'BLE_GATT_CHARA_WRITE_WITH_RSP_IND': 30, # write characteristic value with response + 'BLE_GATT_CHARA_WRITE_WITHOUT_RSP_IND': 31, # write characteristic value without response + 'BLE_GATT_CHARA_READ_IND': 32, # read characteristic value by handle + 'BLE_GATT_CHARA_READ_BY_UUID_IND': 33, # read characteristic value by uuid + 'BLE_GATT_CHARA_MULTI_READ_IND': 34, # read multiple characteristic value + 'BLE_GATT_DESC_WRITE_WITH_RSP_IND': 35, # write characteristic descriptor + 'BLE_GATT_DESC_READ_IND': 36, # read characteristic descriptor + 'BLE_GATT_ATT_ERROR_IND': 37, # attribute error +} + +gatt_status_dict = { + 'BLE_GATT_IDLE' : 0, + 'BLE_GATT_DISCOVER_SERVICE': 1, + 'BLE_GATT_DISCOVER_INCLUDES': 2, + 'BLE_GATT_DISCOVER_CHARACTERISTIC': 3, + 'BLE_GATT_WRITE_CHARA_VALUE': 4, + 'BLE_GATT_WRITE_CHARA_DESC': 5, + 'BLE_GATT_READ_CHARA_VALUE': 6, + 'BLE_GATT_READ_CHARA_DESC': 7, +} + +class EVENT(dict): + def __getattr__(self, item): + return self[item] + + def __setattr__(self, key, value): + raise ValueError("{} is read-only.".format(key)) + + +class BleClient(object): + def __init__(self): + self.ble_server_name = 'Quectel_ble' #目标设备ble名称 + self.connect_id = 0 + self.connect_addr = 0 + self.gatt_statue = 0 + self.discover_service_mode = 0 # 0-discover all service, 1-discover service by uuid + + self.scan_param = { + 'scan_mode' : 1, # 积极扫描 + 'interval' : 0x100, + 'scan_window' : 0x50, + 'filter_policy' : 0, + 'local_addr_type' : 0, + } + + self.scan_report_info = { + 'event_type' : 0, + 'name' : '', + 'addr_type' : 0, + 'addr' : 0, # 初始化时,用0表示无效值,实际存放bytearray + 'rssi' : 0, + 'data_len' : 0, + 'raw_data' : 0, + } + + self.target_service = { + 'start_handle' : 0, + 'end_handle' : 0, + 'uuid_type' : 1, # 短uuid + 'short_uuid' : 0x180F, # 电池电量服务 + 'long_uuid' : bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + } + + self.characteristic_list = [] + self.descriptor_list = [] + self.characteristic_count = 0 # ql_ble_gatt_chara_count + self.chara_descriptor_count = 0 # ql_ble_gatt_chara_desc_count + self.characteristic_index = 0 # ql_ble_gatt_chara_desc_index + self.current_chara_index = 0 # ql_ble_gatt_cur_chara + self.current_desc_index = 0 # ql_ble_gatt_chara_cur_desc + self.ble_short_uuid_pair_len = 7 + self.ble_long_uuid_pair_len = 21 + + ret = ble.clientInit(self.ble_client_callback) + if ret != 0: + print('ble client initialize failed.') + raise ValueError("BLE Client Init failed.") + else: + print('ble client initialize successful.') + print('') + + @staticmethod + def gatt_open(): + ret = ble.gattStart() + if ret != 0: + print('ble open failed.') + else: + print('ble open successful.') + print('') + return ret + + @staticmethod + def gatt_close(): + ret = ble.gattStop() + if ret != 0: + print('ble close failed.') + else: + print('ble close successful.') + print('') + return ret + + @staticmethod + def gatt_get_status(): + return ble.getStatus() + + @staticmethod + def release(): + ret = ble.clientRelease() + if ret != 0: + print('ble client release failed.') + else: + print('ble client release successful.') + print('') + return ret + + def set_scan_param(self): + scan_mode = self.scan_param['scan_mode'] + interval = self.scan_param['interval'] + scan_time = self.scan_param['scan_window'] + filter_policy = self.scan_param['filter_policy'] + local_addr_type = self.scan_param['local_addr_type'] + ret = ble.setScanParam(scan_mode, interval, scan_time, filter_policy, local_addr_type) + if ret != 0: + print('ble client set scan-parameters failed.') + else: + print('ble client set scan-parameters successful.') + print('') + return ret + + @staticmethod + def start_scan(): + ret = ble.scanStart() + if ret != 0: + print('ble client scan failed.') + else: + print('ble client scan successful.') + print('') + return ret + + @staticmethod + def stop_scan(): + ret = ble.scanStop() + if ret != 0: + print('ble client failed to stop scanning.') + else: + print('ble client scan stopped successfully.') + print('') + return ret + + def connect(self): + print('start to connect.....') + addr_type = self.scan_report_info['addr_type'] + addr = self.scan_report_info['addr'] + if addr != 0 and len(addr) == 6: + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('addr_type : {}, addr : {}'.format(addr_type, addr_str)) + ret = ble.connect(addr_type, addr) + if ret != 0: + print('ble client connect failed.') + else: + print('ble client connect successful.') + print('') + return ret + + def cancel_connect(self): + ret = ble.cancelConnect(self.scan_report_info['addr']) + if ret != 0: + print('ble client cancel connect failed.') + else: + print('ble client cancel connect successful.') + print('') + return ret + + def disconnect(self): + ret = ble.disconnect(self.connect_id) + if ret != 0: + print('ble client disconnect failed.') + else: + print('ble client disconnect successful.') + print('') + return ret + + def discover_all_service(self): + ret = ble.discoverAllService(self.connect_id) + if ret != 0: + print('ble client discover all service failed.') + else: + print('ble client discover all service successful.') + print('') + return ret + + def discover_service_by_uuid(self): + connect_id = self.connect_id + uuid_type = self.target_service['uuid_type'] + short_uuid = self.target_service['short_uuid'] + long_uuid = self.target_service['long_uuid'] + ret = ble.discoverByUUID(connect_id, uuid_type, short_uuid, long_uuid) + if ret != 0: + print('ble client discover service by uuid failed.') + else: + print('ble client discover service by uuid successful.') + print('') + return ret + + def discover_all_includes(self): + connect_id = self.connect_id + start_handle = self.target_service['start_handle'] + end_handle = self.target_service['end_handle'] + ret = ble.discoverAllIncludes(connect_id, start_handle, end_handle) + if ret != 0: + print('ble client discover all includes failed.') + else: + print('ble client discover all includes successful.') + print('') + return ret + + def discover_all_characteristic(self): + connect_id = self.connect_id + start_handle = self.target_service['start_handle'] + end_handle = self.target_service['end_handle'] + ret = ble.discoverAllChara(connect_id, start_handle, end_handle) + if ret != 0: + print('ble client discover all characteristic failed.') + else: + print('ble client discover all characteristic successful.') + print('') + return ret + + def discover_all_characteristic_descriptor(self): + connect_id = self.connect_id + index = self.characteristic_index + start_handle = self.characteristic_list[index]['value_handle'] + 1 + + if self.characteristic_index == (self.characteristic_count - 1): + end_handle = self.target_service['end_handle'] + print('[1]start_handle = {:#06x}, end_handle = {:#06x}'.format(start_handle - 1, end_handle)) + ret = ble.discoverAllCharaDesc(connect_id, start_handle, end_handle) + else: + end_handle = self.characteristic_list[index+1]['handle'] - 1 + print('[2]start_handle = {:#06x}, end_handle = {:#06x}'.format(start_handle - 1, end_handle)) + ret = ble.discoverAllCharaDesc(connect_id, start_handle, end_handle) + self.characteristic_index += 1 + if ret != 0: + print('ble client discover all characteristic descriptor failed.') + else: + print('ble client discover all characteristic descriptor successful.') + print('') + return ret + + def read_characteristic_by_uuid(self): + connect_id = self.connect_id + index = self.current_chara_index # 根据需要改变该值 + start_handle = self.characteristic_list[index]['handle'] + end_handle = self.characteristic_list[index]['value_handle'] + uuid_type = 1 + short_uuid = self.characteristic_list[index]['short_uuid'] + long_uuid = bytearray([0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]) + + ret = ble.readCharaByUUID(connect_id, start_handle, end_handle, uuid_type, short_uuid, long_uuid) + if ret != 0: + print('ble client read characteristic by uuid failed.') + else: + print('ble client read characteristic by uuid successful.') + print('') + return ret + + def read_characteristic_by_handle(self): + connect_id = self.connect_id + index = self.current_chara_index # 根据需要改变该值 + handle = self.characteristic_list[index]['value_handle'] + offset = 0 + is_long = 0 + + ret = ble.readCharaByHandle(connect_id, handle, offset, is_long) + if ret != 0: + print('ble client read characteristic by handle failed.') + else: + print('ble client read characteristic by handle successful.') + print('') + return ret + + def read_characteristic_descriptor(self): + connect_id = self.connect_id + index = self.current_desc_index # 根据需要改变该值 + handle = self.descriptor_list[index]['handle'] + print('handle = {:#06x}'.format(handle)) + is_long = 0 + ret = ble.readCharaDesc(connect_id, handle, is_long) + if ret != 0: + print('ble client read characteristic descriptor failed.') + else: + print('ble client read characteristic descriptor successful.') + print('') + return ret + + def write_characteristic(self): + connect_id = self.connect_id + index = self.current_chara_index # 根据需要改变该值 + handle = self.characteristic_list[index]['value_handle'] + offset = 0 + is_long = 0 + data = bytearray([0x40, 0x00]) + print('value_handle = {:#06x}, uuid = {:#06x}'.format(handle, self.characteristic_list[index]['short_uuid'])) + ret = ble.writeChara(connect_id, handle, offset, is_long, data) + if ret != 0: + print('ble client write characteristic failed.') + else: + print('ble client read characteristic successful.') + print('') + return ret + + def write_characteristic_no_rsp(self): + connect_id = self.connect_id + index = self.current_chara_index # 根据需要改变该值 + handle = self.characteristic_list[index]['value_handle'] + data = bytearray([0x20, 0x00]) + print('value_handle = {:#06x}, uuid = {:#06x}'.format(handle, self.characteristic_list[index]['short_uuid'])) + ret = ble.writeCharaNoRsp(connect_id, handle, data) + if ret != 0: + print('ble client write characteristic no rsp failed.') + else: + print('ble client read characteristic no rsp successful.') + print('') + return ret + + def write_characteristic_descriptor(self): + connect_id = self.connect_id + index = self.current_desc_index # 根据需要改变该值 + handle = self.descriptor_list[index]['handle'] + data = bytearray([0x01, 0x02]) + print('handle = {:#06x}'.format(handle)) + + ret = ble.writeCharaDesc(connect_id, handle, data) + if ret != 0: + print('ble client write characteristic descriptor failed.') + else: + print('ble client read characteristic descriptor successful.') + print('') + return ret + + @staticmethod + def ble_client_callback(args): + global msg_queue + msg_queue.put(args) + + +def ble_gatt_client_event_handler(): + global msg_queue + old_time = 0 + + while True: + cur_time = utime.localtime() + timestamp = "{:02d}:{:02d}:{:02d}".format(cur_time[3], cur_time[4], cur_time[5]) + if cur_time[5] != old_time and cur_time[5] % 5 == 0: + old_time = cur_time[5] + print('[{}]event handler running.....'.format(timestamp)) + print('') + msg = msg_queue.get() # 没有消息时会阻塞在这 + # print('msg : {}'.format(msg)) + event_id = msg[0] + status = msg[1] + + if event_id == event.BLE_START_STATUS_IND: + print('') + print('event_id : BLE_START_STATUS_IND, status = {}'.format(status)) + if status == 0: + print('BLE start successful.') + ble_status = ble_client.gatt_get_status() + if ble_status == 0: + print('BLE Status : stopped.') + break + elif ble_status == 1: + print('BLE Status : started.') + else: + print('get ble status error.') + ble_client.gatt_close() + break + + ret = ble_client.set_scan_param() + if ret != 0: + ble_client.gatt_close() + break + ret = ble_client.start_scan() + if ret != 0: + ble_client.gatt_close() + break + else: + print('BLE start failed.') + break + elif event_id == event.BLE_STOP_STATUS_IND: + print('') + print('event_id : BLE_STOP_STATUS_IND, status = {}'.format(status)) + if status == 0: + print('ble stop successful.') + else: + print('ble stop failed.') + break + elif event_id == event.BLE_CONNECT_IND: + print('') + print('event_id : BLE_CONNECT_IND, status = {}'.format(status)) + if status == 0: + ble_client.connect_id = msg[2] + ble_client.connect_addr = msg[3] + addr = ble_client.connect_addr + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('connect_id : {:#x}, connect_addr : {}'.format(ble_client.connect_id, addr_str)) + else: + print('ble connect failed.') + break + elif event_id == event.BLE_DISCONNECT_IND: + print('') + print('event_id : BLE_DISCONNECT_IND, status = {}'.format(status)) + if status == 0: + ble_client.connect_id = msg[2] + ble_client.connect_addr = msg[3] + addr = ble_client.connect_addr + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('connect_id : {:#x}, connect_addr : {}'.format(ble_client.connect_id, addr_str)) + else: + print('ble disconnect failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_UPDATE_CONN_PARAM_IND: + print('') + print('event_id : BLE_UPDATE_CONN_PARAM_IND, status = {}'.format(status)) + if status == 0: + connect_id = msg[2] + max_interval = msg[3] + min_interval = msg[4] + latency = msg[5] + timeout = msg[6] + print('connect_id={},max_interval={},min_interval={},latency={},timeout={}'.format(connect_id,max_interval,min_interval,latency,timeout)) + else: + print('ble update parameter failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_SCAN_REPORT_IND: + if status == 0: + # print(' ble scan successful.') + + ble_client.scan_report_info['event_type'] = msg[2] + ble_client.scan_report_info['name'] = msg[3] + ble_client.scan_report_info['addr_type'] = msg[4] + ble_client.scan_report_info['addr'] = msg[5] + ble_client.scan_report_info['rssi'] = msg[6] + ble_client.scan_report_info['data_len'] = msg[7] + ble_client.scan_report_info['raw_data'] = msg[8] + + device_name = ble_client.scan_report_info['name'] + addr = ble_client.scan_report_info['addr'] + rssi = ble_client.scan_report_info['rssi'] + addr_type = ble_client.scan_report_info['addr_type'] + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + if device_name != '' and rssi != 0: + print('name: {}, addr: {}, rssi: {}, addr_type: {}'.format(device_name, addr_str, rssi, addr_type)) + print('raw_data: {}'.format(ble_client.scan_report_info['raw_data'])) + + if device_name == ble_client.ble_server_name: # 扫描到目标设备后就停止扫描 + ret = ble_client.stop_scan() + if ret != 0: + ble_client.gatt_close() + break + + ret = ble_client.connect() + if ret != 0: + ble_client.gatt_close() + break + else: + print('ble scan failed.') + ret = ble_client.stop_scan() + if ret != 0: + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_MTU: + print('') + print('event_id : BLE_GATT_MTU, status = {}'.format(status)) + if status == 0: + handle = msg[2] + ble_mtu = msg[3] + print('handle = {:#06x}, ble_mtu = {}'.format(handle, ble_mtu)) + else: + print('ble connect mtu failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_RECV_NOTIFICATION_IND: + print('') + print('event_id : BLE_GATT_RECV_NOTIFICATION_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('len={}, data:{}'.format(data_len, data)) + handle = (data[1] << 8) | data[0] + print('handle = {:#06x}'.format(handle)) + else: + print('ble receive notification failed.') + break + elif event_id == event.BLE_GATT_RECV_INDICATION_IND: + print('') + print('event_id : BLE_GATT_RECV_INDICATION_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('len={}, data:{}'.format(data_len, data)) + else: + print('ble receive indication failed.') + break + elif event_id == event.BLE_GATT_START_DISCOVER_SERVICE_IND: + print('') + print('event_id : BLE_GATT_START_DISCOVER_SERVICE_IND, status = {}'.format(status)) + if status == 0: + ble_client.characteristic_count = 0 + ble_client.chara_descriptor_count = 0 + ble_client.characteristic_index = 0 + ble_client.gatt_statue = gatt_status.BLE_GATT_DISCOVER_SERVICE + + if ble_client.discover_service_mode == 0: + print('execute the function discover_all_service.') + ret = ble_client.discover_all_service() + else: + print('execute the function discover_service_by_uuid.') + ret = ble_client.discover_service_by_uuid() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + else: + print('ble start discover service failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_DISCOVER_SERVICE_IND: + print('') + print('event_id : BLE_GATT_DISCOVER_SERVICE_IND, status = {}'.format(status)) + if status == 0: + start_handle = msg[2] + end_handle = msg[3] + short_uuid = msg[4] + print('start_handle = {:#06x}, end_handle = {:#06x}, short_uuid = {:#06x}'.format(start_handle, end_handle, short_uuid)) + if ble_client.discover_service_mode == 0: # discover service all + if ble_client.target_service['short_uuid'] == short_uuid: # 查找到所有服务后,按指定uuid查找特征值 + ble_client.target_service['start_handle'] = start_handle + ble_client.target_service['end_handle'] = end_handle + ble_client.gatt_statue = gatt_status.BLE_GATT_DISCOVER_CHARACTERISTIC + print('execute the function discover_all_characteristic.') + ret = ble_client.discover_all_characteristic() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + else: + ble_client.target_service['start_handle'] = start_handle + ble_client.target_service['end_handle'] = end_handle + ble_client.gatt_statue = gatt_status.BLE_GATT_DISCOVER_CHARACTERISTIC + print('execute the function discover_all_characteristic.') + ret = ble_client.discover_all_characteristic() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + else: + print('ble discover service failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_DISCOVER_CHARACTERISTIC_DATA_IND: + print('') + print('event_id : BLE_GATT_DISCOVER_CHARACTERISTIC_DATA_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + pair_len = data[0] + print('pair_len={}, len={}, data:{}'.format(pair_len, data_len, data)) + if data_len > 0: + if ble_client.gatt_statue == gatt_status.BLE_GATT_DISCOVER_CHARACTERISTIC: + i = 0 + while i < (data_len - 1) / pair_len: + chara_dict = { + 'handle': (data[i * pair_len + 2] << 8) | data[i * pair_len + 1], + 'properties': data[i * pair_len + 3], + 'value_handle': (data[i * pair_len + 5] << 8) | data[i * pair_len + 4], + 'uuid_type': 0, + 'short_uuid': 0x0000, + 'long_uuid': bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + } + print('handle={:#06x}, properties={:#x}, value_handle={:#06x}'.format(chara_dict['handle'], chara_dict['properties'], chara_dict['value_handle'])) + if pair_len == ble_client.ble_short_uuid_pair_len: + chara_dict['uuid_type'] = 1 + chara_dict['short_uuid'] = (data[i * pair_len + 7] << 8) | data[i * pair_len + 6] + print('short_uuid:{:#06x}'.format(chara_dict['short_uuid'])) + elif pair_len == ble_client.ble_long_uuid_pair_len: + start_index = i * pair_len + 6 + end_index = start_index + 16 + chara_dict['uuid_type'] = 0 + chara_dict['long_uuid'] = data[start_index : end_index] + print('long_uuid:{}'.format(chara_dict['long_uuid'])) + i += 1 + if ble_client.characteristic_count < 5: + ble_client.characteristic_list.append(chara_dict) + ble_client.characteristic_count = len(ble_client.characteristic_list) + print('characteristic_list len = {}'.format(ble_client.characteristic_count)) + elif ble_client.gatt_statue == gatt_status.BLE_GATT_READ_CHARA_VALUE: + print('data_len = {}'.format(data_len)) + print('pay_load = {:02x},{:02x},{:02x},{:02x}'.format(data[0], data[1], data[2], data[3])) + else: + print('ble discover characteristic failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_DISCOVER_CHARA_DESC_IND: + print('') + print('event_id : BLE_GATT_DISCOVER_CHARA_DESC_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + fmt = data[0] + print('fmt={}, len={}, data:{}'.format(fmt, data_len, data)) + if data_len > 0: + i = 0 + if fmt == 1: # 16 bit uuid + while i < (data_len - 1) / 4: + descriptor_dict = { + 'handle': (data[i * 4 + 2] << 8) | data[i * 4 + 1], + 'short_uuid': (data[i * 4 + 4] << 8) | data[i * 4 + 3], + } + print('handle={:#06x}, uuid={:#06x}'.format(descriptor_dict['handle'], descriptor_dict['short_uuid'])) + i += 1 + if ble_client.chara_descriptor_count < 5: + ble_client.descriptor_list.append(descriptor_dict) + ble_client.chara_descriptor_count = len(ble_client.descriptor_list) + print('descriptor_list len = {}'.format(ble_client.chara_descriptor_count)) + if ble_client.characteristic_index == ble_client.characteristic_count: + print('execute the function read_characteristic_by_uuid.') + # ble_client.gatt_statue = gatt_status.BLE_GATT_WRITE_CHARA_VALUE + # ret = ble_client.write_characteristic() + # ret = ble_client.write_characteristic_no_rsp() + + ble_client.gatt_statue = gatt_status.BLE_GATT_READ_CHARA_VALUE + ret = ble_client.read_characteristic_by_uuid() + # ret = ble_client.read_characteristic_by_handle() + + # ble_client.gatt_statue = gatt_status.BLE_GATT_READ_CHARA_DESC + # ret = ble_client.read_characteristic_descriptor() + + # ble_client.gatt_statue = gatt_status.BLE_GATT_WRITE_CHARA_DESC + # ret = ble_client.write_characteristic_descriptor() + else: + print('execute the function discover_all_characteristic_descriptor.') + ret = ble_client.discover_all_characteristic_descriptor() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + else: + print('ble discover characteristic descriptor failed.') + ble_client.gatt_close() + break + elif event_id == event.BLE_GATT_CHARA_WRITE_WITH_RSP_IND: + print('') + print('event_id : BLE_GATT_CHARA_WRITE_WITH_RSP_IND, status = {}'.format(status)) + if status == 0: + if ble_client.gatt_statue == gatt_status.BLE_GATT_WRITE_CHARA_VALUE: + pass + elif ble_client.gatt_statue == gatt_status.BLE_GATT_WRITE_CHARA_DESC: + pass + else: + print('ble write characteristic with response failed.') + break + elif event_id == event.BLE_GATT_CHARA_WRITE_WITHOUT_RSP_IND: + print('') + print('event_id : BLE_GATT_CHARA_WRITE_WITHOUT_RSP_IND, status = {}'.format(status)) + if status == 0: + print('write characteristic value without response successful.') + else: + print('write characteristic value without response failed.') + break + elif event_id == event.BLE_GATT_CHARA_READ_IND: + print('') + # read characteristic value by handle + print('event_id : BLE_GATT_CHARA_READ_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('data_len = {}, data : {}'.format(data_len, data)) + if ble_client.gatt_statue == gatt_status.BLE_GATT_READ_CHARA_VALUE: + # print('read characteristic value by handle.') + pass + else: + print('ble read characteristic failed.') + break + elif event_id == event.BLE_GATT_CHARA_READ_BY_UUID_IND: + print('') + # read characteristic value by uuid + print('event_id : BLE_GATT_CHARA_READ_BY_UUID_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('data_len = {}, data : {}'.format(data_len, data)) + handle = (data[2] << 8) | data[1] + print('handle = {:#06x}'.format(handle)) + else: + print('ble read characteristic by uuid failed.') + break + elif event_id == event.BLE_GATT_CHARA_MULTI_READ_IND: + print('') + # read multiple characteristic value + print('event_id : BLE_GATT_CHARA_MULTI_READ_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('data_len = {}, data : {}'.format(data_len, data)) + else: + print('ble read multiple characteristic by uuid failed.') + break + elif event_id == event.BLE_GATT_DESC_WRITE_WITH_RSP_IND: + print('') + print('event_id : BLE_GATT_DESC_WRITE_WITH_RSP_IND, status = {}'.format(status)) + if status == 0: + if ble_client.gatt_statue == gatt_status.BLE_GATT_WRITE_CHARA_VALUE: + pass + elif ble_client.gatt_statue == gatt_status.BLE_GATT_WRITE_CHARA_DESC: + pass + else: + print('ble write characteristic descriptor failed.') + break + elif event_id == event.BLE_GATT_DESC_READ_IND: + print('') + # read characteristic descriptor + print('event_id : BLE_GATT_DESC_READ_IND, status = {}'.format(status)) + if status == 0: + data_len = msg[2] + data = msg[3] + print('data_len = {}, data : {}'.format(data_len, data)) + if ble_client.gatt_statue == gatt_status.BLE_GATT_READ_CHARA_DESC: + # print('read characteristic descriptor.') + pass + else: + print('ble read characteristic descriptor failed.') + break + elif event_id == event.BLE_GATT_ATT_ERROR_IND: + print('') + print('event_id : BLE_GATT_ATT_ERROR_IND, status = {}'.format(status)) + if status == 0: + errcode = msg[2] + print('errcode = {:#06x}'.format(errcode)) + if ble_client.gatt_statue == gatt_status.BLE_GATT_DISCOVER_INCLUDES: + ble_client.gatt_statue = gatt_status.BLE_GATT_DISCOVER_CHARACTERISTIC + print('execute the function discover_all_characteristic.') + ret = ble_client.discover_all_characteristic() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + elif ble_client.gatt_statue == gatt_status.BLE_GATT_DISCOVER_CHARACTERISTIC: + ble_client.gatt_statue = gatt_status.BLE_GATT_IDLE + print('execute the function discover_all_characteristic_descriptor.') + ret = ble_client.discover_all_characteristic_descriptor() + if ret != 0: + print('Execution result: Failed.') + ble_client.gatt_close() + break + else: + print('ble attribute error.') + ble_client.gatt_close() + break + else: + print('unknown event id : {}.'.format(event_id)) + + # ble_client.release() + + +event = EVENT(event_dict) +gatt_status = EVENT(gatt_status_dict) +msg_queue = Queue(50) +ble_client = BleClient() + + +def main(): + checknet.poweron_print_once() + print('create client event handler task.') + _thread.start_new_thread(ble_gatt_client_event_handler, ()) + # ble.setScanFilter(0) # 关闭扫描过滤功能 + ret = ble_client.gatt_open() + if ret != 0: + return -1 + + count = 0 + while True: + utime.sleep(1) + count += 1 + cur_time = utime.localtime() + timestamp = "{:02d}:{:02d}:{:02d}".format(cur_time[3], cur_time[4], cur_time[5]) + if count % 5 == 0: + print('[{}] BLE Client running, count = {}......'.format(timestamp, count)) + print('') + if count > 130: # 这里设置计数是为了程序运行一会自己退出,方便测试,实际根据用户需要来处理 + count = 0 + print('!!!!! stop BLE Client now !!!!!') + ble_status = ble_client.gatt_get_status() + if ble_status == 1: + ble_client.gatt_close() + ble_client.release() + break + else: + ble_status = ble_client.gatt_get_status() + if ble_status == 0: # stopped + print('BLE connection has been disconnected.') + ble_client.release() + break + +if __name__ == '__main__': + main() + +``` + +**注意**: + +当前仅EC200U/EC600U/EG915U/EG912U平台支持`ble`功能。 + +## 初始化相关功能 + +### ble.gattStart + +```python +ble.gattStart() +``` + +开启 BLE GATT 功能。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.gattStop + +```python +ble.gattStop() +``` + +关闭 BLE GATT 功能。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.getStatus + +```python +ble.getStatus() +``` + +获取 BLE 的状态。 + +**返回值描述:** + +- 0 - BLE处于停止状态。1 - BLE处于开启状态。-1 - 获取状态失败。 + +### ble.getPublicAddr + +```python +ble.getPublicAddr() +``` + +获取 BLE 协议栈正在使用的公共地址。该接口需要在BLE已经初始化完成并启动成功后才能调用,比如在回调中收到 event_id 为0的事件之后,即 start 成功后,去调用。 + +**返回值描述:** + +- 执行成功返回bytearray类型的BLE地址,大小6个byte,失败返回整型-1。 + +**示例**: + +```python +>>> addr = ble.getPublicAddr() +>>> print(addr) +b'\xdb3\xf5\x1ek\xac' +>>> mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) +>>> print('mac = [{}]'.format(mac)) +mac = [ac:6b:1e:f5:33:db] +``` + +**注意**: + +如果有出厂设置默认蓝牙MAC地址,那么该接口获取的MAC地址和默认的蓝牙MAC地址是一致的;如果没有设置,那么该接口获取的地址,将是蓝牙启动后随机生成的静态地址,因此在每次重新上电运行蓝牙功能时都不相同。 + +## BLE Server相关功能 + +### ble.serverInit + +```python +ble.serverInit(user_cb) +``` + +初始化 BLE Server 并注册回调函数。 + +**参数描述:** + +- `user_cb`-回调函数,类型为function。回调函数参数含义:args[0] 固定表示event_id,args[1]固定 表示状态,0表示成功,非0表示失败。回调函数的参数个数并不是固定2个,而是根据第一个参数args[0]来决定的,下表中列出了不同事件ID对应的参数个数及说明。 + +| event_id | 参数个数 | 参数说明 | +| :------: | :------: | ------------------------------------------------------------ | +| 0 | 2 | args[0] :event_id,表示 BT/BLE start
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 1 | 2 | args[0] :event_id,表示 BT/BLE stop
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 16 | 4 | args[0] :event_id,表示 BLE connect
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id
args[3] :addr,BT/BLE address,bytearray类型数据 | +| 17 | 4 | args[0] :event_id,表示 BLE disconnect
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id,
args[3] :addr,BT/BLE address,bytearray类型数据 | +| 18 | 7 | args[0] :event_id,表示 BLE update connection parameter
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id
args[3] :max_interval,最大的间隔,间隔:1.25ms,取值范围:6-3200,时间范围:7.5ms\ ~ 4s
args[4] :min_interval,最小的间隔,间隔:1.25ms,取值范围:6-3200,时间范围:7.5ms\ ~ 4s
args[5] :latency,从机忽略连接状态事件的时间。需满足:(1+latecy)\*max_interval\*2\*1.25args[6] :timeout,没有交互,超时断开时间,间隔:10ms,取值范围:10-3200ms,时间范围:100ms ~ 32s | +| 20 | 4 | args[0] :event_id,表示 BLE connection mtu
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :handle
args[3] :mtu值 | +| 21 | 7 | args[0] :event_id,表示 BLE server : when ble client write characteristic value or descriptor,server get the notice
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,获取数据的长度
args[3] :data,一个数组,存放获取的数据
args[4] :attr_handle,属性句柄,整型值
args[5] :short_uuid,整型值
args[6] :long_uuid,一个16字节数组,存放长UUID | +| 22 | 7 | args[0] :event_id,表示 server : when ble client read characteristic value or descriptor,server get the notice
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,获取数据的长度
args[3] :data,一个数组,存放获取的数据
args[4] :attr_handle,属性句柄,整型值
args[5] :short_uuid,整型值
args[6] :long_uuid,一个16字节数组,存放长UUID | +| 25 | 2 | args[0] :event_id,表示 server send notification,and recieve send end notice
args[1] :status,表示操作的状态,0-成功,非0-失败 | + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_callback(args): + event_id = args[0] + status = args[1] + print('[ble_callback]: event_id={}, status={}'.format(event_id, status)) + + if event_id == 0: # ble start + if status == 0: + print('[callback] BLE start success.') + else: + print('[callback] BLE start failed.') + elif event_id == 1: # ble stop + if status == 0: + print('[callback] ble stop successful.') + else: + print('[callback] ble stop failed.') + elif event_id == 16: # ble connect + if status == 0: + print('[callback] ble connect successful.') + connect_id = args[2] + addr = args[3] # 这是一个bytearray类型 + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('[callback] connect_id = {}, addr = {}'.format(connect_id, addr_str)) + else: + print('[callback] ble connect failed.') + elif event_id == 17: # ble disconnect + if status == 0: + print('[callback] ble disconnect successful.') + connect_id = args[2] + addr = args[3] # 这是一个bytearray类型 + addr_str = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]) + print('[callback] connect_id = {}, addr = {}'.format(connect_id, addr_str)) + else: + print('[callback] ble disconnect failed.') + ble.gattStop() + return + elif event_id == 18: # ble update connection parameter + if status == 0: + print('[callback] ble update parameter successful.') + connect_id = args[2] + max_interval = args[3] + min_interval = args[4] + latency = args[5] + timeout = args[6] + print('[callback] connect_id={},max_interval={},min_interval={},latency={},timeout={}'.format(connect_id, max_interval, min_interval, latency, timeout)) + else: + print('[callback] ble update parameter failed.') + ble.gattStop() + return + elif event_id == 20: # ble connection mtu + if status == 0: + print('[callback] ble connect mtu successful.') + handle = args[2] + ble_mtu = args[3] + print('[callback] handle = {:#06x}, ble_mtu = {}'.format(handle, ble_mtu)) + else: + print('[callback] ble connect mtu failed.') + ble.gattStop() + return + elif event_id == 21: # server:when ble client write characteristic value or descriptor,server get the notice + if status == 0: + print('[callback] ble recv successful.') + data_len = args[2] + data = args[3] # 这是一个bytearray类型 + attr_handle = args[4] + short_uuid = args[5] + long_uuid = args[6] # 这是一个bytearray类型 + print('len={}, data:{}'.format(data_len, data)) + print('attr_handle = {:#06x}'.format(attr_handle)) + print('short uuid = {:#06x}'.format(short_uuid)) + print('long uuid = {}'.format(long_uuid)) + else: + print('[callback] ble recv failed.') + ble.gattStop() + return + elif event_id == 22: # server:when ble client read characteristic value or descriptor,server get the notice + if status == 0: + print('[callback] ble recv read successful.') + data_len = args[2] + data = args[3] # 这是一个bytearray类型 + attr_handle = args[4] + short_uuid = args[5] + long_uuid = args[6] # 这是一个bytearray类型 + print('len={}, data:{}'.format(data_len, data)) + print('attr_handle = {:#06x}'.format(attr_handle)) + print('short uuid = {:#06x}'.format(short_uuid)) + print('long uuid = {}'.format(long_uuid)) + else: + print('[callback] ble recv read failed.') + ble.gattStop() + return + elif event_id == 25: # server send notification,and recieve send end notice + if status == 0: + print('[callback] ble send data successful.') + else: + print('[callback] ble send data failed.') + else: + print('unknown event id.') + +ble.serverInit(ble_callback) +``` + +### ble.serverRelease + +```python +ble.serverRelease() +``` + +BLE Server 资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.setLocalName + +```python +ble.setLocalName(code, name) +``` + +设置 BLE 名称。 + +**参数描述:** + +- `code`-编码模式,类型为整型。0 - UTF8,1 - GBK。 +- `name`-编码模式,类型为string。BLE 名称,名称最长不能超过29个字节。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +>>> ble.setLocalName(0, 'QuecPython-BLE') +0 +``` + +**注意**: + +对于BLE,设备在广播时,如果希望扫描软件扫描时,能看到广播设备的名称,是需要在广播数据中包含蓝牙名称的,或者在扫描回复数据中包含设备名称。 + +### ble.setAdvParam + +```python +ble.setAdvParam(min_adv,max_adv,adv_type,addr_type,channel,filter_policy,discov_mode,no_br_edr,enable_adv) +``` + +设置广播参数。 + +**参数描述:** + +- 参数含义如下表。 + +| 参数 | 类型 | 说明 | +| ------------- | ---------- | ------------------------------------------------------------ | +| min_adv | 无符号整型 | 最小广播间隔,范围0x0020-0x4000,计算如下:
时间间隔 = min_adv \* 0.625,单位ms | +| max_adv | 无符号整型 | 最大广播间隔,范围0x0020-0x4000,计算如下:
时间间隔 = max_adv \* 0.625,单位ms | +| adv_type | 无符号整型 | 广播类型,取值范围如下:
0 - 可连接的非定向广播,默认选择
1 - 可连接高占空比的定向广播
2 - 可扫描的非定向广播
3 - 不可连接的非定向广播
4 - 可连接低占空比的定向广播 | +| addr_type | 无符号整型 | 本地地址类型,取值范围如下:
0 - 公共地址
1 - 随机地址 | +| channel | 无符号整型 | 广播通道,取值范围如下:
1 - 37信道
2 - 38信道
4 - 39信道
7 - 上述3个通道都选择,默认该选项 | +| filter_policy | 无符号整型 | 广播过滤策略,取值范围如下:
0 - 处理所有设备的扫描和连接请求
1 - 处理所有设备的连接请求和只处理白名单设备的扫描请求(暂不支持)
2 - 处理所有设备的扫描请求和只处理白名单设备的连接请求(暂不支持)
3 - 只处理白名单设备的连接和扫描请求(暂不支持) | +| discov_mode | 无符号整型 | 发现模式,GAP协议使用,默认为2
1 - 有限可发现模式
2 - 一般可发现模式 | +| no_br_edr | 无符号整型 | 不用BR/EDR,默认为1,如果用则为0 | +| enable_adv | 无符号整型 | 使能广播,默认为1,不使能则为0 | + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_set_param(): + min_adv = 0x300 + max_adv = 0x320 + adv_type = 0 # 可连接的非定向广播,默认选择 + addr_type = 0 # 公共地址 + channel = 0x07 + filter_strategy = 0 # 处理所有设备的扫描和连接请求 + discov_mode = 2 + no_br_edr = 1 + enable_adv = 1 + ret = ble.setAdvParam(min_adv, max_adv, adv_type, addr_type, channel, filter_strategy, discov_mode, no_br_edr, enable_adv) + if ret != 0: + print('ble_gatt_set_param failed.') + return -1 + print('ble_gatt_set_param success.') + return 0 +``` + +### ble.setAdvData + +```python +ble.setAdvData(data) +``` + +设置广播数据内容。 + +**参数描述:** + +- `data`-广播数据,最长不超过31个字节,类型为bytearray。广播数据的内容,采用 length+type+data 的格式。一条广播数据中可以包含多个这种格式数据的组合,如下示例中包含了两个数据组合,第一个是 "0x02, 0x01, 0x05",0x02表示后面有两个数据,分别是0x01和0x05,0x01即type,0x05表示具体数据;第二个是ble名称数据组合, length为ble名称长度加1、type为0x09,具体数据为name对应的具体编码值。关于type具体值代表的含义,请参考蓝牙协议官方标准文档。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_set_data(): + adv_data = [0x02, 0x01, 0x05] + ble_name = "Quectel_ble" + length = len(ble_name) + 1 + adv_data.append(length) + adv_data.append(0x09) + name_encode = ble_name.encode('UTF-8') + for i in range(0, len(name_encode)): + adv_data.append(name_encode[i]) + print('set adv_data:{}'.format(adv_data)) + data = bytearray(adv_data) + ret = ble.setAdvData(data) + if ret != 0: + print('ble_gatt_set_data failed.') + return -1 + print('ble_gatt_set_data success.') + return 0 +``` + +### ble.setAdvRspData + +```python +ble.setAdvRspData(data) +``` + +设置扫描回复数据。 + +**参数描述:** + +- `data`-扫描回复数据,最长不超过31个字节,类型为bytearray。 格式和上面设置广播数据内容接口一致。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_set_rsp_data(): + adv_data = [] + ble_name = "Quectel_ble" + length = len(ble_name) + 1 + adv_data.append(length) + adv_data.append(0x09) + name_encode = ble_name.encode('UTF-8') + for i in range(0, len(name_encode)): + adv_data.append(name_encode[i]) + print('set adv_rsp_data:{}'.format(adv_data)) + data = bytearray(adv_data) + ret = ble.setAdvRspData(data) + if ret != 0: + print('ble_gatt_set_rsp_data failed.') + return -1 + print('ble_gatt_set_rsp_data success.') + return 0 +``` + +**注意**: + +当client设备扫描方式为积极扫描时,设置扫描回复数据才有意义。 + +### ble.addService + +```python +ble.addService(primary, server_id, uuid_type, uuid_s, uuid_l) +``` + +增加一个服务。 + +**参数描述:** + +- `primary`-服务类型,1表示主要服务,其他值表示次要服务,类型为整型。 +- `server_id`-服务ID,用来确定某一个服务,类型为整型。 +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_add_service(): + primary = 1 + server_id = 0x01 + uuid_type = 1 # 短UUID + uuid_s = 0x180F + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + ret = ble.addService(primary, server_id, uuid_type, uuid_s, uuid_l) + if ret != 0: + print('ble_gatt_add_service failed.') + return -1 + print('ble_gatt_add_service success.') + return 0 +``` + +### ble.addChara + +```python +ble.addChara(server_id, chara_id, chara_prop, uuid_type, uuid_s, uuid_l) +``` + +在服务里增加一个特征。 + +**参数描述:** + +- `server_id`-服务ID,用来确定某一个服务,类型为整型。 +- `chara_id`-特征ID,类型为整型。 +- `chara_prop`-特征的属性,十六进制数,可通过“或运算”同时指定多个属性,值具体含义如下表,类型为整型。 + +| 值 | 含义 | +| ---- | ----------------------------- | +| 0x01 | 广播 | +| 0x02 | 可读 | +| 0x04 | 0x04 - 可写且不需要链路层应答 | +| 0x08 | 可写 | +| 0x10 | 通知 | +| 0x20 | 指示 | +| 0x40 | 认证签名写 | +| 0x80 | 扩展属性 | + +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_add_characteristic(): + server_id = 0x01 + chara_id = 0x01 + chara_prop = 0x02 | 0x10 | 0x20 # 0x02-可读 0x10-通知 0x20-指示 + uuid_type = 1 # 短UUID + uuid_s = 0x2A19 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + ret = ble.addChara(server_id, chara_id, chara_prop, uuid_type, uuid_s, uuid_l) + if ret != 0: + print('ble_gatt_add_characteristic failed.') + return -1 + print('ble_gatt_add_characteristic success.') + return 0 +``` + +### ble.addCharaValue + +```python +ble.addCharaValue(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) +``` + +在特征里增加一个特征值。 + +**参数描述:** + +- `server_id`-服务ID,用来确定某一个服务,类型为整型。 +- `chara_id`-特征ID,类型为整型。 +- `permission`-特征值的权限,2个字节,十六进制数,可通过“或运算”同时指定多个属性,值具体含义如下表,类型为整型。 + +| 值 | 含义 | +| ------ | -------------- | +| 0x0001 | 可读权限 | +| 0x0002 | 可写权限 | +| 0x0004 | 读需要认证 | +| 0x0008 | 读需要授权 | +| 0x0010 | 读需要加密 | +| 0x0020 | 读需要授权认证 | +| 0x0040 | 写需要认证 | +| 0x0080 | 写需要授权 | +| 0x0100 | 写需要加密 | +| 0x0200 | 写需要授权认证 | + +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 +- `value`-特征值数据。类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_add_characteristic_value(): + data = [] + server_id = 0x01 + chara_id = 0x01 + permission = 0x0001 | 0x0002 + uuid_type = 1 # 短UUID + uuid_s = 0x2A19 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + for i in range(0, 244): + data.append(0x00) + value = bytearray(data) + ret = ble.addCharaValue(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) + if ret != 0: + print('ble_gatt_add_characteristic_value failed.') + return -1 + print('ble_gatt_add_characteristic_value success.') + return 0 +``` + +### ble.changeCharaValue + +```python +ble.changeCharaValue(server_id, chara_id, value) +``` + +修改特征值。 + +**参数描述:** + +- `server_id`-服务ID,用来确定某一个服务,类型为整型。 +- `chara_id`-特征ID,类型为整型。 + +- `value`-特征值数据。类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.addCharaDesc + +```python +ble.addCharaDesc(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) +``` + +在特征里增加一个特征描述,注意特征描述和特征值同属与一个特征。 + +**参数描述:** + +- `server_id`-服务ID,用来确定某一个服务,类型为整型。 +- `chara_id`-特征ID,类型为整型。 +- `permission`-特征值的权限,2个字节,十六进制数,可通过“或运算”同时指定多个属性,值具体含义如下表,类型为整型。 + +| 值 | 含义 | +| ------ | -------------- | +| 0x0001 | 可读权限 | +| 0x0002 | 可写权限 | +| 0x0004 | 读需要认证 | +| 0x0008 | 读需要授权 | +| 0x0010 | 读需要加密 | +| 0x0020 | 读需要授权认证 | +| 0x0040 | 写需要认证 | +| 0x0080 | 写需要授权 | +| 0x0100 | 写需要加密 | +| 0x0200 | 写需要授权认证 | + +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 +- `value`-特征描述数据。类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def ble_gatt_add_characteristic_desc(): + data = [0x00, 0x00] + server_id = 0x01 + chara_id = 0x01 + permission = 0x0001 | 0x0002 + uuid_type = 1 # 短UUID + uuid_s = 0x2902 + uuid_l = bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) + value = bytearray(data) + ret = ble.addCharaDesc(server_id, chara_id, permission, uuid_type, uuid_s, uuid_l, value) + if ret != 0: + print('ble_gatt_add_characteristic_desc failed.') + return -1 + print('ble_gatt_add_characteristic_desc success.') + return 0 +``` + +### ble.addOrClearService + +```python +ble.addOrClearService(option, mode) +``` + +增加前面已添加的所有服务信息到模块,或者删除模块中已增加的所有服务信息。 + +**参数描述:** + +- `option`-操作类型,类型为整型。0 - 删除服务,1 - 增加服务。 +- `mode`-是否保留系统默认服务,类型为整型。 0 - 删除系统默认的GAP和GATT服务,1 - 保留系统默认的GAP和GATT服务。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.sendNotification + +```python +ble.sendNotification(connect_id, attr_handle, value) +``` + +发送通知。 + +**参数描述:** + +- `connect_id`-连接ID,类型为整型。 +- `attr_handle`-属性句柄,类型为整型。 +- `value`-要发送的数据,发送数据长度不要超过MTU,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.sendIndication + +```python +ble.sendIndication(connect_id, attr_handle, value) +``` + +发送指示。 + +**参数描述:** + +- `connect_id`-连接ID,类型为整型。 +- `attr_handle`-属性句柄,类型为整型。 +- `value`-要发送的数据,发送数据长度不要超过MTU,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.advStart + +```python +ble.advStart() +``` + +开启广播。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.advStop + +```python +ble.advStop() +``` + +停止广播。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +## BLE Client相关功能 + +### ble.clientInit + +```python +ble.clientInit(user_cb) +``` + +初始化 BLE Client 并注册回调函数。 + +**参数描述:** + +- `user_cb`-回调函数,类型为function。回调函数参数含义:args[0] 固定表示event_id,args[1] 固定表示状态,0表示成功,非0表示失败。回调函数的参数个数并不是固定2个,而是根据第一个参数args[0]来决定的,下表中列出了不同事件ID对应的参数个数及说明。 + +| event_id | 参数个数 | 参数说明 | +| :------: | :------: | ------------------------------------------------------------ | +| 0 | 2 | args[0] :event_id,表示 BT/BLE start
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 1 | 2 | args[0] :event_id,表示 BT/BLE stop
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 16 | 4 | args[0] :event_id,表示 BLE connect
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id
args[3] :addr,BT/BLE address,bytearray类型数据 | +| 17 | 4 | args[0] :event_id,表示 BLE disconnect
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id,
args[3] :addr,BT/BLE address,bytearray类型数据 | +| 18 | 7 | args[0] :event_id,表示 BLE update connection parameter
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :connect_id
args[3] :max_interval,最大的间隔,间隔:1.25ms,取值范围:6-3200,时间范围:7.5ms ~ 4s
args[4] :min_interval,最小的间隔,间隔:1.25ms,取值范围:6-3200,时间范围:7.5ms ~ 4s
args[5] :latency,从机忽略连接状态事件的时间。需满足:(1+latecy)\*max_interval\*2\*1.25args[6] :timeout,没有交互,超时断开时间,间隔:10ms,取值范围:10-3200,时间范围:100ms ~ 32s | +| 19 | 9 | args[0] :event_id,表示 BLE scan report
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :event_type
args[3] :扫描到的设备名称
args[4] :设备地址类型
args[5] :设备地址,bytearray类型数据
args[6] :rssi,信号强度
args[7] :data_len,扫描的原始数据长度
args[8] :data,扫描的原始数据 | +| 20 | 4 | args[0] :event_id,表示 BLE connection mtu
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :handle
args[3] :mtu值 | +| 23 | 4 | args[0] :event_id,表示 client recieve notification,即接收通知
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,包含句柄等数据的原始数据,数据格式及解析见最后的综合示例程序 | +| 24 | 4 | args[0] :event_id,表示 client recieve indication,即接收指示
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,包含indication的原始数据,数据格式及解析见最后的综合示例程序 | +| 26 | 2 | args[0] :event_id,表示 start discover service,即开始查找服务
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 27 | 5 | args[0] :event_id,表示 discover service,即查找到服务
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :start_handle,表示service的开始句柄
args[3] :end_handle,表示service的结束句柄
args[4] :UUID,表示service的UUID(短UUID) | +| 28 | 4 | args[0] :event_id,表示 discover characteristic,即查找服务特征
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,包含句柄、属性、UUID等数据的原始数据,数据格式及解析见最后的综合示例程序 | +| 29 | 4 | args[0] :event_id,表示 discover characteristic descriptor,即查找特征描述
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,包含句柄、UUID等数据的原始数据,数据格式及解析见最后的综合示例程序 | +| 30 | 2 | args[0] :event_id,表示 write characteristic value with response,即写入特征值并需要链路层确认
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 31 | 2 | args[0] :event_id,表示 write characteristic value without response,即写入特征值,无需链路层确认
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 32 | 4 | args[0] :event_id,表示 read characteristic value by handle,即通过句柄来读取特征值
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,原始数据 | +| 33 | 4 | args[0] :event_id,表示 read characteristic value by uuid,即通过UUID来读取特征值
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,原始数据 | +| 34 | 4 | args[0] :event_id,表示 read miltiple characteristic value,即读取多个特征值
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,原始数据 | +| 35 | 2 | args[0] :event_id,表示 wirte characteristic descriptor,即写入特征描述,需链路层确认
args[1] :status,表示操作的状态,0-成功,非0-失败 | +| 36 | 4 | args[0] :event_id,表示 read characteristic descriptor,即读特征描述
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :data_len,数据长度
args[3] :data,原始数据 | +| 37 | 3 | args[0] :event_id,表示 attribute error,即属性错误
args[1] :status,表示操作的状态,0-成功,非0-失败
args[2] :errcode,错误码 | + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.clientRelease + +```python +ble.clientRelease() +``` + +BLE Client 资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.setScanParam + +```python +ble.setScanParam(scan_mode, interval, scan_window, filter_policy, addr_type) +``` + +设置扫描参数。 + +**参数描述:** + +- `scan_mode`-扫描模式,类型为整型。扫描模式,默认为积极扫描。0 - 消极扫描,1 - 积极扫描。 +- `interval`-扫描间隔,类型为整型。范围0x0004-0x4000,时间间隔 = interval \* 0.625,单位ms。 +- `scan_window`-一次扫描的时间,类型为整型。范围0x0004-0x4000,扫描时间 = scan_window\* 0.625,单位ms。 +- `filter_policy`-扫描过滤策略,类型为整型。默认为0。0 - 除了不是本设备的定向广播,其他所有的广播包,1 - 除了不是本设备的定向广播,白名单设备的广播包,2 - 非定向广播,指向本设备的定向广播或使用Resolvable private address的定向广播,3 - 白名单设备非定向广播,指向本设备的定向广播或使用Resolvable private address的定向广播。 +- `addr_type`-本地地址类型,类型为整型。0 - 公共地址,1 - 随机地址。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**注意**: + +扫描时间 `scan_window` 不能大于扫描间隔 `interval` 。如果两者相等,则表示连续不停的扫描。此时 BLE 的 Controller 会连续运行扫描,占满系统资源而导致无法执行其他任务。所以不允许设置连续扫描。并且不建议将时间设置的太短,扫描越频繁则功耗越高。 + +### ble.scanStart + +```python +ble.scanStart() +``` + +开始扫描。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.scanStop + +```python +ble.scanStop() +``` + +停止扫描。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.setScanFilter + +```python +ble.setScanFilter(act) +``` + +打开或者关闭扫描过滤。如果打开,那么扫描设备的广播数据时,同一个设备的广播数据只会上报一次;如果关闭,则同一个设备的所有的广播数据都会上报。 + +**参数描述:** + +- `act`-扫描过滤开关,类型为整型。0 - 关闭扫描过滤功能,1 - 打开扫描过滤功能。默认打开过滤功能。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.connect + +```python +ble.connect(addr_type, addr) +``` + +根据指定的设备地址去连接设备。 + +**参数描述:** + +- `addr_type`-地址类型,类型为整型。0 - 公共地址,1 - 随机地址。 +- `addr`-BLE地址,类型为bytearray,大小为6字节。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.cancelConnect + +```python +ble.cancelConnect(addr) +``` + +取消正在建立的连接。 + +**参数描述:** + +- `addr`-BLE地址,类型为bytearray,大小为6字节。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.disconnect + +```python +ble.disconnect(connect_id) +``` + +断开已建立的连接。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.discoverAllService + +```python +ble.discoverAllService(connect_id) +``` + +扫描所有的服务。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.discoverByUUID + +```python +ble.discoverByUUID(connect_id, uuid_type, uuid_s, uuid_l) +``` + +扫描指定UUID的服务。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.discoverAllIncludes + +```python +ble.discoverAllIncludes(connect_id, start_handle, end_handle) +``` + +扫描所有的引用,start_handle和end_handle要属于同一个服务。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `start_handle`-开始句柄,从这个句柄开始寻找引用,类型为整型。 +- `end_handle`-结束句柄,从这个句柄结束寻找引用,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.discoverAllChara + +```python +ble.discoverAllChara(connect_id, start_handle, end_handle) +``` + +扫描所有的特征,start_handle和end_handle要属于同一个服务。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `start_handle`-开始句柄,从这个句柄开始寻找特征,类型为整型。 +- `end_handle`-结束句柄,从这个句柄结束寻找特征,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.discoverAllCharaDesc + +```python +ble.discoverAllCharaDesc(connect_id, start_handle, end_handle) +``` + +扫描所有特征的描述,start_handle和end_handle要属于同一个服务。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `start_handle`-开始句柄,从这个句柄开始寻找特征描述,类型为整型。 +- `end_handle`-结束句柄,从这个句柄结束寻找特征描述,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.readCharaByUUID + +```python +ble.readCharaByUUID(connect_id, start_handle, end_handle, uuid_type, uuid_s, uuid_l) +``` + +读取指定UUID的特征值,start_handle和end_handle必须要包含一个特征值句柄。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `start_handle`-开始句柄,一定要属于同一个特征的句柄,类型为整型。 +- `end_handle`-结束句柄,结束句柄,一定要属于同一个特征的句柄,类型为整型。 +- `uuid_type`-uuid类型,0 - 长UUID,128bit;1 - 短UUID,16bit。类型为整型。 +- `uuid_s`-短UUID,2个字节(16bit),类型为整型,当uuid_type为0时,该值给0。 +- `uuid_l`-长UUID,16个字节(128bit),类型为bytearray,当uuid_type为1时,该值填 bytearray([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.readCharaByHandle + +```python +ble.readCharaByHandle(connect_id, handle, offset, is_long) +``` + +读取指定句柄的特征值。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `handle`-特征值句柄,类型为整型。 +- `offset`-偏移位置,类型为整型。 +- `is_long`-长特征值标志,0-短特征值,一次可以读取完;1-长特征值,分多次读取。类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.readCharaDesc + +```python +ble.readCharaDesc(connect_id, handle, is_long) +``` + +读取特征描述。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `handle`-特征值句柄,类型为整型。 +- `is_long`-长特征值标志,0-短特征值,一次可以读取完;1-长特征值,分多次读取。类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.writeChara + +```python +ble.writeChara(connect_id, handle, offset, is_long, data) +``` + +写入特征值,需要对端应答。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `handle`-特征值句柄,类型为整型。 +- `offset`-偏移位置,类型为整型。 +- `is_long`-长特征值标志,0-短特征值,一次可以读取完;1-长特征值,分多次读取。类型为整型。 +- `data`-特征值数据,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.writeCharaNoRsp + +```python +ble.writeCharaNoRsp(connect_id, handle, data) +``` + +写入特征值,不需要对端应答。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `handle`-特征值句柄,类型为整型。 +- `data`-特征值数据,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### ble.writeCharaDesc + +```python +ble.writeCharaDesc(connect_id, handle, data) +``` + +写入特征描述。 + +**参数描述:** + +- `connect_id`-连接ID,建立连接时得到的连接ID,类型为整型。 +- `handle`-特征描述句柄,类型为整型。 +- `data`-特征描述数据,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 \ No newline at end of file diff --git "a/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/bt.md" "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/bt.md" new file mode 100644 index 0000000000000000000000000000000000000000..b3b034019cd634abd35d98563cbcbede520a3d63 --- /dev/null +++ "b/docs/API_reference/zh/QuecPython\347\261\273\345\272\223/bt.md" @@ -0,0 +1,1557 @@ +# bt - 经典蓝牙相关功能 + +`bt`模块提供经典蓝牙的相关功能,支持HFP、A2DP、AVRCP、SPP。 + +**示例**: + +```python +#HFP 示例程序 + +""" +示例说明:本例程提供一个通过HFP自动接听电话的功能 +运行平台:EC600UCN_LB 铀开发板 +运行本例程后,通过手机A搜索到设备名并点击连接;然后通过手机B拨打电话给手机A, +当手机A开始响铃震动时,设备会自动接听电话 +""" +import bt +import utime +import _thread +from queue import Queue +from machine import Pin + +# 如果对应播放通道外置了PA,且需要引脚控制PA开启,则需要下面步骤 +# 具体使用哪个GPIO取决于实际使用的引脚 +gpio11 = Pin(Pin.GPIO11, Pin.OUT, Pin.PULL_DISABLE, 0) +gpio11.write(1) + +BT_NAME = 'QuecPython-hfp' + +BT_EVENT = { + 'BT_START_STATUS_IND': 0, # bt/ble start + 'BT_STOP_STATUS_IND': 1, # bt/ble stop + 'BT_HFP_CONNECT_IND': 40, # bt hfp connected + 'BT_HFP_DISCONNECT_IND': 41, # bt hfp disconnected + 'BT_HFP_CALL_IND': 42, # bt hfp call state + 'BT_HFP_CALL_SETUP_IND': 43, # bt hfp call setup state + 'BT_HFP_NETWORK_IND': 44, # bt hfp network state + 'BT_HFP_NETWORK_SIGNAL_IND': 45, # bt hfp network signal + 'BT_HFP_BATTERY_IND': 46, # bt hfp battery level + 'BT_HFP_CALLHELD_IND': 47, # bt hfp callheld state + 'BT_HFP_AUDIO_IND': 48, # bt hfp audio state + 'BT_HFP_VOLUME_IND': 49, # bt hfp volume type + 'BT_HFP_NETWORK_TYPE': 50, # bt hfp network type + 'BT_HFP_RING_IND': 51, # bt hfp ring indication + 'BT_HFP_CODEC_IND': 52, # bt hfp codec type +} + +HFP_CONN_STATUS = 0 +HFP_CONN_STATUS_DICT = { + 'HFP_DISCONNECTED': 0, + 'HFP_CONNECTING': 1, + 'HFP_CONNECTED': 2, + 'HFP_DISCONNECTING': 3, +} +HFP_CALL_STATUS = 0 +HFP_CALL_STATUS_DICT = { + 'HFP_NO_CALL_IN_PROGRESS': 0, + 'HFP_CALL_IN_PROGRESS': 1, +} + +BT_IS_RUN = 0 + +msg_queue = Queue(30) + + +def get_key_by_value(val, d): + for key, value in d.items(): + if val == value: + return key + return None + +def bt_callback(args): + global msg_queue + msg_queue.put(args) + +def bt_event_proc_task(): + global msg_queue + global BT_IS_RUN + global BT_EVENT + global HFP_CONN_STATUS + global HFP_CONN_STATUS_DICT + global HFP_CALL_STATUS + global HFP_CALL_STATUS_DICT + + while True: + print('wait msg...') + msg = msg_queue.get() # 没有消息时会阻塞在这 + event_id = msg[0] + status = msg[1] + + if event_id == BT_EVENT['BT_START_STATUS_IND']: + print('event: BT_START_STATUS_IND') + if status == 0: + print('BT start successfully.') + BT_IS_RUN = 1 + bt_status = bt.getStatus() + if bt_status == 1: + print('BT status is 1, normal status.') + else: + print('BT status is {}, abnormal status.'.format(bt_status)) + bt.stop() + break + + retval = bt.getLocalName() + if retval != -1: + print('The current BT name is : {}'.format(retval[1])) + else: + print('Failed to get BT name.') + bt.stop() + break + + print('Set BT name to {}'.format(BT_NAME)) + retval = bt.setLocalName(0, BT_NAME) + if retval != -1: + print('BT name set successfully.') + else: + print('BT name set failed.') + bt.stop() + break + + retval = bt.getLocalName() + if retval != -1: + print('The new BT name is : {}'.format(retval[1])) + else: + print('Failed to get new BT name.') + bt.stop() + break + + # 设置蓝牙可见模式为:可以被发现并且可以被连接 + retval = bt.setVisibleMode(3) + if retval == 0: + mode = bt.getVisibleMode() + if mode == 3: + print('BT visible mode set successfully.') + else: + print('BT visible mode set failed.') + bt.stop() + break + else: + print('BT visible mode set failed.') + bt.stop() + break + else: + print('BT start failed.') + bt.stop() + break + elif event_id == BT_EVENT['BT_STOP_STATUS_IND']: + print('event: BT_STOP_STATUS_IND') + if status == 0: + BT_IS_RUN = 0 + print('BT stop successfully.') + else: + print('BT stop failed.') + break + elif event_id == BT_EVENT['BT_HFP_CONNECT_IND']: + HFP_CONN_STATUS = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_CONNECT_IND, {}, hfp_conn_status:{}, mac:{}'.format(status, get_key_by_value(msg[2], HFP_CONN_STATUS_DICT), mac)) + if status != 0: + print('BT HFP connect failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_DISCONNECT_IND']: + HFP_CONN_STATUS = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_DISCONNECT_IND, {}, hfp_conn_status:{}, mac:{}'.format(status, get_key_by_value(msg[2], HFP_CONN_STATUS_DICT), mac)) + if status != 0: + print('BT HFP disconnect failed.') + bt.stop() + elif event_id == BT_EVENT['BT_HFP_CALL_IND']: + call_sta = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_CALL_IND, {}, hfp_call_status:{}, mac:{}'.format(status, get_key_by_value(msg[2], HFP_CALL_STATUS_DICT), mac)) + if status != 0: + print('BT HFP call failed.') + bt.stop() + continue + + if call_sta == HFP_CALL_STATUS_DICT['HFP_NO_CALL_IN_PROGRESS']: + if HFP_CALL_STATUS == HFP_CALL_STATUS_DICT['HFP_CALL_IN_PROGRESS']: + HFP_CALL_STATUS = call_sta + if HFP_CONN_STATUS == HFP_CONN_STATUS_DICT['HFP_CONNECTED']: + print('call ended, ready to disconnect hfp.') + retval = bt.hfpDisconnect(addr) + if retval == 0: + HFP_CONN_STATUS = HFP_CONN_STATUS_DICT['HFP_DISCONNECTING'] + else: + print('Failed to disconnect hfp connection.') + bt.stop() + continue + else: + if HFP_CALL_STATUS == HFP_CALL_STATUS_DICT['HFP_NO_CALL_IN_PROGRESS']: + HFP_CALL_STATUS = call_sta + print('set audio output channel to 2.') + bt.setChannel(2) + print('set volume to 7.') + retval = bt.hfpSetVolume(addr, 7) + if retval != 0: + print('set volume failed.') + elif event_id == BT_EVENT['BT_HFP_CALL_SETUP_IND']: + call_setup_status = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_CALL_SETUP_IND, {}, hfp_call_setup_status:{}, mac:{}'.format(status, call_setup_status, mac)) + if status != 0: + print('BT HFP call setup failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_CALLHELD_IND']: + callheld_status = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_CALLHELD_IND, {}, callheld_status:{}, mac:{}'.format(status, callheld_status, mac)) + if status != 0: + print('BT HFP callheld failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_NETWORK_IND']: + network_status = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_NETWORK_IND, {}, network_status:{}, mac:{}'.format(status, network_status, mac)) + if status != 0: + print('BT HFP network status failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_NETWORK_SIGNAL_IND']: + network_signal = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_NETWORK_SIGNAL_IND, {}, signal:{}, mac:{}'.format(status, network_signal, mac)) + if status != 0: + print('BT HFP network signal failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_BATTERY_IND']: + battery_level = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_BATTERY_IND, {}, battery_level:{}, mac:{}'.format(status, battery_level, mac)) + if status != 0: + print('BT HFP battery level failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_AUDIO_IND']: + audio_status = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_AUDIO_IND, {}, audio_status:{}, mac:{}'.format(status, audio_status, mac)) + if status != 0: + print('BT HFP audio failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_VOLUME_IND']: + volume_type = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_VOLUME_IND, {}, volume_type:{}, mac:{}'.format(status, volume_type, mac)) + if status != 0: + print('BT HFP volume failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_NETWORK_TYPE']: + service_type = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_NETWORK_TYPE, {}, service_type:{}, mac:{}'.format(status, service_type, mac)) + if status != 0: + print('BT HFP network service type failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_RING_IND']: + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_RING_IND, {}, mac:{}'.format(status, mac)) + if status != 0: + print('BT HFP ring failed.') + bt.stop() + continue + retval = bt.hfpAnswerCall(addr) + if retval == 0: + print('The call was answered successfully.') + else: + print('Failed to answer the call.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_HFP_CODEC_IND']: + codec_type = msg[2] + addr = msg[3] # BT 主机端mac地址 + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('BT_HFP_CODEC_IND, {}, codec_type:{}, mac:{}'.format(status, codec_type, mac)) + if status != 0: + print('BT HFP codec failed.') + bt.stop() + continue + print('Ready to release hfp.') + bt.hfpRelease() + bt.release() + + +def main(): + global BT_IS_RUN + + _thread.start_new_thread(bt_event_proc_task, ()) + + retval = bt.init(bt_callback) + if retval == 0: + print('BT init successful.') + else: + print('BT init failed.') + return -1 + retval = bt.hfpInit() + if retval == 0: + print('HFP init successful.') + else: + print('HFP init failed.') + return -1 + retval = bt.start() + if retval == 0: + print('BT start successful.') + else: + print('BT start failed.') + retval = bt.hfpRelease() + if retval == 0: + print('HFP release successful.') + else: + print('HFP release failed.') + retval = bt.release() + if retval == 0: + print('BT release successful.') + else: + print('BT release failed.') + return -1 + + count = 0 + while True: + utime.sleep(1) + count += 1 + cur_time = utime.localtime() + timestamp = "{:02d}:{:02d}:{:02d}".format(cur_time[3], cur_time[4], cur_time[5]) + + if count % 5 == 0: + if BT_IS_RUN == 1: + print('[{}] BT HFP is running, count = {}......'.format(timestamp, count)) + print('') + else: + print('BT HFP has stopped running, ready to exit.') + break + + +if __name__ == '__main__': + main() + +``` + +```python +#A2DP/AVRCP 示例程序 + +""" +示例说明:本例程提供一个通过A2DP/AVRCP实现的简易蓝牙音乐播放控制功能 +运行本例程后,通过手机搜索到设备名并点击连接;然后打开手机上的音乐播放软件, +回到例程运行界面,根据提示菜单输入对应的控制命令来实现音乐的播放、暂停、上一首、 +下一首以及设置音量的功能 +""" +import bt +import utime +import _thread +from queue import Queue +from machine import Pin + +BT_STATUS_DICT = { + 'BT_NOT_RUNNING': 0, + 'BT_IS_RUNNING': 1 +} + +A2DP_AVRCP_CONNECT_STATUS = { + 'DISCONNECTED': 0, + 'CONNECTING': 1, + 'CONNECTED': 2, + 'DISCONNECTING': 3 +} + +host_addr = 0 +msg_queue = Queue(10) + +# 如果对应播放通道外置了PA,且需要引脚控制PA开启,则需要下面步骤 +# 具体使用哪个GPIO取决于实际使用的引脚 +gpio11 = Pin(Pin.GPIO11, Pin.OUT, Pin.PULL_DISABLE, 0) +gpio11.write(1) + + +def cmd_proc(cmd): + cmds = ('1', '2', '3', '4', '5') + vols = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11') + + if cmd in cmds: + if cmd == '5': + while True: + tmp = input('Please input volume: ') + if len(tmp) != 1: + vol = tmp.split('Please input volume: ')[1] + else: + vol = tmp + if vol in vols: + return cmd, int(vol) + else: + print('Volume should be in [0,11], try again.') + else: + return cmd, 0 + else: + print('Command {} is not supported!'.format(cmd)) + return -1 + +def avrcp_play(args): + return bt.avrcpStart() + +def avrcp_pause(args): + return bt.avrcpPause() + +def avrcp_prev(args): + return bt.avrcpPrev() + +def avrcp_next(args): + return bt.avrcpNext() + +def avrcp_set_volume(vol): + return bt.avrcpSetVolume(vol) + +def bt_callback(args): + pass + +def bt_a2dp_avrcp_proc_task(): + global msg_queue + + cmd_handler = { + '1': avrcp_play, + '2': avrcp_pause, + '3': avrcp_prev, + '4': avrcp_next, + '5': avrcp_set_volume, + } + while True: + # print('wait msg...') + msg = msg_queue.get() + print('recv msg: {}'.format(msg)) + cmd_handler.get(msg[0])(msg[1]) + + +def main(): + global host_addr + global msg_queue + + _thread.start_new_thread(bt_a2dp_avrcp_proc_task, ()) + bt.init(bt_callback) + bt.setChannel(2) + retval = bt.a2dpavrcpInit() + if retval == 0: + print('BT A2DP/AVRCP initialization succeeded.') + else: + print('BT A2DP/AVRCP initialization failed.') + return -1 + + retval = bt.start() + if retval != 0: + print('BT start failed.') + return -1 + + utime.sleep_ms(1500) + + old_name = bt.getLocalName() + if old_name == -1: + print('Get BT name error.') + return -1 + print('The current BT name is {}'.format(old_name[1])) + new_name = 'QuecPython-a2dp' + print('Set new BT name to {}'.format(new_name)) + retval = bt.setLocalName(0, new_name) + if retval == -1: + print('Set BT name failed.') + return -1 + cur_name = bt.getLocalName() + if cur_name == -1: + print('Get new BT name error.') + return -1 + else: + if cur_name[1] == new_name: + print('BT name changed successfully.') + else: + print('BT name changed failed.') + + visible_mode = bt.getVisibleMode() + if visible_mode != -1: + print('The current BT visible mode is {}'.format(visible_mode)) + else: + print('Get BT visible mode error.') + return -1 + + print('Set BT visible mode to 3.') + retval = bt.setVisibleMode(3) + if retval == -1: + print('Set BT visible mode error.') + return -1 + + print('BT reconnect check start......') + bt.reconnect_set(25, 2) + bt.reconnect() + + count = 0 + while True: + count += 1 + if count % 5 == 0: + print('waiting to be connected...') + if count >= 10000: + count = 0 + a2dp_status = bt.a2dpGetConnStatus() + avrcp_status = bt.avrcpGetConnStatus() + if a2dp_status == A2DP_AVRCP_CONNECT_STATUS['CONNECTED'] and avrcp_status == A2DP_AVRCP_CONNECT_STATUS['CONNECTED']: + print('========== BT connected! =========') + addr = bt.a2dpGetAddr() + if addr != -1: + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('The BT address on the host side: {}'.format(mac)) + host_addr = addr + else: + print('Get BT addr error.') + return -1 + print('Please open the music player software on your phone first.') + print('Please enter the following options to select a function:') + print('========================================================') + print('1 : play') + print('2 : pause') + print('3 : prev') + print('4 : next') + print('5 : set volume') + print('6 : exit') + print('========================================================') + while True: + tmp = input('> ') + if len(tmp) != 1: + cmd = tmp.split('> ')[1] + else: + cmd = tmp + if cmd == '6': + break + retval = cmd_proc(cmd) + if retval != -1: + msg_queue.put(retval) + break + else: + utime.sleep_ms(1000) + print('Ready to disconnect a2dp.') + retval = bt.a2dpDisconnect(host_addr) + if retval == 0: + print('a2dp connection disconnected successfully') + else: + print('Disconnect a2dp error.') + print('Ready to stop BT.') + retval = bt.stop() + if retval == 0: + print('BT has stopped.') + else: + print('BT stop error.') + bt.a2dpavrcpRelease() + bt.release() + + +if __name__ == '__main__': + main() +``` + +```python +#SPP 示例程序 + +""" +示例说明:本例程提供一个通过SPP实现与手机端进行数据传输的功能 +(1)运行之前,需要先在手机端(安卓)安装蓝牙串口APP,如BlueSPP,然后打开该软件; +(2)修改本例程中的目标设备的蓝牙名称,即 DST_DEVICE_INFO['dev_name'] 的值改为用户准备连接的手机的蓝牙名称; +(3)运行本例程,例程中会先发起搜索周边设备的操作,直到搜索到目标设备,就会结束搜索,然后向目标设备发起SPP连接请求; +(4)用户注意查看手机界面是否弹出蓝牙配对请求的界面,当出现时,点击配对; +(5)配对成功后,用户即可进入到蓝牙串口界面,发送数据给设备,设备在收到数据后会回复“I have received the data you sent.” +(6)手机端APP中点击断开连接,即可结束例程; +""" +import bt +import utime +import _thread +from queue import Queue + + +BT_NAME = 'QuecPython-SPP' + +BT_EVENT = { + 'BT_START_STATUS_IND': 0, # bt/ble start + 'BT_STOP_STATUS_IND': 1, # bt/ble stop + 'BT_SPP_INQUIRY_IND': 6, # bt spp inquiry ind + 'BT_SPP_INQUIRY_END_IND': 7, # bt spp inquiry end ind + 'BT_SPP_RECV_DATA_IND': 14, # bt spp recv data ind + 'BT_SPP_CONNECT_IND': 61, # bt spp connect ind + 'BT_SPP_DISCONNECT_IND': 62, # bt spp disconnect ind +} + +DST_DEVICE_INFO = { + 'dev_name': 'HUAWEI Mate40 Pro', # 要连接设备的蓝牙名称 + 'bt_addr': None +} + +BT_IS_RUN = 0 +msg_queue = Queue(30) + + +def bt_callback(args): + global msg_queue + msg_queue.put(args) + + +def bt_event_proc_task(): + global msg_queue + global BT_IS_RUN + global DST_DEVICE_INFO + + while True: + print('wait msg...') + msg = msg_queue.get() # 没有消息时会阻塞在这 + event_id = msg[0] + status = msg[1] + + if event_id == BT_EVENT['BT_START_STATUS_IND']: + print('event: BT_START_STATUS_IND') + if status == 0: + print('BT start successfully.') + BT_IS_RUN = 1 + + print('Set BT name to {}'.format(BT_NAME)) + retval = bt.setLocalName(0, BT_NAME) + if retval != -1: + print('BT name set successfully.') + else: + print('BT name set failed.') + bt.stop() + continue + + retval = bt.setVisibleMode(3) + if retval == 0: + mode = bt.getVisibleMode() + if mode == 3: + print('BT visible mode set successfully.') + else: + print('BT visible mode set failed.') + bt.stop() + continue + else: + print('BT visible mode set failed.') + bt.stop() + continue + + retval = bt.startInquiry(15) + if retval != 0: + print('Inquiry error.') + bt.stop() + continue + else: + print('BT start failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_STOP_STATUS_IND']: + print('event: BT_STOP_STATUS_IND') + if status == 0: + BT_IS_RUN = 0 + print('BT stop successfully.') + else: + print('BT stop failed.') + + retval = bt.sppRelease() + if retval == 0: + print('SPP release successfully.') + else: + print('SPP release failed.') + retval = bt.release() + if retval == 0: + print('BT release successfully.') + else: + print('BT release failed.') + break + elif event_id == BT_EVENT['BT_SPP_INQUIRY_IND']: + print('event: BT_SPP_INQUIRY_IND') + if status == 0: + rssi = msg[2] + name = msg[4] + addr = msg[5] + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('name: {}, addr: {}, rssi: {}'.format(name, mac, rssi)) + + if name == DST_DEVICE_INFO['dev_name']: + print('The target device is found, device name {}'.format(name)) + DST_DEVICE_INFO['bt_addr'] = addr + retval = bt.cancelInquiry() + if retval != 0: + print('cancel inquiry failed.') + continue + else: + print('BT inquiry failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_SPP_INQUIRY_END_IND']: + print('event: BT_SPP_INQUIRY_END_IND') + if status == 0: + print('BT inquiry has ended.') + inquiry_sta = msg[2] + if inquiry_sta == 0: + if DST_DEVICE_INFO['bt_addr'] is not None: + print('Ready to connect to the target device : {}'.format(DST_DEVICE_INFO['dev_name'])) + retval = bt.sppConnect(DST_DEVICE_INFO['bt_addr']) + if retval != 0: + print('SPP connect failed.') + bt.stop() + continue + else: + print('Not found device [{}], continue to inquiry.'.format(DST_DEVICE_INFO['dev_name'])) + bt.cancelInquiry() + bt.startInquiry(15) + else: + print('Inquiry end failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_SPP_RECV_DATA_IND']: + print('event: BT_SPP_RECV_DATA_IND') + if status == 0: + datalen = msg[2] + data = msg[3] + print('recv {} bytes data: {}'.format(datalen, data)) + send_data = 'I have received the data you sent.' + print('send data: {}'.format(send_data)) + retval = bt.sppSend(send_data) + if retval != 0: + print('send data faied.') + else: + print('Recv data failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_SPP_CONNECT_IND']: + print('event: BT_SPP_CONNECT_IND') + if status == 0: + conn_sta = msg[2] + addr = msg[3] + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('SPP connect successful, conn_sta = {}, addr {}'.format(conn_sta, mac)) + else: + print('Connect failed.') + bt.stop() + continue + elif event_id == BT_EVENT['BT_SPP_DISCONNECT_IND']: + print('event: BT_SPP_DISCONNECT_IND') + conn_sta = msg[2] + addr = msg[3] + mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) + print('SPP disconnect successful, conn_sta = {}, addr {}'.format(conn_sta, mac)) + bt.stop() + continue + + +def main(): + global BT_IS_RUN + + _thread.start_new_thread(bt_event_proc_task, ()) + retval = bt.init(bt_callback) + if retval == 0: + print('BT init successful.') + else: + print('BT init failed.') + return -1 + retval = bt.sppInit() + if retval == 0: + print('SPP init successful.') + else: + print('SPP init failed.') + return -1 + retval = bt.start() + if retval == 0: + print('BT start successful.') + else: + print('BT start failed.') + retval = bt.sppRelease() + if retval == 0: + print('SPP release successful.') + else: + print('SPP release failed.') + return -1 + + count = 0 + while True: + utime.sleep(1) + count += 1 + cur_time = utime.localtime() + timestamp = "{:02d}:{:02d}:{:02d}".format(cur_time[3], cur_time[4], cur_time[5]) + + if count % 5 == 0: + if BT_IS_RUN == 1: + print('[{}] BT SPP is running, count = {}......'.format(timestamp, count)) + print('') + else: + print('BT SPP has stopped running, ready to exit.') + break + + +if __name__ == '__main__': + main() +``` + +**注意**: + +当前仅EC200U/EC600U/EG915U/EG912U平台支持`bt`功能。 + +## 初始化相关功能 + +### bt.init + +```python +bt.init(user_cb) +``` + +蓝牙初始化并注册回调函数。 + +**参数描述:** + +- `user_cb`-回调函数,类型为function。回调函数参数含义:args[0] 固定表示event_id,args[1] 固定表示状态,0表示成功,非0表示失败。回调函数的参数个数并不是固定2个,而是根据第一个参数args[0]来决定的,下表中列出了不同事件ID对应的参数个数及说明。 + +| event_id | 参数个数 | 参数说明 | +| :------: | :------: | ------------------------------------------------------------ | +| 0 | 2 | args[0] :event_id,表示 BT/BLE start 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败 | +| 1 | 2 | args[0] :event_id,表示 BT/BLE stop
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败 | +| 6 | 6 | args[0] :event_id,表示 BT inquiry 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :rssi,搜索到的设备的信号强度;
args[3] :device_class
args[4] :device_name,设备名称,字符串类型
args[5] :addr,搜到的蓝牙设备的mac地址 | +| 7 | 3 | args[0] :event_id,表示 BT inquiry end 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :end_status,0 - 正常结束搜索,8 - 强制结束搜索 | +| 14 | 4 | args[0] :event_id,表示 BT spp recv 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :data_len,收到的数据长度
args[3] :data,收到的数据,bytearray类型数据 | +| 40 | 4 | args[0] :event_id,表示 BT HFP connect 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_connect_status,表示hfp的连接状态;
0 - 已经断开连接
1 - 连接中
2 - 已经连接
3 - 断开连接中
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 41 | 4 | args[0] :event_id,表示 BT HFP disconnect 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_connect_status,表示hfp的连接状态;
0 - 已经断开连接
1 - 连接中
2 - 已经连接
3 - 断开连接中
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 42 | 4 | args[0] :event_id,表示 BT HFP call status 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_call_status,表示hfp的通话状态;
0 - 当前没有正在进行的通话
1 - 当前至少有一个正在进行的通话
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 43 | 4 | args[0] :event_id,表示 BT HFP call setup status 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_call_setup_status,表示hfp的call setup状态;
0 - 表示没有电话需要接通
1 - 表示有一个拨进来的电话还未接通
2 - 表示有一个拨出去的电话还没有接通
3 - 表示拨出电话的蓝牙连接的另一方正在响铃
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 44 | 4 | args[0] :event_id,表示 BT HFP network status 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_network_status,表示AG的网络状态;
0 - 表示网络不可用
1 - 表示网络正常
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 45 | 4 | args[0] :event_id,表示 BT HFP network signal 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_network_signal,表示AG的信号,范围 0~5
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 46 | 4 | args[0] :event_id,表示 BT HFP battery level 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_battery_level,表示AG端的电池电量,范围 0~5
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 47 | 4 | args[0] :event_id,表示 BT HFP call held status 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_call_held_status,表示hfp的call held状态;
0 - 表示没有保持呼叫
1 - 表示呼叫被暂停或活动/保持呼叫交换
2 - 表示呼叫暂停,没有活动呼叫
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 48 | 4 | args[0] :event_id,表示 BT HFP audio status 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_audio_status,表示audio连接状态;
0 - 表示audio已经断开连接
1 - 表示audio正在连接中
2 - 表示audio已经连接成功
3 - 表示audio正在断开连接
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 49 | 4 | args[0] :event_id,表示 BT HFP volume type 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_volume_type
0 - 表示volume type为speaker
1 - 表示volume type为microphone
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 50 | 4 | args[0] :event_id,表示 BT HFP service type 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_service_type,表示当前AG的网络服务模式;
0 - 表示AG当前为正常网络模式
1 - 表示AG当前处于漫游模式
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 51 | 4 | args[0] :event_id,表示 BT HFP ring 事件,即来电时响铃事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :当前无实际意义,保留
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 52 | 4 | args[0] :event_id,表示 BT HFP codec type 事件,即编解码模式
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :hfp_codec_type,表示当前使用哪个编解码模式;
1 - 表示 CVDS,采用8kHz采样率
2 - 表示mSBC,采用16kHz采样率
args[3] :addr,BT 主设备的地址,bytearray类型数据 | +| 61 | 4 | args[0] :event_id,表示 BT SPP connect 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :spp_connect_status,表示spp的连接状态;
0 - 已经断开连接
1 - 连接中
2 - 已经连接
3 - 断开连接中
args[3] :addr,对端设备的mac地址,bytearray类型数据 | +| 62 | 4 | args[0] :event_id,表示 BT SPP disconnect 事件
args[1] :status,表示操作的状态,0 - 成功,非0 - 失败
args[2] :spp_connect_status,表示spp的连接状态;
0 - 已经断开连接
1 - 连接中
2 - 已经连接
3 - 断开连接中
args[3] :addr,对端设备的mac地址,bytearray类型数据 | + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +def bt_callback(args): + event_id = args[0] # 第一个参数固定是 event_id + status = args[1] # 第二个参数固定是状态,表示某个操作的执行结果是成功还是失败 + ...... +``` + +### bt.release + +```python +bt.release() +``` + +蓝牙资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.start + +```python +bt.start() +``` + +开启蓝牙功能。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.stop + +```python +bt.stop() +``` + +关闭蓝牙功能。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.getStatus + +```python +bt.getStatus() +``` + +获取蓝牙的状态。 + +**返回值描述:** + +- 蓝牙状态:类型为整型,0-蓝牙处于停止状态,1-蓝牙正常运行中,-1-获取状态失败。 + +### bt.getLocalAddr + +```python +bt.getLocalAddr() +``` + +获取蓝牙地址。 + +**返回值描述:** + +- 蓝牙地址:执行成功返回类型为bytearray的蓝牙地址,大小6字节,失败返回整型-1。 + +**示例**: + +```python +>>> addr = bt.getLocalAddr() +>>> print(addr) +b'\xc7\xa13\xf8\xbf\x1a' +>>> mac = '{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}'.format(addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]) +>>> print('mac = [{}]'.format(mac)) +mac = [1a:bf:f8:33:a1:c7] +``` + +**注意**: + +该接口需要在蓝牙已经初始化完成并启动成功后才能调用,比如在回调中收到 event_id 为0的事件之后,即 start 成功后,去调用。 + +### bt.setLocalName + +```python +bt.setLocalName(code, name) +``` + +设置蓝牙名称。 + +**参数描述:** + +- `code`-编码模式,类型为整型,0 - UTF8,1 - GBK。 +- `name`-蓝牙名称,类型为string,最大长度22字节。 + +**返回值描述:** + +- 蓝牙地址:执行成功返回类型为bytearray的蓝牙地址,大小6字节,失败返回整型-1。 + +**示例**: + +```python +>>> bt.setLocalName(0, 'QuecPython-BT') +0 +``` + +### bt.getLocalName + +```python +bt.getLocalName() +``` + +获取蓝牙名称。 + +**返回值描述:** + +- 执行成功返回一个元组`(code, name)`,包含名称编码模式和蓝牙名称,失败返回整型-1。 + + +**示例**: + +```python +>>> bt.getLocalName() +(0, 'QuecPython-BT') +``` + +### bt.setVisibleMode + +```python +bt.setVisibleMode(mode) +``` + +设置蓝牙可见模式,即做从机时,被扫描时,是否可见以及可连接。 + +**参数描述:** + +- `mode`-可见模式,类型为整型,具体含义如下表。 + +| 值 | 含义 | +| ---- | ------------------------ | +| 0 | 不可被发现,不可被连接 | +| 1 | 可以被发现,但不可被连接 | +| 2 | 不可被发现,但可被连接 | +| 3 | 可以被发现,可被连接 | + +**返回值描述:** + +- 蓝牙地址:执行成功返回类型为bytearray的蓝牙地址,大小6字节,失败返回整型-1。 + +**示例**: + +```python +>>> bt.setVisibleMode(3) +0 +``` + +### bt.getVisibleMode + +```python +bt.getVisibleMode() +``` + +获取蓝牙可见模式。 + +**返回值描述:** + +- 执行成功返回蓝牙当前的可见模式值,失败返回整型-1。 + +**示例**: + +```python +>>> bt.getVisibleMode() +3 +``` + +### bt.startInquiry + +```python +bt.startInquiry(mode) +``` + +开始搜索周边的蓝牙设备。 + +**参数描述:** + +- `mode`-搜索类型。表示查询哪一类设备,当前直接写15,表示搜索所有。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +bt.startInquiry(15) +``` + +### bt.cancelInquiry + +```python +bt.cancelInquiry() +``` + +取消搜索操作。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.setChannel + +```python +bt.setChannel(channel) +``` + +设置音频输出通道,使用场景为蓝牙接听电话或者播放音频时。 + +**参数描述:** + +- `channel`-音频通道,类型为整型。0 - 听筒,1 - 耳机,2 - 喇叭。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.reconnect_set + +```python +bt.reconnect_set(max_count, period) +``` + +配置尝试重连的最大次数和相邻2次尝试重连的时间间隔,使用场景为模块和蓝牙设备距离拉远后断开连接时。 + +**参数描述:** + +- `max_count`-尝试重连的最大次数,类型为整型,设置0则关闭自动重连功能。 +- `period`-相邻2次尝试重连的时间间隔,单位秒,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +```python +bt.reconnect_set(25, 2)#配置尝试重连的最大次数为25,每次尝试重连的间隔为2秒 +``` + +### bt.reconnect + +```python +bt.reconnect() +``` + +模组主动重连上次配对过的设备,如手机。使用场景为模组重启后重新初始化打开蓝牙、或者模组不重启仅关闭蓝牙再重新打开蓝牙。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +**示例**: + +参考A2DP示例程序。 + +## HFP相关功能 + +提供蓝牙通话相关功能。 + +### bt.hfpInit + +```python +bt.hfpInit() +``` + +HFP 功能初始化 。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpRelease + +```python +bt.hfpRelease() +``` + +HFP 资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpConnect + +```python +bt.hfpConnect(addr) +``` + +连接AG,建立HFP连接。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpDisonnect + +```python +bt.hfpDisonnect(addr) +``` + +断开HFP连接。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpSetVolume + +```python +bt.hfpSetVolume(addr, vol) +``` + +设置蓝牙通话时的音量。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 +- `vol`-通话音量,类型为整型,范围 1-15。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpRejectAfterAnswer + +```python +bt.hfpRejectAfterAnswer(addr) +``` + +挂断接通的电话。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpRejectCall + +```python +bt.hfpRejectCall(addr) +``` + +拒接电话。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpAnswerCall + +```python +bt.hfpAnswerCall(addr) +``` + +接听电话。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpEnableVR + +```python +bt.hfpEnableVR(addr) +``` + +开启语音助手。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpDisableVR + +```python +bt.hfpDisableVR(addr) +``` + +关闭语音助手。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.hfpDisableVR + +```python +bt.hfpDisableVR(addr, cmd) +``` + +三方通话控制。 + +**参数描述:** + +- `addr`-AG端蓝牙地址,6个字节,类型为bytearray。 +- `cmd`-控制命令,类型为整型。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +## A2DP/AVRCP相关功能 + +提供蓝牙音乐相关功能。 + +### bt.a2dpavrcpInit + +```python +bt.a2dpavrcpInit() +``` + +A2DP和AVRCP功能初始化。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.a2dpavrcpRelease + +```python +bt.a2dpavrcpRelease() +``` + +A2DP和AVRCP 资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.a2dpDisconnect + +```python +bt.a2dpDisconnect(addr) +``` + +断开A2DP连接。 + +**参数描述:** + +- `addr`-A2DP主机蓝牙地址,6个字节,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.a2dpGetAddr + +```python +bt.a2dpGetAddr() +``` + +获取A2DP主机蓝牙地址。 + +**返回值描述:** + +- 执行成功返回bytearray类型的A2DP主机蓝牙地址,6字节,失败返回整型-1。 + +### bt.a2dpGetConnStatus + +```python +bt.a2dpGetConnStatus() +``` + +获取A2DP连接状态。 + +**返回值描述:** + +- A2DP连接状态,具体含义如下表。 + +| 值 | 类型 | 含义 | +| ---- | ---- | ------------ | +| -1 | int | 获取失败 | +| 0 | int | 连接已断开 | +| 1 | int | 正在连接中 | +| 2 | int | 已连接 | +| 3 | int | 正在断开连接 | + +### bt.avrcpStart + +```python +bt.avrcpStart() +``` + +控制主机开始播放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.avrcpPause + +```python +bt.avrcpPause() +``` + +控制主机停止播放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.avrcpPrev + +```python +bt.avrcpPrev() +``` + +控制主机播放上一首。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.avrcpNext + +```python +bt.avrcpNext() +``` + +控制主机播放下一首。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.avrcpSetVolume + +```python +bt.avrcpSetVolume(vol) +``` + +设置主机播放音量。 + +**参数描述:** + +- `vol`-播放音量,类型为整型,范围 0 - 11。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.avrcpGetVolume + +```python +bt.avrcpGetVolume() +``` + +获取主机播放音量。 + +**返回值描述:** + +- 执行成功返回整形音量值,失败返回整型-1。 + +### bt.avrcpGetPlayStatus + +```python +bt.avrcpGetPlayStatus() +``` + +获取主机播放状态。 + +**返回值描述:** + +- 播放状态,具体含义如下表。 + +| 值 | 类型 | 说明 | +| ---- | ---- | -------------- | +| -1 | int | 获取失败 | +| 0 | int | 没有播放 | +| 1 | int | 正在播放 | +| 2 | int | 暂停播放 | +| 3 | int | 正在切换下一首 | +| 4 | int | 正在切换下一首 | + +### bt.avrcpGetConnStatus + +```python +bt.avrcpGetConnStatus() +``` + +通过AVRCP协议获取主机连接状态。 + +**返回值描述:** + +- 连接状态,具体含义如下表。 + +| 值 | 类型 | 说明 | +| ---- | ---- | ------------ | +| -1 | int | 获取失败 | +| 0 | int | 连接已断开 | +| 1 | int | 正在连接中 | +| 2 | int | 已连接 | +| 3 | int | 正在断开连接 | + +## SPP相关功能 + +提供蓝牙传输相关功能。 + +### bt.sppInit + +```python +bt.sppInit() +``` + +SPP 功能初始化。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.sppRelease + +```python +bt.sppRelease() +``` + +SPP 资源释放。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.sppConnect + +```python +bt.sppConnect(addr) +``` + +建立SPP连接。 + +**参数描述:** + +- `addr`-蓝牙地址,类型为bytearray,6个字节。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.sppDisconnect + +```python +bt.sppDisconnect() +``` + +断开SPP连接。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + +### bt.sppSend + +```python +bt.sppSend(data) +``` + +**参数描述:** + +- `data`-待发送的数据,类型为bytearray。 + +**返回值描述:** + +- 执行成功返回整型0,失败返回整型-1。 + diff --git a/docs/API_reference/zh/sidebar.yaml b/docs/API_reference/zh/sidebar.yaml index 2d294fabba0ae5090b1dd1effca4689ceb8ec299..48c445a149c7e720dc01e5b7938f72de284f1004 100644 --- a/docs/API_reference/zh/sidebar.yaml +++ b/docs/API_reference/zh/sidebar.yaml @@ -53,6 +53,10 @@ items: file: QuecPython类库/cellLocator.md - label: wifilocator - WIFI定位 file: QuecPython类库/wifilocator.md + - label: fota - 固件升级相关功能 + file: QuecPython类库/fota.md + - label: app_fota - 用户文件升级相关功能 + file: QuecPython类库/app_fota.md - label: checkNet - 网络就绪检测 file: QuecPython类库/checkNet.md - label: wifiScan - WiFi扫描 @@ -82,6 +86,10 @@ items: file: QuecPython类库/quecgnss.md - label: securedata - 安全数据区 file: QuecPython类库/securedata.md + - label: ble - 低功耗蓝牙相关功能 + file: QuecPython类库/ble.md + - label: bt - 经典蓝牙相关功能 + file: QuecPython类库/bt.md - label: QuecPython组件库 file: QuecPython组件库/README.md items: