首頁>技術>

MicroPython中提供了ubluetooth模組作為藍芽BLE(Bluetooth Low Energy)的操作介面,其主要提供了藍芽控制器層面的操作, 匹配低階藍芽BLE協議,但未整合各種特定裝置型別配置檔案(Profile),僅提供基礎實現模組以供高階層抽象,故稱作低階藍芽BLE介面。

在藍芽BLE中,一個裝置可能需要以多個角色進行工作。當前,其能夠支援中心(Central)、外設(Peripheral)、廣播者(Broadcaster)和觀察者(Observer)角色,還能夠支援GATT伺服器、GATT客戶端和L2CAP面向連線通道的工作模式。目前,僅有部分MicroPython移植版本能夠支援配對和繫結操作。

注意:該模組仍在開發中,其涉及的類、函式、方法和常量定義均有可能發生變化。

class BLE

建構函式

class ubluetooth.BLE

返回BLE類的單例物件。

配置

BLE.active([active,] /)

啟用藍芽BLE射頻元件,並返回其當前狀態。在使用該類下面各方法之前,必須首先進行該操作以啟用射頻元件。

BLE.config('param', /)BLE.config(*, param=value, ...)

查詢或者設定藍芽BLE相應配置引數值。查詢引數值時,引數名需以字串形式傳入,每次只能查詢一個值。設定引數值時,應使用關鍵字引數的語法規則傳入引數名和其對應值,每次可設定多個引數值。

當前支援的配置引數值有:

‘mac’:當前在用的地址,其與當前地址模式有關,查詢時返回(addr_type,addr)形式的元組。具體地址型別在gatts_write部分有詳細描述。

‘addr_mode’:設定地址模式。可能取值如下:

0x00-PUBLIC 使用控制器公共地址;0x01-RANDOM 使用設定的靜態偽隨機地址;0x02-RPA 使用可自解析的私有地址;0x03-NRPA 使用不可自解析的私有地址。

預設情況下,如果PUBLIC地址可用,優先使用PUBLIC地址,否則使用RANDOM地址。

‘gap_name’:查詢或設定通用存取規範GAP(Generic Access Profile)裝置名,該裝置名可用服務控制代碼0x1800和特性控制代碼0x2a00標識。該配置值可以在任意時間進行任意次修改。

‘rxbuf’:查詢或者設定內部用於儲存事件資訊的緩衝區大小。該緩衝區對於藍芽BLE內部驅動全域性有效,能夠處理所有事件,包括所有特性的接收資料。增大該配置值有助於更好地處理類似掃描結果返回的突發資料,提升接收更大的特性資料值的能力。

‘mtu’:查詢或設定在屬性MTU交換期間所使用的MTU值(MTU:Maximum transmission unit,指在一個協議資料單元中能夠傳輸的最大資料量)。程式最終使用的MTU取該配置值和對方裝置MTU值中的較小值。屬性MTU交換過程不會自動進行,其要麼由對端裝置主動發起,要麼由本裝置透過呼叫gattc_exchange_mtu手動發起。使用_IRQ_MTU_EXCHANGED事件可以獲取特定藍芽連線的最終MTU值。

‘bond’:用於設定是否需要在配對期間進行繫結操作。設定該引數值後,配對請求過程中會置位’bond’標誌,並且儲存兩方裝置的金鑰。

‘mitm’:設定配對時,是否需要特意防止MITM(中間人攻擊)。

‘io’:設定裝置的輸入/輸出能力,該能力體現於在配對期間裝置能夠以哪種方式進行金鑰交換。可選項如下:

_IO_CAPABILITY_DISPLAY_ONLY = const(0)_IO_CAPABILITY_DISPLAY_YESNO = const(1)_IO_CAPABILITY_KEYBOARD_ONLY = const(2)_IO_CAPABILITY_NO_INPUT_OUTPUT = const(3)_IO_CAPABILITY_KEYBOARD_DISPLAY = const(4)

‘le_secure’:設定是否需要”LE Secure”式配對,預設為False。(LE Secure和 LE Legacy為藍芽BLE支援的兩種配對方式,預設為後者)

事件處理

BLE.irq(handler, /)

為藍芽BLE協議棧註冊事件回撥函式。該回調函式具有兩個引數,event(如下事件程式碼之一)和data(事件特定的元組值)。

注意:為避免進行非必要的記憶體分配,data元組中的addr,adv_data,char_data,notify_data和uuid變數均為ubluetooth模組內部緩衝區中記憶體例項的只讀映像,僅在IRQ回撥函式被呼叫期間有效。如果應用程式需要儲存這些值(比如儲存在類例項中或者全域性變數中)以便IRQ回撥函式返回後能夠使用,需要以bytes()或者bluetooth.UUID()形式複製所需資料。比如下面形式:

connected_addr=bytes(addr) #若為adv_data、char_data或notify_data,亦需此形式matched_uuid=bluetooth.UUID(uuid)

舉例來講,IRQ回撥函式處理裝置掃描的結果時,需要解析adv_data以查驗其是否為正確的裝置,然後再複製儲存該地址資料以在程式其它地方使用。另外,如果需要在IRQ回撥函式中列印資料,可以使用print(bytes(addr))。

如下事件回撥函式展示了所有可能的事件:

def bt_irq(event, data):     if event == _IRQ_CENTRAL_CONNECT:     				 #中心裝置已連線到本外設裝置上         		 conn_handle, addr_type, addr = data     elif event == _IRQ_CENTRAL_DISCONNECT:             #中心裝置已與本外設裝置斷開             conn_handle, addr_type, addr = data     elif event == _IRQ_GATTS_WRITE:             #客戶端已經對特性值或描述符值進行了寫入操作             conn_handle, attr_handle = data     elif event == _IRQ_GATTS_READ_REQUEST:            #客戶端發起了讀取請求(僅支援STM32平臺)            #返回非零值表示拒絕請求,零值表示接受請求。             conn_handle, attr_handle = data     elif event == _IRQ_SCAN_RESULT:             #掃描結果             addr_type, addr, adv_type, rssi, adv_data = data     elif event == _IRQ_SCAN_DONE:             #掃描週期結束,或手動結束掃描             pass     elif event == _IRQ_PERIPHERAL_CONNECT:             #gap_connect()成功呼叫             conn_handle, addr_type, addr = data     elif event == _IRQ_PERIPHERAL_DISCONNECT:             #所連線的外設裝置已斷開             conn_handle, addr_type, addr = data     elif event == _IRQ_GATTC_SERVICE_RESULT:            #呼叫gattc_discover_services()時每次發現服務後被觸發             conn_handle, start_handle, end_handle, uuid = data     elif event == _IRQ_GATTC_SERVICE_DONE:             #服務發現完成(成功時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, status = data     elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT:             #呼叫gattc_discover_characteristics()時每次發現特性後被觸發             conn_handle, def_handle, value_handle, properties, uuid = data     elif event == _IRQ_GATTC_CHARACTERISTIC_DONE:             #特性發現完成(成功時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, status = data     elif event == _IRQ_GATTC_DESCRIPTOR_RESULT:             #呼叫gattc_discover_descriptors()時每次發現描述符後被觸發             conn_handle, dsc_handle, uuid = data     elif event == _IRQ_GATTC_DESCRIPTOR_DONE:             #描述符發現完成(成功時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, status = data     elif event == _IRQ_GATTC_READ_RESULT:             #gattc_read()返回結果             conn_handle, value_handle, char_data = data     elif event == _IRQ_GATTC_READ_DONE:             #gattc_read()呼叫完成(成功時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, value_handle, status = data     elif event == _IRQ_GATTC_WRITE_DONE:             #gattc_write()呼叫完成(成功時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, value_handle, status = data     elif event == _IRQ_GATTC_NOTIFY:             #伺服器傳送了上報(Notification)請求             conn_handle, value_handle, notify_data = data     elif event == _IRQ_GATTC_INDICATE:             #伺服器傳送了指示(Indication)請求             conn_handle, value_handle, notify_data = data     elif event == _IRQ_GATTS_INDICATE_DONE:             #客戶端確認了指示(Indication)請求(成功確認時狀態值為零,否則,不同平臺依據具體程式碼實現而不同)             conn_handle, value_handle, status = data     elif event == _IRQ_MTU_EXCHANGED:            #屬性MTU交換完成(該交換可能由自身或者對方裝置發起)            conn_handle, mtu = data     elif event == _IRQ_L2CAP_ACCEPT:             #接受/拒絕新的通道連線(返回非零值表示拒絕連線,零值或者None表示接受連線)             conn_handle, cid, psm, our_mtu, peer_mtu = data     elif event == _IRQ_L2CAP_CONNECT:             #新通道連線已建立(可能為主動連線的返回結果,也可能為被動接受連線的狀態指示).             conn_handle, cid, psm, our_mtu, peer_mtu = data     elif event == _IRQ_L2CAP_DISCONNECT:             #已建立的通道被斷開(狀態值為零),或者主動連線嘗試失敗(狀態值非零)              conn_handle, cid, psm, status = data     elif event == _IRQ_L2CAP_RECV:             #通道接收到資料,用使用l2cap_recvinto去讀取資料             conn_handle, cid = data     elif event == _IRQ_L2CAP_SEND_READY:             #前次l2cap_send已經失敗返回,此時該通道可以用於再次傳送(如果狀態值非零,傳輸緩衝區溢位,應用程式應該重新發送資料)             conn_handle, cid, status = data     elif event == _IRQ_CONNECTION_UPDATE:             #對方裝置更新了連線引數             conn_handle, conn_interval, conn_latency, supervision_timeout, status = data     elif event == _IRQ_ENCRYPTION_UPDATE:             #加密狀態已改變(可能由於配對或繫結).             conn_handle, encrypted, authenticated, bonded, key_size = data     elif event == _IRQ_GET_SECRET:            #返回已經儲存完畢的金鑰。(如果key為None,應返回sec_type的第index個值,否則,返回sec_type和key的對應值)            sec_type, index, key = data            return value     elif event == _IRQ_SET_SECRET:             #儲存sec_type和key對應的金鑰             sec_type, key, value = data             return True     elif event == _IRQ_PASSKEY_ACTION:            #在此處響應配對期間的配對金鑰請求(passkey request),可檢視gap_passkey()部分獲取詳情。            #此處進行的操作應對應於”io”引數配置的能力,如果操作為數字比對(numric comparison),passkey應為非零值            conn_handle, action, passkey = data

上面涉及的事件程式碼有如下這些:

from micropython import const        _IRQ_CENTRAL_CONNECT = const(1)        _IRQ_CENTRAL_DISCONNECT = const(2)        _IRQ_GATTS_WRITE = const(3)        _IRQ_GATTS_READ_REQUEST = const(4)        _IRQ_SCAN_RESULT = const(5)        _IRQ_SCAN_DONE = const(6)        _IRQ_PERIPHERAL_CONNECT = const(7)        _IRQ_PERIPHERAL_DISCONNECT = const(8)        _IRQ_GATTC_SERVICE_RESULT = const(9)        _IRQ_GATTC_SERVICE_DONE = const(10)        _IRQ_GATTC_CHARACTERISTIC_RESULT = const(11)        _IRQ_GATTC_CHARACTERISTIC_DONE = const(12)        _IRQ_GATTC_DESCRIPTOR_RESULT = const(13)        _IRQ_GATTC_DESCRIPTOR_DONE = const(14)        _IRQ_GATTC_READ_RESULT = const(15)        _IRQ_GATTC_READ_DONE = const(16)        _IRQ_GATTC_WRITE_DONE = const(17)        _IRQ_GATTC_NOTIFY = const(18)        _IRQ_GATTC_INDICATE = const(19)        _IRQ_GATTS_INDICATE_DONE = const(20)        _IRQ_MTU_EXCHANGED = const(21)        _IRQ_L2CAP_ACCEPT = const(22)        _IRQ_L2CAP_CONNECT = const(23)        _IRQ_L2CAP_DISCONNECT = const(24)        _IRQ_L2CAP_RECV = const(25)        _IRQ_L2CAP_SEND_READY = const(26)        _IRQ_CONNECTION_UPDATE = const(27)        _IRQ_ENCRYPTION_UPDATE = const(28)        _IRQ_GET_SECRET = const(29)        _IRQ_SET_SECRET = const(30)

對於_IRQ_GATTS_READ_REQUEST事件,可能的返回值如下:

_GATTS_NO_ERROR = const(0x00)_GATTS_ERROR_READ_NOT_PERMITTED = const(0x02)_GATTS_ERROR_WRITE_NOT_PERMITTED = const(0x03)_GATTS_ERROR_INSUFFICIENT_AUTHENTICATION = const(0x05)_GATTS_ERROR_INSUFFICIENT_AUTHORIZATION = const(0x08)_GATTS_ERROR_INSUFFICIENT_ENCRYPTION = const(0x0f)

對於_IRQ_PASSKEY_ACTION 事件,可能的action取值如下:

_PASSKEY_ACTION_NONE = const(0)_PASSKEY_ACTION_INPUT = const(2)_PASSKEY_ACTION_DISPLAY = const(3)_PASSKEY_ACTION_NUMERIC_COMPARISON = const(4)

為了節省韌體程式碼的空間佔用,這些常量定義沒有包含在ubluetooth模組中,若程式中需要使用,可以自行新增相應定義。

廣播者角色

BLE.gap_advertise(interval_us,adv_data=None,*, resp_data=None, connectable=True)

開始以特定時間間隔(毫秒級)廣播。該時間間隔會取整到625us的整數倍。若要停止廣播,只需將interval_us設為None。

adv_data和resp_data可以是有緩衝意義的任何資料型別(比如bytes,bytearray,str等等)。adv_data將包含在所有的廣播資料中,resp_data用於對活動掃描的回覆報文。

注意:若adv_data或resp_data引數為None,其會重用前次呼叫所傳入的引數值。這樣,廣播者能夠透過gap_advertise(interval_us)形式的呼叫就能恢復廣播。若要清空廣播的應用層負載,可以傳入一個空的bytes,比如b’’。

觀察者角色

BLE.gap_scan(duration_ms, interval_us=1280000, window_us=11250, active=False, /)

持續進行特定時間(微妙級)的的掃描操作。若要一直掃描下去,需把duration_ms設為0,若要停止掃描,需把duration_ms設為None。

使用interval_us和window_us可以配置掃描佔空比:掃描器每隔interval_ms時間間隔掃描一次,每次持續duration_ms時間,該時間內真正工作window_us時間。預設的後臺掃描時間間隔和視窗時間分別為1.28秒和11.25毫秒。

每次掃描到結果後,_IRQ_SCAN_RESULT事件會被觸發,並帶有如下事件資料:(addr_type,addr,adv_type,rssi,adv_data)。

addr_type值表明為公共地址還是隨機地址:

0x00-PUBLIC0x01-隨機地址(可以為靜態隨機、自解析私有地址RPA或者非自解析私有地址NRPA,其中具體型別編碼於地址本身中)

adv_type取值對應於藍牙規範中的規定:

0x00-ADV_IND                     可連線、可掃描非定向廣播0x01-ADV_DIRECT_IND        可連線定向廣播0x02-ADV_SCAN_IND          可掃描非定向廣播0x03-ADV_NONCONN_IND 不可連線非定向廣播0x04-SCAN_RSP                   掃描響應

active:若要在結果中收到掃描響應資訊,應把該值設為True。

無論由於掃描持續時間到期還是由於使用者顯式停止掃描,掃描結束時_IRQ_SCAN_DONE事件均會被觸發。

中心角色

觀察者角色裝置決定主動連線特定廣播者時,其角色轉換為中心裝置。其既可以主動連線所掃描到的外設裝置,也可以指定連線已知地址的外設裝置。

BLE.gap_connect(addr_type, addr, scan_duration_ms=2000, /)

連線到特定外設裝置(可以檢視gap_scan()部分以瞭解具體地址型別)。成功後,_IRQ_PERIPHERAL_CONNECT事件會被觸發。

外設角色

外設裝置用於傳送可連線廣播資訊(詳情可檢視gap_advertise()部分)。其通常作為GATT伺服器使用,使用gatts_register_services()註冊服務和特性。

當連線中心裝置後,_IRQ_CENTRAL_CONNECT事件會被觸發。

中心和外設角色

BLE.gap_disconnect(conn_handle, /)

斷開特定的連線。其既可能被已接受連線的中心裝置呼叫,也能被髮起連線的外設裝置呼叫。成功後,_IRQ_PERIPHERAL_DISCONNECT事件或者 _IRQ_CENTRAL_DISCONNECT事件會被觸發。如果conn_handle所指定的連線並未真正連線上,該函式會返回False,否則返回True。

35
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 這個開發常識,你必須瞭解一下