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:

    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

    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:

    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 😉

  • 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)

    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