The philosophy of the HPE design is to allow the programmer as much control as possible over the operation of the Ethernet controller, including memory management and the operation of the DMA engine. For example, attaching the transmit frames to the controller in advance of issuing the command to start transmission allows the controller to start to buffer the data so that any FIFOs are loaded before the transmission starts, thus reducing the time between issuing the command the the operation starting
The interface architecture separates the queuing of Ethernet datagrams for transmission and the start of the transmit cycle. This allows for the application to provide the send and receive buffers used directly by the DMA engine, and to control precisely when the transmission starts.
INtime's High-performance Ethernet system calls perform the following actions:
Each Ethernet interface under the control of this software is identified by a short text name. This is determined when the driver loads. An application accesses an interface by opening it. A handle is returned which is then used in all subsequent calls to the same interface until the interface closes.
Since HPE operation directly accesses the network device hardware, a single network device cannot be used directly as a HPE device and as a INtime Network (TCP/IP) device at the same time. If both HPE and TCP/IP are required, you need at least two network devices, or you can use the XCNT "connector" driver to forward packets to and from the network stack from your HPE application.
Alternatively, if both low level Ethernet operation and TCP/IP are required using a single network device, consider using BPF and/or pcap. BPF/pcap are part of INtime network system. BPF/pcap are not as fast as HPE but they allow sending/receiving raw Ethernet frames as well as regular TCP/IP packets using the same network device.
HPE3 is the newest release of the interface and takes advantage of extended functionality available in some advanced Ethernet controllers, especially the Intel i210 controller. The extended functionality for HPE3 is in four areas:
The enhancements implemented in the HPE3 interface combined with the hardware features of the Intel i210 controller allow for the creation of high-performance, high-precision Ethernet applications well suited to the requirements of a range of demanding industrial applications.
A transmit queue can be one of two types. A "priority" queue is the default type and the queue can be assigned a priority. Packets will be transmitted from a high-priority queue before a low-priority queue. This feature can be used for traffic shaping or QoS management. A queue can alternatively be designated as a "stream" queue. Queues of this type transmit packets according to a timer descriptor which uses built-in timer hardware to determine when to transmit packets in the queue. This gives the device isochronous capability and this feature is very useful in the design of industrial Ethernet implementations, for example.
Incoming packets may be filtered using internal filtering hardware and the packets delivered to a different queue depending on its content. This feature may be used to prioritize incoming traffic for example. High-priority traffic would be delivered to the first queue, lower-priority traffic to a second queue, etc.
Three sample applications are included with the product. A general HPE sample application "High Performance Ethernet Sample" illustrates how to use the HPE API to send and receive Ethernet frames. It includes a WIndows application to also send and receive frames using the WinPCAP interface.
A second sample, "HPE3 Extra Features Sample", illustrates some of the advanced features of the HPE3 interface. Included are examples for the following:
A third sample, "XCNT-HPE Sample" illustrates how an HPE application can interact with the TCP/IP stack using the Ethernet Connector driver (XCNT), acting as a filter or monitor for IP traffic.
This lists common operations related to High-performance Gigabit Ethernet and the INtime system calls that do the operations.
To . . . | Use this system call . . . |
---|---|
Initialization and configuration | |
Initialize an Ethernet interface | hpeOpen |
Similar to hpeOpen; specify additional options | hpeOpenWithOptions |
Close an Ethernet interface indicated by the handle parameter | hpeClose |
Obtain information about the hardware interface | hpeGetInterfaceInfo |
Configure options for the Ethernet controller, such as multicast packet reception | hpeConfigOptions |
Obtain a list of queue features supported by the hardware interface | hpeGetQueueConfiguration |
Report the interface's 6-byte MAC address | hpeGetMacAddress |
Report the current status of the media interface of the Ethernet controller | hpeGetMediaStatus |
Obtain statistics from a queue | hpeGetQueueStats |
Receive | |
Allocate a receive buffer set which is compatible with the network device | hpeAllocateReceiveBufferSet |
Attaches a set of receive buffers to a queue for use by the DMA engine to receive Ethernet frames. | hpeAttachReceiveBufferSetToQueue |
Attach a set of receive buffers to queue 0 for use by the DMA engine to receive Ethernet frames. | hpeAttachReceiveBufferSet |
Free memory allocated by hpeAllocateReceiveBufferSet | hpeFreeReceiveBufferSet |
Return a pointer to the next receive buffer in the default receive queue which has a fully-received frame in it | hpeGetReceiveBuffer |
Return a pointer to the next receive buffer in the designated queue which has a fully-received frame in it. | hpeGetReceiveQueueBuffer |
Returns the receive buffer obtained by hpeGetReceiveBuffer to the network device on queue 0. | hpeReturnReceiveBuffer |
Returns the receive buffer obtained by hpeGetReceiveBuffer to the network device on the designated queue. | hpeReturnReceiveQueueBuffer |
Determine the queue to receive packets that are not matched by a filter. | hpeSetDefaultReceiveQueue |
Enable or disable receipt of all packets (promiscuous mode) at the device. | hpeSetPromiscuousMode |
Set the type of a receive queue. | hpeSetReceiveQueueAttributes |
Enable a receive queue filter by setting its parameters. | hpeSetReceiveQueueFilter |
Instruct the caller to sleep until the next receive interrupt occurs for the default queue. | hpeWaitForReceiveComplete |
Instruct the caller to sleep until the next receive interrupt occurs for the designated queue. | hpeWaitForReceiveQueueComplete |
Transmit | |
Attach a set of transmit buffers to the driver on queue 0. | hpeAttachTransmitBufferSet |
Attach a set of transmit buffers to the driver on designated queue. | hpeAttachTransmitBufferSetToQueue |
Return a value indicating the current state of the transmitter of queue 0. | hpeGetTransmitterState |
Return a value indicating the current state of the transmitter of the designated queue. | hpeGetTransmitQueueState |
Set the time to subtract from the launch time to begin packet fetch. | hpeSetTransmitFetchDelta |
Set the type of a transmit queue. | hpeSetTransmitQueueAttributes |
Set the global offset to be added to the launch time. | hpeSetTransmitTimeOffset |
Set the priority of a transmit queue. | hpeSetTransmitQueuePriority |
Cause the transmitter to transmit any and all frames which are ready to be sent from queue 0. | hpeStartTransmitter |
Cause the transmitter to transmit any and all frames which are ready to be sent from designated queue. | hpeStartTransmitterQueue |
Instruct the caller to sleep until the next transmit interrupt occurs for queue 0. | hpeWaitForTransmitComplete |
Instruct the caller to sleep until the next transmit interrupt occurs for the designated queue. | hpeWaitForTransmitQueueComplete |
Timers and IEEE 1588 Time Support | |
Signal a semaphore when a target time is reached. | hpeSetTargetTimer |
Read the 1588 time from the controller. | hpe1588GetSystemTime |
Write the 1588 time to the controller. | hpe1588SetSystemTime |
Adjust the 1588 system clock in the controller. | hpe1588AdjustSystemTime |
Set the offset at which the 1588 timestamp is written in transmit packets. | hpe1588SetTimestampOffset |
Retrieve the receive timestamp from the packet buffer. | hpe1588GetRxTimestamp |
Retrieve the timestamp for the most recently transmitted packet. | hpe1588GetTxTimestamp |
Retrieve the size of the timestamp header. | hpe1588GetRxTimestampHeaderSize |
Add two 1588 time values. | hpe1588TimeAdd |
Subtract a 1588 time values from another. | hpe1588TimeSubtract |
Compare two 1588 time values. | hpe1588TimeCompare |
Return the difference between two 1588 time values. | hpe1588TimeDifference |
Extract a 1588 timestamp from a buffer. | hpe1588ExtractTimestamp |
To . . . | Use this structure . . . |
---|---|
Specify options; used by hpeConfigOptions | HPE_CONFIG_OPTIONS |
Specify options; used by hpeOpenWithOptions | HPE_OPEN_OPTIONS |
Describe a queue configuration | HPEQUEUECONFIG |
Describe an individual buffer to hold frame data | HPEBUFFER |
Obtain information about the currently-connected media | HPEMEDIASTATUS |
Describe a set of receive frame buffers | HPERXBUFFERSET |
Describe a single transmit buffer | HPETXBUFFER |
Describe a transmit buffer set, consisting of multiple transmit buffers | HPETXBUFFERSET |
Describe a single transmit stream buffer | HPETXSTREAMBUFFER |
Describe a transmit stream buffer set, consisting of multiple transmit stream buffers | HPETXSTREAMBUFFERSET |
Describe a IEEE1588 timestamp | HPE_1588_TIMESTAMP |
Define an Ether type filter | HPE_ETHER_FILTER |
Define a Flex Data filter | HPE_FLEX_FILTER |
Define a 2-Tuple filter | HPE_2TUPLE_FILTER |
This section illustrates some possible operations using this API.
To initialize the interface it is necessary to open it, then attach receive buffers, and attach transmit buffers. For example:
HPE initialization |
Copy Code |
---|---|
HPESTATUS status; HPEHANDLE handle; HPERXBUFFERSET *rx_buffers; HPETXBUFFERSET *tx_buffers; int i; char *p; static char fixed_header[56]; // 56-byte fixed header for each transmitted frame status = hpeOpen("ie1g0", SPEED_100|DUPLEX_FULL, ALL_INTERRUPTS, &handle); // allocate 4 receive buffers and attach them status = hpeAllocateReceiveBufferSet(handle, &rx_buffers, 4, ETH_FRAME_SIZE); status = hpeAttachReceiveBufferSet(handle, rx_buffers); // allocate 1 transmit buffer of two fragments and 500 bytes and attach it tx_buffers = AllocateRtMemory(4096); p = (char *)&tx_buffers->buffers[1]; tx_buffers->buffer_count = 1; tx_buffers->buffers[0].fragment_count = 2; // first fragment is the fixed header, second is dynamic data tx_buffers->buffers[0].fragments[0].ptr = fixed_header; tx_buffers->buffers[0].fragments[0].size = 56; tx_buffers->buffers[0].fragments[0].paddr = 0; tx_buffers->buffers[0].fragments[1].ptr = p; tx_buffers->buffers[0].fragments[1].size = 444; tx_buffers->buffers[0].fragments[1].paddr = 0; status = hpeAttachTransmitBufferSet(handle, tx_buffers); |
Once the interface is set up, load the data, attach the transmit set and start the transmitter.
Transmit a frame |
Copy Code |
---|---|
// user function to initialize the frames to be transmitted FillTransmitPayload(tx_buffers[0].fragments[1].ptr); hpeAttachTransmitBufferSet(handle, tx_buffers); status = hpeStartTransmitter(handle); // wait for 1 second: status = hpeWaitForTransmitComplete(handle, 1000); |
First check to see if a buffer is available then process the data in it. Once the buffer has been received the buffer may be reused.
Receive frames |
Copy Code |
---|---|
// user function to initialize the frames to be transmitted HPEBUFFER *rxbuffer; hpeWaitForReceiveComplete(handle, 1000); if (hpeGetReceiveBuffer(handle, &rxbuffer) == E_OK) process_buffer_data(rxbuffer->ptr, rxbuffer->used); // user function |
Open the interface then set up the transmit and receive queues as desired. In this example we are going to designate transmit queue 0 as a STREAM (i.e. QAV) queue, and transmit queue 1 as a priority queue. The receive filter will be set to receive PROFINET frames into receive queue 0 and all other traffic to receive queue 1.
Example Title |
Copy Code |
---|---|
HPESTATUS status; HPEHANDLE hpe; HPERXBUFFERSET *rx_buffers_q0; HPERXBUFFERSET *rx_buffers_q1; HPETXSTREAMBUFFERSET *tx_buffers; HPE_ETHER_FILTER eth_filter; TIMESTAMP_1588 now, next; int i; char *p; static char fixed_header[56]; // 56-byte fixed header for each transmitted frame // Open the Intel Gigabit driver status = hpeOpen(“ie1g0”, SPEED_100|DUPLEX_FULL, ALL_INTERRUPTS, &hpe); // Queue 0 is set to be a STREAM queue // Queue 1 is a PRIORITY queue by default status = hpeSetTransmitQueueAttributes(hpe, 0, HPE_TX_STREAM); // all non-filtered traffic will be received in RX queue 1 status = hpeSetDefaultReceiveQueue(hpe, 1); // allocate 4 receive buffers and attach them status = hpeAllocateReceiveBufferSet(hpe, &rx_buffers, 4, ETH_FRAME_SIZE+sizeof(HPE_1588_TIMESTAMP)); status = hpeAttachReceiveBufferSetToQueue(hpe, 0, rx_buffers_q0); // allocate and attach the set of receive buffers to the default queue status = hpeAllocateReceiveBufferSet(hpe, &rx_buffers_q1, 4, ETH_FRAME_SIZE); status = hpeAttachReceiveBufferSetToQueue(hpe, 1, rx_buffers_q1); // configure the receive queue filter for queue 0 eth_filter.type = 0x8892; // Profinet RT ether_filter.destination_queue = 0; eth_filter.insert_timestamp = 1; status = hpeSetReceiveQueueFilter(hpe, HPE_FILTER_ETHER_TYPE, eth_filter); // Calculate the launch time. hpeGet1588SystemTime(hpe, &now); next.seconds = 0; next.nanoseconds = 10000000; // 10 milliseconds; hpe1588TimeAdd(&next, &now); // Allocate 1 transmit buffer of two fragments and 500 bytes and attach it tx_buffers = AllocateRtMemory(4096); p = (char *)&tx_buffers->buffers[1]; tx_buffers->buffer_count = 1; tx_buffers->buffers[0].fragment_count = 2; tx_buffers->buffers[0].timestamp_offset = 0; // not cyclic tx_buffers->buffers[0].launch_time = next.nanoseconds; // first fragment is the fixed header, second is dynamic data tx_buffers->buffers[0].fragments[0].ptr = fixed_header; tx_buffers->buffers[0].fragments[0].size = 56; tx_buffers->buffers[0].fragments[0].paddr = 0; tx_buffers->buffers[0].fragments[1].ptr = p; tx_buffers->buffers[0].fragments[1].size = 444; tx_buffers->buffers[0].fragments[1].paddr = 0; status = hpeAttachTransmitBufferSetToQueue(handle, 0, 1, tx_buffers); |