diff --git a/.github/workflows/actions/setup-qemu/action.yml b/.github/workflows/actions/setup-qemu/action.yml deleted file mode 100644 index e69777a..0000000 --- a/.github/workflows/actions/setup-qemu/action.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: Download and build QEMU - -inputs: - qemu-version: - description: 'QEMU version' - required: true - type: string - -runs: - using: "composite" - steps: - - name: Cache QEMU - id: cache-qemu - uses: actions/cache/restore@v4 - with: - path: qemu_build - key: qemu-${{ inputs.qemu-version }}-slirp-1 - - name: Download and build QEMU - if: steps.cache-qemu.outputs.cache-hit != 'true' - env: - QEMU_PATH: qemu-${{ inputs.qemu-version }} - PREFIX: ${{ github.workspace }}/qemu_build - shell: bash - run: | - sudo apt-get update && sudo apt-get install -y ninja-build libslirp-dev libglib2.0-dev - wget https://download.qemu.org/$QEMU_PATH.tar.xz && tar -xJf $QEMU_PATH.tar.xz - cd $QEMU_PATH \ - && ./configure --prefix=$PREFIX --target-list=x86_64-softmmu,riscv64-softmmu,aarch64-softmmu,loongarch64-softmmu --enable-slirp \ - && make -j > /dev/null 2>&1 \ - && make install - - uses: actions/cache/save@v4 - if: steps.cache-qemu.outputs.cache-hit != 'true' - with: - path: qemu_build - key: qemu-${{ inputs.qemu-version }}-slirp-1 - - - name: Install QEMU - shell: bash - run: | - echo "$PWD/qemu_build/bin" >> $GITHUB_PATH - - name: Verify installation - shell: bash - run: | - qemu-system-aarch64 --version diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 451b69b..86e69d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,8 +2,6 @@ name: Check, Build and Test on: push: - branches: - - main pull_request: branches: - main diff --git a/Cargo.lock b/Cargo.lock index 84f1f62..9a468dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "allocator-api2" version = "0.2.21" @@ -362,6 +371,19 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "console" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.0", + "windows-sys 0.61.1", +] + [[package]] name = "convert_case" version = "0.7.1" @@ -516,6 +538,29 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" +[[package]] +name = "env_filter" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -625,13 +670,26 @@ version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ - "console", + "console 0.15.11", "number_prefix", "portable-atomic", "unicode-width 0.2.0", "web-time", ] +[[package]] +name = "indicatif" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd" +dependencies = [ + "console 0.16.1", + "portable-atomic", + "unicode-width 0.2.0", + "unit-prefix", + "web-time", +] + [[package]] name = "indoc" version = "2.0.6" @@ -682,6 +740,30 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "jiff" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + [[package]] name = "js-sys" version = "0.3.77" @@ -887,7 +969,7 @@ checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "ostool" -version = "0.7.25" +version = "0.7.26" dependencies = [ "anyhow", "byte-unit", @@ -895,7 +977,9 @@ dependencies = [ "clap", "colored", "crossterm 0.29.0", - "indicatif", + "env_logger", + "indicatif 0.17.11", + "log", "network-interface", "object", "ratatui", @@ -948,6 +1032,15 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1070,6 +1163,35 @@ dependencies = [ "bitflags 2.9.0", ] +[[package]] +name = "regex" +version = "1.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" + [[package]] name = "rend" version = "0.4.2" @@ -1475,10 +1597,12 @@ dependencies = [ [[package]] name = "uboot-shell" -version = "0.1.9" +version = "0.1.10" dependencies = [ "colored", - "indicatif", + "env_logger", + "indicatif 0.18.0", + "log", "ntest", "serialport", ] @@ -1527,6 +1651,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" +[[package]] +name = "unit-prefix" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "323402cff2dd658f39ca17c789b502021b3f18707c91cdf22e3838e1b4023817" + [[package]] name = "utf8-width" version = "0.1.7" @@ -1646,6 +1776,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-sys" version = "0.52.0" @@ -1664,6 +1800,15 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" diff --git a/ostool/Cargo.toml b/ostool/Cargo.toml index a839c9b..126500e 100644 --- a/ostool/Cargo.toml +++ b/ostool/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ostool" -version = "0.7.25" +version = "0.7.26" edition = "2024" description = "A tool for operating system development" authors = ["周睿 "] @@ -26,3 +26,5 @@ ratatui = "0.29" crossterm = "0.29" indicatif = "0.17" uboot-shell = { version = "0.1.9", path = "../uboot-shell" } +log = "0.4" +env_logger = "0.11" diff --git a/ostool/src/main.rs b/ostool/src/main.rs index 24b2fa8..4b7506f 100644 --- a/ostool/src/main.rs +++ b/ostool/src/main.rs @@ -65,6 +65,11 @@ struct QemuArgs { } fn main() -> Result<()> { + env_logger::builder() + .format_module_path(false) + .filter_level(log::LevelFilter::Info) + .init(); + let cli = Cli::parse(); let workdir = cli .workdir diff --git a/uboot-shell/Cargo.toml b/uboot-shell/Cargo.toml index c4b2ea8..7d40b84 100644 --- a/uboot-shell/Cargo.toml +++ b/uboot-shell/Cargo.toml @@ -1,18 +1,20 @@ [package] -name = "uboot-shell" -version = "0.1.9" -edition = "2024" -description = "A crate for communicating with u-boot" authors = ["周睿 "] -license = "MIT" -keywords = ["u-boot", "shell", "embedded"] categories = ["os", "embedded", "development-tools"] +description = "A crate for communicating with u-boot" +edition = "2024" +keywords = ["u-boot", "shell", "embedded"] +license = "MIT" +name = "uboot-shell" repository = "https://github.com/ZR233/ostool/ostool" +version = "0.1.10" [dependencies] colored = "3" +log = "0.4" [dev-dependencies] +indicatif = "0.18" ntest = "0.9" serialport = "4.6" -indicatif = "0.17" +env_logger = "0.11" diff --git a/uboot-shell/examples/env_var.rs b/uboot-shell/examples/env_var.rs new file mode 100644 index 0000000..cf0eafa --- /dev/null +++ b/uboot-shell/examples/env_var.rs @@ -0,0 +1,61 @@ +use std::{ + net::TcpStream, + process::{Child, Command}, + time::Duration, +}; + +use log::info; +use uboot_shell::UbootShell; + +fn main() { + env_logger::init(); + + let (mut out, mut uboot) = new_uboot(); + + uboot.set_env("fdt_addr", "0x40000000").unwrap(); + info!("set fdt_addr ok"); + assert_eq!(uboot.env_int("fdt_addr").unwrap(), 0x40000000); + + info!("finish"); + let _ = out.kill(); + let _ = out.wait(); +} + +fn new_uboot() -> (Child, UbootShell) { + // qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -bios assets/u-boot.bin -serial tcp::12345,server + let out = Command::new("qemu-system-aarch64") + .args([ + "-machine", + "virt", + "-cpu", + "cortex-a57", + "-nographic", + "-serial", + "tcp::12345,server", + "-bios", + "assets/u-boot.bin", + ]) + .spawn() + .unwrap(); + + let tx; + + loop { + std::thread::sleep(Duration::from_millis(100)); + match TcpStream::connect("127.0.0.1:12345") { + Ok(s) => { + tx = s; + break; + } + Err(e) => { + println!("wait for qemu serial port ready: {e}"); + } + } + } + + let rx = tx.try_clone().unwrap(); + rx.set_read_timeout(Some(Duration::from_millis(300))) + .unwrap(); + println!("connect ok"); + (out, UbootShell::new(tx, rx).unwrap()) +} diff --git a/uboot-shell/examples/loady.rs b/uboot-shell/examples/loady.rs index 75de68c..ed55816 100644 --- a/uboot-shell/examples/loady.rs +++ b/uboot-shell/examples/loady.rs @@ -1,25 +1,31 @@ use std::{ - io::Read, net::TcpStream, - process::{Child, Command, Stdio}, + process::{Child, Command}, time::Duration, }; +use log::{debug, info}; use uboot_shell::UbootShell; fn main() { + env_logger::init(); + let (mut out, mut uboot) = new_uboot(); - uboot.loady(0x40200000, "Cargo.toml", |_r, _a| {}).unwrap(); + uboot + .loady(0x40200000, "Cargo.toml", |r, a| { + debug!("{r}/{a}"); + }) + .unwrap(); - println!("finish"); + info!("finish"); let _ = out.kill(); let _ = out.wait(); } fn new_uboot() -> (Child, UbootShell) { - // qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -bios assets/u-boot.bin - let mut out = Command::new("qemu-system-aarch64") + // qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -bios assets/u-boot.bin -serial tcp::12345,server + let out = Command::new("qemu-system-aarch64") .args([ "-machine", "virt", @@ -27,27 +33,31 @@ fn new_uboot() -> (Child, UbootShell) { "cortex-a57", "-nographic", "-serial", - "tcp::12345,server,nowait", + "tcp::12345,server", "-bios", "assets/u-boot.bin", ]) - .stdout(Stdio::piped()) .spawn() .unwrap(); - let stdout = out.stdout.take().unwrap(); - let mut buff = vec![]; - for i in stdout.bytes() { - buff.push(i.unwrap()); - if String::from_utf8_lossy(&buff).contains("qemu") { - break; + let tx; + + loop { + std::thread::sleep(Duration::from_millis(100)); + match TcpStream::connect("127.0.0.1:12345") { + Ok(s) => { + tx = s; + break; + } + Err(e) => { + println!("wait for qemu serial port ready: {e}"); + } } } - let tx = TcpStream::connect("127.0.0.1:12345").unwrap(); - let rx = tx.try_clone().unwrap(); - rx.set_read_timeout(Some(Duration::from_secs(1))).unwrap(); - + rx.set_read_timeout(Some(Duration::from_millis(300))) + .unwrap(); + println!("connect ok"); (out, UbootShell::new(tx, rx).unwrap()) } diff --git a/uboot-shell/src/lib.rs b/uboot-shell/src/lib.rs index a312c43..333c44b 100644 --- a/uboot-shell/src/lib.rs +++ b/uboot-shell/src/lib.rs @@ -1,21 +1,31 @@ +#[macro_use] +extern crate log; + use std::{ fs::File, io::*, path::PathBuf, + sync::{ + Arc, + atomic::{AtomicBool, Ordering}, + }, + thread, time::{Duration, Instant}, }; -use colored::Colorize; - mod crc; mod ymodem; -macro_rules! trace { +macro_rules! dbg { ($($arg:tt)*) => {{ - println!("\r\n{}", &std::fmt::format(format_args!($($arg)*)).bright_black()); + debug!("$ {}", &std::fmt::format(format_args!($($arg)*))); }}; } +const CTRL_C: u8 = 0x03; +const INT_STR: &str = ""; +const INT: &[u8] = INT_STR.as_bytes(); + pub struct UbootShell { pub tx: Option>, pub rx: Option>, @@ -31,7 +41,7 @@ impl UbootShell { perfix: "".to_string(), }; s.wait_for_shell()?; - trace!("shell ready, perfix: `{}`", s.perfix); + debug!("shell ready, perfix: `{}`", s.perfix); Ok(s) } @@ -43,51 +53,41 @@ impl UbootShell { self.tx.as_mut().unwrap() } - fn wait_for_shell(&mut self) -> Result<()> { - let mut history: Vec = Vec::new(); - const CTRL_C: u8 = 0x03; + fn wait_for_interrupt(&mut self) -> Result> { + let mut tx = self.tx.take().unwrap(); - let mut last = Instant::now(); - let mut is_interrupt_found = false; - let mut is_shell_ok = false; - const INT_STR: &str = ""; - const INT: &[u8] = INT_STR.as_bytes(); + let ok = Arc::new(AtomicBool::new(false)); - trace!("wait for `{INT_STR}`"); + let tx_handle = thread::spawn({ + let ok = ok.clone(); + move || { + while !ok.load(Ordering::Acquire) { + let _ = tx.write_all(&[CTRL_C]); + thread::sleep(Duration::from_millis(20)); + } + tx + } + }); + let mut history: Vec = Vec::new(); + let mut interrupt_line: Vec = Vec::new(); + debug!("wait for interrupt"); loop { match self.read_byte() { Ok(ch) => { - if ch == b'\n' && history.last() != Some(&b'\r') { - print_raw(b"\r"); - history.push(b'\r'); - } history.push(ch); - print_raw(&[ch]); - - if history.ends_with(INT) && !is_interrupt_found { - let line = history.split(|n| *n == b'\n').next_back().unwrap(); - let s = String::from_utf8_lossy(line); - self.perfix = s.trim().replace(INT_STR, "").trim().to_string(); - is_interrupt_found = true; - trace!("clear"); - let _ = self.rx().read_to_end(&mut vec![]); - trace!("test shell"); - let ret = self.tx().write_all("testshell\r\n".as_bytes()); - trace!("test shell ret {:?}", ret); - } - - if is_interrupt_found && history.ends_with("\'help\'".as_bytes()) { - is_shell_ok = true; - } - - if is_shell_ok && history.ends_with(self.perfix.as_bytes()) { - return Ok(()); - } - - if last.elapsed() > Duration::from_millis(20) && !is_interrupt_found { - let _ = self.tx().write_all(&[CTRL_C]); - last = Instant::now(); + if history.last() == Some(&b'\n') { + let line = history.trim_ascii_end(); + dbg!("{}", String::from_utf8_lossy(line)); + let it = line.ends_with(INT); + if it { + interrupt_line.extend_from_slice(line); + } + history.clear(); + if it { + ok.store(true, Ordering::Release); + break; + } } } @@ -99,6 +99,24 @@ impl UbootShell { } } } + + self.tx = Some(tx_handle.join().unwrap()); + + Ok(interrupt_line) + } + + fn clear_shell(&mut self) -> Result<()> { + let _ = self.read_to_end(&mut vec![]); + Ok(()) + } + + fn wait_for_shell(&mut self) -> Result<()> { + let mut line = self.wait_for_interrupt()?; + debug!("got {}", String::from_utf8_lossy(&line)); + line.resize(line.len() - INT.len(), 0); + self.perfix = String::from_utf8_lossy(&line).to_string(); + self.clear_shell()?; + Ok(()) } fn read_byte(&mut self) -> Result { @@ -127,14 +145,19 @@ impl UbootShell { pub fn wait_for_reply(&mut self, val: &str) -> Result { let mut reply = Vec::new(); - - trace!("wait for `{}`", val); + let mut display = Vec::new(); + debug!("wait for `{}`", val); loop { let byte = self.read_byte()?; reply.push(byte); - print_raw(&[byte]); + display.push(byte); + if byte == b'\n' { + dbg!("{}", String::from_utf8_lossy(&display).trim_end()); + display.clear(); + } if reply.ends_with(val.as_bytes()) { + dbg!("{}", String::from_utf8_lossy(&display).trim_end()); break; } } @@ -146,17 +169,24 @@ impl UbootShell { pub fn cmd_without_reply(&mut self, cmd: &str) -> Result<()> { self.tx().write_all(cmd.as_bytes())?; - self.tx().write_all("\r\n".as_bytes())?; + self.tx().write_all("\n".as_bytes())?; self.tx().flush()?; - self.wait_for_reply(cmd)?; - trace!("cmd ok"); + // self.wait_for_reply(cmd)?; + // debug!("cmd ok"); Ok(()) } pub fn cmd(&mut self, cmd: &str) -> Result { + info!("cmd: {cmd}"); self.cmd_without_reply(cmd)?; let perfix = self.perfix.clone(); - self.wait_for_reply(&perfix) + let res = self + .wait_for_reply(&perfix)? + .trim_end() + .trim_end_matches(self.perfix.as_str().trim()) + .trim_end() + .to_string(); + Ok(res) } pub fn set_env(&mut self, name: impl Into, value: impl Into) -> Result<()> { @@ -167,18 +197,25 @@ impl UbootShell { pub fn env(&mut self, name: impl Into) -> Result { let name = name.into(); let s = self.cmd(&format!("echo ${}", name))?; - if s.is_empty() { - return Err(Error::new( + let sp = s + .split("\n") + .filter(|s| !s.trim().is_empty()) + .collect::>(); + let s = sp + .last() + .ok_or(Error::new( ErrorKind::NotFound, format!("env {} not found", name), - )); - } + ))? + .to_string(); Ok(s) } pub fn env_int(&mut self, name: impl Into) -> Result { let name = name.into(); let line = self.env(&name)?; + debug!("env {name} = {line}"); + parse_int(&line).ok_or(Error::new( ErrorKind::InvalidData, format!("env {name} is not a number"), @@ -262,6 +299,7 @@ fn print_raw(buff: &[u8]) { #[cfg(target_os = "windows")] fn print_raw_win(buff: &[u8]) { + use std::sync::Mutex; static PRINT_BUFF: Mutex> = Mutex::new(Vec::new()); let mut g = PRINT_BUFF.lock().unwrap(); diff --git a/uboot-shell/src/ymodem.rs b/uboot-shell/src/ymodem.rs index 36bb88a..1eae1f1 100644 --- a/uboot-shell/src/ymodem.rs +++ b/uboot-shell/src/ymodem.rs @@ -60,19 +60,20 @@ impl Ymodem { size: usize, on_progress: impl Fn(usize), ) -> Result<()> { - println!("Sending file: {name}"); + info!("Sending file: {name}"); self.send_header(dev, name, size)?; let mut buff = [0u8; 1024]; + let mut send_size = 0; while let Ok(n) = file.read(&mut buff) { if n == 0 { break; } self.send_blk(dev, &buff[..n], EOF, false)?; - - on_progress(self.blk as usize * 1024); + send_size += n; + on_progress(send_size); } dev.write_all(&[EOT])?; diff --git a/uboot-shell/tests/test.rs b/uboot-shell/tests/test.rs index dc38303..d828a84 100644 --- a/uboot-shell/tests/test.rs +++ b/uboot-shell/tests/test.rs @@ -1,11 +1,11 @@ use std::{ - io::Read, net::TcpStream, - process::{Child, Command, Stdio}, + process::{Child, Command}, sync::atomic::AtomicU32, time::Duration, }; +use log::{debug, info}; use ntest::timeout; use uboot_shell::UbootShell; @@ -15,7 +15,7 @@ fn new_uboot() -> (Child, UbootShell) { let port = PORT.fetch_add(1, std::sync::atomic::Ordering::SeqCst); // qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -bios assets/u-boot.bin - let mut out = Command::new("qemu-system-aarch64") + let out = Command::new("qemu-system-aarch64") .arg("-serial") .arg(format!("tcp::{port},server,nowait")) .args([ @@ -27,26 +27,28 @@ fn new_uboot() -> (Child, UbootShell) { "-bios", "../assets/u-boot.bin", ]) - .stdout(Stdio::piped()) .spawn() .unwrap(); - let stdout = out.stdout.take().unwrap(); - let mut buff = vec![]; - for i in stdout.bytes() { - buff.push(i.unwrap()); - if String::from_utf8_lossy(&buff).contains("qemu") { - break; + let tx; + + loop { + std::thread::sleep(Duration::from_millis(100)); + match TcpStream::connect(format!("127.0.0.1:{port}")) { + Ok(s) => { + tx = s; + break; + } + Err(e) => { + debug!("wait for qemu serial port ready: {e}"); + } } } - let tx = TcpStream::connect(format!("127.0.0.1:{port}")).unwrap(); - - tx.set_read_timeout(Some(Duration::from_millis(300))) - .unwrap(); - let rx = tx.try_clone().unwrap(); - + rx.set_read_timeout(Some(Duration::from_millis(300))) + .unwrap(); + info!("connect ok"); (out, UbootShell::new(tx, rx).unwrap()) } @@ -54,6 +56,7 @@ fn new_uboot() -> (Child, UbootShell) { #[timeout(5000)] fn test_shell() { let (mut out, _uboot) = new_uboot(); + info!("test_shell ok"); let _ = out.kill(); out.wait().unwrap(); } @@ -88,6 +91,8 @@ fn test_setenv() { #[timeout(5000)] fn test_env() { with_uboot(|uboot| { + uboot.set_env("fdt_addr", "0x40000000").unwrap(); + info!("set fdt_addr ok"); assert_eq!(uboot.env_int("fdt_addr").unwrap(), 0x40000000); }); }