This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Writing long characteristic values

Hi, I've the need to write a characteristic value of 65 bytes, from my central device (iPhone/iPad) to a nRF51822 peripheral device, so I was looking at this document for how to implement the write long characteristic on nRF51822.

So in my service implementation file I have added:

void ble_actrl_on_ble_evt(ble_actrl_t * p_actrl, ble_evt_t * p_ble_evt)
{
    uint32_t err_code;
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_actrl, p_ble_evt);
            break;
            
        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_actrl, p_ble_evt);
            break;
            
        case BLE_GATTS_EVT_WRITE:
	    printf("GATTS_EVT_WRITE\r\n");
            on_write(p_actrl, p_ble_evt);
            break;
            
        case BLE_EVT_USER_MEM_REQUEST:
        	err_code = sd_ble_user_mem_reply(p_actrl->conn_handle, &m_dhc_mem_block);
        	if (err_code != NRF_SUCCESS) {
        		printf("ERROR sd_ble_user_mem_reply: %u\r\n", (unsigned int)err_code);
        	} else {
        		printf("USER_MEM_REQUEST OK\r\n");
        	}
        	break;

        case BLE_EVT_USER_MEM_RELEASE:
        	printf("USER_MEM_RELEASE\r\n");
        	break;

        default:
            // No implementation needed.
            break;
    }
}

And inside the on_write function, I check which characteristic has been written using the value_handle like this:

static void on_write(ble_actrl_t * p_actrl, ble_evt_t * p_ble_evt)
{
    uint32_t err_code;
    ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;

	if(p_evt_write->handle == p_actrl->dhc_handles.value_handle)
	{
	    printf("LONG CHARACTERISTIC WRITTEN!\r\n");
	}

}

On the output console I get:

USER_MEM_REQUEST OK GATTS_EVT_WRITE USER_MEM_RELEASE

so it seems that the attribute validation has been passed, but I don't get the "LONG CHARACTERISTIC WRITTEN" printed on the console, maybe the handle that I check is not correct? Which handle should I check when dealing long characteristic writes?

Thanks for any answer. Samuele.

  • Your implementation seems correct, but you may have misunderstood somewhat how the conclusion of a long write is.

    In summary, a handle is only included in each Prepare Write Request, and these are not directly given to your application when not using authorization (since they include partial values and are in general not very useful, since they haven't yet been written). Instead, only the Execute Write is given as an event to the application, and this contains no handle information by spec. Hence, the event that comes to the application is also without handle, but with a specific type; BLE_GATTS_OP_EXEC_WRITE_REQ_NOW (ble_gatts.h).

    At this point, if you want to know which handle(s) were written, you'll have to manually parse the memory block you gave to the softdevice. The format for this memory is given here.

    Depending on what you want, it may also be an option to just look at the actual value the attribute contains at this point. When you get the write event, the data in the GATT Table have already been updated, be it in the memory you've set aside for the block (in case of VLOC_USER), or inside the stack (in case of VLOC_STACK). If the latter, you can get the new value only by using sd_ble_gatts_value_get().

    Part of the reason for doing it this way is as I mentioned above that the partial writes could in some cases be aborted and not committed. Also, as part of one queued write any number of handles could in theory be written to.

    If you need further information on how this works, I'd recommend you to take a close look at MSC you link to, and combine it with the information in the Core Specification about the different requests involved (Volume 3, Part F, section 3.4.6). Please let me know if you need elaborations on something.

  • Hi Ole, thanks for your answer and sorry for my late reply, but I was sick.

    Your answer is very well explained, so I managed to get the handle written doing some little modifications to the on_write function and instead of checking the value_handle I setup this code:

    
    if(p_evt_write->op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
    {
    	if(*((uint16_t *)m_mem_block.p_mem) == p_actrl->dhc_handles.value_handle)
    	{
                printf("LONG CHARACTERISTIC WRITTEN!\r\n");
            }
    }
    
    

    And now the program prints also the "LONG CHARACTERISTIC WRITTEN!" on the console.

    Thanks for your support.

    Regards, Samuele.

Related