Re: Triggering GATT Notification's

2016-06-01 Thread Christopher Collins
On Wed, Jun 01, 2016 at 07:04:02AM +0100, Wayne Keenan wrote:
> Because I'm creating a 'ble_gatt_svc_def' at runtime these are the steps
> I'm having todo to be able to keep hold of the characteristic handle in
> order to be able to call 'ble_gatts_chr_updated(handle)' to send the
> notification when needed:
> 
> 1. When initialising the 'ble_gatt_chr_def' the  'arg' field is set to a
> marker value.
> 
> 2. In my 'gatt_svr_register_cb' callback if a ble_gatt_chr_def.arg marker
> value is found then the 'ctxt->chr_reg.def_handle' is stashed in a global
> var.

That will work, but as you say, the need for the "marker arg" is a bit
unwieldy.  I think you are correct - there isn't currently a good way to
do this.  There is an alternative approach that I came up with, but I am
not sure it is an improvement over what you are currently doing, so it
has been relegated to the bottom of this email!

After reading your email and looking at the code some more, I think
there are a few changes that need to be made to the nimble host
immediately:

1. The characteristic-registration-callback should receive a pointers to
both the service definition and the characteristic definition (currently
it only receives a pointer to the characteristic definition).  Without
the service in hand, it is impossible to identify the characteristic by
UUIDs.

2. (As you mentioned) A function to retrieve the attribute handles
corresponding to the characteristic with a specified
service-UUID/characteristic-UUID pair.

In addition, this is not directly related to the problem being
discussed, but I noticed we need a third change:

3. The characteristic access callback also needs to receive a pointer to
the service definition (rather than just a pointer to the characteristic
definition).  This chnage is needed for the same reason as 1 above: so
that the characteristic can be reliably identified by UUID.

[...]
> Is it safe to cache the 'union ble_gatt_register_ctxt *ctxt' pointer
> given as a parameter 'gatt_svr_register_cb' to use later?

No, it is not safe.  The ctxt object is located on the stack, so you
need to make copies of anything you might need later.

> Being able to call Newt GATT API's like the following would help alleviate
> steps 1,2 and help with step 3:
> 
> a) uuit16_t gatt_get_handle_for_chr(serviceUUID, charUUID)

Agreed.

> b) int gatt_write_chr(uint16_t handle, void* data, uint len, bool
> sendNotificationIfEnabled);

There is the following function:

int
ble_att_svr_write_local(uint16_t attr_handle, void *data,
uint16_t data_len);

When a characteristic is written via this function call, the subsequent
characteristic access callback indicates that the write was done locally
by specifying a connection handle of BLE_HS_CONN_HANDLE_NONE (0x).

The above function will always send notifications to all clients who are
subscribed to the corresponding characteristic.  Perhaps the
characteristic access callback should have the option of disabling
notifications for a particular write.  Alternatively, If you want to
update a characteristic without sending any notifications, you can
always bypass the nimble stack entirely and just write directly to the
attribute data.

[...]

Thanks again for you feedback.  It is very much appreciated.

Chris

-

As promised, below is a technique that eliminates the need for the
marker arg.  As I said, it is a bit too ugly for me to recommend with a
straight face, but I thought I should include it for.. I don't know...
some reason :).  The technique identifies characteristics by memory
address.

#define SVC_IDX_GAP 0
#define CHR_IDX_GAP_DEV_NAME0
#define CHR_IDX_GAP_APPEARANCE  1

static const struct ble_gatt_svc_def my_svcs[] = {
[SVC_IDX_GAP] = {
/*** Service: GAP. */
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid128 = BLE_UUID16(BLE_GAP_SVC_UUID16),
.characteristics = (struct ble_gatt_chr_def[]) {
[CHR_IDX_GAP_DEV_NAME] = {
/*** Characteristic: Device Name. */
.uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_DEVICE_NAME),
.access_cb = gatt_svr_chr_access_gap,
.flags = BLE_GATT_CHR_F_READ,
},

[CHR_IDX_GAP_APPEARANCE] = {
/*** Characteristic: Appearance. */
.uuid128 = BLE_UUID16(BLE_GAP_CHR_UUID16_APPEARANCE),
.access_cb = gatt_svr_chr_access_gap,
.flags = BLE_GATT_CHR_F_READ,
},

/* [...] */

0, /* No more characteristics in this service. */
}
0, /* No more services. */
},
};


static void
gatt_svr_register_cb(uint8_t op, union ble_gatt_register_ctxt *ctxt,
 void *arg)
{
switch (op) {
case BLE_GATT_REGISTER_OP_CHR:
if 

Re: Triggering GATT Notification's

2016-06-01 Thread Wayne Keenan
Hiya Chris,


On 31 May 2016 at 16:36, Christopher Collins  wrote:

>
>
> There are a few ways to send notifications:
>
> 1. The stack sends them automatically to subscribed clients when a
>characteristic value changes.  The client subscribes to notifications
>(or indications) for a particular characteristic by writing to the
>corresponding client characteristic configuration descriptor (CCCD).
>
>
I didn't know newt would automatically do that, thanks for letting me know.

Because I'm creating a 'ble_gatt_svc_def' at runtime these are the steps
I'm having todo to be able to keep hold of the characteristic handle in
order to be able to call 'ble_gatts_chr_updated(handle)' to send the
notification when needed:


1. When initialising the 'ble_gatt_chr_def' the  'arg' field is set to a
marker value.

2. In my 'gatt_svr_register_cb' callback if a ble_gatt_chr_def.arg marker
value is found then the 'ctxt->chr_reg.def_handle' is stashed in a global
var.

3. (In  theory) update the characteristic value
4. Invoke 'ble_gatts_chr_updated(handle)'


At step 3 I say in theory because currently I'm not...  is it safe to cache
the 'union ble_gatt_register_ctxt *ctxt' pointer given as a parameter
'gatt_svr_register_cb' to use later?


Being able to call Newt GATT API's like the following would help alleviate
steps 1,2 and help with step 3:

a) uuit16_t gatt_get_handle_for_chr(serviceUUID, charUUID)
b) int gatt_write_chr(uint16_t handle, void* data, uint len, bool
sendNotificationIfEnabled);



>
> The nimble stack hasn't gotten a lot of practical use, so there are
> undoubtedly some aspects of the API that are lacking common sense.  Now
> is the perfect time to make changes to the API while Mynewt is still in
> its beta phase, and input like yours is extremely valuable.  If you have
> the time, I was hoping you could add some more details concerning what
> you as an application developer would like to see exposed by the nimble
> host.
>

OK, cool.



> You mentioned a function which would send a custom notification to all
> connected devices.  Is this exactly what you are looking for, or were
> you just trying to make a compromise with nimble's current API?
>

Just trying to understand.

>
> An additional facility that the host needs to provide is: a means for
> the application to discover who is currently connected.  As you
> indicated in your email, currently it is up to the application to cache
> this information, which is certainly not ideal.  This is something that
> will need to get added in the next release.
>

That could be useful, although it would be convenient if something like API
example 'b' above
automatically notified all the relevant (connected and subscribed) central
devices.


>
All the best
Wayne


Re: Triggering GATT Notification's

2016-05-31 Thread Christopher Collins
Hi Wayne,

On Tue, May 31, 2016 at 12:59:20PM +0100, Wayne Keenan wrote:
> Hi,
> 
> I have a custom GATT service working with read/write all ok; now I am
> looking at adding notify support.
> 
> On my first look thru the newt source my first take was that the app needs
> to cache the GATT registrations in 'gatt_svr_register_cb' to obtain the
> chr_val_handle and also track BLE_GAP_EVENT_CONN events and keep hold of
> the conn_handles's
>  so at a later point it can trigger a notification (for one for more
> clients) by calling:
> ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle)
> 
> 
> My first reaction to that is that I must be wrong as that perhaps too much
> duplicated state in the app.
> 
> Is there something simpler like   'ble_send_notify(char_handle, data, len)'
>  that will notify all connected clients ?

There are a few ways to send notifications:

1. The stack sends them automatically to subscribed clients when a
   characteristic value changes.  The client subscribes to notifications
   (or indications) for a particular characteristic by writing to the
   corresponding client characteristic configuration descriptor (CCCD).

2. The way you don't like :).  Call ble_gattc_notify() for each
   connection-characteristic pair that needs to be sent.  These
   notifications are sent "at will": the clients don't need to subscribe
   to the characteristic via a write to the CCCD, and the characteristic
   value doesn't need to change.  As you indicated, the application will
   need to keep track of both the connection handles and characteristic
   value handles.

3. Somewhat closer to what you are asking for:

int
ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
void *attr_data, uint16_t attr_data_len)

   The difference between this and option two above is that the
   contents of the notification are specified explicitly by the
   application rather than read from a characteristic.  The attribute
   handle need not even map to characteristic (though it probably
   should).

The nimble stack hasn't gotten a lot of practical use, so there are
undoubtedly some aspects of the API that are lacking common sense.  Now
is the perfect time to make changes to the API while Mynewt is still in
its beta phase, and input like yours is extremely valuable.  If you have
the time, I was hoping you could add some more details concerning what
you as an application developer would like to see exposed by the nimble
host.

You mentioned a function which would send a custom notification to all
connected devices.  Is this exactly what you are looking for, or were
you just trying to make a compromise with nimble's current API?

An additional facility that the host needs to provide is: a means for
the application to discover who is currently connected.  As you
indicated in your email, currently it is up to the application to cache
this information, which is certainly not ideal.  This is something that
will need to get added in the next release.

Please don't hesitate to complain about anything else that seems to be
missing from the API :).

Thanks,
Chris


Triggering GATT Notification's

2016-05-31 Thread Wayne Keenan
Hi,

I have a custom GATT service working with read/write all ok; now I am
looking at adding notify support.

On my first look thru the newt source my first take was that the app needs
to cache the GATT registrations in 'gatt_svr_register_cb' to obtain the
chr_val_handle and also track BLE_GAP_EVENT_CONN events and keep hold of
the conn_handles's
 so at a later point it can trigger a notification (for one for more
clients) by calling:
ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle)


My first reaction to that is that I must be wrong as that perhaps too much
duplicated state in the app.

Is there something simpler like   'ble_send_notify(char_handle, data, len)'
 that will notify all connected clients ?


All the best
Wayne