IBM
Contents Index Previous Next



Reference Section


Representation of Signals and Processes

In this first section, the representation of signals and processes is presented. The symbol table, which is a representation of the static structure of the system, will also be discussed. The information given here will be used in the next part of this section where the environment functions, which should be provided by the user, are described.

Types Representing Signals

A signal is represented by a C struct containing general information about the signal followed by the parameters carried by the signal.

Figure 500 : Data structure representing a signal

A general typedef xSignalRec for a signal without parameters and for a pointer to such a signal, xSignalNode, are given below. These types may be found in the file scttypes.h. These types may be used for type casting of any signal to access the general components.

typedef struct xSignalRec *xSignalNode;
typedef struct xSignalRec {
  xSignalNode Pre;
  xSignalNode Suc;
  SDL_PId     Receiver;
  SDL_PId     Sender;
  xIdNode     NameNode;
  int         Prio;
} xSignalRec;

A xSignalRec contains the following components:

In the generated code there will be types to represent the parameters of the signals according to the following example:

Example 428 : Generated C Code for Signal Definition

Assume the following signal definitions in SDL:

SIGNAL
 S1(Integer),
 S2,
 S3(Integer, Boolean, OwnType);

then the C code below will be generated:

typedef struct {
  SIGNAL_VARS
  SDL_Integer Param1;
} yPDef_z0f_S1;
typedef yPDef_z0f_S1 *yPDP_z0f_S1;

typedef struct {
  SIGNAL_VARS
  SDL_Integer Param1;
  SDL_Boolean Param2;
  z09_OwnType Param3;
} yPDef_z0h_S3;
typedef yPDef_z0h_S3 *yPDP_z0h_S3;

where SIGNAL_VARS is a macro defined in scttypes.h that is expanded to the common components in a signal struct.

For each signal with parameters there are two generated types, a struct type and a pointer type. The struct type contains one component for each parameter in the signal definition and the components will be named Param1, Param2 and so on. The components will be placed in the same order in the struct as the parameters are placed in the signal definition.

Note:

There are no generated types for a signal without parameters.

Types Representing Processes

A PId value is a struct consisting of two components, a global node number, which is an integer (see also Function xGlobalNodeNumber and The Basic Idea) and a local PId value, which is a pointer.

typedef xLocalPIdRec *xLocalPIdNode;

typedef struct {
  int GlobalNodeNr;
  xLocalPIdNode LocalPId;
} SDL_PId;

The global node number identifies the SDL system that the process instance belongs to, while the local PId value identifies the process instance within the system. The local PId pointer value should not be referenced outside the SDL system where it is defined.

By introducing a global node number in the PId values, these values are possible to interpret throughout an application consisting of several SDL systems. You can also define your own PId values in non-SDL defined parts of the application and still use communication with signals.

The variable SDL_NULL, which represents a null value for PIds and which is defined in the runtime library and available through the file scttypes.h, contains zero in both the global node number and the local PId component. Note that the global node number should be greater than zero in all PId values except SDL_NULL.

The Symbol Table

The symbol table is a tree built up during the initialization phase in the execution of the generated program and contains information about the static structure of the SDL system. The symbol table contains, for example, nodes which represent signal types, blocks, channels, process types, and procedures. The C type that are used to represent for example signals in the symbol table is given below.

typedef struct xSignalIdStruct *xSignalIdNode;
typedef struct xSignalIdStruct {
 /* components */
} xSignalIdRec;

It is the nodes that represent the signal types, for signals sent to and from the environment of the SDL system, that are of major interest in connection with the environment functions. For each signal type there will be a symbol table node. That node may be referenced using the name ySigN_ followed by the signal name with prefix. Such references may be used in, for example, xOutEnv to find the signal type of the signal passed as parameter.

In some cases the symbol table nodes for channels from the environment to a block in the system are of interest to refer to. In a similar way as for signals such nodes may be referenced using the name yChaN_ followed by the channel name with prefix.

The Environment Functions

An SDL system communicates with its environment by sending signals to the environment and by receiving signals from the environment. As no information about the environment is given in the SDL system, the Cadvanced SDL to C Compiler cannot generate the actions that should be performed when, for instance, a signal is sent to the environment. Instead you have to provide a function that performs this mapping between a signal sent to the environment and the actions that then should be performed. Examples of such actions are writing a bit pattern on a port, sending information over a network to another computer and sending information to another OS process using some OS primitive.

You should provide the following functions to represent the environment of the SDL system:

There are two ways to get a skeleton for the env functions:

An advantage with the generated env functions is that the SDL to C Compiler knows about the signal interface to be implemented in the env functions, and can therefore insert code or macros for all signals in the interface. To calculate this information is not that easy, especially if partitioning (generating code for a part of a system) is used.

Note:

A make template file is generated every time you generate an environment file. This file contains make information for the environment file and possibly for data encoding and decoding files. If you need to change this skeleton file, then remember to copy it so it is not overwritten next time an environment file is generated. The file can be used as make template in the Organizer's generate options. Note that you may have to generate the file first, before you can select it in the Organizer.

The env functions are thoroughly discussed below, but first we will introduce the system interface header file which considerably simplifies writing the environment functions.

System Interface Header File

The system interface header file contains code for objects that are defined in the system diagram. Included are all type definitions and other external definitions that are needed in order to implement external C code. These object definitions simplify the implementation of the environment functions. Therefore the system interface header file is also known the environment header file. This file is generated if:

The default name of the generated interface header file is <system_file_name>.ifc.

The system interface header file, has the following structure:

Together with these definitions, macros that simplify the translation of SDL names to C names are also be generated.

Names of SDL Objects in C

Due to differences in naming rules in SDL and C, prefixing is used to make C identifiers unique (see section Names and Prefixes in Generated Code). These prefixes, however, may change when you update your SDL diagrams and cannot be predicted. Therefore you should not use the prefixed object names in the environment functions. Instead macros, generated in the system interface header file, assist you by mapping static names to the prefixed names. This means that you must regenerate the system interface header file each time you regenerate code for the system. The good part is that you do not have to make any changes in the environment functions, as the interface names are static.

Example 429 : Macro in the system interface header file

If an SDL signal called Sig1 is defined in the system, the following macro is created:

extern XCONST struct xSignalIdStruct ySigR_z5_Sig1;
#ifndef Sig1
#define Sig1 (&ySigR_z5_Sig1)
#endif

This macro allows you to refer to the xIdNode by using the static name Sig1 rather than the prefixed name, ySigR_z5_Sig1.

Macros generate static names for the following SDL types:

Note:

You must always generate the system interface header file before editing or generating the environment functions.

Avoiding name clashes

In SDL it is allowed to give the same name to different objects. This is not allowed in C. For instance, in SDL you can give a signal and a Newtype the same name. In order to distinguish between the names in the system interface header file, you must define static unambiguous names. Using the Env. Header File Generation tab in the Targeting Expert, you can do this by using available general identifiers. The identifiers are:

Any combination of the identifiers can be used and they are all optional. However, in order to create a useful system interface header file, it is recommended that the %n identifier is always included. Leaving the field empty means that no objects of that type is included in the system interface header file at all.

Note:

If you select to include all objects and use the %n identifier only, the system interface header file will become compatible with earlier versions.

Example 430 : Name Mapping in an system interface header file

If the signal Signal1 is in the system System2 you should type the following in the Signal field in the TAEX.

sig_%n_%s

The result in the system interface header file will be:

sig_Signal1_System2

This approach helps you to avoid name clashes in the ifc file. Literals, for example, are often given the same name when defined in different types. The following example shows how this can be solved.

Example 431 : Avoiding Name Clashes

In an SDL system the following two newtypes are defined:

NewType s
literals red, green

NewType t
literals red, yellow

As the literal red appears in both newtypes, the C code cannot distinguish between them. However, by using the identifiers in the literals field,

lit_%n_%s

the literals are given the following names:

lit_red_s
lit_red_t

Thus we will avoid a possible name clash.

Structure of File for Environment Functions

The file containing the environment functions should have the following structure:

#include "scttypes.h"
#include "file with macros for external synonyms"
#include "systemfilename.ifc"

void xInitEnv XPP((void))
{
}

void xCloseEnv XPP((void))
{
}

#ifndef XNOPROTO
void xOutEnv (xSignalNode *S)
#else
void xOutEnv (S)
  xSignalNode *S;
#endif
{
}

#ifndef XNOPROTO
void xInEnv (SDL_Time Time_for_next_event)
#else
void xInEnv (Time_for_next_event)
  SDL_Time Time_for_next_event;
#endif
{
}

int xGlobalNodeNumber XPP((void))
{
}

The last function, xGlobalNodeNumber, will be discussed later, see Function xGlobalNodeNumber. The usage of the macros XPP and XNOPROTO makes the code possible to compile both with compilers that can handle prototypes and with compilers that cannot. If you do not need this portability, you can reduce the complexity of the function headings somewhat. In the minor examples in the remaining part of this section, only versions with prototypes are shown.

Functions xInitEnv and xCloseEnv

There are two functions among the environment functions that handle initialization and termination of the environment. These functions, as well as the other environment functions, should be provided by the user.

void xInitEnv ( void );

void xCloseEnv ( void );

In the implementation of these functions you can place the appropriate code needed to initialize and terminate the software and the hardware. The function xInitEnv will be called during the start up of the program as first action, while the xCloseEnv will be called in the function SDL_Halt. Calling SDL_Halt is the appropriate way to terminate the program. The easiest way to call SDL_Halt is to include the call in a #CODE directive in a TASK. SDL_Halt is part of the runtime library and has the following definition:

void SDL_Halt ( void );

Note:

xInitEnv will be called before the SDL system is initialized, which means that no references to the SDL system are allowed in this function. To, for example, send signals into the system during the initialization phase, the #MAIN directive should be used (see Initialization - Directive #MAIN). This directive code can be used after the initialization of the SDL system, but before any transitions are executed.

If you use the generated environment file, you could also define the symbols XENV_INIT and XENV_CLOSE to be the bodies of xInitEnv and xCloseEnv.

Function xOutEnv

Each time a signal is sent from the SDL system to the environment of the system, the function xOutEnv will be called.

void xOutEnv ( xSignalNode *S );

The xOutEnv function will have the current signal as parameter, so you have all the information contained in the signal at your disposal when you implement the actions that should be performed. The signal contains the signal type, the sending and receiving process instance and the parameters of the signal. For more information about the types used to represent signals and processes, see section Types Representing Signals and Types Representing Processes.

Note that the parameter of xOutEnv is an address to xSignalNode, that is, an address to a pointer to a struct representing the signal. The reason for this is that the signal that is given as parameter to xOutEnv should be returned to the pool of available memory before return is made from the xOutEnv function. This is made by calling the function xReleaseSignal, which takes an address to an xSignalNode as parameter, returns the signal to the pool of available memory, and assigns 0 to the xSignalNode parameter. Thus, there should be a call

xReleaseSignal(S);

before returning from xOutEnv. The xReleaseSignal function is defined as follows:

void xReleaseSignal ( xSignalNode *S );

In the generated environment skeleton file, the macro RELEASE_SIGNAL releases the signal as described above and returns from xOutEnv.

In the function xOutEnv you may use the information in the signal that is passed as parameters to the function. First it is usually suitable to determine the signal type of the signal. This is best performed by if statements containing expressions of the following form, assuming the use of the system interface header file and that the signal has the name Sig1 in SDL:

(*S)->NameNode == Sig1

The above expression is captured in the macro IF_OUT_SIGNAL in the generated environment skeleton file.

Suitable expressions to reach the Receiver, the Sender, and the signal parameters are:

(*S)->Receiver
(*S)->Sender
((yPDP_Sig1)(*S)) -> Param1
((yPDP_Sig1)(*S)) -> Param2

(and so on)

Sender will always refer to the sending process instance, while Receiver is either a reference to a process in the environment or the value xEnv. xEnv is a PId value that refers to an environment process instance, which is used to represent the general concept of environment, without specifying an explicit process instance in the environment.

Note:

It is not possible to calculate the PId value for a process in the environment, the value has to be taken from an incoming signal (sender or signal parameter). This is the normal procedure in SDL to establish direct communication between two processes in the same SDL system.

Receiver will refer to the process xEnv if the PId expression in an output TO refers to xEnv, or if the signal was sent in an output without a TO clause and the environment was selected as receiver in the scan for receivers.

Remote procedure calls to or from the environment should in the environment functions be treated a two signals, a pCALL_procedurename and a pREPLY_procedurename signal.

Recommended Structure of the xOutEnv Function

You can, of course, write the xOutEnv function as you wish - the structure discussed below may be seen as an example - but also as a guideline of how to design xOutEnv functions.

Example 432 : Structure of xOutEnv Function

void xOutEnv ( xSignalNode *S )
{
 if ( (*S)->NameNode == Sig1 ) {
  /* perform appropriate actions */
  xReleaseSignal(S);
  return;
 }
 if ( (*S)->NameNode == Sig2 ){
  /* perform appropriate actions */
  xReleaseSignal(S);
  return;
 }
 /* and so on */
}

Function xInEnv

To make it possible to receive signals from the environment and to send them into the SDL system, the user provided function xInEnv is repeatedly called during the execution of the system (see section Program Structure). During such a call you should scan the environment to see if anything has occurred which should trigger a signal to be sent to a process within the SDL system.

void xInEnv (SDL_Time Time_for_next_event);

To implement the sending of a signal into the SDL system, two functions are available: xGetSignal, which is used to obtain a data area suitable to represent the signal, and SDL_Output, which sends the signal to the specified receiver according to the semantic rules of SDL. These functions will be described later in this subsection.

The parameter Time_for_next_event will contain the time for the next event scheduled in the SDL system. The parameter will either be 0, which indicates that there is a transition (or a timer output) that can be executed immediately, or be greater than Now, indicating that the next event is a timer output scheduled at the specified time, or be a very large number, indicating that there is no scheduled action in the system, that is, the system is waiting for an external stimuli. This large value can be found in the variable xSysD.xMaxTime.

You should scan the environment, perform the current outputs, and return as fast as possible if Time has past Time_for_next_event.

If Time has not past Time_for_next_event, you have a choice to either return from the xInEnv function at once and have repeated calls of xInEnv, or stay in the xInEnv until something triggers a signal output (a signal sent to the SDL system) or until Time has past Time_for_next_event.

Note:

We recommend always to return from the xInEnv function as fast as possible to ensure that it will work appropriately together with the monitor (during debugging). Otherwise, the keyboard polling, that is, typing <RETURN> in order to interrupt the execution, will not work.

The function xGetSignal, which is one of the service functions suitable to use when a signal should be sent, returns a pointer to a data area that represents a signal instance of the type specified by the first parameter.

xSignalNode xGetSignal
 ( xSignalIdNode SType,
   SDL_PId Receiver,
   SDL_PId Sender );

The components Receiver and Sender in the signal instance will also be given the values of the corresponding parameters.

The function SDL_Output takes a reference to a signal instance and outputs the signal according to the rules of SDL.

void SDL_Output
 ( xSignalNode S,
   xIdNode     ViaList[] );

We now have enough information to be able to write the code to send a signal. Suppose we want to send a signal S1, without parameters, from xEnv into the system without an explicit receiver (without TO). The code will then be:

Example 433 : C Code to Send a Signal to the Environment

SDL_Output( xGetSignal(S1, xNotDefPId, xEnv),
  (xIdNode *)0 );

If S2, with two integer parameters, should be sent from xEnv to the process instance referenced by the variable P, the code will be:

xSignalNode OutputSignal; /* local variable */
...
OutputSignal = xGetSignal(S2, P, xEnv);
((yPDP_S2)OutputSignal)->Param1 = 1;
((yPDP_S2)OutputSignal)->Param2 = 2;
SDL_Output( OutputSignal, (xIdNode *)0 );

For the details of how to reference the parameters of a signal see the subsection Types Representing Signals.

To introduce a via list in the output requires a variable, which should be an array of xIdNode, that contains references to the symbol table nodes representing the current channels (or signal routes) in the via list. In more detail, we need a variable

ViaList xIdNode[N];

where N should be replaced by the length of the longest via list we want to represent plus one. The components in the variable should then be given appropriate values, such that component 0 is a reference to the first channel (its symbol table node) in the via list, component 1 is a reference to the second channel, and so on. The last component with a reference to a channel must be followed by a component containing a null pointer (the value (xIdNode)0). Components after the null pointer will not be referenced. Below is an example of how to create a via list of two channels, C1 and C2.

Example 434 : Via List of two Channels.

ViaList xIdNode[4]; 
/* longest via has length 3 */
...
/* this via has length 2 */
ViaList[0] = (xIdNode)xIN_C1; 
ViaList[1] = (xIdNode)xIN_C2;
ViaList[2] = (xIdNode)0;

The variable ViaList may then be used as a ViaList parameter in a subsequent call to SDL_Output.

Guidelines for the xInEnv Function

It is more difficult to give a structure for the xInEnv function, than for the xOutEnv function discussed in the previous subsection. A xInEnv function will in principle consist of a number of if statements where the environment is investigated. When some information is found that means that a signal is to be sent to the SDL system, then the appropriate code to send a signal (see above) should be executed.

The structure given in the example below may serve as an idea of how to design the xInEnv function.

Example 435 : Structure of xInEnv Function

void xInEnv (SDL_Time Time_for_next_event)
{
  xSignalNode S;

  if ( Sig1 should be sent to the system ) {
    SDL_Output (xGetSignal(Sig1, xNotDefPId,
      xEnv), (xIdNode *)0);
  }
  if ( Sig2 should be sent to the system ) {
    S = xGetSignal(Sig1, xNotDefPId, xEnv);
    ((xPDP_Sig2)S)->Param1 = 3;
    ((xPDP_Sig2)S)->Param2 = SDL_True;
    SDL_Output (S, (xIdNode *)0);
  }
  /* and so on */
}

This basic structure can be modified to suit your own needs. The if statements could, for example, be substituted for while statements. The signal types might be sorted in some "priority order" and a return can be introduced last in the if statements. This means that only one signal is sent during a xInEnv call, which reduces the latency.

In the generated environments skeleton file, there are three macros defined to help with allocating and sending a signal; IN_LOCAL_VARIABLES that declares a signal variable SignalIn, IN_SIGNAL1 that calls xGetSignal and assigns it to SignalIn, and IN_SIGNAL2 that calls SDL_Output for SignalIn.

The macros XENV_IN_START and XENV_IN_END can also be defined to be the top and bottom part of the xEnvIn function body.

Alternative to OutEnv - Directive #EXTSIG

To speed up an application it is sometimes possible to use the directive #EXTSIG instead of the xOutEnv function. The decision to use #EXTSIG or xOutEnv may be taken individually for each signal type.

The usage of the #EXTSIG directive is described in the section Modifying Outputs - Directive #EXTSIG, #ALT, #TRANSFER. This information is not repeated here.

By using the #EXTSIG directive the following overhead can be avoided:

Including the Environment Functions in the SDL System Design

Apart from having the environment functions on a file of their own, it is of course possible to include these function directly into the system diagram in a #CODE directive.

Example 436 : Including Environment Functions in SDL System

/*#CODE
#BODY
... code for the environment functions ...
*/

In this case you cannot use the system interface header file, but instead you have all the necessary declarations already at your disposal, as the functions will be part of the SDL system. The only problem you will encounter is the prefixing of SDL names when they are translated to C. The #SDL directive should be used to handle this problem (or the #NAME directive), see sections Accessing SDL Names in C Code - Directive #SDL and Specifying Names in Generated Code - Directive #NAME. The following table shows how to obtain C names for some SDL objects of interest:

#(Synonym name)
#(Newtype or syntype name)
ySigN_#(Signal name)
yPDP_#(Signal name)
yChaN_#(Channel name)

SDL Data Encoding and Decoding, ASCII coder

Communication between nodes often requires data encoding and decoding between node internal representations and a common format in a protocol buffer. The sending node writes information in the common format and the receiving node reads information from the common format. Data encoding is the transformation from a node internal representation into a common format and data decoding is the transformation from a common format into a node internal representation.

Supported common formats are:

BER (Basic Encoding Rules) is specified in ITU standard X.690 and PER (Packed Encoding Rules) is specified in ITU standard X.691. BER and PER are based on ASN.1 specifications of data types and can only be used for types specified in ASN.1 specifications. See ASN.1 Encoding and De-coding in the SDL Suite and Tutorial: Using ASN.1 Data Types.

ASCII is a format where the data is represented as ASCII characters. It is easy to read and analyze. The ASCII format is specified in appendix A.

Example 437 ASCII common format

newtype Person struct
    nm Charstring;
    nr Integer;
    fm Boolean;
endnewtype Person;

dcl boss Person := (.'Joe',5,false.);

ASCII format:{`Joe',5,F}

The ASCII coder uses the same buffer management and error management as the BER and PER coders, see ASN.1 Encoding and De-coding in the SDL Suite.

Type description nodes for SDL types

SDL data encoders and data decoders need information about types and signals, information that is stored in type descriptions nodes. Type description nodes for an SDL system are generated if the Generate SDL coder option is selected in the organizer, see The Organizer, or in the targeting expert, see The Targeting Expert. Declarations to access the type nodes are in the system interface header files and in a file with the name <system_file_name>_cod.h. Type nodes can be found in any generated c-file from a system or a package and also in the <system_file_name>_cod.c file.

A type description node for SDL is implemented as a static variable with the type information. The variable can be accessed by using the name ySDL_<type_name> or ySDL_<signal_name>, where <type_name> and <signal_name> are the names used in the interface header file. See Names of SDL Objects in C for more information.

Encoding signal and signal parameters into a buffer

You can use an encode function to encode signal parameters into a buffer. There is one encoding function for each common format. For ASCII, it is accessed by using the macro ASCII_ENCODE. An encoding function has a buffer reference as the first parameter, a pointer to a type node as the second parameter and a pointer to the variable to encode as the third. The encoding function returns an integer value, which is 0 if the encoding was successful and error code if it was not. More details about encoding functions, the buffer reference, type nodes and error codes can be found in ASN.1 Encoding and De-coding in the SDL Suite.

Function declarations are in the file "ascii/ascii.h" ("ascii\ascii.h" on Windows platforms) in the coder directory.

Example 438 ASCII encoding of signal parameters

In SDL:
SIGNAL Sig1(Integer,Person,Boolean); 

In xOutEnv:
BufInitWriteMode(buf);
result = ASCII_ENCODE(buf,
              (tSDLTypeInfo *)&ySDL_Integer,    
(void *)&((yPDP_Sig1)(*S))->Param1));
if (result!=0) /* handle error */;
result = ASCII_ENCODE(buf,
              (tSDLTypeInfo *)&ySDL_Person    
(void *)&((yPDP_Sig1)(*S))->Param2));
if (result!=0) /* handle error */;
result = ASCII_ENCODE(buf,
              (tSDLTypeInfo *)&ySDL_Boolean   
(void *)&((yPDP_Sig1)(*S))->Param3));
if (result!=0) /* handle error */;
BufCloseWriteMode(buf);	 

Example 439 ASCII encoding of whole signal (all signal parameters)

In SDL:
SIGNAL Sig1(Integer,Person,Boolean); 

In xOutEnv:
BufInitWriteMode(buf);
result = ASCII_ENCODE(buf, 
             (tSDLTypeInfo *)&ySDL_Sig1,    
(void *)(*S));
if (result!=0) /* handle error */;
BufCloseWriteMode(buf);	 

Note:

The names of the type nodes in the examples, the second parameter in ASCII_ENCODE, depend on the settings for generating system interface header files.

Decoding into signal parameters from a buffer

You can use a decode function to decode from a buffer into a signal parameter. There is one decoding function for each common format. For ASCII, it is accessed by using the macro ASCII_DECODE. A decode function has a buffer reference as the first parameter, a pointer to a type node as the second parameter and a pointer to the variable to decode as the third. The decoding function returns an integer value, which is 0 if the decoding was successful and an error code if it was not. More details about decoding functions, the buffer reference, type nodes and error codes can be found in ASN.1 Encoding and De-coding in the SDL Suite.

Function declarations are in the file "ascii/ascii.h" ("ascii\ascii.h" on Windows platforms) in the coder directory.

Example 440 ASCII decoding into signal parameters

In SDL:
SIGNAL Sig1(Integer,Person,Boolean); 

In xInEnv:
BufInitReadMode(buf);
result = ASCII_DECODE(buf,
              (tSDLTypeInfo *)&ySDL_Integer,    
(void *)&((yPDP_Sig1)(S))->Param1));
if (result!=0) /* handle error */;
result = ASCII_DECODE(buf,
              (tSDLTypeInfo *)&ySDL_Person    
(void *)&((yPDP_Sig1)(S))->Param2));
if (result!=0) /* handle error */;
result = ASCII_DECODE(buf,
              (tSDLTypeInfo *)&ySDL_Boolean   
(void *)&((yPDP_Sig1)(S))->Param3));
if (result!=0) /* handle error */;
BufCloseReadMode(buf);

Example 441 ASCII decoding of whole signal (all signal parameters)

In SDL:
SIGNAL Sig1(Integer,Person,Boolean); 

In xInEnv:
BufInitReadMode(buf);
result = ASCII_DECODE(buf,
              (tSDLTypeInfo *)&ySDL_Sig1,    
(void *)S);
if (result!=0) /* handle error */;
BufCloseReadMode(buf);

Note:

The names of the type nodes in the examples, the second parameter in ASCII_DECODE, depend on the settings for generating system interface header files.

Encoding and decoding signal identifier for ASCII encoding

When sending signals between nodes it is often important to put a signal identifier first in the buffer. The signal identifier must be a unique identifier of the signal in the distributed system. Decoding is then a two step process, first decode signal identifier and find signal information and second decode signal parameters.

You can use any representation of signal identifiers in the environment functions.

For SDL types there is a special signal id type node that supports character string signal ids. The type node can be used for ASCII encoding.

Example 442 Using signal identifier

In SDL:
SIGNAL Sig1(Integer); 

In xOutEnv:
void xOutEnv ( xSignalNode *S )
{
 char * signalId;
 
 BufInitWriteMode(buf);
 if ( (*S)->NameNode == Sig1 ) {
   /* encode signal id into buffer */
   signalId="Sig1";
   result = ASCII_ENCODE(buf,
                        (tSDLInfo *)&ySDL_SignalId,
                        (void *)signalId);
   if (result!=0) /* handle error */;
   /* encode signal parameter */
   result =  ASCII_ENCODE(buf,
                     (tSDLTypeInfo *)&ySDL_Sig1,    
(void *)(*S));
   if (result!=0) /* handle error */;
   
   /* send buffer using protocol*/
   
   /* release memory */
   
   xReleaseSignal(S);
   return;
 }
 BufCloseWriteMode(buf);
}

In xInEnv:
void xInEnv (SDL_Time Time_for_next_event) {
   char SId[100];
   
   BufInitReadMode(buf);
   /* decode signal id */
   result = ASCII_DECODE(buf,
                    (tSDLTypeInfo *)&ySDL_SignalId,
                     SId) );
   if (result!=0) /* handle error */;
   /* signal Sig1 in buffer */
   if ( strcmp(SId,"Sig1") ) {
      S=xGetSignal(Sig1,xNotDefPId, xEnv);
      result = ASCII_DECODE(buf,
                    (tSDLTypeInfo *)&ySDL_Sig1,
(void *)S);
      if (result!=0) /* handle error */;
      SDL_Output(S, (xIdNode *)0 ); 
   }
   BufCloseReadMode(buf);   
}

                     

Function xGlobalNodeNumber

You should also provide a function, xGlobalNodeNumber, with no parameters, which returns an integer that is unique for each executing system.

int xGlobalNodeNumber ( void )

The returned integer should be greater than zero and should be unique among the communicating SDL systems that constitutes an application. If the application consists of only one application then this number is of minor interest (it still has to be set). The global node number is used in PId values to identify the node (OS process / processor) that the process instance belongs to. PId values are thereby universally accessible and you may, for example, in a simple way make "Output To Sender" work between processes in different SDL systems (OS processes / processors).

If you use the generated environment file you could also define XENV_NODENUMBER to be the wanted node number.

When an application consisting of several communicating SDL systems is designed, you have to map the global node number to the current OS process or processor, to be able to transmit signals addressed to non-local PIds to the correct OS process or processor. This will be part of the xOutEnv function.

Program Structure

The generated code will contain two important types of functions, the initialization functions and the PAD functions. The PAD functions implement the actions performed by processes during transitions. There will be one initialization function in each generated.c file. In the file that represents the system this function will have the name yInit. Each process in the system will be represented by a PAD function, which is called when a process instance of the current instance set is to execute a transition.

The example below shows the structure of the main, MainInit, and MainLoop functions.

Example 443 : Start up structure

void main ( void )
{
 xMainInit();
 xMainLoop();
}

void xMainInit ( void )
{
  xInitEnv();
  Init of internal data structures in the 
  runtime library;
  yInit();
}

void xMainLoop ( void )
{
  while (1) {
    xInEnv(...);
    if ( Timer output is possible )
      SDL_OutputTimerSignal();
    else if ( Process transition is possible )
      Call appropriate PAD function;
  }
}

The function xMainLoop contains an endless loop. The appropriate way to stop the execution of the program is to call the runtime library function SDL_Halt. The call of this C function should normally be included in an appropriate task, using the directive #CODE. SDL_Halt which has the following structure:

void SDL_Halt ( void )
{
  xCloseEnv();
  exit(0);
}

To complete this overview, which emphasizes the usage of the environment functions, we have to deal with the xOutEnv function. Within PAD functions, the runtime library function SDL_Output is called to implement outputs of signals. When SDL_Output identifies the receiver of a signal to be a process instance that is not part of the current SDL system, SDL_Output will call the xOutEnv function.

Dynamic Errors

In the library for applications SDL runtime errors will not be reported. The application will just perform some appropriate actions and continue to execute. These actions are in almost all cases the same as the actions at dynamic errors described in the Dynamic Errors.


http://www.ibm.com/rational
Contents Index Previous Next