[riot-notifications] [RIOT-OS/RIOT] netdev: change receive mechanism (#11652)

José Alamos notifications at github.com
Thu Jun 6 17:22:31 CEST 2019

#### Description
While working on #11483, I started evaluating some alternative receive procedures that could help to improve the performance of transceivers and maintainability.

Our current receive procedure using the netdev interface is the following:
1. ISR from transceiver and message to netif thread (ISR offloading)
2. Call `dev->driver->isr(dev)` from thread context
3. `dev->event_callback(NETDEV_EVENT_RX_COMPLETE)` is called from `dev->driver->isr(dev)` function
4. The event callback gets the packet size with `dev->driver->recv(dev, NULL, 0)`
5. The upper layer allocates a buffer and calls `dev->driver->recv(dev, buffer, pkt_size)`

However, there are some disadvantages of this procedure:
- There are more SPI instructions and CPU cycles than needed when calling dev->driver->recv twice
- The implementation of the `dev->driver->recv` function is tricky (usually radios don't understand the concept of "dropping" a packet, so there are blocks and chains of if-else in order to meet the requirements of `buf != NULL`, `len != 0`, etc. Also, some extra care is needed in order to avoid corrupting the frame buffer when reading the first received byte (PHY layer, Physical Service Data Unit length) with `dev->driver->recv(dev, NULL, 0)`. 
- AFAIU, the concept of returning the packet length is for helping the upper layer (GNRC) to allocate the received packet. Considering in MAC layers like IEEE802.15.4 with ACK enabled **half of transceiver traffic is Link Layer traffic**,  allocating packets for ACK is less efficient than having a fixed buffer.

### Proposed procedure
I changed the receive procedure to indicate the rx of a packet, and modified the `_recv` function to simply write to a frame buffer (a.k.a `rx_buf`,127 bytes for IEEE802.15.4). I also added a PHY Indication function as a callback for the upper layer when a packet is received and a `receive` function:

The new procedure looks like:
1. ISR from transceiver and message to netif thread (ISR offloading)
2. Call `dev->driver->isr(dev)` from thread context
3. `dev->event_callback(NETDEV_EVENT_RX_COMPLETE)` is called from `dev->driver->isr(dev)` function.
4. The event callback calls the `dev->driver->recv()` function **to write directly in a fixed size frame buffer** (static or stack allocated), without the drop and pkt size logic. Save the pkt size in a `psdu_len` variable.
5. Call `phy_indication(dev, rx_buf, psdu_len)` to indicate the upper layer a packet was received.

### Results
For both setups (current `dev->driver->recv` and PHY indication), I'm using an AT86RF233 radio, a logic analyzer and GPIO pins to measure time and gnrc_pktbuf within GNRC.

The logic for the measurement is:
1. Set GPIO pin [when RX_DONE is detected](https://github.com/RIOT-OS/RIOT/blob/master/drivers/at86rf2xx/at86rf2xx_netdev.c#L638) within the `dev->driver->isr(dev)` function
2. Clear GPIO [right after `netif->ops->recv()`](https://github.com/RIOT-OS/RIOT/blob/master/sys/net/gnrc/netif/gnrc_netif.c#L1415)

For the PHY indication setup, I modified the `dev->driver->recv` function to (sort of) preserve the original behavior:
int _recv(...) {
    if (buf != NULL) {
        memcpy(buf, rx_buf, psdu_len);
    return psdu_len;
Here is a graph comparing our current `dev->driver->recv` and the `phy_indication` mechanism for packets with different PSDU size:

This is the time overhead (%) of the current `dev->driver->recv()` procedure:

Note there's data duplication in rx_buf and the packet buffer, but could be reduced if the MAC layer is processed from the frame buffer

I've seen this pattern at least on OpenThread, OpenWSN and Linux (local buffers in stack). Contiki also has a similar approach.

### Useful links
<!-- Please include links to any documentation that you think is useful. -->

<!-- Thanks for contributing! -->

You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.riot-os.org/pipermail/notifications/attachments/20190606/c71054bc/attachment.html>

More information about the notifications mailing list