Skip to content

Commit 8152b3d

Browse files
committed
Add EMAC driver README.md with porting guide
1 parent 95f6df1 commit 8152b3d

File tree

1 file changed

+185
-0
lines changed

1 file changed

+185
-0
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# mbed OS Ethernet MAC (EMAC) drivers
2+
3+
This document describes how to port and test an Ethernet MAC (EMAC) driver to
4+
mbed OS. It is based on work on the feature-emac branch as of mbed OS 5.8,
5+
which is intended to be merged into mbed OS 5.9
6+
7+
The scope of this document is limited to Ethernet (IEEE 802.3) or Ethernet-like
8+
devices such as Wi-Fi (IEEE 802.11), where the device presents a MAC interface
9+
to send and receive frames, and this will be used by one of the onboard
10+
network stacks that runs on mbed OS on the host processor.
11+
12+
(If the device has an off-board network stack, a driver would need to implement
13+
`NetworkStack` directly instead to pass network calls to that offboard
14+
stack).
15+
16+
## Abstractions
17+
18+
The EMAC interface is designed to abstract network stacks and drivers, and to
19+
easily permit multiple instances. The key API classes are:
20+
21+
* `NetworkInterface` - an mbed OS network interface of any type
22+
* `NetworkStack` - an mbed OS network stack of any type (may be off-board)
23+
* `OnboardNetworkStack` - an on-board network stack
24+
* `EMAC` - an Ethernet MAC device driver
25+
* `EMACMemoryManager` - a memory manager used to pass data between driver and stack
26+
* `EMACInterface`- a `NetworkInterface` that uses an `EMAC` driver and an `OnboardNetworkStack`
27+
28+
## The EMAC driver core
29+
30+
The first step in the port is to create a driver class that can be instantiated
31+
to control your device. This must be derived from class `EMAC`.
32+
This API is used by a network stack (or test framework) to control your driver.
33+
34+
The EMAC-derived driver would normally be installed in
35+
features/netsocket/emac-drivers, often in a `TARGET_XXX` directory.
36+
37+
Class EMAC is entirely abstract - you need to implement about a dozen calls
38+
to activate the driver, send and receive packets, and perform other control
39+
and information functions.
40+
41+
There are also callback registration functions for upcalls from the driver - the
42+
stack can register callback functions for packet reception and link status
43+
changes.
44+
45+
46+
## The EMAC memory manager
47+
48+
For the send and receive paths, data is transferred in memory buffers controlled
49+
via an `EMACMemoryManager` object. The network stack using an EMAC driver
50+
provides it with a reference to the memory manager in use before powering up -
51+
this will be constant as long as the EMAC is powered up.
52+
53+
On the output call, the EMAC driver is given ownership of a buffer chain - it
54+
must free the chain when it has finished with the data. The data may or may
55+
not be contiguous. A driver can express alignment preferences for outgoing data,
56+
but the network stack is not required to meet these prefernces, so a driver
57+
relying on alignment may need a slow path that copies data into an aligned
58+
(or contiguous) buffer.
59+
60+
For reception, the EMAC driver must allocate memory from the `EMACMemoryManager`
61+
to store the received packets - this is then passed to the link input callback,
62+
which will free it. By preference this memory should be allocated using the pool,
63+
but if contiguous memory is required it can be allocated from the heap.
64+
65+
66+
## EthernetInterface
67+
68+
If your driver is a pure Ethernet driver, there is no further implementation
69+
required. The class `EthernetInterface` can use any `EMAC` driver to provide
70+
an mbed OS `NetworkInterface`:
71+
72+
MyEMAC my_emac(params);
73+
EthernetInterface net(&my_emac);
74+
75+
net.connect();
76+
77+
This will attach the default network stack (normally lwIP - the other
78+
current alternative is Nanostack) to the specified EMAC driver, and provide all
79+
the generic `NetworkInterface` and `NetworkStack` APIs.
80+
81+
## Being the default EMAC / EthernetInterface
82+
83+
To make your EMAC the default for applications you should define the static function
84+
`EMAC::get_default_instance()` to return an instance of your emac, eg:
85+
86+
MBED_WEAK EMAC &EMAC::get_default_instance()
87+
{
88+
static MyEMAC my_emac(params);
89+
return &my_emac;
90+
}
91+
92+
This permits this example application code to work:
93+
94+
EthernetInterface net; // uses EMAC::get_default_instance()
95+
net.connect();
96+
97+
This definition would normally be gated by a target label of some sort. As
98+
target code, your definition of EMAC::get_default_instance() must be weak -
99+
this permits it to be overridden by application code.
100+
101+
## Wi-Fi interfaces
102+
103+
As a Wi-Fi interface, a little more work is required - at a minimum you need
104+
to implement the extra configuration calls in `WiFiInterface`. This
105+
is because the network stacks and EMAC APIs are only related to the
106+
Ethernet-like data path - they have no knowledge of any other configuration
107+
mechanisms and assume they are already set up.
108+
109+
To do this, you should create a C++ class that inherits from both
110+
`WiFiInterface` and `EMACInterface`. The `EMACInterface` is a helper class
111+
that implements all the core `NetworkInterface` functionality for you. You
112+
then just need to implement the extra `WiFiInterface` configuration methods.
113+
114+
For reference, note that `EthernetInterface` also derives from
115+
`EMACInterface`, but has no extra code as there is no extra configuration
116+
required.
117+
118+
As a Wi-fi driver, you will not normally be directly exposing your `EMAC` class -
119+
it would not normally be declared as `EMAC::get_default_instance`, but you
120+
would pass it to the constructor of your base `EMACInterface`. This then
121+
will make it visible via the `get_emac` method. This is for test purposes,
122+
meaning the test framework can do:
123+
124+
MyWiFiInterface net;
125+
net.set_credentials();
126+
EMAC &emac = net.get_emac();
127+
do_emac_test(emac);
128+
129+
This must work in your driver - it must be possible to power up and use the
130+
built-in EMAC directly without the `NetworkInterface::connect()` method being
131+
invoked, as long as the credentials have been set. This structure will come naturally if
132+
you just use the default `EMACInterface::connect()` implementation.
133+
134+
Note also that your constructor must allow the network stack to be specified using
135+
the same form as `EthernetInterface`:
136+
137+
MyWiFiInterface(OnboardNetworkStack &stack = OnboardNetworkStack::get_default_instance());
138+
139+
## OnboardNetworkStack
140+
141+
The precise details of the `OnboardNetworkStack` API should not concern
142+
an EMAC driver writer - it provides the mechanism to bind a driver to a stack, and
143+
the APIs needed to implement a `NetworkInterface`, but this is handled by
144+
`EMACInterface`, either as a base class of your own `XXXInterface` or as
145+
the base of `EthernetInterface`.
146+
147+
## DEVICE_EMAC
148+
149+
At present, as an interim measure, targets providing `EMAC::get_default_instance()`
150+
should add "EMAC" in `device_has` in their `targets.json`. This activates
151+
network tests in CI builds.
152+
153+
This is subject to change, but is necessary in lieu of the previous typical
154+
behaviour of gating tests on `FEATURE_LWIP`.
155+
156+
## Tuning memory allocations
157+
158+
Depending on its use of pool and heap memory, and other factors, a driver might
159+
want to tune the configuration of particular network stacks. This can be done via
160+
the `mbed_lib.json` of each network stack, using their `target_overrides`
161+
section.
162+
163+
## Testing
164+
165+
The mbed OS tree contains Greentea-based tests that exercise the EMAC API
166+
directly, and more general socket tests.
167+
168+
See here for general Greentea information: <https://github.com/ARMmbed/greentea>
169+
170+
See here for the emac tests:
171+
<https://github.com/ARMmbed/mbed-os/tree/feature-emac/TESTS/network/emac>
172+
173+
Greentea socket tests are at:
174+
<https://github.com/ARMmbed/mbed-os/tree/feature-emac/TESTS/netsocket>
175+
176+
The driver should also be exercised with real-world examples like
177+
<https://github.com/ARMmbed/mbed-os-example-client>
178+
179+
The driver should also be tested with both network stacks available in mbed OS,
180+
as they will use the driver somewhat differently - try with the JSON option
181+
`nsapi.default-stack` set to each of `LWIP` and `NANOSTACK`.
182+
183+
Nanostack is IPv6 only. IPv6 operation should also be tested with lwIP, as this
184+
is likely to reveal problems with multicast filtering that may not be spotted
185+
by IPv4 or Nanostack.

0 commit comments

Comments
 (0)