diff --git a/porky/Cargo.toml b/porky/Cargo.toml index 77f06c2a..267f49ad 100644 --- a/porky/Cargo.toml +++ b/porky/Cargo.toml @@ -8,18 +8,16 @@ rust-version = "1.80" [[bin]] name = "porky_w" path = "src/porky_w.rs" -required-features = ["pico_w"] +required-features = ["wifi"] [[bin]] name = "porky" path = "src/porky.rs" -required-features = ["pico"] +required-features = ["usb"] [features] default = ["usb", "no_std"] -pico = ["cyw43-pio"] # I don't know why yet is needed. Reported to EMbassy -pico_w = ["wifi"] -wifi = ["cyw43", "cyw43-pio", "embassy-net", "tcp", "discovery"] +wifi = ["cyw43", "embassy-net", "tcp", "discovery"] no_std = [] debug-probe = [] usb = ["embassy-usb"] @@ -34,9 +32,11 @@ embassy-rp = { version = "0.2.0", default-features = false, features = ["rp2040" embassy-sync = { version = "0.6.0", default-features = false } embassy-futures = { version = "0.1.1", default-features = false } +# Needed even when no wifi - I don't know why yet. Reported to Embassy +cyw43-pio = { version = "0.2.0", default-features = false, features = ["defmt"] } + # Optional Embassy Dependencies cyw43 = { version = "0.2.0", default-features = false, features = ["defmt"], optional = true } -cyw43-pio = { version = "0.2.0", default-features = false, features = ["defmt"], optional = true } embassy-net = { version = "0.5.0", default-features = false, features = ["defmt", "tcp", "udp", "dns", "dhcpv4"], optional = true } embassy-usb = { version = "0.3.0", default-features = false, optional = true } @@ -97,5 +97,4 @@ edge-nal = { git = "https://github.com/ivmarkov/edge-net.git", branch = "embassy [package.metadata.cargo-all-features] skip_optional_dependencies = true -denylist = ["usb"] -always_include_features = ["no_std"] \ No newline at end of file +always_include_features = ["no_std", "wifi"] \ No newline at end of file diff --git a/porky/Makefile b/porky/Makefile index 7ec7f0a8..c7a76be3 100644 --- a/porky/Makefile +++ b/porky/Makefile @@ -4,26 +4,25 @@ clean: cargo clean clippy: - cargo clippy --features "pico_w" - cargo clippy --features "pico" + cargo clippy --features "wifi" run-pico-w: - cargo run --release --bin porky_w --features "pico_w" + cargo run --release --bin porky_w --features "wifi" run-pico: - cargo run --release --bin porky --features "pico" + cargo run --release --bin porky build-pico-w: - cargo build --release --bin porky_w --features "pico_w" + cargo build --release --bin porky_w --features "wifi" build-pico: - cargo build --release --bin porky --features "pico" + cargo build --release --bin porky run-w: - cargo run --release --bin porky_w --features "pico_w" + cargo run --release --bin porky_w --features "wifi" run: - cargo run --release --bin porky --features "pico" + cargo run --release --bin porky install-uf2: curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash diff --git a/porky/src/gpio.rs b/porky/src/gpio.rs index b7aa8b02..04626882 100644 --- a/porky/src/gpio.rs +++ b/porky/src/gpio.rs @@ -1,3 +1,4 @@ +use crate::gpio::GPIOPin::Available; use crate::gpio_input_monitor::monitor_input; use crate::hw_definition::config::HardwareConfig; use crate::hw_definition::config::HardwareConfigMessage; @@ -10,24 +11,30 @@ use crate::hw_definition::pin_function::PinFunction::{Input, Output}; use crate::hw_definition::{BCMPinNumber, PinLevel}; #[cfg(feature = "wifi")] use cyw43::Control; -use defmt::{error, info}; +use defmt::{debug, error, info}; use embassy_executor::Spawner; use embassy_rp::gpio::Flex; use embassy_rp::gpio::Level; use embassy_rp::gpio::Pull; +use embassy_rp::peripherals::{ + PIN_0, PIN_1, PIN_10, PIN_11, PIN_12, PIN_13, PIN_14, PIN_15, PIN_16, PIN_17, PIN_18, PIN_19, + PIN_2, PIN_20, PIN_21, PIN_22, PIN_26, PIN_27, PIN_28, PIN_3, PIN_4, PIN_5, PIN_6, PIN_7, + PIN_8, PIN_9, +}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::channel::Channel; use embassy_sync::channel::{Receiver, Sender}; use heapless::FnvIndexMap; +use static_cell::StaticCell; /// The configured/not-configured state of the GPIO Pins on the Pi Pico, and how to access them /// as 3 of them are accessed via Cyw43 and others via gpio API -pub enum GPIOPin<'a> { +enum GPIOPin<'a> { Available(Flex<'a>), GPIOInput( ( - Sender<'a, ThreadModeRawMutex, bool, 1>, - Receiver<'a, ThreadModeRawMutex, Flex<'a>, 1>, + Sender<'static, ThreadModeRawMutex, bool, 1>, + Receiver<'static, ThreadModeRawMutex, Flex<'static>, 1>, ), ), #[cfg(feature = "wifi")] @@ -37,11 +44,6 @@ pub enum GPIOPin<'a> { GPIOOutput(Flex<'a>), } -pub static mut GPIO_PINS: FnvIndexMap = FnvIndexMap::new(); - -static RETURNER: Channel = Channel::new(); -static SIGNALLER: Channel = Channel::new(); - fn into_level(value: PinLevel) -> Level { match value { true => Level::High, @@ -49,215 +51,311 @@ fn into_level(value: PinLevel) -> Level { } } -/// Set an output's level using the bcm pin number -async fn set_output_level<'a>( - #[cfg(feature = "wifi")] control: &mut Control<'_>, - bcm_pin_number: BCMPinNumber, - pin_level: PinLevel, -) { - info!( - "Pin #{} Output level change: {:?}", - bcm_pin_number, pin_level - ); +pub struct Gpio { + pins: FnvIndexMap, 32>, + returner_receiver: Receiver<'static, ThreadModeRawMutex, Flex<'static>, 1>, + signaller_sender: Sender<'static, ThreadModeRawMutex, bool, 1>, + signaller_receiver: Receiver<'static, ThreadModeRawMutex, bool, 1>, + returner_sender: Sender<'static, ThreadModeRawMutex, Flex<'static>, 1>, +} + +impl Gpio { + /// Create new Gpio controller with pins to be used + /// Pins available to be programmed, but are not connected to header + /// WL_GPIO0 - via CYW43 - Connected to user LED + /// WL_GPIO1 - via CYW43 - Output controls on-board SMPS power save pin + /// WL_GPIO2 - via CYW43 - Input VBUS sense - high if VBUS is present, else low + /// + /// GPIO Pins Used Internally that are not in the list below + /// GP23 - Output wireless on signal - used by embassy + /// GP24 - Output/Input wireless SPI data/IRQ + /// GP25 - Output wireless SPI CS- when high enables GPIO29 ADC pin to read VSYS + /// GP29 - Output/Input SPI CLK/ADC Mode to measure VSYS/3 + /// + /// Refer to $ProjectRoot/assets/images/pi_pico_w_pinout.png + /// Take the set of available pins not used by other functions, including the three pins that + /// are connected via the CYW43 Wi-Fi chip. Create [Flex] Pins out of each of the GPIO pins. + /// Put them all into the GPIO_PINS map, marking them as available + /// NOTE: All pin numbers are GPIO (BCM) Pin Numbers, not physical pin numbers + /// Take the following pins out of peripherals for use a GPIO + #[allow(clippy::too_many_arguments)] + pub fn new( + pin_0: PIN_0, + pin_1: PIN_1, + pin_2: PIN_2, + pin_3: PIN_3, + pin_4: PIN_4, + pin_5: PIN_5, + pin_6: PIN_6, + pin_7: PIN_7, + pin_8: PIN_8, + pin_9: PIN_9, + pin_10: PIN_10, + pin_11: PIN_11, + pin_12: PIN_12, + pin_13: PIN_13, + pin_14: PIN_14, + pin_15: PIN_15, + pin_16: PIN_16, + pin_17: PIN_17, + pin_18: PIN_18, + pin_19: PIN_19, + pin_20: PIN_20, + pin_21: PIN_21, + pin_22: PIN_22, + pin_26: PIN_26, + pin_27: PIN_27, + pin_28: PIN_28, + ) -> Self { + let mut pins = FnvIndexMap::new(); + + #[cfg(not(feature = "debug-probe"))] + let _ = pins.insert(0, Available(Flex::new(pin_0))); + #[cfg(not(feature = "debug-probe"))] + let _ = pins.insert(1, Available(Flex::new(pin_1))); + let _ = pins.insert(2, Available(Flex::new(pin_2))); + let _ = pins.insert(3, Available(Flex::new(pin_3))); + let _ = pins.insert(4, Available(Flex::new(pin_4))); + let _ = pins.insert(5, Available(Flex::new(pin_5))); + let _ = pins.insert(6, Available(Flex::new(pin_6))); + let _ = pins.insert(7, Available(Flex::new(pin_7))); + let _ = pins.insert(8, Available(Flex::new(pin_8))); + let _ = pins.insert(9, Available(Flex::new(pin_9))); + let _ = pins.insert(10, Available(Flex::new(pin_10))); + let _ = pins.insert(11, Available(Flex::new(pin_11))); + let _ = pins.insert(12, Available(Flex::new(pin_12))); + let _ = pins.insert(13, Available(Flex::new(pin_13))); + let _ = pins.insert(14, Available(Flex::new(pin_14))); + let _ = pins.insert(15, Available(Flex::new(pin_15))); + let _ = pins.insert(16, Available(Flex::new(pin_16))); + let _ = pins.insert(17, Available(Flex::new(pin_17))); + let _ = pins.insert(18, Available(Flex::new(pin_18))); + let _ = pins.insert(19, Available(Flex::new(pin_19))); + let _ = pins.insert(20, Available(Flex::new(pin_20))); + let _ = pins.insert(21, Available(Flex::new(pin_21))); + let _ = pins.insert(22, Available(Flex::new(pin_22))); + let _ = pins.insert(26, Available(Flex::new(pin_26))); + let _ = pins.insert(27, Available(Flex::new(pin_27))); + let _ = pins.insert(28, Available(Flex::new(pin_28))); + + static RETURNER: StaticCell, 1>> = + StaticCell::new(); + let returner = RETURNER.init(Channel::new()); + + static SIGNALLER: StaticCell> = StaticCell::new(); + let signaller = SIGNALLER.init(Channel::new()); - // GPIO 0 and 1 are connected via cyw43 Wi-Fi chip - unsafe { - match GPIO_PINS.get_mut(&bcm_pin_number) { + Gpio { + pins, + returner_receiver: returner.receiver(), + signaller_sender: signaller.sender(), + signaller_receiver: signaller.receiver(), + returner_sender: returner.sender(), + } + } + + /// Set an output's level using the bcm pin number + async fn set_output_level( + &mut self, + #[cfg(feature = "wifi")] control: &mut Control<'_>, + bcm_pin_number: BCMPinNumber, + pin_level: PinLevel, + ) { + info!( + "Pin #{} Output level change: {:?}", + bcm_pin_number, pin_level + ); + + // GPIO 0 and 1 are connected via cyw43 Wi-Fi chip + match self.pins.get_mut(&bcm_pin_number) { #[cfg(feature = "wifi")] Some(GPIOPin::CYW43Output) => control.gpio_set(bcm_pin_number, pin_level).await, Some(GPIOPin::GPIOOutput(flex)) => flex.set_level(into_level(pin_level)), _ => error!("Pin {} is not configured as an Output", bcm_pin_number), } } -} -/// Apply the requested config to one pin, using bcm_pin_number -async fn apply_pin_config<'a>( - #[cfg(feature = "wifi")] control: &mut Control<'_>, - spawner: &Spawner, - bcm_pin_number: BCMPinNumber, - new_pin_function: &PinFunction, -) { - let flex_pin = unsafe { - match GPIO_PINS.remove(&bcm_pin_number) { - // Pin was set up as an Input - recover the Flex - Some(GPIOPin::GPIOInput((signaller, returner))) => { - // Signal to pin monitor to exit - signaller.send(true).await; - // Recover the Flex - Some(returner.receive().await) - } - // Pin is available - was unassigned - Some(GPIOPin::Available(flex)) => Some(flex), - // Was assigned as an output - recover the Flex - Some(GPIOPin::GPIOOutput(flex)) => Some(flex), - // The cyw43 pins cannot be changed - just used - #[cfg(feature = "wifi")] - Some(GPIOPin::CYW43Input) | Some(GPIOPin::CYW43Output) => None, - _ => { - error!("Could not find pin #{}", bcm_pin_number); - return; + /// Apply the requested config to one pin, using bcm_pin_number + async fn apply_pin_config( + &mut self, + #[cfg(feature = "wifi")] control: &mut Control<'_>, + spawner: &Spawner, + bcm_pin_number: BCMPinNumber, + new_pin_function: &PinFunction, + ) { + let flex_pin = { + match self.pins.remove(&bcm_pin_number) { + // Pin was set up as an Input - recover the Flex + Some(GPIOPin::GPIOInput((signaller, returner))) => { + // Signal to pin monitor to exit + signaller.send(true).await; + // Recover the Flex + Some(returner.receive().await) + } + // Pin is available - was unassigned + Some(GPIOPin::Available(flex)) => Some(flex), + // Was assigned as an output - recover the Flex + Some(GPIOPin::GPIOOutput(flex)) => Some(flex), + // The cyw43 pins cannot be changed - just used + #[cfg(feature = "wifi")] + Some(GPIOPin::CYW43Input) | Some(GPIOPin::CYW43Output) => None, + _ => { + error!("Could not find pin #{}", bcm_pin_number); + return; + } } - } - }; + }; - match new_pin_function { - PinFunction::None => { - // if we recovered a pin above - then leave it as - if let Some(flex) = flex_pin { - unsafe { - let _ = GPIO_PINS.insert(bcm_pin_number, GPIOPin::Available(flex)); + match new_pin_function { + PinFunction::None => { + // if we recovered a pin above - then leave it as + if let Some(flex) = flex_pin { + let _ = self.pins.insert(bcm_pin_number, GPIOPin::Available(flex)); } + debug!("Pin #{} - Set as Available", bcm_pin_number); } - info!("Pin #{} - Set as Available", bcm_pin_number); - } - Input(pull) => { - match flex_pin { - Some(mut flex) => { - flex.set_as_input(); - info!("Pin #{} Configured as GPIO input", bcm_pin_number); + Input(pull) => { + match flex_pin { + Some(mut flex) => { + flex.set_as_input(); + debug!("Pin #{} Configured as GPIO input", bcm_pin_number); - match pull { - None | Some(InputPull::None) => flex.set_pull(Pull::None), - Some(InputPull::PullUp) => flex.set_pull(Pull::Up), - Some(InputPull::PullDown) => flex.set_pull(Pull::Down), - }; + match pull { + None | Some(InputPull::None) => flex.set_pull(Pull::None), + Some(InputPull::PullUp) => flex.set_pull(Pull::Up), + Some(InputPull::PullDown) => flex.set_pull(Pull::Down), + }; - if let Err(e) = spawner.spawn(monitor_input( - bcm_pin_number, - SIGNALLER.receiver(), - RETURNER.sender(), - flex, - )) { - error!("Spawn Error: {}", e); - } + if let Err(e) = spawner.spawn(monitor_input( + bcm_pin_number, + self.signaller_receiver, + self.returner_sender, + flex, + )) { + error!("Spawn Error: {}", e); + } - unsafe { - let _ = GPIO_PINS.insert( + let _ = self.pins.insert( bcm_pin_number, - GPIOPin::GPIOInput((SIGNALLER.sender(), RETURNER.receiver())), + GPIOPin::GPIOInput((self.signaller_sender, self.returner_receiver)), ); } - } - None => { - #[cfg(feature = "wifi")] - { - // Must be GPIO 2 is connected via cyw43 Wi-Fi chip - unsafe { - let _ = GPIO_PINS.insert(bcm_pin_number, GPIOPin::CYW43Input); + None => { + #[cfg(feature = "wifi")] + { + // Must be GPIO 2 is connected via cyw43 Wi-Fi chip + let _ = self.pins.insert(bcm_pin_number, GPIOPin::CYW43Input); + debug!("Pin #{} - Configured as input via cyw43", bcm_pin_number); } - info!("Pin #{} - Configured as input via cyw43", bcm_pin_number); } } } - } - Output(pin_level) => { - match flex_pin { - Some(mut flex) => { - if let Some(l) = pin_level { - flex.set_level(into_level(*l)); - info!("Pin #{} - Output level set to '{}'", bcm_pin_number, l); - } + Output(pin_level) => { + match flex_pin { + Some(mut flex) => { + if let Some(l) = pin_level { + flex.set_level(into_level(*l)); + info!("Pin #{} - Output level set to '{}'", bcm_pin_number, l); + } - flex.set_as_output(); - info!("Pin #{} Flex pin configured as Output", bcm_pin_number); + flex.set_as_output(); + info!("Pin #{} Flex pin configured as Output", bcm_pin_number); - unsafe { - let _ = GPIO_PINS.insert(bcm_pin_number, GPIOPin::GPIOOutput(flex)); + let _ = self.pins.insert(bcm_pin_number, GPIOPin::GPIOOutput(flex)); } - } - None => { - #[cfg(feature = "wifi")] - { - // Must be GPIO 0 and 1 are connected via cyw43 Wi-Fi chip - info!("Pin #{} cyw43 pin used as Output ", bcm_pin_number); + None => { + #[cfg(feature = "wifi")] + { + // Must be GPIO 0 and 1 are connected via cyw43 Wi-Fi chip + info!("Pin #{} cyw43 pin used as Output ", bcm_pin_number); - if let Some(l) = pin_level { - control.gpio_set(bcm_pin_number, *l).await; - info!("Pin #{} - output level set to '{}'", bcm_pin_number, l); - } - unsafe { - let _ = GPIO_PINS.insert(bcm_pin_number, GPIOPin::CYW43Output); + if let Some(l) = pin_level { + control.gpio_set(bcm_pin_number, *l).await; + info!("Pin #{} - output level set to '{}'", bcm_pin_number, l); + } + let _ = self.pins.insert(bcm_pin_number, GPIOPin::CYW43Output); } } } } } } -} -/// This takes the [HardwareConfig] struct and configures all the pins in it -async fn apply_config<'a>( - #[cfg(feature = "wifi")] control: &mut Control<'_>, - spawner: &Spawner, - config: &HardwareConfig, -) { - // Config only has pins that are configured - for (bcm_pin_number, pin_function) in &config.pin_functions { - apply_pin_config( - #[cfg(feature = "wifi")] - control, - spawner, - *bcm_pin_number, - pin_function, - ) - .await; - } - let num_pins = config.pin_functions.len(); - if num_pins > 0 { - info!("New config applied - {} pins reconfigured", num_pins); - } -} - -/// Apply a config change to the hardware -/// NOTE: Initially the callback to Config/PinConfig change was async, and that compiles and runs -/// but wasn't working - so this uses a sync callback again to fix that, and an async version of -/// send_input_level() for use directly from the async context -pub async fn apply_config_change<'a>( - #[cfg(feature = "wifi")] control: &mut Control<'_>, - spawner: &Spawner, - config_change: &HardwareConfigMessage, - hardware_config: &mut HardwareConfig, -) { - match config_change { - NewConfig(config) => { - apply_config( + /// This takes the [HardwareConfig] struct and configures all the pins in it + async fn apply_config( + &mut self, + #[cfg(feature = "wifi")] control: &mut Control<'_>, + spawner: &Spawner, + config: &HardwareConfig, + ) { + // Config only has pins that are configured + for (bcm_pin_number, pin_function) in &config.pin_functions { + self.apply_pin_config( #[cfg(feature = "wifi")] control, spawner, - config, - ) - .await; - // Update the hardware config to reflect the change - *hardware_config = config.clone(); - } - NewPinConfig(bcm, pin_function) => { - apply_pin_config( - #[cfg(feature = "wifi")] - control, - spawner, - *bcm, + *bcm_pin_number, pin_function, ) .await; - // Update the hardware config to reflect the change - let _ = hardware_config.pin_functions.insert(*bcm, *pin_function); } - IOLevelChanged(bcm, level_change) => { - set_output_level( - #[cfg(feature = "wifi")] - control, - *bcm, - level_change.new_level, - ) - .await; - // Update the hardware config to reflect the change - let _ = hardware_config - .pin_functions - .insert(*bcm, Output(Some(level_change.new_level))); + let num_pins = config.pin_functions.len(); + if num_pins > 0 { + info!("New config applied - {} pins reconfigured", num_pins); + } + } + + /// Apply a config change to the hardware + /// NOTE: Initially the callback to Config/PinConfig change was async, and that compiles and runs + /// but wasn't working - so this uses a sync callback again to fix that, and an async version of + /// send_input_level() for use directly from the async context + pub async fn apply_config_change( + &mut self, + #[cfg(feature = "wifi")] control: &mut Control<'_>, + spawner: &Spawner, + config_change: &HardwareConfigMessage, + hardware_config: &mut HardwareConfig, + ) { + match config_change { + NewConfig(config) => { + self.apply_config( + #[cfg(feature = "wifi")] + control, + spawner, + config, + ) + .await; + // Update the hardware config to reflect the change + *hardware_config = config.clone(); + } + NewPinConfig(bcm, pin_function) => { + self.apply_pin_config( + #[cfg(feature = "wifi")] + control, + spawner, + *bcm, + pin_function, + ) + .await; + // Update the hardware config to reflect the change + let _ = hardware_config.pin_functions.insert(*bcm, *pin_function); + } + IOLevelChanged(bcm, level_change) => { + self.set_output_level( + #[cfg(feature = "wifi")] + control, + *bcm, + level_change.new_level, + ) + .await; + // Update the hardware config to reflect the change + let _ = hardware_config + .pin_functions + .insert(*bcm, Output(Some(level_change.new_level))); + } + HardwareConfigMessage::GetConfig => { /* Nothing to do in GPIO */ } } - HardwareConfigMessage::GetConfig => { /* Nothing to do in GPIO */ } } } diff --git a/porky/src/persistence.rs b/porky/src/persistence.rs index d3d4d538..bf87c670 100644 --- a/porky/src/persistence.rs +++ b/porky/src/persistence.rs @@ -126,6 +126,7 @@ pub async fn get_ssid_spec<'a>( } } +#[allow(dead_code)] // Not used in porky #[cfg(feature = "wifi")] /// Write the [SsidSpec] to the flash database pub async fn store_ssid_spec<'p>( @@ -142,6 +143,7 @@ pub async fn store_ssid_spec<'p>( wtx.commit().await.map_err(|_| "Commit error") } +#[allow(dead_code)] // Not used in porky #[cfg(feature = "wifi")] /// Delete the [SsidSpec] from the flash database pub async fn delete_ssid_spec<'p>( diff --git a/porky/src/porky.rs b/porky/src/porky.rs index de4530de..fbf02d76 100644 --- a/porky/src/porky.rs +++ b/porky/src/porky.rs @@ -5,7 +5,7 @@ use embassy_executor::Spawner; use {defmt_rtt as _, panic_probe as _}; use crate::flash::DbFlash; -use crate::gpio::{GPIOPin, GPIO_PINS}; +use crate::gpio::Gpio; use crate::hw_definition::config::HardwareConfigMessage; use crate::hw_definition::description::{HardwareDescription, HardwareDetails, PinDescriptionSet}; use crate::pin_descriptions::PIN_DESCRIPTIONS; @@ -13,7 +13,6 @@ use core::str; use ekv::Database; use embassy_rp::bind_interrupts; use embassy_rp::flash::{Blocking, Flash}; -use embassy_rp::gpio::Flex; use embassy_rp::peripherals::FLASH; #[cfg(feature = "usb")] use embassy_rp::peripherals::USB; @@ -25,19 +24,7 @@ use embassy_sync::blocking_mutex::raw::{NoopRawMutex, ThreadModeRawMutex}; use embassy_sync::channel::Channel; use heapless::Vec; use static_cell::StaticCell; -use GPIOPin::Available; -#[cfg(not(any(feature = "pico", feature = "pico_w")))] -compile_error!( - "You must chose a feature from:[\"pico\", \"pico_w\"] to select a device to build for" -); - -#[cfg(all(feature = "pico", feature = "pico_w"))] -compile_error!( - "You must chose a just one of [\"pico\", \"pico_w\"] to select a device to build for" -); - -//#[cfg(feature = "usb")] mod usb; /// GPIO control related functions @@ -92,53 +79,34 @@ async fn main(spawner: Spawner) { // GPIO let peripherals = embassy_rp::init(Default::default()); - // Pins available to be programmed, but are not connected to header - // WL_GPIO0 - via CYW43 - Connected to user LED - // WL_GPIO1 - via CYW43 - Output controls on-board SMPS power save pin - // WL_GPIO2 - via CYW43 - Input VBUS sense - high if VBUS is present, else low - // - // GPIO Pins Used Internally that are not in the list below - // GP23 - Output wireless on signal - used by embassy - // GP24 - Output/Input wireless SPI data/IRQ - // GP25 - Output wireless SPI CS- when high enables GPIO29 ADC pin to read VSYS - // GP29 - Output/Input SPI CLK/ADC Mode to measure VSYS/3 - // - // Refer to $ProjectRoot/assets/images/pi_pico_w_pinout.png - // Take the set of available pins not used by other functions, including the three pins that - // are connected via the CYW43 Wi-Fi chip. Create [Flex] Pins out of each of the GPIO pins. - // Put them all into the GPIO_PINS map, marking them as available - // NOTE: All pin numbers are GPIO (BCM) Pin Numbers, not physical pin numbers - // Take the following pins out of peripherals for use a GPIO - unsafe { - #[cfg(not(feature = "debug-probe"))] - let _ = GPIO_PINS.insert(0, Available(Flex::new(peripherals.PIN_0))); - #[cfg(not(feature = "debug-probe"))] - let _ = GPIO_PINS.insert(1, Available(Flex::new(peripherals.PIN_1))); - let _ = GPIO_PINS.insert(2, Available(Flex::new(peripherals.PIN_2))); - let _ = GPIO_PINS.insert(3, Available(Flex::new(peripherals.PIN_3))); - let _ = GPIO_PINS.insert(4, Available(Flex::new(peripherals.PIN_4))); - let _ = GPIO_PINS.insert(5, Available(Flex::new(peripherals.PIN_5))); - let _ = GPIO_PINS.insert(6, Available(Flex::new(peripherals.PIN_6))); - let _ = GPIO_PINS.insert(7, Available(Flex::new(peripherals.PIN_7))); - let _ = GPIO_PINS.insert(8, Available(Flex::new(peripherals.PIN_8))); - let _ = GPIO_PINS.insert(9, Available(Flex::new(peripherals.PIN_9))); - let _ = GPIO_PINS.insert(10, Available(Flex::new(peripherals.PIN_10))); - let _ = GPIO_PINS.insert(11, Available(Flex::new(peripherals.PIN_11))); - let _ = GPIO_PINS.insert(12, Available(Flex::new(peripherals.PIN_12))); - let _ = GPIO_PINS.insert(13, Available(Flex::new(peripherals.PIN_13))); - let _ = GPIO_PINS.insert(14, Available(Flex::new(peripherals.PIN_14))); - let _ = GPIO_PINS.insert(15, Available(Flex::new(peripherals.PIN_15))); - let _ = GPIO_PINS.insert(16, Available(Flex::new(peripherals.PIN_16))); - let _ = GPIO_PINS.insert(17, Available(Flex::new(peripherals.PIN_17))); - let _ = GPIO_PINS.insert(18, Available(Flex::new(peripherals.PIN_18))); - let _ = GPIO_PINS.insert(19, Available(Flex::new(peripherals.PIN_19))); - let _ = GPIO_PINS.insert(20, Available(Flex::new(peripherals.PIN_20))); - let _ = GPIO_PINS.insert(21, Available(Flex::new(peripherals.PIN_21))); - let _ = GPIO_PINS.insert(22, Available(Flex::new(peripherals.PIN_22))); - let _ = GPIO_PINS.insert(26, Available(Flex::new(peripherals.PIN_26))); - let _ = GPIO_PINS.insert(27, Available(Flex::new(peripherals.PIN_27))); - let _ = GPIO_PINS.insert(28, Available(Flex::new(peripherals.PIN_28))); - } + let mut gpio = Gpio::new( + peripherals.PIN_0, + peripherals.PIN_1, + peripherals.PIN_2, + peripherals.PIN_3, + peripherals.PIN_4, + peripherals.PIN_5, + peripherals.PIN_6, + peripherals.PIN_7, + peripherals.PIN_8, + peripherals.PIN_9, + peripherals.PIN_10, + peripherals.PIN_11, + peripherals.PIN_12, + peripherals.PIN_13, + peripherals.PIN_14, + peripherals.PIN_15, + peripherals.PIN_16, + peripherals.PIN_17, + peripherals.PIN_18, + peripherals.PIN_19, + peripherals.PIN_20, + peripherals.PIN_21, + peripherals.PIN_22, + peripherals.PIN_26, + peripherals.PIN_27, + peripherals.PIN_28, + ); // create hardware description let mut flash = flash::get_flash(peripherals.FLASH); @@ -146,7 +114,6 @@ async fn main(spawner: Spawner) { static HARDWARE_DESCRIPTION: StaticCell = StaticCell::new(); let hw_desc = HARDWARE_DESCRIPTION.init(hardware_description(serial_number)); - #[cfg(feature = "usb")] let driver = Driver::new(peripherals.USB, Irqs); // start the flash database @@ -159,17 +126,21 @@ async fn main(spawner: Spawner) { let mut hardware_config = persistence::get_config(db).await; // apply the loaded config to the hardware immediately - gpio::apply_config_change( + gpio.apply_config_change( &spawner, &HardwareConfigMessage::NewConfig(hardware_config.clone()), &mut hardware_config, ) .await; - #[cfg(feature = "usb")] let mut usb_connection = usb::start(spawner, driver, hw_desc).await; - #[cfg(feature = "usb")] usb::wait_connection(&mut usb_connection, &hardware_config).await; - #[cfg(feature = "usb")] - usb::message_loop(&mut usb_connection, &mut hardware_config, &spawner, db).await; + usb::message_loop( + &mut gpio, + &mut usb_connection, + &mut hardware_config, + &spawner, + db, + ) + .await; } diff --git a/porky/src/porky_w.rs b/porky/src/porky_w.rs index e58f92dd..c699a768 100644 --- a/porky/src/porky_w.rs +++ b/porky/src/porky_w.rs @@ -2,8 +2,7 @@ #![no_main] use crate::flash::DbFlash; -use crate::gpio::GPIOPin::Available; -use crate::gpio::GPIO_PINS; +use crate::gpio::Gpio; use crate::hw_definition::config::HardwareConfigMessage; use crate::hw_definition::description::{ HardwareDescription, HardwareDetails, PinDescriptionSet, TCP_MDNS_SERVICE_NAME, @@ -17,10 +16,11 @@ use defmt::{error, info}; use defmt_rtt as _; use ekv::Database; use embassy_executor::Spawner; +#[cfg(all(feature = "usb", feature = "wifi"))] use embassy_futures::select::{select, Either}; use embassy_rp::bind_interrupts; use embassy_rp::flash::{Blocking, Flash}; -use embassy_rp::gpio::{Flex, Level, Output}; +use embassy_rp::gpio::{Level, Output}; #[cfg(feature = "usb")] use embassy_rp::peripherals::USB; use embassy_rp::peripherals::{FLASH, PIO0}; @@ -30,6 +30,7 @@ use embassy_rp::pio::Pio; use embassy_rp::usb::Driver; #[cfg(feature = "usb")] use embassy_rp::usb::InterruptHandler as USBInterruptHandler; +#[cfg(all(feature = "wifi", feature = "usb"))] use embassy_rp::watchdog::Watchdog; use embassy_sync::blocking_mutex::raw::{NoopRawMutex, ThreadModeRawMutex}; use embassy_sync::channel::Channel; @@ -37,15 +38,8 @@ use heapless::Vec; use panic_probe as _; use static_cell::StaticCell; -#[cfg(not(any(feature = "pico", feature = "pico_w")))] -compile_error!( - "You must chose a feature from [\"pico\", \"pico_w\"] to select a device to build for" -); - -#[cfg(all(feature = "pico", feature = "pico_w"))] -compile_error!( - "You must chose a just one of [\"pico\", \"pico_w\"] to select a device to build for" -); +#[cfg(not(any(feature = "usb", feature = "wifi")))] +compile_error!("You must chose a feature from [\"usb\", \"wifi\"] in order to control 'porky'"); /// The ssid config generated by build.rs in "$OUT_DIR/ssid.rs" mod ssid { @@ -141,53 +135,34 @@ async fn main(spawner: Spawner) { // PIN_23 - OP wireless power on signal let (mut control, wifi_stack) = wifi::start_net(spawner, peripherals.PIN_23, spi).await; - // Pins available to be programmed, but are not connected to header - // WL_GPIO0 - via CYW43 - Connected to user LED - // WL_GPIO1 - via CYW43 - Output controls on-board SMPS power save pin - // WL_GPIO2 - via CYW43 - Input VBUS sense - high if VBUS is present, else low - // - // GPIO Pins Used Internally that are not in the list below - // GP23 - Output wireless on signal - used by embassy - // GP24 - Output/Input wireless SPI data/IRQ - // GP25 - Output wireless SPI CS- when high enables GPIO29 ADC pin to read VSYS - // GP29 - Output/Input SPI CLK/ADC Mode to measure VSYS/3 - // - // Refer to $ProjectRoot/assets/images/pi_pico_w_pinout.png - // Take the set of available pins not used by other functions, including the three pins that - // are connected via the CYW43 Wi-Fi chip. Create [Flex] Pins out of each of the GPIO pins. - // Put them all into the GPIO_PINS map, marking them as available - // NOTE: All pin numbers are GPIO (BCM) Pin Numbers, not physical pin numbers - // Take the following pins out of peripherals for use a GPIO - unsafe { - #[cfg(not(feature = "debug-probe"))] - let _ = GPIO_PINS.insert(0, Available(Flex::new(peripherals.PIN_0))); - #[cfg(not(feature = "debug-probe"))] - let _ = GPIO_PINS.insert(1, Available(Flex::new(peripherals.PIN_1))); - let _ = GPIO_PINS.insert(2, Available(Flex::new(peripherals.PIN_2))); - let _ = GPIO_PINS.insert(3, Available(Flex::new(peripherals.PIN_3))); - let _ = GPIO_PINS.insert(4, Available(Flex::new(peripherals.PIN_4))); - let _ = GPIO_PINS.insert(5, Available(Flex::new(peripherals.PIN_5))); - let _ = GPIO_PINS.insert(6, Available(Flex::new(peripherals.PIN_6))); - let _ = GPIO_PINS.insert(7, Available(Flex::new(peripherals.PIN_7))); - let _ = GPIO_PINS.insert(8, Available(Flex::new(peripherals.PIN_8))); - let _ = GPIO_PINS.insert(9, Available(Flex::new(peripherals.PIN_9))); - let _ = GPIO_PINS.insert(10, Available(Flex::new(peripherals.PIN_10))); - let _ = GPIO_PINS.insert(11, Available(Flex::new(peripherals.PIN_11))); - let _ = GPIO_PINS.insert(12, Available(Flex::new(peripherals.PIN_12))); - let _ = GPIO_PINS.insert(13, Available(Flex::new(peripherals.PIN_13))); - let _ = GPIO_PINS.insert(14, Available(Flex::new(peripherals.PIN_14))); - let _ = GPIO_PINS.insert(15, Available(Flex::new(peripherals.PIN_15))); - let _ = GPIO_PINS.insert(16, Available(Flex::new(peripherals.PIN_16))); - let _ = GPIO_PINS.insert(17, Available(Flex::new(peripherals.PIN_17))); - let _ = GPIO_PINS.insert(18, Available(Flex::new(peripherals.PIN_18))); - let _ = GPIO_PINS.insert(19, Available(Flex::new(peripherals.PIN_19))); - let _ = GPIO_PINS.insert(20, Available(Flex::new(peripherals.PIN_20))); - let _ = GPIO_PINS.insert(21, Available(Flex::new(peripherals.PIN_21))); - let _ = GPIO_PINS.insert(22, Available(Flex::new(peripherals.PIN_22))); - let _ = GPIO_PINS.insert(26, Available(Flex::new(peripherals.PIN_26))); - let _ = GPIO_PINS.insert(27, Available(Flex::new(peripherals.PIN_27))); - let _ = GPIO_PINS.insert(28, Available(Flex::new(peripherals.PIN_28))); - } + let mut gpio = Gpio::new( + peripherals.PIN_0, + peripherals.PIN_1, + peripherals.PIN_2, + peripherals.PIN_3, + peripherals.PIN_4, + peripherals.PIN_5, + peripherals.PIN_6, + peripherals.PIN_7, + peripherals.PIN_8, + peripherals.PIN_9, + peripherals.PIN_10, + peripherals.PIN_11, + peripherals.PIN_12, + peripherals.PIN_13, + peripherals.PIN_14, + peripherals.PIN_15, + peripherals.PIN_16, + peripherals.PIN_17, + peripherals.PIN_18, + peripherals.PIN_19, + peripherals.PIN_20, + peripherals.PIN_21, + peripherals.PIN_22, + peripherals.PIN_26, + peripherals.PIN_27, + peripherals.PIN_28, + ); // create hardware description let mut flash = flash::get_flash(peripherals.FLASH); @@ -214,7 +189,7 @@ async fn main(spawner: Spawner) { let mut hardware_config = persistence::get_config(db).await; // apply the loaded config to the hardware immediately - gpio::apply_config_change( + gpio.apply_config_change( &mut control, &spawner, &HardwareConfigMessage::NewConfig(hardware_config.clone()), @@ -238,15 +213,27 @@ async fn main(spawner: Spawner) { TCP_MDNS_SERVICE_PROTOCOL, )); - let tcp = (ip.octets(), TCP_PORT); + #[cfg(all(feature = "usb", feature = "wifi"))] + let mut usb_connection = usb::start( + spawner, + driver, + hw_desc, + Some((ip.octets(), TCP_PORT)), + db, + watchdog, + ) + .await; - #[cfg(feature = "usb")] + #[cfg(all(feature = "usb", not(feature = "wifi")))] let mut usb_connection = - usb::start(spawner, driver, hw_desc, Some(tcp), db, watchdog).await; + usb::start(spawner, driver, hw_desc, None, db, watchdog).await; + #[cfg(feature = "wifi")] let mut wifi_tx_buffer = [0; 4096]; + #[cfg(feature = "wifi")] let mut wifi_rx_buffer = [0; 4096]; + #[cfg(all(feature = "usb", feature = "wifi"))] loop { match select( tcp::wait_connection(wifi_stack, &mut wifi_tx_buffer, &mut wifi_rx_buffer), @@ -257,6 +244,7 @@ async fn main(spawner: Spawner) { Either::First(socket_select) => match socket_select { Ok(socket) => { tcp::message_loop( + &mut gpio, socket, hw_desc, &mut hardware_config, @@ -271,6 +259,7 @@ async fn main(spawner: Spawner) { Either::Second(_) => { #[cfg(feature = "usb")] usb::message_loop( + &mut gpio, &mut usb_connection, &mut hardware_config, &spawner, @@ -282,6 +271,27 @@ async fn main(spawner: Spawner) { } } } + + #[cfg(all(not(feature = "usb"), feature = "wifi"))] + loop { + match tcp::wait_connection(wifi_stack, &mut wifi_tx_buffer, &mut wifi_rx_buffer) + .await + { + Ok(socket) => { + tcp::message_loop( + &mut gpio, + socket, + hw_desc, + &mut hardware_config, + &spawner, + &mut control, + db, + ) + .await + } + Err(_) => error!("TCP accept error"), + } + } } Err(e) => { error!("Could not join Wi-Fi network: {}, so starting USB only", e); @@ -291,6 +301,7 @@ async fn main(spawner: Spawner) { usb::start(spawner, driver, hw_desc, None, db, watchdog).await; usb::wait_connection(&mut usb_connection, &hardware_config).await; usb::message_loop( + &mut gpio, &mut usb_connection, &mut hardware_config, &spawner, @@ -310,6 +321,7 @@ async fn main(spawner: Spawner) { usb::start(spawner, driver, hw_desc, None, db, watchdog).await; usb::wait_connection(&mut usb_connection, &hardware_config).await; usb::message_loop( + &mut gpio, &mut usb_connection, &mut hardware_config, &spawner, diff --git a/porky/src/tcp.rs b/porky/src/tcp.rs index 6de49867..f6d3967c 100644 --- a/porky/src/tcp.rs +++ b/porky/src/tcp.rs @@ -1,7 +1,8 @@ use crate::flash::DbFlash; +use crate::gpio::Gpio; use crate::hw_definition::config::{HardwareConfig, HardwareConfigMessage}; use crate::hw_definition::description::HardwareDescription; -use crate::{flash, gpio, persistence, HARDWARE_EVENT_CHANNEL}; +use crate::{flash, persistence, HARDWARE_EVENT_CHANNEL}; use cyw43::Control; use defmt::info; use ekv::Database; @@ -83,7 +84,8 @@ pub async fn wait_connection<'a>( accept(tcp_socket).await } -pub async fn message_loop( +pub async fn message_loop<'a>( + gpio: &mut Gpio, mut socket: TcpSocket<'_>, hw_desc: &HardwareDescription<'_>, hw_config: &mut HardwareConfig, @@ -107,13 +109,8 @@ pub async fn message_loop( Either::First(config_message) => match config_message { None => break, Some(hardware_config_message) => { - gpio::apply_config_change( - control, - spawner, - &hardware_config_message, - hw_config, - ) - .await; + gpio.apply_config_change(control, spawner, &hardware_config_message, hw_config) + .await; let _ = persistence::store_config_change(db, &hardware_config_message).await; if matches!(hardware_config_message, HardwareConfigMessage::GetConfig) { send_hardware_config(&mut socket, hw_config).await; diff --git a/porky/src/usb.rs b/porky/src/usb.rs index c1dc179f..20017ea1 100644 --- a/porky/src/usb.rs +++ b/porky/src/usb.rs @@ -1,5 +1,6 @@ use crate::flash; use crate::flash::DbFlash; +use crate::gpio::Gpio; use crate::hw_definition::config::{HardwareConfig, HardwareConfigMessage}; use crate::hw_definition::description::HardwareDescription; #[cfg(feature = "wifi")] @@ -11,7 +12,7 @@ use crate::hw_definition::usb_values::{ #[cfg(feature = "wifi")] use crate::hw_definition::usb_values::{GET_WIFI_VALUE, RESET_SSID_VALUE, SET_SSID_VALUE}; use crate::persistence; -use crate::{gpio, HARDWARE_EVENT_CHANNEL}; +use crate::HARDWARE_EVENT_CHANNEL; use core::str; #[cfg(feature = "wifi")] use cyw43::Control; @@ -338,7 +339,8 @@ pub async fn wait_connection( /// Enter a loop waiting for messages either via USB (from Piggui) or from the Hardware. /// - When receive a message over USB from Piggui, apply to the hardware, save in Flash /// - WHen receiving from hardware, send the message to Piggui over USB -pub async fn message_loop( +pub async fn message_loop<'a>( + gpio: &mut Gpio, usb_connection: &mut UsbConnection, Endpoint<'static, USB, Out>>, hw_config: &mut HardwareConfig, spawner: &Spawner, @@ -361,7 +363,7 @@ pub async fn message_loop( .await { Either::First(hardware_config_message) => { - gpio::apply_config_change( + gpio.apply_config_change( #[cfg(feature = "wifi")] control, spawner,