embassy/examples/rp/src/bin/usb_ethernet.rs
bors[bot] 1a87f7477a
Merge #1458
1458: rp: remove take!, add bind_interrupts! r=Dirbaio a=pennae

both of the uart interrupts now check a flag that only the dma rx path ever sets (and now unsets again on drop) to return early if it's not as they expect. this is ... not our preferred solution, but if bind_interrupts *must* allow mutiple handlers to be specified then this is the only way we can think of that doesn't break uarts.

Co-authored-by: pennae <github@quasiparticle.net>
2023-05-15 15:59:30 +00:00

156 lines
4.6 KiB
Rust

#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_net::tcp::TcpSocket;
use embassy_net::{Stack, StackResources};
use embassy_rp::peripherals::USB;
use embassy_rp::usb::{Driver, InterruptHandler};
use embassy_rp::{bind_interrupts, peripherals};
use embassy_usb::class::cdc_ncm::embassy_net::{Device, Runner, State as NetState};
use embassy_usb::class::cdc_ncm::{CdcNcmClass, State};
use embassy_usb::{Builder, Config, UsbDevice};
use embedded_io::asynch::Write;
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
USBCTRL_IRQ => InterruptHandler<USB>;
});
type MyDriver = Driver<'static, peripherals::USB>;
macro_rules! singleton {
($val:expr) => {{
type T = impl Sized;
static STATIC_CELL: StaticCell<T> = StaticCell::new();
let (x,) = STATIC_CELL.init(($val,));
x
}};
}
const MTU: usize = 1514;
#[embassy_executor::task]
async fn usb_task(mut device: UsbDevice<'static, MyDriver>) -> ! {
device.run().await
}
#[embassy_executor::task]
async fn usb_ncm_task(class: Runner<'static, MyDriver, MTU>) -> ! {
class.run().await
}
#[embassy_executor::task]
async fn net_task(stack: &'static Stack<Device<'static, MTU>>) -> ! {
stack.run().await
}
#[embassy_executor::main]
async fn main(spawner: Spawner) {
let p = embassy_rp::init(Default::default());
// Create the driver, from the HAL.
let driver = Driver::new(p.USB, Irqs);
// Create embassy-usb Config
let mut config = Config::new(0xc0de, 0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("USB-Ethernet example");
config.serial_number = Some("12345678");
config.max_power = 100;
config.max_packet_size_0 = 64;
// Required for Windows support.
config.composite_with_iads = true;
config.device_class = 0xEF;
config.device_sub_class = 0x02;
config.device_protocol = 0x01;
// Create embassy-usb DeviceBuilder using the driver and config.
let mut builder = Builder::new(
driver,
config,
&mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..],
&mut singleton!([0; 256])[..],
&mut singleton!([0; 128])[..],
);
// Our MAC addr.
let our_mac_addr = [0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC];
// Host's MAC addr. This is the MAC the host "thinks" its USB-to-ethernet adapter has.
let host_mac_addr = [0x88, 0x88, 0x88, 0x88, 0x88, 0x88];
// Create classes on the builder.
let class = CdcNcmClass::new(&mut builder, singleton!(State::new()), host_mac_addr, 64);
// Build the builder.
let usb = builder.build();
unwrap!(spawner.spawn(usb_task(usb)));
let (runner, device) = class.into_embassy_net_device::<MTU, 4, 4>(singleton!(NetState::new()), our_mac_addr);
unwrap!(spawner.spawn(usb_ncm_task(runner)));
let config = embassy_net::Config::Dhcp(Default::default());
//let config = embassy_net::Config::Static(embassy_net::StaticConfig {
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
// dns_servers: Vec::new(),
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
//});
// Generate random seed
let seed = 1234; // guaranteed random, chosen by a fair dice roll
// Init network stack
let stack = &*singleton!(Stack::new(device, config, singleton!(StackResources::<2>::new()), seed));
unwrap!(spawner.spawn(net_task(stack)));
// And now we can use it!
let mut rx_buffer = [0; 4096];
let mut tx_buffer = [0; 4096];
let mut buf = [0; 4096];
loop {
let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
info!("Listening on TCP:1234...");
if let Err(e) = socket.accept(1234).await {
warn!("accept error: {:?}", e);
continue;
}
info!("Received connection from {:?}", socket.remote_endpoint());
loop {
let n = match socket.read(&mut buf).await {
Ok(0) => {
warn!("read EOF");
break;
}
Ok(n) => n,
Err(e) => {
warn!("read error: {:?}", e);
break;
}
};
info!("rxd {:02x}", &buf[..n]);
match socket.write_all(&buf[..n]).await {
Ok(()) => {}
Err(e) => {
warn!("write error: {:?}", e);
break;
}
};
}
}
}