Repeated connection to NRF52 fails with NrfError.rpc_h5_transport_state
Script to reproduce the issue:
from blatann import BleDevice
dev = '/dev/ttyACM0'
def create():
print('create')
ble = BleDevice(dev)
ble.open()
return ble
def destroy(ble):
print('destroy')
ble.close()
ble = create()
destroy(ble)
ble = create()
destroy(ble)
Second open() raises pc_ble_driver_py.exceptions.NordicSemiException: Failed to open. Error code: NrfError.rpc_h5_transport_state.
Package versions:
blatann==0.3.6
pc-ble-driver-py==0.15.0
NRF52 dongle firmare:
connectivity_4.1.2_usb_with_s132_5.1.0.hex from pc-ble-driver-py package.
Thanks for reporting, this is an issue I've known about for awhile but never formally opened a ticket for it.
The issue is that when the device is closed, the micro is reset to ensure no more bluetooth activity after that point. With the USB-based firmware images, the USB device goes away completely and has to be re-enumerated before opening again, so a delay is needed between close and open. Using serial-based firmware images with the nordic dev kit don't seem to have this issue.
The delay amount I found depends on the OS and other factors, so baking in a delay on either open or close is non-ideal and some form of retry mechanism is likely required.
A simple workaround for now is to sleep between open and close which is what I do for my integrated tests here
Hi,
I implemented a possible fix for the issue. Its a retry loop with a scanner for the nrf52 dongle based on libusb to not use a long delay. If its ok I would create a pullrequest. Please let me know if you have any further suggestions.
regards Alex
Hi any updates on this? I tried the changes suggested by teehee but those did not fix the issue for me
Check my comment with #103 providing a script that may help improve the situation with the nRF52840-Dongle (PCA10059).
Adjusted to the original example code in this #75 ticket, it would look like:
from pathlib import Path
import serial.tools.list_ports as slp
import time
from blatann import BleDevice
dev = '/dev/ttyACM0'
def wait_for_serial_port(serial_port, retries=10, delay=0.5):
print("Wait for serial port {} to be ready...".format(serial_port))
for retry in range(retries):
print("run/retry = {}".format(retry))
for port in slp.comports():
if port.device == serial_port:
print("Found with usb_info={}".format(port.usb_info()))
# HACK: add just a little more time...
# as sometimes it is found while path device is not yet ready
time.sleep(delay)
if Path(serial_port).exists():
return True
print("... but path didn't exist (yet)")
time.sleep(delay)
return False
def get_ble_device(serial_port, retries=10, delay=0.5):
if not wait_for_serial_port(serial_port, retries=retries, delay=delay):
return None
ble_device = BleDevice(serial_port, log_driver_comms=True)
return ble_device
def create():
print('create')
# ble = BleDevice(dev)
ble = get_ble_device(dev)
ble.open()
return ble
def destroy(ble):
print('destroy')
ble.close()
ble = create()
destroy(ble)
ble = create()
destroy(ble)
Still adding the requirement for pyserial 3.5 of course.
The output on my Linux test machine with the nRF52840-Dongle looks like:
create
Wait for serial port /dev/ttyACM0 to be ready...
run/retry = 0
Found with usb_info=USB VID:PID=1915:C00A SER=F20673606AE3 LOCATION=1-2.2:1.1
destroy
create
Wait for serial port /dev/ttyACM0 to be ready...
run/retry = 0
run/retry = 1
run/retry = 2
run/retry = 3
run/retry = 4
run/retry = 5
run/retry = 6
Found with usb_info=USB VID:PID=1915:C00A SER=F20673606AE3 LOCATION=1-2.2:1.1
destroy