Overridable Events System

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks,

Just thought I'd share here a new event system I've been toying with, for my MyUSB library. I think it's quite nice, and was hoping for some feedback before I start to incorporate it.

Currently the library uses basic defines for the event hooks, such as:

#define Event_USB_Connected() { // Hook code here }

Which works fine, but I was looking for something a little better. By messing with the extensions in GCC, I've come up with a system similar to the ISR scheme in avr-lib-c.

Events are mapped via aliases to a single stub function. This function serves as a "do nothing" catch-all for all events, if they're unused by the host application. This means that unused events will waste a RCALL/RET or CALL/RET as opposed to no penalty with the define scheme.

To override an event, there are two relavent macros. HANDLES_EVENT should be placed at the top of a source file which includes an event handler. EVENT_HANDLER is used for the handler itself:

HANDLES_EVENT(USB_Connected);

// Other code here

EVENT_HANDLER(USB_Connected)
{
   // Event code here
}

The above works due to the GCC "weak" attribute being applied to the default event handlers - they are overridden by the host application, so that the resulting binary calls the user-app hooks rather than the empty stub handler.

Events are raised via the RAISE_EVENT macro. This macro uses the C99 variable macro arguments to pass in event data to the event's paremeters. Thus:

RAISE_EVENT(USB_Connected);

Works for the "USB_Connected" event which has no arguments, and:

RAISE_EVENT(USB_Error, "VBUS Too Low!");

For example, for an event with an argument.

While the new scheme results in a little code bloat (events are now fixed as functions, rather than inlined as macros), it allows for much easier coding, and makes upgrading the MyUSB library easier in the future. An added benefit is the possibility to deprecate event handlers, so that a warning is generated if the user's code overrides that particular event.

Attached is an example of what I've been working on. Anyone have any suggestions for improvements, or critisizms?

- Dean :twisted:

Attachment(s): 

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I might miss the point, but all it seems to do is call a function. Wouldn't it be easier to provide a library archive (.a) with the default implementaions (also marked as weak) for the linking stage?

You can still (in your prototype header) give certain API calls the "depricated" attribute. But you wouldn't have to do any macro expansion. That might be less error prone and more intuitive. If a user wants to react to a certain event they implement the corresponding function for it. I would find it easier to read a regular function prototype than the defined macros (it would also not clutter the global namespace).

Just my 2 cents,
Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It does indeed call a function, the point being that the events can be raised inside the library code. That allows the user to hook into the events, and execute their own code when the events occur.

For example, in my MyUSB library, attaching a device causes a VBUS interrupt. That is eventually handled by the library and a USB Connection event is raised. The demo user application hooks into that event to change the color of the bicolor status LEDs on the USBKEY.

By having this scheme, the hooks take the form of appropriatly named event hander functions, and all the backend hooking is taken care of by the linker like the ISRs are for the vector table. This means that between library versions, the event code in the user application remains indentical and the user does not have to worry about maintaining an EventHooks.h header file to match up with any added hooks in new versions - the extra events are just ignored.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In case it wasn't clear what I mean I've added a mini impelementation mimicking your example code.

It would probably be very tedious for you to implement all those default implementations (especially since they all have to be in separate files). But you could auto-generate them from the prototype header file with a little Makefile sorcery ;).

Have fun,
Markus

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Didn't see your post until I'd sent my second one.

In the example I sent all files, except for main.c would be part of your library and wouldn't have to be maintained by the user. They would just include events.h and implement main.c.

If I understand you and your intentions correctly it should work the way you want it to work.

Let me know what I'm missing,
Markus

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That seems to be a good solution, except for the requirement for the seperate event files (or for the special makefile from the user's perspective). I don't see a real problem with that other than having to create a script of some sort to create the seperate event files which complicates things.

As for the deprecation, would that only print the deprecated warning if the event hook is overridden but not if the library hook is used, like with my code?

I'll just have to weigh up first if the increased code usage and clock cycles are worth the ease-of-use. Then I'll have to decide which scheme to use.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
(or for the special makefile from the user's perspective).
I actually thought that you use a special makefile (or script) to generate all those implementations ;). But your deployment would include all default generations.

Quote:
As for the deprecation, would that only print the deprecated warning if the event hook is overridden but not if the library hook is used, like with my code?
Yes, it would, if you include events.h. But nobody says you have to include events.h for your default implementation. Cheating is, kind of, allowed in library code ;).

As for the code usage: Thinking about it a little bit more I have made a version 2 and combined the 2 approaches (test2 and libevents2.a). Best of both worlds :D.

Have fun,
Markus

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't really mind having to maintain three lines of code in the events header file. The real advantage for me is the ability to specify events as deprecated in the future, as well as make upgrading the library much easier, as less configuration files will need to be altered.

Attached is a slightly better version of my idea. I'm still unsure of whether I want to go with my easy route, or your slightly harder route requiring the library to be built. I realise that I could just include a seperate makefile to rebuild the events library but having it all done with the basic code would make it just a little bit eaiser to understand and handle.

- Dean :twisted:

Attachment(s): 

Make Atmel Studio better with my free extensions. Open source and feedback welcome!