Skip to content

How to implement a `ng_netdev` enabled device

Martine Lenders edited this page Mar 10, 2015 · 16 revisions

The following sections describe how to implement a ng_netdev enabled device.

add event callback

  • (implementation of driver.add_event_callback)

  • the implementation is pretty much always the same:

if ((dev == NULL) || (dev->driver != &ng_tapnet_driver)) { return -ENODEV; }

if (dev->event_cb != NULL) { return -ENOBUFS; }

dev->event_cb = cb;

return 0;


# remove event callback
* *(implementation of `driver.rem_event_callback`)*
* the implementation is pretty much always the same:

``` {.c}
if ((dev == NULL) || (dev->driver != &ng_tapnet_driver)) {
 return -ENODEV;
}

if (dev->event_cb != NULL) {
 return -ENOBUFS;
}

dev->event_cb = cb;

return 0;

events

  • in interrupt handler of driver:
    • determine event type event_type

      • value can be chosen by driver
      • not necessarily bound to ng_netdev_event_t
    • determine device dev

    • send message msg to dev->mac_pid (event handler thread) with

msg.type == NG_NETDEV_MSG_TYPE_EVENT msg.content.value = event_type msg_send(&msg, dev->mac_pid); ```

  • in thread dev->mac_pid (dev is known by event handler thread):

msg_receive(&msg);

switch (msg.type) { case NG_NETDEV_MSG_TYPE_EVENT: dev->driver->isr_event(dev, msg.content.value); break; /* ... */ }


* in `driver.isr_event(dev, event_type)`:
 - check `dev` (`dev != NULL` and `dev->driver == &driver`)
 - call event handlers `_event_<event_type>()` for event according to event
* **FAQ**:
 - *TODO*

## RX started
*TODO*

## RX complete
* read received data `data` (of length `data_len`) from device
* add `ng_netif_hdr_t` with both source `l2src` (of length `l2src_len`) and 
destination address `l2_dest` (of length `l2dst_len`) to `ng_pktbuf`

``` {.c}
ng_pktsnip_t *hdr_snip = ng_pktbuf_add(NULL, NULL, 
                                    sizeof(ng_netif_hdr_t) + l2src_len + 
                                    l2dst_len, NG_NETTYPE_UNDEF);

if (hdr_snip == NULL) {
 DEBUG("Packet buffer full.\n");
 return;
}

ng_netif_hdr_t *hdr = hdr_snip->data;
ng_netif_hdr_init(hdr, l2src_len, l2dst_len);
ng_netif_hdr_set_src_addr(hdr, l2src, l2src_len);
ng_netif_hdr_set_src_addr(hdr, l2dst, l2dst_len);
hdr->if_pid = thread_getpid();
hdr->rssi = l2rssi;
hdr->lqi = l2lqi;
  • determine demultiplexing type demux_type (e.g. via Ethertype with Ethernet devices) if available

  • otherwise demux_type can be a fixed value (e.g. NG_NETTYPE_SIXLOWPAN for IEEE 802.15.4 devices)

  • copy payload of received packet into packet buffer

ng_nettype_t demux_type = NG_NETTYPE_UNDEF;

switch (ether_type) { #ifdef MODULE_NG_IPV6 case ETHER_TYPE_IPV6: demux_type = NG_NETTYPE_IPV6; break; #endif

default:
    break;

}

pkt = ng_pktbuf_add(pkt, data + L2_HDR_LEN, data_len, demux_type);

if (pkt == NULL) { DEBUG("Packet buffer full.\n"); ng_pktbuf_release(hdr_snip); return; }


* call callback event handler with `pkt` as argument if available:

 ``` {.c}
if (dev->event_cb) {
 dev->event_cb(NETDEV_EVENT_RX_COMPLETE, pkt);
}
else {
 ng_pktbuf_release(pkt);
}
 ```

* release packet also in other error case, no one else will clean-up your mess :wink:
* **FAQ**:
 - *TODO*

## TX started
*TODO*

## TX complete
*TODO*

# send data
* *(implementation of `driver.send_data`)*
* check if `pkt != NULL`, return `-EFAULT` on failure
* check `dev` (`dev != NULL` and `dev->driver == &driver`)
* on failure: release `pkt` return `-ENODEV`
* build device header from `netif_hdr` (is first header in `pkt`)
* put device header in out buffer
* put rest of `pkt` out buffer `out_buf` (may also be SPI buffer or similar)

```C
ng_pktsnip_t *ptr = pkt->next;
int nwrite = L2_HDR_LEN;

while (ptr) {
 memcpy(out_buf + nwrite, ptr->data, ptr->size);

 if (nwrite > OUT_BUF_SIZE) {
     ng_pktbuf_release(pkt);
     return -ENOBUFS;
 }

 ptr = ptr->next;
}

ng_pktbuf_release(pkt);
  • send content of out buffer
  • release packet also in other error case, no one else will clean-up your mess 😉
  • FAQ:
    • TODO

get

  • (implementation of driver.get)
  • check dev (dev != NULL and dev->driver == &driver), return -ENODEV on failure
  • check if getting of opt is supported, return -ENOSUP on failure
  • check if *value_len is appropriate for opt, return -EOVERFLOW on failure
    • use *value_len < sizeof(option_type) for array like options (like addresses)
    • use *value_len != sizeof(option_type) for primitive types
  • set *value_len to sizeof(option_type)
  • copy option_value into value
  • return length of parameter on success
  • FAQ:
    • TODO

set

  • (implementation of driver.get)
  • check dev (dev != NULL and dev->driver == &driver), return -ENODEV on failure
  • check if setting of opt is supported, return -ENOSUP on failure
  • check if *value_len is appropriate for opt, return -EOVERFLOW on failure
    • use *value_len < sizeof(option_type) for array like options (like addresses)
    • use *value_len != sizeof(option_type) for primitive types
  • set *value_len to sizeof(option_type)
  • copy option_value into value
  • return length of parameter on success
  • FAQ:
    • TODO
Clone this wiki locally