© Leon Starr, Andrew Mangogna and Stephen Mellor 2017

Leon Starr, Andrew Mangogna and Stephen Mellor, Models to Code, 10.1007/978-1-4842-2217-1_4

4. Translating the Air Traffic Control Model

Leon Starr, Andrew Mangogna2 and Stephen Mellor1

(1)San Francisco, California, USA

(2)Nipomo, California, USA

We took a tour of the key decisions made during translation of an xUML model in the previous chapter. Now, we get busy making those decisions for the ATC example introduced in Chapter 2. A pycca model script is prepared, and we examine the resulting C code. The subject of this chapter is implementation oriented, and we assume you are familiar with the C language. Space doesn’t permit us to present all of the code here, but if you are interested in reviewing the entire ATC project, including all of the code, feel free to download it from www.modelstocode.com .

We translate the three facets of xUML in the order of classes, states, and actions. Translating the class model specifies the entities on which the code operates. Translating state models determines the sequencing and synchronization of the code and establishes the structure on which most of the actions are executed. Translating actions implements the algorithmic processing. And by translating all three model facets, we get a complete runnable program.

Overview of Pycca Syntax

Pycca reads one or more model source files and produces a single C header and source file pair. The C code written directly in the model file will be rearranged and mixed in with additional C code generated by pycca. Pycca has a few syntax conventions:

  • Comments: A comment begins with the hash character (#) and continues to the end of the line.

  • Symbol names: Symbol names follow the syntax of C identifiers. Names must begin with a letter, followed by an arbitrary number of letters, decimal digits, or underscore (_) characters. Models may use whitespace in class or attribute names, and these must be eliminated or replaced during translation because the names will be used directly as C identifiers.

  • C code: Anything enclosed in braces ({}) is passed directly on to the C compiler.

  • Variable declarations: Anything enclosed in parentheses (()) is taken as a comma-separated list, possibly empty, of C variable declarations.

Organization of a Pycca File

The largest unit of organization in a pycca file is a domain. The ATC example is centered around a single application domain, though you may have noticed a few actions that coordinate with external domains. In Chapter 6, we’ll pursue a multidomain example, but for this pycca file, we’ll we keep to a single domain.

A domain definition is cumulative. If the same domain name is encountered later in the input, any content in the later definition is simply incorporated into the existing domain. A domain is defined as follows:

domain atctrl
    # Model statements (data types, classes, etc)
end


domain atctrl
    # Additional atctrl model statements
    # For example, the initial instance population.
    #  Domain  statements  may  also  be  placed  in separate  files.
end

The model statements that make up the content of a domain will be introduced as needed as we go about translating the Air Traffic Controller model. For reference, all possible model statements can be found in the online materials. And you don’t need to worry about the ordering of model statements within a domain section. Pycca parses all of its input before attempting to generate any output. It orders the generated output to satisfy the C compiler’s needs.

Pycca assumes the existence of runtime functions that implement data management and the event processing required by the state models. We discuss the runtime library in Chapter 5. For now, it is sufficient to know that a small piece of code manages execution by generating signals and dispatching the corresponding events, causing transitions that invoke state activities. You can use the preprocessor macros that pycca supplies as a convenient way to interface to the runtime code for such activities.

Translating the Class Model

We first translate those aspects of the model that deal with data. We specify the data types, followed by the class definitions and, finally, an initial instance population.

Data Types

What follows is the data type implementation for the domain. Data types are grouped in the interface or implementation categories. The interface category is for those types that must be visible outside the domain for the purposes of interaction. They are put into a header file that can be included by other code. The implementation category is for all other data types in a domain. Generally, the majority of data types are in the implementation category. If it helps, you can think of these two categories as public and private with respect to a domain.

domain atctrl                                      ❶

    # ....
    #  Other  domain  components
    # ....


    interface prolog {                             ❷
        typedef char const *Employee_ID ;          ❸
        typedef char const *Station_Number ;
        typedef char const *Czone_Name ;
    }


    implementation prolog {                        ❹
        typedef char const *Name_T  ;              ❺
        typedef time_t Date_T ;
        typedef unsigned Aircraft_Quantity ;
        typedef unsigned Aircraft_Maximum ;
        typedef unsigned Duration ;
        typedef char const *Experience_Level ;


        #include  <assert.h>
        #include <time.h>
        #include <string.h>
        #include "atctrl.h"
    }


    # ....
    #  Other  domain  components
    # ....


end
  • ❶ In this pycca source, we show the surrounding domain/end statements. Later in this chapter we assume all domain component definitions are enclosed in an outer domain statement and dispense with including the containing statements themselves.

  • ❷ This section defines declarations that are needed as part of the external interface of the domain. Here we include those typedef statements that describe parameters exchanged with other domains. For the atctrl domain, there are external calls to report error and warning conditions (presumably to a user interface domain) that include the value of an employee identifier. So, we must make the data type for that value available for the interface. Interface prolog code is placed at the top of the generated C header file. Any additional required include files or other declarations can be included as part of the interface prolog.

  • ❸ We are careful to declare immutable values as const. For embedded systems, we can direct the linker to place constants in nonvolatile memory (for example, flash), of which we usually have much more than RAM. In C, string literals are constant, and we would not want a piece of code changing a character in an employee’s name.

  • ❹ This section defines declarations used inside the domain and, therefore, not visible externally. The implementation prolog text is placed at the top of the generated C header file. This section can also be used to include declarations for external libraries that might be used as part of the processing of the domain (for example, standard C libraries or a math library or a core algorithm from a legacy system).

  • ❺ We have called these types Name_T and Date_T in variance to the model names because of a limitation in pycca that does not allow attributes and types to have the same name.

Class Definitions

Pycca will translate each class definition in the model file into a C structure definition. In the following sections, we show the pycca class definitions for some of the model classes of the Air Traffic Controller model from Chapter 2. Please refer to the model classes in Chapter 2 as you read along.

Duty Station

We start with a simple class, Duty Station. Figure 4-1 shows the correspondence between the class model graphic and pycca source. In the pycca source, we adhere closely to the names of attributes and relationships as they are found in the model. Nothing is gained by arbitrarily changing names and mucking up the correspondence between the model and the code!

A421575_1_En_4_Fig1_HTML.gif
Figure 4-1. Specifying the Duty Station class
  • ❶ We have retained the Number identifying attribute because its value is used in an activity.

  • Duty_Station participates in a simple relationship, R3. The multiplicity of R3 traversing from Duty_Station to On_Duty_Controller references at most one instance of On_Duty_Controller (0..1 in UML notation). The reference statement with -> denotes this multiplicity. A zero in a multiplicity expression expresses conditionality, which means that there may be no related instances at any given time. This idea is implemented by letting the R3 member take on a NULL value.

Where the model shows attributes as names followed by the data type, we follow C syntax in the model source file with the data type first, followed by the attribute name. Anything enclosed in parentheses must follow C variable declaration syntax because it will be passed directly to the C compiler.

Pycca translates each class statement into a C structure definition. Figure 4-2 shows the correspondence between the model graphic for the Duty Station class and the C structure generated by pycca.

A421575_1_En_4_Fig2_HTML.gif
Figure 4-2. C generated for the Duty Station class
  • ❶ Note that the class names are used directly as structure names, so you must choose class names that are valid C identifiers.

  • ❷ Pycca inserts this member for the runtime to use when managing the data and state processing of the class. Classes that don’t require those functions of the runtime will not be given this structure member. The use of this structure member is described in detail in Chapter 5.

  • ❸ The singular reference statement is converted into a pointer to a structure.

This structure definition has a direct correspondence to the pycca statements. Class attributes become structure members. Simple relationships are implemented as pointers to objects of the related structure type.

Air Traffic Controller

For the Air Traffic Controller class, we follow the same principles for the attributes as with the Duty Station class. The additional consideration for this class is the R1 generalization. Figure 4-3 shows the encoding of the model graphic into pycca statements.

A421575_1_En_4_Fig3_HTML.gif
Figure 4-3. Specifying a superclass with a union
  • ❶ This statement declares R1 as a generalization whose subclasses are to be held as a union member within the Air_Traffic_Controller structure. We chose the union implementation as this works best in simple cases.

  • ❷ It’s okay that we haven’t defined the subclasses yet. Pycca imposes no particular order on the definitions.

Similar to the Duty Station class, pycca generates a C structure definition for the Air Traffic Controller class:

struct Air_Traffic_Controller {
    struct mechinstance common_ ;
    Employee_ID ID ;
    Name_T Name ;
    Experience_level Rating ;
    SubtypeCode R1__code ; ❶
    union {
        struct Off_Duty_Controller R1_Off_Duty_Controller ;
        struct On_Duty_Controller R1_On_Duty_Controller ;
    } R1 ;
} ;
  • ❶ The new constructs seen in this declaration are the R1__code and R1 members. The R1__code member holds a small integer that encodes the union element currently related to the superclass instance, and pycca supplies preprocessor definitions for the encoded values. The R1 structure member is a union of all the subclasses that participate in the R1 generalization.

From a model execution point of view, when navigating R1 from the Air Traffic Controller class to one of its subclasses, we must be able to determine whether the traversal across R1 comes up empty. So, if we have an instance of Air Traffic Controller and we navigate across R1 to the Off Duty Controller class, it could be the case that the Air Traffic Controller instance is not currently related to an Off Duty Controller class instance (that is, it is currently related to an instance of On Duty Controller). The navigation operation yields the empty set, and we must be able to determine that.

From an implementation point of view, we need to know how to interpret the R1 structure member. By testing the value of R1__code, we can determine which element of the union is currently in use. By placing the subclasses in the R1 union member, no other storage for the R1 generalization is needed. We can traverse R1 by appropriate pointer arithmetic. Pycca provides macros to do the heavy lifting and helps prevent common errors. Don’t be alarmed that pycca uses the keyword subtype in this context.

On Duty Controller

Our last example of data translation is the On Duty Controller class. A key decision for this class is how to store information for the R2 association. By considering the domain actions, we see that R2 associates one On Duty Controller instance to many Control Zone instances and that association is dynamic in nature. Actions will link and unlink instances of On Duty Controller to an arbitrary number of Control Zone instances. We need a data structure for the relationship storage that supports the multiplicity and dynamics of R2. Pycca provides a suitable linked list mechanism. That works for R2, but it is often the case, especially in embedded systems, that associations are static over the running time of the application. So pycca also provides a means for storing reference values suited to static associations. Figure 4-4 shows how the On Duty Controller class is specified.

A421575_1_En_4_Fig4_HTML.gif
Figure 4-4. Specifying the On Duty Controller class
  • ❶ Because we have chosen to hold the subclasses as a union composed into the superclass, we have discarded the ID attribute. It is not needed to implement the R1 relationship, and its value is available from the superclass if we need it. The default value for Time_logged_in is zero because we are using a POSIX representation of time, and zero is used to indicate an unknown login time.

  • ❷ The ->>l (lowercase letter l) notation tells pycca to use a linked list to store instance references for the R2 association in the Control Zone direction. This is one of the link types mentioned in Chapter 3 for storing instance references to implement associations.

  • ❸ The -> notation tells pycca that storage for R3 will be a single instance reference to a Duty_Station class.

Pycca generates the following code:

struct On_Duty_Controller {
    Date_T Time_logged_in ;
    rlink_t R2  ;                 ❶
    struct Duty_Station *R3 ;     ❷
} ;
  • ❶ Pycca will provide the necessary data structures and code to deal with the linked list.

  • ❷ The storage for relationship R3 is simply a pointer to the struct Duty_Station. Because the multiplicity of the R3 relationship from On Duty Controller to Duty Station is one, at no time should the value of the R3 member be NULL. The R2 member is the head of the linked list onto which we can link a set of Control_Zones.

The other modeled classes follow a similar pattern, so we won’t reproduce them here. Complete pycca source for the model, in the form of a literate program, can be found at the website for this book.

Initial Instance Population

After the class model has been fully translated, it requires one more thing before it can be used: an initial instance population. This is a set of instances that are present when the system is initialized. Pycca can place an initial population into memory as initialized variables, so no code is required to create instances during initialization. This is particularly important in embedded systems in which instance populations are frequently static. For dynamic populations, instances may be created both before and during runtime.

In Chapter 2, example instances in the ATC domain were shown as tables. Pycca supports a tabular syntax for specifying initial instance populations. (There is also a syntax that is more convenient for specifying single instances.) The following pycca code specifies the initial instance population for our example:

table Air_Traffic_Controller
        (Employee_ID ID) (Name_T Name) (Experience_Level Rating) R1
@atc53  {"53"} ❶        {"Toshiko"}   {"A"}    -> On_Duty_Controller.atc53 ❶
@atc67  {"67"}           {"Gwen"}      {"B"}    -> On_Duty_Controller.atc67
@atc51  {"51"}           {"Ianto"}     {"C"}    -> On_Duty_Controller.atc51
end


table On_Duty_Controller
            R2               R3
@atc53      ->> sfo end      -> s2 ❷
@atc67      ->> oak end      -> s1
@atc51      ->> sjc end      -> s3
end


table Control_Zone
        (Czone_Name Name)    (Aircraft_Quantity  Traffic)      R2
@sfo    {"SFO37B"}           {27}                              ->  atc53
@oak    {"OAK21C"}           {18}                              ->  atc67
@sjc    {"SJC18C"}           {9}                               ->  atc51
end


table Duty_Station
     (Station_Number  Number)  (Name_T  Location)  (Aircraft_Maximum  Capacity)
@s1  {"S1"} ❸                 {"Front"}           {20}
@s2  {"S2"}                    {"Center"}          {30}
@s3  {"S3"}                    {"Front"}           {45}
end
  • ❶ For relationship storage, we are dealing with pointers. By naming the instance (using the @<name> syntax), you can refer to the instances in relationship initializers. Pycca keeps track of where the named instances reside in the allocated storage array and emit the proper address expressions. When specifying the subclass instance for a generalization, it is also necessary to give the subclass name by using the dot notation shown.

  • ❷ For relationship paths that are singular, the -> notation indicates the name of the instance to be related.

  • Pycca stores all instances of a class in a C array. The descriptive attributes, such as Location, are assigned to the appropriate structure member in the initializer for the array element. The values are specified in braces ({}), because pycca passes anything in braces directly through to the C compiler. This means we can use any valid C constant expression as an attribute initializer.

Pycca converts the initial instance population into an array of structures with initializer values. Each class has a separate array that serves as its memory pool. The following are the C variables and initializers generated for the initial instance:

/*
Initial Instance Storage for, "Air_Traffic_Controller"
*/
static  struct  Air_Traffic_Controller  Air_Traffic_Controller_storage[3]  =   {   ❶
    {❷.common_ = {1, 0, &Air_Traffic_Controller_class}, "53", "Toshiko", "A", .R1   code = ,
        1, .R1 = {.R1_On_Duty_Controller = {0, .R2 = {.next = &Control_Zone_storage[0].
        R2__links, .prev  =  &Control_Zone_storage[0].R2__links}, .R3  = &Duty_Station_storage  
        [1]}}},
    {.common_ = {2, 0, &Air_Traffic_Controller_class}, "67", "Gwen", "B", .R1__code = 1, .
        R1 = {.R1_On_Duty_Controller = {0, .R2 = {.next = &Control_Zone_storage[1].R2__links
        , .prev = &Control_Zone_storage[1].R2__links}, .R3 = &Duty_Station_storage[0]}}},
    {.common_ = {3, 0, &Air_Traffic_Controller_class}, "51", "Ianto", "C", .R1__code = 1, .
        R1 = {.R1_On_Duty_Controller = {0, .R2 = {.next = &Control_Zone_storage[2].R2__links
        , .prev = &Control_Zone_storage[2].R2__links}, .R3 = &Duty_Station_storage[2]}}}
} ;
/*
 *Initial Instance Storage for, "Control_Zone"
 */
static struct Control_Zone Control_Zone_storage[3] = { ❸
    {"SFO37B", 27, .R2 = &Air_Traffic_Controller_storage[0].R1.R1_On_Duty_Controller, .
        R2__links = {.next = &Air_Traffic_Controller_storage[0].R1.R1_On_Duty_Controller.R2,
         .prev = &Air_Traffic_Controller_storage[0].R1.R1_On_Duty_Controller.R2, }},
    {"OAK21C", 18, .R2 = &Air_Traffic_Controller_storage[1].R1.R1_On_Duty_Controller, .
        R2__links = {.next = &Air_Traffic_Controller_storage[1].R1.R1_On_Duty_Controller.R2,
         .prev = &Air_Traffic_Controller_storage[1].R1.R1_On_Duty_Controller.R2, }},
    {"SJC18C", 9, .R2 = &Air_Traffic_Controller_storage[2].R1.R1_On_Duty_Controller, .
        R2__links = {.next = &Air_Traffic_Controller_storage[2].R1.R1_On_Duty_Controller.R2,
         .prev = &Air_Traffic_Controller_storage[2].R1.R1_On_Duty_Controller.R2, }}
} ;
/*
 *  Initial Instance Storage for, "Duty_Station"
 */
static struct Duty_Station Duty_Station_storage[3] = {
    {.common_ = {1, 0, &Duty_Station_class}, "S1", "Front", 20, .R3 = NULL},
    {.common_ = {2, 0, &Duty_Station_class}, "S2", "Center", 30, .R3 = NULL},
    {.common_ = {3, 0, &Duty_Station_class}, "S3", "Front", 45, .R3 = NULL}
} ;
  • ❶ Recall that the Air_Traffic_Controller class is a union containing the subclasses of R1, so no separate storage is allocated for the subclasses. The values for the subclass attributes are included directly in the initializer for the superclass.

  • ❷ The common_ member holds an allocation number, the current state, and a pointer to class invariant data. This is the data required by the runtime code to manage the instance. In Chapter 5, we discuss instances from the perspective of the runtime code and exactly how this structure member is used.

  • ❸ The Control_Zone class has no state model, and all of its instances are part of the initial instance population. Consequently, there is no common_ member of its class structure because the runtime does not have to manage the instances in any way.

Recall that R2 was implemented as a linked list originating at the Air_Traffic_Controller instances. Pycca properly initializes the link pointers in both the Air_Traffic_Controller and Control_Zone storage arrays. The pointer values in the initializers are constant expressions that index into the storage arrays and onto the element structure members. Pycca allocates instances to the storage array and can therefore specify these address calculations. Note that these expressions are bound to a memory address at link time after the base address of the storage array has been placed by the linker.

Translating State Models

The second aspect of translating is to specify the state models. All model classes with a state model will have a corresponding machine definition in pycca. State models specify both the transitions and the C code executed when a state is entered. The C code for a state is placed directly in the definition of the state model for a class. We leave out the C code for the time being so that we are better able to show just the transition aspects of the state model. In the next section, “Translating Actions,” the C code will make its appearance. We have included the action language in the state definitions as a C comment. It is particularly convenient to have the action language nearby when translating it into C code.

Duty Station State Model

We recommend referring to the Duty Station state model in Chapter 2, Figure 2-6, as you read along so you can readily see the correspondence between the model elements and the pycca statements.

The state model is encoded using a machine statement:

class Duty_Station

    # ... Other parts of Duty_Station definition, attributes, etc.

    Machine                                                           ❶
        state AVAILABLE()                                             ❷
        {
            // empty
        }
        transition AVAILABLE - In_use -> IN_USE                       ❸


        state IN_USE()
        {
            //+ Max shift exceeded  ->  me  after Shift               ❹
            //+     Specification().Max shift // selects singleton
        }
        transition IN_USE - Max_shift_exceeded -> MAX_SHIFT_EXCEEDED
        transition IN_USE - User_leaving -> Canceling_Shift_Timeout


        state MAX_SHIFT_EXCEEDED()
        {
            //+ UI.Break required( Station: Number )
        }
        transition MAX_SHIFT_EXCEEDED - User_leaving -> AVAILABLE


        state Canceling_Shift_Timeout()
        {
            //+ cancel Max shift exceeded -> me
            //+ Available -> me
        }
        transition Canceling_Shift_Timeout - Available -> AVAILABLE
    end
  • ❶ The state model for a class is completely specified within a machine statement.

  • ❷ Here we define a state. This statement specifies the name of the state along with any parameters passed through incoming transitions. A corollary of the Moore state model formalism is that all incoming transitions to a state must supply the same set of parameters. As it turns out, the Duty Station state model has no parameters defined on any of its transitions.

  • ❸ The transition statement defines the state model transition (that is, what happens when events are received by an instance of this class). Transitions are defined by the starting state, a received event, and the new state that is the destination of the transition. Events do not require a separate definition. Event names are gathered from the transition statements.

  • ❹ The state activity will ultimately be C code, not generated, but written by hand directly into the model source file. Don’t be alarmed; pycca provides a set of C macros that you can substitute for most model actions. We’ll get to all of that later. For now, we are copying in the modeled action language as comments. Even after we replace it with C code, it is a good idea to retain the original action language as a comment.

The pycca source is a direct transliteration of the state model graphic. The syntax to specify a state is reminiscent of a function definition complete with parameters (from the triggering event, none in this example) and the code (activity) to be executed.

No particular order is imposed on the state and transition statements. Here we have placed outgoing transitions immediately below the state to which they apply. Another convenient organization is to place all the transition statements together to emphasize the correspondence to the transition matrix for the state model.

A set of data structures encodes all the state behavior for a given class. The runtime code uses these data structures to dispatch events to state machines. An important function of pycca is generating the data structures used by the runtime event dispatch code. Pycca transforms the state model specification into a set of initialized variables whose values describe how to dispatch events and what processing to execute when transitions occur. The dispatch code uses a tabular encoding of the state model. The behavior of the event dispatch is the same for all the instances of a class. The algorithm for determining transitions and executing state activities is the same for all classes.

The following listing shows the data structures generated by pycca for the Duty Station state model. The data are initialized variables for a dispatch block, transition table, and action table. In Chapter 5, we show the structure of this data and exactly how it is used by the runtime code to cause state transitions to happen. Don’t be too concerned if the following doesn’t make much sense yet. After you’ve read through Chapter 5 and have a better understanding of how state transitions are managed and events are dispatched in the runtime environment, it should all seem a bit more reasonable.

static  PtrActionFunction  const  Duty_Station_acttbl[]  =  {
    Duty_Station_AVAILABLE,                                        ❶
    Duty_Station_IN_USE,
    Duty_Station_MAX_SHIFT_EXCEEDED,
    Duty_Station_Canceling_Shift_Timeout,
} ;
static StateCode  const  Duty_Station_transtbl[]  =  {
    MECH_STATECODE_CH, // AVAILABLE - Available -> CH              ❷
    1, // AVAILABLE - In_use -> IN_USE
    MECH_STATECODE_CH, // AVAILABLE - Max_shift_exceeded -> CH
    MECH_STATECODE_CH, // AVAILABLE - User_leaving -> CH
    MECH_STATECODE_CH, // IN_USE - Available -> CH
    MECH_STATECODE_CH, // IN_USE - In_use -> CH
    2, // IN_USE - Max_shift_exceeded -> MAX_SHIFT_EXCEEDED
    3, // IN_USE - User_leaving -> Canceling_Shift_Timeout
    MECH_STATECODE_CH, // MAX_SHIFT_EXCEEDED - Available -> CH
    MECH_STATECODE_CH, // MAX_SHIFT_EXCEEDED - In_use -> CH
    MECH_STATECODE_CH, // MAX_SHIFT_EXCEEDED - Max_shift_exceeded -> CH
    0, // MAX_SHIFT_EXCEEDED - User_leaving -> AVAILABLE
    0, // Canceling_Shift_Timeout - Available -> AVAILABLE
    MECH_STATECODE_CH, // Canceling_Shift_Timeout - In_use -> CH
    MECH_STATECODE_CH, // Canceling_Shift_Timeout - Max_shift_exceeded -> CH
    MECH_STATECODE_CH, // Canceling_Shift_Timeout - User_leaving -> CH
} ;
static struct objectdispatchblock const Duty_Station_odb =  {      ❸
    .stateCount = 4,
    .eventCount  =  4,
    .transitionTable    =    Duty_Station_transtbl,
    .actionTable   =   Duty_Station_acttbl,
    .finalStates  =  NULL
} ;
  • ❶ In the next section, you will see how activity functions are defined. Here, all the activity functions for a state model are collected into a single array so the appropriate one can be located when a given state is entered.

  • CH means can’t happen. Any event that causes a CH transition results in a system error.

  • ❷The object dispatch block is the collection of information used by the runtime code to accomplish event delivery. This is explained further in Chapter 5.

Air Traffic Controller State Model

The state model for the Air_Traffic_Controller class is somewhat longer but follows the same pattern as shown previously for the Duty_Station class:

class  Air_Traffic_Controller

    # ... Other parts of Air_Traffic_Controller definition, attributes, etc.

    machine
        state OFF_DUTY ()
        {
            // empty
        }
        transition OFF_DUTY - Ready_for_duty -> Verifying_Adequate_Break


        state Verifying_Adequate_Break(Station_Number Station)
        {
            //+ the shift spec .= Shift Specification() // selects singleton
            //+ if ( _now - self.Last shift ended < the shift spec.Min break )
            //+     Log in( in.Station ) -> me
            //+ else
            //+     Cannot  go  on  duty  ->  me
        }
        transition Verifying_Adequate_Break - Log_in -> Logging_In
        transition Verifying_Adequate_Break - Cannot_go_on_duty -> OFF_DUTY


        state Logging_In(Station_Number Station)
        {
            //+ migrate to On Duty Controller
            //+ my station = Duty Station( ID: in.Station )
            //+ link /R3/my station
            //+ Time logged in = now()
            //+ Logged in -> me
            //+ In use -> my station
        }
        transition Logging_In - Logged_in -> ON_DUTY


        state ON_DUTY()
        {
            // empty
        }
        transition ON_DUTY - Ready_for_a_break -> Verifying_Full_Handoff
        transition ON_DUTY - Handoff -> Handing_off_Control_Zone


        state  Handing_off_Control_Zone(
            Czone_Name zone,
            Employee_ID  controller)
        {
            //+ hoff zone .= /R2/Control Zone( Name: in.Zone )
            //+ if in.Controller == ID
            //+     UI.Cannot handoff to self( Controller: in.Controller )
            //+ else {
            //+     new controller .= On Duty Controller( ID: in.Controller )
            //+     swap hoff zone/R2/On Duty Controller with new controller
            //+         !new missing: UI.Unknown controller( Controller: in.Controller)
            //+         !old missing: UI.Zone not handled by( Controller: ID)
            //+ } // swaps controllers and checks for errors
            //+ Handoff complete -> me
        }
        transition Handing_off_Control_Zone - Handoff_complete -> ON_DUTY


        state Logging_Out()
        {
            //+ User leaving -> /R3/Duty Station
            //+ migrate to Off Duty Controller
            //+ Last shift ended = _now.HMS
            //+ Off duty -> me
        }
        transition Logging_Out - Off_duty -> OFF_DUTY


        state Verifying_Full_Handoff()
        {
            //+ if /R1/On Duty Controller/R2/Control Zone{
            //+     Must handoff zones -> me
            //+     UI.Control Zones Active( ATC: ID )
            //+ } else
            //+     Log out -> me   
        }
        transition Verifying_Full_Handoff - Log_out -> Logging_Out
        transition Verifying_Full_Handoff - Must_hand_off_zones -> ON_DUTY
    end
end

We don’t show the generated output, because it follows the same pattern you have already seen.

Translating Actions

In this section, we translate the processing associated with actions in the state activities. Pycca turns each state activity into a C function and arranges for the function to be included in the data structures generated for the runtime dispatch mechanism.

State activities almost always result in updating instance attributes and/or signaling an event. Data access is provided by the normal C mechanism for access to structure members via a pointer. Pycca augments the C code you provide for the state activity with the necessary declarations for a self (me) variable and a rcvd_evt variable used to access event parameters.

Air Traffic Controller State Activities

We begin with the Air Traffic Controller class showing only selected state activities. The state activity for the Logging In state is shown in the following code. We have included the action language for the state as a comment and have interspersed the C that implements the corresponding actions:

class  Air_Traffic_Controller

    # ... Other parts of Air_Traffic_Controller definition, attributes, etc.

    machine

        # ... Other parts of the state model definition

        state Logging_In(Station_Number Station)
        {
            //+ migrate to On Duty Controller
            PYCCA_migrateSubtype(self,  Air_Traffic_Controller,  R1,
                   On_Duty_Controller) ;                                                  ❶


            //+ my_station  =  Duty  Station(  ID:  in.Station  )
            ClassRefVar(Duty_Station, my_station) ;                                       ❷
            PYCCA_selectOneStaticInstWhere(my_station,  Duty_Station,                    strcmp(my_station->Number, rcvd_evt->Station) == 0) ;                 ❸
            assert(my_station != EndStorage(Duty_Station)) ;


            //+ & /R3/my  station
            ClassRefVar(On_Duty_Controller, ondc) =
                    PYCCA_unionSubtype(self, R1, On_Duty_Controller) ;                    ❹
            ondc->R3 = my_station ;                                                       ❺
            my_station->R3 = ondc ;


            //+ Time logged in = now()
            ondc->Time_logged_in = time(NULL) ;                                           ❻


            //+ Logged in -> me
            PYCCA_generateToSelf(Logged_in) ;                                             ❼


            //+ In use -> my station
            PYCCA_generate(In_use, Duty_Station, my_station, self) ;                      ❽
        }


        # ... Other part of the state model definition

    end
end
  • ❶ Pycca provides a macro to perform the subclass migration for union-based generalizations. This hides the internal instance structure members.

  • ❷ The ClassRefVar macro declares a local variable that is a reference to an instance. In this case, my_station is a variable that references an instance of Duty_Station.

  • ❸ Finding a Duty_Station is accomplished with a linear search of the storage array for Duty_Station. Pycca provides a convenience macro to perform the iteration. You would choose other searching techniques if the number of instances of Duty_Station is large. Note that the Station event parameter is obtained via the implicit rcvd_evt variable that is automatically generated by pycca.

  • ❹ Because R3 is between an On Duty Controller and a Duty Station, we must traverse R1 first. R1 is implemented as a union, and the macro performs the required pointer arithmetic.

  • ❺ Each class participating in R3 is keeping a reference to the corresponding instance, and so linking involves setting both pointer values.

  • ❻ Accounting for time is platform specific, and pycca does not supply any time functions. Here we are assuming a POSIX environment.

  • ❼ Here, a signal to self is generated. Note that Logged_in is the same name used in the state model definition.

  • ❽ The general form of signal generation specifies the signal, the class of the target instance, the target instance itself, and the instance that is the source of the signal.

Pycca turns the state action into a C function as shown here:

static void Air_Traffic_Controller_Logging_In(void *const s_, void *const p_)
{
#define THISSTATE__ Logging_In                                                          ❶
    struct Air_Traffic_Controller *const self =  (struct Air_Traffic_Controller *)s_ ;  ❷
    struct Air_Traffic_Controller_Logging_In_rcvd_evt {
        Station_Number Station ;
    } const *const rcvd_evt = (struct Air_Traffic_Controller_Logging_In_rcvd_evt const *)p_ ;


    //+ migrate to On Duty Controller on R1
    PYCCA_migrateSubtype(self, Air_Traffic_Controller, R1, On_Duty_Controller) ;


    //+ my_station = Duty Station( ID: in.Station )
    ClassRefVar(Duty_Station, my_station) ;
    PYCCA_selectOneStaticInstWhere(my_station,  Duty_Station,
            strcmp(my_station->Number, rcvd_evt->Station) == 0) ;
    assert(my_station != EndStorage(Duty_Station)) ;


    //+ & self.R3.my_station    // link station
    ClassRefVar(On_Duty_Controller, ondc) = PYCCA_unionSubtype(self, R1, On_Duty_Controller) ;
    ondc->R3 = my_station ;
    my_station->R3 = ondc ;


    //+ Time logged in = _now.HMS
    ondc->Time_logged_in = time(NULL) ;


    //+ Logged in -> me
    PYCCA_generateToSelf(Logged_in)  ;


    //+ In use -> my station
    PYCCA_generate(In_use, Duty_Station, my_station, self) ;
#undef THISSTATE__
}
  • ❶ Preprocessor #define statements keep track of the current state. The current state is used by other preprocessor macros.

  • ❷ Pycca arranges the declarations of self and rcvd_evt.

Other than the declarations of self and rcvd_evt, pycca has simply turned the state action into a function of file static scope and passed along the C code that was specified in the state model definition. The name of the function has the class name prepended to make it unique within the file.

We show one more example of translating a state activity. Following is the pycca source for the Logging Out state of the Air Traffic Controller class:

class  Air_Traffic_Controller

    # ... Other parts of Air_Traffic_Controller definition, attributes, etc.

    machine

        # ... Other parts of the state model definition

        state Logging_Out()
        {
            //+ User  leaving  ->  /R3/Duty  Station
            assert(self->SubCodeMember(R1 ==
                    SubCodeValue(Air_Traffic_Controller,  R1,On_Duty_Controller)) ;
            ClassRefVar(On_Duty_Controller, ondc) =
                    PYCCA_unionSubtype(self, R1, On_Duty_Controller) ;            ❶
            ClassRefVar(Duty_Station, ds) = ondc->R3 ;                            ❷
            assert(ds != NULL) ;
            PYCCA_generate(User_leaving, Duty_Station, ds, self) ;


            //+ migrate to Off Duty Controller
            ondc->R3 = NULL ;                                                     ❸
            ds->R3 = NULL ;


            PYCCA_migrateSubtype(self,  Air_Traffic_Controller,  R1,
                    Off_Duty_Controller) ;
            assert(self->SubCodeMember(R1)  ==
                    SubCodeValue(Air_Traffic_Controller,  R1,
                    Off_Duty_Controller)) ;


            //+ Last shift ended = _now.HMS ClassRefVar(Off_Duty_Controller, offdc) =
                    PYCCA_unionSubtype(self, R1, Off_Duty_Controller) ;            ❹
            offdc->Last_shift_ended = time(NULL) ;


            //+ Off duty -> me
            PYCCA_generateToSelf(Off_duty) ;
        }


        # ... Other part of the state model definition

    end
end
  • ❶ This traverses R1 from Air_Traffic_Controller to On_Duty_Controller. The assertion checks that the instance of ATC is indeed related to an instance of On_Duty_Controller. If not, something is terribly wrong.

  • ❷ Traversal of R3 from an instance of On_Duty_Controller to an instance of Duty_Station is a simple matter of retrieving a pointer. The relationship is unconditional from On Duty Controller to Duty Station; therefore, a valid pointer value must be stored in Duty_Station.R3. The assertion checks the data integrity.

  • ❸ Because each class contains a reference to the other, maintaining the relationship storage means updating both pointers.

  • ❹ Because we have migrated subclasses, we must obtain a reference to the new subclass.

The generated C code follows:

static void Air_Traffic_Controller_Logging_Out(void *const s_, void *const p_)
{
#define THISSTATE__ Logging_Out
    struct Air_Traffic_Controller *const self =  (struct Air_Traffic_Controller *)s_ ;    ❶


    //+ User leaving -> /R3/Duty Station
    assert(self->SubCodeMember(R1) == SubCodeValue(Air_Traffic_Controller,  R1,
            On_Duty_Controller)) ;
    ClassRefVar(On_Duty_Controller, ondc) =
            PYCCA_unionSubtype(self, R1, On_Duty_Controller) ;
    ClassRefVar(Duty_Station, ds) = ondc->R3 ;
    assert(ds != NULL) ;
    PYCCA_generate(User_leaving, Duty_Station, ds, self) ;


    //+ migrate self to Off Duty Controller on R1
    ondc->R3 = NULL ;
    ds->R3 = NULL ;


    PYCCA_migrateSubtype(self,  Air_Traffic_Controller,  R1,
            Off_Duty_Controller) ;


    //+ Last_shift_ended = _now.HMS
    ClassRefVar(Off_Duty_Controller, offdc) =
            PYCCA_unionSubtype(self, R1, Off_Duty_Controller) ;
    offdc->Last_shift_ended = time(NULL) ;


    //+ Off duty -> me
    PYCCA_generateToSelf(Off_duty) ;
#undef THISSTATE__
}
  • ❶ There is no definition of rcvd_evt for this action because there are no event parameters.

The C output is as expected. The action is turned into a function, and the C code has been passed through.

Summary

The Air Traffic Control model from Chapter 2 has been translated here by applying the principles discussed in Chapter 3. The model was encoded in a text file by using pycca statements intermixed with C code for the state activities and following C language rules for naming. This file was then fed through the pycca processor, which generated additional C code from the pycca statements, passing along the intermixed C code in a form and order acceptable to the compiler. To complete the translation, the generated pair of C header and source code files were then processed by a C compiler. Linking the object file for the domain with the runtime code yields a complete executable program.

All three facets of the model were specified in the pycca script language to create a complete model source file. First, the class model was specified. This consisted of a set of data type definitions split into those required for external interaction and those private to the domain. These were followed by a set of class statements. Each class statement defined the modeled class name, its attributes, its relationships, and an optional state model. Some design decisions were made at this point, based on static vs. dynamic populations and required paths for relationship navigation. In the process, some of the identifier and referential attributes from the class model were not needed and so eliminated. Nonetheless, their fundamental logical intent was still present. For example, a referential attribute may have been replaced by a pointer.

For each class with a state model, a machine statement was embedded within the class statement to specify the states, transitions, events, and activities. Each activity is initially filled with a comment containing the action language copied from the corresponding state.

The last facet of the model, the actions, was then completed by inserting C code within each state. In many cases, the C code consists of pycca-provided C preprocessor macros that provide the implementation of common model actions such as signal generation, instance selection, and relationship navigation. Additionally, user-written C code is used for flow of control, computing expressions, and other algorithmic processing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset