1# Test BLE GAP connect/disconnect with pairing, and read an encrypted characteristic 2# TODO: add gap_passkey testing 3 4from micropython import const 5import time, machine, bluetooth 6 7TIMEOUT_MS = 4000 8 9_IRQ_CENTRAL_CONNECT = const(1) 10_IRQ_CENTRAL_DISCONNECT = const(2) 11_IRQ_GATTS_READ_REQUEST = const(4) 12_IRQ_PERIPHERAL_CONNECT = const(7) 13_IRQ_PERIPHERAL_DISCONNECT = const(8) 14_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11) 15_IRQ_GATTC_CHARACTERISTIC_DONE = const(12) 16_IRQ_GATTC_READ_RESULT = const(15) 17_IRQ_ENCRYPTION_UPDATE = const(28) 18 19_FLAG_READ = const(0x0002) 20_FLAG_READ_ENCRYPTED = const(0x0200) 21 22SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A") 23CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444") 24CHAR = (CHAR_UUID, _FLAG_READ | _FLAG_READ_ENCRYPTED) 25SERVICE = (SERVICE_UUID, (CHAR,)) 26 27waiting_events = {} 28 29 30def irq(event, data): 31 if event == _IRQ_CENTRAL_CONNECT: 32 print("_IRQ_CENTRAL_CONNECT") 33 waiting_events[event] = data[0] 34 elif event == _IRQ_CENTRAL_DISCONNECT: 35 print("_IRQ_CENTRAL_DISCONNECT") 36 elif event == _IRQ_GATTS_READ_REQUEST: 37 print("_IRQ_GATTS_READ_REQUEST") 38 elif event == _IRQ_PERIPHERAL_CONNECT: 39 print("_IRQ_PERIPHERAL_CONNECT") 40 waiting_events[event] = data[0] 41 elif event == _IRQ_PERIPHERAL_DISCONNECT: 42 print("_IRQ_PERIPHERAL_DISCONNECT") 43 elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: 44 if data[-1] == CHAR_UUID: 45 print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1]) 46 waiting_events[event] = data[2] 47 else: 48 return 49 elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: 50 print("_IRQ_GATTC_CHARACTERISTIC_DONE") 51 elif event == _IRQ_GATTC_READ_RESULT: 52 print("_IRQ_GATTC_READ_RESULT", bytes(data[-1])) 53 elif event == _IRQ_ENCRYPTION_UPDATE: 54 print("_IRQ_ENCRYPTION_UPDATE", data[1], data[2], data[3]) 55 56 if event not in waiting_events: 57 waiting_events[event] = None 58 59 60def wait_for_event(event, timeout_ms): 61 t0 = time.ticks_ms() 62 while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms: 63 if event in waiting_events: 64 return waiting_events.pop(event) 65 machine.idle() 66 raise ValueError("Timeout waiting for {}".format(event)) 67 68 69# Acting in peripheral role. 70def instance0(): 71 multitest.globals(BDADDR=ble.config("mac")) 72 ((char_handle,),) = ble.gatts_register_services((SERVICE,)) 73 ble.gatts_write(char_handle, "encrypted") 74 print("gap_advertise") 75 ble.gap_advertise(20_000, b"\x02\x01\x06\x04\xffMPY") 76 multitest.next() 77 try: 78 # Wait for central to connect. 79 wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) 80 81 # Wait for pairing event. 82 wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS) 83 84 # Wait for GATTS read request. 85 wait_for_event(_IRQ_GATTS_READ_REQUEST, TIMEOUT_MS) 86 87 # Wait for central to disconnect. 88 wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS) 89 finally: 90 ble.active(0) 91 92 93# Acting in central role. 94def instance1(): 95 multitest.next() 96 try: 97 # Connect to peripheral. 98 print("gap_connect") 99 ble.gap_connect(*BDADDR) 100 conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) 101 102 # Discover characteristics (before pairing, doesn't need to be encrypted). 103 ble.gattc_discover_characteristics(conn_handle, 1, 65535) 104 value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS) 105 wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS) 106 107 # Pair with the peripheral. 108 print("gap_pair") 109 ble.gap_pair(conn_handle) 110 111 # Wait for the pairing event. 112 wait_for_event(_IRQ_ENCRYPTION_UPDATE, TIMEOUT_MS) 113 114 # Read the peripheral's characteristic, should be encrypted. 115 print("gattc_read") 116 ble.gattc_read(conn_handle, value_handle) 117 wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS) 118 119 # Disconnect from the peripheral. 120 print("gap_disconnect:", ble.gap_disconnect(conn_handle)) 121 wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS) 122 finally: 123 ble.active(0) 124 125 126ble = bluetooth.BLE() 127ble.config(mitm=True, le_secure=True, bond=False) 128ble.active(1) 129ble.irq(irq) 130