[ Table Of Contents | Keyword Index ]

micca(1) 1.1 micca "XUML Model Translation"

Name

micca - Executable Model Translation to C

Table Of Contents

Synopsis

Description

micca options file1 ?file2 ...?

Micca is a program that transforms a domain specific language (DSL) script of an Executable Model into "C" code to implement the logic of the model. The DSL is defined in the micca-DSL manual page.

available options are:

-version

Print out version and copyright information and exit.

-stubexternalops

Include external operation code in output.

-nogenerate

Don't generate any output files.

-lines

Generate #line directives in the generated output that relate back to the micca source file. Because of the code expansion of the embedded commands in actions, the #line directives are not precise indicators into the micca source.

-save filename

Save the domain configuration in a file name, filename. If this option is absent, the domain configuration is saved to a file named "miccasave.ral" in the current directory.

-savesqlite filename

Save the domain configuration to a SQLite database named, filename.

-posix

Output the POSIX version of the run time code and exit.

-efm32gg

Output the EFM32 Giant Gecko version of the run time code and exit.

-msp432

Output the MSP432 version of the run time code and exit.

-msp430

Output the MSP430 version of the run time code and exit.

-doc

Output the manual page documentation in HTML format in the miccadoc directory.

-expanderror error

How macro expansion errors are handled. By default, they fail throwing an error.

--

Stop option processing.

-help

Print a help message.

-?

Print a help message.

Naming Conventions

The micca code generator creates "C" identifiers for various functions and variables. The identifiers names all have suffixes matching the regular expression, __[A-Z0-9]+, appended to them to make them unique. Code supplied as part of state actions or other processing must avoid identifiers that end in two underscore characters followed by a arbitrary number of upper case alphabetic or decimal numeric characters.

The functions of external scope for the run time code all begin with "mrt_". The data types for the run time all begin with "MRT_".

Building A Micca Application

A successful run of micca yields two files: a "C" source file and a "C" header file. To link a running application, the main function must be supplied. The following is an example of how the main function might appear.

#include <stdlib.h>
#include "micca_rt.h"
int
main(
    int argc,
    char *argv[])
{
    /*
     * Hardware and other low level system initialization is usually done
     * first.
     */
    /*
     * Initialize the run-time code itself.
     */
    mrt_Initialize() ;
    /*
     * Initialize domains, bridges and any other code that might require access
     * to the facilities of the run-time code. Typically, each domain in the
     * system would have an "init()" domain operation and these can be invoked
     * here. Sometimes domain interactions are such that a second round of
     * initialization is required.  Bridges between domains may also require
     * that the initialization for a domain be done before the bridge can be
     * initialized. Once mrt_Initialize() has been invoked, domains may
     * generate events and do other model level activities.  Regardless of how
     * the initialization is accomplished, it is system specific and,
     * unfortunately, only temporally cohesive.
     */
    /*
     * Entering the event loop causes the system to run.
     */
    mrt_EventLoop() ;
    /*
     * It is possible that domain activities can cause the main loop to exit.
     * Here we consider that successful. Other actions are possible and
     * especially if the event loop is exited as a result of some unrecoverable
     * system error.
     */
    return EXIT_SUCCESS ;
}

The required elements of main are to invoke mrt_Initialize() before any run-time elements might be needed and to invoke mrt_EventLoop() to cause the system to run.

Conditional Compilation

The following "C" preprocessor symbols may be used to control features included in the object files. Note both the domain "C" files and the run-time source should be compiled with the same set of preprocessor defines.

NDEBUG

The run-time uses the standard assert macro and the assertions may be removed by defining this symbol.

__ARM_ARCH

Defining this symbol to 7, compiles in code to use features of the ARM v7-M architecture. Normally, compilers typically define this symbol by default to match the ARM architecture for which they are generating code. The ARM v7-M architecture code uses the PendSV exception when synchronizing from interrupt context to the background context.

MRT_NO_NAMES

If defined, this symbol will exclude naming information about classes, relationships and other domain entities from being compiled in. For small memory systems, strings can consume a considerable amount of space and are usually only used during debugging.

MRT_NO_TRACE

Defining this symbol removes code from the run-time that traces event dispatch. Event dispatch tracing is important during testing and debugging but may be removed from the delivered system.

MRT_NO_STDIO

Defining this symbol insures that "stdio.h" is not included and no references are made to functions in the standard I/O library. This is useful for smaller embedded systems that cannot support the memory required by the standard I/O library.

MRT_TRANSACTION_SIZE

The value of this symbol sets the maximum number of relationships that can be modified during a data transaction. The default value is 64.

MRT_EVENT_POOL_SIZE

The value of this symbol sets the number event control blocks which are used for signaling events. The default value is 32. This number represents the maximum number of signaled events that may be _in flight_ at the same time.

MRT_ECB_PARAM_SIZE

This value of this symbol set the maximum number of bytes that can be occupied by event parameters or sync function parameters. The default value is 32.

MRT_SYNC_QUEUE_SIZE

The value of this symbol defines the maximum number of synchronization requests from the foreground processing that may be outstanding at the same time. The default value is 10. This symbol represent the number of interrupts that may occur during the execution of a state activity.

MRT_INSTANCE_SET_SIZE

The value of this symbol is the maximum number of instance references that may be held in an instance reference set. The default value is 128.

MRT_INSTRUMENT

Defining this symbol includes code to print the function name, file name and line number for all functions generated by the code generator. This information forms a trace of executed functions.

MRT_INSTRUMENT_ENTRY

Defining this symbol overrides the instrumentation code expansion that is placed at the beginning of each generated function. By default when MRT_INSTRUMENT is defined, then MRT_INSTRUMENT_ENTRY is defined as follows:

    printf("%s: %s %d\n", __func__, __FILE__, __LINE__) ;
MRT_DEBUG(...)

The MRT_DEBUG macro has the same invocation interface as printf(). If MRT_INSTRUMENT is defined, then MRT_DEBUG invocations will include the implied printf invocations. Otherwise, the implied printf invocations are removed from the code (i.e. MRT_DEBUG is defined as empty). If MRT_INSTRUMENT is defined, then the expansion of MRT_DEBUG may be overridden.

MRT_DOMAIN_NAME

The MRT_DOMAIN_NAME macro is defined early in the domain's code file and resolves to a string containing the name of the domain.

MRT_CLASS_NAME

The MRT_CLASS_NAME macro is defined within any class context to be a string literal that matches the name of the class. This symbol is redefined for each class context and is useful for generic debugging or instrumentation output.

MRT_STATE_NAME

The MRT_STATE_NAME macro is defined within the action of a state in a state model be a string literal that matches the name of the state. This symbol is redefined for each state action and is useful for generic debugging or instrumentation output.

Running A Micca Application

The runtime provides several functions that are used to control the state machine event dispatch mechanism.

void mrt_Initialize(void)

The mrt_Initialize is invoked to initalize all the internal data structures of the micca run-time. It must be invoked before any other run-time function.

void mrt_EventLoop(void)

The mrt_EventLoop function is the preferred way for a micca generated application to run. Application supplied main functions should enter the event loop by invoking mrt_EventLoop() causing the application to start running. This function dispatches events, causing the system to execute, and will not return unless some action in the domain invokes mrt_SyncToEventLoop.

bool mrt_SyncToEventLoop(void)

A state activity may invoke mrt_SyncToEventLoop to request that the run-time event loop exit and return to its caller (typically main) at the end of the current ongoing thread of control. The return value is a boolean indicating whether the event loop had already been requested to exit (true). This function provides a way for domain activities to stop the system from running without causing an explicit error.

Controlling the Event Loop

The micca run time provides two function to enable finer control over dispatching events. Using these functions is not the preferred way to cause a micca generated application to run, but they are useful in test situations and when it is necessary to integrate with legacy applications that might have their own event loop.

bool mrt_DispatchThreadOfControl(bool wait)
bool wait

A boolean value that determines if the function waits for an event to begin the thread of control if there is no thread of control currently ready to run. Waiting is useful if the thread of control will be started by a delayed signal.

The mrt_DispatchThreadOfControl function runs at most one thread of control before returning to the caller. It returns a boolean value indicating if a thread of control was actually run. A thread of control is started when an event that was signaled outside any instance context (e.g. by a domain operation or by a portal operation) or a delayed signal whose delay time has expired is dispatched. The thread of control continues until all the events have been delivered which were signaled from within any instance context as a direct or indirect result of any transition caused by the event that started the thread of control.

At the end of the thread of control, the referential integrity implied by the relationships of the domain is evaluated. Any class where instances of the class were created or deleted or any of the relationships in which a class participates are modified will be evaluated to determine if the constraints implied by the relationships of the domain are preserved.

bool mrt_DispatchSingleEvent(void)

The mrt_DispatchSingleEvent function dispatches at most one event from the event queue and returns a boolean indicated if an event was dispatched. If the dispatched event ended a thread of control, then the normal processing associated with ending a thread of control happens (i.e. referential integrity is checked). This function provides a means of fine grained control over event dispatching that can be useful in testing situations or when it is necessary to integrate micca generated domains with legacy code.

Fatal Error Handler

typedef void (*MRT_FatalErrorHandler)(MRT_ErrorCode, char const *, va_list)
MRT_FatalErrorHandler mrt_SetFatalErrorHandler(MRT_FatalErrorHandler newHandler)

Applications may substitute their own fatal error handler for the default one. All errors detected by the run-time cause a fatal error condition. By default, a message is printed to the standard error and the standard library function, abort() is invoked. Applications can install a new hander by invoking mrt_SetFatalErrorHandler which returns a pointer to the previous handler. If the application supplied error handler returns, the run-time will still invoke abort() to insure that no further attempts to dispatch events are made.

Application supplied error handlers may also use the standard library functions, setjmp() and longjmp() to perform a non-local transfer of control. This allows the application to exert finer control over error situations. N.B. that restarting event dispatch after a fatal error must be done with great care.

The following example shows one way to return execution control to an application if a fatal error occurs.

#include <setjmp.h>
#include "micca_rt.h"
static jmp_buf fataljmp ;
static MRT_FatalErrorHandler prevHandler ;
static void
jumpFatalHandler(
    MRT_ErrorCode errNum,
    char const *fmt,
    va_list alist)
{
    /*
     * Print a message using the default error handler.
     */
    prevHandler(errNum, fmt, alist) ;
    /*
     * Non-local goto to return control back to main.
     */
    longjmp(fataljmp, errNum) ;
}
int
main(
    int argc,
    char *argv[])
{
    /*
     * Initialize the run-time code itself.
     */
    mrt_Initialize() ;
    prevHandler = mrt_SetFatalErrorHandler(jumpFatalHandler) ;
    for (;;) {
        int errCode = setjmp(fataljmp) ;
        if (errCode == 0) {
            /*
             * The first time through, we enter the event loop to cause the
             * application to run. "mrt_EventLoop()" does not return unless
             * some domain action invokes "mrt_SyncToEventLoop()".  So in the
             * event that we return from the event loop, it was purposeful and
             * we probably want to end the application.
             */
            mrt_EventLoop() ;
            break ;
        } else {
            /*
             * Control returns here in the event of a fatal error in the
             * run-time. The value of "errCode" is the fatal error number.  The
             * application can do anything it wishes. If the application
             * determines that the program should end, then executing a break
             * statement here (as is done below) will accomplish that.
             * Otherwise, it may wish to take whatever corrective action or
             * other notifications are necessary.  Falling through this else
             * clause will restart the event loop.
             */
            break ;
        }
    }
    return EXIT_SUCCESS ;
}

This technique can be used effectively when testing if the test case can force a fatal error and then repair the state of things after jumping out of the event loop. Then the event loop can be restarted.

See Also

rosea

Keywords

translation