My goal is to have a writeable characteristic that I can reject on my peripheral, based on the state of the application.
In my test application, based on the nus uart service example, I initially received the BLE_GATTS_EVT_WRITE event and echoed the data to the terminal via uart. I then set the wr_auth bit in the attribute meta data for the characteristic and received the BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event.
When I handle the event, my test application simply toggles accepting and rejecting the write. On the central side, the iPhone sees the correct behavior: alternately succeeding and failing to write the characteristic value.
I was expecting that when my application authorized the write that I would then get a subsequent BLE_GATTS_EVT_WRITE event to process the final value. That does not seem to happen. Instead, it looks like I'm supposed to process the data after calling sd_ble_gatts_rw_authorize_reply(). Is that correct?
I attempted to do that and it almost worked. I found that my data is being truncated. The request in the event has the correct offset and length for the data, but only the first two data bytes pointed to by the data pointer are correct. Here's the data of the request and my reply and the result of the call to sd_ble_gatts_rw_authorize_reply().
Variable Value Location Type
request <struct> 0x20003490 struct <Unnamed 87>
type '.' (0x02) 0x20003490 uint8_t
request <union> 0x20003492 union <Unnamed 89>
read <struct> 0x20003492 struct <Unnamed 86>
write <struct> 0x20003492 struct <Unnamed 42>
handle 0x000D 0x20003492 uint16_t
uuid <struct> 0x20003494 ble_uuid_t
op '.' (0x01) 0x20003498 uint8_t
auth_required '.' (0x01) 0x20003499 uint8_t
offset 0 0x2000349A uint16_t
len 4 0x2000349C uint16_t
data <array>"pl∏[" 0x2000349E uint8_t[1]
reply <struct> 0x20003480 struct <Unnamed 84>
type '.' (0x02) 0x20003480 uint8_t
params <union> 0x20003484 union <Unnamed 88>
read <struct> 0x20003484 struct <Unnamed 83>
write <struct> 0x20003484 struct <Unnamed 83>
gatt_status 0 0x20003484 uint16_t
update '.' (0x01) 0x20003486 uint8_t
offset 0 0x20003488 uint16_t
len 4 0x2000348A uint16_t
p_data 0x2000349E 0x2000348C uint8_t const *
'p' (0x70) 0x2000349E uint8_t
errCode NRF_SUCCESS R5 ErrorCodeEnum
The data is "play". The first two characters are correct, but the next two are garbage. After the call to sd_ble_gatts_rw_authorize_reply(), my destination buffer has the same four data bytes, so the call is kind of doing what I expected.
bleUartTxBuffer <array>"pl∏[" 0x20004B50 unsigned char[20]
[0] 'p' (0x70) 0x20004B50 unsigned char
[1] 'l' (0x6C) 0x20004B51 unsigned char
[2] '∏' (0xB8) 0x20004B52 unsigned char
[3] '[' (0x5B) 0x20004B53 unsigned char
[4] '.' (0x02) 0x20004B54 unsigned char
[5] '\0' (0x00) 0x20004B55 unsigned char
[6] 'ˇ' (0xFF) 0x20004B56 unsigned char
[7] '\0' (0x00) 0x20004B57 unsigned char
[8] '\0' (0x00) 0x20004B58 unsigned char
[9] '\0' (0x00) 0x20004B59 unsigned char
[10] '\0' (0x00) 0x20004B5A unsigned char
[11] '\0' (0x00) 0x20004B5B unsigned char
[12] '\0' (0x00) 0x20004B5C unsigned char
[13] '\0' (0x00) 0x20004B5D unsigned char
[14] '\0' (0x00) 0x20004B5E unsigned char
[15] '\0' (0x00) 0x20004B5F unsigned char
[16] '\0' (0x00) 0x20004B60 unsigned char
[17] '\0' (0x00) 0x20004B61 unsigned char
[18] '\0' (0x00) 0x20004B62 unsigned char
[19] '\0' (0x00) 0x20004B63 unsigned char
If the only change I make to my code is to clear the wr_auth bit then I, instead, get the BLE_GATTS_EVT_WRITE event and everything works as expected. My data is fine.
My basic question is about the relationship between the two events. It looks like setting the wr_auth bit means I will receive only the BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event and clearing the bit means I will receive only the BLE_GATTS_EVT_WRITE event. Is that right?
If not, any idea why I wouldn't receive the latter. If so, any idea why the request would point to partial data?