use color_eyre::eyre::Result;
use object::read::{File as ElfFile, Object, ObjectSymbol};
use postform_decoder::{Decoder, ElfMetadata, LogLevel};
use probe_rs::{
flashing::{download_file, Format},
MemoryInterface, Session,
};
use probe_rs_rtt::{Rtt, ScanRegion};
use std::{
fs,
path::PathBuf,
sync::{Arc, Mutex},
time::Duration,
};
use termion::color;
#[derive(Debug, thiserror::Error)]
pub enum RttError {
#[error("Missing symbol {0}")]
MissingSymbol(&'static str),
}
pub fn download_firmware(session: &Arc<Mutex<Session>>, elf_path: &PathBuf) -> Result<()> {
let mut mutex_guard = session.lock().unwrap();
println!("Loading FW to target");
download_file(&mut mutex_guard, &elf_path, Format::Elf)?;
let file_contents = fs::read(elf_path)?;
let elf_file = ElfFile::parse(&file_contents[..])?;
let main = elf_file
.symbols()
.find(|s| s.name().unwrap() == "main")
.ok_or(RttError::MissingSymbol("main"))?;
let mut core = mutex_guard.core(0).unwrap();
let _ = core.reset_and_halt(Duration::from_millis(10))?;
core.set_hw_breakpoint(main.address() as u32)?;
core.run()?;
core.wait_for_core_halted(Duration::from_secs(1))?;
println!("Download complete!");
Ok(())
}
#[derive(Debug)]
pub enum RttMode {
NonBlocking = 1,
Blocking = 2,
}
pub fn configure_rtt_mode(
session: &Arc<Mutex<Session>>,
rtt_addr: u64,
mode: RttMode,
) -> Result<()> {
let mut session_lock = session.lock().unwrap();
let mut core = session_lock.core(0)?;
let mode_flags_addr = rtt_addr as u32 + 44u32;
println!("Setting mode to {:?}", mode);
core.write_word_32(mode_flags_addr, mode as u32)?;
Ok(())
}
pub fn run_core(session: Arc<Mutex<Session>>) -> Result<()> {
let mut mutex_guard = session.lock().unwrap();
let mut core = mutex_guard.core(0)?;
core.clear_all_hw_breakpoints()?;
core.run()?;
Ok(())
}
fn color_for_level(level: LogLevel) -> String {
match level {
LogLevel::Debug => String::from(color::Green.fg_str()),
LogLevel::Info => String::from(color::Yellow.fg_str()),
LogLevel::Warning => color::Rgb(255u8, 0xA5u8, 0u8).fg_string(),
LogLevel::Error => String::from(color::Red.fg_str()),
LogLevel::Unknown => color::Rgb(255u8, 0u8, 0u8).fg_string(),
}
}
pub fn handle_log(elf_metadata: &ElfMetadata, buffer: &[u8]) {
let mut decoder = Decoder::new(&elf_metadata);
match decoder.decode(buffer) {
Ok(log) => {
println!(
"{timestamp:<12.6} {color}{level:<11}{reset_color}: {msg}",
timestamp = log.timestamp,
color = color_for_level(log.level),
level = log.level.to_string(),
reset_color = color::Fg(color::Reset),
msg = log.message
);
println!(
"{color}└── File: {file_name}, Line number: {line_number}{reset}",
color = color::Fg(color::LightBlack),
file_name = log.file_name,
line_number = log.line_number,
reset = color::Fg(color::Reset)
);
}
Err(error) => {
println!(
"{color}Error parsing log:{reset_color} {error}.",
color = color::Fg(color::Red),
error = error,
reset_color = color::Fg(color::Reset)
);
}
}
}
pub fn attach_rtt(session: Arc<Mutex<Session>>, elf_file: &ElfFile) -> Result<Rtt> {
let segger_rtt = elf_file
.symbols()
.find(|s| s.name().unwrap() == "_SEGGER_RTT")
.ok_or(RttError::MissingSymbol("_SEGGER_RTT"))?;
println!("Attaching RTT to address 0x{:x}", segger_rtt.address());
let scan_region = ScanRegion::Exact(segger_rtt.address() as u32);
Ok(Rtt::attach_region(session, &scan_region)?)
}