This chapter describes how to integrate code generated by the C Code Generator with operating systems or real-time executables.
The chapter is focused on how to make a hard integration (from here on referred to as Tight Integration) where SDL process instances or instance sets are mapped to an RTOS task, and signal sending in SDL is handled by the message passing mechanism in the OS. In an introduction the different integration models (Light Integration and Tight Integration) are explained.
In separate annexes, one for each supported RTOS, all the OS specific parts are documented.
The code that is generated by the SDT Cadvanced Code Generator is designed to run on different platforms. This is done by letting all platform dependent concepts be represented by C macros that can be expanded appropriately for each environment. There are also types used in the generated code that have to be defined. Integration, as referred to in this chapter, is the process of adapting the generated code to a certain platform. This chapter describes the different models for doing an integration that are supported in Telelogic Tau.
Basically there are two different integration models in SDT. In the following they are referred to as Light Integration and Tight Integration. The Light Integration Model uses SDT's standard kernel/scheduler and the Tight Integration Model calls primitives from an external RTOS. Both models use the same generated code from the Cadvanced Code Generator.
The SDT standard kernel is provided with the Cadvanced Code Generator. The execution of the SDL system is based on a scheduler calling a certain function representing the scheduled process each time it shall execute a transition. The function is expected to return control to the scheduler after a transition. Signals sent between internal processes are directly put into the input queue of the receiving process instance by the SDT kernel. External signals going in and out of the SDL system are handled by special environment functions that are platform dependent. An application using this integration model can run on an naked machine with no OS support but can also run under an external RTOS. Signal sending in the case of a Light Integration running under an external OS is illustrated in Figure 519.
Figure 519
: Signal sending in the Light Integration Model.
One internal and one outgoing external signal is sent. The grey areas represent different OS tasks.
|
Properties of a Light Integration:
In a Tight Integration the application is using primitives from an underlying RTOS when creating processes, sending signals, etc. Scheduling is thus handled by the RTOS, which normally means it is preemptive, time-sliced and priority based. The principles of signal sending in the Tight Integration Model are illustrated in Figure 520.
Figure 520
: Signal sending in the Tight Integration Model.
One internal and one outgoing external signal is sent. The grey areas represent different OS tasks.
|
Properties of a Tight Integration:
This section describes the parts of the integration that are common to the different models, but also some important differences.
Note: Many of the data structures and macros described in this section are described in more detail in The Master Library. That chapter is, however, focused on a Light Integration. Some things, especially the listings of data structures, are not correct in every detail for Tight Integrations but should still be very useful. |
A source file generated by the SDT C Code Generator is independent from the choice of integration model and operating system. Instead of system calls, it uses macros that have to be defined elsewhere when the system is built. Each SDL concept is represented by one or more C macros. These macros will have different definitions for different integration models and operating systems. Telelogic Tau provides a number of integration packages for this purpose. In a Light Integration, many macros are expanded into functions of the standard SDT kernel. A Tight Integration has lower level macros that are defined in separate files for each operating system, and finally expanded into OS primitives or certain OS dependent constructions.
Below is an example of generated code for signal sending. Code in capital letters are SDT macros. The bracketed numbers indicate corresponding lines of code. For a description of the different macros, see The Master Library.
An integration uses one or more of four files that can be generated by the Code Generator. All integrations require the C source file <systemname>.c
whereas the interface file <systemname>.ifc
is optional. For a Tight Integration the signal number file <systemname>.hs
may be used, and for a Light Integration the file sctenv.c
, representing the environment, can be used.
The source file uses the highest level set of macros, that are expanded in the respective package files of the different integration models and also, for the Tight Integration, different operating systems.
The files containing the necessary macro expansions and support functions are organized as shown in Figure 521. For each operating system there is one package for the Light Integration, and one for the Tight Integration. Although the files in different packages may have the same name they do not necessarily contain the same code. The principles for Tight Integration packages are described more thoroughly in Tight Integration. Details about each operating system can be found in the annexes.
Figure 521 : File structure for the RTOS integrations
|
There is also an INCLUDE
directory containing source files common to all supported operating systems. These files are described in File Structure. Below are some additional comments on these files:
scthooks.h
:
sctos.c
:
sctpred.h
and sctpred.c
:
sctsdl.c
:sct<RTOS>.h
.
scttypes.h
: IdNodes
, etc. It also contains the macro definitions found in generated code. Note that this file is non-OS-specific. This means that if a call to an OS-specific primitive is needed, then a second level of macro is defined, according to the following model.ALLOC_SIGNAL_PAR(ok, ySigN_z3_ok, TO_PROCESS(Env, &yEnvR_env), yPDef_z3_ok)In
scttypes.h
:#define ALLOC_SIGNAL_PAR(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE) \ RTOSALLOC_SIGNAL_PAR(SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_TYPE)In
sct<RTOS>.h
:#define RTOSALLOC_SIGNAL_PAR(SIG_NAME,SIG_IDNODE,\ RECEIVER, SIG_PAR_TYPE) \ yOutputSignalPtr = \ xAlloc(sizeof(xSignalHeaderRec)+ \ sizeof(SIG_PAR_TYPE)); \ yOutputSignalPtr->SignalCode = SIG_NAME; \ yOutputSignalPtr->Sender = SDL_SELF;
The Examples
directory contains a simple SDL system that also uses an external process (a separate OS task). For each supported operating system there is an implementation of this, demonstrating how to hook into the integration package. Further description of the example can be found in A Simple Example.
Names of variables, datatypes and support functions in generated code and package files often start with one of the letters x, y and z.
The general rules (there are some exceptions) are:
extern XCONST struct xVarIdStruct, xInputSignal, xFindReceiver
extern XCONST struct xVarIdStruct yVarR_z012_okmess, ySigR_z3_ok, yPAD_z01_pr1
#define z010_idle 1, z012_okmess
All signals, blocks, processes, channels, etc. in an SDL system have a corresponding representation in the symbol table described in The Master Library. This symbol table consists of nodes (IdNodes
) each representing one entity of the system. Many IdNodes
are pointers to structs. See the following example:
extern XCONST struct xPrsIdStruct yPrsR_z02_dynpr1; #define yPrsN_z02_dynpr1 (&yPrsR_z02_dynpr1)
The N_
and the R_
just before z02_dynpr1
indicate if it is a node (N_
) or a record (R_
).
The xAlloc
function is always used when allocating dynamic memory. The function is placed in the sctos.c
file, but in the Tight Integrations the body of the function is found in the sct<RTOS>.h
file.
The yInit
function is called during startup of the SDL system. It is responsible for creating all static processes and for initializing SDL synonyms.
An SDL process consists of three parts in a code representation. One part defines the dynamic behavior, one contains instance specific data and one contains data common for all instances of a process.
Variables and structures that are common to all instances of a process are stored in a record of the type xPrsIdStruct
, defined in scttypes.h
. This record, as well as the instance data, is represented by a node in the symbol table.
Variables and structures of the process instance are declared via the macro PROCESS_VARS
. This macro is defined in different ways in the Light and the two models of Tight Integration. It contains state information, local variables, pointers to parent and offspring, etc. One important entry is the RestartAddress
, pointing out which transition to execute when the PAD function is called or scheduled.
The dynamic behavior of an SDL process is implemented in a PAD function (Process Activity Definition). The PAD function is used somewhat differently in the different integration models:
Below is the code for ending a transition, before and after macro expansion for a Light Integration.
Basically, every process has at least one signal queue.
All signals that are sent to a process arrive in the input queue. The save queue is used to keep signals that cannot be handled in the current state but should be saved for future use. This is tightly connected to the SDL Save concept, but is also used in the implementation of timers. For a Light Integration there are no save queues. Instead, all signals that should be saved will remain in the input queue until they can be received.
The use of process priorities requires some caution. Priorities can be set with the #PRIO
directive in SDT, but there is no mapping of priorities for different platforms. The generated code will use exactly the values specified in the SDL system. This will not be a problem in a Light Integration, but for Tight Integrations the result may not be the expected.
Priorities in VxWorks can be set in the range from 0 to 255, where 0 represents the highest priority. This maps well to SDT, where 0 is also the highest priority. In pSOS, however, 255 is the highest priority and 0 is the lowest.
An SDT system with two processes, Process1 and Process2, is designed. Process1 has its priority assigned with #PRIO 100
and Process2 with #PRIO 50
. C code is generated and integrated with VxWorks and pSOS. In both operating systems the priorities will then be set to 100 for Process1 and 50 for Process2, which means Process2 will have the higher priority in VxWorks, while Process1 has the highest priority in pSOS.
Regardless of the integration model there are a number of things that have to be done when an SDL process instance is created. The structs that represent the instance have to be created. It needs a representation in the symbol tree and a signal queue, except in the Instance Set Model of Tight Integration where the signal queue belongs to the instance set. A start-up signal is also always allocated and sent to the process.
In generated code a signal sending is handled by two macros: ALLOC_SIGNAL
(or ALLOC_SIGNAL_PAR
for a signal with parameters) and SDL_2OUTPUT_xxxx
(there are different macros depending on how the SDL output was defined, e.g. with or without an explicit TO).
In this example the signal is called go and has no parameters. The SDL_2OUTPUT_COMPUTED_TO
macro indicates that it was sent without an explicit TO.
An SDL procedure is represented by a function similar to a PAD function. Before a procedure is called there are two support functions that need to be called: xGetPrd
and xAddPrdCall
.
The xGetPrd
function allocates an xPrdStruct
for the called procedure and returns an xPrdNode
pointing to the struct.
The xAddPrdCall
function adds the new procedure call in the calling process' ActivePrd
list (an element in the xPrsStruct
).
The procedure is called with a pointer to the instance data of the calling SDL process. This is because the procedure must be able to use internal variables in the calling process.
Before a procedure returns to the caller it performs an xReleasePrd
call. This function removes the call from the ActivePrd
list.
SDL timers are represented by signals. All active timer signals are kept in a sorted list, either within the single task of a Light Integration or in a certain timer task in a Tight Integration. When a timer expires, the signal representing it is sent to the SDL process that set it.
A Light Integration is a stand-alone executable which can be generated with or without a simulator. An executable that should run under UNIX can use the precompiled kernels. Only the environment functions need to be written by the user.
The PAD function is called by the scheduler when its process is in turn to execute a transition. The scheduler calls the PAD function with a symbol table node of the type xPrsNode
, pointing to the instance specific data of the instance that is scheduled.
A Light Integration starts when the generated main function is called. The start-up phase works like this (pseudocode shown in italic):
void main( void ) { xMainInit(); Code from #MAIN xMainLoop(); } void xMainInit( void ) { xinitEnv(); Init of internal structures }
You must supply the xInitEnv()
function to initialize external code and hardware, etc. (this is of course application dependent). This function is placed in the same program module (environment module) as the xInEnv()
and xOutEnv()
functions. The xMainLoop()
function contains an eternal loop, which constitutes the scheduler itself. See below:
void xMainLoop (void) { while (1) { xInEnv(...) if (a timer has expired) send the corresponding timer signal else if (a process can execute a transition) { remove the signal from the input port set up Sender in the process to Sender of the signal call the PAD function for the process } } }
Signals going in and out of the SDL system are handled in the two user written functions xInEnv
and xOutEnv
. There is a template file for writing these two function in the standard SDT distribution. This file can be found at <Telelogic Tau installation directory>/sdt/
.
sdtdir/<your platform os version>sdtdir/INCLUDE/
sctenv.c
Since there are some fundamental differences between different RTOS we can only give a general idea of how to generate a Light Integration under an external RTOS here. Typical things that may be different in different RTOS:
The normal steps to create a Light Integration under an external RTOS can be summarized as follows:
<Telelogic Tau installation directory>/sdt/
sdtdir/<your host and os version>sdtdir/INCLUDE
.<application>.c
file with the SDT Code Generator.
Note: The code generator option Cadvanced must be used. |
sctenv.c
template file to handle your in and out environment signals. Include the generated <application>.ifc
file (the environment header file).
There are two models of Tight Integration. In the Standard Model one SDL process instance is mapped to one OS task. In the Instance Set Model an entire instance set (all instances of a process) is mapped to one OS task. Scheduling between OS tasks is managed by the RTOS scheduler; this means that preemption is normally used, though only on an instance set level in the Instance Set Model. SDL semantics are preserved in a Tight Integration, for example setting a timer implies an automatic reset first.
The start-up of a system, i.e. creation of static processes, initialization of Synonyms and creation of an environment task and a timer task, is handled by a generated initialization function called yInit
. Normally this function is called from another initialization function, where some additional initializations take place before the yInit
function is called.
Timers in the system are handled by one central timer task. This task receives messages2, each containing a request to set a timer, and will send messages back as the timers expire.
The files related to the tight integration concept are placed in the following directory in the SDT installation: <Telelogic Tau installation directory>/sdt/sdtdir/RTOS/<operating system>/
. The same files are used for both the Standard Model and the Instance Set Model.
TightIntegration/
Each RTOS directory contains the following files:
sct<RTOS>.h
:scttypes.h
in The Integration Packages). All macros are using OS-specific calls or types.
sct<RTOS>.c
:
sdt2<RTOS>.c
: .hs
. This file is automatically included in the application. .hs
file can also be generated by the C Code Generator by turning on the option Generate signal number file in the Make dialog. The .hs
file is included in the application if the compilation switch XINCLUDE_HS_FILE
is set.The SDL_PId
(SDL Process ID) type has different meanings in the Standard and the Instance Set Models. In the Standard Model it represents the message queue, while it represents the process instance in the Instance Set Model. This is because the entire instance set will have the same message queue in the last case.
#ifdef X_ONE_TASK_PER_INSTANCE_SET typedef xEPrsNode SDL_PId; #else typedef MSG_Q_ID SDL_PId; #endif
The signal header consists of a struct with information needed to handle the signal inside an SDL system. The signal header struct is defined in the RTOS-specific file sct<RTOS>.h
.
typedef struct xSignalHeaderStruct *xSignalHeader; typedef struct xSignalHeaderStruct { int SignalCode; xSignalHeader Pre, Suc; SDL_PId Sender; #ifdef X_ONE_TASK_PER_INSTANCE_SET SDL_PId Receiver; #endif #ifdef XMSC_TRACE int SignalId; int IsTimer; #endif } xSignalHeaderRec;
The signal header stores SignalCode
, in this case an integer, two pointers Pre
and Suc
used when saving the signal in the save queue, and Sender
, holding the SDL_PId
of the sending SDL process. In the Instance Set Model there is an extra parameter Receiver
, necessary to make a distinction between the SDL processes in an instance set task.
If the signal contains parameters they are allocated in the same function call. Example:
OutputSignalPtr = xAlloc (sizeof (xSignalHeaderRec) + sizeof(yPDef_z05_s2));
The second parameter to the xAlloc
function is a struct representing the signal parameters of the signal. In this case, with one integer, it is defined in the following way:
typedef struct { SIGNAL_VARS SDL_Integer Param1; } yPDef_z05_s2;
The macro SIGNAL_VARS
is in most RTOS empty.
Note: The SDL signal parameters are always named |
Assignment of the signal parameter is done in generated code and not in a macro. Example:
SIGNAL_ALLOC_ERROR yAssF_SDL_Integer(((yPDef_z05_s2*) OUTSIGNAL_DATA_PTR)->Param1 ,yVarP->z023_param1, XASS);
The macro OUTSIGNAL_DATA_PTR
is defined in VxWorks in the following way:
#define OUTSIGNAL_DATA_PTR \ ((xSignalHeader)yOutputSignalPtr+1)
In some RTOS integrations there is an extra element in the SignalHeader
defined as a void
pointer. This pointer is set to point to the parameter area. Example:
...... void * SigP; } xSignalHeaderRec;
The OUTSIGNAL_DATA_PTR
macro is then defined:
#define OUTSIGNAL_DATA_PTR (yOutputSignalPtr->SigP)
After expansion of the whole expression the code will be:
((yPDef_z05_s2 *) ((xSignalHeader) yOutputSignalPtr + 1))->Param1 = yVarP->z023_param1;
The support function xInputSignal
is used for receiving signals in both models of Tight Integration. The implementation and the parameters are different though.
A timer signal is defined similarly to an ordinary signal but will contain some additional elements representing time-out time, etc. The timer header struct looks like this:
typedef struct xTimerHeaderStruct *xTimerHeader; typedef struct xTimerHeaderStruct { int SignalCode; xTimerHeader Pre, Suc; SDL_PId Sender; #ifdef X_ONE_TASK_PER_INSTANCE_SET SDL_PId Receiver; #endif #ifdef XMSC_TRACE int SignalId; int IsTimer; #endif SDL_Time TimerTime; int TimerToSetOrReset; xbool (* yEq)(); xbool TestParams; xTimerHeader Param; } xTimerHeaderRec;
When the System time is required, for example when using NOW, the macro SDL_NOW
is used. The macro is in turn mapped to the function SDL_Clock()
(in sctos.c
). This function is implemented differently depending on the RTOS representation of time. In VxWorks it returns the result of calling the RTOS function tickGet
. SDL_Time
is normally implemented as int
or unsigned long int
.
The macro SDL_DURATION_LIT
specifies the mapping between the SDL time in seconds and the local RTOS representation of time. In VxWorks the system time is given in ticks and the translation is defined as follows:
#define SDL_DURATION_LIT(R,I,D) \ ((I)*1000 + (D)/1000000)
R
is the real type representation of the time in seconds. I
and D
are the integer and decimal parts of an integer type representation of the time. I
is in seconds and D
in nanoseconds. The code generator will generate all three numbers but either R
, or I
and D
will be used depending on the RTOS.
All timer activity in the SDL system is handled by a dedicated timer task. The timer task accepts requests in the form of messages (in VxWorks). It then keeps the requests for setting a timer sorted in a timer queue and uses some OS mechanism to wait for the first request to time out. The mechanism used can be either an OS timer, or a timeout in the waiting for new requests. When a request times out, the timer task sends a signal back to the task that first sent the request. The function calls and OS signaling involved in setting and waiting for an SDL timer can be viewed in Figure 522.
Figure 522
: Function calls and OS signaling when setting and waiting for a timer.
UML notation is being used, thus the full arrowheads represent function calls and the half arrowheads represent messages. Parameters have been left out, except for the name of the timer in the ResetTimer request. Note that a reset is performed first, as required in the SDL specification.
|
To be able to implement the full semantics of SDL timers a number of support functions have been implemented:
xSDLActive
Checks whether an SDL timer is active and returns true or false. The function passes the question on to the timer task in the form of a request.xSDLActiveInTimerTask
Called by the timer task upon request. Checks if an SDL timer is active and returns true or false.xSDLReset
Resets an SDL timer by sending a request to the timer task. While waiting for a reply all new signals to the calling task are saved in the save queue. In the case of an Instance Set Model Tight Integration this means that no instance of the process can execute a transition until a reply is received. If the reply states that the timer couldn't be found it might be in the save queue or the input queue of the task because it has recently expired. If so, it is simply removed. SDL semantics require that a reset is always performed implicitly prior to setting a timer.xSDLResetInTimerTask
Called by the timer task when a request has been made for resetting a timer. Checks the timer queue to see if the timer to reset is there. If the timer is found, it is removed and the data area it holds is freed. A message is sent back to the task that made the request, telling whether the timer was found or not.xSDLSet
Called by the timer task when a request has been made for setting a timer. This function sorts the request into the timer queue.There are two ways to address SDL processes from an external task. Either the xFindReceiver
function can be called to find an arbitrary receiver, or the file pidlist.pr
can be used to provide a list of the SDL processes and then address the receiver explicitly via the input queue ID of its OS task.
When sending a signal into the SDL system where the receiver is not known a support function called xFindReceiver
can be used. This function takes the following parameters:
The following files are needed to get access to SDL types, signal numbers and signal parameter types: scttypes.h
, <system_name>.hs
and <system_name>.ifc
.
Example of how to use the xFindReceiver
function:
#include "scttypes.h" #include "<system_name
>.ifc" #include "<system_name
>.hs" void MyExtTask(void) { xSignalHeader yOutputSignalPtr; int Err; /*Allocate signal header and signal parameter buffer */ yOutputSignalPtr = (xSignalHeader)xAlloc(sizeof(xSignalHeaderRec) + sizeof(yPDef_go); /*Setup signal header */ yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = xEnvPId; /*Give value 100 to integer parameter */ ((yPDef_go *)(yOutputSignalPtr+1))->Param1 = 100; /*Send signal from environment */ Err = msgQSend(xFindReceiver(go, xEnvPrs, 0), (char*) yOutputSignalPtr, sizeof(xSignalHederRec)+sizeof(yPDef_go), 0 ,0); }
The following types, signal definitions and global variables are used in the example:
xEnvPId
: An SDL PId representing the environment, from scttypes.h
xEnvPrs
: A PrsNode representing the environment, from scttypes.h
xSignalHeader
: A datatype representing an SDL signal, from scttypes.h
yPDef_go
: A datatype representing the signal parameter types, from <system_name>.ifc
go
: An SDL signal, from <system_name>.ifc
An alternative way to get the PId for the Receiver is to use an ADT defined in the SDT ADT library called pidlist.pr
. This file defines an ADT called PidList and an operator called PId_Lit. With this ADT it is possible to directly address any static process instance in the system, both from internal SDL processes and from external OS-tasks. You can find more information about this feature in How to Obtain PId Literals.
In the Standard Model of the Tight Integration each SDL process is implemented as an OS task. Preemption and the use of process priorities is only limited to what the OS supports.
An SDL process is created in the following way (in the VxWorks integration):
VXWORKSPAD_
, this is a function which will initialize some internal variables. The task will then call the PAD function.xAllocPrs
) is called to create a representation of the new instance in the global symbol tree.The following actions are carried out when a process terminates:
xTimerTask
with a request to remove all active timers of the process.xFreePrs
is called to free the PrsNode
.Each PAD (Process Activity Definition) function will contain an eternal loop with an OS receive statement. When a process instance is created it is the PAD function that is called in the OS Create primitive.
The start-up and execution of a PAD function works like this:
xInputSignal
is called. This function will wait for the start-up signal, that is always received first, and then return to the PAD function.Label_Execute_Transition
. This label is the start of a code block containing a switch statement that evaluates the process variable RestartAddress
. The code under each different case then represents a transition. At the end of this block the process variable State
is updated and execution continues at Label_New_Transition
.Label_New_Transition
a new call is made to xInputSignal
and execution then continues at Label_Execute_Transition
.The structure of a PAD function is described below (with pseudo-code shown in italic):
void yPAD_z01_pr1 (void *VarP) { Variable declarations xInputSignal is called to receive the start-up signal ........... goto Label_Execute_Transition; ........... Label_New_Transition: xInputSignal is called to receive a signal Label_Execute_Transition: Local declarations switch (yVarP->RestartAddress) { case 0: Execute the start transition Update the process state variable goto Label_New_Transition; case 1: Execute the transition Update the process state variable goto Label_New_Transition; ........... } ........... }
Since each SDL process is implemented as an OS task, scheduling between processes will be handled completely by the OS.
Start-up of a Standard Model Tight Integration can be described as follows (pseudocode is shown in italic):
MyMain() { /* initialization of semaphores etc */ yInit(); Give startup semaphores taskSuspend(Mymain); } yInit() { Create the timer task Create an environment task or only an environment queue for(i=1;i<=NoOfStaticProcessTypes;i++){ for(j=1;j<=NoOfStaticInstancesOfEachProcesstype; j++){ Allocate a startup signal Create a message queue Create a task Call xAllocPrs Send the startup signal } } Assign SDL synonyms }
The semaphore is used for synchronizing start-up of static processes. No static process is allowed to execute its start transition before all static processes are created, because a start transition can have signal sending to other static instances.
The MyMain
function is placed among other support functions in the file sctsdl.c
.
The yInit
function is generated by the code generator and placed last in the generated file for the system.
The Instance Set Model is based on the same principles as the Standard Model with the difference that the instance set is the basic unit rather than the process instance.
Both the instances and the instance sets are represented in the symbol table. In addition to the three parts that always make up an SDL process there is also an extra struct for the instance set, defining for example the input queue which is common to all the instances. Further, there is a PAD function for each instance, but also for the instance set.
An SDL_PId is represented by an xEPrsNode
, pointing to an xEPrsStruct
. An xEPrsNode
also represents a process instance in the symbol table both in the Standard Model and the Instance Set Model.
typedef struct xEPrsStruct { xEPrsNode NextPrs; SDL_PId Self; xPrsIdNode NameNode; int BlockInstNumber; xPrsNode VarP; } xEPrsRec;
The datatype xPrsInstanceSetVars
is only used in the Instance Set Model. It defines common data for all instances of the set, like the save queue and the size of the instance data.
typedef struct { xSignalHeader SaveQ; xSignalHeader CurrentInSaveQ; xSignalHeader yInSignalPtr; char name[100]; unsigned PrsDataSize; } xPrsInstanceSetVars.
In the Instance Set Model there is a PAD function for each process instance but also for each instance set. The instance set PAD functions will be called at system start-up and contain an eternal loop in the same fashion as PAD functions in the Standard Model. Instance PAD functions are only called to execute transitions.
All instance sets, even for dynamic processes, are created at system start-up. Since the OS task and the signal queues are created with the instance set, the creation of an instance requires less labour than in the Standard Model. For the instance set creation the macro INIT_PROCESS_TYPE
is used.
The instance set task is never terminated. Termination of a process instance will not remove the save queue, the input queue and the task. This is done at system termination. All queues, including the active timer queue, are emptied of messages to the terminated process though.
The message queue id of the receiver's instance set is accessed through NameNode
in the receiver's xEPrsStruct
and the variable PROCID
.
Example from xSDLResetInTimerProcess
:
Err=msgQSend ((MSG_Q_ID) (yInSignalPointer->Sender) ->NameNode->PROCID, (char *) yInSignalPointer, sizeof (xTimerHeaderRec), 0, 0);
In this case the receiver is the same as the original sender.
A support function xHandle_Sig
is used when sending signals, instead of the macro RTOSSEND
as in the Standard Model. This difference is shown in bold in the code below:
#ifdef X_ONE_TASK_PER_INSTANCE_SET #define SDL_2OUTPUT(PRIO, VIA, SIG_NAME, SIG_IDNODE,\ RECEIVER, SIG_PAR_SIZE, SIG_NAME_STRING)\ XOS_TRACE_OUTPUT(SIG_NAME_STRING) \ XMSC_TRACE_OUTPUT(RECEIVER, yOutputSignalPtr, \ SIG_NAME_STRING) \ xHandle_Sig(yOutputSignalPtr,SDL_SELF,SIG_PAR_SIZE,\ RECEIVER,(RTOSTASK_TYPE)RECEIVER-> \ NameNode->PROCID RTOSHANDLESIG_PAR); #else #define SDL_2OUTPUT(PRIO, VIA, SIG_NAME, SIG_IDNODE, \ RECEIVER, SIG_PAR_SIZE, SIG_NAME_STRING)\ XOS_TRACE_OUTPUT(SIG_NAME_STRING) \ XMSC_TRACE_OUTPUT(RECEIVER, yOutputSignalPtr,\ SIG_NAME_STRING) \ RTOSSEND(&yOutputSignalPtr, RECEIVER,SIG_PAR_SIZE) #endif
Scheduling between instance sets is handled by the operating system. Within the instance sets, however, scheduling is based on the signal queue. When the instance set PAD function is executing, it takes the first signal in the input queue and calls the PAD function of the addressed SDL process. The instance PAD function then executes one transition and returns control to the scheduling loop of the instance set PAD function.
In general, the same restrictions as for the C Code generator apply, but Tight integrations have some further restrictions. The detailed limitations for Light and Tight integrations are listed in Real-Time Operating System Support.
This section describes an example system named Simple. The integration of the Simple system will be explained for each operating system in the annexes to this chapter.
|
The SDL representation of Simple consists of a single block Bl1. Seen from the outside, the system accepts the signal Go and responds after about five seconds by sending the signal Ok. The signal Go may be sent twice to the system.
|
Block Bl1 has two processes. The static process Pr1 and the dynamic process DynPr1. DynPr1 is created by Pr1 and can send the signal Terminating back to its parent. Pr1 handles all the interaction with the environment, through the signals Go and Ok.
|
Process Pr1 is a static process with two instances. It has two states, Idle and Wait. In the Idle state the process waits for the signal Go with an integer parameter representing the instance number of this instance. It then prints the instance number to the standard output, creates one instance of DynPr1 and enters the Wait state. In the Wait state it waits for the signal Terminating from the created instance of DynPr1, sends Ok back to the environment and goes back into the Wait state. Since the Terminating signal will only be received once, the process is going to remain in the Wait state forever.
|
The dynamic process DynPr1 has no instances at system start and a maximum of two instances. Each instance of Pr1 creates one instance of DynPr1. DynPr1 sets the timer t1 to five seconds, waits for a timeout, sends the signal Terminating to its creator and finally terminates.
The environment is handled in different ways depending on the integration model. See below for details.
In the light integration the entire SDL system will be represented by one OS task. Two external procedures, xInEnv and xOutEnv, are used for connection to the environment.
This is where the start-up signal Go is sent. In a real system xInEnv
could for example be used for polling hardware devices for input. The code looks like this:
xSignalNode S; static int SendGo = 0; if(SendGo<=1){ if(SendGo==0) { S = xGetSignal(go, pr1[1], xEnv ); ((yPDef_go *)(S))->Param1 = startinstance1; } else { S = xGetSignal(go, pr1[2], xEnv ); ((yPDef_go *)(S))->Param1 = startinstance2; } SDL_Output( S, xSigPrioPar(xDefaultPrioSignal) (xIdNode *)0 ); SendGo++;
The signal Go is sent the first and the second time xInEnv
is called. The parameters startinstance1 and startinstance2
are integer constants defined in the SDL system, as type SYNONYM
. They are made available here in the Environment module by generating and including the file simple.ifc
.
The code in xOutEnv
for receiving the signal Ok looks like this:
if ( ((*S)->NameNode) == ok ) { printf("Signal Ok received with the following parameter:%lu\n", ((yPDef_ok *)(*S))->Param1); xReleaseSignal( S ); return;
The signal Ok also has an integer parameter, the value of this should be 1 if it is sent by Pr1 instance one and 2 if it is sent by instance two.
The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
In the standard model of tight integration each instance of the Pr1 and the DynPr1 processes will be represented by an OS task. The environment is represented by a task called MyExtTask
. This task is external to the SDL system.
In the instance set model of tight integration Pr1 and DynPr1 will be represented by one OS task each. The environment is represented by a task called MyExtTask
, just as in the standard model. This task is external to the SDL system.
The signal Go is sent from the external task MyExtTask
. This task is created just after return from the call to yInit()
in the main() function in the generated code. This is
The code for this task is placed in the file MyExtTask.c
.
This section explains data types, procedures and macros used in a Tight Integration (Light Integrations are explained in the Master Library).
The macro XPP
is used in function declarations to specify the function parameters. It is defined like this:
#define XPP(x) x
if function prototypes according to ANSI C can be used, or
#define XNOPROTO #define XPP(x) ()
if Kernighan/Ritchie C should be used.
The following type is also always defined:
#define xptrint unsigned
where xptrint
should be an int
type with the same size as a pointer.
typedef struct xPrsStruct *xPrsNode; typedef struct xPrdStruct *xPrdNode;
xPrsNode
and xPrdNode
are pointers to structs holding instance data for an instance of a process or a procedure. Note that some parts of the structs are OS-dependent.
These defines specify the different ways of handling a signal.
The following macros are defined to exclude unnecessary code for IdNode
variables etc.:
#define XNOSTARTUPIDNODE #define XOPTSIGPARA #define XOPTDC #define XOPTFPAR #define XOPTSTRUCT #define XOPTLIT #define XOPTSORT #define XNOUSEOFSERVICE ......
One group of macros defines default priorities for processes and signals:
#ifndef xDefaultPrioProcess #define xDefaultPrioProcess RTOSPRIODEFAULT #endif #ifndef xDefaultPrioSignal #define xDefaultPrioSignal RTOSPRIODEFAULT #endif ...
First in this section is a macro defining the symbol table root:
xIdNode xSymbolTableRoot;
These macros define the start-up function for a PAD function. It is this function that is called in the task creation. As mentioned before this function will after some variable initializations call the PAD function. The definition of the start-up function varies in different RTOS, that is why there is a second OS-specific macro here.
Each signal in an application is assigned a unique integer value. The values 31992 through 32000 are reserved for internal signals like the start-up signal.
These macros define the elements in the xPrsStruct
and xPrdStruct
respectively.
This macro defines a variable representing a pointer to a signal's parameter area.
This macro defines the variable yVarP
which represents the process instance data.
These three macros define the eternal loop inside processes, procedures and procedures without a state.
Each state in a process and procedure is represented as an integer. The Start state will always have the value 0.
This annex briefly describes the OSE models and primitives used in the SDT OSE tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with OSE-classic and tested under OSE Simulator R1.8.3 for OS68 on a Sun workstation with SunOS 4.1.4.
The main differences between OSE and the general model are:
xAlloc
is implemented using the OSE alloc
system call.xFree
is implemented using the OSE free_buf
system call.union SIGNAL { SIGSELECT sig_no; struct xEmptySignalStruct xParameters; struct PrsSignalStruct xPSS; xReplyPrsSignalStruct xRPSS; struct TimerSignalStruct xTimer; struct TimerResetStruct xResetTimer; struct TimerActiveStruct xActiveTimer; struct StartupSignalStruct xStartup; #ifdef XMSC_TRACE struct CastSignalStruct xCastSignalStruct; #endif };
sdt2ose
to generate <system_name>.osh
which is needed by the OSE confsig
utilities.sender()
is used.current_process()
is used.gettimeofday()
, nexus_sim_receive_w_tmo()
, nexus_sim_get_tick()
) to be able to run an application in a simulated target environment.X_USE_UNION_SIGNAL
should be set when compiling. It is used to avoid redeclaration of union SIGNAL
which we declare in sctose.h
but which is also declared in the OSE file ose.i
.
confsig
program the generated application file must be preprocessed first. For this we are using the Telelogic preprocessor program SCCD. To avoid compiling you are recommended to rename the sccd
program to sccdnocomp
and specify in the config
file that you do not want to compile.sdt2ose
. The sdt2ose
program will generate two files: <application>.hs
and <application>.osh
. The file <application>.hs
will contain the signal number and signal parameter type declaration for all signals in the application according to the specified syntax for OSE-trace. The file <application>.osh
will contain the signal parameter type definitions according to OSE-trace syntax.confsig
is used to generate the sigdesc.c
file. This file contains the information for the OSE-trace and is compiled and linked with the kernel and application files.sccd
for your environment.sccd
program to sccdnocomp
. sccd.cfg
file for your environment. Rename the config file to sccdnocomp.cfg
.sccdCOMPILE = "OFF"
.<application>.hs
files.<application>.c
file with the Make options:
Note: The preprocessed file will be placed in a subdirectory called |
<application>.hs
and <application>.osh
with the sdt2ose
program. See how this is done in MakefileSimple
.sigdesc.c
file with the OSE program confsig
.
Note: Due to the OSE kernel problem described above the OSE-trace for the Simple example will not work properly. |
make -f MakefileSimple OSETRACE
This will preprocess the application file, generate the .hs
and .osh
files and generate, compile and link the sigdesc file.
This example uses a simple SDL system. You will find a detailed description of the system in A Simple Example.
This example is developed as an OSE-classic application on a Sun workstation. The makefile and compilation switches are set up for the application to run under an OSE Simulator for OS68. If you are using another configuration of OSE you will probably need to edit the provided makefile.
Figure 527 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h
$(sdtdir)/INCLUDE/sctpred.c
$(sdtdir)/INCLUDE/sctsdl.c
$(sdtdir)/INCLUDE/sctos.c
$(sdtdir)/INCLUDE/sctpred.h
$(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following files:/****+********************************************* 00 Utility macros ***************************************************/ #include <sys/time.h> #include "ose.h"
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.ROOT
variable to your OSE installation path in the provided makefile.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the OSE case.
TightIntegration
directory.sdt2ose.c
file. (Open the file and follow the instructions.) simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file. sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
ROOT
variable to your OSE installation path in the provided makefile.makefile
to generate an executable. If you are not using the SCCD program you need to remove the sccd
command in front of the compiler command:sctCC = sccd gcc
Compiling with the XMSC_TRACE
flag set and then running should result in the following output:
OSESIM> go System_Init_Proc: instancehead process Environment; msc RTOS_Trace; Pr11: instancehead process Pr1; Pr12: instancehead process Pr1; Pr11: condition Idle; Pr12: condition Idle; Pr11: in Go,0 from MyExtTask3; Signal Go received in Pr1:Instance1 dynpr14: instancehead process dynpr1; Pr11 : create dynpr14; Pr11: condition Wait; Pr12: in Go,1 from MyExtTask3; Signal Go received in Pr1:Instance2 dynpr15: instancehead process dynpr1; Pr12 : create dynpr15; Pr12: condition Wait; dynpr14: set T1,2 (5000); /* #SDTNOW(269) */ dynpr14: condition wait; dynpr15: set T1,3 (5000); /* #SDTNOW(276) */ dynpr15: condition wait; dynpr14: timeout T1,2; /* #SDTNOW(5284) */ dynpr14: out Terminating,4 to Pr11; dynpr14: endinstance; Pr11: in Terminating,4 from dynpr14; Pr11: out Ok,5 to MyExtTask3; Ok received in MyExtTask with paramer = 1 dynpr15: timeout T1,3; /* #SDTNOW(5463) */ dynpr15: out Terminating,6 to Pr12; dynpr15: endinstance; Pr12: in Terminating,6 from dynpr15; Pr12: out Ok,7 to MyExtTask3; Ok received in MyExtTask with paramer = 2 OSESIM>
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the file MyExtTask.c
, as shown below:
#include "scttypes.h" #include "simple.hs" #include "simple.ifc" /****+*************************************************************** Simple example: MyExtTask ********************************************************************/ void MyExtTask(void) { union SIGNAL * yOutputSignalPtr; union SIGNAL * yInputSignalPtr; SDL_PId MyPId; SIGSELECT AllSignals[] = {0}; int i; #ifdef X_ONE_TASK_PER_INSTANCE_SET SDL_PId MyOwnPId; xPrsIdRec NameNodeStruct; xEPrsRec MyEPrsStruct; #endif #ifdef XMSC_TRACE extern int SignalId; #endif for(i=1;i<=2;i++) { /* allocation of signal go */ yOutputSignalPtr = (union SIGNAL *)alloc(sizeof(yPDef_go),go); /* assignment of signal parameter */ if(i==1) ((yPDef_go*)& yOutputSignalPtr->xParameters)->Param1 = startinstance1; else ((yPDef_go*)& yOutputSignalPtr->xParameters)->Param1 = startinstance2; #ifdef XMSC_TRACE /* assignment of signal id */ SignalId = i-1; ((yPDef_z2_go *) & yOutputSignalPtr->xParameters)->SignalId = SignalId; /* assignment of signal id */ ((yPDef_z2_go *) & yOutputSignalPtr->xParameters)->IsTimer = 0; #endif /* sending of signal go */ #ifdef X_ONE_TASK_PER_INSTANCE_SET /* assignment of own id */ MyOwnPId=&MyEPrsStruct; MyOwnPId->NameNode=&NameNodeStruct; MyOwnPId->NameNode->PROCID=current_process(); ((yPDef_z2_go *) & yOutputSignalPtr->xParameters)->Sender=MyOwnPId; /* assignment of receiving proc instance */ ((yPDef_z2_go *) & yOutputSignalPtr->xParameters)->Receiver = pr1[i]; send( &yOutputSignalPtr,pr1[i]->NameNode->PROCID); #else send( &yOutputSignalPtr,pr1[i]); #endif } /* waiting for return signal ok */ for(i=1;i<=2;i++) { yInputSignalPtr = (union SIGNAL *)receive(AllSignals); if(yInputSignalPtr->sig_no == ok) printf("Ok received in MyExtTask with paramer = %lu\n", ((yPDef_ok*)&yInputSignalPtr->xParameters)->Param1); } /* suspending MyExtTask */ stop(current_process()); }
This annex briefly describes the OSE Delta models and primitives used in the SDT OSE tight integration. The presentation is focused on the differences from the OSE classic model described in the previous annex.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with OSE Delta Soft Kernel DESFK P1.2.2.3 and tested on a Sun workstation with SunOS Release 5.5.
The main differences between the OSE Delta and the OSE Classic model are:
systimer.c
, which is supplied by ENEA. This is not accurate and is only for demonstration purposes. You will have to supply a suitable timer implementation for the target environment.This test example is developed as an OSE Delta application on a Sun workstation. The makefile and compilation switches are set up for the application to run under an OSE Simulator for OS68. If you are using another configuration of OSE you probably need to edit the provided makefile.
Figure 528 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h $(sdtdir)/INCLUDE/sctpred.c $(sdtdir)/INCLUDE/sctsdl.c $(sdtdir)/INCLUDE/sctos.c $(sdtdir)/INCLUDE/sctpred.h $(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following files:/****+********************************************* 00 Utility macros ***************************************************/ #include <sys/time.h> #include "ose.h"
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.ROOT
variable to your OSE installation path in the provided makefile.makefile
to make an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the OSE Delta case.
TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
ROOT
variable to your OSE Delta installation path in the provided makefile.makefile
to generate an executable. If you are not using the SCCD program you need to remove the sccd
command in front of the compiler command:sctCC = sccd gcc
simple.ose
.Compiling with the XMSC_TRACE
flag set and then running should result in the following output:
%: simple.ose 65547: instancehead process Environment; msc RTOS_Trace; 65551: instancehead process Pr1; 65552: instancehead process Pr1; 65551: condition Idle; 65552: condition Idle; 65551: in Go,0 from 65553; Signal Go received in Pr1:Instance1 65552: in Go,1 from 65553; Signal Go received in Pr1:Instance2 65553: instancehead process MyExtTask; 65554: instancehead process dynpr1; 65551: create 65554; 65551: condition Wait; 65554: set T1,2 (5000); /* #SDTNOW(49) */ 65554: condition wait; 65555: instancehead process dynpr1; 65552: create 65555; 65552: condition Wait; 65555: set T1,3 (5000); /* #SDTNOW(57) */ 65555: condition wait; 65554: timeout T1,2; /* #SDTNOW(5051) */ 65554: out Terminating,4 to 65551; 65554: endinstance; 65551: in Terminating,4 from 65554; 65551: out Ok,5 to 65553; Ok received in MyExtTask with paramer = 1 65555: timeout T1,3; /* #SDTNOW(5059) */ 65555: out Terminating,6 to 65552; 65555: endinstance; 65552: in Terminating,6 from 65555; 65552: out Ok,7 to 65553; Ok received in MyExtTask with paramer = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c
. This is the same as used for OSE Classic, see the listing in How Signals are Sent to and from the Environment.
This annex describes briefly the VxWorks models and primitives used in the SDT VxWorks tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with VxWorks Tornado 1.0 version and tested under VxSim version 5.3 on a Sun workstation with SunOS 4.1.4.
The main differences between VxWorks and the general model are:
msgQReceive
copies the Signal into a buffer when it is received. The sender makes free of the signal immediately after it has been sent and the receiver allocates a buffer (signal) before a receive statement.XOPTSIGNALALLOC
has been introduced for the VxWorks tight integration. When freeing a signal's memory, we place it in an availlist so that subsequent signal memory allocation calls can check to see if suitable sized memory already exists which may be reused. Otherwise memory is allocated as normal.This test example is developed as a VxWorks Tornado application on a Sun workstation. The makefile and compilation switches are set up for the application to run under an VxSim target simulator. If you are using another configuration of VxWorks you probably need to edit the provided makefile.
Figure 529 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following files:/****+********************************************* 00 Utility macros **************************************************/ #include "vxWorks.h"
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.makefile
to make an executable.
Note: A VxWorks application is not allowed to contain a main function. The name of the generated main is changed to "root" with the compilation switch |
The printout when running the example should be:
Target Name: vxTarget Attaching network interface ul0... done. Attaching network interface lo0... done. NFS client support not included. VxWorks Copyright 1984-1995 Wind River Systems, Inc. CPU: SunOS 4.1.4 [sun4c] VxWorks: 5.3 BSP version: 1.1/0 Creation date: Dec 6 1995 WDB: Ready. Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the VxWorks case.
TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
.makefile
to generate an executable. If you are not using the SCCD program you need to remove the sccd command in front of the compiler command:sctCC = sccd ccsparc
Compiling with the XOS_TRACE
flag set and then running should result in the following output:
Target Name: vxTarget Attaching network interface ul0... done. Attaching network interface lo0... done. NFS client support not included. VxWorks Copyright 1984-1995 Wind River Systems, Inc. CPU: SunOS 4.1.4 [sun4c] VxWorks: 5.3 BSP version: 1.1/0 Creation date: Dec 6 1995 WDB: Ready. Process Pr1:3400168 created Process Pr1:3297552 created Process instance 3400168 Pr1: nextstate Idle Process instance 3297552 Pr1: nextstate Idle Process instance 3400168 Pr1: input signal Go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:3092320 created Pr1: nextstate Wait Process instance 3297552 Pr1: input signal Go Signal Go received in Pr1:Instance2 Pr1: process dynpr1:2989704 created Pr1: nextstate Wait Process instance 3092320 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 2989704 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 3092320 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 3400168 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Process instance 2989704 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Ok received in MyExtTask with paramer = 1 Process instance 3297552 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with paramer = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c, as shown below:
#ifdef SIMPLEEXAMPLE #include "scttypes.h" #include "simple.hs" #include "simple.ifc" void MyExtTask(void) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i,Err; SDL_PId MyPId; /* creation of messageQueue */ MyPId = msgQCreate(MAX_INPUTPORT_LENGTH , VXMAXMSGLENGTH, MSG_Q_FIFO); /*allocation of signal go */ for(i=1;i<=2;i++) { yOutputSignalPtr = xAlloc(sizeof(xSignalHeaderRec)+ sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; /*Sender is assigned MyExtTask=(MyPid) */ yOutputSignalPtr->Sender = MyPId; if(i==1) { /*Integer parameter is assigned 1 (=startinstance1) */ ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; } else { /*Integer parameter is assigned 2 (=startinstance2) */ ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; } /*Instance 1 of Pr1 = pr1[1] and instance 2 = pr1[2] */ Err = msgQSend(pr1[i], (char*)yOutputSignalPtr, sizeof(xSignalHeaderRec) + sizeof(yPDef_go),0,0); } for(i=1;i<=2;i++) { /*allocation of input signal */ yInputSignalPtr = xAlloc(VXMAXMSGLENGTH); /*waiting for signal ok */ Err = msgQReceive(MyPId,(char*)yInputSignalPtr,i VXMAXMSGLENGTH, WAIT_FOREVER); if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); } /*task MyExtTask is Suspended */ taskSuspend(0); }
This annex describes shortly the Chorus models and primitives used in the SDT Chorus tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with Chorus Kernel v3 r5 and tested under Chorus Kernel v3 r5 Simulator for SunOS on a Sun workstation with SunOS 4.1.4.
The main differences between Chorus and the general model are:
createSem
: semaphore to guard the global variable portId
yInitSem
: semaphore to guard start-up of static processesPrsSem
: semaphore to guard xAllocPrs
and xFreePrs
xAlloc
is implemented with Chorus rgnAllocate()
.xFree
is implemented with Chorus rgnFree()
.XOPTSIGNALALLOC
has been introduced for the Chorus tight integration. When freeing a signal's memory, we now place it in an availlist so that subsequent signal memory allocation calls can check to see if suitable sized memory already exists which may be reused. Otherwise memory is allocated as normal.This test example is developed as a Chorus application on a Sun workstation. The makefile and compilation switches are set up for the application to run under an Chorus target simulator. If you are using another configuration of Chorus you probably need to edit the provided makefile.
Figure 530 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following files:/****+********************************************* 00 Utility macros **************************************************/ #include <include/chorus.h>
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.CHORUS_INCLUDE
variable to your Chorus installation path in the provided makefile.makefile
to make an executable.The printout when running the example should be:
Starting program: /tmp_mnt/ti/RTOS/CHORUS/SDT3.5/light/simple.U Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the Chorus case.
TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
.makefile
to generate an executable. If you are not using the SCCD program you need to remove the sccd
command in front of the compiler command:sctCC = sccd ccsparc
Compiling with the XOS_TRACE
flag set and then running should result in the following output:
Starting program: /export/ti/RTOS/CHORUS/SDT3.5/tight/backup/simple.U Process xEnvTask:10979901453 created Process Pr1:10979901455 created Process Pr1:10979901456 created Process instance 10979901455 Pr1: nextstate Idle Process instance 10979901456 Pr1: nextstate Idle Process instance 10979901455 Pr1: input signal Go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:10979901458 created Pr1: nextstate Wait Process instance 10979901456 Pr1: input signal Go Signal Go received in Pr1:Instance2 Process instance 10979901458 DynPr1: Set timer T1 Process instance 10979901459 DynPr1: nextstate wait Process instance 10979901458 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 10979901455 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 1 Process instance 109799014516 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 109799014513 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyextTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "scttypes.h" #include "simple.hs" #include "simple.ifc" void MyExtTask(void) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i, returnValue, localPort; SDL_PId MyPId; KnMsgDesc chorusOutMsg, chorusInMsg; KnIpcDest destPort; /*creation of a messageQueue */ returnValue = portCreate( K_MYACTOR, &MyPId); for(i=1;i<=2;i++) { yOutputSignalPtr = xAlloc(sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = MyPId; chorusOutMsg.flags = 0; chorusOutMsg.bodySize = sizeof(xSignalHeaderRec) + sizeof(yPDef_go); chorusOutMsg.annexAddr = NULL; if(i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; chorusOutMsg.bodyAddr = (VmAddr)yOutputSignalPtr; /*Instance 1 of Pr1 = pr[1] and instance 2 = pr[2] */ destPort.target = pr1[i]; returnValue = ipcSend(&chorusOutMsg, portLi(&MyPId), &destPort); } for(i=1;i<=2;i++) { chorusInMsg.bodyAddr = (VmAddr) 0; localPort = portLi(&MyPId); returnValue = ipcReceive (&chorusInMsg, &localPort, -1); chorusInMsg.bodySize = returnValue; chorusInMsg.bodyAddr = (VmAddr)xAlloc(chorusInMsg.bodySize); returnValue = ipcGetData( &chorusInMsg); yInputSignalPtr = (xSignalHeader)chorusInMsg.bodyAddr; if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*) (yInputSignalPtr+1))->Param1); } threadSuspend(K_MYACTOR,K_MYSELF); } #endif
This annex describes shortly the Chorus ClassiX models and primitives used in the SDT Chorus ClassiX tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with Chorus ClassiX Kernel r3.1b and tested under Chorus ClassiX Kernel Simulator r3 for Solaris on a Sun workstation with SunOS 5.5.1.
The main differences between Chorus and the general model are:
createSem
: semaphore to guard the global variable portId
yInitSem
: semaphore to guard start-up of static processesPrsSem
: semaphore to guard xAllocPrs
and xFreePrs
xAlloc
is implemented with Chorus rgnAllocate()
.xFree
is implemented with Chorus rgnFree()
.XOPTSIGNALALLOC
has been introduced for the Chorus ClassiX tight integration. When freeing a signal's memory, we now place it in an availlist so that subsequent signal memory allocation calls can check to see if suitable sized memory already exists which may be reused. Otherwise memory is allocated as normal.This test example is developed as a Chorus application on a Sun workstation. The makefile and compilation switches are set up for the application to run under an Chorus ClassiX Solaris simulator. If you are using another configuration of Chorus ClassiX you probably need to edit the provided makefile.
Figure 531 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
LightIntegration
directory:$(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following files:/****+********************************************* 00 Utility macros **************************************************/ #include <chorus.h>
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.sctuseinclude
, CDSPATH
and CLASSIXDIR
to your Chorus installation path in the provided makefile common.mf
.mkinit
to generate a makefile and create dependency files (all.dp
, common.dp
). $MERGEDIR
. syst.<your application>
file. Change the entry EXAMPLE to show the path for your LightIntegration
directory.sh mkbuild simple
The printout when running the example should be:
CHORUS/ClassiX r3.0.2 on Sparc Solaris 2.5 Copyright (c) 1994, 1995, 1996 Chorus Systemes Local Site Number 1, Incarnation Number 1 Kernel initialization done Kernel size: text 237868 + data 25080 + bss 1348 = 264296 Kernel modules : CORE SCHED_CLASS [ FIFO RR TS RT ] SEM IPC_L MEM_FLM KDB FAULT_KDB TICK KBIM ENV ETIMER LAP LAP_BIND MUTEX UI DATE TIMEOUT Boot actors set-up done Type <return> to proceed with boot actors execution Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the Chorus ClassiX case.
TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
.sctuseinclude, CDSPATH and CLASSIXDIR
to your Chorus Installation path in the provided makefile common.mf. sccd
put this name in front of the compiler definition $(CXX)
.mkinit
to generate a Makefile and dependency files (all.dp
, common.dp
).make
. $MERGEDIR
. syst.<your application>
file. Change the entry EXAMPLE to show your path to <your path>/TightIntegration/TightIntegration_s
sh mkbuild simple
The output when running the example should be:
CHORUS/ClassiX r3.0.2 on Sparc Solaris 2.5 Copyright (c) 1994, 1995, 1996 Chorus Systemes Local Site Number 1, Incarnation Number 1 Kernel initialization done Kernel size: text 237868 + data 25080 + bss 1348 = 264296 Kernel modules : CORE SCHED_CLASS [ FIFO RR TS RT ] SEM IPC_L MEM_FLM KDB FAULT_KDB TICK KBIM ENV ETIMER LAP LAP_BIND MUTEX UI DATE TIMEOUT Boot actors set-up done Type <return> to proceed with boot actors execution Process xEnvTask:6553611 created Process Pr1:6553613 created Process Pr1:6553614 created Process instance 6553613 Pr1: nextstate Idle Process instance 6553614 Pr1: nextstate Idle Process instance 6553613 Pr1: input signal Go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:6553616 created Pr1: nextstate Wait Process instance 6553614 Pr1: input signal Go Signal Go received in Pr1:Instance2 Process instance 6553616 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 6553614 Pr1: process dynpr1:6553617 created Pr1: nextstate Wait Process instance 6553617 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 6553616 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 6553617 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 6553613 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Process instance 6553614 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 1 Ok received in MyExtTask with parameter = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyextTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "scttypes.h" #include "simple.hs" #include "simple.ifc" void MyExtTask(void) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i, returnValue, localPort; SDL_PId MyPId; KnMsgDesc chorusOutMsg, chorusInMsg; KnIpcDest destPort; /*creation of a messageQueue */ returnValue = portCreate( K_MYACTOR, &MyPId); for(i=1;i<=2;i++) { yOutputSignalPtr = xAlloc(sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = MyPId; chorusOutMsg.flags = 0; chorusOutMsg.bodySize = sizeof(xSignalHeaderRec) + sizeof(yPDef_go); chorusOutMsg.annexAddr = NULL; if(i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; chorusOutMsg.bodyAddr = (VmAddr)yOutputSignalPtr; /*Instance 1 of Pr1 = pr[1] and instance 2 = pr[2] */ destPort.target = pr1[i]; returnValue = ipcSend(&chorusOutMsg, portLi(&MyPId),&destPort); } for(i=1;i<=2;i++) { chorusInMsg.bodyAddr = (VmAddr) 0; chorusInMsg.flags = 0; localPort = portLi(&MyPId); returnValue = ipcReceive (&chorusInMsg, &localPort, -1); chorusInMsg.bodySize = returnValue; chorusInMsg.bodyAddr= (VmAddr)xAlloc(chorusInMsg.bodySize); returnValue = ipcGetData( &chorusInMsg); yInputSignalPtr = (xSignalHeader)chorusInMsg.bodyAddr; if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*) (yInputSignalPtr+1))->Param1); } threadSuspend(K_MYACTOR,K_MYSELF); } #endif
This annex briefly describes the pSOS models and primitives used in the SDT pSOS tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed with pSOSystem/68K release 2.1.3 and tested on target with the BSP MVME-147.
The main differences between pSOS and the general model are:
Tick
task which updates a global system tick variable.XNOUSEOFREAL
should be set.This test example is developed as a pSOS application on a Sun workstation. The build files and compilation switches are set up for the application to run on a MVME-147 target. If you are using another configuration of pSOS you probably need to edit the provided build files.
Figure 532 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. Make a new compiler entry called PSOS_C:/*---+--------------------------------------------- PSOS_C -----------------------------------------------*/ #ifdef PSOS_C #include <psos.h> #include <drv_intf.h> #include <prepc.h> #include <stdio.h> #include <v12.h> #define abs(j) ((j)<0?-(j):(j)) #endif
sctos.c
file. Before the SDL_Clock function definition make the definition:#ifdef PSOS_C unsigned long Sys_Ticks = 0; #endifInside the SDL_Clock function make the following entry:
#if defined(PSOS_C) tmp.s = (xint32)Sys_Ticks; tmp.ns = (xint32)0; #endif
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file. default.bld
file to suit your pSOS installation and your target address. userappl.bld
file to suit your pSOS installation. ram.bld
, select userappl.bld
and build the executable.The printout when running the example should be:
pROBE+ is now ready to talk to the host debugger over the network... The printout when running the example should be: Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Signal Ok received with the following parameter:1 Signal Ok received with the following parameter:2
In addition to the functions described in The xInEnv Function, the code also initializes the pSOS devices and starts the Tick task:
void *dummy; unsigned long iopb[4]; unsigned long ioretval; void *data; unsigned long tmmgr_id; de_init(CONSOLE_DEV, 0, &ioretval, &dummy); de_init(CLOCK_DEV, iopb, &ioretval, &data); t_create("Ticks", 231, 256, 256, T_LOCAL | T_FPU, &tmmgr_id); t_start(tmmgr_id, T_PREEMPT \ | T_TSLICE \ | T_ASR \ | T_USER \ | T_LEVELMASK0, xTicks, 0);
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the pSOS case.
TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file. userappl.bld
file to suit your pSOS installation. ram.bld
, select userappl.bld
and build the executable.Compiling with the XOS_TRACE
flag set and then running should result in the following output:
pROBE+ is now ready to talk to the host debugger over the network... System startup ** Process Pr1:9901455 created ** ** Process Pr1:9901456 created ** ** Process instance 9901455 ** Pr1: nextstate Idle ** Process instance 9901456 ** Pr1: nextstate Idle ** Process instance 9901455 ** Pr1: input signal Go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:9901458 created Pr1: nextstate Wait ** Process instance 9901456 ** Pr1: input signal Go Signal Go received in Pr1:Instance2 ** Process instance 9901458 ** DynPr1: Set timer T1 Process instance 9901459 DynPr1: nextstate wait ** Process instance 9901458 ** DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped ** Process instance 9901455 ** Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 1 ** Process instance 99014516 ** DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped ** Process instance 99014513 ** Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "simple.hs" #include "simple.ifc" /****+************************************************* Simple example: MyExtTask ******************************************************/ extern void MyExtTask XPP(( void )) { xSignalHeader yInputSignalPtr, yOutputSignalPtr; unsigned long i, RetCode, Mess [4]; SDL_PId MyPId; RetCode = q_create( "MyExtTask", Q_COUNT, DEFAULT_Q_CREATE_FLAGS, &MyPId); XOS_ERROR("MyExtTask", "q_create", RetCode) for(i=1;i<=2;i++) { yOutputSignalPtr = (xSignalHeader)xAlloc (sizeof (xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = MyPId; yOutputSignalPtr->SigP = yOutputSignalPtr + 1; Mess [0] = (unsigned long)yOutputSignalPtr; if(i==1) ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance2; /*Instance 1 of Pr1 = pr[1] and instance 2 = pr[2] */ RetCode = q_send (pr1[i],(xIdNode *)0), Mess); XOS_ERROR ("MyExtTask", "q_send", RetCode) } for(i=1;i<=2;i++) { RetCode = q_receive(MyPId, Q_WAIT, 0, Mess); XOS_ERROR("MyExtTask", "q_receive", RetCode) yInputSignalPtr = (xSignalHeader) Mess[0]; if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); xFree((void**)(&yInputSignalPtr)); } t_suspend (0L); } #endif
This annex describes briefly the VRTXsa model and primitives used in the SDT VRTXsa tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example for both a light and tight integration.
This integration is developed using the gcc compiler and the Spectra environment and tested under the Spectra Cross-Development Shell on a Sun workstation with SunOS 4.1.4.
The main differences between VRTXsa and the general model are:
sc_tecreate()
function call. An individual message queue is created for every created task using the sc_qecreate()
function and the queue id is passed as a parameter to the newly created task.This test example is developed as a VRTXsa application on a Sun workstation. The makefile and compilation switches are set up for the application to run under the Spectra Cross-Development Shell. If you are using another configuration of VRTXsa, you probably need to edit the provided makefile.
Figure 533 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
scttypes.h
file. In the beginning of the section "Utility macros" make an include of the following file:/****+******************************************** 00 Utility macros **************************************************/ #include <vrtxil.h>
sctos.c
file and make the following changes. Inside the SDL_Clock
function definition make the following entry:#ifdef VRTX_C int Err; struct timespec time_s; unsigned long ns = 10000000; /* ns per tick for VRTXsa clock */ sc_gclock(&time_s,&ns,&Err); tmp.s = time_s.seconds; tmp.ns = time_s.nanoseconds; #endif
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.makefile
to suit your environment setup and generate an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Ok received with the following parameter:1 Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the VRTX case.
TightIntegration
directory.simple.sdt
and generate a simple.c
, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<your_compiler_type>.cfg
from <your_SDT_installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler_type>.cfg
to sccd.cfg
makefile
to suit your environment setup and generate an executable. If you are using the SCCD program you need to add the sccd
command in front of the compiler command:sctCC = sccd gcc
Compiling with the XOS_TRACE
flag set and then running should result in the following output:
Process Pr1:15 created Process Pr1:14 created Process instance 15 Pr1: nextstate Idle Process instance 14 Pr1: nextstate Idle Pr1: input signal Go Signal Go received in Pr1:Instance2 Pr1: process dynpr1:13 created Pr1: nextstate Wait Pr1: input signal Go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:12 created Pr1: nextstate Wait Process instance 13 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 12 DynPr1: Set timer T1 DynPr1: nextstate wait Process instance 13 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 12 DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped Process instance 14 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Process instance 15 Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 2 Ok received in MyExtTask with parameter = 1
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "scttypes.h" #include "simple.hs" #include "simple.ifc" void MyExtTask(void *dummy) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int Err,i; /*allocation of signal go */ for(i=1;i<=2;i++) { yOutputSignalPtr = xAlloc(sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = EXTTASKQ; yOutputSignalPtr->SigP = yOutputSignalPtr+1; /* Integer parameter is assigned */ if (i==1) ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 =startinstance1; else ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 =startinstance2; /*Instance 1 of Pr1 = pr[1] and instamce 2 = pr[2] */ sc_qpost(pr1[i], (char *)yOutputSignalPtr, &Err); XOS_ERROR("MyExtTask", "sc_qpost", Err) } /*waiting for signal ok */ for(i=1;i<=2;i++) { yInputSignalPtr = (xSignalHeader)sc_qpend(EXTTASKQ, 0, &Err); XOS_ERROR("MyExtTask", "sc_qpend", Err) if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); } sc_tsuspend( 0, 0, &Err); } #endif /* SIMPLEEXAMPLE */
This annex briefly describes integration with Win32 and Windows CE. The presentation is focused on the differences from the general model described earlier in this chapter.
This integration is developed using the Microsoft 32-bit C/C++ Compiler Version 11.00.7022 and tested on NT 4.0, NT 3.51 and Windows 95 platforms. The integration is also compiled with Borland C++ 5.2 for Win32 and tested on NT 4.0, NT 3.51 and Windows 95 platforms.
The main differences between integration with Win32 and the general model are:
CreateThread()
. The thread is then automatically given an input queue the first time it calls a USER or GDI functionxAlloc
is implemented with Win32 function HeapAlloc()
.xFree
is implemented with Win32 function HeapFree()
.GetTickCount()
function.
Note: The internal timer wraps around to zero if Windows is run continuously for approximately 49.7 days. |
The standard Win32 integration package is also used for integrating with Windows CE. It has been tested on Windows CE 2.0.
The main difference between the Win32 integration and the Windows CE integration is that Windows CE does not provide a printf()
function.
If you want to use trace output then you must supply this functionality yourself or use one of the third party solutions that are available. You must also put a prototype for your printf()
function in sctwin32.h
.
Note: To build your system for Windows CE you must use the compilation switch -DXWINCE. |
This test example is developed as a Win32 console application on a PC. The makefiles and compilation switches are set up for the application to compile using either the Borland or the Microsoft compiler listed above. There is a separate makefile for each compiler.
Figure 534 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h $(sdtdir)/INCLUDE/scttypes.h
<compiler_name>makefile
to suit your environment and generate an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Ok received with the following parameter:1 Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the Win32 case.
#ifdef
) are used in this integration:WIN32_INTEGRATION
: Ensures that the sctwin32.h
file is included in each C file. Must be set in all cases.XOS_TRACE
: Gives a textual trace for most of the SDL events by using printf to some device. This flag should not be used together with XMSC_TRACE
.XMSC_TRACE
: Will give a textual trace in the format of MSC/PR Z.120 by using printf. This trace is possible to view in the MSC Editor included in Telelogic Tau. This flag should not be used together with XOS_TRACE
.XMSC_EDITOR
: Used together with the XMSC_TRACE
flag, the MSC trace is automatically displayed in the MSC Editor. Note that you must have the Telelogic Tau Organizer open on your machine.X_ONE_TASK_PER_INSTANCE_SET
: States that the Instance Set Model is used. The Standard Model is otherwise chosen by default.XERR
: When this flag is defined, the return status of all Win32 function calls will be printed.XINCLUDE_HS_FILE
: Includes the system signal header file which is required for tight integrations. This file maps signal names to integers.XRTOSTIME
: Should always be set for all tight integrations.XUSING_SCCD
: This should be set when using the SDT preprocessor SCCD to ensure that the windows header files are not included on the preprocessor pass. The files are included though on the compiler pass and this ensures that the preprocessed C files only contain the expanded SDT macros. It also helps greatly to speed up the process. Note that this flag only works with the Microsoft compiler and should not be used with any other compiler.XWINCE
: This flag allows you to compile the integration for Microsoft WinCE target systems. This flag should not be used together with the MSC trace flags.TightIntegration
directory.sccd.c
and sccd_<compiler type>.cfg
from
<Telelogic Tau installation directory>\sdt\
sdtdir\util\
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler_type>.cfg to sccd.cfg
<compiler_name>makefile
to generate an executable. If you are using the SCCD program, you need to add the sccd
command in front of the compiler command in your makefile, e.g.:sctCC = sccd bcc32
Note: The Borland compiler command line argument limitation can sometimes be exceeded. If this happens, you should define the |
Compiling with the XOS_TRACE
flag set and then running should result in the following output:
System startup Process Pr1:1081 created Process Pr1:1072 created ** Process: Pr1 instance: 1081 ** Pr1: nextstate Idle ** Process: Pr1 instance: 1072 ** Pr1: nextstate Idle ** Process: Pr1 instance: 1081 ** Pr1: input signal Go Signal Go received in Pr1:Instance1 Process dynpr1:1066 created ** Process: Pr1 instance: 1072 ** Pr1: input signal Go Signal Go received in Pr1:Instance2 Process dynpr1:1079 created ** Process: Pr1 instance: 1081 ** Pr1: nextstate Wait ** Process: DynPr1 instance: 1066 ** DynPr1: Set timer T1 DynPr1: nextstate wait ** Process: Pr1 instance: 1072 ** Pr1: nextstate Wait ** Process: DynPr1 instance: 1079 ** DynPr1: Set timer T1 DynPr1: nextstate wait ** Process: DynPr1 instance: 1066 ** DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped ** Process: Pr1 instance: 1081 ** Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate ** Process: DynPr1 instance: 1079 ** DynPr1: input signal T1 DynPr1: signal Terminating sent DynPr1: stopped ** Process: Pr1 instance: 1072 ** Pr1: input signal Terminating Pr1: signal Ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 1 Ok received in MyExtTask with parameter = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c
, as shown below:
#include "scttypes.h" #include "simple.hs" #include "simple.ifc" /****+*************************************************************** Simple example: MyExtTask ********************************************************************/ #ifdef X_ONE_TASK_PER_INSTANCE_SET extern void MyExtTask XPP(( void )) { xSignalHeader yInputSignalPtr, yOutputSignalPtr; unsigned long RetCode; MSG win32Mess; unsigned long MyThreadId; xPrsIdNode MyPrsId; SDL_PId MyPId; int i; MyThreadId = (unsigned long)GetCurrentThreadId(); MyPrsId = xAlloc(sizeof(xPrsIdRec)); MyPId = xAlloc(sizeof(xEPrsRec)); MyPId->NameNode = MyPrsId; MyPId->NameNode->PROCID = (unsigned long *)MyThreadId; #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s", MyPId, ": instancehead process ", "MyExtTask", ";"); RTOSMSCPRINT_STOP #else /* XOS_TRACE_STATIC_CREATE(MyPId, "MyExtTask") XMSC_TRACE_STATIC_CREATE(MyPId, "MyExtTask") */ #endif for(i=1;i<=2;i++) { yOutputSignalPtr = (xSignalHeader)xAlloc (sizeof (xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Receiver = pr1[i]; yOutputSignalPtr->Sender = MyPId; yOutputSignalPtr->SigP = yOutputSignalPtr + 1; win32Mess.wParam = (WPARAM)yOutputSignalPtr; if (i==1) ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance2; RetCode = PeekMessage(&win32Mess, (HWND) NULL, 0, 0, PM_NOREMOVE ); XOS_ERROR("MyExtTask", "PeekMessage", RetCode) win32Mess.lParam = (DWORD)(pr1[i]->NameNode->PROCID); #ifdef XMSC_TRACE RTOSMSCPRINT_START SignalId = SignalId + 1; yOutputSignalPtr->SignalId = SignalId; yOutputSignalPtr->IsTimer = 0; #ifdef XMSC_EDITOR sprintf(msce_buf, "%lu %s %s %s %d %s %lu %s", yOutputSignalPtr->Sender,\ ": out ", "go", ",", SignalId, " to ", pr1[i], ";"); RTOSMSCPRINT_STOP #else /* XMSC_EDITOR */ XMSC_FPRINT(("%lu: out %s,%d to %lu;\n", yOutputSignalPtr->Sender, "go",\ SignalId, pr1[i])) RTOSMSCPRINT_STOP #endif /* XMSC_EDITOR */ #endif /* XMSC_TRACE */ RetCode = 0; while (RetCode == 0) { RetCode = PostThreadMessage( win32Mess.lParam, WM_SDL_SIGNAL, win32Mess.wParam, win32Mess.lParam); } XOS_ERROR ("MyExtTask", "PostThreadMessage", RetCode) } for(i=1;i<=2;i++) { RetCode = GetMessage ( &win32Mess, (HWND) NULL, 0, 0 ); XOS_ERROR("MyExtTask", "GetMessage", RetCode) yInputSignalPtr = (xSignalHeader) win32Mess.wParam; if(yInputSignalPtr->SignalCode == ok) { #ifdef XMSC_TRACE #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s %d %s %ld %s", yInputSignalPtr->Receiver,\ ": in ", "ok", ",", yInputSignalPtr->SignalId, " from ",\ yInputSignalPtr->Sender, ";"); RTOSMSCPRINT_STOP #else /* XMSC_EDITOR */ XMSC_FPRINT(("%lu: in %s,%d from %lu;\n", yInputSignalPtr->Receiver, "ok",\ yInputSignalPtr->SignalId, yInputSignalPtr->Sender)) #endif /* XMSC_EDITOR */ #else /* XMSC_TRACE */ printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); #endif /* XMSC_TRACE */ } xFree((void**)(&yInputSignalPtr)); } SuspendThread(GetCurrentThread()); } #else extern void MyExtTask XPP(( void )) { xSignalHeader yInputSignalPtr, yOutputSignalPtr; unsigned long RetCode; MSG win32Mess; unsigned long MyThreadId; int i; MyThreadId = (WPARAM)GetCurrentThreadId(); #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s", MyThreadId, ": instancehead process ",\ "MyExtTask", ";"); RTOSMSCPRINT_STOP #else /* XOS_TRACE_STATIC_CREATE(MyThreadId, "MyExtTask") XMSC_TRACE_STATIC_CREATE(MyThreadId, "MyExtTask")*/ #endif for(i=1;i<=2;i++) { yOutputSignalPtr = (xSignalHeader)xAlloc (sizeof (xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = MyThreadId; yOutputSignalPtr->SigP = yOutputSignalPtr + 1; win32Mess.wParam = (WPARAM)yOutputSignalPtr; if(i==1) ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr->SigP))->Param1 = startinstance2; RetCode = PeekMessage(&win32Mess, (HWND) NULL, 0, 0, PM_NOREMOVE ); XOS_ERROR("MyExtTask", "PeekMessage", RetCode) #ifdef XMSC_TRACE RTOSMSCPRINT_START SignalId = SignalId + 1; yOutputSignalPtr->SignalId = SignalId; yOutputSignalPtr->IsTimer = 0; #ifdef XMSC_EDITOR sprintf(msce_buf, "%lu %s %s %s %d %s %lu %s", \ MyThreadId, ": out ", "go", ",", SignalId, " to ", pr1[i], ";"); RTOSMSCPRINT_STOP #else XMSC_FPRINT(("%lu: out %s,%d to %lu;\n", MyThreadId, "go", SignalId, pr1[i])) RTOSMSCPRINT_STOP #endif /* XMSC_EDITOR */ #endif /* XMSC_TRACE */ RetCode = 0; while (RetCode == 0) { RetCode = PostThreadMessage((DWORD)/*xFindReceiver (go ,xEnvPrs ,0)*/ pr1[i],WM_SDL_SIGNAL, win32Mess.wParam, win32Mess.lParam); } XOS_ERROR ("MyExtTask", "PostThreadMessage", RetCode) } for(i=1;i<=2;i++) { RetCode = GetMessage ( &win32Mess, (HWND) NULL, 0, 0 ); XOS_ERROR("MyExtTask", "GetMessage", RetCode) yInputSignalPtr = (xSignalHeader) win32Mess.wParam; if(yInputSignalPtr->SignalCode == ok) { #ifdef XMSC_TRACE #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s %d %s %ld %s", MyThreadId, ": in ", "ok", \ ",", yInputSignalPtr->SignalId, " from ", yInputSignalPtr->Sender, ";"); RTOSMSCPRINT_STOP #else XMSC_FPRINT(("%lu: in %s,%d from %lu;\n", MyThreadId, "ok", \ yInputSignalPtr->SignalId, \ yInputSignalPtr->Sender)) #endif /* XMSC_EDITOR */ #else printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); #endif } xFree((void**)(&yInputSignalPtr)); } SuspendThread(GetCurrentThread()); } #endif /* X_ONE_TASK_PER_INSTANCE_SET */
This annex describes briefly the QNX model and primitives used in the SDT QNX tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example in both a light and tight integration.
This integration is developed using the Watcom 10.6 compiler and tested with QNX 4.23 version, running on a PC.
The main differences between QNX and the general model are:
tfork()
function call. An individual message queue is created for each process and the queue name is passed as a parameter to the newly created process.RTOSSDL_CREATE
to ensure that the allocation of the shared memory for dynamic processes is carried out correctly.mq_receive()
until a new message is posted to its queue.This test example is developed as a QNX application on a PC. The makefile and compilation switches are set up for the application to run under QNX 4.23 using the Watcom 10.6 compiler.
Figure 535 : File structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.makefile
to make an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Ok received with the following parameter:1 Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the QNX case.
TightIntegration
directory.simple.sdt
and generate a simple.c
, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from
<your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
makefile
to generate an executable. If you are using the SCCD program you need to add the sccd
command in front of the compiler command:sctCC = ./sccd cc
Compiling with the XOS_TRACE
flag set and then running should result in the following output:
Process Pr1:1 created Process Pr1:2 created Process instance 1 Pr1: nextstate Idle Process instance 2 Pr1: nextstate Idle Process instance 1 Pr1: input signal Go Signal Go received in Pr1:Instance1 Process instance 2 Pr1: input signal Go Signal Go received in Pr1:Instance2 Process instance 1 Pr1: process dynpr1:3 created Pr1: nextstate Wait Process instance 2 Pr1: process dynpr1:4 created Pr1: nextstate Wait Process instance 3 DynPr1: Set timer T1 Process instance 4 DynPr1: Set timer T1 Process instance 3 DynPr1: nextstate wait Process instance 4 DynPr1: nextstate wait Process instance 3 DynPr1: input signal T1 Process instance 4 DynPr1: input signal T1 Process instance 3 DynPr1: signal Terminating sent Process instance 4 DynPr1: signal Terminating sent Process instance 1 Pr1: input signal Terminating Pr1: signal Ok sent Process instance 2 Pr1: input signal Terminating Pr1: signal Ok sent Process instance 3 DynPr1: stopped Process instance 4 DynPr1: stopped Ok received in MyExtTask with parameter = 1 Ok received in MyExtTask with parameter = 2 Process instance 1 Pr1: dash nextstate Process instance 2 Pr1: dash nextstate
The signal Go is sent from an external process MyExtTask
. The code for this task is placed in the program file MyExtTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "scttypes.h" #include "simple.hs" #include "simple.ifc" void MyExtTask(void *dummy) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i; mqd_t QueuePId; /*allocation of signal go */ for (i=1;i<=2;i++) { yOutputSignalPtr = xAlloc (sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = "ExtTaskQueue"; /*Integer parameter is assigned*/ if (i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; QueuePId = mq_open( pr1[i], 2, 0, 0); XOS_ERROR("MyExtTask", "mq_open", QueuePId) Err = mq_send(QueuePId, (char*)yOutputSignalPtr, sizeof(xSignalHeaderRec)+sizeof(yPDef_go), NULL); XOS_ERROR("MyExtTask", "mq_send", QueuePId) Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } /*allocation of input signal */ for (i=1;i<=2;i++) { yInputSignalPtr = xAlloc(4096); /*waiting for signal ok */ QueuePId = mq_open("ExtTaskQueue", 2, 0, 0); XOS_ERROR("MyExtTask", "mq_open", QueuePId) Err = mq_receive(QueuePId,(char*)yInputSignalPtr,4096, NULL); if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } Err = mq_unlink("ExtTaskQueue"); XOS_ERROR("MyExtTask", "mq_unlink", Err) exit(0); } #endif /* SIMPLEEXAMPLE */
This annex describes briefly the Nucleus PLUS model and primitives used in the SDT Nucleus PLUS tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example for a tight integration.
This integration is developed using Microsoft Visual C++ Version 5.0 with Nucleus MNT running on a PC.
The main differences between Nucleus PLUS and the general model are:
sctnucleus.h
, the macros which contain the Nucleus PLUS specific function calls are implemented. The file sctnucleus.c
contains the Nucleus PLUS integration specific functions, e.g. the task manager function. Application_Initialize
routine, which is the main()
function for Nucleus PLUS, is defined in the file sctnucleus.c
. This routine is responsible for defining the initial application environment. Here the memory pool for the system is allocated and the main task for the SDL system, SDL_main
, is created. This main task is responsible for the creation of the tasks and queues, which represent the static SDL processes, plus initializing the SDL system. Once the SDL system is initialized, the application initialization semaphores are released and the system is allowed to run. NU_Create_Task()
is used to create new tasks. The queue Id of a newly created queue is passed as a parameter to the start-up function of the created task and all future referencing of this task is done through this queue. The task suspends (blocks) on its queue using the Nucleus PLUS function NU_Receive_From_Queue()
and it uses the function NU_Send_To_Queue()
to send signals to other tasks. NU_Create_Task()
function requires that you define the stack size, time slice size and priority for your task. To simplify this process five different task types have been identified and these variables are defined as constants at the beginning of the sctnucleus.h
file. This allows the developer to easily change these variables when it comes to porting the application to the target. The queue size for queues associated with the different types of tasks is also defined as a constant in a similar manner. The five different task types identified are: SDL tasks, timer task, environment task, SDL main task, and manager task.XOS_ERROR
is used to perform this check. The developer is free to add an error handler function to suit its application. Another macro XERROR_RECEIVED_WITH_TIMEOUT
is used after each call to the Nucleus PLUS function NU_Receive_From_Queue()
. This ensures that the queue is not allowed to unblock even if the timeout value has been exceeded. Again a suitable error handler function should be added by the developer for the particular application.This test example is developed as a Nucleus MNT application on a PC. The makefile and compilation switches are set up for the application to run under Nucleus MNT using the Microsoft Visual C++ Version 5.0 compiler.
Figure 536 : Structure for the Simple example
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.makefile
to make an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Ok received with the following parameter:1 Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the Nucleus case.
#ifdef
) are used in this integration: NUCLEUS_MNT
: This differentiates between compiling for the MNT simulator or for the target system. XUSING_SCCD
: This is set when using the SDT preprocessor SCCD to ensure that the Windows header files are not included on the preprocessor pass. The files are included though on the compiler pass and this ensures that the preprocessed C files only contain the expanded SDT macros. It also helps greatly to speed up the process. Note that this flag should only be defined when using the Microsoft compiler.XOS_TRACE
: gives a textual trace for most of the SDL events by using printf to some device. This flag should not be used together with XMSC_TRACE
.XMSC_TRACE
: will give a textual trace in the format of MSC/PR Z.120 by using printf. This trace is possible to view in the MSC Editor included in Telelogic Tau. This flag should not be used together with XOS_TRACE
.NUCLEUS_INTEGRATION
: Ensures that the sctnucleus.h
file is included in each C file. Must be set in all cases.X_ONE_TASK_PER_INSTANCE_SET
: Should be defined when the alternative runtime model is to be used.XINCLUDE_HS_FILE
: Includes the system signal header file which is required for tight integrations. This file maps signal names to integers.XRTOSTIME
: Should always be set for all tight integrations.SIMPLEEXAMPLE
: Creates an external task which send the Go signal into the system and receives the Ok return on successful completion of our SDL simple example system.WIN32
, _DEBUG
, _CONSOLE
, APCON
: Windows defines required by Nucleus MNT+.TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file. sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
MicrosoftMakefile
to generate an executable. If you are using the SCCD program you need to add the sccd
command in front of the compiler command:sctCC = sccd cl
The output when running the example should be:
System startup Process Pr1:14956480 created Process Pr1:14961524 created Process instance 14956480 Pr1: nextstate Idle Process instance 14961524 Pr1: nextstate Idle Process instance 14956480 Pr1: input signal go Signal Go received in Pr1:Instance1 Pr1: process dynpr1:14971952 created Pr1: nextstate Wait Process instance 14961524 Pr1: input signal go Signal Go received in Pr1:Instance2 Pr1: process dynpr1:14976996 created Pr1: nextstate Wait Process instance 14971952 DynPr1: Set timer t1 Process instance 14976996 DynPr1: Set timer t1 Process instance 14971952 DynPr1: nextstate Wait_t1 Process instance 14976996 DynPr1: nextstate Wait_t1 Process instance 14971952 DynPr1: input signal t1 DynPr1: signal terminating sent DynPr1: stopped Process instance 14976996 DynPr1: input signal t1 DynPr1: signal terminating sent DynPr1: stopped Process instance 14956480 Pr1: input signal terminating Pr1: signal ok sent Pr1: dash nextstate Process instance 14961524 Pr1: input signal terminating Pr1: signal ok sent Pr1: dash nextstate Ok received in MyExtTask with parameter = 1 Ok received in MyExtTask with parameter = 2
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyextTask
, as shown below:
#ifdef SIMPLEEXAMPLE #include "simple.hs" #include "simple.ifc" #ifdef X_ONE_TASK_PER_INSTANCE_SET void MyExtTask(UNSIGNED argc, VOID *argv) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i; SDL_PId MyOwnPId; xPrsIdRec NameNodeStruct; xEPrsRec MyEPrsStruct; STATUS Err; SDL_PId Self = argv; for(i=1;i<=2;i++) { yOutputSignalPtr = (xSignalHeader)xAlloc (sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; MyOwnPId=&MyEPrsStruct; MyOwnPId->NameNode=&NameNodeStruct; MyOwnPId->NameNode->PROCID=(NU_QUEUE *)Self; yOutputSignalPtr->Receiver = pr1[i]; yOutputSignalPtr->Sender = MyOwnPId; if(i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; Err = NU_Send_To_Queue((NU_QUEUE *)pr1[i]->NameNode->PROCID, &yOutputSignalPtr, 1, NU_SUSPEND); XOS_ERROR("MyExtTask", "NU_Send_To_Queue", Err) } /*waiting for signal ok */ for(i=1;i<=2;i++) { Err = NU_Receive_From_Queue((NU_QUEUE *)Self, &yInputSignalPtr, 1, &received_size, NU_SUSPEND); XOS_ERROR("MyExtTask", "NU_Receive_From_Queue", Err) if(yInputSignalPtr->SignalCode == ok) { printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); } } Err = NU_Suspend_Task(NU_Current_Task_Pointer()); XOS_ERROR("MyExtTask", "NU_Suspend_Task", Err) } #else void MyExtTask(UNSIGNED argc, VOID *argv) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i; STATUS Err; SDL_PId Self = argv; /*allocation of signal go */ for(i=1;i<=2;i++) { yOutputSignalPtr = xAlloc (sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; /*Sender is assigned MyExtTask=(MyPid) */ yOutputSignalPtr->Sender = (SDL_PId)Self; /*Integer parameter is assigned */ if (i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; Err = NU_Send_To_Queue(pr1[i], &yOutputSignalPtr,1, NU_SUSPEND); XOS_ERROR("MyExtTask", "NU_Send_To_Queue", Err) } /*waiting for signal ok */ for(i=1;i<=2;i++) { Err = NU_Receive_From_Queue(Self, &yInputSignalPtr, 1, &received_size, NU_SUSPEND); XOS_ERROR("MyExtTask", "NU_Receive_From_Queue", Err) if(yInputSignalPtr->SignalCode == ok) printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); } Err = NU_Suspend_Task(NU_Current_Task_Pointer()); XOS_ERROR("MyExtTask", "NU_Suspend_Task", Err) } #endif /* X_ONE_TASK_PER_INSTANCE_SET */ #endif /* SIMPLEEXAMPLE */
This annex describes briefly the Solaris 2.6 model and primitives used in the SDT Solaris 2.6 tight integration. The presentation is focused on the differences from the general model described earlier in this chapter.
One section describes how to set up and run a simple test example for a tight integration.
Note: The Solaris 2.6 tight integration is fully POSIX compliant. For this reason it will not work with earlier versions of Solaris. |
This integration is developed using cc:WorkShop Compilers 4.2 with Solaris 2.6 running on a workstation.
The main differences between the Solaris 2.6 integration and the general model are:
sctsolaris.h
, the macros which contain the Solaris 2.6 specific function calls are implemented. The file sctsolaris.c
contains the Solaris 2.6 integration specific functions. pthread_create()
function and POSIX queues are created for each thread using mq_open()
. The threads are suspended when its corresponding queue is empty.This test example is developed as a Solaris 2.6 application on a workstation. The makefile and compilation switches are set up for the application to run under Solaris 2.6 using the cc:WorkShop Compilers 4.2 compiler.
Figure 537 : File Structure for the Simple example.
|
LightIntegration/INCLUDE
directory:$(sdtdir)/INCLUDE/sctlocal.h, $(sdtdir)/INCLUDE/sctpred.c, $(sdtdir)/INCLUDE/sctsdl.c, $(sdtdir)/INCLUDE/sctos.c, $(sdtdir)/INCLUDE/sctpred.h, $(sdtdir)/INCLUDE/scttypes.h
simple.sdt
in SDT and generate a simple.c
and simple.ifc
file. Use the Cadvanced Code Generator and the options Lower Case and Generate environment header file.makefile
to make an executable.The printout when running the example should be:
Signal Go received in Pr1:Instance1 Signal Go received in Pr1:Instance2 Ok received with the following parameter:1 Ok received with the following parameter:2
Please read the section Real-Time Operating System Support for details about limitations that apply to all systems using Tight Integration.
No other limitations apply in the Solaris case.
#ifdef
) are used in this integration: SOLARIS_INTEGRATION
: Ensures that the sctsolaris.h
file is included in each C file. Must be set in all cases.XOS_TRACE
: Gives a textual trace for most of the SDL events by using printf to some device. This flag should not be used together with XMSC_TRACE
.XMSC_TRACE
: Will give a textual trace in the format of MSC/PR Z.120 by using printf. This trace is possible to view in the MSC Editor included in Telelogic Tau. This flag should not be used together with XOS_TRACE
.XMSC_EDITOR
: Used together with the XMSC_TRACE
flag, the MSC trace is automatically displayed in the MSC Editor. Note that you must have the Telelogic Tau Organizer open on your machine.X_ONE_TASK_PER_INSTANCE_SET
: Should be defined when the alternative runtime model is to be used.XINCLUDE_HS_FILE
: Includes the system signal header file which is required for tight integrations. This file maps signal names to integers.XRTOSTIME
: Should always be set for all tight integrations.SIMPLEEXAMPLE
: Creates an external task which send the Go signal into the system and receives the Ok return on successful completion of our SDL simple example system.TightIntegration
directory. simple.sdt
and generate a simple.c, simple.ifc
and simple.hs
file. Use the Cadvanced Code Generator and the options Lower Case, Generate environment header file and Generate signal number file.sccd.c
and sccd_<compiler type>.cfg
from <your SDT installation>/sdt/sdtdir/util/
sccd.c
file (open the file and follow the instructions). Rename sccd_<compiler type>.cfg
to sccd.cfg
makefile
to generate an executable. If you are using the SCCD program you need to add the sccd
command in front of the compiler command:sctCC = sccd cc
The output when running the example should be:
Process Pr1:/X1 created Process Pr1:/X2 created Process instance /X1 Pr1: nextstate Idle Process instance /X2 Pr1: nextstate Idle Process instance /X1 Pr1: input signal go Signal Go received in Pr1:Instance1 Process instance /X2 Pr1: input signal go Signal Go received in Pr1:Instance2 Pr1: process dynpr1:/Y4 created Pr1: nextstate Wait Process instance /Y4 DynPr1: Set timer t1 DynPr1: nextstate Wait_t1 Process instance /X1 Pr1: process dynpr1:/Y3 created Pr1: nextstate Wait Process instance /Y3 DynPr1: Set timer t1 DynPr1: nextstate Wait_t1 Process instance /Y4 DynPr1: input signal t1 DynPr1: signal terminating sent DynPr1: stopped Process instance /X2 Pr1: input signal terminating Pr1: signal ok sent Ok received in MyExtTask with parameter = 2 Pr1: dash nextstate Process instance /Y3 DynPr1: input signal t1 DynPr1: signal terminating sent DynPr1: stopped Process instance /X1 Pr1: input signal terminating Pr1: signal ok sent Ok received in MyExtTask with parameter = 1 Pr1: dash nextstate
The signal Go is sent from an external task MyExtTask
. The code for this task is placed in the program file MyExtTask.c
, as shown below:
#ifdef SIMPLEEXAMPLE #include "simple.hs" #include "simple.ifc" #ifdef X_ONE_TASK_PER_INSTANCE_SET void *MyExtTask(void *dummy) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; SDL_PId MyOwnPId; xPrsIdRec NameNodeStruct; xEPrsRec MyEPrsStruct; mqd_t QueuePId; int i; MyOwnPId=&MyEPrsStruct; MyOwnPId->NameNode=&NameNodeStruct; MyOwnPId->NameNode->PROCID="/ExtTask"; #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s", MyOwnPId, ": instancehead process ", "MyExtTask", ";"); RTOSMSCPRINT_STOP #else /* XOS_TRACE_STATIC_CREATE(MyPId, "MyExtTask") XMSC_TRACE_STATIC_CREATE(MyPId, "MyExtTask") */ #endif for (i=1;i<=2;i++) { yOutputSignalPtr = (xSignalHeader)xAlloc (sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Receiver = pr1[i]; yOutputSignalPtr->Sender = MyOwnPId; if (i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; #ifdef XMSC_TRACE SignalId = SignalId + 1; yOutputSignalPtr->SignalId = SignalId; yOutputSignalPtr->IsTimer = 0; #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s %d %s %lu %s", yOutputSignalPtr->Sender, ": out ", "go", ",", SignalId, " to ", pr1[i], ";"); RTOSMSCPRINT_STOP #else /* XMSC_EDITOR */ XMSC_FPRINT(("%lu: out %s,%d to %lu;\n", yOutputSignalPtr->Sender, "go", SignalId, pr1[i])) #endif /* XMSC_EDITOR */ #endif /* XMSC_TRACE */ QueuePId = mq_open((char *)pr1[i]->NameNode->PROCID, 2, 0, 0); mq_open_ERROR("MyExtTask", "mq_open", QueuePId) Err = mq_send(QueuePId, (char*)yOutputSignalPtr, sizeof(xSignalHeaderRec) + sizeof(yPDef_go),NULL); XOS_ERROR("MyExtTask", "mq_send", Err) Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } for(i=1;i<=2;i++) { yInputSignalPtr = xAlloc(4096); /*waiting for signal ok */ QueuePId = mq_open("/ExtTask",2,0,0); mq_open_ERROR("MyExtTask", "mq_open", QueuePId) Err_Rec = mq_receive(QueuePId,(char*)yInputSignalPtr,4096,NULL); if(yInputSignalPtr->SignalCode == ok) { #ifdef XMSC_TRACE #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s %d %s %ld %s", yInputSignalPtr->Receiver, ": in ", "ok", ",", yInputSignalPtr->SignalId, " from ", yInputSignalPtr->Sender, ";"); RTOSMSCPRINT_STOP #else /* XMSC_EDITOR */ XMSC_FPRINT(("%lu: in %s,%d from %lu;\n", yInputSignalPtr->Receiver, "ok", yInputSignalPtr->SignalId, yInputSignalPtr->Sender)) #endif /* XMSC_EDITOR */ #else /* XMSC_TRACE */ printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); #endif /* XMSC_TRACE */ } Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } Err = mq_unlink("/ExtTask"); XOS_ERROR("MyExtTask", "mq_unlink", Err) } #else void *MyExtTask(void *dummy) { xSignalHeader yOutputSignalPtr, yInputSignalPtr; int i; mqd_t QueuePId; #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%ld %s %s %s", "/ExtTask", ": instancehead process ", "MyExtTask", ";"); RTOSMSCPRINT_STOP #else /* XOS_TRACE_STATIC_CREATE("/ExtTask", "MyExtTask") XMSC_TRACE_STATIC_CREATE("/ExtTask", "MyExtTask")*/ #endif /*allocation of signal go */ for (i=1;i<=2;i++) { yOutputSignalPtr = xAlloc (sizeof(xSignalHeaderRec) + sizeof(yPDef_go)); yOutputSignalPtr->SignalCode = go; yOutputSignalPtr->Sender = "/ExtTask"; /*Integer parameter is assigned */ if (i==1) ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance1; else ((yPDef_go*)(yOutputSignalPtr+1))->Param1 = startinstance2; #ifdef XMSC_TRACE SignalId = SignalId + 1; yOutputSignalPtr->SignalId = SignalId; yOutputSignalPtr->IsTimer = 0; #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%s %s %s %s %d %s %lu %s", yOutputSignalPtr->Sender, ": out ", "go", ",", SignalId, " to ", pr1[i], ";"); RTOSMSCPRINT_STOP #else XMSC_FPRINT(("%lu: out %s,%d to %lu;\n", "/ExtTask", "go", SignalId, pr1[i])) #endif /* XMSC_EDITOR */ #endif /* XMSC_TRACE */ QueuePId = mq_open(pr1[i], 2, 0, 0); mq_open_ERROR("MyExtTask", "mq_open", QueuePId) Err = mq_send(QueuePId, (char*)yOutputSignalPtr, sizeof(xSignalHeaderRec) + sizeof(yPDef_go),NULL); XOS_ERROR("MyExtTask", "mq_send", Err) Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } for (i=1;i<=2;i++) { /*allocation of input signal */ yInputSignalPtr = xAlloc(4096); /*waiting for signal ok */ QueuePId = mq_open("/ExtTask", 2, 0, 0); mq_open_ERROR("MyExtTask", "mq_open", QueuePId) Err_Rec = mq_receive(QueuePId,(char*)yInputSignalPtr,4096,NULL); if(yInputSignalPtr->SignalCode == ok) { #ifdef XMSC_TRACE #ifdef XMSC_EDITOR RTOSMSCPRINT_START sprintf(msce_buf, "%lu %s %s %s %d %s %ld %s", "/ExtTask" , ": in ", "ok", ",", yInputSignalPtr->SignalId, " from ", yInputSignalPtr->Sender, ";"); RTOSMSCPRINT_STOP #else XMSC_FPRINT(("%lu: in %s,%d from %lu;\n", "/ExtTask", "ok", yInputSignalPtr->SignalId, yInputSignalPtr->Sender)) #endif /* XMSC_EDITOR */ #else printf("Ok received in MyExtTask with parameter = %lu\n", ((yPDef_ok*)(yInputSignalPtr+1))->Param1); #endif } Err = mq_close(QueuePId); XOS_ERROR("MyExtTask", "mq_close", Err) } Err = mq_unlink("/ExtTask"); XOS_ERROR("MyExtTask", "mq_unlink", Err) } #endif /* X_ONE_TASK_PER_INSTANCE_SET */ #endif /* SIMPLEEXAMPLE */