Hi
On Fri, 7 Sep 2018 at 21:12, Andrzej Kaczmarek <
andrzej.kaczma...@codecoup.pl> wrote:

> Hi Chris,
>
> On Fri, Sep 7, 2018 at 8:00 PM Christopher Collins <ch...@runtime.io>
> wrote:
>
> > Hello all,
> >
> > TL;DR: Proposal for registration of GAP event listeners in the NimBLE
> > host.  Currently, GAP event callbacks are specified by the code which
> > creates a connection.  This proposal allows code to listen for GAP
> > events without creating a connection.
> >
> > The NimBLE host allows the application to associate callbacks with GAP
> > events.  Callbacks are configured *per connection*.  When the
> > application initiates a connection, it specifies a single callback to
> > be executed for all GAP events involving the connection.  Similarly,
> > when the application starts advertising, it specifies the callback to
> > use with the connection that may result.
> >
> > This design provides some degree of modularity.  If a package
> > independently creates a connection, it can handle all the relevant GAP
> > events without involving other packages in the system.  However, there
> > is a type of modularity that this does not provide: *per event*
> > callbacks.  If a package doesn't want to initiate any GAP events, but
> > it wants to be notified every time a connection is established (for
> > example), there is no way to achieve this.  The problem here is that
> > there is only a single callback associated with each connection.  What
> > we really need is a list of callbacks that all get called whenever a
> > GAP event occurs.
> >
> > My proposal is to add the following to the NimBLE host API:
> >
> >     struct ble_gap_listener {
> >         /*** Public. */
> >         ble_gap_event_fn *fn;
> >         void *arg;
> >
> >         /*** Internal. */
> >         STAILQ_ENTRY(ble_gap_listener) next;
> >     };
> >
> >     /**
> >      * @brief Registers a BLE GAP listener.
> >      *
> >      * When a GAP event occurs, callbacks are executed in the following
> >      * order:
> >      * 1. Connection-specific GAP event callback.
> >      * 2. Each registered listener, in the order they were registered.
> >      *
> >      * @param listener                 The listener to register.
> >      */
> >     void ble_gap_register(struct ble_gap_listener *listener);
> >
> >     /**
> >      * @brief Unregisters a BLE GAP listener.
> >      *
> >      * @param listener                 The listener to unregister.
> >      *
> >      * @return                      0 on success;
> >      *                              BLE_HS_ENOENT if the listener is
> >      *                                  not registered.
> >      */
> >     int ble_gap_unregister(struct ble_gap_listener *listener);
> >
> > Initially, I thought this functionality could be achieved with a new
> > package implemented on top of the host (call it `blemux`).
> > Unfortunately, I think there are some issues that make such an approach
> > unwieldy for the user.  I imagined such a package would be used as
> > follows:
> >
> >     1. The `blemux` package exposes a GAP callback (call it
> >        `blemux_gap_event`).
> >     2. Elsewhere in the sytem, for each GAP function call, the caller
> >        specifies `blemux_gap_event` as the callback.
> >     3. Each package that is interested in GAP events registers one or
> >        more listeners via `blemux_register()`.
> >     4. When a GAP event occurs, `blemux_gap_event` is executed.  This
> >        callback executes every registered listener.
> >
> > The problem is that packages have no guarantee that the app is using
> > blemux.  A package can depend on `blemux` and can register listeners,
> > but it really only works if every other BLE-aware package in the system
> > also uses `blemux`.  If any package doesn't use `blemux`, then the GAP
> > procedures that it initiates won't be reported to the `blemux`
> > listeners.  A secondary problem is that this just feels like a clumsy
> > API.  It is confusing and error prone to need to specify
> > `blemux_gap_event` as the GAP event callback.
> >
> > So, I think this functionality should be implemented directly in the
> > host.
> >
>
>
Like the idea. We could use it for mesh as well - for now we have dedicated
API for Mesh to register for GAP events.
With this change we could get rid of it.


> Sounds exactly like something I wrote some time ago, so I can only agree
> with above :-)
> Typical scenario here (and what I was doing) is that external package, like
> service, wants to be notified about connection or characteristic
> subscription state. Currently we do this by exposing extra API from package
> which app needs to call from GAP callbacks in order to everything work
> properly. It works, but it's really clunky. Hooks provided by host are imo
> good way to handle this.
>
> I did not finish my service so forgot to send a PR with NimBLE changes, but
> here they are for reference - I can create PR if they look ok.
>
> https://github.com/andrzej-kaczmarek/apache-mynewt-nimble/commit/6cc902821e6d65fbd5f72fa89e7219915afca38d


Looks it does what it should, however ble_gap_register() sounds like a
better name for API to me imho.


>
> The API is pretty much the same as proposed. The difference is that
> listener struct is opaque and fields are initialized when listener is
> registered.
> Notified events are the ones which are notifications, i.e. do not require
> interaction from app (so e.g. pairing event does not call listeners since
> it does not make sense to do so).
>
> > Thoughts?

>
> > Thanks,
> > Chris
> >
>
>
Best
Łukasz


> Best,
> Andrzej
>

Reply via email to