From 20452d44f63533d9973ad0a65eea99edd9919249 Mon Sep 17 00:00:00 2001 From: Ling Wang Date: Fri, 13 Sep 2024 01:27:40 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(Test):=20Add=20BPiF3-Armbian?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Finish fixes and changes for real use - Finish test on BPiF3 - Armbian comb --- .gitignore | 1 + TODO.md | 1 + apps/boards/bpif3.py | 8 +++--- apps/bpif3_armbian.py | 21 ++++++++++++--- apps/system/armbian.py | 41 ++++++++++++++++------------- src/exec/cli_exec.rs | 8 +++--- src/term/asciicast.rs | 58 ++++++++++++++++++++++-------------------- src/term/serial.rs | 26 ++++++++++++++----- src/term/shell.rs | 2 +- 9 files changed, 102 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index 44c8b0b..1c3aa0f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target *.log +*.cast # Byte-compiled / optimized / DLL files diff --git a/TODO.md b/TODO.md index 32de66f..5a7a48d 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,5 @@ - [ ] **修 shell……** +- [ ] **想办法把那个 PyTty 缩小掉……** - [ ] 更多的连接方式 - [x] 更完善的 SSH diff --git a/apps/boards/bpif3.py b/apps/boards/bpif3.py index a2a45e7..71d7319 100644 --- a/apps/boards/bpif3.py +++ b/apps/boards/bpif3.py @@ -3,7 +3,7 @@ """ from time import sleep -from tester import PyTty, PySerial, PySdWirec, PyExec +from tester import PyTty, PySerial, PySdWirec, PyExec, info class BPiF3: @@ -23,7 +23,8 @@ def flash(self, shell: PyExec, img: str, dsk="/dev/sda"): self.sdwirec.to_ts() sleep(0.5) shell.assert_script_sudo( - f"dd if={img} of={dsk} bs=1M status=progress", 600) + f"dd if={img} of={dsk} status=progress", 600) + shell.assert_script_sudo("sync") sleep(0.5) self.sdwirec.to_dut() sleep(0.5) @@ -35,7 +36,8 @@ def power_cycle(self): Maybe some relay or something? But for now, manually power cycle the board. """ - input("Please power cycle the board and press enter to continue.") + info("Please power cycle the board and continue. You have arount 10s.") + sleep(10) def get_console(self) -> PyTty: """ diff --git a/apps/bpif3_armbian.py b/apps/bpif3_armbian.py index 7c2a789..0063e27 100644 --- a/apps/bpif3_armbian.py +++ b/apps/bpif3_armbian.py @@ -29,7 +29,8 @@ def default_proc(): board = BPiF3("id = 0\n", "/dev/ttyUSB0", 115200) - url = "/AArmbian-bpi-SpacemiT_24.5.0-trunk_Bananapif3_mantic_legacy_6.1.15_xfce_desktop.img.xz" # 度盘,dummy + # url = "/Armbian-bpi-SpacemiT_24.5.0-trunk_Bananapif3_mantic_legacy_6.1.15_xfce_desktop.img.xz" # 度盘,dummy + url = "https://mirrors.tuna.tsinghua.edu.cn/armbian-releases/bananapif3/archive/Armbian_24.8.1_Bananapif3_noble_legacy_6.1.15_minimal.img.xz" work_dir = "/home/lw/Work/plct/boards/bpif3/armbian" img = wget_image(url, work_dir) if img is None: @@ -43,11 +44,12 @@ def default_proc(): info("Begin flashing board...") - board.flash(e, img) + board.flash(e, img, "/dev/mmcblk0") info("Flash board ended...") console = board.get_console() + console = PyTee(console, "con.log") asciicast = e.exit() local_shell = swap_tty(asciicast, console) @@ -61,13 +63,24 @@ def default_proc(): system.loggin() + asciicast = e.exit() + logger = PyTty("wrap=true\nsimple_recorder=true\n", asciicast) + logger.begin() + e = PyExec(logger) + system.tty = e + system.get_info() - asciicast = e.exit() + logger = e.exit() + info_log = logger.end() + asciicast = logger.exit() res = asciicast.end() - with open("res.cast") as f: + with open("res.cast", "w") as f: f.write(res) + with open("info.log", "w") as f: + f.write(info_log) + if __name__ == "__main__": default_proc() diff --git a/apps/system/armbian.py b/apps/system/armbian.py index 68df569..abc11f4 100644 --- a/apps/system/armbian.py +++ b/apps/system/armbian.py @@ -5,16 +5,19 @@ from time import sleep from tester import PyExec -def slp(t = 0.5): + +def slp(t=0.5): """ Sleep for t second. """ sleep(t) + class Armbian: """ System class for Armbian. """ + def __init__(self, tty: PyExec): self.tty = tty @@ -38,32 +41,34 @@ def loggin(self): """ # init settings - self.wit("IP address:") - self.wln("") - self.wit("Create root password:") + self.wit("Create root password") self.wln("autotest_123") - self.wit("Repeat root password:") + self.wit("Repeat root password") self.wln("autotest_123") # Choose default system command shell: - slp(2) - self.wln("1") + # slp(2) + # self.wln("1") # register new user - self.wit("(eg. your first name):") + self.wit("(eg. your first name)") self.wln("plct") - self.wit("password:") + self.wit("password") self.wln("plct_123") - self.wit("password:") + self.wit("password") self.wln("plct_123") - self.wit("real name:") - self.wln("Plct") + self.wit("real name") + self.wln("") - # Set user language based on your location? [Y/n] - self.wit("[Y/n]") - self.wln("y") - # Set time zone - self.wit("choice:") - self.wln("328") + try: + self.wit("wireless", 10) + self.wln("n") + except Exception: + pass + + # At your location, more locales are possible: + self.wit("location") + slp(2) + self.wln("332") # Please select a continent, ocean, "coord", or "TZ". self.wit("#?") self.wln("4") diff --git a/src/exec/cli_exec.rs b/src/exec/cli_exec.rs index 8343b35..72d69c8 100644 --- a/src/exec/cli_exec.rs +++ b/src/exec/cli_exec.rs @@ -6,7 +6,7 @@ use std::{ }; use crate::{ - consts::DURATION, err, log, term::tty::{DynTty, InnerTty, Tty, WrapperTty}, util::{anybase::AnyBase, util::rand_string} + consts::DURATION, err, info, log, term::tty::{DynTty, InnerTty, Tty, WrapperTty}, util::{anybase::AnyBase, util::rand_string} }; use super::cli_api::CliTestApi; @@ -23,7 +23,7 @@ impl CliTester { impl CliTester { fn run_command(&mut self, command: &String) -> Result<(), Box> { - log!("Write to shell: {}", command); + info!("Write to shell: {}", command); let res = self.inner.write(command.as_bytes()); if let Err(e) = res { return Err(e); @@ -78,6 +78,7 @@ impl CliTestApi for CliTester { fn wait_serial(&mut self, expected: &str, timeout: u32) -> Result<(), Box> { let begin = Instant::now(); let mut buf = Vec::new(); + info!("Waiting for string {{{}}}", expected); loop { sleep(Duration::from_millis(DURATION)); let res = self.inner.read(); @@ -86,8 +87,9 @@ impl CliTestApi for CliTester { } let line = res.unwrap(); buf.extend_from_slice(&line); - let content = String::from_utf8(buf.clone()).unwrap(); + let content = String::from_utf8(buf.clone()).unwrap_or_default(); if content.contains(expected) { + info!("Matched string {{{}}}", expected); break; } if begin.elapsed().as_secs() > timeout as u64 { diff --git a/src/term/asciicast.rs b/src/term/asciicast.rs index 8681437..347a79e 100644 --- a/src/term/asciicast.rs +++ b/src/term/asciicast.rs @@ -85,7 +85,7 @@ impl Asciicast { logged.push(Entry { time: timestamp, event_type: EventType::Output, - event_data: String::from_utf8(new_data.clone()).unwrap(), + event_data: String::from_utf8(new_data.clone()).unwrap_or_default(), }); } @@ -144,29 +144,30 @@ impl Tty for Asciicast { return Ok(res); } fn write(&mut self, data: &[u8]) -> Result<(), Box> { - let begin = self.begin.lock(); - if let Err(_) = begin { - return Err(Box::::from("Recorder not started.")); - } - let begin = begin.unwrap(); - if *begin { - let begin_time = self.begin_time.lock().unwrap(); - let time = begin_time.elapsed().unwrap(); - let timestamp = time.as_millis(); - let timestamp = timestamp as f64 / 1000.0; - let mut logged = self.logged.lock().unwrap(); - let line = String::from_utf8(data.to_vec()).unwrap(); - let line = SHELL_PROMPT.to_string() + &line; - let line = line.replace("\\n", "\\r\\n"); - logged.push(Entry { - time: timestamp, - // event_type: EventType::Input, - event_type: EventType::Output, - event_data: line, - }); - } - - let mut inner = self.inner.lock().unwrap(); + // let begin = self.begin.lock(); + // if let Err(_) = begin { + // return Err(Box::::from("Recorder not started.")); + // } + // let begin = begin.unwrap(); + // if *begin { + // let begin_time = self.begin_time.lock().unwrap(); + // let time = begin_time.elapsed().unwrap(); + // let timestamp = time.as_millis(); + // let timestamp = timestamp as f64 / 1000.0; + // let mut logged = self.logged.lock().unwrap(); + // let line = String::from_utf8(data.to_vec()).unwrap(); + // let line = SHELL_PROMPT.to_string() + &line; + // let line = line.replace("\\n", "\\r\\n"); + // logged.push(Entry { + // time: timestamp, + // // event_type: EventType::Input, + // event_type: EventType::Output, + // event_data: line, + // }); + // } + + let inner = self.inner.clone(); + let mut inner = inner.lock().unwrap(); if inner.is_none() { return Err(Box::::from("You've already exited.")); } @@ -179,7 +180,8 @@ impl Tty for Asciicast { impl WrapperTty for Asciicast { fn exit(self) -> DynTty { - let mut inner = self.inner.lock().unwrap(); + let inner = self.inner.clone(); + let mut inner = inner.lock().unwrap(); let inner = inner.take().unwrap(); inner } @@ -279,14 +281,14 @@ impl Recorder for Asciicast { } fn swap(&mut self, target: DynTty) -> Result> { - sleep(Duration::from_micros(100)); - let mut inner = self.inner.lock().unwrap(); + sleep(Duration::from_micros(DURATION)); + let inner = self.inner.clone(); + let mut inner = inner.lock().unwrap(); if inner.is_none() { return Err(Box::::from("You've already exited.")); } let res = inner.take().unwrap(); *inner = Some(target); - sleep(Duration::from_micros(100)); Ok(res) } } diff --git a/src/term/serial.rs b/src/term/serial.rs index be144e5..1259616 100644 --- a/src/term/serial.rs +++ b/src/term/serial.rs @@ -7,9 +7,9 @@ use std::time::Duration; use serialport::{self, SerialPort}; use crate::consts::SHELL_DURATION; -use crate::{err, info}; use crate::term::tty::Tty; use crate::util::anybase::AnyBase; +use crate::{err, info}; pub struct Serial { inner: Box, @@ -17,7 +17,9 @@ pub struct Serial { impl Serial { pub fn build(port: &str, baud: u32) -> Result> { - let inner = serialport::new(port, baud).open(); + let inner = serialport::new(port, baud) + .timeout(Duration::from_millis(50)) + .open(); if let Err(e) = inner { err!("Open serial port failed! Reason: {}", e); @@ -47,15 +49,18 @@ impl AnyBase for Serial { impl Tty for Serial { fn read(&mut self) -> Result, Box> { let mut buf = Vec::new(); + sleep(Duration::from_millis(SHELL_DURATION)); loop { - sleep(Duration::from_millis(SHELL_DURATION)); let mut buff = [0u8]; match self.inner.read(&mut buff) { Ok(_) => { + if buff[0] == 0x0 { + return Ok(buf); + } buf.extend_from_slice(&buff); - return Ok(buf); } Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Err(e) if e.kind() == ErrorKind::TimedOut => return Ok(buf), Err(e) => { err!("Read from serial port failed. Reason: {}", e); return Err(Box::new(e)); @@ -65,8 +70,8 @@ impl Tty for Serial { } fn read_line(&mut self) -> Result, Box> { let mut buf = Vec::new(); + sleep(Duration::from_millis(SHELL_DURATION)); loop { - sleep(Duration::from_millis(SHELL_DURATION)); let mut buff = [0u8]; match self.inner.read(&mut buff) { Ok(_) => { @@ -87,9 +92,16 @@ impl Tty for Serial { fn write(&mut self, data: &[u8]) -> Result<(), Box> { loop { sleep(Duration::from_millis(SHELL_DURATION)); + self.inner.flush()?; match self.inner.write_all(data) { - Ok(_) => break, - Err(e) if e.kind() == ErrorKind::Interrupted => continue, + Ok(_) => { + self.inner.flush()?; + break; + }, + Err(e) if e.kind() == ErrorKind::Interrupted => { + info!("Write being Interrupted!"); + continue; + }, Err(e) => { err!("Write to serial port failed. Reason: {}", e); return Err(Box::new(e)); diff --git a/src/term/shell.rs b/src/term/shell.rs index df36875..99f5553 100644 --- a/src/term/shell.rs +++ b/src/term/shell.rs @@ -3,7 +3,7 @@ use std::{ collections::HashMap, env, error::Error, - io::{BufReader, ErrorKind, Read, Write}, + io::{ErrorKind, Read, Write}, process::{ChildStdin, Command, Stdio}, sync::{Arc, Mutex}, thread::{sleep, spawn, JoinHandle},