Added some stuff for the monitor (can already reboot the target)

This commit is contained in:
2025-09-19 11:04:53 +02:00
parent c803e6514f
commit ebd24ae7b5
6 changed files with 175 additions and 19 deletions

45
Cargo.lock generated
View File

@@ -65,12 +65,29 @@ version = "0.2.175"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
[[package]]
name = "libredox"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
dependencies = [
"bitflags",
"libc",
"redox_syscall",
]
[[package]]
name = "memchr"
version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]]
name = "numtoa"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f"
[[package]]
name = "pbr"
version = "1.1.1"
@@ -112,6 +129,21 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
[[package]]
name = "redox_termios"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
[[package]]
name = "serial2"
version = "0.2.32"
@@ -134,6 +166,18 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "termion"
version = "4.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3669a69de26799d6321a5aa713f55f7e2cd37bd47be044b50f2acafc42c122bb"
dependencies = [
"libc",
"libredox",
"numtoa",
"redox_termios",
]
[[package]]
name = "tulflash"
version = "0.1.0"
@@ -141,6 +185,7 @@ dependencies = [
"argp",
"pbr",
"serial2",
"termion",
]
[[package]]

View File

@@ -7,3 +7,4 @@ edition = "2024"
argp = "0.4.0"
pbr = "1.1.1"
serial2 = "0.2.32"
termion = "4.0.5"

View File

@@ -22,7 +22,8 @@ pub struct Args {
pub enum ArgCommand {
Read(ArgRead),
Write(ArgWrite),
Erase(ArgErase)
Erase(ArgErase),
Monitor(ArgMonitor)
}
#[derive(FromArgs)]
@@ -80,6 +81,11 @@ pub struct ArgWrite {
#[argp(subcommand, name = "erase")]
pub struct ArgErase {}
#[derive(FromArgs)]
#[argp(description = "Opens the serial monitor.")]
#[argp(subcommand, name = "monitor")]
pub struct ArgMonitor {}
pub fn parse() -> Args {
let args: Args = argp::parse_args_or_exit(argp::DEFAULT);
args

View File

@@ -9,6 +9,9 @@ use args::*;
mod ihex;
use ihex::{IntelHexWriter, IntelHexReader, DataRecord};
mod monitor;
use monitor::Monitor;
mod target;
use target::{PhysicalTarget, Target};
@@ -201,6 +204,13 @@ fn erase_chip(_args: ArgErase, target: &mut PhysicalTarget) -> Result<(), Error>
Ok(())
}
fn monitor_chip(_args: ArgMonitor, target: &mut PhysicalTarget) -> Result<(), Error> {
let _ = Monitor::new().run(target.port())?;
target.resync_target().unwrap();
target.read_info(0x00, 0x00).unwrap();
Ok(())
}
fn main() {
let args = args::parse();
@@ -211,7 +221,8 @@ fn main() {
let res = match args.command {
ArgCommand::Read(args) => read_chip(args, &mut target),
ArgCommand::Write(args) => write_chip(args, &mut target),
ArgCommand::Erase(args) => erase_chip(args, &mut target)
ArgCommand::Erase(args) => erase_chip(args, &mut target),
ArgCommand::Monitor(args) => monitor_chip(args, &mut target)
};
if let Err(err) = res {

76
src/monitor.rs Normal file
View File

@@ -0,0 +1,76 @@
use std::io::Error;
use std::time::Duration;
use serial2::SerialPort;
use termion::raw::IntoRawMode;
use termion::event::Key;
use termion::input::TermRead;
pub struct Monitor {
hooks: Vec<(Key, &'static str)>
}
impl Monitor {
pub fn new() -> Self {
let mut hooks = Vec::new();
hooks.push((Key::Ctrl('c'), "Exit monitor"));
hooks.push((Key::Ctrl('r'), "Reboot target"));
Self { hooks }
}
pub fn add_hook(&mut self, key: Key, desc: &'static str) {
self.hooks.push((key, desc));
}
pub fn run(&mut self, port: &mut SerialPort) -> Result<Key, Error> {
port.set_dtr(true)?;
port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(100));
port.set_dtr(false)?;
port.set_rts(false)?;
println!("Monitor controls:");
for (key, desc) in &self.hooks {
let key = match key {
Key::Char(c) => format!("{}", c.to_uppercase()),
Key::Ctrl(c) => format!("Ctrl+{}", c.to_uppercase()),
key => format!("{:?}", key)
};
println!(" {} - {}", key, desc);
}
println!();
let mut _stdout = std::io::stdout().into_raw_mode().unwrap();
let mut stdin = termion::async_stdin().keys();
'main: loop {
if let Some(Ok(key)) = stdin.next() {
if let Key::Ctrl('r') = key {
port.set_dtr(true)?;
port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(10));
port.set_dtr(false)?;
port.set_rts(false)?;
continue
}
for (hook_key, _) in &self.hooks {
if hook_key == &key {
break 'main Ok(key)
}
}
println!("{:?}\r", key);
} else {
std::thread::sleep(Duration::from_millis(100));
}
}
}
}

View File

@@ -22,24 +22,10 @@ impl PhysicalTarget {
port.set_read_timeout(Duration::from_millis(100))?;
port.set_dtr(false)?;
std::thread::sleep(Duration::from_millis(100));
for i in (0..5).rev() {
port.write(b"U")?;
let mut buf = [0u8; 1];
port.read(&mut buf)?;
if buf[0] == b'U' { break }
if i == 0 {
Err(Error::other(format!("Invalid sync response: 0x{:02X}", buf[0])))?
}
}
let mut new = Self { port };
new.resync_target()?;
let manufacturer = new.read_info(0x00, 0x00).unwrap();
let family = new.read_info(0x00, 0x01).unwrap();
let name = new.read_info(0x00, 0x02).unwrap();
@@ -50,6 +36,29 @@ impl PhysicalTarget {
Ok(new)
}
pub fn resync_target(&mut self) -> Result<(), Error> {
self.port.set_dtr(true)?;
self.port.set_rts(true)?;
std::thread::sleep(Duration::from_millis(10));
self.port.set_dtr(false)?;
std::thread::sleep(Duration::from_millis(100));
for i in (0..5).rev() {
self.port.write(b"U")?;
let mut buf = [0u8; 1];
self.port.read(&mut buf)?;
if buf[0] == b'U' { break }
if i == 0 {
Err(Error::other(format!("Invalid sync response: 0x{:02X}", buf[0])))?
}
}
Ok(())
}
pub fn read_info(&mut self, category: u8, idx: u8) -> Result<u8, Error> {
self.send_command(0x05, 0, &[category, idx])?;
@@ -126,6 +135,10 @@ impl PhysicalTarget {
Ok(())
}
pub fn port(&mut self) -> &mut SerialPort {
&mut self.port
}
}
impl Target for PhysicalTarget {
@@ -228,7 +241,11 @@ impl Target for PhysicalTarget {
impl Drop for PhysicalTarget {
fn drop(&mut self) {
let _ = self.port.set_dtr(true);
self.port.set_dtr(true).unwrap();
self.port.set_rts(true).unwrap();
std::thread::sleep(Duration::from_millis(100));
self.port.set_dtr(false).unwrap();
self.port.set_rts(false).unwrap();
}
}