Programming in The OSEK-VDX Environment (With CD-ROM)
Programming in The OSEK-VDX Environment (With CD-ROM)
Programming in The OSEK-VDX Environment (With CD-ROM)
OSEK/VDX Environment
Joseph Lemieux
CMP Books
Lawrence, Kansas 66046
CMP Books
CMP Media LLC
1601 West 23rd Street, Suite 200
Lawrence, KS 66046
USA
www.cmpbooks.com
Designations used by companies to distinguish their products are often claimed as trademarks. In
all instances where CMP Books is aware of a trademark claim, the product name appears in initial
capital letters, in all capital letters, or in accordance with the vendor’s capitalization preference.
Readers should contact the appropriate companies for more complete information on trademarks
and trademark registrations. All trademarks and registered trademarks in this book are the prop-
erty of their respective holders.
Copyright © 2001 by CMP Books, except where noted otherwise. Published by CMP Books, CMP
Media LLC. All rights reserved. Printed in the United States of America. No part of this publica-
tion may be reproduced or distributed in any form or by any means, or stored in a database or
retrieval system, without the prior written permission of the publisher; with the exception that the
program listings may be entered, stored, and executed in a computer system, but they may not be
reproduced for publication.
The programs in this book are presented for instructional value. The programs have been carefully
tested, but are not guaranteed for any particular purpose. The publisher does not offer any war-
ranties and does not guarantee the accuracy, adequacy, or completeness of any information herein
and is not responsible for any errors or omissions. The publisher assumes no liability for damages
resulting from the use of the information in this book or for any infringement of the intellectual
property rights of third parties that would result from the use of this information.
v
vi Table of Contents
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355
xiii
xiv Foreword
ing the problem, in such a well-researched and comprehensive manner. OSEK/VDX has now
come of age.
Frank J. Leonhardt
Independent OSEK/VDX Working Group Member and consultant based in Europe
Preface
I was first introduced to the OSEK/VDX set of standards in 1998. During a meeting at my
employer’s European technical center, I mentioned that I was redesigning the division’s soft-
ware architecture in the United States. A European engineer asked if the new architecture
would be OSEK compliant. Not knowing anything about OSEK/VDX, I did what any good
engineer would do — I dodged the question by responding that many options were being
investigated. When I returned stateside, I immediately spoke with the software engineer
responsible for the new software architecture, and I began my journey into discovering what
OSEK/VDX was and, more importantly, what it was not.
The OSEK/VDX standards, like many specifications, were difficult to read and understand
and were written primarily by committee members who were not native English speakers. I
had to read many of the phrases three or four times to understand what was intended. In
addition, feature functionality was sometimes defined in many different sections. From this
effort, I wrote two articles for Embedded Systems Programming Magazine that provided an
overview of the specifications. These articles, The OSEK/VDX Standard: Operating System
and Communication and OSEK/VDX Network Manager and Implementation Language,
appeared in the March and April, 2000 issues. Next, I expanded the articles into a class,
which I still present for the Embedded Systems Conferences. The result of these articles and
classes is this book, which I hope will shorten the time it takes you to implement the
OSEK/VDX standard.
What is OSEK/VDX?
OSEK/VDX is a set of standards for a distributed, real-time architecture that was developed
by a consortium of European automobile manufacturers and suppliers in conjunction with the
University of Karlsruhe, Germany. It is primarily comprised of four standards: the operating
system (OS), communication (COM), network management (NM), and the OSEK implemen-
tation language (OIL). Three additional standards are in progress: the OSEK/VDX real-time
interface (ORTI), the OSEK/VDX Time-Triggered Operating System, also known as OSEK-
xv
xvi Preface
Time, and the OSEK/VDX Fault Tolerant Communication specification. ORTI defines a real-
time interface for application development with the use of third-party tools. OSEKTime is an
extension of the existing standards that address the specific nature of time-critical applica-
tions, such as stear-by-wire and brake-by-wire in automobiles. The OSEK/VDX Fault Toler-
ant Communication specification is also intended for time critical applications that include
time critical communication. Because I am not involved in either of these efforts and because
they are still evolving, I cannot comment on them at this time.
Acknowledgments
First I acknowledge the loving support of my family: my wife, Jennifer, and my two darling
children, Megan and Kyle. I have noticed in many books that the family is acknowledged
first. I always thought that this was a very nice gesture, demonstrating the love of one’s fam-
ily. It was not until I wrote this book that I understood the tremendous sacrifices a family
makes while a family member is writing. The support that my wife gave me while I focused
on the book, instead of assisting in the maintenance of our home and family, was tremen-
dous. Thanks a lot Jennifer!
The second major contributor has been Wind River Systems, Inc., who provided all the
software and some of the hardware that I used to develop the applications in this book.
Included in this software was the Tornado Development Environment, the OSEKWorks
implementation of the OSEK/VDX standards, the Diab toolchain for the Motorola Power PC
MPC555 processor, and the EST VisionProbe Debug Interface with VisionClick software.
The development of the example program provided an opportunity for me to increase my
understanding of the actual operation of each service. Wind River Technical Support was
extremely responsive in answering questions on the workings of OSEKWorks and on their
interpretations of the standards. They also corrected some of my misinterpretations of the
standards. In particular, I would like to thank Michael O’Donnell, the Business Development
Manager for Wind River in the Detroit area, Gary Bourdon, the Product Marketing Manager
for OSEKWorks, and Venkat Viswanathan and Thomas Yu from the Wind River Technical
Support team. Their support in making sure that I had the right software and equipment and
knew how to use it was critical in the success of this book.
Acknowledgments xvii
The hardware on which this book was written was provided by Axiom Manufacturing. I
thank them for providing this equipment at a discount so that I could get up to speed rapidly.
Axiom Manufacturing develops a line of low-cost development boards for various processors
that are ideal for evaluation and prototyping of both hardware and software systems.
I would also like to thank Frank Leonhardt, who has been a member of the OSEK/VDX
Technical Committee since 1997 and who provided significant insight into the background of
the standards, in particular the communication standard. Mr. Leonhardt also reviewed the
entire book to ensure the technical accuracy of the statements, and provided valuable addi-
tions in many areas.
Finally, and not least, I thank the Applied Engineering Solutions organization of Elec-
tronic Data Systems (EDS), my employer. As crunch time came, they provided me with the
time I needed to finish the book. In particular, I thank Mohamed Ashmawey, my direct leader,
for his support and encouragement while I was writing this book, and John Huth, our Client
Delivery Executive, who supported my assignment to an in-house project so I could maintain
my focus on writing this book.
xviii Preface
1
2 Introduction
the software and the service. It is not intended to, and frequently does not, illustrate the best
way to implement the intended function.
Although an I/O standard was not developed by the OSEK/VDX committee, it is strongly
recommended by the committee that the user develop a standard method. This topic is out of
the scope of this book and is not covered.
History of OSEK/VDX
OSEK, a German acronym for Offene Systeme und deren Schnittstellen für die Elektronik im
Kraftfahrzeug, which translates roughly to Open Systems and their Corresponding Interfaces
for Automotive Controllers, was initiated in Germany in May 1993 by the automotive com-
panies BMW, Daimler Benz (now DaimlerChrysler), Opel, and Volkswagen; the major auto-
motive suppliers Bosch and Siemens; and the Institute of Industrial Information Technology
at the University of Karlsruhe, Germany. VDX, an acronym for Vehicle Distributed eXecu-
tive, was initiated in France about the same time by the French automotive companies PSA
and Renault. In 1994, the two consortia merged to form the OSEK/VDX Consortium and
created the OSEK/VDX Steering Committee. Since that time, other companies have joined as
members of the Technical Committee to assist in developing the technical standards.
The original motivation for the standards was to resolve the problems of increasing soft-
ware content in automobiles, duplication of effort in the areas of operating systems and com-
munication networks, lack of qualified software engineers, and a desire for high-quality
products. The goal was to develop a standard API that could reduce the amount of duplicated
effort and increase the amount of code reuse within the vehicle. The result was the three stan-
dards in existence today: Operating System (OS), Communication (COM), and Network
Management (NM). Although originally intended for the automobile environment, the speci-
fications have been carefully developed to meet the requirements of a small embedded system
with interprocessor communication.
Throughout the book, an API service has the format ApiService(); references to operating
system tasks will have the form TaskName. Although a task is typically a function in C, I have
eliminated the parentheses to illustrate the difference. All other OSEK/VDX objects, such as
alarms, events, and messages, are in capital letters (e.g., ALARM_OBJ).
Flow of Book
Each of the three OSEK/VDX standards was written to stand alone and can be implemented
independently of each other. This book follows that format and is written in parts, with each
part corresponding to one of the major OSEK/VDX standards. The reader can choose to read
the parts in any order based on which components of the standard are being implemented.
However, because the example program uses all components of a complete implementation
and builds on previously developed concepts, I recommend that you read the book sequen-
tially. The OSEK/VDX standards do not explicitly cover I/O in any standard. The Technical
Committee does address I/O by strongly encouraging each company to develop a standard
hardware abstraction methodology to allow for maximum portability of application compo-
nents within the company. Figure 1 shows a typical application, with each standard identified
as a separate block, and the relationships also shown.
Application
OS NM
Tasks
I/OLayer COM
PhysicalLayer
4 Introduction
Part 2: Communication
The communication standard is covered in the second part of the book. Interprocess and
interprocessor communication is specified in this standard. Communication conformance
classes also are introduced, along with the different types of messages. This standard works
with an OS that provides certain services, but it does not have to be an OSEK/VDX OS. It
also works in systems that have minimal OS support, such as simple round-robin schedulers
and time-sliced executives.
The COM standard defines three layers: interaction, network, and data link. This book
focuses primarily on the interaction layer because it is the only one visible to the application.
However, knowledge of the other layers is required to some extent to understand how the sys-
tem works and to enable message configuration. Therefore, a high-level discussion of these
layers is provided.
Example Program
I develop the example program, an electronic blackjack game for 1 or 2 players, throughout
this book. It is intended to demonstrate all aspects of the standard without focusing on the
automotive origins. The requirements of the card game are defined in Table 1.
Example Program 5
Requirement
Description
Number
1 System plays one game — Blackjack.
2 If no other systems are connected, the system defaults to a single-player
game against the dealer.
3 When another player connects, the system allows either player to start a
head-to-head game.
4 The program only allows the player to request a head-to-head game
between local hands.
5 The system allows players to send messages while connected. The players
do not have to be playing head-to-head.
6 The dealer in a single-player game must hit at 16 and stay at 17. Five cards
under 21 automatically wins.
7 The dealer in a head-to-head game is not limited to the previous require-
ments.
8 In head-to-head play, the deal rotates between two players when fewer
than 10 cards remain in the deck at the beginning of a new hand.
9 When a player drops out of a game, the system immediately terminates the
current game and returns to a single-player game against the dealer.
Each chapter includes snippets of code from the example application, and the final section
in each chapter describes the code for the entire example application using the API routines
described to that point. Exercises provide hands-on practice. The application was developed
using Wind River System’s Tornado for OSEKWorks and two Axiom Manufacturing CME
555 development boards incorporating a Motorola MPC555 Power PC microcontroller. The
example code included on the CD can be used as-is with these two systems. However, if you
use another system, some code changes will be needed. In keeping with the goal of
OSEK/VDX, these changes are primarily in the I/O layer and the configuration files. The loca-
tion of these changes are clearly marked in the code, along with the interface requirements. It
is left to the reader to make the modifications.
The accompanying CD is described in more detail in Appendix B, including installation
and modification of files for different OSEK/VDX environments. Included on the CD is the
entire source code for each chapter to enhance learning while studying this book. The com-
plete OSEK/VDX standards are also included for reference. Because the standards are copy-
righted material, the following copyright notice is included in the documents and reproduced
here at their request.
“This document is an official release and replaces all previously distributed documents.
The OSEK group retains the right to make changes to this document without notice and
does not accept any liability for errors. All rights reserved. No part of this document may
be reproduced, in any form or by any means, without permission in writing from the
OSEK/VDX steering committee.”
6 Introduction
7
This Page Intentionally Left Blank
1
Chapter 1
Implementation Startup
After you have decided on the OSEK/VDX operating system (OS), you must choose which
implementation to use. An implementation refers to how a development company realizes the
OS standard. Unlike many other OSs, OSEK/VDX is an open standard, and many companies
have created implementations for different processors. This differs from Linux, which is an
open-source system; only one implementation of the kernel exists, which is controlled by
Linus Torvalds’ team. Implementation features and capabilities vary from those that just meet
the standard to full-blown systems that include the integrated development environment
(IDE) with an OSEK/VDX-aware debugger.
To determine which implementation to use, you should analyze many factors. Appendix A
lists some questions that may help you analyze these factors. This book uses examples that
can be used immediately if you already have an OSEK/VDX OS implementation and have
installed it per the instructions. If you have not yet chosen an implementation, this book can
help you make the best choice. After obtaining an implementation, return to the examples in
this book to help you get up to speed.
This chapter shows you how to get your system running and ready for the OS. This
includes the system boot, the C entry point main(), and the first OS interface, StartOS().
Finally, you’ll learn about the OSEK/VDX implementation language (OIL). By the end of this
chapter, your system should be up and running and doing absolutely nothing! Don’t worry,
you will add features and functions later.
9
10 Chapter 1: Implementation Startup
_MemMap:
lwz r3,0(r5) #Get next register value
stw r3,0(r4) #Store to register
add r4,r4,r7 #Update pointers
add r5,r5,r7
sub. r6,r6,r7
bne cr0,_MemMap #Continue if not complete
bl InitReg16
;# Initialize C variables
bl cinit
InitReg16(InitHardwareRegs16);
InitReg32(InitHardwareRegs32);
InitSystem(INIT_RESET);
while(1){
StartOS(SINGLE_PLAYER);
}
}
The first step is to initialize the application-specific microcontroller registers, which typi-
cally control the I/O ports. The example application uses InitReg16() and InitReg32() to
perform this initialization. I wrote these functions to assist in register initialization; they are
not part of an OSEK/VDX implementation. Because MPC555 registers are two different
lengths — 16 and 32 bits — two functions allow you to create an efficient routine that fills
the registers from a table constructed with 16- or 32-bit values. With just one function, the
table would have to include the size of the registers, the routine would be slower and not
much smaller, and the tables would be much larger. The argument for each function is a
pointer to a table of register description structures, which the routine navigates and which are
defined in the init.cfg configuration file. At this point, the lists are empty because I have not
defined the hardware functions. These lists are filled in later.
Now the application has to be initialized. At this point, it is put into a state in which it is
ready to be run by the OS. Because the OS is not functioning yet, no OS calls can be made.
The application-specific initialization functions are invoked using InitSystem(), which I
developed to aid in system initialization. This function accepts an argument that defines the
type of initialization to be performed and navigates a predefined table of initialization func-
tion calls. Each application has only one table of function calls defined in init.cfg. At this
14 Chapter 1: Implementation Startup
stage in the application, only the INIT_RESET type of initialization is performed. (You will see
other types of initializations throughout this book.) The application developer is responsible
for ensuring that the initialization functions do not call OS API services.
The application can use the APPMODE of an OSEK/VDX OS to modify its operation. This
concept is discussed in detail in . The current APPMODE is defined by the application when the
OS is started. At least one APPMODE must be defined, but the OSEK/VDX standard does not
define a limit for the maximum number of modes. However, each implementation sets a limit
based on the size of the memory variable used to store the mode. I have defined just one APP-
MODE, SINGLE_PLAYER, to enable the system start.
The start of the OS is performed using the API call StartOS(), which is described in more
detail in Chapter 2. Because the OSEK/VDX OS is capable of being started and stopped with-
out a reset, this interface is enclosed in a while(1) loop, which can be expanded in the future
to include more processing outside of the OS execution. The argument to StartOS() is the
default application mode SINGLE_PLAYER.
The final routine in the main module of the example is ChangeMode() and is specific to a
particular application. ChangeMode() is responsible for changing the APPMODE of the system
based on requests from the user. In the example application, this routine first checks that a
valid mode is requested then shuts down the OS using the API call ShutdownOS(). Because this
routine is specific to the application, it can be modified to ensure that a shutdown can occur
safely. If not, the routine should return an error. The OSEK/VDX OS then usually returns
from the previous StartOS(), where main() restarts the OS using the default APPMODE. This
might seem like a lot of code to do nothing, but as you will see in later chapters, these func-
tions will be expanded extensively. The ChangeMode() routine is shown in Listing 1.3.
The OIL configuration file appears similar to a C structure definition. It consists of objects
that correspond to the objects in the OS, with a minimum set of attributes that are defined for
each object. An attribute can be required (mandatory) or optional. Because the OIL standard
only defines the minimum attributes for each object, an actual OSEK/VDX implementation
may define additional attributes. Because these attributes are not portable, they should be
16 Chapter 1: Implementation Startup
/**************************************************/
/* Application Modes */
/**************************************************/
APPMODE SINGLE_PLAYER {
VALUE = AUTO;
};
/**************************************************/
/* O/S */
/**************************************************/
OS OSEKWorks_os {
CC = AUTO;
STATUS = EXTENDED;
SCHEDULE = AUTO;
SYSTEMSTACKSIZE = 1024;
StartupHook = FALSE;
ErrorHook = FALSE;
ShutdownHook = FALSE;
PreTaskHook = FALSE;
PostTaskHook = FALSE;
};
};
The CPU object is defined first in the OIL file and is a container object for all other objects
defined for the configuration. In this example, the CPU object is called cardgame because there
is only one CPU in this application. The CPU object has no attributes.
Within the cardgame CPU object are five additional objects. The first is a TASK object. Most
implementations require that at least one TASK is defined to operate. To compile the program,
I defined a do-nothing task that immediately terminates itself. This task is included in main.c
and is shown in Listing 1.5. It is probably a good idea to add this task as a sanity check when
the system is started. Place a breakpoint at the entrance to this task to verify that the OS has
started properly.
The final object, OS, defines the parameters of the OS configuration used on the cardgame
processor. Only one OS object can be in each CPU; consequently, I have chosen to leave the
name as OSEKWorks_os, which is the default name in the Wind River system. Other implemen-
tations will have different default names. Six required attributes are in this object: STATUS,
STARTUPHOOK, SHUTDOWNHOOK, PRETASKHOOK, POSTTASKHOOK, and ERRORHOOK. STATUS defines the
return status of each OSEK/VDX OS API service and is either STANDARD or EXTENDED. The
return status is discussed in more detail in later chapters. The other five attributes define the
existence of each of the hook routines within the application and are either TRUE or FALSE.
The application provides the hook routines, which are introduced in later chapters. At this
time, the OS operates in EXTENDED status and the application does not define any of the hook
routines.
The provider of the implementation usually adds many attributes in the OS object. Because
each microcontroller has its own quirks, the OS object is the most likely section in which to
add attributes that configure the microcontroller-specific features. The added attributes in
Wind River OSEKWorks are defined in Table 1.1. Similar attributes can exist in any imple-
mentation; unfortunately, a naming standard for these attributes does not exist, so names will
likely be different between implementations.
Attribute Description
CC Conformance class for the application. With this attribute, the
configurator can force a conformance class of AUTO, BCC1, BCC2,
ECC1, or ECC2 and can generate an error if the class is violated.
SCHEDULE Like CC, can force the scheduling policy for the application. Valid
values are AUTO, NON, FULL, or MIXED with respect to preemption.
SYSTEMSTACKSIZE Reserves a set amount of system stack space that can be set by the
application developer.
1.4.1 Modules
The “Modules” section, included in all chapters, describes each of the source code modules
found in the src directory.
startup.s The startup.s module contains the startup assembly language code that is
entered when the microcontroller is reset. Its only function, _cstart, is entered when the sys-
tem is reset; trap vectors also are used in case other exceptions occur. This module is specific
to the microcontroller being used and needs to be modified extensively if you use this code on
anything other than an MPC555-based system. The good news is that this module is the same
throughout the book.
initspr.s The initspr.s module contains the assembly language code that sets the spe-
cial-purpose registers of an MPC555 microcontroller. Its only function is InitSPR(), which is
called from startup.s. It is required because of the inherent nature of addressing special-pur-
pose registers in the PowerPC type of processor. This module is not required in systems using
a different microcontroller, but a similar module might be required.
cinit.s The cinit.s module contains two functions, InitRAM() and cinit(), which ini-
tialize RAM to a known value as well as all the C initialized variables. The cinit() function
is usually provided by the supplier of the compiler and might have a different name or be inte-
grated into a startup module. I developed InitRAM() to initialize memory. Both of these
assembly language functions use registers alone and do not require that any memory is initial-
ized or available.
init.c The init.c module contains the routines that support initialization of the micro-
controller registers and the application. At this point, only three services are available to the
application.
void InitSystem(InitType type); This service invokes a series of functions that are
registered by the application in init.cfg and that allow the application to initialize itself
based on a specific application-wide event. This event is defined in the parameter type,
and can be any of the values defined in the InitType enumeration that appears in init.h.
This routine invokes all of the functions in the list InitFunctionList, regardless of the
value of the parameter type. InitFunctionList is defined using the macros in init.cfg,
which create this constant array. The initialization function defined in this list is responsi-
ble for determining the actions to be taken based on the initialization type, which is also
forwarded as a parameter to each function. As the example application is developed, ini-
tialization functions will be added to new modules to ensure that the application is in the
proper state.
main.c The main.c module contains two functions and one OS task. This module will be
expanded throughout the book to include functions and tasks that are applicable to the entire
application. The two functions are described below.
void main(long argc); This is the C entry point that is called from startup.s. For
my particular startup system I allow the startup code to pass one argument defined as a
long integer. At this point, the startup code always passes a 0, but it can be modified to
pass information that indicates the type of startup that occurred, such as a hard reset, a
watchdog timeout, or another exception. This routine performs all functions required out-
side of the OS function for the application and invokes the service that starts the OS. It
does not return to the startup code in the OSEKWorks implementation, but it may on
other systems.
The only task included in main.c is the background task: a do-nothing task that is
expanded in future chapters.
cardgame.oil This is the OSEK/VDX OIL configuration file that is produced by the config-
uration utility. It contains all the information used to generate the specific implementation of
Exercises 21
the OSEK/VDX OS. Do not edit this file directly if you have a GUI-based configuration util-
ity.
init.cfg This file contains the configurations for the register initialization tables and the
function initialization table. These tables are constructed by macros that start the table, add a
new entry to the table, and close the table at the end. Refer to the comments in the configura-
tion file for a description of how the macros are used.
1.5 Exercises
Now that you understand the modules in the example program, it is time to change them.
The best way to learn a new OS is to start using it. The exercises at the end of each chapter
are intended to allow you to play with the software and become more familiar with how the
system operates. At this point, you will become most familiar with your development tools,
such as your compiler and debugger. However in later chapters, you will make changes that
use the services of the OSEK/VDX OS.
1. Determine the source of the reset that put you into the startup.s module. Pass this value
to main() as the argument, then within main(), save this value to a global variable.
2. Modify the RAM initialization routine to check whether memory has been compromised
before initialization. If memory has not been compromised, skip memory initialization
and C initialization. Pass this information, combined with the type of reset, to main().
Hint: The MPC555 has a register that indicates whether memory integrity is questionable.
Other microcontrollers will require a different algorithm.
3. Expand the definition of the InitType enumeration to include possibilities based on the
type of reset and the integrity of the memory after the reset. Pass this information to Init-
System().
4. Add some registers to the initialization lists to put the system into a different state than the
default state on reset. For example, switch some digital ports into output mode and set
them to a default value of either on or off. You might want to add an LED to a port to
observe the initial values.
5. Modify the background task so that it immediately calls ChangeMode() with the requested
mode of SINGLE_PLAYER. Then use the debugger to observe what happens as the applica-
tion enters and exits the OS.
1.6 Summary
This chapter has defined the items required to get an OSEK/VDX OS implementation up and
running on a specific target hardware system. The boot code provides the method to get the
hardware functioning and then enters the C startup function main() with the proper parame-
ters. The purpose of main() is to provide any further application-specific initialization of the
hardware and to start the OS.
ChangeMode() was added to allow the application to change mode at any time because
OSEK/VDX does not allow the APPMODE to be changed directly without shutting down and
restarting the OS. ChangeMode() verifies that the new mode is valid before shutting down the
OS and allowing main() to restart.
22 Chapter 1: Implementation Startup
Finally, the OSEK/VDX implementation language (OIL) was introduced and the objects
required to get the system up and running were defined. The result is a fully operational
OSEK/VDX application that can be used to set up an implementation when it is first pur-
chased. This book will now expand upon this application to include more of the OS services.
2
Chapter 2
23
24 Chapter 2: Starting and Ending
mode, a manufacturing mode, a diagnostic mode, and so on. These APPMODEs are then used to
design the individual application modules and to define their functions. In the example here,
the only APPMODE defined to this point is the SINGLE_PLAYER mode.
Three modes will be defined in this example program: a single-user mode (SINGLE_
PLAYER), a multiplayer mode (HEAD_TO_HEAD), and a test mode (TEST). The single-user mode is
a single user playing a card game against the computer and is the default mode after a reset.
The multiplayer mode will be added at a later time when discussing the communication and
networking portions of the OSEK/VDX standard. The test mode is based on communication
over a serial port and is intended to be used at the end of the manufacturing line to test and
diagnose the display and the keypad. This mode is not implemented in this book, but you can
implement it as a way of developing your skills. The OSEK/VDX implementation language
(OIL) configuration for the APPMODEs is shown in Listing 2.1.
AppModeType GetActiveApplicationMode(void);
An application uses this service to determine the active APPMODE and then uses this infor-
mation to modify its operation. ChangeMode() is expanded from a previous example to
include a check of the requested APPMODE and compare it to the current mode. If the current
and requested modes are the same, then the function returns with no error. At this point, mul-
tiplayer mode is not allowed because networking is not supported. However, the multiplayer
and test modes are valid APPMODEs in the OIL file; consequently, if ChangeMode() is called with
a request to enter either of these modes, the request is ignored and an error is returned. The
resulting function is shown in Listing 2.2. ShutdownOS() is considered later in the section
when I discuss shutting down the OS.
Startup 25
if(mode != GetActiveApplicationMode()){
if((mode == SINGLE_PLAYER)){
SelectedMode = SINGLE_PLAYER;
ShutdownOS(E_OK);
}
if((mode == HEAD_TO_HEAD)){
error = ERROR_INVALID_MODE;
}
if((mode == TEST)){
error = ERROR_INVALID_MODE;
}
error = ERROR_INVALID_MODE;
}
return error;
}
2.2 Startup
After the APPMODEs are defined, the example program must be modified to use them. The
updated main() is shown in Listing 2.3.
InitSystem(INIT_RESET);
SelectedMode = SINGLE_PLAYER;
while(1){
StartOS(SelectedMode);
}
}
26 Chapter 2: Starting and Ending
void StartupHook(void);
During StartupHook(), all system interrupts are disabled and the application has limited
access to the OS services. The available services are GetActiveApplicationMode(), Acti-
vateTask(), and ShutdownOS(). ActivateTask() is discussed in more detail in Chapter 4. In
the example application, I have added StartupHook() in main(). It performs only one task: It
calls InitSystem(), as defined in Chapter 1, but with an argument of INIT_STARTUP. The
individual initialization routines then can check the current APPMODE and perform any applica-
tion-specific initialization required. This hook routine is shown in Listing 2.4.
2.3 Shutdown
The OS is shutdown using the OS API service ShutdownOS().
void ShutdownOS(StatusType);
When ShutdownOS() is called, the OS first checks to see if the hook routine ShutdownHook() is
defined, and if so, it is invoked and the StatusType passed in the original call is also passed to
the hook routine. The routine ShutdownHook() is created by the application programmer.
Shutdown 27
void ShutdownHook(StatusType);
During ShutdownHook(), the application might or might not return. If the error is severe
enough, the application might try to recover from the error by forcing the system into a reset.
The only OS API service that can be evoked from this hook routine is GetActiveApplica-
tionMode(). When ShutdownHook() returns, the OS then closes all objects opened during star-
tup and returns from the previous call to StartOS(). Control is now back in the hands of the
application in main().
One ShutdownHook() limitation concerns the existence of a new OSEK/VDX specification
called OSEKtime OS. It is also referred to as TT (time-triggered). This new specification,
which had not been released at the time of publication of this book, is a forced real-time
scheduler extension intended for time-critical applications such as drive-by-wire and brake-
by-wire. It is possible that an individual application will have both versions of the
OSEK/VDX OS running, in which case, ShutdownHook() must return. The ShutdownHook()
used in the example program is shown in Listing 2.5.
SCHEDULE = AUTO;
SYSTEMSTACKSIZE = 1024;
StartupHook = TRUE;
ErrorHook = FALSE;
ShutdownHook = TRUE;
PreTaskHook = FALSE;
PostTaskHook = FALSE;
};
2.5 Exercises
1. Add an APPMODE called END_OF_LINE to the application and check for a change in Change-
Mode(). Do not do anything at this time if the user requests a change to the new mode.
2. In StartupHook(), if the APPMODE is END_OF_LINE, call InitSystem() with a new value of
INIT_EOL.
3. Set breakpoints at the hook routines and the background task. Run the program and verify
that the hook routines execute properly.
2.6 Summary
This chapter showed how to complete the skeleton of the main module of the application.
The functions defined here can be used as a basis on which to build an entire application. The
three functions — main(), StartupHook(), and ShutdownHook() — are typical of functions
you would find in an OSEK/VDX application. The other function, ChangeMode(), was added
so that the application could define a new operating environment. Although this function is
not required and is not typical of an OSEK/VDX application, it might be helpful in a real-
world application.
3
Chapter 3
Development Support
Two more characteristics of the OSEK/VDX OS need to be discussed before developing the
application. Almost all of the functions in the OSEK/VDX API have a StatusType return
type, which returns an error code based on the results of the API service. The other character-
istic discussed in previous chapters is hook routines. This chapter introduces the features that
aid the developer in debugging the application. After this, you will be ready to address the
meat of the OS and the application.
29
30 Chapter 3: Development Support
When debugging is complete, the system has been tested, and the application is ready for
release, standard reporting status is enabled in the OIL configuration file. In standard status
mode, most API services only return E_OK.
The OSEK/VDX standard defines two types of errors: application errors and fatal errors.
An application error occurs when an API service is unable to complete the service because the
data or the OS state is invalid. The API service returns the error to the calling function and
the service is not performed. Any values referenced by parameters that were passed as argu-
ments to the service are undefined on return. A fatal error occurs when the API identifies that
its internal data might be corrupted. In this case, the OS does not return to the calling func-
tion; rather, it shuts itself down and returns to the function that called StartOS().
As with system startup and shutdown, the application can define a hook routine that is
invoked after an application error is detected.
void ErrorHook(StatusType);
ErrorHook() is called at the end of an API service routine, and immediately before returning
to the calling function, if the return is other than E_OK. It is also called if an error occurs when
an alarm expires or a message is transmitted or received, although OSEK COM might call a
different ErrorHook(), especially when mixing OS and COM modules from different vendors.
ErrorHook() is never called recursively.
For the application here, I have defined an ErrorHook() that keeps a running buffer of the
last 10 errors identified by the system. The complete routine is shown in Listing 3.1 and has
been added to a debug module found in debug.c.
OS OSEKWorks_os {
CC = AUTO;
STATUS = EXTENDED;
SCHEDULE = AUTO;
SYSTEMSTACKSIZE = 1024;
StartupHook = TRUE;
ErrorHook = TRUE;
ShutdownHook = TRUE;
PreTaskHook = TRUE;
PostTaskHook = TRUE;
};
debug.c This module contains all routines used by the application to assist in system run-
time debugging. At this point, the module only has the three hook routines described in detail
in this chapter. Additional debugging functions are added to this module in the exercises
presented throughout the book.
32 Chapter 3: Development Support
3.4 Exercise
1. Set a breakpoint at the entrance to each of the hook routines, including StartupHook().
Run the program and observe the sequence of events as the program starts and executes,
then terminates, the background task.
3.5 Summary
This chapter introduced briefly how an OSEK/VDX OS processes errors and provides debug-
ging capability. In Chapter 4, I will define the basic application building block — the task.
4
Chapter 4
Tasks
The first and most importing concept in the OSEK/VDX OS is the task. As you might remem-
ber from the previous chapters, even the simplest application required defining a small task.
The task in the example program, a game of blackjack, was called background. It did abso-
lutely nothing except terminate itself on startup; however, without it, the OS could not be
built.
This chapter describes tasks as they relate to the OSEK/VDX OS. First I’ll discuss the
overall task model and the attributes of an individual task. Next, I will discuss each of the
interfaces of the OSEK/VDX API that relate to tasks. Finally, I will discuss the scheduling pol-
icies of the OSEK/VDX OS.
33
34 Chapter 4: Tasks
SUSPENDED
activate
terminate
start
RUNNING READY
preempt [SCHEDULE=FULL]
Because OSEK/VDX is a statically defined OS, all tasks must be defined at compile time.
When the OS is started by StartOS(), a basic task is started either in the SUSPENDED or READY
state, depending on the configuration in the OIL file. If a task is defined as an AUTOSTART task,
then it starts in the READY state; otherwise, it starts in the SUSPENDED state. The task then flows
through the transitions shown in Figure 4.1 based on the events that occur. More details on
task transitions are discussed in the section “Scheduling.”
The advantage of a basic task is using the minimal amount of resources required to sup-
port it. Because a basic task inhibits not only the lower priority tasks but also other tasks at
the same priority, the amount of stack space required is minimized. Basic tasks usually are
used in instances where interprocess synchronization is not required.
Task Model 35
For the example program, I created a basic task, IOSampleKeypad, which samples the key-
pad, debounces the input, then activates another task whenever a key is pressed. The task is
shown in Listing 4.1 and can be found in the module input.c.
while(1){
tempKey = HWGetValue(&KEYPAD);
if(tempKey == lastKey){
if(keyCount++ == KEY_DEBOUNCE_TIME){
--keyCount;
keyValue = tempKey;
}
}
else{
keyCount = 0;
lastKey = tempKey;
}
if(keyState==FALSE){
if(keyValue != 0){
keyState = TRUE;
ActivateTask(ProcessKeyPress);
}
}
else{
if(keyValue == 0){
keyState = FALSE;
}
}
for(delayTimer = 1000;delayTimer>0;delayTimer--){
Schedule();
}
}
}
36 Chapter 4: Tasks
The API services ActivateTask() and Schedule() found in this task are described later in
this chapter. The HWGetValue() task encapsulates the hardware interface to the keypad and
returns the ASCII code of the key that was pressed. This function is not discussed in this
book, but you should be able to understand the source code on the CD.
The task is defined in the source module with TASK(IOSampleKeypad). All OSEK/VDX
implementations are required to use this macro to encapsulate the implementation-specific
formatting of the task definition. The C name of the function that corresponds to the task
usually is created by either prepending or appending the task name with an implementation-
specific tag. The function can then be viewed with the debugger using this mangled name. See
the implementation documentation for what this tag is and how the task name is mangled for
the OS.
This basic task uses a while(1) loop, which creates some limitations. The first is that this
task must be the lowest priority in the system, and no other tasks with the same priority can
exist. The second is that a keypad press could be missed if the higher priority tasks consume
too much processor throughput. At this point, the system is still simple, and these limitations
are not a concern. As you learn about more features of the OSEK/VDX OS, you can modify
this task extensively to streamline the operation. When complete, it will resemble a typical
keypad processing routine with a buffer of key presses. The other API services listed in this
task are defined throughout this chapter.
4.1.3 Priority
As with any RTOS, tasks in an OSEK/VDX OS have a priority, which is statically defined and
cannot be changed dynamically by the application. In one case, however, the OS does change
the priority of a task: When the priority ceiling protocol is active, the priority of a task is ele-
vated to the priority ceiling value calculated statically. This protocol is discussed in Chapter 7,
“Resources.”
Task Model 37
SUSPENDED
terminate activate
preempt [SCHEDULE=FULL ]
RUNNING READY
start
wait
trigger
WAITING
4.1.5 Preemption
Every task, whether basic or extended, can be defined as having either no preemption or full
preemption. A task with no preemption essentially runs until it terminates or, in the case of
extended tasks, until it makes the transition into the WAITING state. Even with no preemption
capability, a task can still perform cooperative multitasking using the API service Schedule().
StatusType Schedule(void);
Schedule() checks for the task with the highest priority that is in the READY state and
transfers processor control to it. The system only returns to the original task when all higher
priority tasks are complete; then the original task again becomes the highest priority task.
This service does not allow cooperative multitasking among tasks with the same priority
because only higher priority tasks are allowed to execute. The calling task is immediately
resumed if no higher priority tasks are ready. This service is not allowed at interrupt level.
In standard API return type mode, E_OK is always returned. Under extended status, Sched-
ule() can also return E_OS_CALLEVEL if called from interrupt level.
The IOSampleKeypad task is defined as non-preemptive at this time to better demonstrate
the operation of Schedule() and ActivateTask() when a key is pressed. To allow cooperative
multitasking, Schedule() is called continuously within a delay loop. This programming
device will not be required when the task is defined as preemptive, so the loop is removed in
later chapters.
TASK IOSampleKeypad {
TYPE = BASIC;
SCHEDULE = NON;
PRIORITY = 0;
ACTIVATION = 1;
AUTOSTART = TRUE;
STACKSIZE = 64;
SCHEDULE_CALL = TRUE;
};
TASK OutputDisplay {
TYPE = BASIC;
SCHEDULE = FULL;
PRIORITY = 3;
ACTIVATION = 1;
AUTOSTART = FALSE;
40 Chapter 4: Tasks
STACKSIZE = 64;
SCHEDULE_CALL = FALSE;
};
TASK ProcessKeyPress {
TYPE = BASIC;
SCHEDULE = FULL;
PRIORITY = 2;
ACTIVATION = 1;
AUTOSTART = FALSE;
STACKSIZE = 64;
SCHEDULE_CALL = FALSE;
};
The attributes available for each task and defined in the OSEK/VDX standard follow.
• PRIORITY The priority of the task from 0 to the maximum allowed by the implementa-
tion (eight priorities must be supported; using more can lead to portability problems).
• SCHEDULE Either NON or FULL. SCHEDULE defines the type of preemption allowed for this
task.
• AUTOSTART Set to either TRUE or FALSE. AUTOSTART defines whether the task is moved into
the READY state automatically by the StartOS() API service.
• RESOURCE Defines a reference to a resource that is used by this task. This is an optional
attribute that can have multiple instances. I discuss resources in more detail in Chapter 7.
• EVENT Defines a reference to an event that is controlled by this task. This is an optional
attribute that can have multiple instances. I discuss events in more detail in Chapter 6.
• ACCESSOR Defines an optional accessor for a message used within a task. Multiple acces-
sors can be defined for each task. The value of this attribute is either SENT or RECEIVED and
includes its own references. The subattributes are MESSAGE, WITHOUTCOPY, and ACCESSNAME.
These subattributes are discussed in more detail in Chapter 9.
• STACKSIZE The size of the stack required by that particular task. STACKSIZE is not
defined in the OSEK/VDX OIL specification; however, it is discussed in the sample implemen-
tation. Because it is not required by the specification, do not expect to see it in all implemen-
tations.
• SCHEDULE_CALL Defines whether the API service Schedule() can be invoked from a task.
If set to TRUE, a non-preemptive task can use Schedule() for cooperative multitasking, as
defined ealier in this chapter.
4.4 Scheduling
Task switching within an OSEK/VDX OS is performed by a scheduler using one of three pos-
sible policies: non-preemptive, fully preemptive, or mixed preemptive. Each one of these poli-
cies are discussed in detail in this section.
As mentioned earlier in this chapter, the scheduler uses task priorities to determine which
singular task is in the RUNNING state. Each task is defined with a static priority that cannot be
changed by the user at run time. The lowest available priority is 0, and the highest available
priority is specific to the implementation.
In the case of conformance classes ECC2 and BCC2, multiple tasks can have the same pri-
ority, and individual basic tasks can have multiple activations. To accomplish this, the sched-
uler uses a first in, first out (FIFO) queue for each priority that has multiple tasks, multiple
activations, or both. Tasks at the same priority level are started based on the order in which
they are moved to the READY state. The first task in each queue must either complete or move
into a WAITING state before the next task can run. If a task is preempted, it remains as the first
task in the queue.
RUNNING A A B A
READY B A
WAITING
SUSPENDED B B
Event
A = IOSampleKeypad B = ProcessKeyPress
RUNNING A B A
READY A
WAITING
B
SUSPENDED B
Before After ProcessKeyPress
ActivateState() ActivateState() Terminates
Event
A = IOSampleKeypad B = ProcessKeyPress
Example Program 47
When a preemptive task is in the RUNNING state, the scheduler is invoked when any of the
following events occur.
• The task is successfully terminated by TerminateTask().
• The task is successfully terminated and another task is activated by ChainTask().
• A task is activated from the task level using the API service ActivateTask().
• An extended task is moved into the WAITING state.
• An event is set that causes an extended task to move out of the WAITING state to the READY
state (events are covered in Chapter 6).
• A resource is released at task level (resources are covered in Chapter 7).
• A return from a category two or category three interrupt to task level occurs. The sched-
uler is not invoked if the system is running at the interrupt level (i.e., at the return of a
nested interrupt).
4.5.1 Modules
The modules startup.s, initspr.s, cinit.s, init.c, and main.c were not changed in this
chapter. The following modules either were changed or added.
debug.c The only change to this module was the modification to ErrorHook() discussed in
section 4.3, “Other Task Services.”
48 Chapter 4: Tasks
cardgame.c This new module holds all of the tasks and functions required to implement the
game of blackjack in the example application. At this point, it consists of only one task, Pro-
cessKeyPress.
ProcessKeyPress This is the main task, and it is expanded extensively throughout the
book. It consists of one switch statement that takes action based on the current state of
the system and the value of the key that was pressed. At this time, the only state of the sys-
tem is after one # key has been pressed that signals the system to await the next key press.
dispdrv.c This new module accesses the display driver on the Axiom board, which consists
of a Hitachi HD44780 display driver chip and a 20-column by four-row alphanumeric dis-
play. This module uses five functions and one task to control the display. If a different display
is used, this module will have to be modified. The functions are as follows.
void wait(UINT32 time) This local service provides a time delay that allows the display
driver to react to commands from the processor. It simply takes the value passed in the
parameter time and decrements at 0. On the MPC555 microcontroller running at 20MHz,
it takes approximately 250ns per count.
void PackDisplay(char *string) This function simply packs a display mirror buffer,
which is held locally with the information passed in the null-terminated parameter STRING,
which can contain special control characters. For example, 0x0A is recognized as the new
line character, \n, at which point PackDisplay() continues writing the string at the first
character in the next line. This is accomplished using OutputNewLine(), which is discussed
later. The value 0x0C is recognized as the form feed character, \f, which essentially blanks
the display and begins outputting the rest of the string to the first character in the first
row. Any character with a value greater than 240 is interpreted as a special character that
is one of the first eight characters in the display driver buffer.
void OutputNewLine(void) This function moves the cursor to the beginning of the next
line. If the cursor is already at the bottom of the display, this routine scrolls the display up
one line.
void OutputNewDisplay(void) This function writes the local mirror of the display to the
display driver. All of the required handshaking is performed by this one routine.
hw.c This module provides the lowest level device driver to the system hardware. It is
intended to interface with simple external devices such as switches, digital outputs, and ana-
log inputs. More complex devices, such as the display, would have their own drivers. The
hw.c module has just one function, HWGetValue(). If the method of obtaining a key press is
changed or a different keypad is used, change this module.
IOSampleKeypad This task is the keypad device driver and has been discussed extensively
throughout this chapter, and I will not discuss it here again.
hw.cfg Here, the application programmer defines the characteristics of all the hardware
inputs and outputs controlled by the low-level drivers with the use of a macro that encapsu-
lates the definition of the structure. The details of these macros can be found in the configura-
tion file.
4.6 Exercises
1. Create a routine in PreTaskHook() that counts the number of times a key is pressed since
the system has been reset. Hint: One task is activated every time a key is pressed.
2. Create a task that writes a message to the display whenever the * (asterisk) key is pressed.
Modify the ProcessKeyPress task to start your task instead of chaining the OutputDis-
play task. Please do not use “Hello World!” as your message :).
50 Chapter 4: Tasks
3. Modify the OutputDisplay task to identify which task sent the message. Hint: The highest
priority task that is in the READY state would activate OutputDisplay.
4. If you enjoy adding hardware to your system, add an LED that is on whenever a key is
pressed. Create two tasks, one that turns the LED on and the other that turns the LED off,
and activate these tasks whenever the state of the keypad changes.
4.7 Summary
In this chapter, I introduced the most important concept in the OSEK/VDX OS standard: the
task. Tasks are the most used item in the OS. The API services ActivateTask(), ChainTask(),
and TerminateTask() are probably the most used services in the OS.
5
Chapter 5
Alarms
Now that the concept of a task has been defined, the services available within the OSEK/VDX
API can be expanded. The first API service discussed is alarms, which also includes the con-
cept of counters. Unlike other real-time OSs, OSEK/VDX does not have a timer concept;
instead, an alarm is defined that covers the functions of a timer and the unique need of an
embedded control system to take an action based on the occurrence of a series of events. This
is accomplished by creating a counter object that is incremented whenever an event occurs.
The alarm is triggered when the corresponding counter reaches a preset value. This counter
can be a free-running timer, or it can be another type of input, such as a series of pulses from
a sensor.
This chapter introduces the concepts of counters and alarms and defines the API services
that manage these objects. The OSEK/VDX standards do not currently define an API for
counters. Only the API for alarms is defined. Consequently, the counter API can be different
for each vendor-specific implementation of the OSEK/VDX OS.
5.1 Counters
A counter is an OS object that keeps track of the number of ticks that have occurred. Some
counter-specific constants are defined in the OIL configuration file. Because a standardized
API for managing counters does not exist, I strongly advise that all counter manipulation be
kept in a separate file to allow portability between implementations or target processors.
51
52 Chapter 5: Alarms
MDA12
1Kohm
In the circuit, I use an output of the MPC555 to generate a frequency output then feed
that back into an input that is sampled periodically to determine when a pulse occurs. I will
also create a task that samples the input and updates a counter every time a pulse occurs. Ide-
ally, this frequency output would be fed back into an input that can generate an interrupt
whenever a pulse occurs (I make this modification when I discuss interrupts later in the
book). By depressing the switch, the user can determine how long the deck of cards are shuf-
fled and thereby generate a random number to be used by the shuffling routine. The portion
of the OIL configuration file that defines both the system counter and the shuffling counter is
shown in Listing 5.1.
Counters 53
COUNTER SHUFFLE_COUNTER {
/*@****************************************************************/
/* Shuffling Counter */
/*@****************************************************************/
MAXALLOWEDVALUE = 9;
TICKSPERBASE = 1;
MINCYCLE = 3;
};
COUNTER SYSTEM_COUNTER {
MAXALLOWEDVALUE = 65535;
TICKSPERBASE = 1000000;
MINCYCLE = 1;
};
Each counter has three standard attributes.
• MAXALLOWEDVALUE This is the maximum value for the counter. When it is reached, the
next counter increment is to 0. For example, a sensor on a wheel that sends a pulse every time
the wheel turns one degree would have a maximum allowed value of 359 (zero base) if the
counter represents the current angle of the wheel.
• TICKSPERBASE This attribute is vaguely defined by the OSEK/VDX standard as being the
number of ticks required to reach a counter-specific unit. The standard indicates that the
interpretation of this attribute is specific to the implementation. Consequently, you should
refer to your implementation documentation for a description of the use of this attribute.
• MINCYCLE This attribute defines the minimum cyclic number of counter ticks allowed for
a cyclic alarm. Cyclic alarms are described in the next section.
For the card game example application, the SHUFFLE_COUNTER shuffling counter is defined
with a maximum value of 9 and a minimum cycle of 3. In the next section, I use this counter
to generate a random number that is used to sort the cards when the application shuffles the
deck.
The standard timer counter in OSEKWorks is called SYSTEM_COUNTER and is set up as a
free-running 16-bit counter. The minimum number of counts for a cyclic alarm is 1. The name
of this timer varies with each implementation, and in some, multiple standard timers might be
54 Chapter 5: Alarms
available. In the OSEKWorks implementation, the TICKSPERBASE attribute is not used by the
implementation, but it is available for the application to use as required. The OSTICKDURATION
system constant, discussed later, is set to this value for the system counter. The TICKSPERBASE
attribute is available to the application as a return from an API service that is discussed in the
next section. I have chosen the value of TICKSPERBASE for SYSTEM_COUNTER to be 1000000,
which corresponds to 1ms (1,000,000ns).
After a counter is defined, a minimum of two routines must be created: an initialization
routine and a handler routine. The initialization and handler routines for the standard system
counter that is used as a timer are not only specific to each implementation, but also specific
to the individual microcontroller. Refer to the implementation documentation for details on
how the standard system counter is initialized and handled. Initialization and processing can
be provided by the implementation supplier, or the end user might have to supply these func-
tions. The initialization routine for the example program is shown in Listing 5.2; the handler
task is shown in Listing 5.3. Many of the services included in Listing 5.3 will be discussed
throughout this chapter, so do not worry if the task is confusing at this time. These routines
are found in shuffle.c on the accompanying CD.
switch(ShuffleState){
case SHUFFLE_HIGH:
if(HWGetValue(&SHUFFLESWITCH)==INACTIVE){
ShuffleState = SHUFFLE_LOW;
}
break;
case SHUFFLE_LOW:
if(HWGetValue(&SHUFFLESWITCH)==ACTIVE){
timeout = SHUFFLE_SWITCH_OFF;
if(GetAlarm(ShuffleAlarm,(TickRefType)tick) == E_OS_NOFUNC){
SetAbsAlarm(ShuffleAlarm,5,3);
strcpy(displayBuffer,"\fSHUFFLING -");
ActivateTask(OutputDisplay);
}
ShuffleState = SHUFFLE_HIGH;
IncrCounter(SHUFFLE_COUNTER);
}
else{
if(timeout!=0){
if(--timeout == 0){
CancelAlarm(ShuffleAlarm);
CancelAlarm(SampleShuffleSwitchAlarm);
ActivateTask(ShufflingComplete);
}
}
}
56 Chapter 5: Alarms
break;
}
TerminateTask();
}
ALARM SampleKeypad {
COUNTER = SYSTEM_COUNTER;
ACTION = ACTIVATETASK{
TASK = IOSampleKeypad;
};
};
ALARM SampleShuffleSwitchAlarm {
COUNTER = SYSTEM_COUNTER;
ACTION = ACTIVATETASK{
TASK = IOSampleShuffleSwitch;
};
};
ALARM ShuffleAlarm {
COUNTER = SHUFFLE_COUNTER;
Using Alarms 57
ACTION = ACTIVATETASK{
TASK = ShuffleCards;
};
};
Within an alarm object definition, the standard requires two attributes: COUNTER and
ACTION. The COUNTER attribute defines the counter associated with this alarm when active. The
name used in this attribute must match the name of a counter object defined elsewhere in the
configuration file. The ACTION attribute can be either ACTIVATETASK or SETEVENT. Depending
on the value of this attribute, either one or two references to other OIL objects must be
defined. If the action is ACTIVATETASK, then one reference, TASK, is required. This references
the name of a task to activate, which is also defined in this configuration file. If the action is
SETEVENT, then two references are required: TASK and EVENT. EVENT is a valid event for the TASK
reference as defined elsewhere in the configuration file. In the OSEKWorks v4.0 implementa-
tion, the TASK and EVENT references appear as separate attributes, instead of being associated
directly with one ACTION attribute as references. This might affect portability of the OIL file
and should be fixed in a later version. The code on the accompanying CD includes the OIL
configuration file output from OSEKWorks and will be different from the listing here.
Now that the alarms and counters are defined in the configuration file, I have to update
the application to use these alarms. The first item to update is the task previously defined to
sample the keypad, IOSampleKeypad (Listing 5.5). This is now be a preemptible task with a
higher priority, so I need to remove the delay loop used to allow higher priority tasks to run.
tempKey = HWGetValue(&KEYPAD);
if(tempKey == lastKey){
if(keyCount++ == KEY_DEBOUNCE_TIME){
--keyCount;
keyValue = tempKey;
}
}
else{
keyCount = 0;
lastKey = tempKey;
}
if(keyState==FALSE){
if(keyValue != 0){
58 Chapter 5: Alarms
keyState = TRUE;
ActivateTask(ProcessKeyPress);
}
}
else{
if(keyValue == 0){
keyState = FALSE;
}
}
TerminateTask();
}
Because this task is now triggered by the expiration of an alarm, you must start the alarm
at some point with the use of a special initialization task that is run immediately after the OS
starts. The purpose of this task, which is not defined in the standards or included in an imple-
mentation, is to start the alarms that the application must have running on startup. These are
typically periodic alarms that kick off periodic tasks required by the application. The
OSEK/VDX standard does not have an autostart configuration for alarms, as it does with
tasks, because the state of the counters is uncertain. The task I created to autostart alarms is
InitAlarms (Listing 5.6, in init.c).
while(list->appmodemask != 0x00000000){
if((list->appmodemask & currentAppModeMask)!= 0){
if(list->alarmtype == ALARM_REL){
SetRelAlarm(list->alarm,list->start,list->cycle);
}
else{
SetAbsAlarm(list->alarm,list->start,list->cycle);
}
}
list++;
}
TerminateTask();
}
Using Alarms 59
InitAlarms is configured as an autostart task in the OIL configuration file with the highest
possible priority. In addition, no other tasks are allowed to have the same priority. This
ensures that this task is the first run after the OS starts.
InitAlarms first obtains the current APPMODE and then determines which alarms it needs to
start. First, it translates the APPMODE into a bit mask. The AppModeType is not explicitly defined
in the OSEK/VDX standard. In one implementation I have seen, AppModeType is a scalar value
realized with the use of enumeration. In another implementation, it is a pointer to a structure
defining the APPMODE. Consequently, I have created a conversion routine ConvertAppMode(),
which encapsulates the format of the APPMODE type. This routine obtains the current APPMODE
using GetActiveApplicationMode() and converts it to either a number or a bitmap, which it
returns.
When calling ConvertAppMode(), the requested type of return, either APP_MODE_MASK or
APP_MODE_VALUE, is passed to the routine as a flag. The return value is always UINT32. If a
number is returned, it can be used efficiently in a switch statement; if a bit mask is returned,
it can be used efficiently in a table lookup. The details of this routine are found in the source
code on the accompanying CD in os.h and os.c. The os files were created to hold any imple-
mentation-specific glue routines that might be required to port an application from one
OSEK/VDX implementation to another.
In InitAlarms, I traverse a null-terminated list of structures that define the alarms to be
started. For each alarm, the structure defines the type and periodicity, the starting value, and
a mask of the APPMODEs in which the alarm must be started. The NULL value is the mask of
APPMODEs, because there has to be at least one mode in which an alarm starts, or it should not
be in the list. The type definition for the startup alarm structure InitAlarmType is shown in
Listing 5.7.
to autostart in the current APPMODE, one of two API service routines are invoked: SetRelA-
larm() or SetAbsAlarm(), depending on the alarmtype structure member. The C function
prototypes for each service are defined below.
deckStart = cardDeck;
while((count--)>0){
location1 = ((UINT32)rand() * 52u) / RAND_MAX;
if(location1==52) location1 = 51;
location2 = ((UINT32)rand() * 52u) / RAND_MAX;
if(location2==52) location2 = 51;
tempcard = cardDeck[location1];
cardDeck[location1] = cardDeck[location2];
cardDeck[location2] = tempcard;
}
strcpy(displayBuffer,busyDisplay[busyLocation++]);
if(busyLocation == 4) busyLocation = 0;
ActivateTask(OutputDisplay);
TerminateTask();
}
The rand() C library function is used to shuffle the deck every three counts of the shuffling
switch. This task is set up with a higher priority than the routine that checks the switch input
to ensure that the shuffle is a higher priority than the switch. In Chapter 7 on resources, I con-
sider the deck to be a resource that can be locked.
64 Chapter 5: Alarms
• ticksperbase The number of ticks required to reach a counter-specific value. The inter-
pretation of this number is specific to the implementation.
GetAlarmBase() can be invoked from the task or interrupt level and from the hook routines
ErrorHook(), PreTaskHook(), and PostTaskHook().
In addition to the services defined above, four global constant values must be defined by
every implementation. These values are as follows and might be used by the application.
• OSMAXALLOWEDVALUE The maximum allowed value for the system counter that is used as a
timer. This is the same as the AlarmBaseType member maxallowedvalue.
These constant values are usually defined in initialization code for the application. The
configuration program then uses the values from this counter to define these constants.
5.4.1 Modules
The modules startup.s, initspr.s, cinit.s, and debug.c did not change in this chapter. The
following modules were changed or added.
init.c The InitAlarms task was added. It is set as the highest priority task in the applica-
tion and autostarts. Its purpose is to start all of the alarms that kick off periodic tasks or are
required in other ways by the application.
main.c The background task was modified so that it no longer terminates but runs continu-
ously in the background. This allows it to perform functions such as petting the watchdog
and monitoring the function of the system.
cardgame.c The ProcessKeyPress task was modified and one additional task was added.
Also, this module now keeps track of the state of the game in the gameState static variable.
The tasks in this module are described below.
ProcessKeyPress This task now provides only two functions. When the * key is pressed,
the card deck is reshuffled. When the # key is pressed, the next card is displayed. All other
keys are ignored.
dispdrv.c The initialization of the display that is performed in InitDisplay() was modi-
fied slightly. A new startup screen was defined to inform the user to press the * key in order to
shuffle the deck, and a new special character was added to allow the simulated clock to dis-
play while shuffling. The Hitachi display driver does not support the backslash character (\).
hw.c The HWGetValue() service was expanded to allow two types of input. In addition to the
keypad input previously defined, a standard digital input from a 16-bit digital channel has
been defined. This supports sampling of the shuffling switch.
keypad.c The IOSampleKeypad task has been modified extensively to support the change
from a background task that is constantly running to a periodic task. It is now a much sim-
pler task that only executes when it is time to sample the keypad.
carddeck.c This new module maintains the deck of cards used by the game. The current
deck of cards is held in the cardDeck[] static array, which is 53 bytes long. The final entry in
66 Chapter 5: Alarms
the array is never used except to indicate the end of the array. The cards are encoded with val-
ues from 0 to 51. The value of the card is the value from this array modulo 13, with 0 equal-
ing an Ace and 12 representing a King. The suit of the card is the value from the array divided
by integer 13. Because integer math is used, the remainder is discarded. The suits are taken in
ascending order starting with hearts, followed by diamonds, spades, and clubs. The deck of
cards is maintained with the following tasks and functions:
ShuffleCards This task performs one shuffle of the deck. First it generates a random
number from 1 to 100 for the number of pairs of cards to be exchanged in the deck. Then
pairs of cards are exchanged randomly. When complete, ShuffleCards updates the display
to show the simulated clock moving one position.
UINT8 DealCard(void) This function deals and displays the next card from the deck. It
also translates the value from a single byte into a card value and suit.
os.c This new module encapsulates all of the routines that are required to port the applica-
tion to a new implementation of the OSEK/VDX OS. Each implementation will require some
hardware initialization, such as the hardware timer that generates the events for SYSTEM_
COUNTER. This module has two routines.
shuffle.c This new module is the device driver for the shuffle switch. It consists of an ini-
tialization function and the sample task. Both the function and the task were discussed in
detail in this chapter and will not be repeated here.
5.5 Exercises
You can do much more with the sample application now that tasks and alarms are defined.
1. In the IOSampleShuffleSwitch task, replace the timeout counter with an alarm that starts
with the first pulse and restarts on every pulse. When this alarm expires, activate the Shuf-
flingComplete task. Modify ShufflingComplete to cancel the other alarms.
2. In the previous chapter, you created a task that output a message to the display when the *
key was pressed. Modify this task to output the message when the 0 (zero) key is pressed,
and flash the message at a rate of one second on and one second off.
3. Create a timer and a task that stores the hours, minutes, and seconds that the system has
been running since the last reset. Display this time whenever the 1 key is pressed.
4. Calculate the amount of time spent in the background task using the time from the clock
in the previous exercise and the PreTaskHook() and PostTaskHook() hook routines.
5. Add a switch to a digital input that sends a low pulse every time the switch is pressed
using a pull-up resistor to +5V and the switch connected to ground. Create a new counter
object and a device driver for the switch that increments this new counter every time the
switch is pressed. For every 10 times the switch is pressed, create an alarm that activates a
task that sends a message to the display.
5.6 Summary
At this point, the most widely used OS services have been used in the example. Tasks and
alarms are the primary objects used by application developers. In Chapters 6 and 7, Events
and Resources, I discuss some advanced topics that are used less often but could be required
in many applications.
68 Chapter 5: Alarms
Events
The event, which was introduced briefly in Chapter 4 during the discussion of extended tasks,
is the next OSEK/VDX OS object to discuss. Events are owned by tasks in a one-to-one rela-
tionship. When a task owns an event, it becomes an extended task. Other tasks refer to the
event by both the task name and the event name when accessing the API service.
In OSEK/VDX, events primarily provide synchronization between tasks and between
applications that reside on different microcontrollers. Synchronization between different
applications is accomplished by the combination of events and external communication mes-
sages. (Communication messages are covered in Part 2 on the OSEK/VDX communication
standard.) This chapter defines events in more detail, discusses the API services provided to
handle events, and expands the sample application to use events.
69
70 Chapter 6: Events
set of events to occur. When each activity completes, it sets an event on which the activating
task is waiting. This releases the original task from the waiting mode and allows it to con-
tinue with the knowledge that everything has completed properly.
TASK ProcessKeyPress {
TYPE = EXTENDED;
SCHEDULE = FULL;
PRIORITY = 2;
ACTIVATION = 1;
AUTOSTART = TRUE;
STACKSIZE = 128;
SCHEDULE_CALL = FALSE;
EVENT = { KEYPRESS, SHUFFLED };
};
/**************************************************************/
/* Events */
/**************************************************************/
Managing Events 71
EVENT ABORT_SHUFFLE {
MASK = AUTO;
};
EVENT KEYPRESS {
MASK = AUTO;
};
EVENT SHUFFLED {
MASK = AUTO;
};
An additional attribute in the ProcessKeyPress task object definition, EVENT, links the
EVENT object to the task. The EVENT attribute for each task object can have multiple event
names. At this point, I have defined only two events for this task: SHUFFLED and KEYPRESS.
The OSEK/VDX event is defined as the combination of the TASK and EVENT objects as defined
in the task object definition.
The definition of the EVENT object has only one attribute, MASK, which is required for the
event. The value of this attribute can be either AUTO or up to a 64-bit unsigned integer with a
single bit set. In most cases, you want to leave this value set to AUTO and allow the OS config-
uration utility to optimize the bit value.
Although the OSEK/VDX event is defined as being owned by a single task, the EVENT
object defined in the OIL configuration file is only a mask and can be used by multiple
extended tasks because the event is defined as a combination of TASK and EVENT objects. To
trigger an event for all tasks that use the event, you must call the API service for each combi-
nation of task and event. This is also illustrated in Listing 6.1, where I have added the new
task DealCards. This task is different from the function DealCard(), which was originally cre-
ated in Chapter 5 to add the next card in the deck to the display. DealCards is activated by the
ProcessKeyPress task when it determines that the cards need to be shuffled. It immediately
enters the WAITING state until shuffling is completed with the occurrence of the SHUFFLED
event. After the event occurs, it deals the cards.
Now that the new objects are defined, modify the application to take advantage of the
new events. First change the ProcessKeyPress task (Listing 6.2) so that it can use the added
services provided for extended tasks.
while(1){
WaitEvent(KEYPRESS);
ClearEvent(KEYPRESS);
while((keyValue = GetKeyValue())!= 0){
switch(CheckGameTransition(keyValue)){
case START_SHUFFLING:
SetRelAlarm(SampleShuffleSwitchAlarm,10,10);
ActivateTask(DealCards);
ActivateTask(ShuffleCards);
gameState = GAME_SHUFFLING;
shuffleComplete = FALSE;
do{
WaitEvent(KEYPRESS|SHUFFLED);
GetEvent(ProcessKeyPress,(EventMaskRefType)&eventMask);
if((eventMask & KEYPRESS)!= 0){
ClearEvent(KEYPRESS);
while((keyValue = GetKeyValue()) != 0){
if(keyValue == '#'){
CancelAlarm(ShuffleAlarm);
CancelAlarm(SampleShuffleSwitchAlarm);
SetEvent(DealCards,ABORT_SHUFFLE);
shuffleComplete = TRUE;
}
}
}
else{
ClearEvent(SHUFFLED);
shuffleComplete = TRUE;
}
}while(shuffleComplete == FALSE);
break;
...
}
}
}
}
I have included only part of the entire task because it must handle many key press cases
that do not involve events. The complete task is in cardgame.c on the accompanying CD.
Within the task, I added a while(1) loop that invokes the WaitEvent() API service (see the C
Managing Events 73
prototype below), which puts the ProcessKeyPress task immediately into the WAITING state
for the KEYPRESS event.
StatusType WaitEvent(EventMaskType event);
When WaitEvent() is called, the service checks the events that are defined by the event
mask passed as the argument. If any of the events defined in the mask are set, the service
immediately returns to the invoking task, which continues in the RUNNING state. If all of the
events defined by the event mask are cleared, then the invoking task is put into the WAITING
state, and the scheduler is run to reschedule the system. When any one of the events defined
by the event mask occurs, the invoking task is moved back into the READY state. When the
scheduler moves the task from the READY to the RUNNING state, the task continues at the
instruction immediately following the WaitEvent() service call. The service might only be
invoked from a running extended task. Consequently, the service is only available in an appli-
cation that is operating in either the ECC1 or ECC2 conformance class.
The return values from the service are
• E_OK in standard status mode and when the service is successful,
• E_OS_ACCESS in extended status mode if the calling task is not an extended task,
• E_OS_RESOURCE in extended status mode if the calling task still occupies resources
(resources are discussed in Chapter 7; having a resource occupied while in the WAITING
state can have catastrophic consequences), or
• E_OS_CALLEVEL in extended status mode if the service is invoked from interrupt level.
WaitEvent() can only be invoked from the task level of an extended task. It cannot be
invoked at the interrupt level or in any hook routine.
If one of the events set in the event mask is not valid for the particular task, the standard
does not define the actions of the API service. During development, this would make it very
difficult to identify an error when one task sets an event and expects an extended task to be
moved from the WAITING to READY state.
I configured ProcessKeyPress as a lower priority task because this task dispatches user
interface events. It can be preempted by the higher priority events that process the user input,
which minimizes the number of tasks that are in the READY state but requires the application
to make a decision about which task needs to run first. Consequently, when ProcessKeyPress
activates the DealCards and ShuffleCards tasks in the START_SHUFFLING case, it will be pre-
empted. DealCards will return rapidly because it immediately enters the WAITING state. Shuf-
fleCards will return after it has shuffled the cards once. This feature was added to eliminate
the “quick finger” of the user. A quick finger event occurs when the player presses the shuffle
switch fast enough to get a pulse but does not hold it long enough for sufficient pulses to pro-
duce shuffling. Remember, up to 10 pulses are required before the ShuffleAlarm expires the
first time. Activating ShuffleCards immediately guarantees that at least one shuffling occurs
whenever shuffling is requested. When ProcessKeyPress resumes, it waits for either a KEY-
PRESS or SHUFFLED event.
Because multiple key presses could theoretically occur between executions of the Process-
KeyPress task, I have modified keypad sampling to create a buffer of key presses. The most
recent key pressed is returned from the routine GetKeyValue(). This routine replaces the glo-
bal value keyValue that was used in earlier examples.
74 Chapter 6: Events
switch(ShuffleState){
case SHUFFLE_HIGH:
if(HWGetValue(&SHUFFLESWITCH)==INACTIVE){
ShuffleState = SHUFFLE_LOW;
}
break;
case SHUFFLE_LOW:
if(HWGetValue(&SHUFFLESWITCH)==ACTIVE){
timeout = SHUFFLE_SWITCH_OFF;
if(GetAlarm(ShuffleAlarm,(TickRefType)tick) == E_OS_NOFUNC){
SetAbsAlarm(ShuffleAlarm,5,3);
strcpy(displayBuffer,"\fSHUFFLING -");
ActivateTask(OutputDisplay);
}
ShuffleState = SHUFFLE_HIGH;
IncrCounter(SHUFFLE_COUNTER);
}
else{
if(timeout!=0){
if(--timeout == 0){
CancelAlarm(ShuffleAlarm);
CancelAlarm(SampleShuffleSwitchAlarm);
SetEvent(DealCards,SHUFFLED);
SetEvent(ProcessKeyPress,SHUFFLED);
}
}
}
Managing Events 75
break;
}
TerminateTask();
}
The only modification to this task occurs after the counter decrements to 0, which indi-
cates that the player has stopped pressing the shuffling switch. The API service SetEvent() is
called instead of activating the ShufflingComplete task as in Chapter 5.
StatusType SetEvent(TaskType task, EventMaskType event);
When SetEvent() is invoked, it first checks whether the task is in the SUSPENDED state. If it is,
then the event is not set. When an extended task is moved from the SUSPENDED to the READY
state, all events for the task are cleared by the OS. Consequently, any events that occurred
while the task was suspended are irrelevant. If the task is not suspended, then the event or
events are set for the task, which is automatically moved into the READY state if it is in the
WAITING state. Depending on the scheduling mode of the invoking task, the scheduler might
execute at this time.
The return values from this API service are
• E_OK if the event is set successfully,
• E_OS_ID in extended status mode if the value sent as the task is not a valid task,
• E_OS_ACCESS in extended status mode if the task is not an extended task, or
• E_OS_STATE in extended status mode if the task is in the SUSPENDED state.
This service can be invoked from either the task or the interrupt level but must not be invoked
from a hook routine.
Two tasks are interested in a SHUFFLED event: ProcessKeyPress and DealCards. Conse-
quently, SetEvent() is invoked twice to set the events for both of these tasks. Because both
tasks are in the WAITING state, they are moved to the READY state, and the scheduler runs.
Because IOSampleShuffleSwitch has a higher priority than the other tasks, it completes
before they move to the RUNNING state.
When ProcessKeyPress enters the RUNNING state, it first checks which event released it
from the WAITING state with the use of the GetEvent() API service, which determines the sta-
tus of all events for a given task.
StatusType GetEvent(TaskType task, EventMaskRefType mask);
GetEvent() checks the events for the requested task and sets the bits in the variable pointed
to by mask that correspond to all events set for the task. You can check the status of the event
by ANDing the mask variable with the event as defined in the OIL configuration file.
The return values from this API service are
• E_OK if no error occurs,
• E_OS_ID in extended status mode if the task is not a valid task,
• E_OS_ACCESS in extended status mode if the task is not a valid extended task, or
• E_OS_STATE in extended status mode if the task is in the SUSPENDED state.
This service is available from the task or interrupt levels and from ErrorHook(), Pre-
TaskHook(), and PostTaskHook().
76 Chapter 6: Events
ProcessKeyPress waits for two events during shuffling: KEYPRESS and SHUFFLED. If the
task is moved from the WAITING state by a KEYPRESS event, it checks which key was pressed. If
it was the # key, then shuffling is aborted by canceling the alarms that sample the shuffling
switch then setting the ABORT_SHUFFLE event. This event signals to the DealCards task that
shuffling was aborted and it should return to the prior state. If the SHUFFLED event occurs,
ProcessKeyPress changes game state to the state of PLAYER_TURN and continues with the nor-
mal loop, in which it only waits for the KEYPRESS event. The PLAYER_TURN state is new, and
defines how the program interprets key presses.
In both cases, after the event is serviced, ProcessKeyPress clears the event using
ClearEvent().
6.4.1 Modules
The modules startup.s, initspr.s, cinit.s, init.c, main.c, hw.c, and os.c did not change
in this chapter.
debug.c I modified the hook routines PreTaskHook() and PostTaskHook() to measure the
time in the background loop. At any point, the system can be stopped and the amount of time
that the background task has executed and not executed can be calculated based on ticks of
the MPC555 real-time clock. This gives a very good approximation of the amount of idle
time in the system. An additional function encapsulates as a 64-bit value the assembly lan-
guage instructions required to obtain the real-time clock.
cardgame.c This module has changed extensively in order to support a true card game. A
state machine was defined in which the state of the game is modified based on key presses and
other events in the system. The ProcessKeyPress task was modified extensively, a number of
new functions were added, and the ShufflingComplete task was removed.
ProcessKeyPress task This task was modified extensively to take different actions based
on the transition that occurs when a key is pressed. The private function CheckGameTran-
sition() determines the type of transition that occurs based on the current state of the
game and the key that was pressed. Also, this task is now an extended task and will
always reside in memory.
DealCards task This is the first task to run after shuffling is complete or when a new
game starts. It clears the display and deals the first four cards; the first card dealt to the
dealer is set up as the hole card and is not displayed.
DealerTurn task This task is activated after the player presses the B key to end the turn.
It displays the dealer’s hole card and takes additional cards based on the rule that the
dealer must hit at 16 and stay at 17, as discussed earlier in this section. To simulate real
play, the task deals one card a time and sets an alarm for two seconds before it deals
another card.
• void EndGame(void) This local function is executed by the DealerTurn task after the
dealer’s turn has completed. It displays the scores for both the dealer and the player and
sets the game state to normal in anticipation of the next key press.
dispdrv.c This module was modified to add one more special character to the display: the
character to be displayed as the back of a card. In addition, the following function was
added.
void SetDisplayPosition(UINT8 row, UINT8 column) This function moves the cursor
to an absolute display position defined by the row and the column parameters. The next
string to be written to the display will start from this new position.
keypad.c This module was modified to create a buffer of key presses rather than just hold-
ing the last key pressed. The support to obtain data from the buffer and to encapsulate the
key buffer was added.
char GetKeyValue(void) This routine simply pops the oldest key press from the buffer,
updates the buffer pointers, and returns the value.
carddeck.c This module also has been extensively modified to provide more information
about dealt cards. The ShuffleCards task is modified only slightly to initialize the remaining-
Cards static variable to 52 when the deck reshuffles. However, DealCard() was rewritten
extensively, and other functions were added.
UINT8 DealCard(PlayerType player, UINT8 position, BOOLEAN up) This routine now
deals the next card based on the player parameter, which defines whether the next card
goes to the dealer or the player, the position parameter, which defines which of the five
positions of the dealer’s or player’s hand a card is dealt, and the up parameter, which
defines whether the value or the back of the card is shown. The return value is now the
value of the card that was dealt, from 0 to 51. This task also invokes DisplayCard() to
display the card.
void DisplayCard(UINT8 card) This routine copies the codes required to send the card
to the display buffer. If card is BLANK, the back of the card is displayed.
UINT8 GetCardValue(UINT8 card) This function returns the value of the card that is
passed in the card parameter. An Ace always has a value of 11, and a face card always has
a value of 10.
shuffle.c This module was changed to use events instead of activating a task when shuf-
fling is complete.
Exercises 79
6.5 Exercises
1. Modify the task you created in the last chapter that keeps track of the time the program
has been running. Make this an extended task with an event that is set when the alarm
expires.
2. Modify the previous task to reset the time when a key is pressed. Use the event mechanism
to signal this event from the task ProcessKeyPress.
6.6 Summary
Events differentiate basic from extended tasks and are used primarily as a method of synchro-
nization between tasks. An event is a combination of an event and an extended task. An event
differs from an event mask, which is a specific bit value in a mask. Multiple tasks can use the
event mask to create a series of unique events.
Any task and interrupt service routine and most hook routines can set and check the sta-
tus of an event. However, only the extended task that owns the event can wait for it to occur
or clear the event.
80 Chapter 6: Events
Resources
Most multitasking/multiprocessing OSs provide a method for sharing a resource between
tasks or processes. The typical methods are semaphores and mutexes (MUTual EXclusion). A
drawback of these methods is possible priority inversion or deadlock. The OSEK/VDX OS
also provides a method for managing resources that avoids these drawbacks. In this chapter, I
discuss the issues of priority inversion and deadlock, then introduce the method used by
OSEK/VDX to eliminate these issues — the priority ceiling protocol. I then discuss how
resources are managed using the scheduler as a resource and the limitations to using resources
in a system.
81
82 Chapter 7: Resources
3. Task C attempts to lock resource R. Because the resource is already locked, Task C is
placed in the WAITING state. This is similar to the WAITING state in OSEK/VDX. Task A
resumes where it was preempted.
4. Task B is activated and preempts task A. At this point, priority inversion has occurred:
Task C has to wait for task B to complete only because of the locked resource. Task B has
effectively preempted task C.
5. Task B completes and task A resumes processing.
6. Task A releases resource R. Task C can then preempt task A again and complete process-
ing.
7. Task C completes and terminates. Task A resumes running.
8. Task A completes and terminates.
1 B C A R
2 B C A R
3 B A C R
4 B C A R
5 C A B R
6 B C A R
7 B A C R
8 B C A R
PriorityInversion
Because of priority inversion, the amount of time that C can be delayed is nondeterminis-
tic. Without priority inversion, the maximum amount of time that C can be delayed can be
calculated by taking the set of all lower priority tasks that share resource R. For each task,
you can calculate the amount of time that resource R is locked by the task. The longest time
that C can be delayed is the maximum time that any lower priority task has locked the
resource.
Deadlock is a much more serious situation, where the locking of resources causes a con-
flict between two tasks, where each task has locked a resource that the other needs and nei-
ther task is allowed to complete. In an automotive or other critical embedded system, the
possibility of killing the tasks that are deadlocked is not possible. Figure 7.2 illustrates dead-
lock in a general RTOS system.
Priority Inversion and Deadlock 83
1 B C A R1 R2
B C A R2 R1
2
B A C R2 R1
3
4 B A C R1 R2
5 B C A R1 R2
B C A R1 R2
6
C A B R1 R2
Deadlock
These are the same tasks discussed in the priority inversion example, except task A and
task C share two resources — R1 and R2. The sequence of events that illustrate deadlock are
as follows.
1. Task A locks resource R1.
2. Task C preempts task A.
3. Task C locks resource R2.
4. Task C attempts to lock resource R1. Because task A has already locked the resource, task
C is placed in the WAITING state and task A resumes.
5. Task A attempts to lock resource R2. Because task C has already locked the resource, task
A is placed in the WAITING state. At this point, both tasks A and C are WAITING and will
never leave WAITING because neither resource can be released.
6. Task B is activated and runs normally.
Because of its nature, deadlock might not be discovered during normal testing and might
occur only after the product has been released. Even worse, deadlock could be misdiagnosed
as a partial failure of the system and could create large warranty costs before the actual fail-
ure is determined. This typically occurs when a technician replaces the “malfunctioning”
component with a new component, which “fixes” the problem. When the original component
is returned to the manufacturer for diagnosis, no problem is found because the act of remov-
ing power from the component resets the software and eliminates the deadlock.
Many manual methods can eliminate priority inversion and deadlock from a system.
These usually entail strict programming standards that must be followed by the application
programmer. As with any manual system, these methods are ripe for human error. The only
84 Chapter 7: Resources
surefire way of eliminating priority inversion and deadlock is to use an automatic method
that is inherent to the OS. The priority ceiling protocol of OSEK/VDX is one such automatic
method.
1 B C A R
B C A R
2
B C A R
3
4 C B A R
A B C R
5
C A B R
6
7 B C A R
As illustrated in Figure 7.3, the priority ceiling protocol allows tasks to be scheduled as
expected. Because task C is activated before task B, it is proper for task B to remain in the
READY state and not preempt task A. However, if task B is activated before task C but after
task A locks the resource, it would be expected that task B preempts task A. With the priority
ceiling protocol active, this preemption would not occur. This is one drawback of the priority
ceiling protocol, where a lower priority task can inhibit a higher priority task that is lower
than the ceiling priority. However, the time that a resource is locked should be minimized by
good application design. When a task releases a resource, the scheduler runs immediately and
the preemption will occur at that point. Because the time that a resource is locked can be cal-
culated for all tasks, the maximum latency until preemption occurs can be addressed. This
drawback of the priority ceiling protocol is less severe than the effect of priority inversion or
deadlock and can be addressed in the application design.
Deadlock is eliminated in much the same way. Task A is set to the ceiling priority of
resource R1 when it locks this resource. Again, the ceiling priority will be at least 3, the prior-
ity of task C. Task C will never preempt task A and will not lock resource R2. Task A can
lock resource R2 successfully because task C is not allowed to preempt task A. The priority of
Task A may be raised if the ceiling priority of R2 is greater than R1. The revised sequence of
events from the previous example of deadlock is shown in Figure 7.4.
The sequence of events in Figure 7.4 is as follows.
1. Task A locks resource R1 and has its priority raised to the ceiling priority of the resource.
2. Task C is activated. Because of the priority ceiling protocol, this task remains in the READY
state.
3. Task A locks resource R2 and has its priority set to the maximum ceiling priority of R1
and R2.
86 Chapter 7: Resources
1 B C A R1 R2
2 B C A R2 R1
B C A R2 R1
3
4 B C A R1 R2
5 B C A R2 R1
B A C R1 R2
6
B C A R1 R2
7
4. Task A releases resource R2 and has its priority set to the ceiling priority of R1.
5. Task A releases resource R1 and has its priority reset to the statically defined priority of
the task. At this point, scheduling occurs and task C preempts and begins running.
6. Task C terminates and task A resumes running.
7. Task A terminates.
Notice in steps 4 and 5 above that the resources were released in a last in, first out (LIFO)
order. This is a requirement of the OSEK/VDX standard that must be followed by the appli-
cation. In the extended status mode, a violation of the release order is identified by the OS.
The previous examples have focused on the required priority ceiling protocol for all tasks.
The OSEK/VDX standard allows the optional extension of the priority ceiling protocol to
interrupt levels. Because interrupt handling is processor dependent, the standard leaves a
description of how software priorities and hardware interrupt levels are handled to the imple-
mentation. For example, one processor might be able to mask an interrupt in hardware, and
another processor might be required to handle the interrupts in software. When a task is
raised to an interrupt level priority, the implementation must mask all interrupts of lower pri-
ority.
The extension of the priority ceiling protocol for interrupts is handled as follows.
1. The set of all possible priorities is divided into two sections: the lower section is reserved
for tasks and the upper section is reserved for Interrupt Service Routines (ISR). The upper
section of priorities is referred to as virtual priorities because they function differently
from the normal task priorities.
2. Each ISR is assigned a virtual priority in the configuration file.
Managing Resources 87
3. The priority ceiling protocol, as seen from the application, appears to function exactly the
same. However, because the ceiling priority for a resource could be a virtual priority, the
effect to the implementation could be extensive. Interrupt masking is hidden from the
application, but it will affect the time to lock resources and activate tasks.
As can be seen in these revised examples, the priority ceiling protocol effectively eliminates
the problems of priority inversion and deadlock.
};
/***************************************************/
/* Resources */
/***************************************************/
RESOURCE CARDDECK {
/* No attributes defined */
};
In the definition of a task, an additional attribute, RESOURCE, is required. Like the EVENT
attribute defined in the last chapter, RESOURCE is a multiple-reference attribute and can include
multiple resources within the attribute. Once the resource has been defined, the tasks that use
the resource must be modified. The modified ShuffleCards task in carddeck.c is shown in
Listing 7.2.
deckStart = cardDeck;
remainingCards = 52;
GetResource(CARDDECK);
while((count--)>0){
location1 = ((UINT32)rand() * 52u) / RAND_MAX;
if(location1==52) location1 = 51;
location2 = ((UINT32)rand() * 52u) / RAND_MAX;
if(location2==52) location2 = 51;
tempcard = cardDeck[location1];
cardDeck[location1] = cardDeck[location2];
cardDeck[location2] = tempcard;
}
ReleaseResource(CARDDECK);
strcpy(displayBuffer,busyDisplay[busyLocation++]);
if(busyLocation == 4) busyLocation = 0;
ActivateTask(OutputDisplay);
TerminateTask();
}
Managing Resources 89
The CARDDECK resource was defined to guarantee that the deck of cards is not corrupted by
dealing a card while the deck is being shuffled. This could occur under the following scenario.
1. The shuffle switch toggles from low to high and SHUFFLE_COUNTER increments to the point
where ShuffleAlarm is triggered. This activates the ShuffleCards task.
2. The shuffle switch is immediately released by the player.
3. Because of preemption, ShuffleCards does not run immediately, but IOSampleShuf-
fleSwitch continues to execute.
4. ShuffleCards finally begins and shuffles the cards. The point in the shuffle when a card
has been moved from one location to another and now exists temporarily in two locations
is reached when the task is preempted by IOSampleShuffleSwitch.
tempcard = cardDeck[location1];
cardDeck[location1] = cardDeck[location2];
<<Preemption occurs here>>
cardDeck[location2] = tempcard;
The two locations of the duplicated card will be referred to as the original and the new
locations.
5. IOSampleShuffleSwitch identifies that the switch has been released and sets the SHUFFLED
event. This releases the DealCards task from the WAITING state.
6. In the example program, DealCards has a higher priority than ShuffleCards. It executes
next and deals the cards to start the game. Among the cards that have been dealt is the
card that exists in two places. The original location is dealt.
7. ShuffleCards resumes and replaces the card at the original location with the shuffled
card. However, because the original location has already been dealt to a player, the shuf-
fled card is not used.
8. Later in the game, the new location of the card is used and appears again in the game,
causing a failure.
This situation has a low probability of occurring, but as the program is expanded (i.e., to
add sound, animation, etc.), the probability increases. If the deck of cards is defined as the
CARDDECK resource, the priority ceiling protocol eliminates the possibility of a corrupted deck
because DealCards is never allowed to preempt ShuffleCards. However, IOSampleShuf-
fleSwitch will still preempt ShuffleCards because it has a higher priority.
The astute reader will notice that another method to eliminate this situation is possible. If
the priorities are changed such that ShuffleCards has a higher priority than DealCards, the
corruption will not occur. Although this could be a short-term solution, it might not be possi-
ble in the long run as the application matures and grows. Only resource management guaran-
tees that the deck of cards will not be corrupted by multiple tasks.
Resource management is accomplished with the use of two API services: GetResource()
and ReleaseResource(). In the ShuffleCards task, these two services surround the section of
the task in which the card deck is shuffled. The GetResource() service locks the resource.
StatusType GetResource(ResourceType resource);
90 Chapter 7: Resources
It compares the priority of the calling task with the ceiling priority of the resource. If the ceil-
ing priority is greater than the priority of the calling task, the calling task is raised to the
higher priority. The possible return values from the service are
• E_OK if no error occurs,
• E_OS_ID in extended status mode if the resource parameter is invalid,
• E_OS_ACCESS in extended status mode if the resource is already occupied by another task
or ISR, or
• E_OS_ACCESS in extended status mode if the priority statically assigned to the calling task
is greater than the calculated ceiling priority.
GetResource() can be invoked from the task or the interrupt level; it cannot be invoked from
any of the hook routines.
ReleaseResource() is recommended to appear in the same function as GetResource() and
exits the critical section that was entered using GetResource().
StatusType ReleaseResource(ResourceType resource);
The return values in this service are
• E_OK if no error occurs,
• E_OS_ID in extended status mode if the resource parameter is invalid,
• E_OS_NOFUNC in extended status mode if the resource is not occupied by another task or
ISR,
• E_OS_NOFUNC in extended status mode if another resource must be released prior to the
requested resource, or
• E_OS_ACCESS in extended status mode if the priority statically assigned to the calling task
is greater than the calculated ceiling priority.
ReleaseResource() can be invoked from the task or the interrupt level; it cannot be
invoked from any of the hook routines.
carddeck.c As with the previous module, the only change here is in the ShuffledCards
task, where the CARDDECK resource is locked.
7.5 Exercises
1. Create a new task called DealerCheat that resides in carddeck.c and has a priority higher
than DealCards. In this task, pull a card from the deck into a static variable that the dealer
can use later. It also should lock the CARDDECK resource when it is adjusting the deck. Acti-
vate this task after the dealer has dealt the first card in the DealCards task. Run the pro-
gram and observe the action of the tasks.
2. Define the display as a resource and lock the resource everywhere the displayBuffer glo-
bal variable is updated. This includes the OutputDisplay task. In tasks where the display-
Buffer variable is modified, make sure that the task activation for OutputDisplay is
contained within the resource locking.
92 Chapter 7: Resources
7.6 Summary
In this chapter, I discussed the resource management method in the OSEK/VDX OS, and I
defined the priority ceiling protocol and explained how it eliminates priority inversion and
deadlock. Resource management is usually critical in any real-time control system where mul-
tiple tasks can access the same resource. This resource could be a piece of hardware, such as
an I2C or SPI serial communication port that is connected to multiple high-speed devices and
requires handshaking (when the time to transmit a message is short, defining a port as a
resource works well), or a software entity, such as the deck of cards in the example program.
The OSEK/VDX method works well where a shared resource needs to be locked for a
short period of time. If a resource must be locked for an extended period of time, such as dur-
ing an EEPROM erase or write, the application developer must devise another method.
8
Chapter 8
Interrupts
The next major object in the OSEK/VDX OS is the interrupt. In many embedded applica-
tions, interrupts are critical interfaces with external asynchronous events. Examples of inter-
rupts that can be found in embedded systems are real-time clocks, sensors that send a stream
of pulses, and interrupts based on an action by the user. In this chapter, I discuss the interrupt
types identified in the OSEK/VDX OS standard and the services that manage the interrupts.
93
94 Chapter 8: Interrupts
transmission of every byte of data. If there is still data to be transmitted, the ISR simply trans-
mits the next byte of data and returns. However, after the last byte is transmitted, you might
need to set an event indicating that it has occurred, in which case, the only time an API ser-
vice is called is after the last byte has been transmitted. Therefore, it is more efficient to incur
the overhead required for an API service access only when needed.
temp = mios1Int.mios1sr0;
mios1Int.mios1sr0 = ~(0x1000);
if(GetGameState() == GAME_SHUFFLING){
EnterISR();
if(GetAlarm(ShuffleAlarm,(TickRefType)tick) == E_OS_NOFUNC){
SetAbsAlarm(ShuffleAlarm,5,3);
strcpy(displayBuffer,"\fSHUFFLING -");
ActivateTask(OutputDisplay);
}
CancelAlarm(ShufflingCompleteAlarm);
SetRelAlarm(ShufflingCompleteAlarm,1000,0);
IncrCounter(SHUFFLE_COUNTER);
LeaveISR();
}
}
I also have added an alarm — ShufflingCompleteAlarm — that replaces SampleShuf-
fleSwitchAlarm. This alarm is reset each time an edge is received. When it expires, the shuf-
fling switch is considered released and the ShufflingComplete task (Listing 8.2) is activated.
It manually sets the two events set previously in IOSampleShuffleSwitch because an alarm
can only activate one task or set one event.
The hardware used with the example program has a keyboard decoding chip that provides
an interrupt when a key is pressed. I used this capability to eliminate the IOSampleKeypad
task, and I replaced it with the category 2 ISR IOReadKeypadISR (Listing 8.3) because the
interrupt always activates the ProcessKeyPress task. The ISRs also must be defined in the
OIL configuration file prior to use (Listing 8.4).
ISR IOReadKeypadISR {
CATEGORY = 2;
};
Interrupt Services 97
ISR IOShuffleSwitchISR {
CATEGORY = 3;
};
The first category of API services is a query category in which the application can check
which interrupts are enabled or disabled. This category has one service, GetInterruptDe-
scriptor().
if(recursive==0){
recursive=1;
nextErrorLog->error = error;
GetTaskID(&nextErrorLog->task);
GetInterruptDescriptor(&nextErrorLog->descriptor);
++nextErrorLog;
98 Chapter 8: Interrupts
*displayControl = 0x01;
wait(30000);
DisableAllInterrupts();
while(translateRow < MAX_DISPLAY_ROWS)
{
outputRow = RowTranslation[translateRow++];
for(i=0;i<MAX_DISPLAY_LINE_LENGTH;i++)
{
*display = displayMessage[outputRow][i];
wait(1000);
}
}
i=((cursorPosition.row&0x01)*0x40) +
((cursorPosition.row&0x02)/2*MAX_DISPLAY_LINE_LENGTH) +
cursorPosition.column;
*displayControl = 0x80+i;
wait(1000);
EnableAllInterrupts();
}
In the task, I added DisableAllInterrupts() and EnableAllInterrupts() to create a critical
section while the routine writes the current display value to the display. This critical section
was added to ensure that the display is completely updated and not preempted in the middle
of an update. If an interrupt occurs and the task is preempted, one-half of the display can be
modified before a noticeable pause occurs and the rest of the display is updated. This inter-
ruption appears as a flicker and can be annoying to the user, so the critical section eliminates
that possibility.
100 Chapter 8: Interrupts
The fourth category of interrupt masking services disables all interrupts of category 2 or
3. This pair of services, SuspendOSInterrupts() and ResumeOSInterrupts(), have the follow-
ing function prototypes.
void SuspendOSInterrupts(void);
void ResumeOSInterrupts(void);
When SuspendOSInterrupts() is invoked, it saves the current state of all interrupts. This
state is restored when ResumeOSInterrupts() is invoked. Unlike the previous category of
interrupt masking services, these two services can be nested. The original states of all inter-
rupts that were saved when SuspendOSInterrupts() was first invoked will be restored when
the final call to ResumeOSInterrupts() is performed. How this is actually performed in an
implementation is dependent on the characteristics of the microprocessor.
As with the previous category of interrupt masking services, the application is not allowed
to invoke any API service while in this critical section. These services can be called from the
task or the interrupt level but cannot be called from any hook routines.
One point made in the OSEK/VDX OS standard is that these two services are only
intended to disable category 2 and 3 interrupts. However, if the implementation cannot dis-
able these interrupts in a limited and efficient manner, other interrupts could be disabled,
which indicates that there might be no differences between these final two categories of inter-
rupt masking services in some implementations.
In the OutputDisplay task described with the previous category of services, the critical sec-
tion also can be realized using this category of interrupt masking services. Because ISR cate-
gory 1 interrupts are typically very short, this category of interrupts should not affect the
user’s perception of the display update.
8.4.1 Modules
The modules startup.s, initspr.s, cinit.s, init.c, hw.c, and carddeck.c were not modi-
fied.
main.c This module was modified to add a specific initialization function required by the
board support package provided by Wind River. Init_ExtISRs() initializes the Wind River
external ISR routines to a dummy ISR routine that traps spurious interrupts.
debug.c This module was modified to allow the ErrorHook() hook routine to log the cur-
rent status of the interrupt mask to the error log. In addition, a special flag was added to
avoid recursive calls of ErrorHook() because the current version (as of the writing of this
book) of OSEKWorks only meets the OSEK/VDX OS v2.0 requirements. In the version 2.1
specification, recursive calls to this hook routine are prevented — the OS will not call Error-
Hook() if an error occurs while it is running. The application must check service return values
to trap an OS error in a service called from within ErrorHook().
GameState GetGameState(void)
This function simply returns the current state of the blackjack game, which is used in the ISR.
dispdrv.c OutputNewDisplay() now disables all interrupts while writing to the display, as
discussed in this chapter.
keypad.c This module was extensively modified to support an interrupt-based keypad ver-
sus a sampled keypad. The IOSampleKeypad task was replaced by the ISR IOReadKeypadISR
and was significantly shortened. In addition, one new function was added.
shuffle.c This module was also modified extensively to support the interrupts generated by
the shuffle switch.
This initialization routine was modified to remove the initial state of the input and to register
the ISR to the OSEKWorks board support package.
IOShuffleSwitchISR This ISR, which was discussed in this chapter, replaces the prior
task, IOSampleShuffleSwitch, and extensively shortens the code. The INTERRUPT modifier
is not defined because the board support package does not support ISR category 3 inter-
rupts. However, if this routine is used on a different processor, the INTERRUPT macro
should be defined as the modifier for an interrupt routine for the specific compiler. The
definition for INTERRUPT is found in os.h.
8.4.2 Exercises
1. In an exercise in Chapter 5, a switch was added and the number of times that it was
depressed was counted. Make sure that the switch is connected to an input that can gener-
ate an interrupt when the switch is depressed and modify the routine to be an ISR.
2. Set a breakpoint in OutputNewDisplay() after the interrupts are disabled. Also set a break-
point at the entrance to the keypad ISR. Press a key on the keypad and then step through
the rest of the routine. Verify that the interrupt does not occur until after EnableAllInter-
rupts() is invoked.
3. Review the source code and determine if there are other critical sections that need to be
added.
8.5 Summary
In this chapter, I discussed how interrupts are handled in the OSEK/VDX OS. The categories
of ISRs were introduced and the requirements for each category, with respect to the OS, was
described. In addition, the many different methods of enabling and disabling interrupts and
determining current interrupt status were discussed.
Interrupts are the most powerful method of optimizing throughput in the application.
However, when interrupts are introduced into an application, the possibility of problems
increases because it is very difficult to debug interrupt-driven software. The example program
uses interrupts for all user inputs because the application will probably be installed in a bat-
tery-driven system, so it is very important to conserve battery power. The developer of the
application will have to make the trade-off decision about using interrupts — complexity ver-
sus efficiency.
9
Chapter 9
Interprocess
Communication
The final OS objects are interprocess communication, or messaging, objects that are actually
part of the communication (COM) standard. In version 2.1 of the OS standard, any OS that
is OSEK/VDX-compliant must support, at a minimum, conformance class A from the COM
standard. Some implementations could include communication conformance class B, but this
chapter describes the attributes of conformance class A only and the services available to sup-
port this level of interprocess communication.
The OSEK/VDX COM standard is very complex and is covered in detail in Part 2. How-
ever, some of the features, as they apply to the minimal requirements of the OS, are intro-
duced here.
Unqueued messages Messages are not queued under a conformance class A implementa-
tion. This means that a message can be read by an application any number of times and the
data received last is returned every time; that is, it is not consumed by being read.
103
104 Chapter 9: Interprocess Communication
With- and without-copy In a with-copy scenario, messages are sent and received using a
copy of the message object that is available to the application. This allows the application to
access the message data without concern to corrupting the data or creating inconsistent data.
In the without-copy scenario, the application accesses the message object directly, and a con-
cern arises about corruption of the data. Conformance class B provides mechanisms to
address this concern, and will be discussed in Part 2.
1:1 and 1:many messaging Messages are sent by one task, but they can be received by
one or a multitude of tasks. Inputs sampled and filtered by one task but used by many tasks
use 1:many messaging, often referred to as 1:n.
9.2 Notification
The OSEK/VDX COM standard has five notification classes through which the communica-
tion system notifies an application of a message status. Only notification class 1 is available
for conformance class A. Class 1 notification is also referred to as message reception notifica-
tion. For internal communication, which is the only kind of communication supported by the
OS, notification occurs as soon as the message is transmitted.
Four types of mechanisms are available for notification: Task, Event, Callback Routine,
and Flag. Task and Event notification require an OS that supports these mechanisms. Task
refers to the mechanism that activates the task when the notification occurs. Event refers to
the mechanism that sets an event when the notification occurs.
The OSEK/VDX COM standard was intended as a stand-alone specification and does not
require an OSEK/VDX-compatible OS to support its lower conformance classes. Conse-
quently, the communication component can be used in an application that does not support
activating tasks or setting events. To handle this eventuality, the Callback Routine and Flag
notification mechanisms were added to support more general RTOSs or applications without
an RTOS, such as a cyclic executive. Because this chapter discusses the use of messages within
the OSEK/VDX OS, I do not discuss these mechanisms until Part 2, which covers the Com-
munication Specification.
To demonstrate the use of messages and notifications, I will modify the example program
and create a simple message that is sent to the display. This replaces the displayBuffer global
variable, which was used as a temporary location for the message. I will use the messaging
capability of the OS to perform most of the work. First, I create the definition of the message
in the OIL configuration file (Listing 9.1) and modify whichever task uses the message.
The MESSAGE object defines a message structure to the application. The first attribute is
TYPE. For conformance class A, the only type available is UNQUEUED. For other conformance
classes, QUEUED is also available and is discussed in Part 2.
Notification 105
TASK OutputDisplayBuffer {
TYPE = EXTENDED;
SCHEDULE = NON;
PRIORITY = 14;
ACTIVATION = 1;
AUTOSTART = TRUE;
ACCESSOR=RECEIVED {
MESSAGE = DisplayMessage;
WITHOUTCOPY = FALSE;
ACCESSNAME = displayMirrorTemp;
};
STACKSIZE = 128;
SCHEDULE_CALL = FALSE;
EVENT = { BUFFER_CHANGED, DISPLAY_READY };
};
/**************************************************************************/
/* Messages */
/**************************************************************************/
MESSAGE DisplayMessage {
TYPE = UNQUEUED;
CDATATYPE= "DISPLAY_MESSAGE_TYPE"
ACTION=SETEVENT {
106 Chapter 9: Interprocess Communication
TASK = OutputDisplayBuffer;
EVENT = BUFFER_CHANGED;
};
LENGTH = 80;
ALIGNMENT = 1;
USAGE = SEND_RECEIVE;
ACCESSNAMES = { displayMirrorTemp, displayMirror };
};
The second attribute in the MESSAGE object definition is CDATATYPE, a string that describes
the data type of the message. This can be either a standard C data type such as int or char, or
it can be a user-defined type such as DISPLAY_MESSAGE_TYPE, as in this example, which is
defined in dispdrv.h. It defines a local copy of the message that appears on the display. This
type definition defines a structure of one character array of 80 characters, as shown in Listing
9.2. The constants MAX_DISPLAY_ROWS and MAX_DISPLAY_LINE_LENGTH define the number of
rows and lines on the display.
Message Task
1 MESSAGE ACCESSNAME
0..* 0..*
Accessor
+WITHOUTCOPY:RiCBoolean
+SENT_RECEIVED:char
Because the relationship between the task class and the message class is a many:many
relationship, ACCESSOR is a container object that maps this relationship. For each task, zero to
many accessors could be defined. Each accessor maps to only one message, but multiple
accessors can and will map to one message.
The ACCESSOR attribute has a value of SENT or RECEIVED and sets three parameters: MES-
SAGE, WITHOUTCOPY, and ACCESSNAME. The MESSAGE parameter is the name of the message to
which the relationship is mapped. This message must be defined elsewhere in the OIL config-
uration file. The WITHOUTCOPY parameter is a Boolean TRUE or FALSE. Finally, the ACCESSNAME
parameter is the name of the accessor that is typically created by the OIL configuration utility
and referenced by the task.
The message accessor concept within the OSEK/VDX COM specification appears confus-
ing at first. In the COM v2.0 specification, the implementation of an accessor was left to the
developer. However, since COM v2.2, it simply defines the name of the variable that is visible
to the application and is used by the task to send or receive data. This global variable is cre-
ated by the OIL configuration utility.
When the OIL configuration file is processed, an implementation typically creates the mes-
sage object in the OIL output source file. It then selects all of the message accessors defined
within the TASK object definitions that have the WITHOUTCOPY parameter set to FALSE and cre-
ates a duplicate copy in the output file. For all tasks with the ACCESSOR parameter WITHOUT-
COPY set to TRUE, the configuration utility will create an alias name that allows the application
to access the message object using the accessor name. Use of these access names is discussed
in the examples.
One drawback of accessors is the way they are used in some of the implementations on
the market. When a message is defined, the message object is created as a RAM variable. For
every accessor that is defined with the WITHOUTCOPY parameter set to FALSE, a variable of the
same type as the message is created and is available globally. It is the responsibility of the
application to ensure that the only task that accesses this variable is the one to which the
accessor name is defined. This also limits the ability of an application to create a locally
108 Chapter 9: Interprocess Communication
defined variable into which the message is copied and which is destroyed when the task termi-
nates. From the implementation standpoint, however, these multiple copies make the imple-
mentation much more efficient and robust.
In an application that has limited RAM memory, this drawback can be addressed by
accessing all message objects using ACCESSOR objects with the WITHOUTCOPY parameter set to
TRUE. This limits the creation of only one message object in RAM. If the application requires
a local copy of the message object when received, then the application can use the C library
function memcpy() to do a byte-wise copy of the global message object into a local message
object. However, the application must ensure that the local object has the exact same
CDATATYPE as the global object. Because of some quirks of C , this is not guaranteed to work.
A message is now defined that will be used by the OutputDisplay task to send a message
to the OutputDisplayBuffer task, which then outputs the message to the display.
StartCOM();
while(list->appmodemask != 0x00000000){
if((list->appmodemask & currentAppModeMask)!= 0){
if(list->alarmtype == ALARM_REL){
SetRelAlarm(list->alarm,list->start,list->cycle);
}
else{
SetAbsAlarm(list->alarm,list->start,list->cycle);
}
}
list++;
}
TerminateTask();
}
TYPE = BASIC;
SCHEDULE = FULL;
PRIORITY = 16;
ACTIVATION = 1;
AUTOSTART = TRUE;
STACKSIZE = 128;
SCHEDULE_CALL = FALSE;
};
Communication Services 111
For example, if the communication component needs an extended task to perform a cer-
tain function, StartCOM() will activate that task. It gets tricky here because the OSEK/VDX
COM specification was written to be independent of the OS. If the communication compo-
nent uses counters, alarms, or tasks as defined in the OSEK/VDX OS, it might not be porta-
ble. I discuss this relationship between the OS and the communication component in more
detail in Part 2. At this time, I am not concerned with the issue since I only use the OS portion
of the OSEK/VDX COM specification.
The return value, which is the same whether the system is in standard or extended status
mode, is
• E_OK if the startup completes successfully or
• specific to the implementation if the startup does not complete successfully.
StartCOM() must be called from within a task and must be called after InitCOM() and before
CloseCOM() or else the behavior is undefined.
InitCOM() and CloseCOM() were added in the latest COM specification to allow the ini-
tialization of communication hardware before the OS starts. In earlier COM implementa-
tions, these services were not present, and in most current implementations, they exist but do
nothing, especially where the OS and COM modules are integrated.
As mentioned earlier, messages can be sent and received with- or without-copy. If the mes-
sage is handled without-copy, the variable that holds the copy needs to be initialized prior to
use. Many times, this variable will be global and needs to be set to a default value by the
application. This is accomplished from within StartCOM() by optionally using the user-
defined callback routine MessageInit().
StatusType MessageInit(void);
This routine allows the application to initialize all application-specific message objects.
Although provided by the specification, the application is not required to provide this call-
back routine and could use another method of initializing message objects.
Message object initialization can be accomplished a number of ways. The two most com-
mon methods is either to set the global variable to a constant for without-copy messages or to
send a message initially using SendMessage(), which is described later in this chapter. Send-
Message() cannot be invoked from within MessageInit().
Because COM only allows messages to be sent from one location within the system, the
initial value of any message sent with-copy theoretically can only be set by that task or func-
tion. Consequently, if an internal message is received before the application sends the mes-
sage, the value of the data is indeterminate. In the COM specification v2.2.2 released in early
2001, the return status for an unqueued message that indicates a message was never sent or
received was removed from the standard. The COM specification requires that the value
returned to the application be the value set at initialization. However, there is no description
of how the message is initialized. To resolve this, the application has a number of options to
initialize messages sent by the application.
1. If the COM implementation does not enforce sending messages from only one task or
function, the application can send the message from one task or function during initializa-
tion and from the regular location during normal operation. This option can affect porta-
bility of the application and could require changes if a different COM implementation is
used. However, if the initialization of the message data for all messages in the system is
112 Chapter 9: Interprocess Communication
kept within one task or function, porting to a new implementation would be minimized.
This option typically would be performed immediately after the return from the function
StartCOM(). You should take care during normal operation of the application that the
message is sent only from one location. This option is only available for internal and inter-
nal–external messages.
2. Activate all tasks and execute all functions that send messages immediately after the com-
munication component starts. This would occur in the same location as option 1 men-
tioned previously. The drawback of this method is that there is no guarantee the tasks will
be performed in the proper order to ensure data consistency.
3. Send all internal messages without-copy and receive them either with- or without-copy. In
this manner, the application can initialize the global variable either within the Message-
Init() callback function or within the task that executes StartCOM(). This requires that a
coding standard is enforced globally within an application.
4. Create a flag for every unqueued message using the COM notification mechanism. These
flags can be reset in the routine that calls StartCOM() and then checked whenever a mes-
sage is needed. If the flag is set to TRUE, the message has been sent or received at least once
by the COM component. If the flag is set to FALSE, the message has never been sent or
received since the COM component was started. The drawbacks of this method are the
added overhead every time a message is received by an application task and the unavail-
ability of flags in conformance class A.
Because of the extensive effort required to initialize unqueued messages, the COM specifi-
cation still needs some work. A revised COM specification or the next release of the OIL
specification could address how message data is initialized. Until that time, I recommend that
you select a COM implementation that does not enforce sending messages from a single point
as in option 1. When the initialization issue is addressed, only a single routine in an applica-
tion will have to be changed.
The other task to be created is CloseOS, which has exactly the same attributes in the OIL
configuration file as the previous task, InitOS, does not start automatically, and has a priority
of one less than InitOS. A priority of one less than InitOS maintains a level 1 (BCC1/ECC1)
system that results in a more optimal implementation. To move to a level 2 (BCC2/ECC2)
system, the priority of CloseOS if you could be the same as that of InitOS.
The CloseOS task performs application-specific housekeeping procedures prior to shutting
down the OS. It is activated by ChangeMode(), which was created in Chapter 1. ChangeMode()
activates the task CloseOS instead of calling ShutdownOS(). I do not discuss ChangeMode()
here because the changes are minimal. You can refer to main.c on the accompanying CD to
view the modified service. I have also added one small application service called GetRequest-
edMode(), which simply returns the requested APPMODE. Listing 9.7 shows the CloseOS task
and Listing 9.8 shows the OIL configuration for this task.
In CloseOS, StopCOM() stops the communication component and ShutdownOS() shuts
down the OS and sets the status type parameter to E_OK.
StatusType StopCOM(Scalar mode);
Communication Services 113
StopCOM() immediately stops all OSEK/VDX communication activity, frees all OS resources
used or puts the resources in an inactive state, and prepares the communication component
for the next invocation of StartCOM(). Because the level of support for OSEK/VDX COM in
an OS environment only allows internal messages, StopCOM() does not have to worry about
initializing hardware or waiting for messages in the process of transmission to complete. The
function of the communication component with respect to external communication is dis-
cussed in Part 2.
The mode parameter passed to StopCOM() tells the service how to shut down the communi-
cation component. The OSEK/VDX COM specification only defines one possible value for
this parameter, COM_SHUTDOWN_IMMEDIATE. If this value is passed to the service, the service
shuts down the communication component immediately without waiting for pending opera-
tions, such as transmissions in progress, to complete. This behavior directly contradicts the
StopCOM() definition, which says the system should complete sending messages before it shuts
down. The original proposal for StopCOM() included the COM_SHUTDOWN_GRACEFUL parameter,
which allowed operations to complete, if necessary, or would cause the service to return E_
COM_BUSY if the application locked one of COM’s resources, such as a message buffer, prevent-
ing its release. This feature was removed from the published standard. Specific implementa-
tions could define additional modes, but to ensure portability, they should not be used.
In the listing, StopCOM() is shown without a parameter. This is due to the fact that the
example was written for an implementation that was compliant to the OSEK/VDX COM
standard version 2.1, which did not have this service explicitly defined.
114 Chapter 9: Interprocess Communication
The return value from StopCOM(), which is the same whether the system is in standard or
extended status mode, is
• E_OK if the communication component stops successfully or
• E_COM_BUSY if the communication component cannot shut down because a resource
owned by the component is in use by the application.
With these changes to the initialization of the communication component, an application
can now use interprocess communication. The first task is to modify how messages are out-
put to the display. In Chapter 4, I created the OutputDisplay task, which uses a global vari-
able to obtain the information to be displayed. The simplest way to modify this task would be
to create a message that contains the information to be displayed. The application sends this
message to this task, so it has to be able to send it from multiple locations (many:1 communi-
cation). However, the OSEK/VDX COM standard only allows 1:1 and 1:many communica-
tion.
To get around this limitation of the system, I made extensive modifications to how the
application handles the display. In prior examples, the application wrote the data to a global
variable. This created all of the problems associated with global variables; namely, multiple
tasks can update the single variable. To address this, I created two display services that encap-
sulate the output buffer: WriteDisplay() and WriteDisplayAt(). WriteDisplayAt() includes
two additional parameters, the row and the column from which to begin displaying the value,
whereas WriteDisplay() is implemented as a call to WriteDisplayAt(), with the row and col-
umn set to 0xFF, indicating that output should occur at the current cursor position. WriteDis-
playAt() (Listing 9.9) buffers the information and the desired cursor position.
if(displayBufferError == FALSE){
SuspendOSInterrupts();
displayBuffer[displayBufferEnd].row = row;
displayBuffer[displayBufferEnd].column = column;
strcpy(&displayBuffer[displayBufferEnd].buffer,text);
if(++displayBufferEnd == DISPLAY_BUFFER_SIZE){
displayBufferEnd = 0;
}
if(displayBufferEnd == displayBufferStart){
displayBufferError = TRUE;
}
ResumeOSInterrupts();
ActivateTask(OutputDisplay);
}
Communication Services 115
else{
result = FALSE;
}
return result;
}
while(*string != 0)
{
switch(*string)
{
...
default:
if(*string >= 240)
{
displayMirror->message[cursorPosition.row*MAX_DISPLAY_LINE_LENGTH
+ cursorPosition.column++] = *string - (char)240;
}
else
{
displayMirror->message[cursorPosition.row*MAX_DISPLAY_LINE_LENGTH
+ cursorPosition.column++] = *string;
}
if(cursorPosition.column == MAX_DISPLAY_LINE_LENGTH)
{
OutputNewLine();
}
}
++string;
}
}
Communication Services 117
My decision to limit the example application to a level 1 conformance class and to limit
the number of extended tasks illustrates the problems inherent in determining the conform-
ance class to use. If a task with a higher priority than OutputDisplay attempts to display
information between the end of the while loop and the termination of the task (preemption),
information would be locked into the buffer and would not be output until the next time a
task attempted to send information to the display. The sequence of events that can cause this
to occur is shown in Figure 9.2, in which Task A is priority 13, Task B is priority 14, Task C is
priority 15, and OutputDisplay is priority 12.
0
1 B C A
1
2 C A B
0
3 C A B
0
4 A B C
1
5 A B C
1
6 C A B
1
B C A
One method of resolving this issue is to make the task that extracts information from the
buffer an extended task and to clear the event that signals that the information has been
added to the buffer prior to flushing the buffer. When an item is added to the buffer, an event
must be set. This will need to be added to tasks A and C above. If the situation in number 4
above occurs, the event remains set, and as soon as the task attempts to wait on the event
again, it immediately resumes and flushes the remaining item from the buffer. The drawback
to this method is that it requires an extended task, which increases the size of the kernel and
the resources used.
A method that would work with basic tasks is to make the task that extracts information
from the buffer non-preemptive and use Schedule() to multitask cooperatively. In the exam-
ple program, I made OutputDisplay a non-preemptive task. However, I allow preemption to
occur after one piece of information has been processed from the buffer and prior to the
check for an empty buffer. In this manner, preemption is allowed under the control of the
application and addresses the issue described in Figure 9.2.
After all pieces of information have been removed from the information buffer, the mirror
buffer with the copy of the display is transmitted to the output display driver using SendMes-
sage().
WriteDisplay(InitMessage);
while(1){
translateRow = 0;
WaitEvent(BUFFER_CHANGED);
ClearEvent(BUFFER_CHANGED);
ReceiveMessage(DisplayMessage,displayMirrorTemp);
*displayControl = 0x01;
SetRelAlarm(DisplayWaitAlarm,10,0);
WaitEvent(DISPLAY_READY);
ClearEvent(DISPLAY_READY);
DisableAllInterrupts();
while(translateRow < MAX_DISPLAY_ROWS){
outputRow = RowTranslation[translateRow++];
for(i=0;i<MAX_DISPLAY_LINE_LENGTH;i++){
*display = displayMirrorTemp->message
[outputRow*MAX_DISPLAY_LINE_LENGTH + i];
wait(1000);
}
}
i=((cursorPosition.row&0x01)*0x40) +
((cursorPosition.row&0x02)/2*MAX_DISPLAY_LINE_LENGTH) +
cursorPosition.column;
*displayControl = 0x80+i;
wait(1000);
EnableAllInterrupts();
}
}
OutputDisplayBuffer is an extended task that starts automatically when the OS starts. It
waits for the BUFFER_CHANGED event to be set and enters the WAITING state. Because the display
is relatively slow compared to the speed of the application, the local copy of the display can
120 Chapter 9: Interprocess Communication
be modified and thereby corrupted during the write operation. Consequently, OutputDis-
playBuffer accesses the message with-copy using the access name displayMirrorTemp prior
to writing the information to the display. I also added a delay early in the task after I clear the
display and return the cursor to the home position. An alarm moves this task out of the WAIT-
ING state while the display clears, which can take up to 10 milliseconds.
ReceiveMessage() copies the message object to the copy object.
9.4.1 Modules
The modules startup.s, initspr.s, cinit.s, debug.c, hw.c, os.c, and keypad.c were not
changed in this chapter. The following modules were changed.
Example Program 121
init.c The InitAlarms task was renamed InitOS and the CloseOS task was added. In addi-
tion, the MessageInit() callback routine was provided, but at this point, it does not perform
any actions.
main.c ChangeMode() was modified to activate a task instead of shutting down the system.
The hook routines StartupHook() and ShutdownHook() were modified to initialize a commu-
nication component. Finally, GetRequestedMode() was added.
cardgame.c A number of tasks and functions within this module were modified to use the
new interfaces WriteDisplay() and WriteDisplayAt() instead of the displayBuffer global
variable.
dispdrv.c Many changes were made to the tasks and functions found in this module.
void PackDisplay(char *string) This function now updates the message object refer-
enced by the displayMirror accessor instead of the displayMessage static variable.
WriteDisplay() and WriteDisplayAt() were described in detail in this chapter and will
not be repeated here.
OutputDisplayBuffer task This task first writes the initialization message to the display
and then waits for a message to be sent. OutputDisplayBuffer, which was discussed in
detail in this chapter, replaces OutputNewDisplay() from Chapters 4 and 8.
OutputDisplay task This task was modified extensively from the versions in Chapters 4
and 8.
carddeck.c This module was modified to support the new interfaces WriteDisplay() and
WriteDisplayAt(). The following function was modified.
shuffle.c This module also was modified to support the new interfaces WriteDisplay()
and WriteDisplayAt().
9.5 Exercises
1. Create a message that contains a single character. Whenever a key is pressed on the key-
pad that is not required for the game, send a message with this character. Create a task in
the debug.c module to receive this message, and activate the task whenever the message is
sent. Log the last 20 illegal characters pressed. Send and receive messages with-copy.
2. Create a message that contains a structure that has the current game time from the task
that was created in Chapter 5, Exercise 3. Whenever the deck is shuffled, send a message
with the current running time. Create a new task in the cardgame.c module that receives
this message and calculates the average time it takes to play a hand. Remember to ignore
the first shuffle. Send and receive messages without-copy; however, perform a manual
copy to a local variable within the task. This manual copy was discussed in Section 9.2,
“Notification,” which discusses RAM.
9.6 Summary
In this chapter, I discussed the interprocess communication support required in an
OSEK/VDX-compliant OS. These services are a subset of the OSEK/VDX COM specification
and implements, at a minimum, communication conformance class A. Most OSEK/VDX
implementations probably will implement conformance class B. A description of conform-
ance class B is provided in Part 2.
To provide interprocess communication, the system must be initialized and started before
messages are sent and received. Because the COM specification is intended to operate inde-
pendently of the OS, you can start and stop communication and initialize and close the com-
munication component without leaving the OS.
This concludes the coverage of the OSEK/VDX OS specification. I recommend that you
take some time now to play with a stand-alone application, if you have an implementation
available, and really learn the intricacies of the system and your particular implementation.
P ART 2
Communication
The second specification in the OSEK/VDX system, communication (also referred to as
COM), defines the interfaces and the protocols for both intertask and interprocessor commu-
nication within an application and across applications. The OSEK/VDX COM specification is
similar to the OS specification in that it provides a standard API with services. Because each
OSEK/VDX standard is capable of operating on its own, you might have skipped the OS por-
tion of this book and moved directly to this section. Consequently, items of overlap between
the OS and COM systems that were covered in Chapter 9, “Interprocess Communication,”
and brief definitions of tasks, alarms, and events are repeated throughout Part 2.
123
This Page Intentionally Left Blank
10
Chapter 10
Communication
10.1 Communication Model
The OSEK/VDX communication standard supports both intertask communication and inter-
processor communication. It is intended to be independent of protocol and flexible enough to
use in any environment. To reach these goals, a five-layer system was developed that has some
parallels to the International Organization for Standardization open systems interconnection
(ISO/OSI) seven-layer model. This chapter describes the attributes of the communication
model and builds the foundation on which the rest of Part 2 rests. I’ve included very few
examples in this chapter, but each chapter builds on a part of the model introduced here.
The communication model is complex and not easily understood. This chapter introduces
all of the attributes of messages at one time in a summary format and could appear confusing
on first read. If something is not clear in this chapter, read on into the next chapters, for more
detailed discussions.
125
126 Chapter 10: Communication
point protocol, or proprietary protocols, and several hardware networking standards can be
mixed in a single COM environment.
The COM specification defines an asynchronous communication model in which the
application is not required to wait for a message before it resumes processing and it is not
blocked if a message is not available when it is requested. To implement this model, COM
defines a number of notification mechanisms that assist the application in understanding
when a message has been sent or received.
Each message defined for an application can have only one sender within the system, but it
can be received by one or many receivers. These receivers can be tasks that are internal, exter-
nal, or both.
Application Application
Interaction Presentation
Session
Transport
Network Network
DataLink DataLink
Physical Physical
The third layer, the network layer, consists of the software that transfers messages from
the interaction layer to the data link layer. Like the data link layer, there can be multiple net-
work layers, one for each protocol used in the system. The network layer provides services to
the interaction layer and uses the services of the data link layer to provide two types of data
transfer: unacknowledged unsegmented data transfer (UUDT) and unacknowledged seg-
mented data transfer (USDT). This layer is described in more detail in Chapters 12 and 13.
The network layer knows to which data link layer to send the message and the maximum size
of the message allowed over the network. One network layer can interface with multiple data
link layers.
The fourth layer, the interaction layer, interacts directly with the application. This layer
understands two types of messages (internal and external), provides all of the API services to
the application, and uses the network layer to transfer external messages over the network. If
the message is internal, it is completely processed in this layer. This layer is described in more
detail in Chapter 11. Figure 10.2 shows an example application in which an electronic con-
trol unit (ECU) is attached to four separate networks. An ECU, as defined within the
OSEK/VDX standard, is an electronic device that consists of at least one microcontroller. This
particular example has a single microcontroller. CAN typically operates at 125 kbits/sec to 1
mbit/sec. J1850 also is an automotive industry–standard communication protocol, but it runs
at a much slower rate. Both protocols allow the use of different physical layers. Figure 10.2
shows both a single-wire and a differential dual-wire physical layer, each requiring a different
data link component because of hardware differences. When hardware differences are not an
issue, a single data link layer can support both physical layers.
the following sections. Throughout this section and the following sections, I refer to a num-
ber of messages as examples. The OIL configuration for these messages is shown in Listing
10.1 and is referred to throughout this chapter. This configuration uses the implementation-
specific attributes found in the OSEKWorks implementation.
Interaction Layer
Physical Layer
RX_NOTIFICATION = ON_SUCCESS;
TRANSMISSION = DIRECT;
RX_SUCCESS_TASK = ProcessKeyPress;
ACCESSNAMES = { keyValue };
};
MESSAGE OpponentMessage {
TYPE = EXTERNAL;
LENGTH = 80;
ALIGNMENT = 1;
USAGE = RECEIVE;
QUEUED = FALSE;
TX_NOTIFICATION = NONE;
RX_NOTIFICATION = ON_SUCCESS;
TRANSMISSION = DIRECT;
RX_SUCCESS_TASK = ProcessOpponentMessage;
ACCESSNAMES = { opponentMessageString };
CAN_ADDRESSES = { OpponentMessageAddress };
};
Application
Communication
Component
CopyA1 CopyB1
Message1 Message2
In Figure 10.3, two messages —Message1 and Message2 — and three application tasks
—TaskA, TaskB, and TaskC — exist. When a message is sent with-copy, the communication
component maintains a copy of the message internally and copies the data from it into the
message object when sent. When received with-copy, it puts the data into this internal copy
from the message object. The internal copy is visible to the application through the accessor.
In the example, when TaskA updates Message1, it updates the data in CopyA1, which is
accessed using the access name defined in the OIL configuration file for the accessor. When
the message is sent, the communication component copies the data from CopyA1 into the
Message Attributes 133
data section of Message1. When TaskB receives Message1 that was sent by TaskA, the com-
munication component copies the data out of the data section of Message1 into CopyB1.
TaskB can then access the copy of the data using the access name defined in the OIL configu-
ration file for the accessor.
When a message is sent without-copy, the communication component exposes the mes-
sage object as a global variable. In the example in Figure 10.3, when TaskB accesses the data
in Message2, it updates the message object. When the message is sent, the communication
component does not copy any data; instead, it updates the status of the message. When
TaskC receives Message2, the communication component only returns the status of the mes-
sage and takes no action on the message data itself. TaskC, if the return status indicates that
the message is valid, will access the message object directly because it must be visible to both
TaskB and TaskC.
In the case where a message is accessed both with- and without-copy, the communication
component creates a copy for the with-copy accessor and allows the task that has defined a
without-copy accessor to access the message object directly. In the example, if TaskB sends
Message2 without-copy and TaskC receives the message with-copy, the implementation cre-
ates CopyC2 into which the message object is copied, when received, and is accessible to
TaskC.
One obvious drawback is that with-copy access requires that additional copies of the mes-
sage object be created for every task. In some implementations, these copies are defined stati-
cally and use scarce RAM resources, even when the sending or receiving task is suspended.
This drawback was addressed by creating the without-copy access method. However, the
message object now becomes a global variable, which can be corrupted by the sender before
the receiver has completed processing the last message, so this also is not a good practice. To
address the access issue with global variables, the OSEK/VDX COM specification has created
a method of locking a COM resource.
In some cases, an application might need to conserve scarce RAM resources, but it still
requires a local copy of a message object that is destroyed when the function or task termi-
nates. To accomplish this, perform the following.
• Create the message and access it without copy.
• Lock the message resource.
• Copy the global message object to the local object. This might require the use of memcpy(),
so make sure that the message object and the local object are identical.
• Release the resource.
The task now has a local copy of the message object, and the sending task is now free to
update the message object without affecting the data used by the receiving task. This particu-
lar scenario is discussed in more detail in an example in Chapter 11.
All queued messages must be accessed with-copy because, by definition, the communica-
tion component must create the queue internally. Unqueued messages, however, can use the
global variable created by the communication component to hold the message data and can
be accessed without-copy.
With-copy messages guarantee data consistency to the application at the expense of a mes-
sage buffer for each receiving task and the time required to make the copy. Without-copy
messages are faster and use less RAM, but the application programmer is responsible for
134 Chapter 10: Communication
ensuring data consistency (i.e., preventing the sender and receiver from using the buffer at the
same time).
The message attributes introduced throughout Section 10.2 are defined in more detail in
the chapters that follow, along with examples showing how each affects the messages.
10.3.1 Direct
Direct transmission describes a mode in which the message is sent only when the application
requests it. By definition, internal messages can only be direct messages because as soon as
they are sent, they are available to be read by another task in the application. External mes-
sages that are defined as direct messages are transmitted on the external bus as soon as possi-
ble after the application sends the message. This message is delayed based only on the priority
within the protocol chosen for the external network and the depth of the queue of messages
in the data link layer.
10.3.2 Periodic
Periodic transmission mode, referred to as periodical transmission mode in the specification,
describes a message that is sent periodically with the period defined statically by the system.
Periodic messages must also be defined as external messages. The application can start and
stop transmission of all periodic messages as a group, but not individual periodic messages.
If an application sends a periodic message without-copy, the application must lock the
message resource while it is being updated. If the COM component transmits the message
data while the message is being updated, inconsistent data will be transmitted on the network
bus. Locking is not required for messages that are sent with-copy because the COM compo-
nent insures consistency of data.
Transmission Modes 135
Direct()
Direct_Msg()
Direct_Msg()
Direct_Frame()
Periodic()
Mixed()
Mixed_Msg()
Mixed_Msg()
Mixed_Frame()
Periodic_Msg()
Periodic_Msg()
<=Mix_Period
Per_Period Periodic_Frame()
Mixed_Msg()
Mixed_Msg()
Mixed_Frame()
Mix_Period Periodic_Msg()
Periodic_Msg()
Periodic_Frame()
Mixed_Msg()
Mixed_Msg()
Mixed_Frame()
10.3.3 Mixed
The final transmission mode is mixed mode, in which an external or internal–external mes-
sage is sent both directly and periodically. In Figure 10.4, the mixed message is sent at a fixed
period. Whenever the application sends the message, it is sent out on the network based on a
set of conditions that are defined statically. The possible conditions under which the message
is sent are shown in Table 10.1. Keep this table in mind because the conditions used here are
used later when I discuss conditional notification of message reception.
Conditional transmission assumes that a comparison can be made between two message
objects that would require that a value in the message could be compared using the normal C
logical functions, although it would be specific to the implementation. If this is the case, then
messages that consist of a structure, strings, or arrays cannot be compared and, therefore,
will always be transmitted. However, if the implementation provides a mechanism to com-
pare more complex messages, such as a callback function, it might not be portable and should
be avoided (i.e., the callback function should emulate the situation described above and
always send the message.)
136 Chapter 10: Communication
Change Description
Less than The value of the message object is less than a constant value
Greater than The value of the message object is greater than a constant value
Equal The value of the message object is equal to a constant value
The difference (current – previous) in the values of the message
Delta less than object is less than a constant
The difference (current – previous) in the values of the message
Delta greater than object is greater than a constant
The difference (current – previous) in the values of the message
Delta equal object is equal to a constant
Always A relevant change is always detected
User defined The user defines a relevant change (implementation specific)
In mixed message transmission mode, the message is transmitted on the network without
regard to when the periodic message is scheduled to be sent next. Sending the direct message
does not restart the timer that determines when the next periodic message is sent. Conse-
quently, a message could be transmitted twice in a row over the network if the application
sends the message just prior to or just after the periodic message is transmitted.
Direct()
Direct_Msg()
Direct_Msg()
Direct_Frame()
Monitor
Msg_Success()
Msg_Success()
Direct()
Direct_Msg()
Direct_Msg()
Monitor
Notify()
In the second part of the example, the timer expires prior to notification by the network
layer that the message has been transmitted successfully. This will coincide roughly with the
time to transmit the third message. If this occurs, the timer function notifies the interaction
layer that time has expired, and the interaction layer then notifies the application by invoking
one of the notification mechanisms. The interaction layer, however, will continue to attempt
to send the periodic message. If the timer is not running or has expired, the interaction layer
restarts the timer when the message is sent; however, if the timer is still running, it is not
restarted. This addresses the instance where the integer multiple of the period is greater than
one, as in the final part of the example.
Deadline Monitoring 139
Periodic()
Periodic_Msg()
Periodic_Msg()
Periodic_Frame()
Msg_Success()
Msg_Success()
Periodic_Msg()
Periodic_Msg()
Period*2
Periodic_Msg()
Periodic_Msg()
Periodic_Msg()
Periodic_Msg()
Notify()
Periodic_Msg()
Periodic_Msg()
When the periodic timeout is greater than one, the timer is allowed to run until it expires
or one of the messages is sent successfully on the network. If the timer expires before one
message is sent successfully, then the notification mechanism is activated again.
when the interaction layer determines that a message should be transmitted under the peri-
odic portion of mixed transmission mode, or when the application requests a direct transmis-
sion, in which case, the message is transmitted conditionally. The conditions under which a
direct transmission can occur were discussed in Table 10.1. The value of the timer used for
mixed-mode deadline monitoring is the same as that calculated for monitoring the transmis-
sion of periodic messages. Cancellation of the timer occurs if the network layer notifies the
interaction layer of successful transmission of the message over the physical network.
In the first part of Figure 10.7, the timer is restarted when the periodic message is sent by
the application with a value that meets the conditions for direct transmission and canceled on
receipt of confirmation that the message was sent. In the second part of the figure, the timer is
started after the periodic message is sent to the network layer and expires before a confirma-
tion of successful transmission is received. In this case, the interaction layer notifies the appli-
cation of the transmission failure.
Mixed_Msg()
Mixed_Msg()
Mixed_Frame()
Msg_Success()
Period
Msg_Success()
Mixed()
Mixed_Msg()
Period Mixed_Msg()
Mixed_Frame()
Msg_Success()
Msg_Success()
Mixed_Msg()
Mixed_Msg()
Period
Mixed_Msg()
Mixed_Msg()
Notify()
142 Chapter 10: Communication
Start()
First_Timeout
Msg_Frame()
Msg_Received()
Msg_Received()
Monitor Msg_Frame()
Msg_Received()
Msg_Received()
Monitor
Notify()
The mechanisms of callback and flag were added in the COM v2.2 specification. Because
the goal of COM was to create a specification that could stand on its own, a method to notify
an application not using an OS was required. Under the callback mechanism, the COM com-
ponent executes a function when a notification is to occur. This function must have the fol-
lowing C prototype.
void CallbackFunc(void);
Because CallbackFunc() is executed immediately when notification is required, it could be
evoked at the interrupt level if the COM component determines that notification is required
from within an ISR, which could affect interrupt latency.
The flag mechanism works in an OS that polls the status of messages from within tasks
that are executed either in a round-robin or a time-sliced executive. API services that check
the status of the flag and reset the flag were added.
Notification Mechanisms 143
The COM specification also defines five classes of notification (Table 10.2). Within each of
these classes, all notification mechanisms are available. A conditional version of the first class
that limits execution of a notification, based on the condition of the data in the message,
could be considered a sixth class. The available conditions are exactly the same as the condi-
tions under which a direct message is transmitted in the mixed mode of transmission. The use
of these notification classes is discussed in more detail in the following chapters.
10.9 Summary
In this chapter, I covered a lot of information concerning the attributes of messages. If your
head is not spinning, then you are one of the few in the world who understand this subject the
first time! Don’t worry, each area is discussed in more detail in the following chapters as I
consider each type of message and use the attributes in examples.
146 Chapter 10: Communication
Internal Communication
As seen in the last chapter, the OSEK/VDX COM specification describes a complex system
with many levels of capability. To better understand how a COM implementation works, I
dive deeper in this chapter into different types of communication, starting with internal com-
munication. Internal communication is supported in all conformance classes, with CCCA and
CCCB offering internal intertask communication only.
As with all of the OSEK/VDX specifications, COM is never complete. In the chapters of
Part 2, I identify issues that could cause concern in the use of COM, and as I develop the
chapters, I discuss ways to work around these concerns.
Throughout this and the succeeding chapters, the examples I develop use OSEK/VDX OS
tasks to illustrate how communication works. If your application does not use an
OSEK/VDX OS, these tasks can be replaced with functions or tasks for the OS being used,
and you can ignore the task OIL configuration file listings.
147
148 Chapter 11: Internal Communication
The first part of this book, which covered the OS standard, introduced conformance class
A (CCCA). This level of communication is required in any OSEK/VDX OS. The question
then is whether the interaction layer is part of COM or part of the OS. The answer is that it is
a part of COM, but any OS must implement this portion of COM with CCCA conformance.
The concept of internal communication is shown Figure 11.1, which shows a simple appli-
cation with four tasks that communicate using two internal messages.
Application
Interaction
Layer
MESSAGE_A_TYPE MESSAGE_B_TYPE
TaskA sends a message using the interaction layer. The content of this message is a
MESSAGE_A_TYPE data type, which could be an integer type (char, short, long) or a user-
defined type such as a structure. The interaction layer processes the message and returns to
the application. I discuss the details of how the message is processed throughout this chapter.
At some point in the future, TaskB and TaskC execute and request the data from the interac-
tion layer. These tasks know the type of data that was sent and can therefore properly access
it and process it. Based on this data, a second message is sent by TaskB, which is later received
by TaskD. The data is accessed by the tasks using message accessors. How these accessors are
defined and used is discussed throughout this chapter. This is a high-level description of the
functioning of intertask communication but should work as a good overview for the sections
to follow.
The return value from this service, which is the same whether the system is in standard or
extended status mode, is
• E_OK if the initialization completes successfully or
• specific to the implementation if the initialization does not complete successfully.
An OSEK/VDX task can invoke InitCOM(); however, all interrupts must be masked prior
to calling it, and if it is called while the COM component is active, its behavior is not defined
by the OSEK/VDX specification.
Within ShutdownHook(), CloseCOM() closes the COM component.
StatusType CloseCOM(void);
This API service is the complement of InitCOM(). CloseCOM() releases the low-level hard-
ware resources that were initialized in InitCOM(). When CloseCOM() is invoked, all COM
operations are halted, and any messages queued for transmission or partially received are
lost. Typically, this service is not invoked while the COM component is active.
Once the communication component is initialized and the OS is started, StartCOM() and
StopCOM() can start and stop the communication component. StartCOM(), unlike StopCOM(),
must be called from the task level within the OS. The specification indicates that StopCOM()
can use any OS service; consequently, it will most likely be called from the task level because
many OS API services are not allowed at interrupt level or during hook routines.
StartCOM() and StopCOM() allow an application to use COM only when necessary
because COM can consume resources that might be needed for other purposes. This is not an
issue in the example here, so to demonstrate these two API services, I use two tasks: InitOS
and CloseOS. If the application does not use an OS, these tasks will be functions. InitOS (List-
ing 11.3) executes first. The OIL configuration definition of this task is shown in Listing 11.4.
InitOS will be the highest priority task in the system to ensure that it executes first after the
OS starts.
First, I start the communication component with StartCOM(), and then I perform specific
OS initializations. Because the example was developed using an OSEK/VDX OS, this task
automatically starts the alarms that the system requires.
StatusType StartCOM(void);
StartCOM() starts the OSEK/VDX communication component and initializes internal
states and variables. It also initializes OS resources used by the communication component.
For example, if the communication component needs a task to perform a certain function on
starting, StartCOM() will activate that task. It gets tricky here because the OSEK/VDX COM
specification was written to be independent of the OS. If the communication component
requires the OS or application to provide resources — resources required for the component
to run, not the notification mechanisms of COM — the component might not be portable. In
particular, if a COM component expects an OSEK/VDX OS to be available, the component
will not function in another OS unless the application provides the required services.
COM Startup and Shutdown 151
StartCOM();
while(list->appmodemask != 0x00000000){
if((list->appmodemask & currentAppModeMask)!= 0){
if(list->alarmtype == ALARM_REL){
SetRelAlarm(list->alarm,list->start,list->cycle);
}
else{
SetAbsAlarm(list->alarm,list->start,list->cycle);
}
}
list++;
}
TerminateTask();
}
TYPE = BASIC;
SCHEDULE = FULL;
PRIORITY = 16;
ACTIVATION = 1;
AUTOSTART = TRUE;
STACKSIZE = 128;
SCHEDULE_CALL = FALSE;
};
152 Chapter 11: Internal Communication
The typical services required by a COM component include task scheduling, some form of
timer, the handling of interrupts, and possibly memory allocation. Some COM implementa-
tions might provide these services at the cost of additional overhead. When determining
which COM implementation to use, unless you are purchasing an entire OSEK/VDX solution
from one supplier, make sure that you fully understand the requirements to integrate the
implementation into your system. This is very much a concern in the automotive industry,
where automobile manufacturers typically supply or specify a particular implementation for
the communication component but do not supply or specify the OS. This might change as
OSEK/VDX matures and obtains ISO standardization.
The return value, which is the same whether the system is in standard or extended status
mode, is
• E_OK if the startup completes successfully or
• specific to the implementation if the startup does not complete successfully.
StartCOM() must be called from within a task and must be called after InitCOM() and before
CloseCOM() or else the behavior is undefined.
As mentioned earlier, messages can be sent and received with or without a copy being
made. If the message is handled without a copy, the variable that holds the copy needs to be
initialized prior to use. Many times, this variable will be global and needs to be set to a
default value by the application. This is accomplished from within StartCOM() by optionally
using the user-defined callback routine MessageInit().
StatusType MessageInit(void);
This routine allows the application to initialize all application-specific message objects.
Although defined in the specification, the application is not required to provide this callback
routine and could use another method of initializing message objects.
Message object initialization can be accomplished a number of ways. The two most com-
mon methods is either to set the global variable to a constant for without-copy messages or to
send a message initially using SendMessage(), which is described later in this chapter. How-
ever, SendMessage() cannot be invoked from within MessageInit() because it requires
StartCom() to be complete before it can be invoked. It must be invoked from the task level
after StartCom() returns.
Because COM only allows messages to be sent from one location within the system, the
initial value of any message sent with-copy theoretically can only be set by that task or func-
tion. Consequently, if an internal message is received before the application sends the mes-
sage, the value of the data is indeterminate. For a queued message, the returned status for a
received message indicates that the queue is empty and can be handled by the application. In
the COM specification v2.2.2 released in early 2001, the return status for an unqueued mes-
sage that indicates a message was never sent or received was removed from the standard. The
COM specification requires that the value returned to the application be the value set at ini-
tialization. However, there is no description of how the message is initialized. To resolve this,
the application has a number of options.
1. If the COM implementation does not enforce sending messages from only one task or
function, the application can send the message from one task or function during initializa-
tion and from the regular location during normal operation. This option can affect porta-
bility of the application and could require changes if a different COM implementation is
COM Startup and Shutdown 153
used. The single-sender rule is normally considered a global system design concept rather
than something to be enforced at the source code level. However, if the initialization of the
message data for all messages in the system is kept within one task or function, porting to
a new implementation would be minimized. This option typically would be performed
immediately after the return from StartCOM(). You should take care during normal opera-
tion of the application that the message is sent only from one location. This option is only
available for internal and internal–external messages.
2. Activate all tasks and execute all functions that send messages immediately after the com-
munication component starts. This would occur in the same location as option 1 men-
tioned previously. The drawback of this method is that there is no guarantee the tasks will
be performed in the proper order to ensure data consistency.
3. Send all internal messages without-copy and receive them either with- or without-copy. In
this manner, the application can initialize the global variable either within the Message-
Init() callback function or within the task that executes StartCOM(). This requires that a
coding standard is enforced globally within an application.
4. Create a flag for every unqueued message using the COM notification mechanism. These
flags can be reset in the routine that calls StartCOM() and then checked whenever a mes-
sage is needed. If the flag is set to TRUE, the message has been sent or received at least once
by the COM component. If the flag is set to FALSE, the message has never been sent or
received since the COM component was started. The drawback of this method is added
overhead every time the message is received by an application task.
Because of the extensive effort required to initialize unqueued messages, the COM specifi-
cation still needs some work. A revised COM specification or the next release of the OIL
specification could address how message data is initialized. Until that time, I recommend that
you select a COM implementation that does not enforce sending messages from a single point
as in option 1. When the initialization issue is addressed, only a single routine in an applica-
tion will have to be changed.
Initialization is problematic for external unqueued messages received by the local applica-
tion. Because an application has no way to initialize a message received from an external
source, the application must rely on a combination of system design and network manage-
ment. Network management is discussed in more detail in Part 3, when I discuss the
OSEK/VDX Network Management specification. From the system design angle, the network
system designer needs to implement a method that sends all external messages at least once
immediately after communication begins. One hopes that the OSEK/VDX COM working
group will address this issue soon. Until then, the reader should look for a COM implementa-
tion that provides a mechanism to initialize external messages within StartCOM().
The other task to be created is CloseOS, which has exactly the same attributes in the OIL
configuration file as the previous task, InitOS, does not start automatically, and has a priority
of one less than InitOS. A priority of one less than InitOS maintains a level 1 (BCC1/ECC1)
system that results in a more optimal implementation. If you move to a level 2 (BCC2/ECC2)
system, the priority of CloseOS could be the same as that of InitOS.
The CloseOS task performs application-specific housekeeping procedures prior to shutting
down the OS. It is activated by the application service ChangeMode(), which was created in
Chapter 1 and modified in Chapter 9. ChangeMode() is specific to an OSEK/VDX OS and
enables APPMODE switching. No changes have been made to this service since Chapter 9. List-
ing 11.5 shows the CloseOS task and Listing 11.6 shows its OIL configuration listing.
154 Chapter 11: Internal Communication
if(displayBufferError == FALSE){
SuspendOSInterrupts();
displayBuffer[displayBufferEnd].row = row;
displayBuffer[displayBufferEnd].column = column;
strcpy(&displayBuffer[displayBufferEnd].buffer,text);
if(++displayBufferEnd == DISPLAY_BUFFER_SIZE){
156 Chapter 11: Internal Communication
displayBufferEnd = 0;
}
if(displayBufferEnd == displayBufferStart){
displayBufferError = TRUE;
}
ResumeOSInterrupts();
ActivateTask(OutputDisplay);
}
else{
result = FALSE;
}
return result;
}
The WriteDisplayAt() service first ensures that sufficient space exists in the display buffer
before transmitting the information into displayBuffer, which is now static to this module
and which allows multiple tasks to send messages to the display without worrying about
overwriting someone else’s message. WriteDisplayAt() guarantees that a message cannot be
preempted by another task while writing to the buffer by creating a critical section using Sus-
pendOSInterrupts() and ResumeOSInterrupts(). This critical section is implemented differ-
ently if a different operating environment is used. If the information is buffered successfully,
WriteDisplayAt() activates the OutputDisplay task and returns TRUE. If an error occurs, such
as insufficient buffer space, and the information cannot be buffered, the service returns FALSE.
The OutputDisplay task (Listing 11.8) must now be modified to take advantage of the new
format of the display buffer.
}
SendMessage(DisplayMessage,displayMirror);
TerminateTask();
}
OutputDisplay first checks the information in the display buffer. If the cursor needs to
move, it invokes SetCursorPosition() then formats the internal copy of the display using
PackDisplay() (Listing 11.9), which is specific to the display.
while(*string != 0)
{
switch(*string)
{
...
default:
if(*string >= 240)
{
displayMirror->message[cursorPosition.row*MAX_DISPLAY_LINE_LENGTH
+ cursorPosition.column++] = *string - (char)240;
}
else
{
displayMirror->message[cursorPosition.row*MAX_DISPLAY_LINE_LENGTH
+ cursorPosition.column++] = *string;
}
if(cursorPosition.column == MAX_DISPLAY_LINE_LENGTH)
{
OutputNewLine();
}
}
++string;
}
}
158 Chapter 11: Internal Communication
PackDisplay() performs multiple actions, but I have only shown the section where the
message object is accessed. In order to access the message object, I have to define an ACCESSOR
for the OutputDisplay task. Accessors, as discussed in Chapter 10, define how an application
accesses the message data. Figure 11.2 shows the relationship between the message object and
the task object. The task object can be replaced by an interrupt service routine or a function
or callback routine when an OS is not used. For simplicity, only the task object is discussed
here.
Message Task
MESSAGE ACCESSNAME
1
0..* 0..*
Accessor
+WITHOUTCOPY:RiCBoolean
+SENT_RECEIVED:char
Because the relationship between the task class and the message class is a many:many
relationship, ACCESSOR is a container object that maps this relationship. For each task, zero to
many accessors could be defined. Each accessor maps to only one message, but multiple
accessors can and will map to a message.
In the current OIL specification, the ACCESSOR object is an attribute of a task because only
internal communication, as defined within an OS environment, is supported. The next ver-
sion of the OIL specification will support the entire COM specification and expand the infor-
mation available. Listing 11.10 shows the OIL configuration file entry for the OutputDisplay
task.
The ACCESSOR attribute has a value of SENT or RECEIVED and sets three parameters: MES-
SAGE, WITHOUTCOPY, and ACCESSNAME. The MESSAGE parameter is the name of the message to
which the relationship is mapped. This message must be defined elsewhere in the OIL config-
uration file. The WITHOUTCOPY parameter is a Boolean TRUE or FALSE. Finally, the ACCESSNAME
parameter is the name of the accessor that is created by the OIL configuration utility and ref-
erenced by the task.
The message accessor concept within the OSEK/VDX COM specification appears confus-
ing at first. However, it simply defines the name of the variable that is visible to the applica-
tion and is used by the task to send or receive data. This global variable is created by the OIL
configuration utility.
Unqueued Messages (CCCA) 159
WriteDisplay(InitMessage);
while(1){
translateRow = 0;
WaitEvent(BUFFER_CHANGED);
ClearEvent(BUFFER_CHANGED);
GetResource(RES_SCHEDULER);
if(ReceiveMessage(DisplayMessage,displayMirrorTemp)==E_OK){
memcpy(&displayMirrorLocal,displayMirrorTemp,
sizeof(DISPLAY_MESSAGE_TYPE));
}
ReleaseResource(RES_SCHEDULER);
...
}
}
OutputDisplayBuffer starts automatically when the OS starts. It waits for the BUFFER_
CHANGED event to be set and enters the WAITING state. Because the display is relatively slow
compared to the speed of the application and the message is received without-copy, the global
copy of the display can be modified and thereby corrupted during the write operation. Conse-
quently, OutputDisplayBuffer creates a local copy of the buffer prior to writing the informa-
tion to the display. As mentioned in Chapter 10, creating a local copy of the message is
typically not possible with most current implementations because with-copy access typically
declares a static variable. Some implementations might function differently, but the ones I
have worked with do not allow local copies of messages. You can make a copy using the
without-copy capabilities of the system and memcpy(), but note the memcpy() argument names
carefully. The displayMessageTemp argument is an accessor, which is defined as a reference to
the message object. Consequently, it is already a pointer and is included directly. However,
the local copy is a variable, so the address of the local copy must be sent. Copying occurs in a
section in which the RES_SCHEDULER resource is locked to ensure that the buffer is not cor-
rupted while it is copied. The event is cleared prior to locking the resource so that any
changes to the buffer are processed on completion of the update.
Unqueued Messages (CCCA) 163
• Other return values are effective only if the message is queued, which is discussed in
“Queued Messages (CCCB).”
• In extended status mode only, the service returns E_COM_ID if the message referenced in the
message parameter is not valid.
If the service returns E_OK, copy the message object to the local object. The original pur-
pose of creating a local copy was to preserve memory by using a larger stack but less static
memory; however, that is not the result in this example because OutputDisplayBuffer is an
extended task and is always using resources. This example does show how a local copy of the
message object can be created and used in a task that executes and then terminates, thereby
preserving scarce RAM resources at the temporary cost of additional stack space.
Now that you have a local copy of the buffer that cannot be corrupted, you can send the
output to the display with the use of a timer based on the real-time clock that creates the
delays necessary between the commands and the characters written to the display.
TASK IOSampleKeypad {
TYPE = BASIC;
SCHEDULE = FULL;
PRIORITY = 13;
ACTIVATION = 1;
AUTOSTART = FALSE;
166 Chapter 11: Internal Communication
STACKSIZE = 128;
SCHEDULE_CALL = FALSE;
ACCESSOR = SENT {
MESSAGE = KeyPressMessage;
WITHOUTCOPY = FALSE;
ACCESSNAME = “keyPressed”;
}
};
The task IOSampleKeypad is invoked periodically to determine if a key is pressed on the
keypad (Listing 11.16). IOSampleKeypad reads the value of the keypad and debounces the key
presses. When a key is pressed, the task sends the key value to the application using SendMes-
sage(), which functions exactly as discussed in “Unqueued Messages (CCCA)” above. How-
ever you cannot send this message without-copy. The return status is also determined as for
an unqueued message, but because the ACCESSOR parameter is defined for the task, any
attempt to send an unqueued message without-copy should be caught by the system configu-
ration tool when the OIL configuration file is processed. When the message is sent, the COM
component sets the KEYPRESS event that is associated with the ProcessKeyPress task.
tempKey = HWGetValue(&KEYPAD);
if(tempKey == lastKey){
if(keyCount++ == KEY_DEBOUNCE_TIME){
--keyCount;
if(tempKey != 0){
if(keyState == FALSE){
*keyPressed = tempKey;
SendMessage(KeyPressMessage,keyPressed);
keyState = TRUE;
}
}
else{
keyState = FALSE;
}
Queued Messages (CCCB) 167
}
}
else{
keyCount = 0;
lastKey = tempKey;
}
TerminateTask();
}
ProcessKeyPress (Listing 11.17) is a background task that is either always active or in the
SUSPENDED state. It is a large task, so I show only the portions of the task that are applicable
to the discussion here. The complete task is on the CD.
When an application operates in CCCB, the application can lock a message resource. This
capability is typically used for unqueued messages accessed without-copy, where the message
resource is a globally accessible variable. In the unqueued message example, the displayMir-
ror accessor was created without-copy. To ensure that this data was not corrupted, the exam-
ple application forces the OutputDisplay task to be non-preemptive. An alternative is to lock
the message resource while the task updates the data and to allow preemption to occur nor-
mally. The updated OutputDisplay task is shown in Listing 11.18.
GetResource(RES_SCHEDULER);
if(ReceiveMessage(DisplayMessage,displayMirrorTemp)==E_OK){
memcpy(&displayMirrorLocal,displayMirrorTemp,
sizeof(DISPLAY_MESSAGE_TYPE));
}
else{
i=1;
}
ReleaseResource(RES_SCHEDULER);
if(i==1){
SetRelAlarm(DisplayWaitAlarm,10,0);
WaitEvent(DISPLAY_READY);
ClearEvent(DISPLAY_READY);
}
}while(i==1);
...
}
}
In this revised task, the return value from ReceiveMessage() is checked to determine if the
message was available. If the service returns anything other than E_OK, the task starts a timer
and waits for the message to be unlocked.
Within an implementation operating under CCCB, one other API service, GetMessageSta-
tus(), is available to the application. This service simply checks the message status without
acting on the message itself.
StatusType GetMessageStatus(SymbolicName message);
This service returns the status as follows.
• If the service cannot guarantee that access to the message is safe, it returns E_COM_LOCKED.
Determining when access cannot be granted to the message object is specific to the imple-
mentation.
• If the message is currently locked by the application and is considered busy, the service
returns E_COM_BUSY.
• If the queue of a queued message is empty, the return value is E_COM_NOMSG.
• If the queue was full the last time the message was sent (internal or internal–external mes-
sage) or physically received (external message), this service returns E_COM_LIMIT, indicat-
ing that at least one message was lost because the queue was full.
• If the service executes successfully, it returns E_OK.
• In extended status mode only, the service returns E_COM_ID if the message referenced in the
message parameter is not valid.
Example Program 171
11.5.1 Modules
cardgame.c The ProcessKeyPress task was modified as described in this chapter to use the
intertask message capability to obtain the value of a key press.
dispdrv.c The OutputDisplayBuffer and OutputDisplay tasks were modified to use mes-
sage resource locking to ensure that OutputDisplay does not try to write to the without-copy
message object while the OutputDisplayBuffer task makes a copy of the message object. Out-
putDisplayBuffer also creates a local copy of the message object before writing to the dis-
play.
keypad.c The ISR IOReadKeypadISR was replaced by the IOSampleKeypad task to allow illus-
tration of queued messages. Because queued messages are used now, the local queue is no
longer required, and GetKeyValue() is not required and was removed.
init.cfg The registers that had been initialized to allow interrupt driver sampling of the
keypad were removed, and the alarm that periodically triggers the task was added to the
autostart list of alarms.
11.6 Exercises
1. Create a new task that controls the display during a shuffle (displays the message “SHUF-
FLING –”) and create an unqueued message that informs this task which direction to turn
the “clock.” The value of this message will be 0 for 12:00, 1 for 1:30, 2 for 3:00, and so
on, up to 7 for 10:30. Whenever the clock needs to move, send the message to activate the
task that calculates the output to the display.
172 Chapter 11: Internal Communication
2. Create a new task that outputs an error to the display, and create a queue of invalid key
presses. First, the task should save the value of the display by receiving the DisplayMes-
sage message and saving a copy. Whenever an invalid key is pressed (as indicated by the
NO_ACTION action in the ProcessKeyPress task), send the key value using a new queued
message. When the message is sent, the new task should display an error message, along
with the invalid key that was pressed. Display for three seconds, then restore the display
to the prior value if no other invalid key presses are in the queue.
11.7 Summary
In this chapter, I introduced the basis on which an application can use the OSEK/VDX COM
standard. The services required by the application to initialize, start, stop, and close an
OSEK/VDX COM component were discussed. I divided the chapter into two sections based
on the two conformance classes that address internal, or intertask, communication: conform-
ance classes A and B. The API services available in each of these conformance classes were
described and examples were given. In addition, the function of locking a message resource in
order to support without-copy configurations was discussed, and the API services were
defined.
In Chapter 12, I dive into the topic that separates OSEK/VDX from other small real-time
OSs — the support of distributed computing environments.
12
Chapter 12
Basic External
Communication
Now that a basic communication component is up and running, I can discuss external com-
munication over a network. As mentioned in Chapter 10, the OSEK/VDX communication
specification does not limit the type of network allowed. In reality, most implementations
today only support the controller area network (CAN) protocol. However, with the multitude
of automotive-based networks that are presently in development, this definitely will change in
the near future. Even networks that are typically PC or telecommunications based, such as
IEEE1394, USB, and the myriad of cellular technologies, are finding their way into automo-
biles. For simplicity, I limit discussion in this book to the use of a CAN network.
173
174 Chapter 12: Basic External Communication
application standpoint, I am only concerned with the data frame message. The remote, error,
and overload frames should be invisible to the application and should only be used by the
communication driver. The complete data frame for a CAN message is shown in Figure 12.1.
Start of Frame
The arbitration and the data fields are the only portions of the CAN data frame of con-
cern to an application. The two types of message defined in a CAN network, standard and
extended, affect the number of bits in the arbitration field. Standard messages have an ID of
11 bits and extended messages of 29 bits; therefore, the arbitration field length is either 12 or
32 bits. The extra bit in the standard ID is called the remote transmission request bit and is
not of concern to the application. This bit also resides in the arbitration field of an extended
message, along with two additional bits that also are not of concern to the application. When
defining the ID of the message in the configuration file, the application developer only defines
the 11 or 29 bits of the identifier.
The arbitration field determines which device has control of the bus when two devices
attempt to transmit at the same time through the concept of dominant and recessive states of
the bus. Simply translated, this means that the transmission of a 0 bit will be dominant over
the transmission of a 1 bit. Each device listens on a bit-by-bit basis to determine if its attempt
to transmit a 1 on the bus is successful. If it was not successful, the device stops transmitting
and waits until the current message is transmitted before it attempts to start again. Conse-
quently, a message with an ID of 0 is the highest priority message on the bus.
Each CAN data frame can hold up to eight data bytes. The number of data bytes sent is
defined in the message length of the external message in the OIL configuration file. At this
time, the OSEK/VDX COM specification does not support sending multiple messages within
one data frame, but this could change in the future. Messages that fit within these eight data
bytes are sent within one data frame. If a message is larger than eight data bytes, the message
is broken into multiple data frames. Transmission of multiple data frames is discussed in
Chapter 13.
This has been a very brief overview of the function of the CAN network. More in-depth
information can be obtained from a number of sources that can be found on the Internet.
Unacknowledged Unsegmented Data Transfer 175
game mode and perform other program-related control operations. The first message is used
to receive a request from the other player, and the second message is used to send a message
to the other player.
MESSAGE CardMessageOut {
TYPE = EXTERNAL;
LENGTH = 3;
ALIGNMENT = 1;
USAGE = SEND;
QUEUED = TRUE;
TX_NOTIFICATION = ON_SUCCESS;
RX_NOTIFICATION = NONE;
TRANSMISSION = DIRECT;
ACCESSNAMES = { dealtCard };
CAN_ADDRESSES = { CardMessageNode0 };
QUEUE_SIZE = 12;
TX_SUCCESS_TASK = ProcessKeyPress;
TX_SUCCESS_EVENT = TRANSMIT_COMPLETE;
};
MESSAGE RequestModeMessageIn {
TYPE = EXTERNAL;
LENGTH = 1;
Unacknowledged Unsegmented Data Transfer 177
ALIGNMENT = 1;
USAGE = RECEIVE;
QUEUED = FALSE;
TX_NOTIFICATION = NONE;
RX_NOTIFICATION = ON_SUCCESS;
TRANSMISSION = DIRECT;
RX_SUCCESS_TASK = ChangeGameMode;
CAN_ADDRESSES = { RequestModeMessageNode1 };
ACCESSNAMES = { requestedMode };
};
MESSAGE RequestModeMessageOut {
TYPE = EXTERNAL;
LENGTH = 1;
ALIGNMENT = 1;
USAGE = SEND;
QUEUED = FALSE;
TX_NOTIFICATION = NONE;
RX_NOTIFICATION = NONE;
TRANSMISSION = DIRECT;
CAN_ADDRESSES = { RequestModeMessageNode0 };
ACCESSNAMES = { requestMode };
};
CardMessageOut is accessed without-copy to conserve memory. Because it is an external
message and will only be accessed from one location, corruption will not occur so without-
copy can be used safely. If there is any possibility that the object can be accessed by multiple
locations, then with-copy should be used.
The CardMessage messages are associated with two CAN addresses: CardMessageNode0
and CardMessageNode1. Before continuing, I need to define some of the assumptions that must
be understood when using an OSEK/VDX system. OSEK/VDX is a statically defined system;
consequently, when it is defined, each device is statically defined to be at one location on the
network. The CAN protocol is also defined such that only one node on the network can
transmit a message with a given ID. Consequently, for a message to be sent by two nodes, the
message IDs must be slightly different to indicate who is sending the message. In the example
program, the distributed system was designed with the following system requirements.
• A maximum of two nodes are available on the network.
• If only one node is available on the network, that node operates as a single player, with
both the dealer and the player on that node.
• When connected to a network, a node can request a head-to-head game against another
node or can receive a request for a head-to-head game from another node. This request
has to be granted before a head-to-head game begins.
178 Chapter 12: Basic External Communication
CANADDRESS CardMessageNode1 {
NETWORK = Net1;
TYPE = STANDARD;
MESSAGE_ID = 2033;
};
CANADDRESS RequestModeMessageNode0 {
NETWORK = Net1;
TYPE = STANDARD;
MESSAGE_ID = 2034;
};
CANADDRESS RequestModeMessageNode1 {
NETWORK = Net1;
TYPE = STANDARD;
MESSAGE_ID = 2035;
};
When defining the CAN address, the implementation needs to know on which network to
transmit the data (NETWORK), whether the data is transmitted with standard or extended
addressing (TYPE), and the address of the data frame (MESSAGE_ID). This configuration pro-
vides the information required by the network and data link layers to successfully transmit
data over or receive data from the network. OSEK/VDX COM does not limit the number of
Unacknowledged Unsegmented Data Transfer 179
networks to one; consequently the physical network on which a message is transmitted must
be defined. The definition of the physical network or networks available is also performed in
the OIL configuration file, but because this is specific to the implementation and target micro-
controller, I do not include this definition here. The OIL configuration file on the accompany-
ing CD includes this definition for the OSEKWorks implementation.
Now that I have defined a series of messages, I can modify the example program to use
these messages to create a full-featured application that allows both stand-alone and head-to-
head play. The first step is to modify the program to negotiate head-to-head play. The steps
involved in head-to-head negotiation are shown in Figure 12.2.
ProcessKeyPress()
SendMessage() RequestModeMessage(
REQUEST_HEAD_TO_HEAD)
ChangeGameMode()
RequestModeMessage( SendMessage()
ACCEPT_HEAD_TO_HEAD)
ChangeGameMode()
Initiation of head-to-head play occurs when one player presses the * key, and the key is
processed in the ProcessKeyPress task (Listing 12.3). Because this task is very long, I only
include that portion of the task necessary to demonstrate this message.
When the * key is pressed, the application sends the RequestModeMessageOut message
with the REQUEST_HEAD_TO_HEAD data value in the ACCESSOR RequestMode using SendMes-
sage(), which functions the same for external and internal messages. The COM implementa-
tion, however, performs a completely different series of functions for external messages, as
illustrated in Figure 12.3.
180 Chapter 12: Basic External Communication
while(1){
WaitEvent(KEYPRESS|SIM_KEY);
GetEvent(ProcessKeyPress,(EventMaskRefType)&eventMask);
ClearEvent(KEYPRESS|SIM_KEY);
while((ReceiveMessage(KeyPressMessage,keyValue) == E_OK)||(
(eventMask & SIM_KEY) != 0)){
if((eventMask&SIM_KEY)!=0){
i=simulatedKey;
eventMask &= ~SIM_KEY;
}
else{
i=*keyValue;
}
switch(CheckGameTransition(i)){
...
case REQUEST_MULTIPLE:
*requestMode = REQUEST_HEAD_TO_HEAD;
SendMessage(RequestModeMessageOut,requestMode);
requestHeadToHead = TRUE;
SetRelAlarm(RequestModeAlarm,25000,0);
WriteDisplay(RequestModeAwaitPrompt);
gameState = GAME_AWAITING_RESPONSE;
break;
...
case NO_ACTION:
break;
}
}
}
}
Unacknowledged Unsegmented Data Transfer 181
SendMessage()
NDataRequest()
DDataRequest()
DataFrame()
DDataConfirm()
DDataIndication()
NDataConfirm()
NDataIndication()
Notify()
Notify()
When the application sends the message, the interaction layer first determines whether the
message is an internal or an external message. Internal messages are fully processed by the
interaction layer, but an external message is forwarded to the network layer for further pro-
cessing. Services that start with NData or DData are internal services and indicate the action
that is taken. Because the layer model is a figurative model, these services might or might not
actually exist as distinct functions. Request messages request message processing by the layer;
Confirm messages indicate the result of the request; Indication messages indicate that a mes-
sage has been received and needs to be processed.
If the message sent to the network layer is a UUDT message, then the network layer passes
the message on to the data link layer. The data link layer formats the data frame and puts the
data frame into the queue for transmission. The data link layer then returns to the network
layer, which returns to the interaction layer, which returns to the application. If everything is
successful, the return value to the application is E_OK. However, if the data link layer deter-
mines that it cannot safely transmit the data, it returns the status E_COM_LOCKED. The condi-
tions under which the locked status is returned depends on the implementation.
Because OSEK/VDX COM is an asynchronous communication model, the application
continues before the message is transmitted over the network. So that the application knows
when a message is transmitted successfully, notification class 2 (as illustrated in Figure 12.3)
provides confirmation from the data link layer through the network layer to the interaction
layer that the message was transmitted successfully on the network. The interaction layer can
then notify the application of the success. In the example application, this notification is not
enabled for the RequestModeMessageOut message; however, it will be enabled for the CardMes-
sage messages described in more detail later.
After the message has been sent, the application sets a local flag, requestHeadToHead, to
TRUE and starts a 25-second timer. When the RequestModeMessageIn message is received or
the timer expires, the ChangeGameMode task (Listing 12.4) is activated. Only the actions taken
in SINGLE_PLAYER mode are shown for brevity.
182 Chapter 12: Basic External Communication
while(1){
...
switch(CheckGameTransition(i)){
...
case REQUEST_CARD_DEALT:
dealComplete = FALSE;
while(dealComplete == FALSE){
dealtCard->type = REQUEST_CARD;
SendMessage(CardMessageOut,dealtCard);
SetRelAlarm(CardMessageAlarm,5000,0);
184 Chapter 12: Basic External Communication
WaitEvent(TRANSMIT_COMPLETE|TRANSMIT_FAILED);
GetEvent(ProcessKeyPress,(EventMaskRefType)&eventMask);
if(eventMask&TRANSMIT_COMPLETE){
dealComplete = TRUE;
CancelAlarm(CardMessageAlarm);
}
ClearEvent(TRANSMIT_COMPLETE|TRANSMIT_FAILED);
}
break;
...
case NO_ACTION:
break;
}
}
}
}
This action sends the CardMessageOut message, which requests a card, as a CARD_MESSAGE_
TYPE structure (Listing 12.6).
while(ReceiveMessage(CardMessageIn,receivedCard) == E_OK){
switch(receivedCard->type){
case REQUEST_CARD:
186 Chapter 12: Basic External Communication
if(gameRole == GAME_DEALER){
GetResource(CARDDECK);
playerCards[playerPosition] =
DealCard(PLAYER,playerPosition,TRUE);
ReleaseResource(CARDDECK);
playerScore += GetCardValue(playerCards[playerPosition]);
if(playerScore > 21){
for(i=0;i<=playerPosition;i++){
if(GetCardValue(playerCards[i])==11){
playerCards[i] = ACE_IS_ONE;
playerScore -= 10;
break;
}
}
}
simulatedKey = 'X';
SetEvent(ProcessKeyPress,SIM_KEY);
}
break;
...
}
}
TerminateTask();
}
At the end of the action taken when a card is requested, a static variable, simulatedKey, is
set to 'X', and an event is set for the ProcessKeyPress task. Because the ProcessKeyPress
task “owns” the CardMessageOut message, this mechanism triggers the task to send the mes-
sage. These steps enforce the limitation that only one task can send a message.
MESSAGE NodeStatusMessageOut {
TYPE = EXTERNAL;
LENGTH = 2;
ALIGNMENT = 1;
USAGE = SEND;
QUEUED = FALSE;
TX_NOTIFICATION = ON_DEADLINE;
RX_NOTIFICATION = NONE;
TRANSMISSION = PERIODIC;
TRANSMIT_INTERVAL = 100;
TX_DEADLINE_ALARM = StatusMessageAlarm;
188 Chapter 12: Basic External Communication
TX_DEADLINE_TIME = 25;
CAN_ADDRESSES = { Node0StatusMessage };
ACCESSNAMES = { nodeStatus };
};
Because of the current COM specification limitations concerning initialization of message
objects, I defined the transmitted message as being accessed from the ProcessKeyPress task
without-copy. During initialization of the communication component, I check the current
APPMODE in the callback function MessageInit() (Listing 12.10). Recall that MessageInit() is
called at the end of StartCom() and was discussed in Chapters 9 and 11.
StartCom()
MessageInit()
StartPeriodical()
SetTimer()
SendMessage()
TimerExpires()
SetTimer()
NDataRequest()
DDataRequest()
DataFrame()
When the timer expires, it is reset to the period of the message, and the message is then
sent with the same period until periodic transmission halts. The interaction layer then obtains
the latest data from the message object and sends this to the network layer. Next, the network
layer sends the message to the data link layer, which assembles the data frame and queues the
message for transmission. This message uses notification class 4 to notify the application
whether the message was successfully transmitted within 25 timer ticks (25 milliseconds) or
not. If no one is connected on the network other than the device that sends a message, then
no one is available to acknowledge that the message was sent. Consequently, the sending
device will never be able to successfully transmit any message. The data link layer therefore
never sends a confirmation to the interaction layer that the message was sent successfully.
When the timer expires, notification class 4 informs the interaction layer. The notification
mechanism used for this message is the callback function SetDeviceLonely() (Listing 12.11).
190 Chapter 12: Basic External Communication
Notification
Interpretation
Class
1 Message was received unconditionally or conditionally.
2 Message was transmitted successfully.
3 Message was not received successfully.
4 Message was not transmitted successfully.
5 USDT first frame was received.
In the example program, when the flag is set TRUE, it indicates that the message has been
received at least once since the last time that the flag was reset. If the flag has been set, then
the task clears the lonely status flag using ClearLonelyFlag(). If the flag has not been set and
the return value is FALSE, the task sets the lonely flag using the previous callback routine Set-
LonelyFlag(). The task then resets the flag using ResetFlag().
When this API service is invoked, the COM component cancels all timers that are running
and disables the transmission of the periodic messages. The return status from this service is
• E_OK if the service executes successfully or
• specific to the implementation if the service fails (refer to the implementation documenta-
tion for a list of other possible return values).
MESSAGE RemainingCardsMessageOut {
TYPE = EXTERNAL;
LENGTH = 1;
ALIGNMENT = 1;
USAGE = SEND;
QUEUED = FALSE;
TX_NOTIFICATION = NONE;
RX_NOTIFICATION = NONE;
Unacknowledged Unsegmented Data Transfer 193
TRANSMISSION = MIXED;
TRANSMIT_INTERVAL = 500;
VALUE_SIZE = ONE_BYTE;
RELEVANT_CHANGE = NEQ;
COMPARE_VALUE = 0;
CAN_ADDRESSES = { RemainingCardsNode0 };
ACCESSNAMES = { remainingCardsOut };
};
The message is transmitted every 500 milliseconds to indicate the number of cards remain-
ing and for diagnostic purposes. In addition, whenever SendMessage() updates the message
value and the new value is not equal to the old, a direct message is sent using the attributes
VALUE_SIZE, RELEVANT_CHANGE, and COMPARE_VALUE in the OIL configuration file. Figure 12.5
shows the sequence of events with respect to this message.
StartCom()
MessageInit()
StartPeriodical()
SetTimer()
SendMessage()
NDataRequest()
DDataRequest()
DataFrame()
TimerExpires()
SetTimer()
NDataRequest()
DDataRequest()
DataFrame()
The sequence is as seen from the node 0 device when it is functioning as the dealer. Similar
to a periodic message sequence, the message is initialized and then sent periodically after the
call to StartPeriodical(). The difference occurs when the data is updated after a card is
194 Chapter 12: Basic External Communication
dealt or the deck is reshuffled. When this occurs, a message is transmitted immediately on the
network with the new value.
At this point, the example program does not take any action if a discrepancy between
message data and internally calculated data exists. However, it could be used as a method of
handshaking to indicate that the CardMessage message was not received by the device operat-
ing in the role of player. For illustrative purposes, this message was added as an additional
status message that also indicates that a device has left the network. When this message has
not been received after 700 milliseconds, notification class 3 is invoked and the LostOpponent
task is activated. This task simply notifies the person who is playing at that device that the
opponent has shut down and then restarts the system in a single-player mode.
12.3.1 Modules
makefile The makefiles were changed to allow two types of builds: Node 0 and Node 1.
This includes the *.mk files.
carddeck.c Definition of the BLANK_CARD macro has been moved from a local definition in
carddeck.c to a global definition in carddeck.h.
ProcessKeyPress was modified extensively to process key presses when the application
is in HEAD_TO_HEAD mode.
DealCards was modified to recognize when a head-to-head game was in progress and to
transmit the cards to the other player when the cards are dealt.
CardReceived processes the CardMessageIn message when a card is received from the
other player or when a request for a card or end of turn is received.
void SetDeviceLonely(void) sets a flag when the status messages are no longer being
received.
void ClearDeviceLonely(void) clears the flag when the status messages resume.
dispdrv.c This module was modified to display a different startup screen for HEAD_TO_HEAD
versus SINGLE_PLAYER mode. The display is different on the DEALER node (node 0) than it is on
the PLAYER node (node 1).
init.c This module was modified to initialize the periodic status message and to start and
stop the transmission of periodic messages.
main.c This module now allows entry into the HEAD_TO_HEAD APPMODE in ChangeMode().
os.c The SetNetworkFlag task simulates setting a flag when a message is received. This was
required because OSEKWorks only supports COM v2.1. It will be removed when the exam-
ples are updated to the new version of OSEKWorks.
12.4 Exercises
1. Create four new periodic or mixed-mode messages that contain five cards each for the
dealer and player. Each node will transmit two messages that include the cards as each
player should see them. If a given card was not yet dealt, then the value in the message
should be zero. The node will also receive two other distinct messages for the cards as
viewed by the opponent. If at any time there is a difference between the cards as dealt and
as received, flash the message “Someone’s Cheating,” wait five seconds, then reset to sin-
gle-player mode. To test this, you will have to write code in one device that corrupts the
data of the message.
2. Create a direct message that is sent whenever the ‘0’ (zero) key is pressed and include a
small message of seven or fewer characters. When received by the other node, the message
flashes for three seconds on the display. The contents of the direct message should always
be constant, such as “Hello” or “I’m in.”
12.5 Summary
In this chapter, I discussed basic external communication using an OSEK/VDX COM imple-
mentation. I provided examples of direct transmission mode, periodic transmission mode,
and mixed-mode transmission, along with notification classes 2, 3, and 4. At this point, the
portions of the OSEK/VDX COM specification that will be used in most embedded applica-
tions have been introduced and described. In Chapter 13, I introduce advanced external com-
munication, which will probably appear in only a few applications.
13
Chapter 13
Advanced External
Communication
The final topic to be covered in the OSEK/VDX COM standard is advanced external commu-
nication. The specification for COM is not divided into basic or advanced external communi-
cation — I have made this split because most embedded applications will not use the features
available under the CCC2 COM conformance class.
The features available when the COM component is operating in CCC2 are
• transmission of messages segmented in multiple data frames on the network (USDT),
• dynamic message lengths,
• dynamic message addressing, and
• notification of the application when the first frame of the segmented message is received.
In this chapter, I discuss segmented messages and describe using these additional features.
197
198 Chapter 13: Advanced External Communication
application. Limitations to the type of message that can be sent as a segmented message are
outlined in Table 13.1.
Attribute Limitation
Transmission type Only direct transmission is allowed.
Size Maximum size of the complete message is 4,095 bytes.
1:1/1:n All messages are 1:1 only.
Queueing All messages must be unqueued.
Although the USDT transmission mechanism is transparent to the application, under-
standing of the data frames that appear on the bus is critical when debugging the system;
therefore, I discuss the mechanism used to transmit a segmented message across the bus first.
The following terms will help you better understand the segmenting mechanism.
Network Protocol Data Unit (NPDU) The network protocol data unit is a unique data
frame on the network used to transmit the segmented data. Four network protocol data units
— single frame, first frame, flow control, and consecutive frame — are required and are
defined later. Each NPDU has three fields: the address information, the protocol control infor-
mation, and the data.
Network Address Information (N_AI) This field contains information about the message
that is to be transmitted and optionally includes the target address and source address.
This identifier is the same for all frames transmitted on the network for a given message.
For a CAN network, it is an 11- or a 29-bit identifier.
Network Protocol Control Information (NPCI) This field of up to three bytes is embed-
ded in the data frame of the network that defines information for the network protocol
data unit that is being exchanged.
Single Frame NPDU This frame is used when the segmented message can be transmitted in
a single frame. Because USDT is a segmented protocol, the size of the message that can be
transmitted in a single frame is one less than the maximum size of a message that can be
transmitted using the UUDT protocol because a single-byte NPCI is required in this frame.
This NPDU exists because of support for dynamic message lengths. If a USDT message is
transmitted with a length that fits within a single frame, then the message appears as a UUDT
message on the network; that is, only one frame is transmitted.
First Frame NPDU This frame is transmitted first to initiate a segmented data transmission
session. Included in this frame is the total length of the message. The first two bytes of the
data frame constitute the first frame NPCI, followed by the first bytes of the message to be
transmitted. In the case of a CAN network, six data bytes are transmitted in the first frame.
Unacknowledged Segmented Data Transfer (CCC2) 199
Flow Control NPDU This frame is transmitted by the device that receives the message and
controls the flow of information from the transmitting device. This frame has three NPCI
bytes and no data. Because USDT transmission only occurs in a 1:1 model, a unique receiving
device for every message must be defined on the network.
Consecutive Frame NPDU This frame transmits the data in the message after the first
frame has been transmitted. The flow control frames from the receiving device times and con-
trols the frames.
Block Size (BS) This defines the number of consecutive frames that can be transmitted
before the transmitting device stops and waits for a flow control message from the receiving
device.
Separation Time (ST) This is the time between consecutive frames that the transmitting
device must wait to allow the receiving device to process the message.
N_As, N_Bs, N_Cs, N_Ar, N_Br, N_Cr (Table 13.2) Timeout times for determining that the
segmented message communication has been lost. The s stands for a time with respect to the
sender of the message, and an r stands for a time with respect to the receiver of the message.
Time Description
Sender
N_As From when the message was sent to when the message is transmitted suc-
cessfully by the data link layer.
N_Bs From confirmation that the message was transmitted successfully to when
the flow control message is received by the sender.
N_Cs From indication that the flow control message was received to when the next
message is transmitted by the sender.
Receiver
N_Ar From confirmation that the message was received to when the message is
transmitted by the data link layer.
N_Br From when the message was sent to when the flow control message is trans-
mitted successfully by the sender
N_Cr From confirmation that the flow control message was transmitted to when
the next message is received from the sender.
A good graphical depiction of these times can be found in section 3.2.4.7 of the standard,
which is included in the file COM2-2-2.PDF on the CD. The standard values for BS, ST, and all
the N_ timeouts are defined in the OIL configuration files.
Two possible cases of segmented data transmission can appear on the network bus: single-
frame and multiple-frame transmission. The maximum number of bytes that can be transmit-
ted in the multiple-frame sequence is 4,095, whereas the maximum number of bytes allowed
200 Chapter 13: Advanced External Communication
in a single-frame sequence is one less than the maximum transmission unit of the data link
layer, or 15, whichever is less. Figure 13.1 shows a sequence diagram for a single-frame trans-
mission.
NSDataRequest()
DDataRequest()
DataFrame()
DDataConfirm() DDataIndication()
NSDataConfirm()
NSDataIndication()
BitPosition 7 6 5 4 3:0
Value 0 0 0 0 DataLength
The single-frame NPCI informs the receiving device of the number of bytes in the only
frame being transmitted. Because of the single-frame NPCI format, a maximum of 15 bytes
can be transmitted in a single frame. This is not a problem with the CAN protocol, but it
could be a limitation in other protocols.
The data link layer transmits the frame over the bus and provides confirmation back
through the system that the frame was transmitted successfully. The receiving device also
notifies its system that it has received the message. The network layer on the receiving device
identifies that it is a single-frame message and processes the message completely.
The sequence diagram for multiple-frame segmented data transmission is shown in Figure
13.3 and shows the first part of the multiple-frame transmission sequence, where the session
between the transmitting device and receiving device is created.
NSDataRequest()
DDataRequest()
DataFrame(FirstFrame)
DDataConfirm() DDataIndication()
NSDataIndication()
DDataRequest()
DataFrame(FlowControlCTS)
DDataIndication()
DDataConfirm()
When the interaction layer sends a message to the network layer, the network layer identi-
fies that the message is segmented and will require more than one frame to transmit. The net-
work layer then assembles the UUDT message that will be transmitted and sends it over the
bus to the data link layer. The first two bytes of the data portion of this message is the first
frame NPCI. The remaining bytes of the first frame are the first bytes of the message. For
202 Chapter 13: Advanced External Communication
example in a CAN network, the first six bytes of the message are sent. The format of the two
NPCI bytes is shown in Figure 13.4.
Byte1 Byte2
BitPosition 7 6 5 4 3:0 7:0
Value 0 0 0 1 DataLength
As can be seen here, the maximum data length for a message is 4,095 bytes (212–1).
Although it is theoretically possible to have data lengths of zero, the smallest number actually
occurs in a first frame NPDU is the number of bytes in a single data frame of the data link
layer, which is eight for a CAN network. Anything smaller is sent as a single frame.
When the data frame is received at the receiving device, the data link layer indicates to the
network layer that it has received the message. The network layer then identifies it as the first
frame of a segmented message and indicates to the interaction layer that the first frame was
received. If notification class 5 is enabled, the interaction layer notifies the application.
The network layer then assembles the flow control message in response to the first frame
and sends this message to the data link layer. This message consists of three bytes (Figure
13.5) that contain the flow control NPCI.
BitPosition 7 6 5 4 3:0
Value 0 0 1 1 FlowStatus
Byte2
BitPosition 7:0
Value BlockSize
Byte3
BitPosition 7:0
Value Minimum Separation Time
Two versions of the flow control NPCI exist: the Clear-to-Send and the Wait version. The
response to a first frame message is always the Clear-to-Send version, and is identified by a
value of 0x30 in byte 1 (Flow Status = 0). The second byte in this message is the block size
parameter defined in the OIL file and defines the number of consecutive frames that can be
Unacknowledged Segmented Data Transfer (CCC2) 203
transmitted by the sending device before waiting for another Clear-to-Send flow control
NPDU. The third byte is the separation time between the transmission of consecutive frames,
as defined in the OIL file, which is the time (in milliseconds) from the completion of transmis-
sion of one consecutive frame over the network to the initialization of transmission of the
next consecutive frame. The sending device uses the information in the BS and ST bytes to
coordinate data transmission. The sequence diagram in Figure 13.6 shows the sequence of
events for the remainder of the segmented data transmission.
DDataRequest()
DataFrame(ConsecutiveFrame)
DDataConfirm()
DDataIndication()
DDataRequest()
DataFrame(ConsecutiveFrame)
DDataIndication()
DDataConfirm()
DDataRequest()
DataFrame(FlowControlWait)
DDataIndication()
DDataRequest()
DataFrame(FlowControlCTS)
DDataIndication()
DDataRequest()
DataFrame(ConsecutiveFrame)
DDataIndication()
DDataConfirm()
NSDataConfirm()
NSDataIndication()
This example uses a block size of two to simplify the figure. After receiving the Clear-to-
Send flow control NPDU, the sending device assembles the consecutive frame with the next
bytes of data to be sent. The first byte of the consecutive frame is the consecutive frame NPCI,
which is shown in Figure 13.7.
204 Chapter 13: Advanced External Communication
BitPosition 7 6 5 4 3:0
Value 0 0 1 0 SequenceNo.
The four bits that define the sequence number define the sequence of messages that are
transmitted by the sending device. By default, the first frame NPDU has a sequence number of
0, and the first consecutive frame that is transmitted has a sequence number of 1. Because the
sequence number limit is 15, the consecutive frame immediately following a sequence number
of 15 will wrap around to 0. The reception of flow control NPDUs does not affect the
sequence number.
In Figure 13.6, two consecutive frames are transmitted and then the sending device waits
for a flow control NPDU. The receiving device first sends a Wait flow control NPDU, because
it is still busy processing the messages, and then sends a Clear-to-Send flow control NPDU.
The sending device then sends the next consecutive frames. This process continues until all
data has been transmitted. In this example, only one more consecutive frame is required.
When the final frame has been transmitted, the receiving device notifies the interaction layer
that the complete message has been received and reconstructed properly.
MESSAGE OpponentMessageOut {
TYPE = EXTERNAL;
LENGTH = 60;
ALIGNMENT = 1;
USAGE = SEND;
QUEUED = FALSE;
TX_NOTIFICATION = NONE;
RX_NOTIFICATION = NONE;
TRANSMISSION = DIRECT;
ACCESSNAMES = { opponentMessageOutBuffer };
CAN_ADDRESSES = { OpponentMessageNode0, OpponentMessageNode2};
};
Notice that there is no direct indication that this message will be sent via USDT. Because
the message is not defined as being a USDT message until it is associated with a given net-
work, the determination of this attribute is performed by the configuration utility that trans-
lates the OIL file into the proper code. At this time, it is the responsibility of the
implementation to determine that it is a USDT message and to create the proper configura-
tions that enable segmented versus unsegmented transmissions. Because only USDT messages
can be dynamically addressed, the definition of two possible destinations indicates to the
implementation that this will have to be a USDT message.
Initiation of the message is performed by pressing the # key on the keypad. A message
then appears on the sender’s display that prompts for the message. On the 16-key keypad
used in the example program, words are entered using letters as found on a telephone keypad.
The letter pressed selects the position of the letter that accompanies a telephone number as
follows: Press ‘A’ for the first letter, ‘B’ for the second letter, and so on. For example, to send
206 Chapter 13: Advanced External Communication
“Hello,” the player would press the keys 4-B, 3-B, 5-C, 5-C, and 6-C. The letter ‘Q’ is
assumed to be in the second position of key number 7, and the letter ‘Z’ is in the fourth posi-
tion of key number 9. A space is entered using the number 1, a period is entered using the
number 0, and the backspace is the * key. When complete, the player presses the # key again,
which sends the message to the other player. If no key is pressed for 10 seconds, the display
returns to the prior display and the message is aborted.
To implement this messaging system, extensive changes have to be made to the Process-
KeyPress task. Some of these changes are shown in Listing 13.2, which only shows the areas
concerned with sending the message.
while(1){
...
switch(CheckGameTransition(pressedKey)){
...
case CREATE_OPPONENT_MESSAGE:
messageSize = 0;
messageNumber = '2';
gameState = GAME_CONSTRUCT_OPPONENT_MESSAGE;
WriteDisplay(OpponentMessagePrompt);
break;
...
case SEND_OPPONENT_MESSAGE:
opponentMessageOutBuffer[messageSize++] = 0;
SendMessageTo(OpponentMessageOut,opponentMessageOutBuffer,
messageSize,messageOpponent);
gameState = GAME_NORMAL;
WriteDisplay(GameNormalPrompt);
break;
case CLEAR_OPPONENT_MESSAGE:
WriteDisplay(GameNormalPrompt);
gameState = GAME_NORMAL;
break;
Dynamic Address Messages 207
case NO_ACTION:
break;
}
}
}
}
Pressing the # key presents two possibilities: starting a message and sending a message.
The rest of the task, in which the message buffer is constructed in preparation for transmis-
sion, is pretty self-explanatory. I have not included it in this listing to conserve space, but it
can be viewed on the CD in cardgame.c.
When the # key is pressed the first time, CREATE_OPPONENT_MESSAGE executes. During this
action, the buffer is cleared, the state is set to GAME_CONSTRUCT_OPPONENT_MESSAGE, local vari-
ables are initialized, and the display is updated. If the # key is pressed a second time while the
state is GAME_CONSTRUCT_OPPONENT_MESSAGE, then SEND_OPPONENT_MESSAGE executes and the
message is sent to the opponent defined by the messageOpponent variable. Although this lim-
ited example has only one opponent, the code allows a message to be sent to one of a number
of opponents. The size of the message was calculated by the messageSize variable as the mes-
sage was constructed. The message is transmitted using the COM API service SendMessag-
eTo().
When the system is up and running and a network analysis tool is monitoring the network
when the message is sent, two different sequences of messages will be seen depending on the
length of the message that the one player sends. If the length of the message is less than the
maximum number of bytes per data frame, a single-frame message is sent. In the example
application with a CAN network, sending the message “Hello” would result in a single-frame
message. Longer messages would result in multiple data frames, as described earlier.
At the other end of the network, the receiving device has two notification classes for
receiving USDT messages: Notification class 1 is triggered when the entire message is
received, and notification class 5, available only for USDT messages, is triggered on receipt of
the first frame. In the example application, I defined two tasks that are activated based on
these notification classes. The first task is IncomingMessage (Listing 13.3), which is activated
when the first frame is received over the network. It puts the message “Incoming Message” on
the display, sets the state of the card game to GAME_RECEIVING_OPPONENT_MESSAGE, and starts a
timer that requires that the message is received within 10 seconds. If the timer expires, the
AbortMessage task is activated, returning the program to normal operation. I do not discuss
AbortMessage here, but it is included on the accompanying CD.
ReceiveMessageFrom(OpponentMessageIn,opponentMessageInBuffer,
&messageSize,&messageSource);
ReceiveMessage(OpponentMessageIn,opponentMessageInBuffer);
WriteDisplay("\f");
WriteDisplay(opponentMessageInBuffer);
gameState = GAME_RECEIVED_OPPONENT_MESSAGE;
WriteDisplayAt(3,0,OpponentMessageReceivedPrompt);
CancelAlarm(IncomingMessageAlarm);
TerminateTask();
}
13.5 Modules
cardgame.c This module was modified extensively to support the added feature of sending
messages. The following tasks were created or changed.
ProcessKeyPress This task was modified to process the request to send a message, con-
struct the message as keys are pressed, send the message, and clear a message sent by an
opponent.
IncomingMessage This task is activated after the first frame is received. It indicates on
the display that a message is incoming and starts a timer. Because the network often is
very fast, the message on the display usually flashes for less than a second unless the mes-
sage is lost, in which case, the timer elapses and the display is cleared.
AbortMessage This task aborts the incoming message when the timer mentioned under
IncomingMessage expires.
13.6 Exercises
1. A set of messages was created in Chapter 12 that transmitted the dealer and player hands
periodically. Because the maximum CAN message has eight bytes, and transmitting all
possible cards in one message requires 10 bytes, four messages of five bytes each were
used. Modify the program you wrote to use two segmented 10-byte messages.
Summary 211
13.7 Summary
In this chapter, I discussed the advanced external communication capabilities of an
OSEK/VDX COM implementation. Segmenting a large message across multiple data frames
on a network is very complex; however, the OSEK/VDX COM specification encapsulates this
complexity so that the application no longer has to be concerned with the size of the messages
it transmits. I describe this capability as advanced because most small embedded controllers
work with data that is, at most, four bytes long and will fit in one data frame on all currently
used networks. However, with the advent of multiple new networks and the addition of Inter-
net TCP/IP capabilities into embedded devices, it is no longer science fiction to conceive of an
embedded device that has to communicate with both CAN and TCP/IP networks. In this sce-
nario, it is possible that a TCP/IP message 1,500 bytes long would need to be transmitted
over a CAN network. OSEK/VDX COM will perform this function, and it will be transpar-
ent to the application.
Now that the complete OSEK/VDX COM specification has been introduced and
described, a number of issues that have been identified throughout Part 2 need to be resolved.
How does an application differentiate between signals that are received via an external net-
work and signals that are measured from internal ports on the controller? At first glance, it
would appear that a separate API is required for local signals and an additional API — the
OSEK/VDX COM API — for signals received over a network. In addition, how do you han-
dle the case where multiple signals are packed into one message? I would recommend an
additional I/O layer that provides signal information to the application and encapsulates the
source of or destination for a particular signal. This is typically referred to as a presentation
layer, which presents the application with the data in the expected format. One drawback of
another layer is the additional time expended in accessing the signal; however, a properly
designed system should be able to save time somewhere else. The discussion of a presentation
layer, and the methods of accessing signals or data, is an entirely different subject and is not
covered in this book. At this time, I am unaware of any other book that would describe this
topic.
212 Chapter 13: Advanced External Communication
213
This Page Intentionally Left Blank
14
Chapter 14
Network Management
Overview
The OSEK/VDX Network Management (NM) specification defines the algorithms that moni-
tor the status of nodes on a static network, provides an API for control of the NM compo-
nent, and develops information that reports network status and configuration to the
application. Because NM was originally developed for an automotive environment, the net-
work is assumed to be static, which means that the total set of possible nodes on the network
is fixed and known by every node on the network, although every node does not have to be
available in an application. Optional nodes, such as navigation systems, entertainment
devices, and security devices, can be defined that might not reside in a particular automobile
but can be added later. However, each of these nodes has a unique identifier that is known to
all possible nodes in the network. The diagram of network management with respect to other
portions of an application is shown in Figure 14.1.
215
216 Chapter 14: Network Management Overview
Station Management (1) The station management component resides within the user’s
application and provides system-dependent algorithms to coordinate the network. Based on
the requirements of the application, this component queries the NM component to determine
the status of the nodes on the network and either takes action or provides the information
back to the application in an application-specific format. This particular component is not
defined by the NM specification.
As an example of how station management might work, consider an application in which
the station management component monitors message data and the network status. If a node
on the network is identified by NM as not being available, the station management compo-
nent could provide a default value for the message back to the application so that the applica-
tion could continue in a reduced functionality mode. This would be accomplished by creating
an additional layer that is responsible for presenting the data in the proper format between
the functional application and the COM and NM components. The application would then
request the data, which would be dependent on the status of the network and the values
within the messages that are received, from this additional layer. The component described
here would be the presentation layer mentioned briefly at the end of Chapter 13.
Another function that station management could perform is changing the overall func-
tioning of the application based on the status of nodes within the network. If the application
is operating within an OSEK/VDX OS, the station management component could identify
when the APPMODE must be changed because critical data is not available from an external
node.
Network Management APIs (2) The NM component provides a number of API services
that can be used by the station management component to initialize, control, and query the
status of the NM component. These API services are categorized into three types of services:
Summary 217
common, direct NM, and indirect NM. Each of these services will be described in more detail
in the following chapters.
Network Management Algorithms (3) This section of the NM component contains the
specific algorithms for both direct and indirect NM. These algorithms determine the current
configuration of the network and identify the status of each node. They will be discussed in
more detail in the following sections.
Interaction Layer Interface (4) This interface is provided by the interaction layer of the
COM component for use by the indirect NM portion of the NM component. It was not dis-
cussed in Part 2 because it is not visible to the application. The services provided by this inter-
face are discussed in Chapter 16, “Indirect Network Management.”
Data Link Layer Interface (6) Similar to the interaction layer interface discussed previ-
ously, the data link layer of the COM component must provide an API for the NM compo-
nent. These services also were not discussed in Part 2 but are discussed in the following
chapters.
Multiple Network Interfaces (7) The model of network management comprehends the
possibility of multiple networks attached to a particular device. These might be multiple sim-
ilar networks or completely unique networks. Each network must be supported by a proto-
col-specific algorithm, as mentioned earlier.
14.2 Summary
In this chapter, I looked at the basic architecture of network management and how it interacts
with an application and other components. The OSEK/VDX NM specification defines two
algorithms that have minimal overlap: direct NM, which is covered in Chapter 15, and indi-
rect NM, which is covered in Chapter 16.
218 Chapter 14: Network Management Overview
Direct Network
Management
Various forms of direct network management (NM) are used extensively in the European
automotive industry that require an extensive, robust NM component and can identify
changes to the configuration of the network rapidly. In this chapter, I introduce the concept of
direct NM and describe how network management is configured and used by an application.
The station management component is developed as an example throughout this chapter.
219
220 Chapter 15: Direct Network Management
ECU ECU
B D
1
1
4 2
The logical ring is implemented by passing a “Ring” message sequentially from the small-
est to the largest numbered node, which then passes the Ring message back to the smallest
numbered node. Direct NM also requires a broadcast type of network implementation so that
every node can hear the messages that are being sent. Two additional types of messages are
broadcast asynchronously on the network: an “Alive” message and a “Limp Home” message.
The Alive message identifies a new node on the network and puts the system into a transient
state. When the new node has identified all nodes on the network, the system transitions into
a stable state. In the stable state, the NM component is fully aware of the status of all nodes
on the network. A node that is not functioning properly transmits the Limp Home message.
Each of these messages are discussed in more detail later in this chapter.
The NM component uses information from the transmission of these messages to deter-
mine the status and configuration of the network. The status of the network provides infor-
mation on the state in which network management is presently operating. The three main
states for network management are shown in Figure 15.2.
When the system is reset, network management enters the NMOff state. When the applica-
tion invokes StartNM(), the NM component enters the NMOn state.
StatusType StartNM(NetId net);
Direct Network Management Concept 221
NMOff
StartNM
NMOn...
NMShutDown
StopNM
Core versus Optional Services Within the OSEK/VDX NM specification, all API services
are defined as either core or optional. In version 2.51 of the specification, the only core ser-
vices are StartNM() and StopNM(); consequently, a minimal implementation of a NM compo-
nent could participate in the logical ring yet provide little or no information to the
application. As an example, the network management version included in the WindRiver
OSEKWorks implementation provides three levels of network management — Full Master,
Master, and Slave — which corresponds with the suggested implementation that is included
in the OSEK/VDX NM specification. The Full Master level includes most of the services
defined in the NM specification but also requires the most system resources. The Master level
provides status information only and requires fewer resources. Finally, the Slave level pro-
vides only the services defined as core to the NM specification that will allow participation in
the ring. Although no conformance classes are defined in the NM specification, the three sug-
gested levels of services are similar to conformance classes. The next version of the NM spec-
ification could include a set of conformance classes for direct NM.
When choosing a network management implementation, you must determine which ser-
vices are supported before deciding which to use. As I mentioned, only StartNM() and
StopNM() are required. Consequently, an implementation can claim OSEK/VDX NM con-
formance, yet not provide any status or configuration information to the application. This
might be acceptable in some applications, but not in others.
222 Chapter 15: Direct Network Management
StartNM() initiates participation in the network management ring on the network defined
by the net parameter without affecting other networks that might be connected to this device.
Consequently, if multiple networks are connected to the same device, as in ECU G in Figure
15.1, each network functions separately and has to be started individually. The NM compo-
nent for the network that is being started transitions from the NMOff to the NMOn state. E_OK is
the only return value defined for StartNM(). One restriction for this API service is that the
communication component must already be running. For an OSEK/VDX COM component,
this means that StartCOM() has completed. In the example program, I added this network
management API service in the InitOS task (Listing 15.1).
StartCOM();
StartPeriodical();
StartNM(NM1);
while(list->appmodemask != 0x00000000){
if((list->appmodemask & currentAppModeMask)!= 0){
if(list->alarmtype == ALARM_REL){
SetRelAlarm(list->alarm,list->start,list->cycle);
}
else{
SetAbsAlarm(list->alarm,list->start,list->cycle);
}
}
list++;
}
TerminateTask();
}
The NMShutDown state is entered when the application invokes StopNM().
StatusType StopNM(NetId net);
The only action taken by StopNM() is to move the NM component for the network identified
by the net parameter into the NMShutDown state. Once this state is entered, the NM compo-
nent performs all the housecleaning required, such as stopping timers and clearing flags, and
then immediately enters the NMOff state. As with StartNM(), the only status returned is E_OK.
Direct Network Management Concept 223
It is possible for only one network to be in the NMOff state while the other networks are oper-
ating in the NMOn state. In the example program, the NM component is shut down just before
the communication component is stopped in the CloseOS task (Listing 15.2).
NMon
NMInit NMActive
Wakeup
NMAwake... TalkNM SilentNM
Sleep NMPassive
NMBusSleep
NMAwake
NMReset
NMTransmi tError
NoNMTransmi tError
NoNMError
NMReceiveError
NMNormal NMLimpHome
NMTransmitError FatalBusErrorr
In the NMLimpHome state, the NM component continues to monitor the network to deter-
mine if message transmission has been restored, which could indicate an intermittent connec-
tion somewhere in the system. While the system is in this state, a periodic Limp Home
message is transmitted. If transmission is restored, the system transitions back into the NMRe-
set state and reinitializes.
NM NM1 {
TYPE = FULL_MASTER;
IDBASE = 1792;
WINDOW_MASK = 469762048;
NODE_ID = 1;
RX_LIMIT = 10;
TX_LIMIT = 10;
MAX_NODES = 4;
NM_TASK = NMProcessing;
NM_NETWORK = Net1;
RING_DELAY = 250;
RX_TIMEOUT = 2000;
LIMPHOME_TIMEOUT = 5000;
BUSSLEEP_TIMEOUT = 6000;
RETRANSMIT_TIMEOUT = 150;
CAN_MSGTYPE = STANDARD;
};
Many attributes of the NM object are discussed throughout this chapter, so don’t worry if it
is a little confusing at this point. Like the OSEK/VDX COM specification, the NM specifica-
tion does not have a standard OIL configuration format. Your specific implementation could
be slightly different from this listing; however, the concepts defined in the NM specification
will be the same. The first attribute in this configuration object is TYPE, which describes the
specific types of FULL_MASTER, MASTER, or SLAVE. The next attribute of concern is NM_TASK,
which defines the task activated when activity related to network management occurs on the
network. In this case, instead of processing the messages at the driver level, a task is activated
that processes the received messages. This task is created by the OIL configuration utility
automatically and is not a task that needs to be created by the application developer. It is
unique to OSEKWorks. The NM_NETWORK attribute defines the physical network on which this
particular network management object participates. This network is defined as part of the
COM component. With this configuration, a different task is activated for changes in each of
the networks attached to the device. To accomplish this, each NM object requires a unique
name for the NM_TASK attribute.
The OSEK/VDX NM specification defines a number of support items to generate system
configurations. These items are optional and not implemented by OSEKWorks; however, they
Status Monitoring 227
affect operation in the NMNormal state and need to be discussed because they could be encoun-
tered in an implementation that realizes these configuration items in the OIL configuration
file or as macros included in the application source.
InitCMaskTable initializes the mask of configuration items that signals a changed configu-
ration. This mask resides in a table of masks and has two types: Normal and Limp Home.
Each mask is given a handle that can be used later.
InitIndDeltaConfig defines the way the application is notified when the configuration
changes. The notification mechanism either activates a task or sets an event.
InitIndRingConfig defines the way the application is notified when the Ring message is
received. The notification mechanism either activates a task or sets an event.
GetStatus(NM1,&networkManagementStatus);
GetConfig(NM1,&networkConfigurationNormalNew,NMCFG_NORMAL);
if(CmpConfig(NM1,&networkConfigurationNormalNew,
&networkConfigurationNormal,
&networkConfigurationMask)!= TRUE){
if((networkConfigurationNormalNew & OTHER_NODE_MASK)==0){
if(GetActiveApplicationMode() == HEAD_TO_HEAD){
ChangeMode(SINGLE_PLAYER);
}
}
228 Chapter 15: Direct Network Management
}
memcpy(&networkConfigurationNormal,&networkConfigurationNormalNew,
sizeof(ConfigType));
TerminateTask();
}
When run, the StationManagement task obtains the current status of the network using Get-
Status().
Description Definition
Operating mode of the Expands the standard status bit to two bits, which are
network interface interpreted as follows:
00 — No error
01 — Error but communication is possible
10 — Error and communication is not possible
11 — Reserved
Number of nodes identified on The number of nodes actively participating in the
the logical ring logical ring.
Number of nodes on the logical The number of nodes sending a Limp Home message.
ring in Limp Home mode
Time elapsed in the stable state The amount of time that the network has been operat-
ing in the stable state. The units are not defined by the
standard and are implementation specific.
Time elapsed in the The amount of time that the network has been operat-
dynamic state ing in the dynamic state. The units are not defined by
the standard and are implementation specific.
Two additional API services are defined as optional and have not been included in the
example application. SelectDeltaStatus() is the first service.
StatusType SelectDeltaStatus(NetIdType net, StatusHandleType status,
StatusHandleType mask);
SelectDeltaStatus() notifies the application of the network status changes of its choosing.
The values passed to the NM component are handles to a network status and the status mask
defined by the Init configuration items discussed earlier in this section. The handle refers to
the particular mask and target from the table. How this is implemented is not defined in the
specification. Whenever the status changes, the NM component checks to see whether the
mask bit that corresponds to the status change is set and whether the new value of that bit is
equal to the value in the corresponding bit in the status parameter before notification occurs.
The task or event that is triggered is configured using InitIndDeltaStatus, discussed earlier.
The status returned from this API service is always assumed to be E_OK; however, the status in
the specification indicates that no status is returned, which directly contradicts many of the
standards created in the OSEK/VDX specifications and is probably in error.
230 Chapter 15: Direct Network Management
The next optional API service is CmpStatus(), which compares two status values with
respect to a mask and determines if the required status values have changed. Although
optional, it is a simple test to perform if the status is implemented as a bit field–encoded inte-
ger, as recommended, and can be implemented as a macro.
StatusType CmpStatus(NetIdType net, StatusRefType test,
StatusRefType ref, StatusRefType mask);
The values passed in the test, ref, and mask parameters are references to variables within
the application. The parameters are passed by reference because, in the extended status case,
these variables can be very large structures and should not be passed by value to any API ser-
vice. The logic performed by the service for each status item is
Two additional API services are optional. The first, SelectDeltaConfig(), functions iden-
tically to SelectDeltaStatus() but is based on changes to the network configuration, not the
network status.
StatusType SelectDeltaConfig(NetIdType net, ConfigKindName kind,
ConfigHandleType handle,
ConfigHandleType mask);
SelectDeltaConfig() includes one more parameter than SelectDeltaStatus(). The kind
parameter determines whether this Delta configuration applies to the Normal or Limp Home
configurations.
The other optional API service is InitConfig(), which forces the NM component to move
from the NMNormal state to the NMReset state and to restart network configuration monitoring.
StatusType InitConfig(NetIdType net);
When InitConfig() is invoked, the configuration of the node in the application is considered
Mute, and all other nodes are considered Absent. Nodes are then added based on an algo-
rithm defined later in this chapter, and the local node is Not Mute as soon as a network man-
agement message is sent successfully. The status returned from this service is always E_OK.
Now that I have described the basic concept of direct NM, I will now describe in more
detail the mechanics of the method, although in most applications, the implementation is
transparent. However when debugging the system, it is imperative to know about the mes-
sages that are running around on the network and how they function.
MessageReceived(Alive)
WindowDataConfirmation(Failed)
Ttyp
Ttx
TransmitMessage(Ali ve)
MessageFrame(Alive)
When an Alive message is received by an active node, the following steps are performed.
1. The sending node is added to the configuration of the network as being Present.
2. The local node determines whether the new node is the new logical successor on the ring.
(Definition of logical successors is discussed in more detail in the next section.)
If the communication component indicates to the NM component through service D_Win-
dowData.confirmation (WindowDataConfirmation(Failed) message in Figure 15.7) that the
Alive message could not be transmitted, a second timer, TTx, starts and a counter increments.
This timer is defined by the RETRANSMIT_TIMEOUT attribute in the OIL file. If the counter
exceeds a certain threshold, then the NM component enters the Limp Home mode. This
threshold is defined by the TX_LIMIT attribute; otherwise, when TTx expires, the Alive message
is retransmitted by the NM component. This timer is used for the transmission of either Alive
or Ring messages.
requirements dictate that messages be communicated on a broadcast bus, each node monitors
the Ring messages to assist in building the configuration and identifying when a node has dis-
appeared from the network. In this section, I describe the movement of Ring messages around
the logical ring.
Network Startup When network management first starts and after the Alive message is
transmitted, the network is considered to be in the dynamic state. During this state, the NM
component monitors the bus for both Alive and Ring messages. A number of different scenar-
ios can occur during this state.
1. If an Alive message is received, the configuration and successor are updated. This was dis-
cussed in the previous section.
2. If at any point before the TTyp timer expires a Ring message is received, then the timer is
canceled and the Ring message is processed. Processing of Ring messages is discussed
shortly.
3. When the TTyp timer expires, the local node transmits the Ring message.
4. If a Ring message is received between the time that the local node sends it to the data link
layer and the time that the data link layer confirms back to the NM component that the
message has been sent, it is ignored.
Figures 15.8 and 15.9 show the sequence of events during network startup for two scenar-
ios: TTyp expires before a Ring message is received and a Ring message is received before TTyp
expires.
MessageIndicated(Ring)
TTyp
MessageReceived(Ring)
Network Management Protocol Data Unit 237
TTyp
TransmitMessage(Ring)
MessageFrame(Ring)
During the time that the network is in the dynamic state, multiple Ring messages can be
traveling at the same time. However, based on the actions that are taken when a Ring mes-
sage is received, these multiple Ring messages disappear rapidly.
Processing Ring Messages When a Ring message is received, the local node checks the
destination ID of the NMPDU. The following actions are taken based on the value of this
field.
1. If the Ring message is not destined for the local node, the TTyp timer is canceled, then the
TMax timer is started if it is not running or restarted if it is running. TMax is defined by the
RX_TIMEOUT attribute. The NM component checks the nodes in the source and destination
identifiers and updates the network configuration based on these identifiers.
2. If the Ring message is destined for the local node, the TMax timer is canceled, then the TTyp
timer is started if it is not running or restarted if it is running. If the source ID is indicated
as Absent in the configuration management information, the state of the source node is
changed to Present.
3. If the NM component has sent the ring NMPDU to the data link layer and is awaiting
confirmation, the Ring message that was received is ignored.
The sequence of events in Figure 15.10 clearly shows how multiple Ring messages that
exist at startup could disappear quickly. If a Ring message is received by a node while it is
waiting to transmit a Ring message, the pending Ring message is canceled, thereby eliminat-
ing one of the extra messages. This occurs whether or not the new Ring message is destined
for the local node. If a Ring message is received during the time frame between sending the
NMPDU to the data link layer and the confirmation of the transmission, the new Ring mes-
sage is discarded, thereby eliminating the extra message.
238 Chapter 15: Direct Network Management
MessageIndicated(Ring)
TTyp MessageReceived(Ring!=Local)
MessageIndicated(Ring)
Tmax MessageReceived(Ring!=Local)
MessageIndicated(Ring)
Tmax
MessageReceived(Ring=local)
Ttyp
p
TransmitMessage(Ring)
MessageIndicated(Ring)
MessageReceived(Ring=local)
MessageFrame(Ring)
WindowDataConfirmation(Success)
Tmax
When superfluous Ring messages are canceled and one Ring message completely circles
the logical ring without an Alive message transmission, the state of the network transitions
from dynamic to stable. It is only during the stable state that optional data can be added to a
network message. During the dynamic state of the network, data in these fields is ignored.
When a Ring message is received and the network is in the stable state, the NM compo-
nent can notify the application that a Ring message has been received. The optional configu-
ration item that defines the task or event to be triggered is InitIndRingData. If this
functionality is implemented, the NM component would be able to activate a task or set an
event in the same manner as notification of status and configuration management changes.
The StationManagement task in the example application would have two additional API ser-
vices to manipulate this data. These functions would be called only if the status indicates that
the ring data could be updated.
StatusType ReadRingData(NetIdType net, RingDataType data);
Detection of an Absent Node The NM component detects when a node is no longer par-
ticipating in the logical ring if the TMax timer expires. When this occurs, the following steps
are taken.
1. The NM component enters the NMReset state.
2. A receive counter is incremented. If this counter exceeds the threshold, Limp Home mode
is entered.
3. An Alive message is transmitted.
4. The state of the network is set to dynamic.
5. The configuration management is reset such that the local node is the only node on the
network and the logical successor is set to local node.
6. The TTyp timer is started.
7. The NM component moves back into the NMNormal state.
Operation continues from this point in the same manner as it did during the startup of
network management.
Skipped Nodes As Ring messages are transmitted around the logical ring, each node
checks to ensure that it has not been skipped. Because a Ring message is transmitted from the
logically lower to the next logically higher ID number, wrapping around from the highest to
the lowest number, it is very easy for a node to determine whether a Ring message was
addressed properly or not. If a node is skipped, it immediately sends an Alive message to
notify everyone that it is still on the network. Figure 15.11 shows an example of how a node
can be skipped.
240 Chapter 15: Direct Network Management
Ring
Ring
Ring
Alive
Ring
Ring
Ring
Alive
Ring
Ring
Ring
In this scenario, nodes 1, 2, and 3 are actively transmitting Ring messages around the sta-
ble network. Immediately after the Ring message is transmitted to node 2, node 4 comes alive
and sends out its Alive message. It then monitors the Ring messages, identifies those from 2
and 3, and updates its configuration. When node 4 receives the Ring message from node 3, it
only knows about the existence of nodes 2, 3, and itself, so it transmits the Ring message to
node 2. Node 1 detects that it has been skipped and sends the “I’m here” Alive message.
15.5 Sleep
The final item I discuss in direct NM is the ability to put the bus to sleep. Two types of nodes
can exist on the network, particularly in an automobile. The first type is a switched node, in
which power to the node is switched on and off directly. When switched off, the node stops
participating in the logical ring, and a timeout error occurs. The other type is a constantly
powered node (e.g., powered by a battery), which must decide when to turn off in order to
preserve battery power. The OSEK/VDX NM specification provides a negotiation method to
ensure that all nodes attached to the network go to sleep at the same time. The application
initiates the transition into NMBusSleep using GotoMode(), which is an optional service having
the following function prototype.
StatusType GotoMode(NetIdType net, NMModeName mode);
When GotoMode() is invoked, it indicates to the network identified by the net parameter
that it wants to transition into the mode defined by the mode parameter. The mode parameter
can be either BusSleep, to transition to the NMBusSleep state, or Awake, to transition to the
NMAwake state.
Negotiation of the transition into the sleep mode is accomplished using the sleep.ind and
sleep.ack opcodes as follows.
1. The application calls GotoMode(BusSleep) requesting that the bus go to sleep. The next
time the node receives the Ring message, the NM component sets the opcode to the Ring
message with the sleep.ind option set to TRUE.
2. If the node is operating in the Limp Home mode, the next Limp Home message sent has
the sleep indication field set to TRUE. This message is sent after TMax, instead of TError, has
elapsed.
3. While sleep negotiation is ongoing and if it is necessary to send an Alive message, then the
Alive message is transmitted with the sleep indication field set to TRUE.
4. When the Ring message has completely traveled around the logical ring with the sleep
indication field of all received network management messages set to TRUE, the first node to
pass the Ring message sets sleep.ack to TRUE.
5. All nodes that receive a Ring message with the sleep acknowledge field set to TRUE stop
transmitting Ring messages, start the TWaitBusSleep timer, and enter the NMTwbsNormal
242 Chapter 15: Direct Network Management
state. The timer is defined in the OIL file with the BUSSLEEP_TIMEOUT attribute. Because it
is a change in status, the NM component notifies the application that bus sleep is about to
occur so the application can enter a state in which messages are no longer sent.
6. When the TWaitBusSleep timer expires, the NM component stops all transmissions on the
bus and transitions into the NMBusSleep state. It is a change of status, so the application is
notified through the indication mechanism.
Figure 15.12 shows a typical sequence of Ring messages around the network during sleep
negotiation. The time delay from the point where the sleep acknowledge Ring message is
received and bus sleep occurs allows all nodes to complete transmission of messages that are
presently in the queue.
Ring- SleepReq
Ring- SleepReq
Ring- SleepReq
Ring- NoSleepReq
Ring- SleepReq
Ring- SleepReq
Ring- SleepReq
Ring- SleepReq
Ring- SleepAck
While the node is in the NMTwbsNormal state, it continues to monitor messages on the net-
work. If any network management message (Alive, Ring, or Limp Home) is received with the
sleep indication bit set to FALSE, the node restarts by entering the NMReset state. This also
occurs if the application invokes GotoMode(Awake). After the node transitions into the NMBus-
Sleep state, it remains asleep until one of the following occurs.
Example Program 243
1. The application invokes GotoMode(Awake).
2. The data link layer of the COM component notifies the NM component that the bus has
awoken. This uses the D_Status.ind service defined in the COM specification. How a bus
is awoken is a function of the network.
3. The data link layer notifies the NM component that a network management message has
been received.
15.6.1 Modules
nm.c This is a new module that contains the StationManagement task.
init.c The InitOS and CloseOS tasks were modified to start and stop network manage-
ment.
cardgame.c The LostOpponent task was removed because it is now performed by the Sta-
tionManagement task.
15.7 Exercises
1. When a node is added to the network, detect the configuration change and display a
prompt that allows the player to immediately change to HEAD_TO_HEAD mode.
2. After five minutes has expired, put the bus to sleep.
244 Chapter 15: Direct Network Management
15.8 Summary
Direct NM does very little in an application, but it is very complex to understand. I attempted
to explain how direct NM functions from the viewpoint of messages transmitted across the
bus. The NM specification, which is included on the accompanying CD, includes extensive
state transition diagrams and flow charts that describe in gory detail how network manage-
ment works under the covers. One warning: many of the state transition diagrams are incon-
sistent in their format and terminology. Hopefully, after reading this chapter these
inconsistencies will become apparent.
Throughout this chapter, I have discussed a number of timers. Table 15.4 summarizes
these timers and provides typical values for each. In addition, I have shown the scope of each
timer — either global for all nodes or local to a specific node. When a timer is global to all
nodes, it must be the same on all of the nodes. Local timers can differ from node to node.
Typical
Timer Description Value Scope
(ms)
TTyp Typical time from receipt of a Ring mes- 100 Global
sage to retransmission of the message.
TTx Time to wait before retransmitting a Ring 25 Local
message.
TMax Maximum time to wait after a Ring mes- 250 Global
sage is transmitted before determining that
the
destination node is missing.
TError Time between transmissions of Limp 1000 Local
Home message.
TWaitBusSleep Time after bus sleep has been acknowl- 1500 Global
edged before entering NMBusSleep
Direct NM provides a critical service to an application that is operating in a distributed
environment. It is imperative for the application to know as soon as possible if information
that it requires is no longer available from an external node. Direct NM performs this func-
tion with minimal overhead to the application and a high level of portability across multiple
functions and applications.
16
Chapter 16
Indirect Network
Management
Indirect network management is much simpler to implement but is less robust than direct
NM. It is implemented by passively monitoring network messages that are sent periodically
by the individual nodes on the network. If a periodic message is not received within a certain
time frame, the node is considered Absent. Because some periodic messages can transmit at a
very low rate, such as once per second, indirect NM might not be able to identify when a
node is no longer available within the required period of time.
In this chapter, I discuss the concept of indirect NM and identify the differences between
direct and indirect NM. I assume you have read the chapter on direct NM. Indirect NM is not
supported in the current release of OSEKWorks; therefore, an example program using this
form of network management was not developed. However, the API services between the two
forms of network management are almost identical, and the effect on the application would
be minimal. I will describe any differences that occur in the API services.
245
246 Chapter 16: Indirect Network Management
ECU ECU
B D
Network 1 continues to operate under the direct NM protocol, but network 2 will now
operate under the indirect NM protocol. The node identification numbers in network 2 have
been removed in this figure. Indirect NM has no concept of a node address or identifier.
Although all nodes on a given network must use the same form of network management, an
individual ECU can use different forms for the different nodes. This is illustrated in gateway
unit ECU G.
Under indirect NM, the system can operate in one of two states: NMOff or NMOn (Figure
16.2).
In this state chart, the NMShutdown state that existed under direct NM no longer exists. It is
no longer required because indirect NM passively monitors the network and nothing needs to
be shut down. StartNM() and StopNM() are invoked in exactly the same manner as under
direct NM; consequently, the example program does not have to change to handle these ser-
vices. StopNM() performs a slightly different function under indirect NM by transitioning the
system directly from NMOn to NMOff.
The OSEK/VDX network management specification recommends that an indirect NM
implementation be scalable to address different requirements of different applications. This
would indicate that an implementation might have multiple configurations, similar to the Full
Master, Master, and Slave configurations discussed under direct NM.
Indirect NM Concept 247
NMOff
StopNM StartNM
NMOn...
NMAwake
Wakeup Sleep
NMBusSleep
NMAwake
NMWaitBusSleep
WaitTimeExpired
W
GoToMode_Awake
Aw
NoNMTransmitError
GoToMode_BusSleep
Description Definition
Operating mode of the net- Expands the standard status bit to two bits, which are
work interface interpreted as follows:
00 — No error
01 — Error but communication is possible
10 — Error and communication is not possible
11 — Reserved
The bit positions are my additions and are not defined in the specification. The selected bit
positions can be the same or different bit positions as in direct NM. SelectDeltaStatus()
and CmpStatus() are also supported under indirect NM and function in the same manner as
they do under direct NM. However, because the masks can be different between the two
implementations, code written for a direct NM implementation will probably have to be
modified to function under indirect NM.
16.3.1 Configuration
System configuration requires additional objects in the OIL configuration file. The current
version of the OSEK/VDX OIL specification does not define the objects for network manage-
ment. First, the periodic messages have to be defined for the COM component. Next, the net-
work management objects need to be defined. The following classes of objects are typical of
objects that need to be defined for network management. Because the current OIL specifica-
tion does not define naming standards for network management objects, refer to the imple-
mentation-specific documentation to determine those names.
Monitored node is monitored on the network and has to be linked to a monitored mes-
sage. If node monitoring is performed with one timeout per message, the timeout period must
be included. In addition, the increment and decrement counter values for extended network
configuration are set for each node. From the set of monitored nodes, the default configura-
tion of the network can be developed.
Timeout for observation is the time of one global timeout, also known as TOB. It is part
of the InitIndirectNMParams configuration item.
Time for error recovery is the time after entering the NMLimpHome state before network
management attempts to restart communications. It also is part of the InitIndirectNMParams
configuration item.
Wait for sleep timeout is the time to wait before going to sleep and is included in InitIn-
directNMParams.
TransmitMessage()
MessageIndicated(Node1)
MessageReceived(Node1)
TOB
WindowDataConfirmation(Success)
MessageIndicated(Node2)
MessageReceived(Node2)
UpdateConfiguration()
tion()
TransmitMessage()
MessageIndicated(Node1)
1)
MessageReceived(Node1)
TOB
WindowDataConfirmation(Failure)
UpdateConfiguration()
254 Chapter 16: Indirect Network Management
Node1Time MessageIndicated(Node1)
MessageReceived(Node1)
Node2Time
MessageIndicated(Node2)
Node1Time
MessageReceived(Node2)
MessageTimeout()
UpdateConfiguration()
The decision to use a single timeout or individual timeouts usually depends on the period
of the messages that are to be monitored. If all messages are approximately the same period
(i.e., every 80–120 ms), then one timeout is probably best. However, if the periodic messages
vary extensively (i.e., 80–1,000 ms) and responding to missed messages is critical, then indi-
vidual timeouts are necessary. Individual timeouts have the added overhead of one additional
timer per message.
NodeAbsent
NodePresent
NodeAbsent
NodeAbsent
5
NodePresent
NodeAbsent
NodeAbsent
CounterValue
NodePresent
NodeAbsent
NodeAbsent
3
2 Absent
Statically
1
In Figure 16.7, extensive noise in the system causes the periodic message to be missed ran-
domly. Whenever the timers expire and the periodic message is missing, the counter is incre-
mented by one. Whenever the message is received, the counter is decremented by three. The
threshold value is four. Extended configuration management allows some level of noise toler-
ance in the system, whereas the Normal configuration management does not tolerate any
noise.
16.7 Sleep
GoToMode() with the BusSleep argument initiates the transition into the NMBusSleep state
under indirect NM. When this occurs, the TWaitBusSleep timer is started and the NMWaitBus-
Sleep state is entered. When this timer expires, the NMBusSleep state is entered immediately.
Unlike direct NM, negotiation of transition into the Sleep state does not occur.
The OSEK/VDX NM specification describes a methodology called Master–Slave that
allows sleep negotiation. It is implemented by defining one node on the network as the Mas-
ter node; it reserves one bit as the sleep bit in a normal application message. All remaining
256 Chapter 16: Indirect Network Management
nodes on the network are Slave nodes and monitor the sleep bit. When the Master has deter-
mined that it is time for the bus to go to sleep, it sets this bit. Each Slave node then executes
GoToMode() to put its bus to sleep. This methodology is not supported by an indirect NM
component, so you will have to develop it for each application.
16.9 Exercises
1. Create an indirect NM module that uses the capabilities of the COM and OS components
to monitor periodic messages from multiple nodes and to construct a network configura-
tion. This module can use either one timeout per node or one global timeout to perform
the monitoring. Determine both Normal and Normal Extended configuration.
2. Implement a Master–Slave sleep module that provides the GoToMode() service and moni-
tors the network sleep message. For simplicity, create a new message that is used exclu-
sively to trigger bus sleep. Because the application is not capable of controlling the COM
data link layer, it will not be possible to shut down the network, but the new module
should stop all periodic messages when it is time to put the bus to sleep.
16.10 Summary
Indirect NM is the last topic in the OSEK/VDX set of standards to be covered in this book.
This form of network management is much simpler to implement than direct NM, but it is
also less robust. For systems that do not require the rapid response of direct NM or that have
limited resources, this form of network management is an ideal alternative.
The OSEK/VDX standards are constantly evolving. Shortly, the OSEK/VDX implementa-
tion language (OIL) will be updated to include standard objects and attributes that define
COM messages. A set of OSEK/VDX standards for time-critical applications, referred to as
OSEKTime, also is in the process of being developed. Finally, an OSEK run-time interface
(ORTI) is being developed that will assist application development by providing a standard
interface to development tools. As I complete this book, the first version of ORTI has been
released for comments. To keep up-to-date on the standards, visit the OSEK/VDX organiza-
tion’s Web site at http://www.osek-vdx.org. The OSEK/VDX steering committee has submit-
ted a set of standards (ISO-17356) to the International Standards Organization (ISO),
making it a candidate for standardization.
A
Appendix A
Choosing an
Implementation
This appendix provides information that could be helpful when searching for an OSEK/VDX
implementation. It is arranged as a series of questions that should be answered by the vendor
prior to evaluating the implementation. A discussion is also included to describe more about
the question, why it should be asked, and what else might be required.
A.1 Certification
Is the implementation certified OSEK/VDX compliant?
Although OSEK/VDX is an open standard, the name is still a trademark and can only be used
with the approval of the OSEK/VDX Steering Committee. The process is simple, and no
licensing fees are required. However, there is a cost to have the test suite analyzed by an out-
side company. See the licensing process on the Web site at http://www.osek-vdx.org if you
want to license the trademark name. This site also lists the names of the products that are cur-
rently certified to be compliant and are authorized to use the trademark. When looking for an
OSEK/VDX implementation, check for certification both with the vendor and with the site. In
many cases, the vendor will be in the process of certification and will not yet appear on the
site. Make sure that the certification has been completed before finalizing an agreement with
the vendor.
257
258 Appendix A: Choosing an Implementation
A.2 Conformance
Which conformance classes or API services are supported?
As mentioned throughout this book, each of the three standards have different levels of con-
formance. The OS standard has BCC1, BCC2, ECC1, and ECC2, along with CCCA and pos-
sibly CCCB borrowed from the COM standard for intertask communication. The COM
standard has CCCA, CCCB, CCC0, CCC1, and CCC2 conformance classes. Finally, the NM
standard does not define conformance classes, but does define many optional API services.
This makes it difficult to determine what level of conformance a particular NM implementa-
tion meets. Make sure that the NM implementation provides the necessary services. (Is the
current configuration of the network available to the application? Can the Ring message data
be read and modified? And so on.).
It is important to know the level of conformance because the OSEK/VDX standard does
not require a particular implementation to support all conformance classes. Many smaller
implementations support only the simpler conformance classes but are very compact and fast.
If your application is growing or will be scaled across many products with different RTOS
requirements, an implementation that supports more features would be required.
A.7 Benchmarks
What are the benchmarks of the implementation?
Benchmarks include the ROM and RAM size based on the options used, the context switch
time, and the additional overhead in ROM and RAM per object the application uses.
261
262 Appendix B: Example Program Build Structure
src
ch01
bin
bld
cfg
inc
lst
obj
src
ch16
doc
The src subdirectory contains all of the source code discussed in the book, including the
source files, header files, configuration files, and all files required to rebuild the application.
Because of licensing requirements, object files are not included; however, empty directories
for the object files, listings files, and map files are included in the directory tree. Within the
src subdirectory is a unique subdirectory for each chapter in the book. The layout of the
chapter subdirectories follows.
bin This subdirectory is empty on the CD but will contain the binary outputs of the com-
plete application, the map file, and the hexadecimal file encoded in Motorola S19 format.
bld This subdirectory contains the files required to build the application.
Makefile and *.mk These are the makefiles used to build the application and are written
for GNU make. Makefile is the main makefile; the other files are included as necessary. All
make references are relative to the start directory, which is required to be chXX\bld. The
following dummy targets are available and can be passed using make.
• build_ram Builds the application with a RAM memory target for the application.
• build_flash Builds the application with a FLASH memory target for the application.
Porting to Different Implementations 263
• rebuild_ram and rebuild_flash Performs a clean then a build_ram or build_flash.
The NODE variable must be defined as NODE0 or NODE1. When Node 1 is being created, the
TARGET_NODE variable is set to 1. Depending on the values of the command line parame-
ters, the proper make and link files are used to build the application.
To build the application for Node 0 in RAM, execute the following command from the
chXX\bld directory.
Some changes might be needed in these files based on your specific host configuration.
Although I hate to do this, please refer to the files for a discussion of what needs to be
changed. Documentation separate from the actual files should be provided, but because
the changes are minimal and linked directly with the files, I am breaking my own rule in
this case. Search on the characters CHANGE_ME for the comments on what needs to be
changed.
*.lk These files are used by the program linker to place the files in the proper location in
memory. The program.lk file maps the program into RAM on the Axiom board, and the file
progflsh.lk maps the program into the FLASH memory.
cfg This directory contains the OIL configuration file, along with the application-specific
configuration files that are discussed in each chapter.
inc This directory contains all of the include files used by the application.
lst This empty directory will receive all of the listings from the build of the application. The
make file creates a listing with the assembly code interleaved with the source code.
obj The individual module object files will be placed in this directory after build. The linker
will look in this directory for all nonlibrary files to build.
src This directory contains the source files for the application in both C and assembly.
264 Appendix B: Example Program Build Structure
Mode switches All switches are in the OFF position except SW1 number 2 and SW2 num-
ber 6.
• JP1 — On 1-2
• JP2 — On
• JP3 — On 1-2
• JP4 — On
• JP5–JP7 — Off
• JP8 — On
• JP9 — Off
• JP10 — Both vertical
• JP11 — On
• JP12 — On
• JP13 — N/A
• FPROG_EN — Off
• VPP_EN — Off
• EXT_CFG — On
• EXT_EN — On
• MEM_OPT — 5, 7 On
• M-SEL — 2
• FLSH_SEL — 3
• RAM_SEL — 1
• MEM-VOLT — 5V
CAN interconnect Connect pin J1-1 on one board to pin J1-1 on the second board. Do the
same for J1-2 pins. Terminate at each end with a 150-ohm resistor.
C
Appendix C
265
266 Appendix C: OSEK/VDX API Reference
ActivateTask()
Prototype
StatusType ActivateTask(TaskType taskID);
Inputs
taskID Name of the task that is to be activated. This is the task name exactly as it appears in
the OIL configuration file.
ActivateTask()
Outputs
None.
Return
Status Description S E
E_OS_ID Input taskID is not a valid task. X
E_OS_LIMIT Too many activations of taskID task. Only applicable in X
XCC2 conformance classes. Activation is ignored.
E_OK Service executed without error. X X
Function
This API service moves the task identified by the input taskID from the SUSPENDED state to the
READY state. If the service is invoked from a preemptive task when the RES_SCHEDULER resource
is not locked, the scheduler is entered and preemption occurs if the activated task is a higher
priority than the invoking task. If the service is invoked from a non-preemptive task from the
ISR level or from within a critical section in which RES_SCHEDULER is locked, the scheduler
will not be invoked and preemption will not occur.
CancelAlarm()
Prototype
StatusType CancelAlarm(AlarmType alarmID);
Inputs
alarmID Name of the alarm that is to be canceled. This is the alarm name exactly as it
appears in the OIL configuration file.
Outputs
CancelAlarm()
None.
Return
Status Description S E
E_OS_ID Input alarmID is not a valid alarm. X
E_OS_NOFUNC Alarm defined by alarmID is not in use. X X
E_OK Service executed without error. X X
Function
This service cancels an alarm that has been set but has not yet been triggered. If the applica-
tion wants to restart an alarm that is currently running, it must first invoke this service before
it can reset the value of the alarm.
ChainTask()
Prototype
StatusType ChainTask(TaskType taskID);
Inputs
taskID Name of the task that is to be activated. This is the task name exactly as it appears in
the OIL configuration file.
Outputs
None.
ChainTask()
Return
Status Description S E
E_OS_ID Input taskID is not a valid task. X
E_OS_LIMIT Too many activations of taskID task. Only X
applicable in XCC2 conformance classes.
Activation is ignored.
E_OS_RESOURCE Invoking task still occupies resources and X
termination is not safe.
E_OS_CALLEVEL Service was invoked from the interrupt level. X
E_OK This status is never returned because service X X
does not return if successful.
Function
This service terminates the invoking task, moves the task identified by the input taskID from
the SUSPENDED state to the READY state, and reschedules the application. Because the invoking
task terminates first, invoking this service with taskID set to the same ID as the invoking task
does not cause multiple activations. All resources locked by the invoking task must be
released using ReleaseResource() prior to invoking this service. This service only returns in
the extended status state when an error occurs. All tasks must end with either ChainTask() or
TerminateTask().
Appendix C: OSEK/VDX API Reference 269
Specification/Conformance Class Usage
OS Conformance Classes/Call Levels
BCC1 BCC2 ECC1 ECC2 TASK ISR
X X X X X
ChainTask()
270 Appendix C: OSEK/VDX API Reference
ChangeProtocolParameters()
Prototype
ChangeProtocolParameters()
Inputs
message Symbolic name of the USDT message that is targeted. This is the name of the mes-
sage as it appears in the OIL configuration file.
bsValue Value to be used for the block size (BS) of the USDT message. This value is the num-
ber of frames transmitted before waiting for a flow control frame from the receiving control-
ler.
stValue Value used for the minimum separation time (STmin) of the USDT message. This is
the minimum time required in milliseconds between transmission of consecutive frames.
Outputs
None.
Return
Status Description S E
E_COM_ID The input message is not a valid message. X
E_COM_RX_ON The parameters were not changed because X X
there is a message reception in progress.
E_OK Service executed without error. X X
Function
This service changes the block size (BS) and separation time (STmin) parameters for the USDT
message defined by the input message. These parameters override the default values for this
message and are not required to set the original values.
ClearEvent()
Prototype
StatusType ClearEvent(EventMaskType mask);
Inputs
mask Event mask of the events that are to be cleared. This is a logical OR of the event names
as they appear in the OIL configuration file.
Outputs
ClearEvent()
None.
Return
Status Description S E
E_OS_ACCESS Service was not invoked from an extended task. X
E_OS_CALLEVEL Service was invoked on the interrupt level. X
E_OK Service executed without error. X X
Function
This service clears all of the events based on the events that are included in the input mask.
This service can only be invoked from the extended task that owns the events. Typically, this
service will be invoked after the task returns from the WAITING state and has processed a par-
ticular event or set of events.
CloseCOM()
Prototype
StatusType CloseCOM(void);
Inputs
None.
Outputs
None.
Return
CloseCOM()
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values are returned
if the service does not complete successfully.
Function
This service releases all hardware and low-level resources that were used by the communica-
tion component. It will not release any OS resources, which are only released by StopCOM().
This service is typically called prior to StopCOM() if a critical error occurs to reinitialize the
complete system; otherwise, StopCOM() is typically called first. CloseCOM() is typically called
during or immediately after shutting down the OS. It might be possible to invoke this service
from within an OS task; however, all interrupts must be masked prior to invoking the service.
During processing, all communications that are in process will be aborted and data will be
lost.
CmpConfig()
Prototype
StatusType CmpConfig(NetIdType netID, ConfigRefType testRef,
ConfigRefType baseRef, ConfigRefType maskRef);
Inputs
netID Identifier of the communication network on which the configuration will be com-
pared. This is the network name exactly as it appears in the OIL configuration file.
testRef Reference to a variable of type ConfigType that is being checked for changes.
CmpConfig()
baseRef Reference to a variable of type ConfigType that is being checked against for
changes.
maskRef List of relevant nodes that are being tested for changes.
Outputs
None.
Return
Status Description S E
TRUE Returned if all of the relevant nodes in the test configuration X X
have the same state as those in the base configuration.
FALSE Returned if any of the relevant nodes in the test configuration X X
have a different state from those in the base configuration.
Function
This service compares a test configuration to a base configuration to determine if any of the
nodes have changed state. Only the nodes that are defined by the list of relevant nodes will be
checked. If all of the relevant nodes have the same state between the test and base configura-
tions, the service returns TRUE; otherwise, the service returns FALSE. These return values do
not fit the format of the type StatusType but are valid values.
CmpStatus()
Prototype
StatusType CmpStatus(NetIdType netID, StatusRefType testRef,
StatusRefType baseRef, StatusRefType maskRef);
Inputs
netID Identifier of the communication network on which the status will be compared. This
is the network name exactly as it appears in the OIL configuration file.
testRef Reference to a variable of type StatusType that is being checked for changes.
CmpStatus()
baseRef Reference to a variable of type StatusType that is being checked against for
changes.
maskRef List of relevant status values that are being tested for changes.
Outputs
None.
Return
Status Description S E
TRUE Returned if the test status and the base status are the same. X X
FALSE Returned if the test status is different from the base status, X X
and the new status is defined in the mask.
Function
This service compares a test status to a base status to determine if the network has changed
state. A difference is only indicated if the new status is included in the mask. Note that the
status type variable that is being referenced is different than the return value and will proba-
bly have a different name in the actual implementation.
DeclareAlarm()
Syntax
DeclareAlarm(alarmId)
Inputs
alarmId Name of the alarm that is being declared. This is the alarm name exactly as it
appears in the OIL configuration file.
DeclareAlarm()
Outputs
None.
Function
This declaration provides an external declaration of an alarm. It could be used by an imple-
mentation to declare an alarm that is referenced by the application code in a given module. In
many OSEK/VDX implementations, the utility that translates the OIL file into a header file
will typically include the declaration in the global include file, and this macro will be defined
as a blank macro.
DeclareEvent()
Syntax
DeclareEvent(eventId)
Inputs
eventId Name of the event that is being declared. This is the event name exactly as it
appears in the OIL configuration file.
DeclareEvent()
Outputs
None.
Function
This declaration provides an external declaration of an event. It can be used by an implemen-
tation to declare an event that is referenced by the application code in a given module. In
many OSEK/VDX implementations, the utility that translates the OIL file into a header file
typically includes the declaration in the global include file, and this macro will be defined as a
blank macro.
DeclareResource()
Syntax
DeclareResource(resId)
Inputs
resId Name of the resource that is being declared. This is the resource name exactly as it
DeclareResource()
appears in the OIL configuration file.
Outputs
None.
Function
This declaration provides an external declaration of a resource. It can be used by an imple-
mentation to declare a resource that is referenced by the application code in a given module.
In many OSEK/VDX implementations, the utility that translates the OIL file into a header file
typically includes the declaration in the global include file, and this macro will be defined as a
blank macro.
DeclareTask()
Syntax
DeclareTask(taskId)
Inputs
taskId Name of the task that is being declared. This is the task name exactly as it appears in
the OIL configuration file.
Outputs
DeclareTask()
None.
Function
This declaration provides an external declaration of a task. It can be used by an implementa-
tion to declare a task that is referenced by the application code in a given module. In many
OSEK/VDX implementations, the utility that translates the OIL file into a header file typically
includes the declaration in the global include file, and this macro will be defined as a blank
macro.
DisableAllInterrupts()
Prototype
void DisableAllInterrupts(void);
DisableAllInterrupts()
Inputs
None.
Outputs
None.
Return
Status Description S E
None X X
Function
This API service saves the current state of all interrupts, disables all interrupts that are
enabled, and identifies the beginning of a critical section. Within the critical section, no API
service calls are allowed. How the system interrupts are disabled will differ between imple-
mentations and between microcontrollers. However, the effect on the application will be the
same. This service does not allow nesting of critical sections. Library routines and hardware
API routines should use SuspendOSInterrupts() and ResumeOSInterrupts() instead, which
may be nested.
DisableInterrupt()
Prototype
StatusType DisableInterrupt(IntDescriptorType descriptor);
Inputs
Outputs
None.
Return
Status Description S E
E_OS_NOFUNC At least one of the interrupt sources could not be disabled. X
E_OK Service executed without error. X X
Function
This service disables the interrupts indicated by a 1 in the input parameter. The interpretation
of the descriptor is hardware dependent. If all interrupts requested cannot be disabled, an
error is returned, but the other interrupts will be disabled. This service should only be used in
hardware-dependent routines, such as hardware device drivers. Application modules should
use the more abstract DisableAllInterrupts() and SuspendOSInterrupts().
EnableAllInterrupts()
Prototype
void EnableAllInterrupts(void);
Inputs
EnableAllInterrupts()
None.
Outputs
None.
Return
Status Description S E
None. X X
Function
This API service enables all interrupts that were enabled prior to the previous call to Dis-
ableAllInterrupts() and identifies the end of a critical section. Within the critical section,
no API service calls are allowed. If DisableAllInterrupts() was not previously called, the
action taken is undefined by the specification. How the system interrupts are re-enabled will
differ between implementations and between microcontrollers; however, the effect to the
application will be the same.
EnableInterrupt()
Prototype
StatusType EnableInterrupt(IntDescriptorType descriptor);
Inputs
Outputs
None.
Return
Status Description S E
E_OS_NOFUNC At least one of the interrupt sources could not be enabled. X
E_OK Service executed without error. X X
Function
This service enables the interrupts indicated by a 1 in the input parameter. The interpretation
of the descriptor is hardware dependent. If all interrupts requested cannot be enabled, an
error is returned, but the other interrupts will be enabled. This service should only be used in
hardware-dependent routines, such as hardware device drivers. Application modules should
use the more abstract EnableAllInterrupts() and ResumeOSInterrupts().
EnterISR()
Prototype
void EnterISR(void);
Inputs
None.
Outputs
None.
Return
EnterISR()
Status Description S E
None X X
Function
This API service is only used in a category 3 ISR to notify the implementation that the ISR
intends to invoke an OS service. The actions taken when this service is invoked are specific to
the implementation and to the microcontroller targeted. Although this service should only be
called from a category 3 ISR, invoking the service from the task level or from a different ISR
level might or might not result in an error.
ErrorHook()
Prototype
void ErrorHook(StatusType error);
Inputs
Outputs
None.
ErrorHook()
Return
Status Description S E
None.
Function
This hook routine, if used, must be provided by the application and defined as available in the
OIL configuration file. The prototype for the routine in the application must be identical to
the prototype here. This hook routine is called by the OS whenever an API service is about to
return a status value other than E_OK to the application or an error occurs when an alarm
expires and a task is activated or an event is set. It is not called recursively if an error occurs
within an API service invoked from the hook routine. It is typically used in Extended Status
mode and is not included in the final release code.
GetActiveApplicationMode()
Prototype
GetActiveApplicationMode()
AppModeType GetActiveApplicationMode(void);
Inputs
None.
Outputs
None.
Return
This service returns the current APPMODE that was defined when the OS was started. This value
will be the exact value defined in the OIL configuration file.
Function
This service is typically used in applications that take different actions based on the current
APPMODE.
GetAlarm()
Prototype
StatusType GetAlarm(AlarmType alarmID, TickRefType tickRef);
Inputs
alarmID Name of the alarm that is to be checked. This is the alarm name exactly as it
appears in the OIL configuration file.
Outputs
tickRef Reference to a variable of type TickType into which the service places the remaining
GetAlarm()
counter ticks before the alarm expires. If this service returns the value E_OS_NOFUNC, then the
variable is undefined.
Return
Status Description S E
E_OS_ID The alarm is not a valid alarm. X
E_OS_NOFUNC The alarm is not presently used. This typically indicates X X
that the alarm has not been set or has already expired.
E_OK Service executed without error. X X
Function
This service checks the requested alarm to determine if it has been set and has not yet expired.
If this is true, it then sets the variable referred to by the parameter tickRef to the number of
counter ticks remaining before the alarm expires.
GetAlarmBase()
Prototype
StatusType GetAlarmBase(AlarmType alarmID, AlarmBaseRefType baseRef);
Inputs
alarmID Name of the alarm that is to be checked. This is the alarm name exactly as it
appears in the OIL configuration file.
GetAlarmBase()
Outputs
baseRef Reference to a structure of type AlarmBaseType into which the service places the
current characteristics of the alarm identified by the input alarmID.
Return
Status Description S E
E_OS_ID The alarm is not a valid alarm. X
E_OK Service executed without error. X X
Function
This service sets the values in the structure defined by baseRef to the current characteristics of
the alarm. The members of the structure follow.
ticksperbase The number of counter ticks required to reach a counter-specific unit. This
value is vaguely defined in the specification and is typically not used.
mincycle The smallest allowed value for the cycle parameter when setting the alarm.
GetConfig()
Prototype
StatusType GetConfig(NetIdType netID, ConfigRefType configRef,
ConfigKindName kind);
Inputs
kind The kind of configuration — either Normal, Normal Extended, or Limp Home. These
GetConfig()
types are typically replaced by a nonportable constant for the given implementation.
Outputs
configRef Reference to a variable of type ConfigType into which this service will place the
present configuration.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service obtains the current configuration of the type defined by the kind parameter and
places it in the variable defined by the configRef parameter. The constants chosen by the
individual implementations could affect portability of the application and should be encapsu-
lated in a single module that is easily changed. Normal Extended configuration is only avail-
able under indirect NM, and Limp Home configuration is only available under direct NM.
GetEvent()
Prototype
StatusType GetEvent(TaskType taskID, EventMaskRefType maskRef);
Inputs
taskID Name of the extended task that is to being queried. This is the task name exactly as
it appears in the OIL configuration file.
Outputs
maskRef Reference to a variable of type EventMaskType into which the current status of the
GetEvent()
events for the task is placed. This will be a logical OR of the event names as they appear in the
OIL configuration file.
Return
Status Description S E
E_OS_ID The task is not a valid task. X
E_OS_ACCESS The task is not an extended task. X
E_OS_STATE The task is in the SUSPENDED state. Events are X
not valid for tasks in the SUSPENDED state.
E_OK Service executed without error. X X
Function
The current status of all events for the task defined by the input taskID are placed in the vari-
able referenced by the eventRef input. The value placed here is the current state, either set or
cleared, and does not indicate whether the task is waiting for the event.
GetInterruptDescriptor()
Prototype
StatusType GetInterruptDescriptor(IntDescriptorRefType descRef);
GetInterruptDescriptor()
Inputs
None.
Outputs
descRef Reference to a variable of type IntDescriptorType into which the service places the
status of all interrupt sources. If a source is enabled, the corresponding bit is set to 1; other-
wise, it is set to 0.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service determines the status of all interrupt sources for the specific microcontroller. The
result is dependent on the target hardware and should only be used within target-specific rou-
tines, such as hardware device drivers.
GetMessageResource()
Prototype
StatusType GetMessageResource(SymbolicName message);
Inputs
GetMessageResource()
message Name of the message that is to be locked. This is the message name exactly as it
appears in the OIL configuration file.
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED The message is locked by the communication component. X X
E_COM_BUSY The message is already busy. X X
E_OK Service executed without error. X X
Function
This service sets the message object defined by the input message to Busy. This service is used
to limit access to a message whose Copy configuration has been defined as without-copy. If
the message is already busy, the application should not attempt to change the data in the mes-
sage object. It is recommended that ReleaseMessageResource() be invoked within the same
function as this service. The application also must release the resource before terminating the
task or entering the wait state whenever an OSEK/VDX-compliant OS is used.
GetMessageStatus()
Prototype
StatusType GetMessageStatus(SymbolicName message);
Inputs
message Name of the message that is to be checked. This is the message name exactly as it
GetMessageStatus()
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED The message is locked by the communication component. X X
E_COM_BUSY The message is busy. X X
E_COM_NOMSG The queue for a queued message is empty. X X
E_COM_LIMIT At least one queued message has been lost because of X X
a FIFO buffer overflow.
E_OK Service executed without error. X X
Function
This service returns the current status of the message.
GetResource()
Prototype
StatusType GetResource(ResourceType resID);
Inputs
resID Name of the resource that is to be locked. This is the resource name exactly as it
appears in the OIL configuration file. If this value is the constant RES_SCHEDULER, the system is
essentially operating in a non-preemptive mode.
GetResource()
Outputs
None.
Return
Status Description S E
E_OS_ID Requested resource is not a valid resource. X
E_OS_ACCESS The application has attempted to get a resource that X
is already locked.
E_OK Service executed without error. X X
Function
This service allows the application to lock a resource and to enter into a critical section that
will disable all other tasks that need access to the resource through the priority ceiling proto-
col. The corresponding call to ReleaseResource() should appear within the same function.
The resource must be released prior to the task being placed in either the SUSPENDED or the
WAITING state.
GetStatus()
Prototype
StatusType GetStatus(NetIdType netID, NetworkStatusType statusRef);
Inputs
netID Identifier of the communication network on which the status is to be reported. This is
the network name exactly as it appears in the OIL configuration file.
Outputs
GetStatus()
statusRef Reference to a variable of type NetworkStatusType into which the current status
of the network is placed.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service obtains the current status of the network and places it in the variable defined by
the statusRef parameter. The prototype for this function is misleading in that it appears that
the variable statusRef
is passed by value, when in fact, according to the specification, it should be passed by refer-
ence.
GetTaskID()
Prototype
StatusType GetTaskID(TaskRefType taskIDRef);
Inputs
None.
Outputs
taskIDRef Reference to a variable of type TaskType that contains the identifier of the task
that is currently running. If no task is running, the variable is set to INVALID_TASK.
GetTaskID()
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service provides the application with the identifier of the task that is presently running. It
is intended to be used in hook routines and library functions to check the task from which it
was invoked.
GetTaskState()
Prototype
StatusType GetTaskState(TaskType taskID, TaskStateRefType stateRef);
Inputs
taskID Name of the task that is to be checked. This is the task name exactly as it appears in
the OIL configuration file.
GetTaskState()
Outputs
stateRef Reference to a variable of type TaskStateType into which the service will place the
current state of the task identified by the input taskID. The value will be one of the following
constants: RUNNING, WAITING, READY, SUSPENDED.
Return
Status Description S E
E_OS_ID Input taskID is not a valid task. X
E_OK Service executed without error. X X
Function
This service identifies the current state of the task identified by the taskID parameter and
places this value into the variable referenced by stateRef. If this service is invoked by a task
that can be preempted, the result could be invalid by the time it is evaluated. In this case, it is
recommended that interrupts are disabled prior to invoking the service and until the result is
analyzed.
GotoMode()
Prototype
StatusType GotoMode(NetIdType netID, NMModeName mode);
Inputs
netID Identifier of the communication network on which the mode will change. This is the
network name exactly as it appears in the OIL configuration file.
mode The new operating mode, either BusSleep or Awake. These values can be replaced by
implementation-specific constants.
GotoMode()
Outputs
None.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service forces the NM component to either wake up or go to sleep.
InitCMaskTable()
Syntax
InitCMaskTable(NetIdType netID, ConfigKindName config, ConfigRefType cmask);
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
InitCMaskTable()
config The kind of configuration — either Normal, Normal Extended, or Limp Home.
Outputs
None.
Function
This directive initializes an element of the table of relevant configuration masks. The entries
in this table are used by SelectDeltaConfig().
InitCOM()
Prototype
StatusType InitCOM(void);
Inputs
None.
Outputs
None.
Return
InitCOM()
Status Description S E
E_OK Service executed without error. X X
Other Other Implementation-specific return values can be
returned if the service does not complete successfully.
Function
This service initializes all hardware and low-level resources that will be used by the COM
component. It is typically called before starting the OS or during OS startup. It might be pos-
sible to invoke this service from within an OS task, however, all interrupts must be masked
prior to invoking the service.
InitConfig()
Prototype
StatusType InitConfig(NetIdType netID);
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
InitConfig()
None.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service is used to instruct the NM component to reset the configuration of the network
to the default configuration and to restart configuration management. This service is only
functional if the NM component is operating in the NMNormal state. The default configuration
for direct NM is all nodes Absent from the network, and the default configuration for indirect
NM is all nodes Present on the network.
InitDirectNMParams()
Syntax
InitDirectNMParams(NetIdType netID, NodeIdType nodeId, TickType timerTyp,
TickType timerMax, TickType timerErr, TickType timerWBS,
TickType timerTx)
InitDirectNMParams()
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
Function
This directive initializes the parameters for a specific network that will operate in the direct
mode of network management. There will be one of these directives for each node in a con-
trol unit operating under direct NM.
InitIndDeltaConfig()
Syntax
InitIndDeltaConfig(NetIdType netID, ConfigKindName config, SignallingMode mode,
TaskRefType taskID, EventMaskType eventMask);
InitIndDeltaConfig()
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
config The kind of configuration — either Normal, Normal Extended, or Limp Home.
taskID Name of the task that is to be activated or which owns the event(s) to be set. This is
the task name exactly as it appears in the OIL configuration file.
eventMask Mask of the event or events to be set and associated with the task defined by the
previous parameter. This parameter is only valid if the mode parameter is set to Event.
Outputs
None.
Function
This directive is used to specify how changes in the configuration of the network are to be
indicated to the application. The signaling of the application occurs when the configuration
of the network changes as defined by SelectDeltaConfig().
InitIndDeltaStatus()
Syntax
InitIndDeltaStatus(NetIdType netID, SignallingMode mode, TaskRefType taskID,
EventMaskType eventMask);
InitIndDeltaStatus()
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
taskID Name of the task that is to be activated or that owns the event(s) to be set. This is
the task name exactly as it appears in the OIL configuration file.
eventMask Mask of the event or events to be set and associated with the task defined by the
previous parameter. This parameter is only valid if the mode parameter is set to Event.
Outputs
None.
Function
This directive specifies how changes in the status of the network are to be indicated to the
application. Application signaling occurs when the status of the network changes as defined
by SelectDeltaStatus().
InitIndirectNMParams()
Syntax
InitIndirectNMParams(NetIdType netID, NodeIdType nodeID, TickType timerTOB,
TickType timerErr, TickType timerWBS);
InitIndirectNMParams()
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None
Function
This directive initializes the parameters for a specific network that will operate in the indirect
mode of network management. There will be one of these directives for each node in a con-
trol unit that is operating under indirect NM.
InitIndRingData()
Syntax
InitIndRingData(NetIdType netID, SignallingMode mode, TaskRefType taskId,
EventMaskType eventMask);
Inputs
InitIndRingData()
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
taskID Name of the task to be activated or which owns the event(s) to be set. This is the
task name exactly as it appears in the OIL configuration file.
eventMask Mask of the event or events to be set and associated with the task defined by the
previous parameter. This parameter is only valid if the mode parameter is set to Event.
Outputs
None.
Function
This directive specifies how reception of a Ring message with data is to be indicated to the
application. Application signaling occurs when a Ring message is received by the local node.
InitNMScaling()
Syntax
InitNMScaling(NetIdType netID, ScalingParamType scaling)
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
InitNMScaling()
scaling Set of parameters used to scale the NM component for the particular network.
Outputs
None.
Function
This directive defines the scaling of the different parameters for the particular network man-
agement type on a given network. How this scaling is defined is specific to both a given imple-
mentation and the type of network management.
InitNMType()
Syntax
InitNMType(NetIdType netID, NMType type)
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
type The type of network management used on the network — either direct or indirect.
InitNMType()
Outputs
None.
Function
This directive defines the type of network management used for a given network. There will
be one of these directives for each of the networks connected to the controller. The type is
typically defined with a constant parameter. This parameter is not defined in the standard and
will probably vary between implementations.
InitSMaskTable()
Syntax
InitSMaskTable(NetIdType netID, StatusRefType smask);
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
InitSMaskTable()
Outputs
None.
Function
This directive initializes an element of the table of relevant status masks. The entries in this
table will be used by SelectDeltaStatus().
InitTargetConfigTable()
Syntax
InitTargetConfigTable(NetIdType netID, ConfigKindName config,
InitTargetConfigTable()
ConfigRefType target);
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
config The kind of configuration — can be Normal, Normal Extended, or Limp Home.
Outputs
None.
Function
This directive initializes an element of the table of relevant configuration targets. The entries
in this table are used by SelectDeltaConfig().
InitTargetStatusTable()
Syntax
InitTargetStatusTable(NetIdType netID, StatusRefType target);
InitTargetStatusTable()
Inputs
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
Function
This directive initializes an element of the table of relevant status targets. The entries in this
table are used by SelectDeltaStatus().
LeaveISR()
Prototype
void LeaveISR(void);
Inputs
None.
Outputs
None.
Return
LeaveISR()
Status Description S E
None X X
Function
This API service is the counterpart of EnterISR() and is invoked from a category 3 ISR to
inform the implementation that it has completed processing all API services. This must be the
last statement in a category 3 ISR and can be invoked only after EnterISR() has been
invoked. The API service might or might not return to the ISR, depending on the implementa-
tion.
MessageInit()
Prototype
StatusType MessageInit(void);
Inputs
None.
Outputs
None.
MessageInit()
Return
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This is a callback function provided by the application and is invoked by the communication
component from within StartCOM(). Many of the COM component API services indicate that
they cannot be called until after StartCOM() is called; these services cannot be used within this
function. The purpose of this callback function is to allow the application to initialize the
application-specific message objects.
PostTaskHook()
Prototype
void PostTaskHook(void);
Inputs
None.
Outputs
PostTaskHook()
None.
Return
Status Description S E
None
Function
This hook routine, if used, must be provided by the application and defined in the OIL config-
uration file as being available. The prototype for the routine in the application must be identi-
cal to the prototype here. This hook routine is called by the OS just after control of the CPU
has been taken from a task and just prior to the task transitioning from the RUNNING to the
READY, WAITING, or SUSPENDED state. Within this hook routine, the API service GetTaskID()
returns the identifier of the old task. This hook routine is typically used to benchmark the
application during development.
PreTaskHook()
Prototype
void PreTaskHook(void);
Inputs
None.
Outputs
None.
PreTaskHook()
Return
Status Description S E
None
Function
This hook routine, if used, must be provided by the application and defined in the OIL config-
uration file as being available. The prototype for the routine in the application must be identi-
cal to the prototype here. This hook routine is called by the OS after a task has transitioned
from the READY to the RUNNING state and just prior to giving the task control of the CPU.
Within this hook routine, GetTaskID() returns the identifier of the new task. This hook rou-
tine is typically used to benchmark the application during development.
ReadFlag()
Prototype
FlagValue ReadFlag(FlagType flag);
Inputs
flag The name of the flag that is to be read. This is the flag name exactly as it appears in the
OIL configuration file.
Outputs
None.
ReadFlag()
Return
Status Description S E
TRUE The conditions associated with the notification class to X X
which this flag has been assigned have been met.
FALSE The conditions associated with the notification class to X X
which this flag has been assigned have not been met since
the last time the flag was reset.
Function
This service queries the current state of the flag and returns whether the flag is set to TRUE or
FALSE. The interpretation of the meaning of a TRUE flag depends on the notification class to
which the flag is associated. If the conditions that would trigger that particular notification
class have been met, the flag is set to TRUE. The flag is only reset to FALSE by ResetFlag().
ReadRingData()
Prototype
StatusType ReadRingData(NetIdType netID, RingDataType ringRef);
Inputs
netID Identifier of the communication network that has received the Ring message. This is
the network name exactly as it appears in the OIL configuration file.
ReadRingData()
Outputs
ringRef Reference to a variable of type RingDataType into which the Ring data is placed.
Return
Status Description S E
E_OK Service executed without error. X X
E_NotOK Either the Ring data is not presently valid, or the X X
logical ring is not running in a stable state.
Function
This service obtains the Ring data that was received with the last valid Ring message and
places it in the variable referenced in the parameter list. This data can be read only while the
local node has control of the Ring message. The prototype for this function is misleading in
that it appears that the variable ringRef is passed by value, when in fact according to the
specification it should be passed by reference.
ReceiveDynamicMessage()
Prototype
StatusType ReceiveDynamicMessage(SymbolicName message, AccessNameRef dataRef,
ReceiveDynamicMessage()
LengthRef lengthRef);
Inputs
message Name of the message that is to be received. This is the message name exactly as it
appears in the OIL configuration file.
Outputs
dataRef Reference to the message data that is to be updated with the current data.
lengthRef Reference to a variable of type Length into which the length of the received mes-
sage is placed.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_OK Service executed without error. X X
Function
This service updates the data referenced by the input dataRef with the data from the message
object associated with the requested message. How this data is updated depends on whether
the message is accessed with- or without-copy. If the message is accessed with-copy, the data
reference is filled with the data from the message object. If the message is accessed without-
copy, no update of the data occurs because it already contains the proper data. The length of
the data received is placed in the variable referenced by lengthRef.
ReceiveMessage()
Prototype
StatusType ReceiveMessage(SymbolicName message, AccessNameRef dataRef);
Inputs
message Name of the message that is to be received. This is the message name exactly as it
appears in the OIL configuration file.
ReceiveMessage()
Outputs
dataRef Reference to the message data that is to be updated with the current data.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_COM_NOMSG The queue for a queued message is empty. X X
E_COM_LIMIT At least one queued message has been lost because X X
of a FIFO buffer overflow.
E_OK Service executed without error. X X
Function
This service updates the data referenced by the input dataRef with the data from the message
object associated with the requested message. How this data is updated depends on whether
the message is accessed with- or without-copy. If the message is accessed with-copy, the data
reference is filled with the data from the message object. If the message is accessed without-
copy, no update of the data occurs because it already contains the proper data. This function
cannot be invoked from an ISR if it is accessing a queued message.
Appendix C: OSEK/VDX API Reference 319
Specification/Conformance Class Usage
OS/COM Conformance Classes/Call Levels
BCC1 BCC2 ECC1 ECC2 TASK ISR
X X X X X X*
CCCA CCCB CCC0 CCC1 CCC2
X X X X X
ReceiveMessage()
Error Startup Shutdown PreTask PostTask
320 Appendix C: OSEK/VDX API Reference
ReceiveMessageFrom()
Prototype
StatusType ReceiveMessageFrom(SymbolicName message, AccessNameRef dataRef,
LengthRef lengthRef, AddressRef senderRef);
ReceiveMessageFrom()
Inputs
message Name of the message that is to be received. This is the message name exactly as it
appears in the OIL configuration file.
Outputs
dataRef Reference to the message data that is to be updated with the current data.
lengthRef Reference to a variable of type Length into which the length of the received mes-
sage is placed.
senderRef Reference to a variable of type Address into which the address of the sender of
the message is placed.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_OK Service executed without error. X X
Function
This service updates the data referenced by the input dataRef with the data from the message
object associated with the requested message. How this data is updated depends on whether
the message is accessed with- or without-copy. If the message is accessed with-copy, the data
reference is filled with the data from the message object. If the message is accessed without-
copy, no update of the data occurs because it already contains the proper data. The length of
the data received and the address of the sender of the data are placed in the variables refer-
enced by lengthRef and senderRef.
ReleaseMessageResource()
Prototype
StatusType ReleaseMessageResource(SymbolicName message);
ReleaseMessageResource()
Inputs
message Name of the message that is to be released. This is the message name exactly as it
appears in the OIL configuration file.
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_OK Service executed without error. X X
Function
This service sets the message object defined by the input message to NOT_BUSY and limits
access to a message whose copy configuration has been defined as without-copy. It is recom-
mended that GetMessageResource() be invoked within the same function as this service. It is
also required that the application release the resource before terminating the task or entering
the wait state whenever an OSEK/VDX-compliant OS is used.
ReleaseResource()
Prototype
StatusType ReleaseResource(ResourceType resID);
Inputs
resID Name of the resource that is to be unlocked. This is the resource name exactly as it
ReleaseResource()
Outputs
None.
Return
Status Description S E
E_OS_ID Requested resource is not a valid resource. X
E_OS_FUNC The application has attempted to release a resource X
that is not locked or another resource has to be
released first.
E_OS_ACCESS The application has attempted to release a resource X
that has a lower ceiling priority than the statically
assigned priority of the task or ISR that invoked the
service.
E_OK Service executed without error. X X
Function
This service allows the application to unlock a resource and to leave a critical section. The
priority ceiling protocol returns the task that contains the critical section to the statically
assigned priority. The corresponding call to GetResource() should appear within the same
function. The resource must be released prior to the task being placed in either the SUSPENDED
or the WAITING state.
ResetFlag()
Prototype
StatusType ResetFlag(FlagType flag);
Inputs
flag The name of the flag that is to be reset. This is the flag name exactly as it appears in the
OIL configuration file.
Outputs
None.
ResetFlag()
Return
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This service resets the state of the flag to FALSE.
ResumeOSInterrupts()
Prototype
void ResumeOSInterrupts(void);
Inputs
ResumeOSInterrupts()
None.
Outputs
None.
Return
Status Description S E
None X X
Function
This API service enables OS interrupts that were enabled prior to the most recent invocation
of SuspendOSInterrupts() and identifies the end of a critical section. OS interrupts are
defined as any interrupts that are serviced by a category 2 or 3 ISR. Within the critical sec-
tion, no API service calls are allowed except nested calls to SuspendOSInterrupts() and
ResumeOSInterrupts(). If a matching SuspendOSInterrupts() call is not found, the action
taken is undefined by the specification. How the OS interrupts are enabled will differ between
implementations and between microcontrollers. However, the effect to the application will be
the same.
Schedule()
Prototype
StatusType Schedule(void);
Inputs
None.
Outputs
None.
Return
Schedule()
Status Description S E
E_OS_CALLEVEL Service was called from the interrupt level. X
E_OK Service executed without error. X X
Function
This service is used in non-preemptive tasks to allow cooperative multitasking by forcing the
scheduler to run a higher priority task if there is one in the READY state. Although it is possible
to call this service from a full-preemptive task, no action is taken.
SelectDeltaConfig()
Prototype
StatusType SelectDeltaConfig(NetIdType netID, ConfigKindName kind,
ConfigHandleType hConfig, ConfigHandleType hCmask);
Inputs
SelectDeltaConfig()
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
kind The kind of configuration — can be Normal, Normal Extended, or Limp Home. These
types will typically be replaced by a constant for the given implementation.
hConfig Handle to a target configuration that was previously defined by the directive Init-
TargetConfigTable().
hCmask Handle to a configuration mask that was previously defined by the directive InitC-
MaskTable().
Outputs
None.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service selects a combination of nodes on the network to be monitored and a target con-
figuration for those nodes. When any of the nodes that are being monitored meets the target
configuration, the application is signaled that a configuration has changed.
SelectDeltaStatus()
Prototype
StatusType SelectDeltaStatus(NetIdType netID, StatusHandleType hStatus,
StatusHandleType hSmask);
Inputs
SelectDeltaStatus()
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
hStatus Handle to a target status that was previously defined by the directive InitTarget-
StatusTable().
hSmask Handle to a status mask that was previously defined by the directive InitSMaskTa-
ble().
Outputs
None.
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service selects a target network status and a status mask that will be used to trigger an
indication back to the application when the status changes. When any of the monitored net-
work status values meet the target status, the application is notified.
SelectHWRoutines()
Syntax
SelectHWRoutines(NetIdType netID, RoutineRefType busInit,
RoutineRefType busAwake, RoutineRefType busSleep,
RoutineRefType busRestart, RoutineRefType busShutDwn)
Inputs
SelectHWRoutines()
netID Identifier of the communication network to be initialized. This is the network name
exactly as it appears in the OIL configuration file.
busInit Routine to be invoked when the bus needs to be initialized. It is called once when
the network is started.
busAwake Routine to be invoked when the bus leaves the power-down mode.
busSleep Routine to be invoked when the bus enters the power-down mode.
busRestart Routine to be invoked to restart the bus hardware in the case of a fatal bus
error.
Outputs
None.
Function
This directive defines the set of routines that will be used by the network management com-
ponent to control the hardware.
SendDynamicMessage()
Prototype
StatusType SendDynamicMessage(SymbolicName message, AccessNameRef dataRef,
LengthRef lengthRef);
SendDynamicMessage()
Inputs
message Name of the message that is to be sent. This is the message name exactly as it
appears in the OIL configuration file.
lengthRef Reference to a variable of type Length that contains the length of the message to
be sent.
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_OK Service executed without error. X X
Function
This service updates the message object associated with the requested message with the data
referenced by the input dataRef. How this message object is updated depends on whether the
message is accessed with- or without-copy. If the message is accessed with-copy, the data ref-
erence is copied to the message object. If the message is accessed without-copy, no update of
the message object occurs because it already contains the proper data. After the data has been
copied, if necessary, the COM component requests the transmission of the message depending
on the transmission mode specified. The input length is sent to the lower layers of the COM
component to format the network messages.
SendMessage()
Prototype
StatusType SendMessage(SymbolicName message, AccessNameRef dataRef);
Inputs
message Name of the message that is to be sent. This is the message name exactly as it
appears in the OIL configuration file.
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_OK Service executed without error. X X
Function
This service updates the message object associated with the requested message with the data
referenced by the input dataRef. How this message object is updated depends on whether the
message is accessed with- or without-copy. If the message is accessed with-copy, the data ref-
erence is copied to the message object. If the message is accessed without-copy, no update of
the message object occurs because it already contains the proper data. After the data has been
copied, if necessary, the COM component requests the transmission of the message depending
on the transmission mode specified. This function cannot be invoked from an ISR if it is
accessing a queued message.
Appendix C: OSEK/VDX API Reference 331
Specification/Conformance Class Usage
OS/COM Conformance Classes/Call Levels
BCC1 BCC2 ECC1 ECC2 TASK ISR
X X X X X X*
CCCA CCCB CCC0 CCC1 CCC2
X X X X X
SendMessage()
332 Appendix C: OSEK/VDX API Reference
SendMessageTo()
Prototype
StatusType SendMessageTo(SymbolicName message, AccessNameRef dataRef,
LengthRef lengthRef, AddressRef addressRef);
Inputs
message Name of the message that is to be sent. This is the message name exactly as it
appears in the OIL configuration file.
SendMessageTo()
lengthRef Reference to a variable of type Length that contains the length of the message to
be sent.
addressRef Reference to a variable of type Address that contains the address of the recipient
of the message.
Outputs
None.
Return
Status Description S E
E_COM_ID The message is not a valid message. X
E_COM_LOCKED Either the message is locked by the communication X X
component or a with-copy message is set to Busy.
E_OK Service executed without error. X X
Function
This service updates the message object associated with the requested message with the data
referenced by the input dataRef. How this message object is updated depends on whether the
message is accessed with- or without-copy. If the message is accessed with-copy, the data ref-
erence is copied to the message object. If the message is accessed without-copy, no update of
the message object occurs because it already contains the proper data. After the data has been
copied, if necessary, the COM component requests the transmission of the message depending
on the transmission mode specified. The length and address inputs are sent to the lower layers
of the COM component that format the network messages.
SetAbsAlarm()
Prototype
StatusType SetAbsAlarm(AlarmType alarmID, TickType start, TickType cycle);
Inputs
alarmID Name of the alarm that is to be set. This is the alarm name exactly as it appears in
the OIL configuration file.
start The absolute value in counter ticks at which the alarm is to expire the first time.
SetAbsAlarm()
cycle If this input is not 0, then the alarm is a cyclic alarm with cycle ticks.
Outputs
None.
Return
Status Description S E
E_OS_ID The alarm is not a valid alarm. X
E_OS_VALUE Either the value of the input start is less than 0 or X
greater than the alarm base value maxallowedvalue,
or the input cycle is less than mincycle or greater
than maxallowedvalue.
E_OS_STATE The alarm has previously been set and has not expired X X
prior to a second attempt to set the alarm.
E_OK Service executed without error. X X
Function
This service sets an alarm to expire at an absolute value of the counter to which it is assigned.
When the counter reaches the value defined by the input start, the alarm expires. If the
counter has already passed the value defined by start, the alarm expires only after the
counter rolls over one time. If the counter is very close to the start value, the counter can
expire prior to the OS returning from this service. Typically, this service is not used for a time-
based alarm, but only for an alarm based on a position input, such as an engine crank angle.
A cyclic alarm is defined if the input cycle is not equal to 0. When the alarm expires, the
value of the input cycle is added to the current alarm value and used as the next set point at
which to expire. If the alarm is currently in use, this service fails. To restart an alarm that is
currently in use, first invoke CancelAlarm().
334 Appendix C: OSEK/VDX API Reference
SetEvent()
Prototype
StatusType SetEvent(TaskType taskID, EventMaskType mask);
Inputs
taskID Name of the task that owns the event(s). This is the task name exactly as it appears
in the OIL configuration file.
mask Event mask of the events that are to be set. This is a logical OR of the event names as
they appear in the OIL configuration file.
SetEvent()
Outputs
None.
Return
Status Description S E
E_OS_ID The task is not a valid task. X
E_OS_ACCESS The task is not an extended task. X
E_OS_STATE The task is in the SUSPENDED state. Events cannot X
be set for tasks in the SUSPENDED state.
E_OK Service executed without error. X X
Function
The events defined by the input mask are set for the task defined by the input taskID. Multiple
events can be set for a given task with one call to this service. If the task is in the WAITING
state, and is waiting on one of the events that is set, the OS will move the task into the READY
state. If the task is in the READY state, the event is set but no action occurs for that task until it
runs again and invokes WaitEvent() with one of these events set. At that time, the task does
not enter the WAITING state because the event is already set.
SetRelAlarm()
Prototype
StatusType SetRelAlarm(AlarmType alarmID, TickType increment, TickType cycle);
Inputs
alarmID Name of the alarm that is to be set. This is the alarm name exactly as it appears in
the OIL configuration file.
increment The incremental value in counter ticks relative to the current counter value at
SetRelAlarm()
cycle If this input is not 0, then the alarm is a cyclic alarm with cycle ticks.
Outputs
None.
Return
Status Description S E
E_OS_ID The alarm is not a valid alarm. X
E_OS_VALUE Either the value of the input increment is less than 0 X
or greater than the alarm base value maxallowedvalue,
or the input cycle is less than mincycle or greater
than maxallowedvalue.
E_OS_STATE The alarm has previously been set and has not expired X X
prior to a second attempt to set the alarm.
E_OK Service executed without error. X X
Function
This service sets an alarm to expire at an incremental value of the counter to which it is
assigned. When the counter reaches the value defined by the input increment plus the current
value of the counter, the alarm expires. Typically, this service is used for a time-based alarm to
set the next time that an action, such as a periodic task, would occur. A cyclic alarm is defined
if the input cycle is not equal to 0. When the alarm expires, the value of the input cycle is
added to the current alarm value and used as the next set point at which to expire. If the
alarm is currently in use, this service will fail. To restart an alarm that is currently in use, first
invoke CancelAlarm().
Appendix C: OSEK/VDX API Reference 337
Specification/Conformance Class Usage
OS Conformance Classes/Call Levels
BCC1 BCC2 ECC1 ECC2 TASK ISR
X X X X X X
SetRelAlarm()
338 Appendix C: OSEK/VDX API Reference
ShutdownHook()
Prototype
void ShutdownHook(StatusType error);
Inputs
Outputs
ShutdownHook()
None.
Return
Status Description S E
None
Function
This hook routine, if used, must be provided by the application and defined in the OIL config-
uration file as being available. The prototype for the routine in the application must be identi-
cal to the prototype here. This hook routine is called by the OS after ShutdownOS() is
invoked. If the OS is being shutdown because of an error detected by the OS, the error
parameter will never be E_OK. This hook routine is not required to return to the OS unless
both an OSEK/VDX OS and an OSEKTime OS coexist. Consequently, if the error is critical
enough, it is possible for the application running in only an OSEK/VDX OS environment to
force the application hardware to reset and attempt to resolve the issue.
ShutdownOS()
Prototype
void ShutdownOS(StatusType error);
Inputs
error This is the error value that is passed to the ShutdownHook() hook routine.
Outputs
None.
ShutdownOS()
Return
Status Description S E
None
Function
This service can be called by an application to abort the OS function. Typically, this service is
used by an application to switch APPMODEs or to indicate that a critical error has occurred and
the system will need to be reset. While processing this service, the implementation calls the
ShutdownHook() hook routine if it exists. If this hook routine returns, the resulting behavior is
implementation specific. In most implementations, it will cause the system to return to the
point in the application immediately after the call to StartOS().
SilentNM()
Prototype
StatusType SilentNM(NetIdType netID);
Inputs
netID Identifier of the communication network to be silenced. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
SilentNM()
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service disables participation of the node in the network defined by the parameter. When
invoked, this service forces network management to transition from the NMActive state to the
NMPassive state.
StartCOM()
Prototype
StatusType StartCOM(void);
Inputs
None.
Outputs
None.
Return
StartCOM()
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This service initializes all implementation-specific internal states, variables, and resources. If
the callback function MessageInit() exists, it is invoked to initialize application-specific mes-
sages. On completion, the communication component is fully functional and ready to trans-
mit and receive messages. If an OSEK/VDX-compliant OS is used, this service must be
invoked from within a task.
StartNM()
Prototype
StatusType StartNM(NetIdType netID);
Inputs
netID Identifier of the communication network to be started. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
StartNM()
Return
Status Description S E
E_OK Service executed without error. X X
Function
This service starts network management on the network defined by the parameter. When
invoked, this service forces network management to transition from the NMOff to the NMOn
state.
StartOS()
Prototype
void StartOS(AppModeType mode);
Inputs
Outputs
None.
Return
StartOS()
Status Description S E
None
Function
This service is only allowed to be invoked outside of the OS. It starts the OS after the applica-
tion hardware has been initialized. There may be implementation-specific restrictions that
apply to how the OS starts or what must be done before starting the system. Although the
specification indicates that this call does not need to return, most implementations will return
after the OS has been shutdown. While processing this service, the implementation calls the
StartupHook() hook routine if it exists.
StartPeriodical()
Prototype
StatusType StartPeriodical(void);
Inputs
None.
StartPeriodical()
Outputs
None.
Return
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This API service initiates the periodic transmission of messages that are defined as either peri-
odic or mixed transmission mode messages. It also restarts the periodic transmission of these
messages after they have been stopped by StopPeriodical().
StartupHook()
Prototype
void StartupHook(void);
Inputs
None.
Outputs
None.
StartupHook()
Return
Status Description S E
None
Function
This hook routine, if used, must be provided by the application and defined in the OIL config-
uration file as being available. The prototype for the routine in the application must be identi-
cal to the prototype here. This hook routine is called by the OS after the system has been
initialized and just prior to running the scheduler the first time after StartOS() has been
invoked. The application can use this hook routine to initialize device drivers, start tasks
based on the APPMODE that is active, or provide other application-specific initialization.
StopCOM()
Prototype
StatusType StopCOM(Scalar mode);
Inputs
mode This value determines how the system is shut down. At this time, the only required
value in the standard is COM_SHUTDOWN_IMMEDIATE, in which case communication is shut down
immediately and all pending communication is aborted. Other values can be supported by
individual implementations.
Outputs
StopCOM()
None.
Return
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This service releases all resources used by COM and ceases all activity. It will not return until
all pending COM operations are completed or successfully aborted and their resources can be
released. On completion, the COM component is in a state where StartCOM() can be called to
restart the component. If an OSEK/VDX-compliant OS is used, this service must be invoked
from within a task. This service typically puts a network bus to sleep when it is not required.
StopNM()
Prototype
StatusType StopNM(NetIdType netID);
Inputs
netID Identifier of the communication network to be stopped. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
Return
StopNM()
Status Description S E
E_OK Service executed without error. X X
Function
This service stops network management on the network defined by the parameter. When
invoked, this service forces network management to transition from the NMOn to the NMShut-
Down state. After all of the activities related to shutting down the network occur, the NM com-
ponent transitions into the NMOff state.
StopPeriodical()
Prototype
StatusType StopPeriodical(void);
Inputs
None.
Outputs
StopPeriodical()
None.
Return
Status Description S E
E_OK Service executed without error. X X
Other Other implementation-specific return values can be
returned if the service does not complete successfully.
Function
This API service cancels the periodic transmission of messages that are defined as either peri-
odic or mixed transmission mode messages.
SuspendOSInterrupts()
Prototype
void SuspendOSInterrupts(void);
Inputs
SuspendOSInterrupts()
None.
Outputs
None.
Return
Status Description S E
None X X
Function
This API service saves the current state of OS interrupts and then disables them. It identifies
the start of a critical section. OS interrupts are defined as any interrupts that are serviced by
an ISR of category 2 or 3. Within the critical section, no API service calls are allowed except
nested calls to SuspendOSInterrupts() and ResumeOSInterrupts(). How the OS interrupts
are disabled differs between implementations and between microcontrollers. However, the
effect to the application will be the same.
TalkNM()
Prototype
StatusType TalkNM(NetIdType netID);
Inputs
netID Identifier of the communication network to be changed. This is the network name
exactly as it appears in the OIL configuration file.
Outputs
None.
Return
TalkNM()
Status Description S E
E_OK Service executed without error. X X
Function
This service enables participation of the node in the network defined by the parameter. When
invoked, this service forces network management to transition from the NMPassive to the
NMActive state.
TerminateTask()
Prototype
StatusType TerminateTask(void);
Inputs
None.
Outputs
TerminateTask()
None.
Return
Status Description S E
E_OS_RESOURCE Invoking task still occupies resources and termination X
is not safe.
E_OS_CALLEVEL Service was invoked from the interrupt level. X
E_OK Service executed without error. X X
Function
This function terminates the task that invoked the service, transferring it from the RUNNING to
the SUSPENDED state. The service then forces a rescheduling of the application. All resources
locked by the invoking task must be released using ReleaseResource() prior to invoking this
service. This service only returns in the extended status state when an error occurs. All tasks
must end with either TerminateTask() or ChainTask().
TransmitRingData()
Prototype
StatusType TransmitRingData(NetIdType netID, RingDataType ringRef);
Inputs
netID Identifier of the communication network that has received the Ring message. This is
TransmitRingData()
ringRef Reference to data to be placed in the data field of the Ring message when it is
passed to the next consecutive node.
Outputs
None.
Return
Status Description S E
E_OK Service executed without error. X X
E_NotOK Either the Ring data is not presently valid, or the X X
logical ring is not running in a stable state.
Function
This service places the Ring data into the data field of the Ring message. This data can be
updated only when the local node has control of the Ring message. The prototype for this
function is misleading in that it appears that a variable is passed by value, when in fact,
according to the specification, it should be passed by reference.
WaitEvent()
Prototype
StatusType WaitEvent(EventMaskType mask);
Inputs
mask Event mask of the events to be waited for. This is a logical OR of the event names as
they appear in the OIL configuration file.
Outputs
None.
WaitEvent()
Return
Status Description S E
E_OS_ACCESS Service was not invoked from an extended task. X
E_OS_RESOURCE The extended task from which the service was X
invoked still has resources locked.
E_OS_CALLEVEL Service was invoked on the interrupt level. X
E_OK Service executed without error. X X
Function
This service checks the status of all of the events defined by the input value mask. If any of the
events are set, the service immediately returns; otherwise, the service puts the extended task
into the WAITING state and invokes the scheduler. The service can only be invoked from the
extended task that owns the events.
354 Appendix C: OSEK/VDX API Reference
355
356 Index
I InitIndDeltaConfig() 302 M
InitIndDeltaStatus 227
implementation main() 9–10, 12, 20, 25, 27–28
InitIndDeltaStatus() 303
choosing 9 _MEMORY_BASE_ADDR 12
InitIndirectNMParams 249,
startup 10 _MEMORY_MAP 12
251
IncomingMessage 208 MessageInit() 188, 312
InitIndirectNMParams() 304
IncrCounter() 54, 63 defined 111, 152
InitIndRingConfig 227, 249
Indirect network management messages 103
InitIndRingData 238
245 1:1 131
InitIndRingData() 305
configuration management 1:many 131
InitNMScaling() 306
Normal 249–250 accessor 106
InitNMType() 307
Normal Extended 249– advanced external 197
InitOS task 222
250, 254 external 128, 173
InitOS() 109, 150, 153
extended configuration initialization 111, 152
InitRAM() 12, 19
thresholds 254 internal 128, 148
InitReg16() 12–13, 19
Master-Slave sleep 255 internal–external 128
InitReg16ListType 19
message monitoring 251 length 130
InitReg32() 12–13, 20
states local copy 133
InitShuffleSwitch() 54
NMAwake 247–248 queued 130, 164
InitSMaskTable 227
NMBusSleep 247, 255 resource locking 168
InitSMaskTable() 308
NMLimpHome 248, 251 segmented 131
InitSPR() 12, 19
NMNormal 248–249, 255 sending
InitSystem() 13, 20, 26–27, 54
NMOff 246 direct 179
InitTargetConfigTable 227
NMOn 246–248 mixed 193
InitTargetConfigTable() 309
NMWaitBusSleep 248, periodic 188
InitTargetStatusTable 227
255 unqueued 130, 155
InitTargetStatusTable() 310
timeouts unsegmented 131
InitType 20
individual 252 with-copy 104, 132
interaction layer 147
single 252 without-copy 104, 107, 132
internal communication 147
TOB 251 mixed transmission mode 135,
interprocess communication 103
TWaitBusSleep 255 192
interrupt 93
INIT_RESET 14 Motorola Embedded Application
INVALID_TASK 44
INIT_SHUTDOWN 27 Binary Interface 12
IOSampleKeypad 35, 37, 57, 166
INIT_STARTUP 26 mutex 81
IOSampleShuffleSwitch 54, 74
InitAlarms 58
IOShuffleSwitchISR 94
InitCMaskTable 227, 249
InitCMaskTable() 298
ISO seven-layer model 126 N
ISO-17356 256 network 147
InitCOM() 150, 299
ISR network address information 198
defined 108, 149
categories 93 Network Management
InitConfig() 232, 251, 300
declaration 95 Overview 215
InitCounter() 54
InitDirectNMParams 227, 249 Network management
InitDirectNMParams() 301 L direct 219
InitFunctionList 20 indirect 245
LeaveISR() 93, 311
initialization Network management protocol
defined 94
application 13 data unit 232
Limp Home message 220
registers 10, 13 network protocol control
InitIndDeltaConfig 227 information 198
358 Index
network protocol data unit 198 MAXALLOWEDVALUE 53 ACCESSOR 40, 106, 132,
NMPDU 232 MINCYCLE 53 158
data field 233 TICKSPERBASE 53 ACTIVATION 40
destination node identifier CPU 16 AUTOSTART 34, 40
232, 234 EVENT 71 EVENT 40, 71
ID base 234 MASK 71 PRIORITY 40
message types 233 ISR 96 RESOURCE 40, 88
opcode 233–234 ACCESSOR 96 SCHEDULE 40
source node identifier 232, CATEGORY 96 SCHEDULE_CALL 41
234 RESOURCE 96 STACKSIZE 41
window mask 234 MESSAGE 104 TYPE 41
Notification classes ACCESSNAMES 160 OpponentMessageReceived 208
message reception 104 ACTION 106, 160 OS
notification mechanism ALIGNMENT 130 shutting down 26
callback routine 104 CDATATYPE 106, 130, 160 starting 25, 100
event 104 LENGTH 130, 136 OSEK run-time interface 256
flag 104 QUEUE_SIZE 130 OSEKTime 256
task 104 QUEUED 130 OSMAXALLOWEDVALUE 64
notification mechanisms RECEPTION_DEADLINE_ OSMINCYCLE 64
flag MONITOR 137 OSTICKDURATION 64
interpretation 191 RX_NOTIFICATION 160 OSTICKSPERBASE 64
NPCI 198 RX_SUCCESS_EVENT 160 OutputDisplayBuffer 118
first frame 201 RX_SUCCESS_TASK 160 OutputNewDisplay() 43, 99
flow control 202 TRANSMISSION 134
Clear-to-Send 202 TX_DEADLINE_ALARM 137
Wait 202 TX_DEADLINE_TIME 137 P
single frame 200 TX_NOTIFICATION 137 PackDisplay() 43, 115, 157
NPDU 198 TYPE 104, 128, 130 periodic transmission mode 134,
consecutive frame 199 NM 225 186
first frame 198, 202 BUSSLEEP_TIMEOUT 242 PostTaskHook() 313
flow control 199, 203 LIMPHOME_TIMEOUT 241 defined 31
single frame 198, 200 NM_NETWORK 226 preemption 38
NM_TASK 226 PreTaskHook() 314
RETRANSMIT_TIMEOUT 235 defined 31
O RING_DELAY 235 priority 36
OIL 14 RX_TIMEOUT 237 highest 37
MESSAGE TX_LIMIT 235 lowest 37
USAGE 128 TYPE 226 priority ceiling protocol 36, 84
ALARM 137 OS 16 priority inversion 81
ACTION 57 ERRORHOOK 18 ProcessKeyPress 43, 61, 70,
COUNTER 57 POSTTASKHOOK 18 167, 179, 183, 206
APPMODE 16, 24 PRETASKHOOK 18
CANADDRESS SHUTDOWNHOOK 18
MESSAGE_ID 178 STARTUPHOOK 18 R
NETWORK 178 STATUS 18 ReadFlag() 190, 315
TYPE 178 RESOURCE 16, 87 ReadRingData() 239, 316
COUNTER 16 TASK 17 ReceiveDynamicMessage() 317
Index 359
EmbeddedSystems
®
P R O G R A M M I N G
MicroC/OS-II
The Real-Time Kernel
by Jean J. Labrosse
“This document is an official release and replaces all previously distributed documents.
The OSEK group retains the right to make changes to this document without notice and
does not accept any liability for errors. All rights reserved. No part of this document may
be reproduced, in any form or by any means, without permission in writing from the
OSEK/VDX steering committee.”