-
Notifications
You must be signed in to change notification settings - Fork 2.1k
How to implement a `ng_netdev` enabled device
The following sections describe how to implement a ng_netdev enabled device.
- An instance of
ng_netdev_driver_tthat references your functions (as they are described below). - An extension of
ng_netdev_t(an instance of this will be called the device descriptor)- You can extend a struct by adding the following members
-
ng_netdev_driver_t *driver(required, must be a pointer to yourng_netdev_driver_tinstance above) -
ng_netdev_event_cb_t event_cb(required) -
kernel_pid_t mac_pid(required) - add additional members as you like (e.g. your configuration options or information of the states)
-
- You can extend a struct by adding the following members
- Your device needs an initialization function which has the device instance as an out parameter
- set driver to the
ng_netdev_driver_tinstance of your device - set your configuration options to there initial default value
- if you have to initialize the hardware address, take it from a node-unique source like
periph/cpuid. - remember to set the universal/local-bit for EUI-48 and EUI-64 to local!
- remember to set the individual/group-bit for EUI-48 and EUI-64 to individual!
- if you have to initialize the hardware address, take it from a node-unique source like
- do any initialization routine your device needs
-
(implementation of
driver.add_event_callback) -
the implementation is pretty much always the same:
static int _add_cb(ng_netdev_t *dev, ng_netdev_event_cb_t cb) { if ((dev == NULL) || (dev->driver != &ng_tapnet_driver)) { return -ENODEV; } if (dev->event_cb != NULL) { return -ENOBUFS; } dev->event_cb = cb; return 0; }
-
(implementation of
driver.rem_event_callback) -
the implementation is pretty much always the same:
static int _remove_cb(ng_netdev_t *dev, ng_netdev_event_cb_t cb) { if ((dev == NULL) || (dev->driver != &ng_tapnet_driver)) { return -ENODEV; } if (dev->event_cb != NULL) { return -ENOBUFS; } dev->event_cb = cb; return 0; }
-
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
msgtodev->mac_pid(event handler thread) withmsg.type == NG_NETDEV_MSG_TYPE_EVENT msg.content.value = event_type msg_send(&msg, dev->mac_pid);
-
-
in thread
dev->mac_pid(devis 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 != NULLanddev->driver == &driver) - call event handlers
_event_<event_type>()for event according to event
- check
-
FAQ:
- TODO
TODO
-
read received data
data(of lengthdata_len) from device -
add
ng_netif_hdr_twith both sourcel2src(of lengthl2src_len) and destination addressl2_dest(of lengthl2dst_len) tong_pktbufng_pktsnip_t *hdr = ng_netif_hdr_build(l2src, l2src_len, l2dst, l2dst_len); if (hdr == NULL) { DEBUG("Packet buffer full.\n"); return; } 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_typecan be a fixed value (e.g.NG_NETTYPE_SIXLOWPANfor 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(NULL, data + L2_HDR_LEN, data_len, demux_type); pkt->next = hdr; if (pkt == NULL) { DEBUG("Packet buffer full.\n"); ng_pktbuf_release(hdr_snip); return; } -
call callback event handler with
pktas 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
TODO
TODO
-
(implementation of
driver.send_data) -
check if
pkt != NULL, return-EFAULTon failure -
check
dev(dev != NULLanddev->driver == &driver)- on failure: release
pktreturn-ENODEV
- on failure: release
-
build device header from
netif_hdr(is first header inpkt) -
put device header in out buffer
-
put rest of
pktout bufferout_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
- (implementation of
driver.get) - check
dev(dev != NULLanddev->driver == &driver), return -ENODEV on failure - check if getting of
optis supported, return-ENOSUPon failure - check if
*value_lenis appropriate foropt, 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
- use
- set
*value_lentosizeof(option_type) - copy
option_valueintovalue - return length of parameter on success
-
FAQ:
- TODO
- (implementation of
driver.set) - check
dev(dev != NULLanddev->driver == &driver), return -ENODEV on failure - check if setting of
optis supported, return-ENOSUPon failure - check if
*value_lenis appropriate foropt, 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
- use
- set
*value_lentosizeof(option_type) - copy
option_valueintovalue - return length of parameter on success
-
FAQ:
- TODO