Users create their own events by inheriting ecu_event via C-style inheritance. This is accomplished by declaring ecu_event as the first member:
enumuser_event_ids{USER_EVENT_ID_0=ECU_USER_EVENT_ID_BEGIN,USER_EVENT_ID_1,}structuser_event0{structecu_eventbase;/* Inherit by declaring ecu_event as first member. */intdata;};structuser_event1{structecu_eventbase;/* Inherit by declaring ecu_event as first member. */chardata;intdata2;};
To create an instance of a derived event, the ecu_event base class constructor must also be called. This can be done at compile-time via ECU_EVENT_CTOR():
Notice in the snippet above that ECU_EVENT_BASE_CAST() is used to pass the derived event into the ecu_event base class constructor. ECU_EVENT_BASE_CAST() and ECU_EVENT_CONST_BASE_CAST() should be used to supply derived events into the ecu_event base class API. These macros simply upcast back into the ecu_event base class to create a scheme that is functionally equivalent to C++ inheritance:
These casts are always safe in C as long as ecu_event is the first member because the C standard mandates there is no padding before the first struct member:
This behavior is not mandated in C++. Class memory layout is implementation-defined and there is no guarantee (struct ecu_event *)&event == &event.base like in the example above. Compilers often put virtual tables as the first class member, making these expressions not equal.
The figure above shows why ecu_event must be the first member. Incorrect inheritance causes misinterpretation of the event type, making the above casts unsafe. In this example, int data would be interpreted as a struct ecu_event type:
The derived event type can be determined from the ecu_event base class using an event ID. It is simply a unique integer value assigned to each event type.
The scheme presented in this module prevents an event ID used internally by ECU and a user’s event ID from sharing the same value. This is accomplished by starting user-defined event ID’s at ECU_USER_EVENT_ID_BEGIN:
ECU_USER_EVENT_ID_BEGIN is guaranteed to always be 0. IDs less than ECU_USER_EVENT_ID_BEGIN are reserved for internal use by ECU library. Therefore reserved IDs are always negative. User-defined IDs are always >= 0.
This value should be the number of bytes of the derived event and is meant to facilitate easier event handling (i.e. reading and writing different event types to the same queue). ECU_EVENT_SIZE_UNUSED can be supplied to the constructor if this parameter is unused.
The following example uses this framework to process multiple event types dispatched to a pseudocode state machine created using ECU’s finite state machine framework: