diff --git a/tests/multi_bluetooth/ble_deepsleep.py b/tests/multi_bluetooth/ble_deepsleep.py new file mode 100644 index 0000000000..7c34c03606 --- /dev/null +++ b/tests/multi_bluetooth/ble_deepsleep.py @@ -0,0 +1,96 @@ +# Test BLE re-connect after peripheral deepsleep. +# instance0 needs to be a device capable of deepsleep without disconnecting the +# REPL, eg. STM32WB55 Nucleo board with REPL on UART port. + +from micropython import const +import time, machine, bluetooth + +TIMEOUT_MS = 4000 + +_IRQ_CENTRAL_CONNECT = const(1) +_IRQ_CENTRAL_DISCONNECT = const(2) +_IRQ_PERIPHERAL_CONNECT = const(7) +_IRQ_PERIPHERAL_DISCONNECT = const(8) + +waiting_events = {} + + +def irq(event, data): + if event == _IRQ_CENTRAL_CONNECT: + print("_IRQ_CENTRAL_CONNECT") + waiting_events[event] = data[0] + elif event == _IRQ_CENTRAL_DISCONNECT: + print("_IRQ_CENTRAL_DISCONNECT") + elif event == _IRQ_PERIPHERAL_CONNECT: + print("_IRQ_PERIPHERAL_CONNECT") + waiting_events[event] = data[0] + elif event == _IRQ_PERIPHERAL_DISCONNECT: + print("_IRQ_PERIPHERAL_DISCONNECT") + + if event not in waiting_events: + waiting_events[event] = None + + +def wait_for_event(event, timeout_ms): + t0 = time.ticks_ms() + while time.ticks_diff(time.ticks_ms(), t0) < timeout_ms: + if event in waiting_events: + return waiting_events.pop(event) + machine.idle() + raise ValueError("Timeout waiting for {}".format(event)) + + +# Acting in peripheral role. +def instance0(): + multitest.globals(BDADDR=ble.config("mac")) + print("gap_advertise") + ble.gap_advertise(20_000, b"\x02\x01\x06\x04\tMPY") + multitest.next() + # Wait for central to connect, then wait for it to disconnect. + wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) + wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS) + + multitest.expect_reboot(resume="instance0_resume", delay_ms=100) + machine.deepsleep(100) + + +# Acting in peripheral role. +def instance0_resume(): + # continue here after reboot + print("restarted") + print("gap_advertise") + ble.gap_advertise(20_000, b"\x02\x01\x06\x04\tMPY") + try: + # Wait for central to connect, then disconnect it. + conn_handle = wait_for_event(_IRQ_CENTRAL_CONNECT, TIMEOUT_MS) + print("gap_disconnect:", ble.gap_disconnect(conn_handle)) + wait_for_event(_IRQ_CENTRAL_DISCONNECT, TIMEOUT_MS) + finally: + ble.active(0) + + +# Acting in central role. +def instance1(): + multitest.next() + try: + # Connect to peripheral and then disconnect. + print("gap_connect") + ble.gap_connect(*BDADDR) + conn_handle = wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) + print("gap_disconnect:", ble.gap_disconnect(conn_handle)) + wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS) + + # Connect to peripheral and then let the peripheral disconnect us. + # Extra scan timeout allows for the peripheral to receive the disconnect + # event and start advertising again. + print("gap_connect") + ble.gap_connect(BDADDR[0], BDADDR[1], 5000) + wait_for_event(_IRQ_PERIPHERAL_CONNECT, TIMEOUT_MS) + wait_for_event(_IRQ_PERIPHERAL_DISCONNECT, TIMEOUT_MS) + finally: + ble.active(0) + + +ble = bluetooth.BLE() +ble.active(1) +ble.irq(irq) diff --git a/tests/multi_bluetooth/ble_deepsleep.py.exp b/tests/multi_bluetooth/ble_deepsleep.py.exp new file mode 100644 index 0000000000..cc699768a5 --- /dev/null +++ b/tests/multi_bluetooth/ble_deepsleep.py.exp @@ -0,0 +1,18 @@ +--- instance0 --- +gap_advertise +_IRQ_CENTRAL_CONNECT +_IRQ_CENTRAL_DISCONNECT +WAIT_FOR_REBOOT instance0_resume 100 +restarted +gap_advertise +_IRQ_CENTRAL_CONNECT +gap_disconnect: True +_IRQ_CENTRAL_DISCONNECT +--- instance1 --- +gap_connect +_IRQ_PERIPHERAL_CONNECT +gap_disconnect: True +_IRQ_PERIPHERAL_DISCONNECT +gap_connect +_IRQ_PERIPHERAL_CONNECT +_IRQ_PERIPHERAL_DISCONNECT