Closed AGlass0fMilk closed 3 years ago
@pan- While it's not feasible to make this work for every situation, I think this can save a lot of copy-pasting and typing when doing new service classes.
We can even make a generator that takes the input .json
and creates a properly-formatted issue template (with most of the fields filled out already!)
It would be nice to make a python module to encapsulate some of the more common formatting required. I didn't want to start making a whole installable python package at this point though. I'm not sure if cog would be able to pick up packages that aren't installed in the python environment.
I like the idea of boilerplate generation tools to create services. The json
description of the service in your example is clear.
I wonder if it can be extended to authorization callbacks and more importantly if it's possible to have a model where the service declaration is separated from the service logic. In such model, it would be possible to add new characteristics to the service and re generate the declaration without breaking the existing code.
I will provide a detailed review when I'm back from holiday; next year.
I will provide a detailed review when I'm back from holiday; next year.
Happy Holidays and Happy New Year! :champagne: :smile:
@pan- Bringing this back on your radar.
This is really slick! I needed a '-' in front of the 'D'. I also need '-o' in front of ExampleService.x to create the output file. I didn't have the 'inflection' package and was able to pip install.
I like the idea of boilerplate generation tools to create services. The
json
description of the service in your example is clear. I wonder if it can be extended to authorization callbacks and more importantly if it's possible to have a model where the service declaration is separated from the service logic. In such model, it would be possible to add new characteristics to the service and re generate the declaration without breaking the existing code.
I'm thinking of ways to do this. My current idea follows the EventHandler
paradigm found everywhere else in the BLE API.
I can add sections to the JSON specification file that allow one to specify an EventHandler API. The details will have to be worked out as I develop this (some caveats are not initially clear). Some ideas I have so far:
EventHandler
callback to execute when an "OnWrite" event happens.I also want to add fields that let you add documentation/comments to the generated service. This enables the tools to generate corresponding documentation (I'm planning to support LaTeX, which will allow nice PDFs to be generated).
My goal is to automate a lot of the work I do translating service specifications into code and customer-facing documentation.
I think we can separate the logic from the specification in this way, using EventHandlers
. I will spend some time working on this.
Additionally, we can provide generic BaseEventHandler
s for the auto-generated services. For example, if a service has some required logic on a given characteristic (eg: the DFUService has certain bits that are read-only in a bitfield characteristic, so must reject writes to these bits by default), that logic can be implemented in a BaseEventHandler
. Out-of-the-box functionality would then be provided by either that BaseEventHandler
or some SpecializedEventHandler
that we provide.
For the DFUService, this would accomplish decoupling the BlockDevice
API from the DFUService
-- we can provide a BlockDeviceDFUServiceEventHandler
that implements the BaseDFUServiceEventHandler
using the BlockDevice
API. If the user wants to implement some custom functionality they may subclass the BaseDFUServiceEventHandler
and put their logic there.
Similarly, if a user wants to extend a service (eg: add an additional control characteristic to the DFUService
) they can subclass the DFUService to do so. We will have to consider how we structure services to allow this kind of customization though...
Perhaps we can instead have this generate tool create an "Interface" class that implements the "boilerplate" constructor (initializing all the characteristics), class members (characteristics), and basic service API.
Then the implementation can subclass the interface. This prevents the generation code from getting unmanageably complex.
The above EventHandler scheme can then be used to further decouple application-specific logic from the BLE service itself.
I finally took the time to look at this work and it looks good! I have few observations:
mbed
object instead of the type
field would give us freedom for future extensions. For example, what if you want to link a characteristic with read or write callbacks, what if you want to customize the variable name, etc. That's not problem that have to be solved today but it would make things more readable. It can also be useful if one wants to tackle supports of other OS' like Android or IOs to generates clients or servers. I'm thinking of ways to do this. My current idea follows the EventHandler paradigm found everywhere else in the BLE API. I can add sections to the JSON specification file that allow one to specify an EventHandler API.
I think this could work, if the generated class has setter/getter and offer an event handler interface that forwards the authorization callback to the classes using it then it becomes easy to create a service from a generated one through composition. The boiler plate of the user facing service would just be the private inheritance of the EventHandler in the service declaration and registration of itself as the event handler. The service declaration class would not have to be changed.
Closing for now as this will require some additional discussions regarding the BLE application framework and service structure.
* We don't need to keep the characteristics or the value in the class once they have been registered. From a memory standpoint, I think it would be more efficient to instantiate the GattService and GattCharacteristics when they are registered. In the service generated we can keep the handle to the characteristics.
How would this work? We need to be able to get the characteristics handles, for example when filtering GattServer events.
Without dynamic memory allocation how would this work?
* I think it could be useful to have some getter and setters -even if they are just internal - to the characteristics value, that would avoid writing gattServer().read() and provide a more user friendly interface to work with.
I agree. I'd like to come up a with a common pattern for making new services and then this boilerplate generation tool can take care of generating a majority of that.
* In the JSON representation I think starting an `mbed` object instead of the `type` field would give us freedom for future extensions. For example, what if you want to link a characteristic with read or write callbacks, what if you want to customize the variable name, etc. That's not problem that have to be solved today but it would make things more readable. It can also be useful if one wants to tackle supports of other OS' like Android or IOs to generates clients or servers.
Can you give some example JSON? I'm not understanding what you mean.
I'm thinking of ways to do this. My current idea follows the EventHandler paradigm found everywhere else in the BLE API. I can add sections to the JSON specification file that allow one to specify an EventHandler API.
I think this could work, if the generated class has setter/getter and offer an event handler interface that forwards the authorization callback to the classes using it then it becomes easy to create a service from a generated one through composition. The boiler plate of the user facing service would just be the private inheritance of the EventHandler in the service declaration and registration of itself as the event handler. The service declaration class would not have to be changed.
This commit introduces an experimental boilerplate generator using the python library cog. The associated cog templates will product a basic .h and .cpp file for a service specified by the given .json file. A template service definition json file is also included.
Usage:
cog -d D spec_file=example.json ExampleService.h ServiceTemplate.h
cog -d D spec_file=example.json ExampleService.cpp ServiceTemplate.cpp
Example output has been attached as a zip. The zip contains an example
.json
service specification along with the generated ExampleService.h and ExampleService.cppExampleService.zip