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
  • I found the function "sd_ble_gap_device_name_set". I created a pull request for implementing this feature in pc_ble_driver_py as using it seems to work:

    https://github.com/NordicSemiconductor/pc-ble-driver-py/pull/189

    But then, when should sd_ble_gap_device_name_set be used and when should BLEConfigGapDeviceName be used?

  • Hello gnf,

    Thank you for your patience.

    gnf said:
    I found the function "sd_ble_gap_device_name_set". I created a pull request for implementing this feature in pc_ble_driver_py as using it seems to work:

    I am happy to hear that you were able to figure out a way to achieve this. Thank you for submitting the pull request, and sharing the complete code you used to produce this - this will make the debugging part much easier.

    gnf said:
    But then, when should sd_ble_gap_device_name_set be used and when should BLEConfigGapDeviceName be used?

    I've passed this question on to the developers of the pc-ble-driver-py, and I will let you know as soon as they get back to me on this.
    The pc-ble-driver-py is just a python layer for the the pc-ble-driver, which is a serialized version of the SoftDevice API. So, I suppose the difference here really comes down to either using the sd_ble_gap_device_name_set function directly, or using the sd_ble_cfg_set function - this is my initial though anyways, but we will know more once the developers gets back to me.

    Best regards,
    Karl

  • Ah, you have "Sportlov" just as we have in Sweden? Great! Hope you still have some snow left.

  • Hehe, yes - only here it is called Vinterferie, but I assume it is essentially the same thing - a vacation to go skiing other snow activities with family and friends! :)
    Unfortunately a lot of the snow disappeared the last few days, but otherwise the weather has been great. Hope it is equally as nice where you are! 

  • Hello again gnf,

    Thank you for your patience with this.

    I have now checked whether there is a difference behind the scenes between calls to sd_ble_gap_device_name_set and sd_ble_cfg_set, and their primary difference is that sd_ble_cfg_set is used to configure the SoftDevice (before the BLE part of the SoftDevice is enabled, as per its API Reference), while the sd_ble_gap_device_name_set may be used to update the GATT db directly, also after the BLE part of the SoftDevice is initialized.
    I also spoke with the lead developer Bjørn today, and he told me that he had been in contact with you directly last week, which was possibly also related to some of your other PR's, as I understood it.

    Did this and you talk with Bjørn answer your questions here, or do you still have any questions related to this?

    Best regards,
    Karl

  • Hello Karl,

    I don't think me and Bjørn touched this issue when discussing the other PR's. 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(). That is on line 148 in my file listing above. 

  • 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

Reply
  • 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

Children
  • 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