aboutsummaryrefslogtreecommitdiff
path: root/examples/rp/src/bin/usb_ethernet.rs
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-08-24 23:46:07 +0200
committerDario Nieuwenhuis <[email protected]>2022-08-25 00:03:55 +0200
commita730e2cd0f4f282a78cc5d9897c584ec4f5a44a3 (patch)
treebae14ab23330d99b06c462746615dc2efbc45ad8 /examples/rp/src/bin/usb_ethernet.rs
parentf11aa9720be6b5f608becb3472e4fd13de324080 (diff)
rp: add usb device support.
Diffstat (limited to 'examples/rp/src/bin/usb_ethernet.rs')
-rw-r--r--examples/rp/src/bin/usb_ethernet.rs264
1 files changed, 264 insertions, 0 deletions
diff --git a/examples/rp/src/bin/usb_ethernet.rs b/examples/rp/src/bin/usb_ethernet.rs
new file mode 100644
index 000000000..2cb0010f1
--- /dev/null
+++ b/examples/rp/src/bin/usb_ethernet.rs
@@ -0,0 +1,264 @@
1#![no_std]
2#![no_main]
3#![feature(generic_associated_types)]
4#![feature(type_alias_impl_trait)]
5
6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::Waker;
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_net::tcp::TcpSocket;
12use embassy_net::{PacketBox, PacketBoxExt, PacketBuf, Stack, StackResources};
13use embassy_rp::usb::Driver;
14use embassy_rp::{interrupt, peripherals};
15use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex;
16use embassy_sync::channel::Channel;
17use embassy_usb::{Builder, Config, UsbDevice};
18use embassy_usb_ncm::{CdcNcmClass, Receiver, Sender, State};
19use embedded_io::asynch::{Read, Write};
20use static_cell::StaticCell;
21use {defmt_rtt as _, panic_probe as _};
22
23type MyDriver = Driver<'static, peripherals::USB>;
24
25macro_rules! singleton {
26 ($val:expr) => {{
27 type T = impl Sized;
28 static STATIC_CELL: StaticCell<T> = StaticCell::new();
29 STATIC_CELL.init_with(move || $val)
30 }};
31}
32
33#[embassy_executor::task]
34async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
35 device.run().await
36}
37
38#[embassy_executor::task]
39async fn usb_ncm_rx_task(mut class: Receiver<'static, MyDriver>) {
40 loop {
41 warn!("WAITING for connection");
42 LINK_UP.store(false, Ordering::Relaxed);
43
44 class.wait_connection().await.unwrap();
45
46 warn!("Connected");
47 LINK_UP.store(true, Ordering::Relaxed);
48
49 loop {
50 let mut p = unwrap!(PacketBox::new(embassy_net::Packet::new()));
51 let n = match class.read_packet(&mut p[..]).await {
52 Ok(n) => n,
53 Err(e) => {
54 warn!("error reading packet: {:?}", e);
55 break;
56 }
57 };
58
59 let buf = p.slice(0..n);
60 if RX_CHANNEL.try_send(buf).is_err() {
61 warn!("Failed pushing rx'd packet to channel.");
62 }
63 }
64 }
65}
66
67#[embassy_executor::task]
68async fn usb_ncm_tx_task(mut class: Sender<'static, MyDriver>) {
69 loop {
70 let pkt = TX_CHANNEL.recv().await;
71 if let Err(e) = class.write_packet(&pkt[..]).await {
72 warn!("Failed to TX packet: {:?}", e);
73 }
74 }
75}
76
77#[embassy_executor::task]
78async fn net_task(stack: &'static Stack<Device>) -> ! {
79 stack.run().await
80}
81
82#[embassy_executor::main]
83async fn main(spawner: Spawner) {
84 let p = embassy_rp::init(Default::default());
85
86 // Create the driver, from the HAL.
87 let irq = interrupt::take!(USBCTRL_IRQ);
88 let driver = Driver::new(p.USB, irq);
89
90 // Create embassy-usb Config
91 let mut config = Config::new(0xc0de, 0xcafe);
92 config.manufacturer = Some("Embassy");
93 config.product = Some("USB-Ethernet example");
94 config.serial_number = Some("12345678");
95 config.max_power = 100;
96 config.max_packet_size_0 = 64;
97
98 // Required for Windows support.
99 config.composite_with_iads = true;
100 config.device_class = 0xEF;
101 config.device_sub_class = 0x02;
102 config.device_protocol = 0x01;
103
104 struct Resources {
105 device_descriptor: [u8; 256],
106 config_descriptor: [u8; 256],
107 bos_descriptor: [u8; 256],
108 control_buf: [u8; 128],
109 serial_state: State<'static>,
110 }
111 let res: &mut Resources = singleton!(Resources {
112 device_descriptor: [0; 256],
113 config_descriptor: [0; 256],
114 bos_descriptor: [0; 256],
115 control_buf: [0; 128],
116 serial_state: State::new(),
117 });
118
119 // Create embassy-usb DeviceBuilder using the driver and config.
120 let mut builder = Builder::new(
121 driver,
122 config,
123 &mut res.device_descriptor,
124 &mut res.config_descriptor,
125 &mut res.bos_descriptor,
126 &mut res.control_buf,
127 None,
128 );
129
130 // WARNINGS for Android ethernet tethering:
131 // - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
132 // - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
133 // it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
134 // This is due to regex spaghetti: https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r84/core/res/res/values/config.xml#417
135 // and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
136
137 // Our MAC addr.
138 let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
139 // Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
140 let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
141
142 // Create classes on the builder.
143 let class = CdcNcmClass::new(&mut builder, &mut res.serial_state, host_mac_addr, 64);
144
145 // Build the builder.
146 let usb = builder.build();
147
148 unwrap!(spawner.spawn(usb_task(usb)));
149
150 let (tx, rx) = class.split();
151 unwrap!(spawner.spawn(usb_ncm_rx_task(rx)));
152 unwrap!(spawner.spawn(usb_ncm_tx_task(tx)));
153
154 let config = embassy_net::ConfigStrategy::Dhcp;
155 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
156 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
157 // dns_servers: Vec::new(),
158 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
159 //});
160
161 // Generate random seed
162 let seed = 1234; // guaranteed random, chosen by a fair dice roll
163
164 // Init network stack
165 let device = Device { mac_addr: our_mac_addr };
166 let stack = &*singleton!(Stack::new(
167 device,
168 config,
169 singleton!(StackResources::<1, 2, 8>::new()),
170 seed
171 ));
172
173 unwrap!(spawner.spawn(net_task(stack)));
174
175 // And now we can use it!
176
177 let mut rx_buffer = [0; 4096];
178 let mut tx_buffer = [0; 4096];
179 let mut buf = [0; 4096];
180
181 loop {
182 let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
183 socket.set_timeout(Some(embassy_net::SmolDuration::from_secs(10)));
184
185 info!("Listening on TCP:1234...");
186 if let Err(e) = socket.accept(1234).await {
187 warn!("accept error: {:?}", e);
188 continue;
189 }
190
191 info!("Received connection from {:?}", socket.remote_endpoint());
192
193 loop {
194 let n = match socket.read(&mut buf).await {
195 Ok(0) => {
196 warn!("read EOF");
197 break;
198 }
199 Ok(n) => n,
200 Err(e) => {
201 warn!("read error: {:?}", e);
202 break;
203 }
204 };
205
206 info!("rxd {:02x}", &buf[..n]);
207
208 match socket.write_all(&buf[..n]).await {
209 Ok(()) => {}
210 Err(e) => {
211 warn!("write error: {:?}", e);
212 break;
213 }
214 };
215 }
216 }
217}
218
219static TX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
220static RX_CHANNEL: Channel<ThreadModeRawMutex, PacketBuf, 8> = Channel::new();
221static LINK_UP: AtomicBool = AtomicBool::new(false);
222
223struct Device {
224 mac_addr: [u8; 6],
225}
226
227impl embassy_net::Device for Device {
228 fn register_waker(&mut self, waker: &Waker) {
229 // loopy loopy wakey wakey
230 waker.wake_by_ref()
231 }
232
233 fn link_state(&mut self) -> embassy_net::LinkState {
234 match LINK_UP.load(Ordering::Relaxed) {
235 true => embassy_net::LinkState::Up,
236 false => embassy_net::LinkState::Down,
237 }
238 }
239
240 fn capabilities(&self) -> embassy_net::DeviceCapabilities {
241 let mut caps = embassy_net::DeviceCapabilities::default();
242 caps.max_transmission_unit = 1514; // 1500 IP + 14 ethernet header
243 caps.medium = embassy_net::Medium::Ethernet;
244 caps
245 }
246
247 fn is_transmit_ready(&mut self) -> bool {
248 true
249 }
250
251 fn transmit(&mut self, pkt: PacketBuf) {
252 if TX_CHANNEL.try_send(pkt).is_err() {
253 warn!("TX failed")
254 }
255 }
256
257 fn receive<'a>(&mut self) -> Option<PacketBuf> {
258 RX_CHANNEL.try_recv().ok()
259 }
260
261 fn ethernet_address(&self) -> [u8; 6] {
262 self.mac_addr
263 }
264}