Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Repeated connection to NRF52 fails with NrfError.rpc_h5_transport_state #75

Open
juhhov opened this issue Feb 25, 2021 · 4 comments
Open

Comments

@juhhov
Copy link

juhhov commented Feb 25, 2021

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.

@ThomasGerstenberg
Copy link
Owner

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

teeheee pushed a commit to teeheee/blatann that referenced this issue Nov 4, 2021
added a reconnect feature in open that also reruns __init__

added wait_for_nrf52_to_restart to prevent the use of long delays.
The device is scanned with libusb

added libusb to requirements
@teeheee
Copy link

teeheee commented Nov 4, 2021

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

@regin-mBohm
Copy link

Hi
any updates on this? I tried the changes suggested by teehee but those did not fix the issue for me

@mdxs
Copy link
Contributor

mdxs commented Nov 8, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants