Chapter 6. Interface Call-outs

Interface call-outs allow the user to capture execution control of the generated system running on a target.

Especially in the deeply embedded software development world, it may be necessary to tightly interface the xtUML system to the surrounding/containing system. MC-3020 provides callout routines that enable the user to easily interface code generated by the model compiler with other system code. These callout routines are empty when generated by the model compiler. It is up to the user to define additional functionality (if necessary) to be performed at these callout points.

Using Callouts

MC-3020 tries to provide callout functions at as many key points of control as possible. It is the goal of the model compiler to make it easy for the user to interface to the generated code.

The user callout file sys_user_co.c will initially be generated into the source directory (/src). After being generated once, it is common to copy the file to the /gen folder to be edited. (Note that hand edited/modified .c and .h files in the /gen folder get copied on top of files in the /src folder at build time.) The user should add invocations from this file into appropriate system specific functionality.

MC-3020 generates hooks into the generated at key points where these callouts are needed. In early versions of MC-3020, these hooks represented real C instructions even if the callouts where not being used actively. In recent versions, the sys_user_co.h defines the hooks as macros. Until they are activated, they take no time or space inline with the generated code. They are effectively invisible. The comments in the sys_user_co files explain how to activate and modify the callouts.

Callout Routines Provided

Edit sys_user_co.h to activate particular callout functions. Edit sys_user_co.c to add code to the defined callout routines. It is important that both files be edited to enable the callout capability.

User Initialization

This function is invoked at the immediate beginning of application initialization. It is the very first function to be executed at system startup. User supplied implementation of this function should be restricted to things like memory initialization, early hardware duties, etc.

UserInitializationCallout(void); 
 

Example 6.1. Bring-up Initialization

        void UserInitializationCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Pre-xtUML Initialization

This function is invoked immediately prior to executing any xtUML application initialization function.

UserPreOoaInitializationCallout(void); 
 

Example 6.2. Pre-xtUML Initialization

        void UserPreOoaInitializationCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Post-xtUML Initialization

This function is invoked immediately after executing any/all xtUML application initialization function(s). When this callout function returns, the system dispatcher will allow the xtUML state models to start consuming events.

UserPostOoaInitializationCallout(void); 
 

Example 6.3. Post-xtUML Initialization

        void UserPostOoaInitializationCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Background Processing

This function is invoked once during each loop execution of the system dispatcher. (This may be an excellent place to hang an invocation to a timer (TIM) tick routine.)

UserBackgroundProcessingCallout(void); 
 

Example 6.4. Background Processing

        void UserBackgroundProcessingCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Pre-Shutdown Processing

This function is invoked at termination of the system dispatcher, but prior to performing any xtUML application shutdown sequencing.

UserPreShutdownCallout(void); 
 

Example 6.5. Pre-Shutdown

        void UserPreShutdownCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Post-Shutdown Processing

This function is invoked immediately before application exit.

UserPostShutdownCallout(void); 
 

Example 6.6. Post-Shutdown Callout

        void UserPostShutdownCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Event ``Can't Happen'' Processing

This function is invoked any time that an event is received that results in a ``can't happen'' transition.

UserEventCantHappenCallout(const Escher_StateNumber_t current_state,
 const Escher_StateNumber_t next_state,
 const Escher_EventNumber_t event_number);
 

Where the input parameters are:

current_state

is the number of the state before the transition.

next_state

is the number of the calculated next state.

event_number

is the number of the event that is stimulating this transition.

Example 6.7. Event Can't Happen

        void UserEventCantHappenCallout( const Escher_StateNumber_t current_state,
                                         const Escher_StateNumber_t next_state,
                                         const Escher_EventNumber_t event_number
        )
        {
          /* Insert implementation specific code here.  */
        }
        

User Event with No Instance Processing

This function is invoked any time that an event is received and there is no target instance to receive it. This often means that the instance was deleted while the event was in flight. Usually this indicates a modeling error. The default behavior without supplying a body to this function is simply to consume the event and go on.

UserEventNoInstanceCallout(const Escher_EventNumber_t event_number);
 

Where the input parameters are:

current_state

is the number of the state when event is dispatched.

next_state

is the number of the calculated next state.

event_number

is the number of the event that is landing on the missing object instance.

Example 6.8. Event with No Instance

        void UserEventNoInstanceCallout( const Escher_EventNumber_t event_number
        )
        {
          /* Insert implementation specific code here.  */
        }
        

User Event Free List Empty

This function is invoked when an attempt is made to allocate an event, but there are no more left.

UserEventFreeListEmptyCallout(void); 
 

Example 6.9. Event Free List Empty Handler

        void UserEventFreeListEmptyCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

User Empty Handle Detection

When marked active, this function is invoked when an attempt is made to use an instance reference variable (handle) that is null (empty).

UserEmptyHandleDetectedCallout(c_t * object_keyletters,
 c_t * string);
 

Example 6.10. User Empty Handle Detection

        void UserEmptyHandleDetectedCallout( const char * object_keyletters,
                                             const char * s )
        {
          /* Insert implementation specific code here.  */
        }
        

User Object Pool Empty Handling

This function is called from instance creation methods when an attempt is made to create an instance of an object and no allocation units are available.

UserObjectPoolEmptyCallout(c_t * domain,
 c_t * object_name);
 

Example 6.11. Object Pool Empty

        void UserObjectPoolEmptyCallout( const char * domain,
                                         const char * object_name )
        {
          /* Insert implementation specific code here.  */
        }
        

Empty Node List Handling

MC-3020 uses a collection of set ``containoids'' to link data items together in lists. These utility list nodes are used collecting extents, events and relationships. In the situation that an attempt is made to allocate a node, but none are available, this function will be called.

UserNodeListEmptyCallout(void); 
 

Example 6.12. Node List Empty

        void UserNodeListEmptyCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

Overflow of Interleaved Bridge Invocations

MC-3020 uses an array as a queue to manage invocations of interleaved bridges (bridge operations marked safe for interrupt invocation). UserInterleavedBridgeOverflowCallout is invoked when an attempt is made to post too many interleaved bridges. The depth of this list is defined by SYS_MAX_INTERLEAVED_BRIDGES (unless changed in the rule file).

UserInterleavedBridgeOverflowCallout(void); 
 

Example 6.13. Overflow of Interleaved Bridge

        void UserInterleavedBridgeOverflowCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        

Empty Event Queue Callouts

If the user wishes to gain control of processing when either of the two event queues are empty (no events to be processed at the current time), two callouts are provided. UserSelfEventQueueEmptyCallout and UserNonSelfEventQueueEmptyCallout are invoked (assuming they are enabled) each time the corresponding event queue is interrogated and found to be empty.

UserSelfEventQueueEmptyCallout(void); 
 
UserNonSelfEventQueueEmptyCallout(void); 
 

Example 6.14. Event Queue Empty Notification

        void UserSelfEventQueueEmptyCalloutf()
        {
          /* Insert implementation specific code here.  */
        }
        void UserNonSelfEventQueueEmptyCalloutf()
        {
          /* Insert implementation specific code here.  */
        }