This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Device Name shows garbage using pc_ble_driver_py

Using pc_ble_driver_py (version 0.15.0) to create a peripheral with a specific Device Name in characteristic 0x2A00 (Generic access service), the resulting device name is garbage. The class "BLEConfigGapDeviceName" is used to try setting the device name in the following way:

        configName = BLEConfigGapDeviceName(device_name="0000000000",device_name_read_only=False)
        ble_driver.ble_cfg_set(BLEConfig(driver.BLE_GAP_CFG_DEVICE_NAME), configName)
        ble_driver.ble_enable()

This is the result in nRF Connect:

In the log window the following is seen:

Attribute value read, handle: 0x03, value (0x): D4-03-00-20-00-00-00-00-D0-1C

 

This is the complete file:

import logging
import sys
import time
from threading import Condition, Lock
from pc_ble_driver_py.observers import BLEDriverObserver

BASE_UUID_DICT                 = {'BV_BASE_UUID': [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
                               0x10, 0x00, 
                               0x80, 0x00, 
                               0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB]}
SERVICE1 = (("MyService1"      , 0x3000),
                                (("Char1"               , 0x3001, 1,   [0x00], "Desc"),
                                 ("Char2"                , 0x3002, 2,   [0x00], "Desc"),))

DEVICE_INFORMATION_SERVICE = (("Device Information"   , 0x180A),
                                (("Manufacturer name"    , 0x2A29, 20,   b"Name", None),
                                ("Model name"           , 0x2A24,  20,   b"Model1", None),
                                ("Firmware version"     , 0x2A26,  20,   b"v_0.0.1", None),))

SERVICES_CONFIG = ( DEVICE_INFORMATION_SERVICE,
                    SERVICE1,
                     )

logger = logging.getLogger(__name__)

def init(conn_ic_id):
    # noinspection PyGlobalUndefined
    global BLEAdapter, BLEDriver, BLEAdvData, BLEConfigGapDeviceName, BLEEvtID, BLEEnableParams, config, driver, BLEAdvData, BLEGattsHVXParams, BLEService, BLEUUIDBase, BLEUUID, BLEGattsAttr, BLEGattsAttrMD, BLEGattHandle, BLEGattsCharHandles, BLEGattsCharMD, BLEGattCharProps, BLEConfig, BLEConfigCommon
    from pc_ble_driver_py import config

    config.__conn_ic_id__ = conn_ic_id
    # noinspection PyUnresolvedReferences
    from pc_ble_driver_py.ble_driver import (
        BLEDriver,
        BLEAdvData,
        BLEConfigGapDeviceName,
        BLEEvtID,
        BLEEnableParams,
        BLEGattsHVXParams,
        BLEService,
        BLEUUIDBase,
        BLEUUID,
        BLEGattHandle,
        BLEGattsAttr,
        BLEGattsAttrMD,
        BLEGattsCharHandles,
        BLEGattsCharMD,
        BLEGattCharProps,
        BLEConfig,
        BLEConfigCommon,
        driver,
    )
        # noinspection PyUnresolvedReferences
    from pc_ble_driver_py.ble_adapter import BLEAdapter


class Peripheral:
    def __init__(self, adapter):
        self.adapter = adapter
        logger.info(
            "Peripheral adapter is %d",
            self.adapter.driver.rpc_adapter.internal,
        )
        self.char_128_handles_dict = {}
        self.serv_128_handle_dict = {}
        self.uuid_128_base_dict = {}
        self.serv_128_uuid_dict = {}

    def _add_char(self, base_uuid, service_uuid, char_uuid, max_len, value, user_desc_str):
        """Add characteristic"""
        char_128_handles = BLEGattsCharHandles()
        char_128_uuid = BLEUUID(char_uuid, self.uuid_128_base_dict[base_uuid] )
        
        max_len=16
        
        props = BLEGattCharProps(notify=True, read=True, write=True)
        if user_desc_str:
#            user_desc = list(user_desc_str.encode())
#            desc_md = BLEGattCharProps(read=True)
#            char_md = BLEGattsCharMD(char_props=props, user_desc=user_desc, desc_md=desc_md)
            char_md = BLEGattsCharMD(char_props=props)            
        else:
            char_md = BLEGattsCharMD(char_props=props)            
        
       
        attr_md = BLEGattsAttrMD()
        attr = BLEGattsAttr(uuid=char_128_uuid, attr_md=attr_md,
                            max_len=max_len, value=value)
        self.adapter.driver.ble_gatts_characteristic_add(
                            self.serv_128_handle_dict[service_uuid].handle,
                            char_md, attr, char_128_handles)
        self.char_128_handles_dict[char_uuid] = char_128_handles

    def _add_service(self, base_uuid, service_uuid):
        """Add specific service"""       
        if not base_uuid in self.uuid_128_base_dict:
            uuid_128_base = BLEUUIDBase(BASE_UUID_DICT[base_uuid])
            self.uuid_128_base_dict[base_uuid] = uuid_128_base
            self.adapter.driver.ble_vs_uuid_add(self.uuid_128_base_dict[base_uuid])

        self.serv_128_handle_dict[service_uuid]= BLEGattHandle()
        self.serv_128_uuid_dict[service_uuid] = BLEUUID(service_uuid, self.uuid_128_base_dict[base_uuid])
  
        self.adapter.driver.ble_gatts_service_add(
            driver.BLE_GATTS_SRVC_TYPE_PRIMARY, self.serv_128_uuid_dict[service_uuid], self.serv_128_handle_dict[service_uuid])
 
    def setup_services_128bit(self):
        """Setup services"""
        for (_, service_uuid), chars in SERVICES_CONFIG:
            self._add_service(base_uuid='BV_BASE_UUID', service_uuid=service_uuid)
            for (_, char_uuid, max_len, value, user_desc_str) in chars:
                self._add_char(base_uuid='BV_BASE_UUID', 
                           service_uuid=service_uuid, 
                           char_uuid=char_uuid, max_len=max_len, value=value,
                           user_desc_str=user_desc_str)
def main(serial_port):
    print("Serial port used: {}".format(serial_port))
    ble_driver = BLEDriver(serial_port=serial_port, 
                       baud_rate=1000000,
                       auto_flash=True,
                       log_severity_level="debug")
    adapter = BLEAdapter(ble_driver)
    observer = TimeoutObserver()

    adv_data = BLEAdvData(short_local_name="MyDevice")

    ble_driver.observer_register(observer)
    ble_driver.open()
    if config.__conn_ic_id__.upper() == "NRF51":
        ble_driver.ble_enable(
            BLEEnableParams(
                vs_uuid_count=0,
                service_changed=0,
                periph_conn_count=1,
                central_conn_count=0,
                central_sec_count=0,
            )
        )
    elif config.__conn_ic_id__.upper() == "NRF52":
#         configCommon = BLEConfigCommon()
#         configCommon.vs_uuid_count = 1
#         driver.ble_cfg_set(BLEConfig.uuid_count, configCommon)
#         cfg = BLEConfigGap()
#         cfg.device_name = "test123"
#         cfg.device_name_read_only = False
#        ble_tester.driver.ble_cfg_set(BLEConfig.device_name, cfg)
        
        configName = BLEConfigGapDeviceName(device_name="0000000000",device_name_read_only=False)
        ble_driver.ble_cfg_set(BLEConfig(driver.BLE_GAP_CFG_DEVICE_NAME), configName)
#         ble_driver.ble_cfg_set(BLEConfig.device_name, cfg)
        #sd_ble_gap_device_name_set()
        ble_driver.ble_enable()
        
    peripheral = Peripheral(adapter)
    peripheral.setup_services_128bit()
       
    ble_driver.ble_gap_adv_data_set(adv_data)
    ble_driver.ble_gap_adv_start()
    observer.wait_for_timeout()

    while(True):
        time.sleep(10)
    print("Closing")
    ble_driver.close()


class TimeoutObserver(BLEDriverObserver):
    def __init__(self, *args, **kwargs):
        super(BLEDriverObserver, self).__init__(*args, **kwargs)
        self.cond = Condition(Lock())

    def on_gap_evt_timeout(self, ble_driver, conn_handle, src):
        with self.cond:
            self.cond.notify_all()

    def on_gap_evt_disconnected(self, ble_driver, conn_handle, reason):
        with self.cond:
            self.cond.notify_all()

    def wait_for_timeout(self):
        with self.cond:
            self.cond.wait()


if __name__ == "__main__":
    logFormatter = logging.Formatter("%(asctime)s [%(levelname)-7s][%(name)s] %(message)s")
    rootLogger = logging.getLogger()
     
    fileHandler = logging.FileHandler("ble_test.log")
    fileHandler.setFormatter(logFormatter)
    rootLogger.addHandler(fileHandler)
     
    consoleHandler = logging.StreamHandler(sys.stdout)
    consoleHandler.setFormatter(logFormatter)
    rootLogger.addHandler(consoleHandler)
     
    rootLogger.setLevel(logging.DEBUG)
    
    id = "NRF52"
    serial_port = "/dev/ttyACM0"
    init(id)
    main(serial_port)

What am I doing wrong?

Parents Reply Children
  • Sorry for the late reply here.

    gnf said:
    I don't think me and Bjørn touched this issue when discussing the other PR's.

    Aha, I must have misunderstood Bjørn then.

    gnf said:
    What is missing for me regarding the device name issue is that I am looking for a working code snippet in Python on how to set the device name in the SoftDevice config, I guess  using BLEConfigGapDeviceName().

    I will create such an example for you tomorrow, to illustrate how it can be implemented.

    Best regards,
    Karl

  • Hello gnf,

    I have worked on this today, and naturally discovered the same issue as you describe in your original ticket - with the device name turning into jibberish when attempting to set it with the following:

    config_device_name = BLEConfigGapDeviceName()
    error_code = driver.ble_cfg_set(BLEConfig.device_name, config_device_name)

    Closer investigation of the device name as transmitted over the BLE connection reveals that there is a trailing character in the transmitted name.
    The equivalent pc-ble-driver function works as expected, indicating that there is an error somewhere in the python-to-c casting of the device name.

    I have created an internal ticket for this, where I ask the developers to examine this more closely.

    Unfortunately, that leaves you with only the sd_ble_gap_device_name_set option for setting the device name, for the time being. Thank you for rooting out this bug for us, we will see it fixed!

    Best regards,
    Karl

  • Thank you for your help! Then it sounds like my other issue could also be caused by python-to-c casting. Please check this issue:

    devzone.nordicsemi.com/.../user-description-in-pc-ble-driver-py

  • gnf said:
    Thank you for your help!

    No problem at all, I am happy to help! And thank you likewise, for pointing this out to us! :)

    gnf said:
    Then it sounds like my other issue could also be caused by python-to-c casting. Please check this issue:

    These two calls does not call the exact same function to cast to c, but it definitely looks like these issues can be related.
    I will update my internal ticket with the pc-ble-driver-py developers to contain a link to your other case, so they may examine this too more closely, and see if there might not be a connection here.

    I find it very strange that these two issues has not been brought up earlier if they always have been present - given how widespread the pc-ble-driver-py is being used - but perhaps the developers can trace this bug introduction to a specific release or change.

    You've done a good job of debugging this, and you've already reduced the bug search area by a drastic amount. Well done! :)

    Best regards,
    Karl

  • heart_rate_monitor example in pc-ble-driver-4.1.4.zip uses advertisement_data_set() function to set DeviceName (Nordic_HRM) but DeviceName in characteristic UUID 0x2A00 under service Generic Access 0x1800 was "nRF5x" to my surprise. As long as sd_ble_gap_device_name_set hasn't been included ...

Related