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

General question about services, characteristics, BLE connection

Hello, i recently followed your tutorial nAN-36 to understand how to add a custom service to my project. I managed to do this and i also created three characteristics to control RGB led on my board. However now i have some, i think, basic questions, but i am not able to find answers to it, so if anyone could answer my, i would appreciate.

  1. According to nAN-36, we need to create a scanResponse if we want to advertise our own custom service with its 128-bit UUID. Does this mean that, if i am creating a custom service, i will be able to create only one service, because i just don't have any more space for another custom service, since i have space only to advertise 31 bytes?

  2. Does every characteristic which i create, requires a handler? Can one handler be used to handle multiple characteristics write/read?

  3. Can you point me to an example which would show how to add and use a descriptor to a characteristic?

  4. Off-topic question: Do you have an example for a multiple master connection to a single slave?

Thank your for your support and wasting time in answering my questions. Regards.

  • Hi,

    1. Limits to advertising custom UUIDs

    It is correct that advertising packets and scan response packets have a maximum payload of 31 bytes each. A custom service has a 16 bytes adress, so the maths should be obvious. You will not have space for advertising more than one custom service in one packet.

    However, it is perfectly valid to provide services that are not advertised. They will still be found during service discovery after connecting. In fact, there are no requirements to advertise any service at all. (But it would still be a good idea, so that centrals know that it is worth connecting.)

    1. Write handler for characteristic

    I certainly understand that this area can be a little confusing. Sorry for such a long answer, I have tried to give a thorough answer, yet as short as possbile.

    The program flow of the LED Button Service (peripheral blinky) example on a BLE GATTS write event is as follows:

    • A BLE event occurs. The SoftDevice calls the ble_evt_dispatch() callback function, which was initialised in ble_stack_init() using the softdevice_ble_evt_handler_set(ble_evt_dispatch) SoftDevice call. ble_evt_dispatch() is the main BLE event handler for your application, and it is called whenever a BLE event occurs from the SoftDevice.
    • ble_evt_dispatch() calls ble_lbs_on_ble_evt(), with a pointer to the static structure containing state information for the service, &m_lbs, and a pointer to the BLE event from the SoftDevice, p_ble_evt. ble_lbs_on_ble_evt() is the dispatch function for the LED Button Service, and it is responsible for handling all BLE events related to this service.
    • ble_lbs_on_ble_evt() uses a switch to filter on the BLE_GATTS_EVT_WRITE event and in that case call on_write(), still with a pointer to thelbsstructure and p_ble_evt as parameters. on_write is a static function in the LED Button Service module responsible for GATTS write event handling for that module.
    • on_write() checks if the attribute handle from the BLE event equals the attribute handle of the value of the LED characteristic (as well as write data length and that a handler exists.) It then calls the led_write_handler with the pointer to the lbs data structure and the write value (led_state).
    • led_write_handler simply turns the LED on or off depending on the value provided in led_state. It is defined in main.c, and it is initialised to be the write handler of the m_lbsstructure by being set in the ble_lbs_init_t structure sent to ble_lbs_init() in services_init().

    To sum up: SoftDevice -> ble_evt_dispatch(ble_evt) -> ble_lbs_on_ble_evt(lbs, ble_evt) -> on_write(lbs, ble_evt) -> led_write_handler(lbs, value).

    Now what to do to add a characteristic to the LED Button Service. You still want to send all BLE events to ble_lbs_on_ble_evt() and to handle BLE_GATTS_EVT_WRITE in on_write(), so you should leave ble_evt_dispatch() and ble_lbs_on_ble_evt() as is.

    A few changes are needed in on_write and led_write_handler. Currently on_write checks to see if the handle is correct, i.e. if the characteristic value that has been written to is the characteristic value of the LED characteristic. Now you must check for the attribute handles of both characteristics. To prepare for this, the ble_lbs_s structure (this is the lbs structure) must be extended. Previously it had a ble_gatts_char_handles_t structure for the LED characteristic, but it will now need another one for the new characteristic. Further, m_lbs must be populated with the handle values for the new characteristic (and indeed, a new characteristic must be set up). I will leave these details as an exercise for the reader.

    So now you should be able to check for both characteristics. You will then have to choose if the same handler can be used for both characteristics (i.e. it does the same or a similar action for both characteristics). If there are two LEDs, for instance, then it could make sense to use the same handler and to use an additional parameter for what LED to set. In on_write() you would check the characteristic value and determine what the LED parameter should be for the handler call.

    If the characteristics are not similar, you should create a new handler for the new functionality related to the new characteristic, and do the required changes to ble_lbs_s, ble_lbs_init_t, initialisation function &c. using the same pattern as for the existing LED characteristic. The job of on_write() would then be to choose what handler to call based on what characteristic value has been written.

    1. Examples of adding a descriptor to a characteristic

    Adding characteristics and descriptors uses the GATT server API of the SoftDevice, and discovering/reading uses the GATT client API.

    The SDK examples do not set up characteristic descriptors directly, but if you have a look at the source for the Battery Service module you will find that it uses sd_ble_gatts_descriptor_add() to add a descriptor at the bottom of battery_level_char_add(). In SDK 10 this is in <SDK folder>\components\ble\ble_services\ble_bas\ble_bas.c, line 214. Two more uses can be found in (...)\ble_services\ble_hids\ble_hids.c, which is the Human Interface Device Service module.

    1. Peripheral connected to multiple centrals

    None of the current SoftDevices supports concurrent connections to more than one central. This means you must end the current connection before connecting to a new central. You can bond with several centrals, which basically means you have performed a handshake and will recognise the central on future connection requests. Bonding can be performed when in a connection. You can however combine the (connected) peripheral role with the (non-connectable advertising) broadcast role.

    Regards, Terje

  • Thank you very much for your answer. You helped me a lot here. Sorry that you didn't understand my questions. My english isn't very good :), so i am trying to elaborate what i want to to ask:

    2)I was following nAN-36 and "ble_app_hrs" for custom service creation. So i am creating service with my 128-bit UUID, and i am adding one Characteristic. So i need a handler for that. In nAN-36 it is shown like this:

    typedef void (*ble_blinky_led_write_handler_t) (ble_blinky_t * p_blinky, uint8_t new_state);
    
    typedef struct
    {
        ble_blinky_led_write_handler_t led_write_handler; 
    } ble_blinky_init_t;
    

    Then i am adding this handler to the service, initializing in the main and adding a handler code. This handler code is executed when i write something to this characteristic. Correct? So i wanted to ask can i add a second Characteristic to that service, and handle writes to it with same handler?

  • And sorry for the second comment, but didn't have enough space to put everything in one. For the question number 4: I was playing with "ble_app_hrs" example, using NRF51 Dongle, i modified it a little bit and created a service to blink RGB LED. When i connect to it with my phone, other phones doesn't find my Dongle anymore. I think what really happens is that dongle just stops advertising. So my question basically was: is there an example, where my nrf51 dongle wouldn't stop advertising after i connect to it? And i would be able to connect to my dongle let's say with Three or Four phones? Thank you very much for your help. Regards.

  • It was nothing wrong with the language. The problem was that the questions were short and general. They could have been related to almost anything. Thank you for making things clear. I will address your questions and update my initial answer.

  • Wow Terje, thank you for such a good update on my questions. You made things a lot clearer. Im marking this question as answered, thank you very much for your support. However if you could also answer the last question, even in the comments, or you could maybe update the 2 question answer it would be fantastic. So we are dealing with characteristics, and one characteristic can have multiple bytes, not a single byte. Correct? In ble_app_lbs example, led_char size is ony byte? So can i make a characteristic value larger? if yes, what are the limits of it(5,10,20 bytes for a single characteristic? ) and is it this piece of code in lbs_example that controls char size?

    attr_char_value.init_len = sizeof(uint8_t);

    attr_char_value.init_offs = 0;

    attr_char_value.max_len = sizeof(uint8_t);

    attr_char_value.p_value = NULL;

    Thank you very much for your support Terje, Regards.

Related