SiliconLabs / pybgapi

Other
3 stars 1 forks source link

Unreliable #3

Open jensolsson opened 4 months ago

jensolsson commented 4 months ago

Hi

I use this library together with a thunderboard which I have installed the correct firmware to. I have a very simple applicaiton that should scan for a specific peripheral, connect to it, find a specific service / characteristic and write to it.

It works sometimes, but commonly for example when I connect and try to retrieve services, I dont get a response. I power cycle the thunderboard and it may work, and then stops working again. Why is it so unreliable?

import bgapi
import time

SERVICE_UUID = bytes.fromhex("708ec9bd-a35d-4f81-9474-49276f0be635".replace("-", ""))[::-1]
CHARACTERISTIC_UUID = bytes.fromhex("a31afb58-0cef-4656-b187-2eb62249d7b7".replace("-", ""))[::-1]

l = bgapi.BGLib(bgapi.SerialConnector('/dev/tty.usbmodem0004402316081'), 'sl_bt.xapi')
l.open()

reboot = l.bt.system.reset(0)

for e in l.gen_events(timeout=None, max_time=5):
    if e == 'bt_evt_system_boot':
        print (e)

address = l.bt.system.get_identity_address()
print(address)

scanner = l.bt.scanner.start(l.bt.scanner.SCAN_PHY_SCAN_PHY_1M, l.bt.scanner.DISCOVER_MODE_DISCOVER_OBSERVATION)
print (scanner)
time.sleep(5)
l.bt.scanner.stop()

devices = {}

address = None
address_type = None
for e in l.gen_events(timeout=None, max_time=1):
    if e == 'bt_evt_scanner_legacy_advertisement_report':
        if e.data.startswith(b"\x0c\xff\xfa\x00"):
            if e.address not in devices:
                devices[e.address] = e
                devices[e.address].scans = 1
                devices[e.address].sumrssi = e.rssi

            else:
                devices[e.address]
                devices[e.address].scans += 1
                devices[e.address].sumrssi += e.rssi

    else:
        print("Received event: {}".format(e))

selected_device = None
print ("Devices found: " + str(len(devices)))
for mac, device in devices.items():
    if device.sumrssi/device.scans <= -18: #too far away
        continue
    #TODO Check if it is in mac pending mode
    print (mac, device, device.sumrssi/device.scans)
    if selected_device == None or (selected_device.sumrssi/selected_device.scans<device.sumrssi/device.scans):
        selected_device = device
        address = e.address
        address_type = e.address_type

print ("selected device: " + str(selected_device))

if address == None:
    print ("Peripheral not found")
    quit()

print (address, address_type)

l.gen_events(timeout=None, max_time=5)
l.bt.connection.open(address, address_type, l.bt.gap.PHY_PHY_1M)

connection = None
for e in l.gen_events(timeout=None, max_time=1):
    if e == 'bt_evt_connection_opened':
        print ("bt_evt_connection_opened")
        connection = e.connection
        print (connection)
        break;

time.sleep(3)

service = None
while service == None:
    try:
        print ("Finding service...")
        l.gen_events(timeout=None, max_time=5)
        l.bt.gatt.discover_primary_services_by_uuid(connection, SERVICE_UUID)
        for e in l.gen_events(timeout=None, max_time=3):
            print ('bt_evt_gatt_service?=', e)
            if e == 'bt_evt_gatt_service':
                service = e.service
            if e == 'bt_evt_gatt_procedure_completed' and service != None:
                break;
        print ("service " + str(service))
    except:
        pass
        time.sleep(3)

characteristic = None
while characteristic == None:
    try:
        print ("Finding charactersitic...")
        l.gen_events(timeout=None, max_time=1)
        find_characteristic = l.bt.gatt.discover_characteristics_by_uuid(connection, service, CHARACTERISTIC_UUID)
        print ("find_characteristic " + str(find_characteristic))
        for e in l.gen_events(timeout=None, max_time=1):
            print("bt_evt_gatt_characteristic")
            if e == 'bt_evt_gatt_characteristic':
                characteristic = e.characteristic
                print (e)
                #break;
            if e == 'bt_evt_gatt_procedure_completed' and characteristic != None:
                break;
    except:
        pass

print ("characteristic " + str(characteristic))

Here is some sample output:

bt_evt_system_boot(major=6, minor=1, patch=0, build=176, bootloader=0, hw=258, hash=1218182300)
bt_rsp_system_get_identity_address(result=0, address='60:a4:23:c9:8c:43', type=0)
bt_rsp_scanner_start(result=0)
Devices found: 1
d0:16:f0:90:00:2e bt_evt_scanner_legacy_advertisement_report(event_flags=3, address='d0:16:f0:90:00:2e', address_type=0, bonding=255, rssi=-16, channel=38, target_address='00:00:00:00:00:00', target_address_type=0, data=b'\x0c\xff\xfa\x00\x04\x90\x00.\x00\x00\x00\x00\xef\x11\x07\xbc\xc8_\xcdB\xef\x85\xa8e@]\x83&\xabv\xa9') -16.02173913043478
selected device: bt_evt_scanner_legacy_advertisement_report(event_flags=3, address='d0:16:f0:90:00:2e', address_type=0, bonding=255, rssi=-16, channel=38, target_address='00:00:00:00:00:00', target_address_type=0, data=b'\x0c\xff\xfa\x00\x04\x90\x00.\x00\x00\x00\x00\xef\x11\x07\xbc\xc8_\xcdB\xef\x85\xa8e@]\x83&\xabv\xa9')
70:b8:f6:1f:26:6e 0
bt_evt_connection_opened
1
Finding service...
bt_evt_gatt_service?= bt_evt_connection_parameters(connection=1, interval=20, latency=0, timeout=100, security_mode=0, txsize=27)
bt_evt_gatt_service?= bt_evt_connection_phy_status(connection=1, phy=1)
bt_evt_gatt_service?= bt_evt_gatt_mtu_exchanged(connection=1, mtu=247)
bt_evt_gatt_service?= bt_evt_connection_remote_used_features(connection=1, features=b'/\x00\x00\x00\x00\x00\x00\x00')
bt_evt_gatt_service?= bt_evt_connection_data_length(connection=1, tx_data_len=251, tx_time_us=2120, rx_data_len=251, rx_time_us=2120)
bt_evt_gatt_service?= bt_evt_connection_parameters(connection=1, interval=36, latency=0, timeout=400, security_mode=0, txsize=251)
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
service None
Finding service...
bt_evt_gatt_service?= bt_evt_gatt_procedure_completed(connection=1, result=0)
silabs-beta commented 4 months ago

Hi Jens!

This use case is very similar to our bt_thermometer_client example code. I think you can try that one quickly by replacing the UUIDs here and write the characteristic value here.

My other advice is to use the bt_ncp firmware from the latest Gecko SDK v4.4.1, because it contains an important fix (with the ID 1241153 in this document) that affects the NCP performance.

I hope it helps!

jensolsson commented 4 months ago

Thanks @silabs-beta

I got the feeling that the new sdk worked slightly better, but issue remains that I often do not get a service when scanning for services. and what I try to do then is to scan for services again, which does not seem to work....

Would love to try the thermometer eample but I think it is a bit over-complicated for such an easy thing with inheritance and a lof ot libraries in the parent folders.

Kind regards Jens

jensolsson commented 4 months ago

It seem my SERVICE_UUID cannot be found from the python app. If I use NcpCommander I see it when I run sl_bt_rsp_gatt_discover_primary_services(0) However when I do the same from my python script l.bt.gatt.discover_primary_services(connection) I get all services except the one I am interested in, also if I do l.bt.gatt.discover_primary_services_by_uuid(connection, SERVICE_UUID) in the python script it usually do not yield a response. I have not figured out how to run the equalivalent to l.bt.gatt.discover_primary_services_by_uuid on NcpCommander, would be interesting

silabs-beta commented 4 months ago

You can copy the UUID directly from the sl_bt_evt_gatt_service event received on the sl_bt_gatt_discover_primary_services(0) command, like this:

Screenshot 2024-02-22 at 17 02 19

The NCP commander also shows hints for the commands while you are typing:

Screenshot 2024-02-22 at 16 32 08
simongfish commented 2 months ago

works well, but I have problem interacting with self.lib.btmesh.config_client , whatever I try it returns error 0x502.

self.lib.btmesh.config_client.list_netkeys(0,8228) Traceback (most recent call last): File "", line 1, in File "/home/pi/.local/lib/python3.9/site-packages/bgapi/bglib.py", line 384, in apiCommand response = lib.conn_handler.send_command(cmd, response_timeout=response_timeout) File "/home/pi/.local/lib/python3.9/site-packages/bgapi/bglib.py", line 102, in send_command raise CommandFailedError(response=response, command=bgcmd) bgapi.bglib.CommandFailedError: Command returned 'result' parameter with non-zero errorcode: 0x502

silabs-beta commented 2 months ago

I'm not a BT mesh expert, but 0x502 stands for SL_STATUS_BT_MESH_DOES_NOT_EXIST.

Returned when trying to manipulate a key or some other resource with an ID which does not exist.

Does it ring a bell?

silabs-beta commented 2 months ago

@jensolsson , what is the status of your original issue? Do you need more assistance?

simongfish commented 2 months ago

Ive got a support ticket raised and am receiving assistance, afaik the Ids im using are correct

simongfish commented 2 months ago

sorry I commeneted on someone elses issue, should have started a new one ;)