From 58461b60b1dbf6e59a7a3f980278eb7a70290782 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 24 May 2023 00:22:18 +0800 Subject: [PATCH] Extra USB serial with menu kind of works Need to figure out echo problem --- embassy/demos/picow/Cargo.toml | 2 + embassy/demos/picow/src/main.rs | 39 ++++++++++------ embassy/demos/picow/src/usbserial.rs | 66 ++++++++++++++++++---------- embassy/src/embassy_sunset.rs | 17 +++++++ embassy/src/lib.rs | 2 +- 5 files changed, 87 insertions(+), 39 deletions(-) diff --git a/embassy/demos/picow/Cargo.toml b/embassy/demos/picow/Cargo.toml index 18ad37f..5786c99 100644 --- a/embassy/demos/picow/Cargo.toml +++ b/embassy/demos/picow/Cargo.toml @@ -76,6 +76,8 @@ embassy-usb-driver = { git = "https://github.com/embassy-rs/embassy", rev = "3e7 embassy-net-driver-channel = { git = "https://github.com/embassy-rs/embassy", rev = "3e730aa8b06401003202bf9e21a9c83ec6b21b0e" } embassy-net-driver = { git = "https://github.com/embassy-rs/embassy", rev = "3e730aa8b06401003202bf9e21a9c83ec6b21b0e" } +# embedded-io = { path = "/home/matt/3rd/rs/embedded-io" } + [profile.dev] debug = 2 debug-assertions = true diff --git a/embassy/demos/picow/src/main.rs b/embassy/demos/picow/src/main.rs index 968b8f9..c888403 100644 --- a/embassy/demos/picow/src/main.rs +++ b/embassy/demos/picow/src/main.rs @@ -16,6 +16,9 @@ pub use defmt::{debug, info, warn, panic, error, trace}; use {defmt_rtt as _, panic_probe as _}; +use core::fmt::Write as _; + + use embassy_executor::Spawner; use embassy_net::Stack; use embassy_futures::join::join; @@ -23,7 +26,7 @@ use embassy_futures::select::select; use embassy_rp::{pio::PioPeripheral, interrupt}; use embassy_rp::peripherals::FLASH; use embedded_io::{asynch, Io}; -use embedded_io::asynch::Write; +use embedded_io::asynch::Write as _; use heapless::{String, Vec}; @@ -79,10 +82,6 @@ async fn main(spawner: Spawner) { SunsetMutex::new(config) ); - let usb_pipe = singleton!(takepipe::TakePipe::new()); - let usb_pipe = singleton!(usb_pipe.base()); - let usb_irq = interrupt::take!(USBCTRL_IRQ); - spawner.spawn(usb_serial_task(p.USB, usb_irq, usb_pipe)).unwrap(); let (wifi_net, wifi_pw) = { let c = config.lock().await; @@ -96,6 +95,9 @@ async fn main(spawner: Spawner) { let wifi_control = singleton!(SunsetMutex::new(wifi_control)); spawner.spawn(net_task(&stack)).unwrap(); + let usb_pipe = singleton!(takepipe::TakePipe::new()); + let usb_pipe = singleton!(usb_pipe.base()); + let state = GlobalState { usb_pipe, wifi_control, @@ -104,6 +106,9 @@ async fn main(spawner: Spawner) { }; let state = singleton!(state); + let usb_irq = interrupt::take!(USBCTRL_IRQ); + spawner.spawn(usb_serial_task(p.USB, usb_irq, state)).unwrap(); + for _ in 0..NUM_LISTENERS { spawner.spawn(listener(&stack, config, state)).unwrap(); } @@ -135,7 +140,9 @@ struct DemoShell { username: SunsetMutex>, } +// `local` is set for usb serial menus which require different auth async fn menu(mut chanr: R, mut chanw: W, + local: bool, state: &'static GlobalState) -> Result<()> where R: asynch::Read+Io, W: asynch::Write+Io { @@ -163,9 +170,14 @@ async fn menu(mut chanr: R, mut chanw: W, // TODO: move this to a function or something if menu.context.switch_usb1 { - serial(chanr, chanw, state).await?; - // TODO we could return to the menu on serial error? - break 'io; + menu.context.switch_usb1 = false; + if local { + writeln!(menu.context.out, "serial can't loop"); + } else { + serial(chanr, chanw, state).await?; + // TODO we could return to the menu on serial error? + break 'io; + } } if menu.context.need_save { @@ -178,6 +190,8 @@ async fn menu(mut chanr: R, mut chanw: W, warn!("Error writing flash"); } } + + menu.context.out.flush(&mut chanw).await?; } } Ok(()) @@ -264,7 +278,7 @@ impl Shell for DemoShell { if *self.username.lock().await == "serial" { serial(stdio.clone(), stdio, self.ctx).await } else { - menu(stdio.clone(), stdio, self.ctx).await + menu(stdio.clone(), stdio, false, self.ctx).await } }; @@ -280,13 +294,10 @@ async fn net_task(stack: &'static Stack>) -> ! { #[embassy_executor::task] async fn usb_serial_task(usb: embassy_rp::peripherals::USB, irq: embassy_rp::interrupt::USBCTRL_IRQ, - pipe: &'static TakeBase<'static>, + global: &'static GlobalState, ) -> ! { - info!("usb serial"); - let (mut rx, mut tx) = pipe.split(); - - usbserial::usb_serial(usb, irq, &mut tx, &mut rx).await; + usbserial::usb_serial(usb, irq, global).await; todo!("shoudln't exit"); } diff --git a/embassy/demos/picow/src/usbserial.rs b/embassy/demos/picow/src/usbserial.rs index 272f582..5780265 100644 --- a/embassy/demos/picow/src/usbserial.rs +++ b/embassy/demos/picow/src/usbserial.rs @@ -6,7 +6,7 @@ pub use log::{debug, error, info, log, trace, warn}; #[cfg(feature = "defmt")] pub use defmt::{debug, error, info, panic, trace, warn}; -use embassy_futures::join::join; +use embassy_futures::join::{join, join3}; use embassy_rp::usb::Instance; use embassy_usb::class::cdc_acm::{self, CdcAcmClass, State}; use embassy_usb::Builder; @@ -17,16 +17,15 @@ use embedded_io::{asynch, Io, asynch::BufRead}; use heapless::Vec; use sunset::*; -use sunset_embassy::io_copy; +use sunset_embassy::*; -pub async fn usb_serial( +use crate::*; + +pub(crate) async fn usb_serial( usb: embassy_rp::peripherals::USB, irq: embassy_rp::interrupt::USBCTRL_IRQ, - tx: &mut W, - rx: &mut R, + global: &'static GlobalState, ) - where R: asynch::Read+Io, - W: asynch::Write+Io { info!("usb_serial top"); @@ -53,7 +52,9 @@ pub async fn usb_serial( let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 64]; - let mut state = State::new(); + // lives longer than builder + let mut usb_state0 = State::new(); + let mut usb_state2 = State::new(); let mut builder = Builder::new( driver, @@ -64,34 +65,54 @@ pub async fn usb_serial( &mut control_buf, ); - let cdc = CdcAcmClass::new(&mut builder, &mut state, 64); - let (mut cdc_tx, mut cdc_rx) = cdc.split(); - // let cdc_tx = &mut cdc_tx; - // let cdc_rx = &mut cdc_rx; + // if00 + let cdc0 = CdcAcmClass::new(&mut builder, &mut usb_state0, 64); + let (mut cdc0_tx, mut cdc0_rx) = cdc0.split(); + // if02 + let cdc2 = CdcAcmClass::new(&mut builder, &mut usb_state2, 64); + let (mut cdc2_tx, mut cdc2_rx) = cdc2.split(); let mut usb = builder.build(); + // Run the USB device. let usb_fut = usb.run(); - let io = async { + let io0 = async { + let (mut chan_rx, mut chan_tx) = global.usb_pipe.split(); + let chan_rx = &mut chan_rx; + let chan_tx = &mut chan_tx; + loop { + info!("usb waiting"); + cdc0_rx.wait_connection().await; + info!("Connected"); + let mut cdc0_tx = CDCWrite::new(&mut cdc0_tx); + let mut cdc0_rx = CDCRead::new(&mut cdc0_rx); + + let io_tx = io_buf_copy(&mut cdc0_rx, chan_tx); + let io_rx = io_copy::<64, _, _>(chan_rx, &mut cdc0_tx); + + let _ = join(io_rx, io_tx).await; + info!("Disconnected"); + } + }; + + let setup = async { loop { info!("usb waiting"); - cdc_rx.wait_connection().await; + cdc2_rx.wait_connection().await; info!("Connected"); - let mut cdc_tx = CDCWrite::new(&mut cdc_tx); - let mut cdc_rx = CDCRead::new(&mut cdc_rx); + let cdc2_tx = CDCWrite::new(&mut cdc2_tx); + let cdc2_rx = CDCRead::new(&mut cdc2_rx); - let io_tx = io_copy::<64, _, _>(&mut cdc_rx, tx); - let io_rx = io_copy::<64, _, _>(rx, &mut cdc_tx); + let _ = menu(cdc2_rx, cdc2_tx, true, global).await; - join(io_rx, io_tx).await; info!("Disconnected"); } }; info!("usb join"); - join(usb_fut, io).await; + join3(usb_fut, io0, setup).await; } pub struct CDCRead<'a, 'p, D: Driver<'a>> { @@ -184,10 +205,7 @@ impl<'a, D: Driver<'a>> asynch::Write for CDCWrite<'a, '_, D> { async fn write(&mut self, buf: &[u8]) -> sunset::Result { // limit to 63 so we can ignore dealing with ZLPs for now let b = &buf[..buf.len().min(63)]; - self.0 - .write_packet(b) - .await - .map_err(|_| sunset::Error::ChannelEOF)?; + self.0.write_packet(b).await.map_err(|_| sunset::Error::ChannelEOF)?; Ok(b.len()) } } diff --git a/embassy/src/embassy_sunset.rs b/embassy/src/embassy_sunset.rs index 6dd9be8..7746c8b 100644 --- a/embassy/src/embassy_sunset.rs +++ b/embassy/src/embassy_sunset.rs @@ -530,3 +530,20 @@ pub async fn io_copy(r: &mut R, w: &mut W) -> Result<()> #[allow(unreachable_code)] Ok::<_, Error>(()) } + +pub async fn io_buf_copy(r: &mut R, w: &mut W) -> Result<()> + where R: asynch::BufRead+Io, + W: asynch::Write+Io +{ + loop { + let b = r.fill_buf().await?; + if b.len() == 0 { + return sunset::error::ChannelEOF.fail(); + } + let n = b.len(); + w.write_all(b).await?; + r.consume(n) + } + #[allow(unreachable_code)] + Ok::<_, Error>(()) +} diff --git a/embassy/src/lib.rs b/embassy/src/lib.rs index d5db6eb..79c292b 100644 --- a/embassy/src/lib.rs +++ b/embassy/src/lib.rs @@ -19,4 +19,4 @@ pub use client::SSHClient; pub use embassy_channel::{ChanInOut, ChanIn, ChanOut}; -pub use embassy_sunset::{SunsetMutex, SunsetRawMutex, io_copy}; +pub use embassy_sunset::{SunsetMutex, SunsetRawMutex, io_copy, io_buf_copy};