Platform Abstraction Layer
The PAL, or Platform Abstraction Layer, enables the STRIDE Runtime to be platform-independent by providing a consistent interface for the STRIDE Runtime regardless of the operating system or data transport used. This interface layer is necessary given the broad variety of operating systems and data transports that exist within embedded systems today.
A small set of functions, written according to the PAL specification, provide the interfaces between your operating system and platform transport mechanism to the STRIDE Runtime. Through the PAL, the STRIDE Runtime becomes independent of any specific platform. The PAL is designed to use standard concepts and services present in almost all operating systems and transport mechanisms. To complete a PAL, you’ll need to be familiar with concepts such as event signaling, scheduling, timers, critical section protection, memory allocation and data transfers.
The pal.h header file provided with the STRIDE Runtime contains all the function prototypes necessary for writing the PAL.
STRIDE provides fully functional implementations of the PAL for several major platforms (Windows, Linux, FreeBSD, etc.).
For a detailed description of the PAL and its interfaces, see the Platform Abstraction Layer description and the STRIDE Platform Abstraction Layer (PAL) Specification.
This section describes the basic concepts of the PAL and the system services it must provide.
Typically, the STRIDE Runtime calls PAL functions; however, there are some functions in the STRIDE Runtime that need to be called by the PAL. To eliminate PAL dependencies on the STRIDE Runtime, these functions are accessed through a function registration process initiated by the STRIDE Runtime at startup. You write the registration routine called by the Runtime. This registration routine passes in the address of the STRIDE Runtime function to be registered as the input parameter, and stores the address of the STRIDE Runtime function in your own function variable, which is actually a pointer to a function. You can then call the registered function using your function pointer variable.
The registered STRIDE Runtime functions allow you to complete such tasks as delivering a received I block to the Runtime, checking the number of I-blocks the Runtime has ready to send out, or signalling the Runtime that your transport is ready for the next I-block. It is not necessary for the PAL to know the details of these Runtime functions.
Task Synchronization / Event Notification
Unique information is required by an operating system to notify a thread of a pending event. This information can be a native OS thread id, a simple index into a table, an address to a thread control block, the address of a semaphore or one of a number of other implementations. Although each implementation may be different, a unique notifier is necessary for each thread. The STRIDE Runtime calls this unique information a Notification Identifier (NID). A thread uses a NID when waiting for a STRIDE event, and the STRIDE Runtime uses the same NID to notify the thread of a pending STRIDE event.
Support for sharing of the synchronization object among multiple applications should be ensured in case of multi-process target is enabled.
Protection using Mutex
The STRIDE Runtime needs to protect critical and shared data structures from multiple, simultaneous accesses by multiple threads and, in case of multi-process target is enabled, by multiple applications. The PAL requires implementing protection using Mutexes that can be created and, in case of multi-process target is enabled, used with a unique name by any STRIDE Runtime module or PAL itself. The STRIDE Runtime guarantees that calls to palMutexLock() will not be nested.
The STRIDE Runtime requires that at least one timer be available. When a timer is created, a callback is registered so that the STRIDE Runtime can be notified of timer expirations. A user parameter, provided when the timer is created, is passed to the callback when it gets called. If several timers share a callback routine, this user parameter can be used to identify which timer expired. The STRIDE Runtime can also stop, start and delete timers.
Because the STRIDE Runtime also has the need to timestamp trace log data, a routine that returns the system time, palGetTime(), is also part of the PAL. This routine is not associated with timers.
The STRIDE Runtime dynamically allocates memory for messages and trace log storage. The Runtime uses palMemAlloc() and palMemFree() to allocate memory dynamically and then return it to the system.
The Runtime uses palMemSegmentOpen() and palMemSegmentClose() to create, open and close memory segments. In case of single process target, these routines can simply allocate dynamic memory as in normal memory allocation routines.
To support multi-process target, the STRIDE Runtime requires dynamic and configurable memory allocated through palMemAlloc() and static internal memory allocated directly through palMemSegmentOpen() to be shared memory.
In case of multi-process target, palMemAlloc() and palMemFree() routines can simply use the STRIDE Runtime’s Memory Management module srMem, which is in turn dependent on palMemSegmentOpen() and palMemSegmentClose() routines.
The PAL transport routines are needed to transfer I-blocks (STRIDE data packets) into and out of the STRIDE Runtime on your target platform. These routines handle the buffering and transferring of data to and from your transport mechanism. The PAL also contains registration routines that allow for STRIDE Runtime routines to be called by the PAL.
The palOut() routine enables the STRIDE Runtime to transfer I-blocks to your transport. The STRIDE Runtime calls the palOut() routine whenever it needs to send out an I-block.
Your transport calls the routine registered with the palOutRdyReg() routine when the transport is ready for the next I-block to be transmitted. The STRIDE Runtime will not call the palOut() routine until you call the registered function. In this way, you can control the flow of transmitted I-blocks. When a complete I-block has been received by your transport, the routine registered with the palInReg() routine should be called to put the received I-block into the STRIDE Runtime.
In some cases it is useful to know when the transmit path is not being requested. Your transport mechanism can check the number of I-blocks the STRIDE Runtime has ready for transmission by calling the routine registered with the palOutPndReg() routine.
This section explains the two categories of PAL services that support the STRIDE Runtime, as well as the files used to implement these services on your target. The pal.h header file provided with the STRIDE installation contains all the function prototypes.
The PAL services include the following:
- Operating System (OS) Services
- Input/Output (IO) Services
PAL Operating System Services
The PAL Operating System (OS) Services are the routines that enable the STRIDE Runtime to work with the operating system on your target platform. In order to write your PAL OS services you must have detailed knowledge of how your operating system handles thread synchronization, timers, mutexes, dynamic memory, shared memory, and notification. The PAL OS services make the features of your operating system available to the STRIDE Runtime.
|palCreateNID||Create a Notification Identifier (NID)|
|palDeleteNID||Delete a Notification Identifier (NID)|
|palCreateRFCProxyNID||Create the RFC Proxy Notification Identifier (NID)|
|palDeleteRFCProxyNID||Delete the RFC Proxy Notification Identifier (NID)|
|palWait||Wait for an event|
|palNotify||Signal a thread that an event is pending|
|palGetThreadId||Return current thread Id|
|palGetProcessId||Return current process Id|
|palSleep||Suspend the execution of the current thread|
|palCreateTimer||Create a timer|
|palDeleteTimer||Delete a timer|
|palStartTimer||Start a timer|
|palStopTimer||Stop a timer|
|palGetTime||Return system time (e.g., tick count)|
|palMutexInit||Initialize a mutex object|
|palMutexDestroy||Destroy a mutex object|
|palMutexLock||Lock a mutex object|
|palMutexUnlock||Unlock a mutex object|
|palMemAlloc||Allocate a block of dynamic memory|
|palMemFree||Free a block of dynamic memory|
|palMemSegmentOpen||Create/open memory segments|
|palMemSegmentClose||Close memory segments|
PAL Input/Output Services
The PAL Input/Output (IO) Services are the routines that enable the STRIDE Runtime to work with different data transport mechanisms. These routines enable your transport to send and receive data between the host and the target.
The IO services have also been defined to allow the target platform to control how memory is managed and the rate of data exchange.
|palOutPndReg||Registers a callback to query the current output queue of the Runtime|
|palOutRdyReg||Registers a callback to identify the transport as ready to receive data|
|palOut||Send data to the host platform|
|palInReg||Registers a callback to process the data extracted from the transport and identified for the STRIDE Runtime|
Integrating the PAL
PAL Operating System (OS) Services
The PAL OS Services provide the glue between the STRIDE Runtime and the Target Operating System. The services it must provide are:
- Task protection and synchronization (e.g. mutexes)
- Periodic Timers
- Get Time Stamp
- Memory Management
By convention, these services are implemented in a file called palOS.c.
PAL Transport (I/O) Services
The PAL Transport Services implement the target peer of the I/O services between the Host and Target. By convention, these services are implemented in a file called palIO.c.
The pre-packaged PALs below provide both a Serial and a TCP/IP transport.
- What about USB?
- S2 does not yet provide a native USB transport. If you wish to use one of our prepackaged transports, then the USB can either be used to emulate a serial (COM) port, or can be used with TCP/IP by installing and using USBNet. USBNet is open software for Linux and Windows that permits TCP/IP connections over USB. Google "USBNet" to locate a driver for your systems.
- What if I need a custom transport?
- A custom transport can be implemented. Your PAL implementation will need to implement the target side of the custom communication.
PAL Resource Requirements
Most PALs require a reader task to monitor the Transport input data stream.
PAL memory usage is limited to a few dozen bytes for table and control block storage. The size of I/O buffers used by the reader task are Transport dependent but are usually in the 8KB range.
There is no "formal" mechanism required for initializing the PAL. That is, an initialization function is not required by the STRIDE Runtime or IM. In addition good practices require releasing resources on application exit. However, over time the convention of providing palInit() and palUninit() functions has developed. All of the Pre-Packaged PAL use this convention and their palInit() function must be called before any other STRIDE Runtime function and palUninit() on application shutdown.