Setting up smoltcp
1. Adding smoltcp
to your Cargo.toml
To use smoltcp
in your project, you must add it as a dependency in the Cargo.toml
file.
smoltcp
uses a lot of feature flags for configuration and therefore the correct ones need to be added.
Depending on the medium that is used, at least one of the following features must be enabled:
medium-ethernet
for Ethernet devices;medium-ieee802154
for IEEE802.15.4 devices. Enabling this feature, also enablesproto-sixlowpan
;medium-ip
for devices without medium.
For the network layer, at least one of the following features must be enabled:
proto-ipv4
for IPv4;proto-ipv6
for IPv6;proto-sixlowpan
for 6LoWPAN.
There are many more feature flags that can be enabled. For more information, see the documentation.
For a IEEE802.15.4 device using 6LoWPAN and RPL, the following is added in the Cargo.toml
file:
[dependencies.smoltcp]
version = "0.10"
default-features = false
features = [
"medium-ieee802154",
"proto-sixlowpan",
"rpl-mop-2"
]
This will use RPL with MOP 2 (Storing Mode of Operation) and 6LoWPAN with the IEEE802.15.4 medium.
These are the available modes of operation: rpl-mop-0
, rpl-mop-1
, rpl-mop-2
and rpl-mop-3
.
2. Implementing smoltcp::phy::Device
for your platform
In order for smoltcp
to effectively handle incoming and outgoing packets,
a connection must be established between the TCP/IP stack and the underlying hardware.
This essential linkage is achieved by implementing the smoltcp::phy::Device
trait for the hardware:
#![allow(unused)] fn main() { extern crate smoltcp; use smoltcp::phy::DeviceCapabilities; pub trait RxToken { fn consume<R, F>(self, f: F) -> R where F: FnOnce(&mut [u8]) -> R; } pub trait TxToken { fn consume<R, F>(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R; } pub trait Device { type RxToken<'a>: RxToken where Self: 'a; type TxToken<'a>: TxToken where Self: 'a; fn receive(&mut self, timestamp: Instant) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)>; fn transmit(&mut self, timestamp: Instant) -> Option<Self::TxToken<'_>>; fn capabilities(&self) -> DeviceCapabilities; } }
3. Setting up the smoltcp
stack
Once you have the Device
trait implemented, an Interface
can be created.
The Interface
is the main entry point for the smoltcp
stack.
It is responsible for handling incoming and outgoing packets, as well as managing the sockets.
The Interface
is created by passing a Config
and a Device
to the new
function.
The Config
struct contains all the configuration options for the stack.
The MyDevice
is the hardware abstraction layer that was implemented in the previous step.
extern crate smoltcp; use smoltcp::wire::*; use smoltcp::iface::{Interface, Config}; use smoltcp::socket::{SocketSet, SocketStorage}; fn main() { // Get the MAC address from the device: let mac_adddr = Ieee802154Address::Extended([0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8]); // Create the device: let mut device = MyDevice::new(mac_adddr); // Create the configuration for the stack: let mut config = Config::new(mac_addr.into()); config.pan_id = Some(Ieee802154Pan(0xbeef)); // Create the sockets: let mut sockets_buffer = [SocketStorage::EMPTY; 1]; let mut sockets = SocketSet::new(&mut sockets_buffer[..]); // Create the interface: let mut iface = Interface::new(config, device)?; }
4. Polling the smoltcp
stack
The interface is now ready to be used.
Polling the interface will handle incoming and outgoing packets.
For the interface to continue working, it must be polled regularly.
This is done by calling the poll
function on the interface.
If a packet is received, it is queued by the device and can be handled by the stack.
After processing the packet, the stack might have to send a packet.
Calling poll_at
on the interface returns the time when the next poll
should be called.
Calling poll
before that time is only wasting energy, but is not harmful for the stack.
Calling poll
after that duration might be harmful for the stack.
#![allow(unused)] fn main() { loop { iface.poll(now, device, sockets); match iface.poll_at(Instant::now()) { Some(Instant::ZERO) => continue, Some(d) => sleep(d), None => sleep_until_new_packet(), } } }
5. You're all set 🎉 (for now)
That's it! There is nothing more that needs to be done!
The smoltcp
stack will now handle all incoming and outgoing packets.
The next step is to create sockets and use them to send and receive data.