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

Flow control over the Bluetooth link (central -> peripherial) for UART example

Hi,

I'm currently using SDK 14.2 (on 840) and SDK 15.0 (on 810) with the UART example. 

I'm trying to implement the following system.

The Device only receives data from 810 occasionally, hence I need a way of telling the 840 to stop sending requests whenever the 810 TX buffer is close to being full. 

Currently, I'm using write requests, whereby BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST on 810 causes a write to TX buffer, an invalid response is returned if the buffer size is above a certain threshold. This is achieved through the red arrow.

case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
    {
        const ble_gatts_evt_rw_authorize_request_t*  req;
        ble_gatts_rw_authorize_reply_params_t auth_reply;
        req = &p_ble_evt->evt.gatts_evt.params.authorize_request;
		uint32_t size = tx->write_pos - tx->read_pos;

        if (req->type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
        {
            if (req->request.write.op == BLE_GATTS_OP_WRITE_REQ)
            {
				auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
				auth_reply.params.write.update = 1;
				auth_reply.params.write.len = req->request.write.len;
				auth_reply.params.write.p_data = req->request.write.data;
				auth_reply.params.write.offset = req->request.write.offset;
				auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
				
				for(int i = 0; i < req->request.write.len; i++){
					err = app_uart_put(req->request.write.data[i]);
					if (err != NRF_SUCCESS) //THIS SHOULD NEVER HAPPEN, OTHERWISE DATA IS LOST 
					{
						auth_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;		
						break;
					}
				}
				
				if(size >= 200){
						auth_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
				}
				
				err = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
																									 &auth_reply);
				if (err != NRF_SUCCESS){
				 APP_ERROR_CHECK(err);
				}
			}
        }
    } 

Consequently, this causes a flag to trigger on the 840 which causes a delay in main loop, keep in mind the code for sending data from 840->810 is in the main loop:

In ble_evt_handler

case BLE_GATTC_EVT_WRITE_RSP:
    //server_full_flag == false to avoid critical section
	if(p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED && server_full_flag == false){
		server_full_flag = true;
	}
	

In main

if(server_full_flag == true){
	nrf_delay_ms(4000);
	server_full_flag = false; // critical section
}

This particular implementation works so far, although it's very non-deterministic. In the event that an overflow occurs, I get NRF_ERROR_NO_MEM. It took a lot of trial and error to figure out that 4000 ms is a sufficient delay. (I started with 1us)

I have a few problems I'd like to discuss:

1. Currently, the 810 receive buffer is double the size of the 840 transmit buffer. This is done as the delay stops any write operations to the 840 transmit buffer, however, values in the buffer are transmitted via the soft device nonetheless. In the situation where the 810 receive buffer is (256 Bytes), and the 840 transmit buffer is (256 Bytes), and both are full, the 810 would overflow unless if its receive buffer is 512 Bytes. Is there a way of stopping the 840 soft device from sending its buffer contents?

2. I'd like to ditch the delay mechanism in favour of something more deterministic. I want the 840 to not send anything unless the 810 (through some special event) causes it to, this is highlighted in the green arrow. What is the best way to go about this?

Thank you

Parents Reply Children
No Data
Related