-
Notifications
You must be signed in to change notification settings - Fork 2k
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_t
that 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) -
ng_netdev_event_cb_t event_cb
(required) -
ng_netdev_driver_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_t
instance 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 _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; }
# remove event callback
* *(implementation of [`driver.rem_event_callback`](http://riot-os.org/api/structng__netdev__driver__t.html#a04583d4d29e2e11b1f6ad0557ed2a576))*
* the implementation is pretty much always the same:
``` {.c}
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;
}
-
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
todev->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
(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
anddev->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_t
with both sourcel2src
(of lengthl2src_len
) and destination addressl2_dest
(of lengthl2dst_len
) tong_pktbuf
ng_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_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(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
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
TODO
TODO
-
(implementation of
driver.send_data
) -
check if
pkt != NULL
, return-EFAULT
on failure -
check
dev
(dev != NULL
anddev->driver == &driver
)- on failure: release
pkt
return-ENODEV
- on failure: release
-
build device header from
netif_hdr
(is first header inpkt
) -
put device header in out buffer
-
put rest of
pkt
out 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 != NULL
anddev->driver == &driver
), return -ENODEV on failure - check if getting of
opt
is supported, return-ENOSUP
on failure - check if
*value_len
is 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_len
tosizeof(option_type)
- copy
option_value
intovalue
- return length of parameter on success
-
FAQ:
- TODO
- (implementation of
driver.set
) - check
dev
(dev != NULL
anddev->driver == &driver
), return -ENODEV on failure - check if setting of
opt
is supported, return-ENOSUP
on failure - check if
*value_len
is 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_len
tosizeof(option_type)
- copy
option_value
intovalue
- return length of parameter on success
-
FAQ:
- TODO