From INtime 6.0 the INtime Service and Port objects have been deprecated.
New projects should not be started using these features, and existing projects will not work with XM mode
This describes how to design and use an INtime service to perform a hardware driver capability, or to provide intermediate services between driver and application. The INtime Service is described in detail and examples given of certain key issues.
INtime software includes the features required to write an application which can control an I/O-mapped hardware device which generates interrupts. With INtime software, you can:
Advantages of using the service model to implement a hardware driver include:
A hardware interface may be required to support multiple services to different applications. For example, a serial controller designed to transmit and receive streams of bytes could be enhanced by adding a service which organizes the bytes into packets, and switch the packets depending on the packet contents. This can be accomplished by writing an intermediate service to do the packet formatting and switching, and which uses a hardware service to transmit and receive the bytes.
The INtime service model is based on the INtime port object, which provides a messaging interface to a service. Messages may be sent to and received from a port. A given service is defined by:
Two services supporting the same message set are interchangeable. This makes for easy porting of applications between different hardware interfaces by careful design of the service interface.
A process which uses a service (a user process) may send or receive messages from more than one port, and more than one user process may use the same port.
A user process may fall into one of these categories:
Functionally, the purpose of a service is to process messages from a user and events from an interface. A service is defined by the set of messages and the actions provoked by those messages. The user sending and receiving the messages via the port does not have to know the details of the service internals or of the interface. Two services supporting the same message set are interchangeable. This makes for easy porting of applications between different interfaces by careful design of the service message interface.
Services can classified in one of two broad categories.
A service may be further classified by the type of interface it serves. Hardware services typically include interrupt services, or alarm services while intermediate services are always port services.
INtime Services are dynamically loaded during run-time by loading the service process. When a service is loaded it must make a call to InstallRtServiceDescriptor to install each of its service descriptors before the service is made available to other applications.
Services may be configured by passing static parameters in the service descriptor, and by dynamically changing certain attributes using the primitive SetRtServiceAttributes. These and other attributes may be monitored using the primitive GetRtServiceAttributes. The implementation of these interfaces is optional.
A service may be removed by making a call to UninstallRtServiceDescriptor.
Once a hardware service is installed, other intermediate services may be loaded to provide higher-level functionality. For example, services to provide different functionality may be loaded "on top" of a hardware service. During the initialization of the intermediate service it creates a port for access to the hardware service. Thus an intermediate service is itself a user process for another service. Intermediate services may also create ports into other intermediate services, providing a multi-layered architecture.
This section describes how Services are implemented and what decisions have to be made to achieve that implementation. It describes the architecture of a service and gives examples of different types of service.
This picture illustrates the architecture of a service and its interaction with the INtime kernel:
Points to notice:
A service consists of four major components.
Several internal control structures are defined and managed by the RT kernel to support message and transaction handling within a service. These structures contain details of each message and each transaction. When a service is initialized, a pool of each type of structure is created according to parameters given in the service descriptor.
INtime service control structures include:
CONTROLBUFFERA library is provided for the service developer to allow access to system services specific to service requirements. It includes functions to manage the transaction and message buffer pools, to deliver messages to ports, queue management and port ID lookup services. A corresponding C header file (RTSERV.H) is also available in the standard include directories.
This library must be linked with each service application.
Follow these steps to implement a service:
Note: The SERVICEDESC structure contains all the configuration information needed to run the service. It must be initialized before installation so that the kernel can configure the internal resources ready for use.
The items delivered by the implementer will be (as a minimum) a service application, and a header file for service users.
The primitives SendRtMessage, SendRtMessageRSVP and SendRtReply all cause the kernel to invoke the compulsory handler SendMessage. This handler starts the transmit operation (however it is implemented in the service) and manages the send side of the service data path.
The routine is presented with a pointer to a transaction and a pointer to a control buffer, each of which has been initialized with the relevant system information. The implementer has the following responsibilities:
Part of the service thread function is to handle transmission completion events. The second part of transmission handling is done here.
Receive operations are a little more complicated. In general, the service thread processes one or more events from the interface to generate a message, which it then delivers to a port. When a user calls ReceiveRtMessage or ReceiveRtReply the kernel formats all the information in the message buffer into the ReceiveInfo structure supplied by the caller. The service implementer may optionally specify a handler to handle unusual formatting requirements.
InControlMessage
field of the Transaction buffer to the pointer to the control buffer. When an input message has been received at the interface (with good or bad status), the actions required differ dependent upon whether the newly-arrived message is a response to a previous request, or a new request, or a transaction-less message.
In this case a transaction structure will already exist for this message. The service:
lpData
, dwDataLength
and wFlags
fields of the control buffer. Link this buffer to the lpInControl
field of the transaction.
Fragmentation describes the process where a given message is split up for transmission and must be put together again by the receiving entity. The fragmentation scheme for any given service is a function of the design of that service, and in general, not much support can be given to the implementer. However, to make a given fragmentation scheme easier to implement, certain fields are provided in the transaction structure and one interface is provided to help.
To . . . | Use this system call . . . |
---|---|
Indicate a complete transactionless message is ready to deliver to a port. | DeliverMessage |
Terminate a transmit operation, usually from the service thread. | DeliverStatus |
Indicate a response message is ready to deliver to a port. | DeliverTransaction |
Dequeue the transaction at the head of the service input queue and returns a pointer to it. | DequeueInputTransaction |
Dequeue the transaction at the head of the service output queue and returns a pointer to it. | DequeueOutputTransaction |
Enter the region associated with the service. | EnterServiceRegion |
Enqueue a transaction on either the service or a port input queue. | EnqueueInputTransaction |
Enqueue a transaction on either the service or a port output queue. | EnqueueOutputTransaction |
Exit the service region previously entered with EnterServiceRegion. | ExitServiceRegion |
Return the port ID for a given port handle. | GetPortId |
Use a TRANSACTION structure to tie up a response message received from the interface. | GetTransaction |
Look up a port handle given a port ID. | LookupPortHandle |
Return the first valid transaction at the head of the input queue referenced by the hObject parameter. |
QueryInputTransactionQueue |
Return the first valid transaction at the head of the output queue referenced by the hObject parameter. |
QueryOutputTransactionQueue |
Return a control buffer to the service pool. | ReleaseControlBuffer |
Return a TRANSACTION structure to the pool. | ReleaseTransaction |
Request a control buffer from the service pool. | RequestControlBuffer |
Return a TRANSACTION buffer from the service transaction pool. | RequestTransaction |
Set the port parameter for the given port to a value given by the caller. | SetPortParameter |
Retrieve the parameter previously associated with a port by a call to SetPortParameter. | GetPortParameter |
TRANSACTION, SERVICEDESC, CONTROLBUFFER, RECEIVEINFO, InstallRtServiceDescriptor, SetRtServiceAttributes, SetRtServiceAttributes, UninstallRtServiceDescriptor, SendMessage, SendRtMessage, SendRtMessageRSVP, SendRtReply, DeliverStatus, DeliverMessage, GetTransaction, RequestControlBuffer, LookupPortHandle