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

How to send a sequence of indications?

I need to indicate a characteristic value that is longer than the MTU. Using the pc-ble-driver, no problem. Windows supports semaphores and I can call sd_ble_gatts_hvx(), wait on a semaphore, and release the semaphore in the BLE_GATTS_EVT_HVC event and then indicate the next hunk.

That doesn't work when you write code for the chip as the SDK and SoftDevice do not support semaphores or an equivalent to semaphore functionality in any form. So how does one indicate a characteristic value longer than the MTU? It may require a sequence of N indications to get all the data across.

I have tried the following:

call err_code = sd_ble_gatts_hvx() and if the err_code = NRF_ERROR_BUSY then call sd_ble_gatts_hvx() again until one gets success. If I replace the semaphore with this while loop in the pc-ble-driver, it works. However, when I do the same thing on the chip, I get the NRF_ERROR_BUSY and then it hangs. It seems one cannot repeatedly call this method when busy even though the documentation says you can. How can I solve this issue on the nRF51822?

I do not know if the problem persists on the nRF52840. My pc-ble-driver code is for the nRF52840 dongle where both semaphores and the busy loop work. I have not used the pc-ble-driver on a nrf51822 chip.

I put the method that sends the sequence of indications in a single-shot timer, called from the BLE_GATTS_EVT_WRITE event handler (the central peer writes commands to the peripheral to send data - no I do NOT want to have the peer do reads here!!!!). It helped a little bit in the sense I got three indications in the sequence sent but then it stopped.

Thanks for any solution to this problem.

  • Application event comes from the interrupts sources listed in  the nrf51.h header. I've highlighted those that are reserved to the Softdevice in the image below. Interrupts reserved by the Softdevice are proccessed in the background without invoking the application.

    brianreinhold said:
    what events would cause 'my_command_handler' to be called? Would a BLE_GATTS_EVT_WRITE cause the sd_app_evt_wait() to return? Is BLE_GATTS_EVT_WRITE an Application event?

     The app will wake up on the SD_EVT_IRQn, and then start to poll the Softdevice event queue (BLE_GATTS_EVT_WRITE, etc). It's the SD_EVT_IRQn interrupt that makes the app tor return from sd_app_evt_wait().

    brianreinhold said:
    what events would cause 'my_command_handler' to be called?

     After any of the interrupt shown above, so you will still need to use a bolean flag if you want "my_command_handler()" to only be executed after a certain event.

  • It appears something you have told me is wrong. When sd_app_evt_wait() returns the only function I have at my disposal is sd_evt_get(). This method reports these events according to the documentation:

    enum NRF_SOC_EVTS
    {
      NRF_EVT_HFCLKSTARTED,                         /**< Event indicating that the HFCLK has started. */
      NRF_EVT_POWER_FAILURE_WARNING,                /**< Event indicating that a power failure warning has occurred. */
      NRF_EVT_FLASH_OPERATION_SUCCESS,              /**< Event indicating that the ongoing flash operation has completed successfully. */
      NRF_EVT_FLASH_OPERATION_ERROR,                /**< Event indicating that the ongoing flash operation has timed out with an error. */
      NRF_EVT_RADIO_BLOCKED,                        /**< Event indicating that a radio timeslot was blocked. */
      NRF_EVT_RADIO_CANCELED,                       /**< Event indicating that a radio timeslot was canceled by SoftDevice. */
      NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was invalid. */
      NRF_EVT_RADIO_SESSION_IDLE,                   /**< Event indicating that a radio timeslot session is idle. */
      NRF_EVT_RADIO_SESSION_CLOSED,                 /**< Event indicating that a radio timeslot session is closed. */
      NRF_EVT_NUMBER_OF_EVTS
    };

    These are useless to me and have nothing to do with Bluetooth. How do I get the BLE events?

    Do I have to deal with this function: sd_nvic_GetPendingIRQ()? If so, what is the correct IRQn_Type to use? Is it SWI2_IRQn? How would I use this function to get the BLE events?

    When you say app will wake up you mean my app, correct?

    How do I poll the softdevice event queue? I have not found a method to do that.

  • So I guess you are not using the SoftDevice handler library to retreive and forward Softdevice events as you are trying to implement this mechanism yourself? To get BLE events, you will need to call sd_ble_evt_get(). sd_evt_get() is for SoC events like you said.

    Do I have to deal with this function: sd_nvic_GetPendingIRQ()? If so, what is the correct IRQn_Type to use? Is it SWI2_IRQn? How would I use this function to get the BLE events?

    I recommend you review the existing softdevice_handler.c implementation to see how it's done there. You may also want to read up on the ARM Cortex M exception model to get a better understandig of interrupts work on this chip.

    sd_nvic_GetPendingIRQ(SWI2_IRQn) is always going return false because the interrupt pending bit is cleared as soon as the interrupt is serviced by the  SWI2_IRQHandler (Note: SWI2_IRQHandler  is redefined to SOFTDEVICE_EVT_IRQHandler in sdk code). It only makes sense to use sd_nvic_GetPendingIRQ() if the interrupt is masked (ie temporarly disabled)

    When you say app will wake up you mean my app, correct?

    Yes, correct. The program will return from the sd_app_evt_wait() call when an application interrupt has been triggered.

    How do I poll the softdevice event queue? I have not found a method to do that.

    With sd_evt_get() and sd_ble_evt_get()

  • Yes, I found the sd_ble_evt_get() method. The documentation itself is pretty good, but the search engine stinks. It doesn't even find text on the same page that you put into the search bar. I stumbled on this method after methodically looking for every 'function' list I could find in the SoftDevice. 

    I also did a simple experiment by putting a handler in the that final for-loop and trying each of the sd_*_get() methods that had to do with getting events and printing the results. I didn't try the sd_ble_evt-get() method yet as it was the last one I found.

    In my case sd_nvic_GetPendingIRQ(SWI2_IRQn)  always returned true and quickly overflowed the print buffer.

    I am not using the SDK for a couple of reasons - I want to minimize SDK calls making portability from one chip to another as well as portability to newer versions much simpler. There were HUGE changes in the SDK from s110 v 8 to s130 v 12.3 demanding major code re-writes. However, after converting the old s110 v 8 code to using JUST SoftDevice, moving to s130 was very simple and took but a few minutes. Changes to move from nRF51822 to nRF52840 using just SoftDevice are also minimal. I personally find it easier sticking with BLE fundamentals which SoftDevice gives; you know that every BLE API must be able to perform certain basic tasks. Those I know. Learning how an SDK wrapper works is always a big commitment.

    BUT the biggest reason for sticking with SoftDevice only is that I also have code for the pc-ble-driver which ONLY has SoftDevice. It's a great test platform as you can use the PC. Having all code bases as similar and as portable as possible is clearly advantageous.

    Now I try sd_ble_evt_get() in my test loop and see what it gives me. First and foremost, who gets the event first. My test loop or my ble event dispatch function that appears in all the Nordic health device examples?

    Result of try

    Well it looks like the event handler I registered with SoftDevice gets it first and when I get it in the main 'for' loop the event is already drained. So that means (I guess) that I need to call my event handler from my 'test' method where I call sd_ble_evt_get().  AND do NOT register my event handler with SoftDevice. (Does this slow things down?)

    The whole purpose is, again, to allow me to call the indication method repeatedly in a 'BUSY' loop without hanging. Since I would be calling my event handler from the main for-loop, the event handler and the timer should all be in the main process.   I hope.

  • Events are removed from the Softdevice's internal event buffer when you run the event get functions. So,  these functions should not be called from multiple places in your code.

    You may use the "Thread mode event" retrival approach shown by the sequence chart linked to below if you preffer to poll the SD events from the main loop. Just make sure the Softdevice interrupt is not enabled in that case.

    Relevant Message Sequence Charts

    Interrupt-driven Event Retrieval

    Thread Mode Event Retrieval

    Also, a bit back to the original topic, you can take a look at the ancs_tx_buffer.c implementation in the ble_app_ancs_c example to see how we use a ring buffer to queue up multiple indication packets in the application.

Related