2020-08-19 09:23 AM
When receiving a write event to a characteristic via Bluetooth it is possible to return SVCCTL_EvtAckFlowDisable from the service handler.
This then results in the event buffer not being released back to CPU2.
But what happens if CPU2 runs out of memory? My observation is that packets get dropped.
Is it somehow possible to signal CPU2 to throttle the L2CAP connection when memory runs low?
2020-08-20 06:00 AM
Hello,
There is some buffering capabilities on the CPU2 side where it is still possible to store some incoming events waiting for CPU1 to release the one that is under process.
The Buffer poll used is EvtPool[POOL_SIZE] from app_entry.c
When this pool is getting full and the CPU1 did not yet release any buffer, the flow control is forwarded to the Link Layer that push it on the physical layer using the flow control mechanism over the air as defined by the BLE specification. The flow control over the air basically Nack the incoming packet from the remote device.
So, the remote device should keep sending the same packet until it is acked.
Therefore, you should not have any packet loss but only an impact of performance.
Regards.
2020-08-21 04:18 AM
Hello Christophe,
Thank you for your insights, but this is not what I'm observing.
From your explanation, it should even be possible to halt CPU1 (i.e. in a breakpoint, for a reasonable amount of time) and not lose any packet.
From my experience though, this is not the case. When receiving write commands from another bluetooth device and hitting a breakpoint, the other device happily sends more packets (without ever getting throttled or blocked).
Currently i'm still using the 1.6.0 Bluetooth Stack, I'll upgrade to 1.8.0 soon and give that a try.
2020-08-21 07:52 AM
Hello,
I don't expect any change on v1.8.0 since that mechanism has almost not been changed since v1.0.0.
There are some risk that halting CPU1 may just break CPU2 firmware. That would be much better if you could o runtime implement a mechanism when you decide to stop the flow for 15s and then restart it.
I would expect the flow to be hold on air during these 15s. In order to try this, I would start from a non modified example so that we are sure something else did not change in the firmware that may impact that feature.
Regards.
2020-08-21 08:36 AM
Hello,
I'm actually implementing the suggested runtime mechanism (FlowDisable). The breakpoint was just a worst-case example.
In my actual use-case I'm extending the SBSFU Loader to accept updates via BT. Therefore I extended the Loader example with the ble_OTA bluetooth code.
I experience packet loss during flash-erase, since that takes a considerable amount of time (in the range of a few seconds). The first firmware packets are buffered, but once the buffer is full, a section of packets is lost.
My intermediate solution is to not use WRITE_WITHOUT_RESPONSE but WRITE for the base characteristic. This allows me to send the success response after erasing the flash region. But actually I want to erase the flash only after receiving a valid header. Then I would need to utilize write with response on the raw data characteristic, producing a lot of overhead.
I'll try to reproduce this with a stock example on a nucleo board next.
2020-08-24 05:44 AM
I confirmed the same behaviour with the Ble_OTA example.
When hitting a breakpoint it will happily accept more data without any limit.
Tested with two devices: Galaxy S9+ and a Nexus 5X
2020-08-26 02:34 PM
Just by accident I realized that if a characteristic is instantiated with CHAR_PROP_WRITE_WITHOUT_RESP and GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP the desired behaviour occurs, meaning CPU1 will wait until aci_gatt_write_resp is called before processing any more packets (or a timeout occurs).
Is this documented somewhere? Is this guaranteed to hold true for future updates of the wireless stack? Since this code will end up in a non-replaceable Loader application this is very important to know.
Thank you again in advance.
2020-08-27 07:50 AM
Hello,
Generally speaking, all new CPU2 deliveries is based on the assumption that it may be used on old product where the CPU1 is not updated.
The GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP will be supported in all our next deliveries.
The team is currently working on the reason why the flow is not raised in the default use case ( this point has been confirmed by our team).
For the time being, using GATT_NOTIFY_WRITE_REQ_AND_WAIT_FOR_APPL_RESP property makes sure the remote will not send a new packet until the current one is acked by the application. This will allow you to handle cases when the CPU1 does not read the received packets fast enough.
This is reliable and will be working even in any CPU2 update.
Regards.