1# Test concurrency between filesystem access and BLE host. This is 2# particularly relevant on STM32WB where the second core is stalled while 3# flash operations are in progress. 4 5from micropython import const 6import time, machine, bluetooth, os 7 8TIMEOUT_MS = 10000 9 10LOG_PATH_INSTANCE0 = "stress_log_filesystem_0.log" 11LOG_PATH_INSTANCE1 = "stress_log_filesystem_1.log" 12 13_IRQ_CENTRAL_CONNECT = const(1) 14_IRQ_CENTRAL_DISCONNECT = const(2) 15_IRQ_GATTS_WRITE = const(3) 16_IRQ_GATTS_READ_REQUEST = const(4) 17_IRQ_PERIPHERAL_CONNECT = const(7) 18_IRQ_PERIPHERAL_DISCONNECT = const(8) 19_IRQ_GATTC_SERVICE_RESULT = const(9) 20_IRQ_GATTC_SERVICE_DONE = const(10) 21_IRQ_GATTC_CHARACTERISTIC_RESULT = const(11) 22_IRQ_GATTC_CHARACTERISTIC_DONE = const(12) 23_IRQ_GATTC_READ_RESULT = const(15) 24_IRQ_GATTC_READ_DONE = const(16) 25_IRQ_GATTC_WRITE_DONE = const(17) 26 27SERVICE_UUID = bluetooth.UUID("A5A5A5A5-FFFF-9999-1111-5A5A5A5A5A5A") 28CHAR_UUID = bluetooth.UUID("00000000-1111-2222-3333-444444444444") 29CHAR = ( 30 CHAR_UUID, 31 bluetooth.FLAG_READ | bluetooth.FLAG_WRITE | bluetooth.FLAG_NOTIFY | bluetooth.FLAG_INDICATE, 32) 33SERVICE = ( 34 SERVICE_UUID, 35 (CHAR,), 36) 37SERVICES = (SERVICE,) 38 39 40waiting_events = {} 41log_file = None 42 43 44def write_log(*args): 45 if log_file: 46 print(*args, file=log_file) 47 log_file.flush() 48 49 50last_file_write = 0 51 52 53def periodic_log_write(): 54 global last_file_write 55 t = time.ticks_ms() 56 if time.ticks_diff(t, last_file_write) > 50: 57 write_log("tick") 58 last_file_write = t 59 60 61def irq(event, data): 62 write_log("event", event) 63 64 if event == _IRQ_CENTRAL_CONNECT: 65 print("_IRQ_CENTRAL_CONNECT") 66 waiting_events[event] = data[0] 67 elif event == _IRQ_CENTRAL_DISCONNECT: 68 print("_IRQ_CENTRAL_DISCONNECT") 69 elif event == _IRQ_PERIPHERAL_CONNECT: 70 print("_IRQ_PERIPHERAL_CONNECT") 71 waiting_events[event] = data[0] 72 elif event == _IRQ_PERIPHERAL_DISCONNECT: 73 print("_IRQ_PERIPHERAL_DISCONNECT") 74 elif event == _IRQ_GATTC_SERVICE_RESULT: 75 # conn_handle, start_handle, end_handle, uuid = data 76 if data[-1] == SERVICE_UUID: 77 print("_IRQ_GATTC_SERVICE_RESULT", data[3]) 78 waiting_events[event] = (data[1], data[2]) 79 else: 80 return 81 elif event == _IRQ_GATTC_SERVICE_DONE: 82 print("_IRQ_GATTC_SERVICE_DONE") 83 elif event == _IRQ_GATTC_CHARACTERISTIC_RESULT: 84 # conn_handle, def_handle, value_handle, properties, uuid = data 85 if data[-1] == CHAR_UUID: 86 print("_IRQ_GATTC_CHARACTERISTIC_RESULT", data[-1]) 87 waiting_events[event] = data[2] 88 else: 89 return 90 elif event == _IRQ_GATTC_CHARACTERISTIC_DONE: 91 print("_IRQ_GATTC_CHARACTERISTIC_DONE") 92 elif event == _IRQ_GATTC_READ_RESULT: 93 print("_IRQ_GATTC_READ_RESULT", bytes(data[-1])) 94 elif event == _IRQ_GATTC_READ_DONE: 95 print("_IRQ_GATTC_READ_DONE", data[-1]) 96 elif event == _IRQ_GATTC_WRITE_DONE: 97 print("_IRQ_GATTC_WRITE_DONE", data[-1]) 98 elif event == _IRQ_GATTS_WRITE: 99 print("_IRQ_GATTS_WRITE") 100 elif event == _IRQ_GATTS_READ_REQUEST: 101 print("_IRQ_GATTS_READ_REQUEST") 102 103 if event not in waiting_events: 104 waiting_events[event] = None 105 106 107def wait_for_event(event, timeout_ms): 108 t0 = time.ticks_ms() 109 while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms: 110 periodic_log_write() 111 if event in waiting_events: 112 return waiting_events.pop(event) 113 machine.idle() 114 raise ValueError("Timeout waiting for {}".format(event)) 115 116 117# Acting in peripheral role. 118def instance0(): 119 global log_file 120 log_file = open(LOG_PATH_INSTANCE0, "w") 121 write_log("start") 122 ble.active(1) 123 ble.irq(irq) 124 multitest.globals(BDADDR=ble.config("mac")) 125 ((char_handle,),) = ble.gatts_register_services(SERVICES) 126 multitest.next() 127 try: 128 for repeat in range(2): 129 print("gap_advertise") 130 ble.gap_advertise(50_000, b"\x02\x01\x06\x04\xffMPY") 131 # Wait for central to connect, do a sequence of read/write, then disconnect. 132 wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) 133 for op in range(4): 134 wait_for_event(_IRQ_GATTS_READ_REQUEST, TIMEOUT_MS) 135 wait_for_event(_IRQ_GATTS_WRITE, TIMEOUT_MS) 136 wait_for_event(_IRQ_CENTRAL_DISCONNECT, 2 * TIMEOUT_MS) 137 finally: 138 ble.active(0) 139 log_file.close() 140 os.unlink(LOG_PATH_INSTANCE0) 141 142 143# Acting in central role. 144def instance1(): 145 global log_file 146 log_file = open(LOG_PATH_INSTANCE1, "w") 147 write_log("start") 148 ble.active(1) 149 ble.irq(irq) 150 multitest.next() 151 try: 152 for repeat in range(2): 153 # Connect to peripheral and then disconnect. 154 print("gap_connect") 155 ble.gap_connect(BDADDR[0], BDADDR[1], 5000) 156 conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) 157 158 # Discover services. 159 print("gattc_discover_services") 160 ble.gattc_discover_services(conn_handle) 161 start_handle, end_handle = wait_for_event(_IRQ_GATTC_SERVICE_RESULT, TIMEOUT_MS) 162 wait_for_event(_IRQ_GATTC_SERVICE_DONE, TIMEOUT_MS) 163 164 # Discover characteristics. 165 print("gattc_discover_characteristics") 166 ble.gattc_discover_characteristics(conn_handle, start_handle, end_handle) 167 value_handle = wait_for_event(_IRQ_GATTC_CHARACTERISTIC_RESULT, TIMEOUT_MS) 168 wait_for_event(_IRQ_GATTC_CHARACTERISTIC_DONE, TIMEOUT_MS) 169 170 for op in range(4): 171 print("gattc_read") 172 ble.gattc_read(conn_handle, value_handle) 173 wait_for_event(_IRQ_GATTC_READ_RESULT, TIMEOUT_MS) 174 wait_for_event(_IRQ_GATTC_READ_DONE, TIMEOUT_MS) 175 print("gattc_write") 176 ble.gattc_write(conn_handle, value_handle, "{}".format(op), 1) 177 wait_for_event(_IRQ_GATTC_WRITE_DONE, TIMEOUT_MS) 178 179 # Disconnect. 180 print("gap_disconnect:", ble.gap_disconnect(conn_handle)) 181 wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, 2 * TIMEOUT_MS) 182 finally: 183 ble.active(0) 184 log_file.close() 185 os.unlink(LOG_PATH_INSTANCE1) 186 187 188ble = bluetooth.BLE() 189