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

sd_ble_gatts_rw_authorize_reply() works for short responses but not long responses

Hi,

I'm having an issue when responding to rw_auth requests on the nrf52840 w/ sdk 15.0. When I'm attempting to update the table, If I make the length too large then it seems to update multiple times in the transmission. For every 1 read request I get at least 3 different sets of values. It appears to be independent of the server device because it happens if I trigger it from Noble (my computer) and nrfConnect. 

Ideas:

  • somehow the system can trigger multiple events if the user is too slow
  • ? any other ideas would be helpful

Code that is having problems

static st_ble_pos_t m_pos;
NRF_SDH_BLE_OBSERVER(m_pos ## _obs,                                                                 \
                     BLE_HRS_BLE_OBSERVER_PRIO,                                                     \
                     st_ble_pos_on_ble_evt, &m_pos)   
uint8_t global_data[255];

void * working_read_handler(uint8_t * len, uint8_t * update) {
    uint8_t packet_len = 20;
    memcpy(global_data, __SOME_DATA__, packet_len);
    *len = packet_len; *update = 1;
    return global_data;
}

void * NOT_working_read_handler(uint8_t * len, uint8_t * update) {
    uint8_t packet_len = 20;
    uint8_t max_packets = (247/packet_len)*packet_len; //247 is the maximum transfer size I believe
    memcpy(global_data, __SOME_DATA__, max_packets);
    *len = packet_len; *update = 1;


    //LOGGING code
    uint8_t *p_data = global_data;
    int16_t val = *(int16_t*)(p_data+18);
    int16_t out[4], new_val;
    out[0] = val;
    for ( uint8_t i = 1; i < max_packets/packet_length; i++ ) {
        p_data += packet_length;
        new_val = *(int16_t*)(p_data+18);
        if ( (val+4)%1024 != new_val) NRF_BREAKPOINT;
        if (i%4==0) {
            NRF_LOG_DEBUG("vals: %d   %d   %d   %d",out[0],out[1],out[2],out[3]);
        }
        out[i%4] = new_val;
        val = new_val;
    }
    NRF_LOG_DEBUG("vals: %d   %d   %d   %d",out[0],out[1],out[2],out[3]);
    //End LOGGING



    return global_data;
}

void st_ble_pos_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context)
{
    st_ble_pos_t * p_pos = (st_ble_pos_t *) p_context;
    switch (p_ble_evt->header.evt_id)
    {
        ...
        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            ble_gatts_rw_authorize_reply_params_t auth_reply;
            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
            uint16_t handleRead=p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle; 

            auth_reply.params.read.gatt_status=BLE_GATT_STATUS_SUCCESS;
            auth_reply.params.read.offset = 0;
            uint8_t update = 1;
            uint8_t err_code;

            if(p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle == p_pos->desired_value_handle)
            {
                auth_reply.params.read.p_data = p_pos->read_handler(&auth_reply.params.read.len, &update);
            }
            auth_reply.params.read.update = update;
            err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,&auth_reply);
            APP_ERROR_CHECK(err_code);
}

Output:

The values on the left are rtc ticks for data the is collected at 1/4th the frequency (so they should increment by 4, with a max value of 1020 as 1024==0)
These values should line up with the right most column of the data in the right half of the picture, but this data has the jumps in it. in the first data set there are jumps from 980->8 (1032) and 24->76

Thanks for any help,

Quinn

  • Hi,

    I don't think I understand what it is you are trying to do here. I get that there seems to be missing values on the receiver end, but what lengths are you talking about? You seem to set the 

    packet_len =  *len = auth_reply.params.read.len = 20 in both read_handlers?

    And what ware you truing to do with this?

    uint8_t packet_len = 20;
    uint8_t max_packets = (247/packet_len)*packet_len; //247 is the maximum transfer size I believe
    memcpy(global_data, __SOME_DATA__, max_packets);
    *len = packet_len; *update = 1;

    Maybe it would be an idea to put som logging inside the BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event to check that the lengths and buffers are what you think they are. 

    It could also be an idea to make a sniffer trace and see what packets are actually being transmitted. If you have a Nordic dev kit to spare you can use our nRF Bluetooth Sniffer solution. 

  • sorry, the not working code should look like the below snippet, I did a little moving around to keep some proprietary stuff out.

    The code snip above is moving some memory to a location we read from. It also sets the length of data to be read and the update flag to 1. I have logged inside of the the event and everything there seems fine except I get more events then I get read requests. I can try the sniffer today and verify my results .

    is there possibly a timeout that causes the event to trigger a second time if it hasn't completed sending?

    void * NOT_working_read_handler(uint8_t * len, uint8_t * update) {
        uint8_t packet_len = 20;
        uint8_t max_packets = (247/packet_len)*packet_len; //247 is the maximum transfer size I believe
        memcpy(global_data, __SOME_DATA__, max_packets);
        *len = max_packets; *update = 1;
        //LOGGING code
        ...
        
        return global_data;
    }

    -Quinn

  • Alright, I've fixed it on my end. apparently the soft device will send multiple events on each rw_auth event if the response is over a certain length. but each subsequent response will have a starting offset with the assumption that you may want to write from that point on. Because in my case, I wrote the entire transmission on the first event, I need to ignore the subsequent events.

    static st_ble_pos_t m_pos;
    NRF_SDH_BLE_OBSERVER(m_pos ## _obs,                                                                 \
                         BLE_HRS_BLE_OBSERVER_PRIO,                                                     \
                         st_ble_pos_on_ble_evt, &m_pos)   
    uint8_t global_data[255];
    
    void * working_read_handler(uint8_t * len, uint8_t * update) {
        uint8_t packet_len = 20;
        uint8_t max_packets = (247/packet_len)*packet_len; //247 is the maximum transfer size I believe
        memcpy(global_data, __SOME_DATA__, max_packets);
        *len = max_packets; *update = 1;
    
        return global_data;
    }
    
    void st_ble_pos_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context)
    {
        st_ble_pos_t * p_pos = (st_ble_pos_t *) p_context;
        switch (p_ble_evt->header.evt_id)
        {
            ...
            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST :
            {
                ble_gatts_rw_authorize_reply_params_t auth_reply;
                auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                uint16_t handleRead=p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle; 
    
                auth_reply.params.read.gatt_status=BLE_GATT_STATUS_SUCCESS;
                auth_reply.params.read.offset = 0;
                uint8_t update = 1;
                uint8_t err_code;
                if (p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.offset==0)
                {
                    update = 1;
                    if(p_ble_evt->evt.gatts_evt.params.authorize_request.request.read.handle == p_pos->desired_value_handle)
                    {
                        auth_reply.params.read.p_data = p_pos->read_handler(&auth_reply.params.read.len, &update);
                    }
                }
                else
                {
                    update = 0;// because we updated the entire packet already, we just want the device to keep reading the data it already has
                }
                auth_reply.params.read.update = update;
                err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,&auth_reply);
                APP_ERROR_CHECK(err_code);
                break;
            }
        }
    }
    

Related