Creating a Real-Time Application that Uses the NAL
An RTSS application can use the NAL API function set (starting with the prefix RtNal). An application that uses the NAL typically runs a Layer 2 protocol for transmitting and receiving data and does not need to use the RT-TCP/IP Stack or socket API.
This
Sections in this topic:
- Creating the Real-Time Application
- Writing the Application Using the NAL API
- Typical Application Sequence
- Typical Receive Thread Function
- Notification Events
- Acquiring a Queue
- Configuring the Queue to Send and Receive Data
- Writing a Receive Thread
- Using the Receive Packet Callback
- Sending a Packet
Creating the Real-Time Application
The RTX64 Application template provides the structure for creating RTX64 applications. Use the following procedure to create an RTX64 project using the RTX64 Application template in Microsoft Visual Studio.
To create a RTX64 application project:
- Create a new project in Visual Studio.
- Select C or C++ as the template type.
- Select the RTX64 Application template. This template is a single-page dialog that displays the default project settings and provides optional application and program settings.
Specify the following options:
- For SDK Version, select RTX64 4.0 or above.
- Clear selection of RT-TCP/IP Support
- Click Finish to create the project. This generates the RTX64 solution and project according to the options you selected.
Set additional project properties:
- Right-click the project name and select Properties from the pull-down menu.
- Add the following properties:
In the properties page... | Add... | For these configurations... |
---|---|---|
Linker /Input | RtNal.lib | RtssRelease, RtssDebug |
Add includes to the header file:
Add the following includes to the application header file, below all existing includes and after Rtapi.h
:
#include <Rtnapi.h>
#include <RtNalApi.h>
Rebuild the application:
- Select the RtssDebug configuration and rebuild the application.
NOTE: If encounter problems building the application, compare your project properties with the properties of the NalDataStream sample provided with the NAL.
Writing the Application
The NAL application typically:
- acquires and runs one or multiple queues; it needs separate queues to send and receive data.
- runs a receive thread (or timer) per queue.
- sends data from one or multiple threads, or a timer.
The transmit thread might wait on an event flag set from an application timer to send a packet.
NOTE: There is no receive thread that runs in the context of the RTX64NAL process. All packets received on the wire, when there is no application attached to the driver queue, are discarded.
The priority of the receive and transmit threads must be less than the priority of the interrupt thread configured by the driver (the default is 64). The transmit thread priority should be less than the priority of the transmit complete thread (the default is 62).
All API calls that use a queue handle fail with error code ERROR_INVALID_HANDLE if the queue is released from another thread.
NOTE: The main function must wait until all threads complete before exiting.
NOTE: If the RtNal functionality is encapsulated into an RTDLL and not used by the loading RTSS process, you must not free the library before you exit your main process.
See the RTX64 Network Abstraction Layer (NAL) API Reference and NalDataStream sample for the complete information on using the NAL API.
Typical Application Sequence
Below are the steps that make up a typical application sequence.
Steps:
- Call RtNalInit.
- Call RtNalAcquireQueue for all the queues needed for the application.
- Prepare the application context structures for all acquired queues, as well as for the RTNAL_QUEUE_CAPABILITIES structure.
- Start receive threads.
- Call RtNalConfigureQueue for all acquired queues.
- Start transmit threads.
- The main thread waits for stop events or for some signal to stop the application and sets stop events.
- The main thread waits for all threads to complete.
- The main thread releases all queues and other application resources and frees allocated memory.
- The main thread returns.
See the RTX64 Network Abstraction Layer (NAL) API Reference and NalDataStream sample for the complete information on using the NAL API.
Typical Receive Thread Function
Below are the steps for a typical receive thread function, which loops until the thread wakes up by the stop event or until one of API calls fails with error code ERROR_INVALID_HANDLE.
Steps:
- Wait on receive and stop notification event handles.
- Call RtNalGetReceivePacketCount to get the receive count.
- Call RtNalReceive count times in a loop.
- Break out of this loop and the outer loop if RtNalReceive fails with error code ERROR_INVALID_HANDLE.
- If RtNalReceive succeeds, process the receive packet.
Notification Events
Notification events are used to notify an application of received packets, transmitted packets, link change, and the queue being released. The event handles are returned in the structure in RtNalAcquireQueue. Typically, the events are set by the NAL and the application threads wait on event handles. The application might also set the stop event to let its threads know that it wants to terminate.
- An application does not need to close notification event handles explicitly. They are closed by the NAL in RtNalReleaseQueue.
- The stop event is a manual-reset event. All other notification events are auto-reset events.
- Receive notifications are used to wake up the application receive thread from the driver interrupt service thread (IST). If you run a receive timer instead of a thread, you don’t need to use a receive event. Note that receive interrupts will still execute unless they are disabled in a driver. Receive notifications must not be configured on a queue when using RtNalEnableReceivePolling.
- Transmit complete notifications should be configured to use transmit complete callbacks for packets transmitted with RtNalTransmitEx. See Porting a Real-Time Network Filter Driver to Use the NAL for more information.
NOTE: An application must not use the transmit complete event handle directly.
- When an application gets the link change event it should call RtNalIoctl with the ENIOLINKSTATUS command to find out if the link is up or down. The NalDataStream sample includes an example of such a function (GetLinkStatus). The DataStream sample waits on link change event in the transmit thread.
- The stop notification is always enabled. The stop event is set when the queue is released from RtNalReleaseQueue call or from the NAL exit cleanup (including the case of RtssKill) for the queues that are not released by the application.
Acquiring a Queue
- To get the friendly name for a device, call RtNalGetNumberOfQueues and then iterate through queues by calling RtNalGetQueueInfoByIndex, starting with the index 0 and incrementing the index. This way, you can see information on all of the queues configured for the system.
- See the NalDataStream sample for a usage example in DisplayAllConfiguredQueues.
- Before calling RtNalAcquireQueue, fill in the structure of RTNAL_QUEUE_CRITERIA type with the device’s friendly name, receive or transmit queue type, search method, and event flag mask.
- Search methods allow you to use the device name or PCI Bus location. Use the device queue with the specified queue number, use any available queue, or use the default queue (receiving unfiltered packets) for receive.
- Set flags to RTNAL_USE_RX_EVENT_FLAG | RTNAL_USE_LINK_EVENT_FLAG for a receive queue to use receive, link change, and stop events to receive packets in a receive thread.
- Set flags to RTNAL_USE_LINK_EVENT_FLAG for a receive queue to use link change and stop events to receive packets in a polling timer.
- Set flags to RTNAL_USE_LINK_EVENT_FLAG for a transmit queue to use link change and stop events to send packets with RtNalTransmit (or RtNalTransmitEx without transmit complete callbacks).
- Set flags to RTNAL_USE_LINK_EVENT_FLAG | RTNAL_USE_TRANSMIT_COMPLETE_EVENT_FLAG for a transmit queue to use link change, transmit complete and stop events to if you send packets with RtNalTransmitEx and use transmit complete callbacks.
- Call RtNalAcquireQueue with the pointers to the prepared structures RTNAL_QUEUE_CRITERIA, RTNAL_QUEUE, and RTNAL_QUEUE_EVENTS.
- Upon successful return, the system queue information and the associated device is returned in the RTNAL_QUEUE structure. The notification event handles are returned in the RTNAL_QUEUE_EVENTS structure. The returned information contains:
- the correct MAC address
- the driver instance index
- the driver queue index
- the number of receive packet buffers configured by the driver
- the number of transmit packet buffers configured by the driver
- the maximum packet size used by the driver. Note that the driver might report the maximum packet size without accounting for Ethernet FCS, but still place FCS in the receive packet buffer. An application must add 4 bytes to the buffer size used in RtNalReceive. For example, if the reported maximum packet size is 1514, an application must use 1518-byte buffers for RtNalReceive.
Configuring the Queue to Send or Receive Data
The NAL application should do the following for the queue to properly send and receive data:
- prepare its own application data structures, which represent a queue application context to the NAL
- store the queue handle, which is used in all API calls that use the queue
- either copy data from the RTNAL_QUEUE and RTNAL_QUEUE_EVENTS structures, or set pointers to those structures
- initialize the RTNAL_QUEUE_CAPABILITIES structure. This structure has pointers to application callback functions. The , callback is called back from RtNalReceive. fpRtnDecodePacket is called back from RtNalReceive and RtNalTransmit . The fpRtnReceivePacketCallback is called from RtNalReceive, RtNalReceiveWithCallback, and the polling timer.
The application calls RtNalConfigureQueue with the queue handle, an application context pointer, and the pointer to a RTNAL_QUEUE_CAPABILITIES structure. An application context pointer must not be NULL.
Writing a Receive Thread
Below are rules for writing a receive thread:
- Typically, an application starts the receive thread before configuring the queue.
- The receive thread should wait on multiple objects with the receive and stop event handles. It should call RtNalGetReceivePacketCount to determine how many times to call RtNalReceive. Alternatively, an application can call RtNalReceive until RtNalReceive fails with the error code ERROR_NO_DATA.
- Upon successful return from RtNalReceive, the received packet data is copied to the packet returned by the application fpRtnGetPacket callback at the pointer returned in fpRtnDecodePacket callback. The received packet length is the argument, passed to fpRtnGetPacket.
The application can now process the received packet.
NOTES:
- The receive thread (servicing one queue) should return when it is awoken by the stop event or any API call has failed with the ERROR_INVALID_HANDLE (the queue was released in another thread) error code.
- If RtNalReceive fails with a different error code it might be because of a driver receive error, fpRtnGetPacket returned NULL, an application buffer is too small, or the receive packet callback returned TRUE to discard the packet.
Using the Receive Packet Callback
Below are rules for using the receive packet callback:
NOTE: The RtNalE1000 driver does not support RtndReceiveWithCallback.
- The receive packet callback is supplied in the RTNAL_QUEUE_CAPABILITIES structure (fpRtnReceiveCallback) in RtNalConfigureQueue.
- The fpRtnReceiveCallback function is called directly by the driver from RtndReceive or RtndReceiveWithCallback.
- If fpRtnReceiveCallback returns TRUE, the functions fpRtnGetPacket or fpRtnDecodePacket are not called and RtNalReceive returns FALSE with the error code ERROR_DISCARDED.
- If you are using RtNalReceiveWithCallback, you need fpRtnReceiveCallback but not callbacks fpRtnGetPacket or fpRtnDecodePacket.
- The polling timer started by RtNalEnableReceivePolling calls RtNalReceiveWithCallback.
Sending a Packet
Below are rules for sending a packet:
- A packet data buffer must be a fully formatted Ethernet packet. The source MAC address is returned as part of the information in RTNAL_DEVICE_INFO as part of RTNAL_QUEUE in function RtNalAcquireQueue. If the device MAC fills in the source MAC address, an application does not have to supply it.
- The application calls RtNalTransmit with the pointer to the packet structure in application format. The application function fpRtnDecodePacket is called back with this packet pointer. fpRtnDecodePacket must fill in the following data:
- the pointer to the data buffer
- the packet length in bytes
- the application context pointer for this queue
- The transmit thread (servicing one queue) should return when a stop event occurs or when any API call fails with error code ERROR_INVALID_HANDLE.
Sending Multiple Packets with RtNalTransmitEx
NOTE: The RtNalE1000 driver does not support RtndTransmitEx.
RtNalTransmitEx transmits multiple Ethernet frames in a single call. The frames must be pre-allocated by RtNalAllocateFrame, which returns a pointer to an RTNAL_FRAME structure, containing a virtual address and a physical address of the frame. The application must not alter the virtual and physical addresses of the frame buffer. The RTNAL_FRAME structure also contains, size of the packet to transmit and other information. RtNalTransmitEx uses an array of pointers to RTNAL_FRAME to send multiple Ethernet packets. An application can also provide callbacks to be called with each or some of the frames from a transmit complete thread. A pointer to a transmit complete callback must be written to a RTNAL_FRAME structure for a packet for which an application wants to get a callback.
To use transmit complete callbacks, the transmit notifications must be enabled for this queue. When the queue is acquired with the transmit notifications, the NAL runs an additional transmit complete thread per queue in the application process context. This thread runs on the ideal processor and with the priority, configured for the interface. Even though the transmit complete event handle is returned in the structure RTNAL_QUEUE_EVENTS from RtNalAcquireQueue, the application must not use it directly.