Skip to content

Commit

Permalink
Add w5500-evb-pico support
Browse files Browse the repository at this point in the history
A few other bits of tidying too
  • Loading branch information
mkj committed Jun 20, 2023
1 parent 0d64eb7 commit 3d02cc4
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 74 deletions.
14 changes: 13 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.2.0-alpha"
edition = "2021"
description = "A SSH library suitable for embedded and larger programs"
repository = "https://github.com/mkj/sunset"
categories = ["network-programming", "no-std"]
categories = ["network-programming", "embedded", "no-std"]
license = "MPL-2.0"
keywords = ["ssh"]

Expand Down Expand Up @@ -99,6 +99,7 @@ embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "ae8

cyw43 = { git = "https://github.com/embassy-rs/embassy/", rev = "ae83e6f5367197feb8361b9a28adbdedbe37e0c5" }
cyw43-pio = { git = "https://github.com/embassy-rs/embassy/", rev = "ae83e6f5367197feb8361b9a28adbdedbe37e0c5" }
embassy-net-w5500 = { git = "https://github.com/embassy-rs/embassy/", rev = "ae83e6f5367197feb8361b9a28adbdedbe37e0c5" }

bcrypt = { version = "0.14", git = "https://github.com/mkj/rust-bcrypt", branch = "noalloc" }

Expand Down
55 changes: 35 additions & 20 deletions embassy/demos/common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,27 @@ pub struct SSHConfig {
pub wifi_net: String<32>,
/// WPA2 passphrase. None is Open network.
pub wifi_pw: Option<String<63>>,

pub mac: [u8; 6],
}

fn random_mac() -> Result<[u8; 6]> {
let mut mac = [0u8; 6];
sunset::random::fill_random(&mut mac)?;
// unicast, locally administered
mac[0] = (mac[0] & 0xfc) | 0x02;
Ok(mac)
}


impl SSHConfig {
/// Bump this when the format changes
pub const CURRENT_VERSION: u8 = 4;
pub const CURRENT_VERSION: u8 = 5;
/// A buffer this large will fit any SSHConfig.
// It can be updated by looking at
// `cargo test -- roundtrip_config --show-output`
pub const BUF_SIZE: usize = 443;
// `cargo test -- roundtrip_config`
// in the demos/common directory
pub const BUF_SIZE: usize = 449;

/// Creates a new config with default parameters.
///
Expand All @@ -68,6 +80,7 @@ impl SSHConfig {

let wifi_net = option_env!("WIFI_NET").unwrap_or("guest").into();
let wifi_pw = option_env!("WIFI_PW").map(|p| p.into());
let mac = random_mac()?;
Ok(SSHConfig {
hostkey,
console_pw: None,
Expand All @@ -77,6 +90,7 @@ impl SSHConfig {
admin_keys: Default::default(),
wifi_net,
wifi_pw,
mac,
})
}

Expand Down Expand Up @@ -143,28 +157,25 @@ impl SSHEncode for SSHConfig {
info!("enc si");
enc_signkey(&self.hostkey, s)?;

info!("enc pw");
enc_option(&self.console_pw, s)?;

for k in self.console_keys.iter() {
info!("enc k");
enc_option(k, s)?;
}

self.console_noauth.enc(s)?;

info!("enc ad");
enc_option(&self.admin_pw, s)?;

for k in self.admin_keys.iter() {
info!("enc ke");
enc_option(k, s)?;
}

info!("enc net");
self.wifi_net.as_str().enc(s)?;
info!("enc netpw");
enc_option(&self.wifi_pw, s)?;

self.mac.enc(s)?;

Ok(())
}
}
Expand All @@ -174,34 +185,29 @@ impl<'de> SSHDecode<'de> for SSHConfig {
where
S: SSHSource<'de>,
{
info!("dec si");
let hostkey = dec_signkey(s)?;

info!("dec pw");
let console_pw = dec_option(s)?;

let mut console_keys = [None, None, None];
for k in console_keys.iter_mut() {
info!("dec k");
*k = dec_option(s)?;
}

let console_noauth = SSHDecode::dec(s)?;

info!("dec ad");
let admin_pw = dec_option(s)?;

let mut admin_keys = [None, None, None];
for k in admin_keys.iter_mut() {
info!("dec adk");
*k = dec_option(s)?;
}

info!("dec wn");
let wifi_net = SSHDecode::dec(s)?;
info!("dec wp");
let wifi_pw = dec_option(s)?;

let mac = SSHDecode::dec(s)?;

Ok(Self {
hostkey,
console_pw,
Expand All @@ -211,6 +217,7 @@ impl<'de> SSHDecode<'de> for SSHConfig {
admin_keys,
wifi_net,
wifi_pw,
mac,
})
}
}
Expand Down Expand Up @@ -289,12 +296,12 @@ mod tests {
let mut buf = [0u8; 1000];
let l = sshwire::write_ssh(&mut buf, &c1).unwrap();
let v = &buf[..l];
let c2: SSHConfig = sshwire::read_ssh(&buf, None).unwrap();
let c2: SSHConfig = sshwire::read_ssh(v, None).unwrap();
assert_eq!(c1, c2);

// All the fruit, to check BUF_SIZE.
// Variable length fields are all max size.
let mut c1 = SSHConfig {
let c1 = SSHConfig {
hostkey: c1.hostkey,
console_pw: Some(PwHash::new("zong").unwrap()),
console_keys: [
Expand All @@ -313,13 +320,21 @@ mod tests {
wifi_pw: Some(
core::str::from_utf8([b'f'; 63].as_slice()).unwrap().into(),
),
mac: [6,2,3,4,5,6],
};

let mut buf = [0u8; SSHConfig::BUF_SIZE];
// test once to determine size to print
let mut buf = [0u8; 3000];
let l = sshwire::write_ssh(&mut buf, &c1).unwrap();
let size_msg = format!("BUF_SIZE must be at least {}", l);
println!("{size_msg}");

// now test for real
let mut buf = [0u8; SSHConfig::BUF_SIZE];
let l = sshwire::write_ssh(&mut buf, &c1).expect(&size_msg);
println!("BUF_SIZE must be at least {}", l);
let v = &buf[..l];
let c2: SSHConfig = sshwire::read_ssh(&buf, None).unwrap();
let c2: SSHConfig = sshwire::read_ssh(v, None).unwrap();
assert_eq!(c1, c2);
}
}
17 changes: 12 additions & 5 deletions embassy/demos/picow/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ sunset = { path = "../../.." }
sunset-sshwire-derive = { version = "0.1", path = "../../../sshwire-derive" }
sunset-demo-embassy-common= { path = "../common" }

cyw43 = { version = "0.1.0", features = ["defmt"]}
cyw43-pio = "0.1.0"
cyw43 = { version = "0.1.0", optional = true, features = ["defmt"] }
cyw43-pio = { version = "0.1.0", optional = true }
# cyw43 = { path = "/home/matt/3rd/rs/cyw43", features = ["defmt"] }
# cyw43-pio = { path = "/home/matt/3rd/rs/cyw43/cyw43-pio" }

embassy-net-w5500 = { version = "0.1.0", optional = true }

embassy-executor = { version = "0.2", features = ["defmt", "integrated-timers", "executor-thread", "arch-cortex-m", "nightly"] }
embassy-time = { version = "0.1", features = ["defmt", "defmt-timestamp-uptime"] }
embassy-rp = { version = "0.1.0", features = ["defmt", "unstable-traits", "nightly", "unstable-pac"] }
Expand All @@ -25,7 +27,7 @@ embassy-sync = { version = "0.2.0" }
embassy-futures = { version = "0.1.0" }
embassy-usb = { version = "0.1.0" }
atomic-polyfill = "0.1.5"
static_cell = "1.0"
static_cell = { version = "1.0", features = [ "nightly" ] }

defmt = { version = "0.3", optional = true }
defmt-rtt = "0.3"
Expand Down Expand Up @@ -60,13 +62,18 @@ sha2 = { version = "0.10", default-features = false }
smoltcp = { version = "0.9", default-features = false }

[features]
default = ["defmt", "sunset-demo-embassy-common/defmt", "embassy-usb/defmt"]
default = ["cyw43", "defmt", "sunset-demo-embassy-common/defmt" ]
defmt = ["dep:defmt", "sunset/defmt", "sunset-embassy/defmt", "smoltcp/defmt"]

# for pico w board
cyw43 = ["dep:cyw43", "dep:cyw43-pio"]
# for wiznet w5500-evb-pico board
w5500 = ["dep:embassy-net-w5500"]

# Use cyw43 firmware already on flash. This saves time when developing.
# probe-rs-cli download firmware/43439A0.bin --format bin --chip RP2040 --base-address 0x10100000
# probe-rs-cli download firmware/43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000
romfw = []

# Default console is serial
# Set default console to serial
serial1 = []
79 changes: 46 additions & 33 deletions embassy/demos/picow/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,14 @@ mod picowmenu;
mod serial;
mod takepipe;
mod usbserial;
#[cfg(feature = "w5500")]
mod w5500;
#[cfg(feature = "cyw43")]
mod wifi;

#[cfg(not(any(feature = "cyw43", feature = "w5500")))]
compile_error!("No network device selected. Use cyw43 or w5500 feature");

use demo_common::{SSHConfig, Shell};

use takepipe::TakePipe;
Expand All @@ -53,7 +59,7 @@ pub(crate) const NUM_SOCKETS: usize = NUM_LISTENERS + 1;

#[embassy_executor::main]
async fn main(spawner: Spawner) {
info!("Hello World!");
info!("Welcome to Sunset SSH");

let mut p = embassy_rp::init(Default::default());

Expand All @@ -72,20 +78,6 @@ async fn main(spawner: Spawner) {

let config = &*singleton!(SunsetMutex::new(config));

let (wifi_net, wifi_pw) = {
let c = config.lock().await;
(c.wifi_net.clone(), c.wifi_pw.clone())
};
// spawn the wifi stack
let (stack, wifi_control) = wifi::wifi_stack(
&spawner, p.PIN_23, p.PIN_24, p.PIN_25, p.PIN_29, p.DMA_CH0, p.PIO0,
wifi_net, wifi_pw,
)
.await;
let stack = &*singleton!(stack);
let wifi_control = singleton!(SunsetMutex::new(wifi_control));
spawner.spawn(net_task(&stack)).unwrap();

let usb_pipe = {
let p = singleton!(takepipe::TakePipeStorage::new());
singleton!(p.pipe())
Expand All @@ -110,40 +102,66 @@ async fn main(spawner: Spawner) {
embassy_rp::watchdog::Watchdog::new(p.WATCHDOG)
));

let state = GlobalState {
usb_pipe,
serial1_pipe,

_wifi_control: wifi_control,
config,
flash,
watchdog,
};
let state = GlobalState { usb_pipe, serial1_pipe, config, flash, watchdog };
let state = singleton!(state);

spawner.spawn(usbserial::task(p.USB, state)).unwrap();

for _ in 0..NUM_LISTENERS {
spawner.spawn(listener(&stack, config, state)).unwrap();
// spawn the wifi stack
#[cfg(feature = "cyw43")]
{
let stack = wifi::wifi_stack(
&spawner, p.PIN_23, p.PIN_24, p.PIN_25, p.PIN_29, p.DMA_CH0, p.PIO0,
config,
)
.await;

for _ in 0..NUM_LISTENERS {
spawner.spawn(cyw43_listener(&stack, config, state)).unwrap();
}
}

// spawn the ethernet stack
#[cfg(feature = "w5500")]
{
let stack = w5500::w5500_stack(
&spawner, p.PIN_16, p.PIN_17, p.PIN_18, p.PIN_19, p.PIN_20, p.PIN_21,
p.DMA_CH0, p.DMA_CH1, p.SPI0, config,
)
.await;

for _ in 0..NUM_LISTENERS {
spawner.spawn(w5500_listener(&stack, config, state)).unwrap();
}
}
}

// TODO: pool_size should be NUM_LISTENERS but needs a literal
#[cfg(feature = "cyw43")]
#[embassy_executor::task(pool_size = 4)]
async fn listener(
async fn cyw43_listener(
stack: &'static Stack<cyw43::NetDriver<'static>>,
config: &'static SunsetMutex<SSHConfig>,
global: &'static GlobalState,
) -> ! {
demo_common::listener::<_, DemoShell>(stack, config, global).await
}

#[cfg(feature = "w5500")]
#[embassy_executor::task(pool_size = 4)]
async fn w5500_listener(
stack: &'static Stack<embassy_net_w5500::Device<'static>>,
config: &'static SunsetMutex<SSHConfig>,
global: &'static GlobalState,
) -> ! {
demo_common::listener::<_, DemoShell>(stack, config, global).await
}

pub(crate) struct GlobalState {
// If taking multiple mutexes, lock in the order below avoid inversion.
pub usb_pipe: &'static TakePipe<'static>,
pub serial1_pipe: &'static TakePipe<'static>,

pub _wifi_control: &'static SunsetMutex<cyw43::Control<'static>>,
pub config: &'static SunsetMutex<SSHConfig>,
pub flash: &'static SunsetMutex<
embassy_rp::flash::Flash<'static, FLASH, { flashconfig::FLASH_SIZE }>,
Expand Down Expand Up @@ -312,8 +330,3 @@ impl Shell for DemoShell {
session.await
}
}

#[embassy_executor::task]
async fn net_task(stack: &'static Stack<cyw43::NetDriver<'static>>) -> ! {
stack.run().await
}
Loading

0 comments on commit 3d02cc4

Please sign in to comment.