2022-04-23 05:24:38 +02:00
#![ no_std ]
#![ no_main ]
#![ feature(generic_associated_types) ]
#![ feature(type_alias_impl_trait) ]
use core ::mem ;
use core ::sync ::atomic ::{ AtomicBool , Ordering } ;
use core ::task ::Waker ;
2022-06-12 22:15:44 +02:00
2022-04-23 05:24:38 +02:00
use defmt ::* ;
2022-08-17 23:40:16 +02:00
use embassy_executor ::Spawner ;
2022-05-04 20:48:37 +02:00
use embassy_net ::tcp ::TcpSocket ;
2022-05-23 03:50:43 +02:00
use embassy_net ::{ PacketBox , PacketBoxExt , PacketBuf , Stack , StackResources } ;
use embassy_nrf ::rng ::Rng ;
2022-07-09 08:40:10 +02:00
use embassy_nrf ::usb ::{ Driver , PowerUsb } ;
2022-08-17 18:49:55 +02:00
use embassy_nrf ::{ interrupt , pac , peripherals } ;
2022-04-23 05:24:38 +02:00
use embassy_usb ::{ Builder , Config , UsbDevice } ;
use embassy_usb_ncm ::{ CdcNcmClass , Receiver , Sender , State } ;
2022-07-29 21:58:35 +02:00
use embassy_util ::blocking_mutex ::raw ::ThreadModeRawMutex ;
use embassy_util ::channel ::mpmc ::Channel ;
2022-05-04 20:48:37 +02:00
use embedded_io ::asynch ::{ Read , Write } ;
2022-08-22 15:51:44 +02:00
use static_cell ::StaticCell ;
2022-06-12 22:15:44 +02:00
use { defmt_rtt as _ , panic_probe as _ } ;
2022-04-23 05:24:38 +02:00
2022-07-09 08:40:10 +02:00
type MyDriver = Driver < 'static , peripherals ::USBD , PowerUsb > ;
2022-04-23 05:24:38 +02:00
2022-08-22 15:51:44 +02:00
macro_rules ! singleton {
2022-05-23 03:50:43 +02:00
( $val :expr ) = > { {
type T = impl Sized ;
2022-08-22 15:51:44 +02:00
static STATIC_CELL : StaticCell < T > = StaticCell ::new ( ) ;
STATIC_CELL . init_with ( move | | $val )
2022-05-23 03:50:43 +02:00
} } ;
}
2022-07-29 21:58:35 +02:00
#[ embassy_executor::task ]
2022-04-23 05:24:38 +02:00
async fn usb_task ( mut device : UsbDevice < 'static , MyDriver > ) -> ! {
device . run ( ) . await
}
2022-07-29 21:58:35 +02:00
#[ embassy_executor::task ]
2022-04-23 05:24:38 +02:00
async fn usb_ncm_rx_task ( mut class : Receiver < 'static , MyDriver > ) {
loop {
warn! ( " WAITING for connection " ) ;
LINK_UP . store ( false , Ordering ::Relaxed ) ;
class . wait_connection ( ) . await . unwrap ( ) ;
warn! ( " Connected " ) ;
LINK_UP . store ( true , Ordering ::Relaxed ) ;
loop {
let mut p = unwrap! ( PacketBox ::new ( embassy_net ::Packet ::new ( ) ) ) ;
let n = match class . read_packet ( & mut p [ .. ] ) . await {
Ok ( n ) = > n ,
Err ( e ) = > {
warn! ( " error reading packet: {:?} " , e ) ;
break ;
}
} ;
let buf = p . slice ( 0 .. n ) ;
if RX_CHANNEL . try_send ( buf ) . is_err ( ) {
warn! ( " Failed pushing rx'd packet to channel. " ) ;
}
}
}
}
2022-07-29 21:58:35 +02:00
#[ embassy_executor::task ]
2022-04-23 05:24:38 +02:00
async fn usb_ncm_tx_task ( mut class : Sender < 'static , MyDriver > ) {
loop {
let pkt = TX_CHANNEL . recv ( ) . await ;
if let Err ( e ) = class . write_packet ( & pkt [ .. ] ) . await {
warn! ( " Failed to TX packet: {:?} " , e ) ;
}
}
}
2022-07-29 21:58:35 +02:00
#[ embassy_executor::task ]
2022-05-23 03:50:43 +02:00
async fn net_task ( stack : & 'static Stack < Device > ) -> ! {
stack . run ( ) . await
2022-04-23 05:24:38 +02:00
}
2022-07-29 21:58:35 +02:00
#[ embassy_executor::main ]
2022-08-17 18:49:55 +02:00
async fn main ( spawner : Spawner ) {
let p = embassy_nrf ::init ( Default ::default ( ) ) ;
2022-04-23 05:24:38 +02:00
let clock : pac ::CLOCK = unsafe { mem ::transmute ( ( ) ) } ;
info! ( " Enabling ext hfosc... " ) ;
clock . tasks_hfclkstart . write ( | w | unsafe { w . bits ( 1 ) } ) ;
while clock . events_hfclkstarted . read ( ) . bits ( ) ! = 1 { }
// Create the driver, from the HAL.
let irq = interrupt ::take! ( USBD ) ;
2022-07-09 08:40:10 +02:00
let power_irq = interrupt ::take! ( POWER_CLOCK ) ;
let driver = Driver ::new ( p . USBD , irq , PowerUsb ::new ( power_irq ) ) ;
2022-04-23 05:24:38 +02:00
// 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 ;
struct Resources {
device_descriptor : [ u8 ; 256 ] ,
config_descriptor : [ u8 ; 256 ] ,
bos_descriptor : [ u8 ; 256 ] ,
control_buf : [ u8 ; 128 ] ,
serial_state : State < 'static > ,
}
2022-08-22 15:51:44 +02:00
let res : & mut Resources = singleton! ( Resources {
2022-04-23 05:24:38 +02:00
device_descriptor : [ 0 ; 256 ] ,
config_descriptor : [ 0 ; 256 ] ,
bos_descriptor : [ 0 ; 256 ] ,
control_buf : [ 0 ; 128 ] ,
serial_state : State ::new ( ) ,
} ) ;
// Create embassy-usb DeviceBuilder using the driver and config.
let mut builder = Builder ::new (
driver ,
config ,
& mut res . device_descriptor ,
& mut res . config_descriptor ,
& mut res . bos_descriptor ,
& mut res . control_buf ,
None ,
) ;
// WARNINGS for Android ethernet tethering:
// - On Pixel 4a, it refused to work on Android 11, worked on Android 12.
// - if the host's MAC address has the "locally-administered" bit set (bit 1 of first byte),
// it doesn't work! The "Ethernet tethering" option in settings doesn't get enabled.
// 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
// and this nonsense in the linux kernel: https://github.com/torvalds/linux/blob/c00c5e1d157bec0ef0b0b59aa5482eb8dc7e8e49/drivers/net/usb/usbnet.c#L1751-L1757
// 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 , & mut res . serial_state , host_mac_addr , 64 ) ;
// Build the builder.
let usb = builder . build ( ) ;
unwrap! ( spawner . spawn ( usb_task ( usb ) ) ) ;
let ( tx , rx ) = class . split ( ) ;
unwrap! ( spawner . spawn ( usb_ncm_rx_task ( rx ) ) ) ;
unwrap! ( spawner . spawn ( usb_ncm_tx_task ( tx ) ) ) ;
2022-05-23 03:50:43 +02:00
let config = embassy_net ::ConfigStrategy ::Dhcp ;
//let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
// 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 mut rng = Rng ::new ( p . RNG , interrupt ::take! ( RNG ) ) ;
let mut seed = [ 0 ; 8 ] ;
rng . blocking_fill_bytes ( & mut seed ) ;
let seed = u64 ::from_le_bytes ( seed ) ;
// Init network stack
2022-06-12 22:15:44 +02:00
let device = Device { mac_addr : our_mac_addr } ;
2022-08-22 15:51:44 +02:00
let stack = & * singleton! ( Stack ::new (
2022-05-23 03:50:43 +02:00
device ,
config ,
2022-08-22 15:51:44 +02:00
singleton! ( StackResources ::< 1 , 2 , 8 > ::new ( ) ) ,
2022-05-23 03:50:43 +02:00
seed
) ) ;
unwrap! ( spawner . spawn ( net_task ( stack ) ) ) ;
2022-04-23 05:24:38 +02:00
// And now we can use it!
let mut rx_buffer = [ 0 ; 4096 ] ;
let mut tx_buffer = [ 0 ; 4096 ] ;
let mut buf = [ 0 ; 4096 ] ;
loop {
2022-05-23 03:50:43 +02:00
let mut socket = TcpSocket ::new ( stack , & mut rx_buffer , & mut tx_buffer ) ;
2022-04-23 05:24:38 +02:00
socket . set_timeout ( Some ( embassy_net ::SmolDuration ::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 ;
}
} ;
}
}
}
static TX_CHANNEL : Channel < ThreadModeRawMutex , PacketBuf , 8 > = Channel ::new ( ) ;
static RX_CHANNEL : Channel < ThreadModeRawMutex , PacketBuf , 8 > = Channel ::new ( ) ;
static LINK_UP : AtomicBool = AtomicBool ::new ( false ) ;
struct Device {
mac_addr : [ u8 ; 6 ] ,
}
impl embassy_net ::Device for Device {
fn register_waker ( & mut self , waker : & Waker ) {
// loopy loopy wakey wakey
waker . wake_by_ref ( )
}
fn link_state ( & mut self ) -> embassy_net ::LinkState {
match LINK_UP . load ( Ordering ::Relaxed ) {
true = > embassy_net ::LinkState ::Up ,
false = > embassy_net ::LinkState ::Down ,
}
}
2022-05-23 03:50:43 +02:00
fn capabilities ( & self ) -> embassy_net ::DeviceCapabilities {
2022-04-23 05:24:38 +02:00
let mut caps = embassy_net ::DeviceCapabilities ::default ( ) ;
caps . max_transmission_unit = 1514 ; // 1500 IP + 14 ethernet header
caps . medium = embassy_net ::Medium ::Ethernet ;
caps
}
fn is_transmit_ready ( & mut self ) -> bool {
true
}
fn transmit ( & mut self , pkt : PacketBuf ) {
if TX_CHANNEL . try_send ( pkt ) . is_err ( ) {
warn! ( " TX failed " )
}
}
fn receive < ' a > ( & mut self ) -> Option < PacketBuf > {
RX_CHANNEL . try_recv ( ) . ok ( )
}
2022-05-02 16:15:05 +02:00
fn ethernet_address ( & self ) -> [ u8 ; 6 ] {
2022-04-23 05:24:38 +02:00
self . mac_addr
}
}