Data Transfer


Detailed Description

Packet transport interface.

These functions access the low level transport driver which makes the application independent of the actual physical transport layer (usually SDIO or SPI).

For the IP stack integration you need to intercept received packets so they can be sent up the stack and to transmit packets coming down the stack.

By default the wl_api library discards all data packets. To receive them the application must register a rx interrupt service routine (isr) using the wl_register_rx_isr() function.

static void rx_isr(void* ctx) {
       rx_pending = TRUE;
}

Since the rx_isr() function is only called in interrupt context, it is not safe to perform the actual read directly from rx_isr(). If an OS is used, the normal case is to signal a receiver thread to invoke the ip stack read function to read the pending data. In a system that runs without an OS (as in the example), a flag is set to indicate that wl_rx() can be invoked from the ip stack read function next time the ip stack is polled. The beginning of a ip stack read function can look like this

static void ip_stack_rx_pkt() {
       char *pkt = malloc(MAX_PKT_SIZE);
       uint16_t len = MAX_PKT_SIZE;

       if (p == NULL) {
              app_error("Out of memory.");
              return;
       }
       wl_rx(pkt, &len);
       if (0 == len) {
              app_error("Packet reception failed.");
              free(pkt);
              return
       }      
}

Since the ip_stack_rx_pkt() function should only be called when there is actually a packet ready to read you do not have to check the return value from wl_rx() since it only returns failure if there is no packet ready to read.

A packet arriving from the WiFi interface can be either a data packet or a message from the WiFi hardware to the WiFi driver (which is implemented by the wl_api library). This means that wl_api must process every packet to decide if it is an internal message or a data frame that should be passed up to the application. Data packets are prefixed with an extra header containing some administrative information, and may be followed by padding bytes and so wl_api also needs to strip the extra header and any padding before the packet can be safely ingested by the IP stack. All this happens in the function wl_process_rx() which must be called on every packet received by a call to wl_rx().

Continuing the ip_stack_rx_pkt() example

       {
                char*  stripped_pkt;
                size_t stripped_pkt_len;
                uint16_t vlan;
                int status;
                
                status = wl_process_rx(pkt,
                                       len,
                                       &stripped_pkt,
                                       &stripped_pkt_len,
                                       &NULL,
                                       &vlan,
                                       NULL);
                if (WL_ABSORBED == status) {
                       // This is normal. The packet was a
                       // wl_api-internal message.
                       free(pkt);
                       return;    
                }
                app_ip_stack_input(stripped_pkt,
                                   stripped_pkt_len,
                                   vlan);
                free(pkt);
        }
}

If wl_process_rx() decides that the packet was a command it processes it and returns WL_ABSORBED to signal that the packet should not be used by anyone else. Otherwise stripped_pkt is pointing to the beginning of a 802.3 ethernet frame of length stripped_pkt_len. If the IP stack supports VLAN and QoS the extra VLAN tag should be passed to the IP stack together with the packet. For IP stacks without this support the VLAN tag contents can safely be ignored, but it must still be filled in by wl_process_tx().

To register the receive isr

        wl_register_rx_isr(rx_isr, NULL);

Transmitting data packets happens in a similar way but does not require a callback/isr since the application/IP stack knows when it has packets to send.

int ip_stack_tx_pkt(char *pkt, size_t len, uint16_t vlan_tag) {
        int status;
        size_t hdr_len;
        char wlan_hdr[WL_HEADER_SIZE];
        // The packet must have an ethernet header
        if (len < ETHERNET_HEADER_SIZE) {
                app_error("Invalid packet length");
                return 0;
        }
        hdr_len = sizeof wlan_hdr;
        status = wl_process_tx(pkt,
                               ETHERNET_HEADER_SIZE,
                               len,
                               wlan_hdr,
                               &hdr_len,
                               vlan_tag,
                               NULL);
        if ( WL_SUCCESS != status ) {
                app_error("Packet processing failed");
                return 0;
        }
        // Transmit the header first
        if (wl_tx(wlan_hdr, hdr_len) != WL_SUCCESS) {
                app_error("Header transmission failed");
                return 0;
        }
        // Then transmit the data packet
        if (wl_tx(pkt, len) != WL_SUCCESS) {
                app_error("Packet transmission failed");
                return 0;
        }
}

The final piece of the puzzle in the IP stack integration is the MAC address of the WiFi interface

        char mac_addr[WL_MAC_ADDR_LENGTH];

        wl_get_mac_addr(mac_addr);
        ip_stack_set_mac_address(mac_addr);

Functions

wl_err_t wl_process_rx (char *pkt, size_t pkt_len, char **stripped_pkt, size_t *stripped_pkt_len, uint16_t *vlanid_prio)
 Process rx packet.
wl_err_t wl_process_tx (char *eth_hdr, size_t eth_hdr_len, size_t pkt_len, char *hdr, uint16_t vlanid_prio)
 Process tx packet.
wl_err_t wl_register_rx_isr (wl_rx_isr_t isr, void *ctx)
 Register RX callback.
wl_err_t wl_rx (uint8_t *buf, uint16_t *len)
 Read pending packet.
wl_err_t wl_tx (const uint8_t *buf, uint16_t len)
 Send processed tx packet.

Function Documentation

wl_err_t wl_process_rx ( char *  pkt,
size_t  pkt_len,
char **  stripped_pkt,
size_t *  stripped_pkt_len,
uint16_t *  vlanid_prio 
)

Process rx packet.

Processes a raw rx packet by unencrypting it (if necessary) and stripping headers so as to output a 802.3 frame.

Parameters:
pkt Input buffer (raw packet)
pkt_len Length of the input buffer (in bytes)
stripped_pkt Pointer to the packet with the transport header stripped.
stripped_pkt_len Length of the stripped packet.
vlanid_prio VLAN ID and 802.1p priority value using following format:
        1
  5|432109876543|210
  -+------------+---
  0|   VLANID   |PRI
 
Returns:
  • WL_FAILURE
  • WL_ABSORBED if the packet was an internal driver command and not a proper data packet. The packet should be freed and the stripped_pkt will not point to a valid packet.
  • WL_SUCCESS

wl_err_t wl_process_tx ( char *  eth_hdr,
size_t  eth_hdr_len,
size_t  pkt_len,
char *  hdr,
uint16_t  vlanid_prio 
)

Process tx packet.

Prepare tx packet for transmission.

This function is typically used only by the TCP/IP stack driver.

Takes a Ethernet II frame header and generates a message passing header for it. The ethernet header is assumed to have the following layout : <dst addr:6><src addr:6><type:2>... The rest of the ethernet header buffer (if any) is ignored.

Parameters:
eth_hdr Input buffer (ethernet header)
eth_hdr_len Input buffer length (must be >= 14)
pkt_len Length of the complete data packet (in bytes)
hdr Pointer to the header buffer (must be allocated by the caller). The length of the buffer must be at least WL_HEADER_SIZE bytes.
vlanid_prio VLAN ID and 802.1p priority value using following format:
        1
  5|432109876543|210
  -+------------+---
  0|   VLANID   |PRI
 
Ignored for legacy association (no WMM)
Returns:
  • WL_FAILURE
  • WL_RESOURCES if packet can not be processed at the moment. The caller must either drop the packet or try retransmit it later.
  • WL_AVAIL if network not available
  • WL_SUCCESS if packet is ready for transmission through wl_tx().

wl_err_t wl_register_rx_isr ( wl_rx_isr_t  isr,
void *  ctx 
)

Register RX callback.

Register function to be called by the low level transport driver when a new packet is available or when there is a state change in the data path. When invoked, any pending data can be fetched by calling wl_rx().

This function is typically used only by the TCP/IP stack driver. Note, the registered function is called in interrupt context.

Parameters:
isr rx interrup handler.
ctx Opaque context pointer that is passed unmodified to the rx_cb callback when it is invoked.
Returns:
WL_SUCCESS

wl_err_t wl_rx ( uint8_t *  buf,
uint16_t *  len 
)

Read pending packet.

Read a pending packet from the low level transport driver. The read packet must be passed to the wl_process_rx() function for proper driver operation.

Parameters:
buf Buffer to read the packet into. This buffer must be at least WL_MAX_PKT_LEN bytes long.
len Length of buf in bytes. Contains the length of the read packet in bytes on output.
Returns:
  • WL_FAILURE if no RX packet is pending.
  • WL_SUCCESS

wl_err_t wl_tx ( const uint8_t *  buf,
uint16_t  len 
)

Send processed tx packet.

Send a packet to the low level transport driver. This packet has to have been successfully processed by the wl_process_tx() function.

Parameters:
buf Buffer to send.
len Length of buf in bytes.
Returns:
  • WL_FAILURE if the interface is not ready to send.
  • WL_SUCCESS if the packet was successfully transmitted.


API Reference Manual Copyright © 2009 H&D Wireless AB, All rights reserved.